diff options
-rw-r--r-- | exec/exec.c | 168 | ||||
-rw-r--r-- | exec/priv.h | 34 |
2 files changed, 168 insertions, 34 deletions
diff --git a/exec/exec.c b/exec/exec.c index 7d80f32a..c09bfaf4 100644 --- a/exec/exec.c +++ b/exec/exec.c @@ -36,6 +36,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <hurd.h> #include <hurd/exec.h> #include <sys/stat.h> +#include <sys/param.h> #include <unistd.h> mach_port_t procserver; /* Our proc port. */ @@ -268,21 +269,10 @@ load_section (void *section, struct execdata *u) { /* Cannot map the data. Read it into a buffer and vm_write it into the task. */ - void *buf; const vm_size_t size = filesz - (mapstart - addr); - buf = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); - u->error = (buf == (caddr_t) -1) ? errno : 0; - if (! u->error) - { - if (fseek (&u->stream, - filepos + (mapstart - addr), SEEK_SET) || - fread (buf, size, 1, &u->stream) != 1) - u->error = errno; - else - write_to_task (mapstart, size, vm_prot, - (vm_address_t) buf); - munmap (buf, size); - } + void *buf = map (u, filepos + (mapstart - addr), size); + if (buf) + write_to_task (mapstart, size, vm_prot, (vm_address_t) buf); } if (u->error) return; @@ -341,14 +331,14 @@ load_section (void *section, struct execdata *u) readsize = filesz; if (SECTION_IN_MEMORY_P) - bcopy (SECTION_CONTENTS, readaddr, readsize); + memcpy (readaddr, SECTION_CONTENTS, readsize); else - if (fseek (&u->stream, filepos, SEEK_SET) || - fread (readaddr, readsize, 1, &u->stream) != 1) - { - u->error = errno; + { + const void *contents = map (u, filepos, readsize); + if (!contents) goto maplose; - } + memcpy (readaddr, contents, readsize); + } u->error = vm_write (u->task, overlap_page, ourpage, size); if (u->error == KERN_PROTECTION_FAILURE) { @@ -433,18 +423,95 @@ load_section (void *section, struct execdata *u) } } +void * +map (struct execdata *e, off_t posn, size_t len) +{ + const size_t size = e->file_size; + size_t offset; + + if ((map_filepos (e) & ~(map_vsize (e) - 1)) == (posn & ~(map_vsize (e) - 1)) + && posn + len - map_filepos (e) <= map_fsize (e)) + /* The current mapping window covers it. */ + offset = posn & (map_vsize (e) - 1); + else if (e->file_data != NULL) + /* The current "mapping window" is in fact the whole file contents. + So if it's not in there, it's not in there. */ + return NULL; + else if (e->filemap == MACH_PORT_NULL) + { + /* No mapping for the file. Read the data by RPC. */ + char *buffer = map_buffer (e); + mach_msg_type_number_t nread = map_vsize (e); + /* Read as much as we can get into the buffer right now. */ + e->error = io_read (e->file, &buffer, &nread, posn, round_page (len)); + if (e->error) + return NULL; + if (buffer != map_buffer (e)) + { + /* The data was returned out of line. Discard the old buffer. */ + if (map_vsize (e) != 0) + munmap (map_buffer (e), map_vsize (e)); + map_buffer (e) = buffer; + map_vsize (e) = round_page (nread); + } + + map_filepos (e) = posn; + map_set_fsize (e, nread); + offset = 0; + } + else + { + /* Deallocate the old mapping area. */ + if (map_buffer (e) != NULL) + munmap (map_buffer (e), map_vsize (e)); + map_buffer (e) = NULL; + + /* Make sure our mapping is page-aligned in the file. */ + offset = posn & (vm_page_size - 1); + map_filepos (e) = trunc_page (posn); + map_vsize (e) = round_page (posn + len) - map_filepos (e); + + /* Map the data from the file. */ + if (vm_map (mach_task_self (), + (vm_address_t *) &map_buffer (e), map_vsize (e), 0, 1, + e->filemap, map_filepos (e), 1, VM_PROT_READ, VM_PROT_READ, + VM_INHERIT_NONE)) + { + e->error = EIO; + return NULL; + } + + if (e->cntl) + e->cntl->accessed = 1; + + map_set_fsize (e, MIN (map_vsize (e), size - map_filepos (e))); + } + + return map_buffer (e) + offset; +} + + /* Initialize E's stdio stream. */ static void prepare_stream (struct execdata *e); /* Point the stream at the buffer of file data in E->file_data. */ static void prepare_in_memory (struct execdata *e); + +#ifndef EXECDATA_STREAM + +static void prepare_stream (struct execdata *e) {} +static void prepare_in_memory (struct execdata *e) {} + +#else + #ifdef _STDIO_USES_IOSTREAM # error implement me for libio! #else /* old GNU stdio */ +#if 0 void * map (struct execdata *e, off_t posn, size_t len) { @@ -532,13 +599,24 @@ map (struct execdata *e, off_t posn, size_t len) return f->__bufp; } +#endif /* stdio input-room function. */ static int input_room (FILE *f) { - return (map (f->__cookie, f->__target, 1) == NULL ? EOF : - (unsigned char) *f->__bufp++); + struct execdata *e = f->__cookie; + char *p = map (e, f->__target, 1); + if (p == NULL) + { + (e->error ? f->__error : f->__eof) = 1; + return EOF; + } + + f->__target = f->__offset; + f->__bufp = p; + + return (unsigned char) *f->__bufp++; } static int @@ -606,6 +684,8 @@ prepare_in_memory (struct execdata *e) e->stream.__seen = 1; } #endif + +#endif /* Prepare to check and load FILE. */ @@ -749,7 +829,7 @@ check_elf (struct execdata *e) if (! ehdr) { - if (! ferror (&e->stream)) + if (!e->error) e->error = ENOEXEC; return; } @@ -787,7 +867,7 @@ check_elf (struct execdata *e) phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (Elf32_Phdr)); if (! phdr) { - if (! ferror (&e->stream)) + if (!e->error) e->error = ENOEXEC; return; } @@ -886,7 +966,16 @@ finish (struct execdata *e, int dealloc_file) } else #endif - fclose (&e->stream); + { +#ifdef EXECDATA_STREAM + fclose (&e->stream); +#else + if (e->file_data != NULL) + free (e->file_data); + else if (map_buffer (e) != NULL) + munmap (map_buffer (e), map_vsize (e)); +#endif + } if (dealloc_file && e->file != MACH_PORT_NULL) { mach_port_deallocate (mach_task_self (), e->file); @@ -1004,9 +1093,19 @@ check_gzip (struct execdata *earg) size_t zipdatasz = 0; FILE *zipout = NULL; jmp_buf ziperr; + off_t zipread_pos = 0; int zipread (char *buf, size_t maxread) { - return fread (buf, 1, maxread, &e->stream); + char *contents = map (e, zipread_pos, 1); + size_t n; + if (contents == NULL) + { + errno = e->error; + return -1; + } + n = MIN (maxread, map_buffer (e) + map_fsize (e) - contents); + memcpy (buf, contents, n); + return n; } void zipwrite (const char *buf, size_t nwrite) { @@ -1041,7 +1140,6 @@ check_gzip (struct execdata *earg) return; } - rewind (&e->stream); if (get_method (0) != 0) { /* Not a happy gzip file. */ @@ -1101,9 +1199,19 @@ check_bzip2 (struct execdata *earg) size_t zipdatasz = 0; FILE *zipout = NULL; jmp_buf ziperr; + off_t zipread_pos = 0; int zipread (char *buf, size_t maxread) { - return fread (buf, 1, maxread, &e->stream); + char *contents = map (e, zipread_pos, 1); + size_t n; + if (contents == NULL) + { + errno = e->error; + return -1; + } + n = MIN (maxread, map_buffer (e) + map_fsize (e) - contents); + memcpy (buf, contents, n); + return n; } void zipwrite (const char *buf, size_t nwrite) { @@ -1138,8 +1246,6 @@ check_bzip2 (struct execdata *earg) return; } - rewind (&e->stream); - zipout = open_memstream (&zipdata, &zipdatasz); if (! zipout) { @@ -1542,7 +1648,7 @@ do_exec (file_t file, name = map (&e, (e.interp.phdr->p_offset & ~(e.interp.phdr->p_align - 1)), e.interp.phdr->p_filesz); - if (! name && ! ferror (&e.stream)) + if (! name && ! e.error) e.error = ENOEXEC; } diff --git a/exec/priv.h b/exec/priv.h index 75a350f1..1e836c55 100644 --- a/exec/priv.h +++ b/exec/priv.h @@ -72,10 +72,15 @@ typedef struct trivfs_protid *trivfs_protid_t; /* For MiG. */ extern mach_port_t procserver; /* Our proc port. */ -#ifndef BFD +#define EXECDATA_STREAM /* XXX */ + +#ifdef BFD +#define EXECDATA_STREAM /* BFD uses stdio to access the executable. */ +#else typedef void asection; #endif + /* Data shared between check, check_section, load, load_section, and finish. */ struct execdata @@ -87,11 +92,34 @@ struct execdata vm_address_t entry; file_t file; +#ifndef EXECDATA_STREAM + + /* Note that if `file_data' (below) is set, then these just point + into that and should not be deallocated (file_data is malloc'd). */ + char *map_buffer; /* Our mapping window or read buffer. */ + size_t map_vsize; /* Page-aligned size allocated there. */ + size_t map_fsize; /* Bytes from there to end of mapped data. */ + off_t map_filepos; /* Position `map_buffer' maps to. */ +#define map_buffer(e) ((e)->map_buffer) +#define map_fsize(e) ((e)->map_fsize) +#define map_vsize(e) ((e)->map_vsize) +#define map_filepos(e) ((e)->map_filepos) +#define map_set_fsize(e, fsize) ((e)->map_fsize = (fsize)) + +#else + #ifdef _STDIO_USES_IOSTREAM +# error implement me for libio! #else FILE stream; +#define map_buffer(e) ((e)->stream.__buffer) #define map_fsize(e) ((e)->stream.__get_limit - (e)->stream.__buffer) #define map_vsize(e) ((e)->stream.__bufsize) +#define map_filepos(e) ((e)->stream.__offset) +#define map_set_fsize(e, fsize) \ + ((e)->stream.__get_limit = (e)->stream.__buffer + (fsize)) +#endif + #endif #ifdef BFD @@ -136,11 +164,11 @@ error_t elf_machine_matches_host (Elf32_Half e_machine); void finish (struct execdata *, int dealloc_file_port); /* Make sure our mapping window (or read buffer) covers - LEN bytes of the file starting at POSN. */ + LEN bytes of the file starting at POSN, and return + a pointer into the window corresponding to POSN. */ void *map (struct execdata *e, off_t posn, size_t len); - void check_hashbang (struct execdata *e, file_t file, task_t oldtask, |