diff options
Diffstat (limited to 'exec')
-rw-r--r-- | exec/ChangeLog | 643 | ||||
-rw-r--r-- | exec/Makefile | 26 | ||||
-rw-r--r-- | exec/core.c | 264 | ||||
-rw-r--r-- | exec/do-bunzip2.c | 1745 | ||||
-rw-r--r-- | exec/elfcore.c | 630 | ||||
-rw-r--r-- | exec/exec.c | 752 | ||||
-rw-r--r-- | exec/execmutations.h | 2 | ||||
-rw-r--r-- | exec/exectrans.c | 81 | ||||
-rw-r--r-- | exec/gcore.c | 88 | ||||
-rw-r--r-- | exec/hashexec.c | 205 | ||||
-rw-r--r-- | exec/hostarch.c | 77 | ||||
-rw-r--r-- | exec/main.c | 153 | ||||
-rw-r--r-- | exec/priv.h | 71 |
13 files changed, 3200 insertions, 1537 deletions
diff --git a/exec/ChangeLog b/exec/ChangeLog deleted file mode 100644 index d650dbd8..00000000 --- a/exec/ChangeLog +++ /dev/null @@ -1,643 +0,0 @@ -Sun Jul 7 21:13:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * exec.c (S_exec_exec): Don't use unsafe MOVE_SEND in call to - interruptible exec_exec stub. - -Mon Jul 1 16:08:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * Makefile (DIST_FILES): Removed crash.c. - * crash.c: Moved to ../trans. - -Thu Jun 20 15:43:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * Makefile (exec): Link against fshelp too now. - - * exec.c (do_exec): Call proc_setowner *after* possible - proc_reassign; otherwise it modifies the stub process's state and - not the real process's. - -Wed Jun 19 14:08:15 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * exec.c (do_exec, S_exec_exec): Pass 0 for new LOOKUP arg to - hurd_file_name_lookup. - * hashexec.c (hurd_file_name_path_lookup): Declaration removed. - (check_hashbang): Pass 0 for new LOOKUP arg to hurd_file_name_lookup. - -Wed Jun 12 21:17:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * gzip.h (basename): Comment out declaration; it conflicts with - libc's. - - * exec.c (do_exec): If secure, set the owner with proc_setowner. - -Fri May 10 16:47:11 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * hashexec.c (search_path): Don't make PATH or PFXED_NAME const. - -Fri May 10 09:20:26 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * exec.c (do_exec) [use1]: Use new auth_user_authenticate interface. - * hashexec.c (check_hashbang) [userport/reauthenticate]: Likewise. - - * hashexec.c (check_hashbang) [setup_args/search_path]: Declare - PATH to be `char const *'. - -Tue May 7 16:24:52 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> - - * hashexec.c (check_hashbang): Use io_identity instead of io_stat to - compare files. - -Mon May 6 14:26:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * main.c (exec_version): Upgrade to 0.0. - -Fri May 3 14:16:17 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> - - * exec.c (map): Use F->__offset and F->__target properly. - -Thu May 2 10:21:37 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> - - * exec.c (map): Fix fencepost error in check of current mapping - window. Request round_page (LEN) bytes in io_read to avoid many small - reads. - - * exec.c (do_exec): Terminate OLDTASK if we get an error after killing - its threads and deallocating its address space. - -Tue Apr 30 11:36:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * exec.c (check_gzip) [ziprderr]: Treat all read errors as - ENOEXEC. First off, because that's what they are; also because - some callers of read_error don't set errno at all. - -Mon Apr 29 15:11:55 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * exec.c (check_section): If the format makes no sense, return - ENOEXEC, not EINVAL. - (check_bfd): Likewise. - (check_elf): Likewise. - (check_elf_phdr): Likewise. - (do_exec): Likewise. - - * exec.c (do_exec): Use correct args to ports_create_port. - -Sat Apr 27 06:02:42 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> - - * crash.c: Use ports_create_port instead of ports_allocate_port, and - notice the error. - * exec.c: Likewise. - -Tue Apr 23 18:53:54 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> - - * hashexec.c (check_hashbang: user_port): Use default root port when - secure. - -Mon Apr 15 12:48:35 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * Makefile (DIST_FILES): Add elfcore.c, crash.c, and exectrans.c. - (SRCS): That's hashexec.c, not .o. - - * Makefile (exec-MIGSFLAGS): Look for execmutations.h in - $(srcdir). - -Mon Apr 8 15:49:39 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * exec.c (prepare): If io_map returns EOPNOTSUPP, suppress the - error, and still setup E's stream. - (prepare_and_check): If prepare returns an error, do no more. - -Thu Mar 28 14:06:07 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * hashexec.c (check_hashbang): Pass open flags & mode args to - hurd_file_name_path_lookup. - -Mon Feb 26 16:33:22 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * hashexec.c (check_hashbang): Correctly deal with interpreter - lines having no argument. - -Sat Jan 13 12:28:03 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * hashexec.c (check_hashbang): Use hash_file_name_path_lookup() - instead of doing the path search ourselves, and get rid of - LOOKUP_CWDIR & associated logic. - * exec.c (S_exec_exec): Use strdupa(). Also update use of - hurd_file_name_lookup() [still probably not right though]. - -Thu Jan 11 15:36:18 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * hashexec.c (check_hashbang): When using executable name found on - the path, don't return alloca()ed memory from search_path(); use - malloc() instead. - Use envz_get() to search the environment. - - * exec.c (S_exec_exec): Use envz_get() to search the environment. - -Thu Jan 4 11:30:15 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (safe_bzero): Rewritten using hurd_catch_signal. - * hashexec.c (check_hashbang): Rearrange arg frobbing code - somewhat to use hurd_catch_signal instead of old preemption interface. - -Fri Dec 29 15:54:06 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * exec.c (do_exec): Be careful not to look at BOOT after we - release our reference on it. - Correctly initialize BOOT->intarray in the case where NINTS < - INIT_INT_MAX but we don't alloc a new array. - -Fri Dec 15 01:53:07 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (map): Rearrange code to fix some bugs and not remap - unless necessary. - (input_room): Simplify. - (check_elf): Extract all information from file header before - calling `map' for program headers. - -Sat Nov 25 22:10:41 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * crash.c (S_msg_sig_post_untraced): Also let the debugger have - the process back if it's posting the crashing signal. - -Tue Nov 21 15:01:56 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (safe_bzero): New function, broken out of load_section. - (load_section): Call it. - - * main.c (going_down): Variable removed. - (deadboot): Don't test it. Instead, use ports calls to check if - there are no other live ports. - (trivfs_goaway): Don't set it. - -Wed Nov 15 19:40:44 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * hashexec.c (user_port): Fixed port selection logic. - (check_hashbang): Fixed PATH searching in script name guessing. - -Mon Nov 13 15:11:37 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (S_exec_startup): Compatibility RPC removed. - - * exec.c (load_section): Catch faults while zeroing partial bss page. - -Sun Nov 5 00:15:07 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (main): Add flags arg to trivfs_startup call. - -Wed Oct 25 15:50:38 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (S_exec_startup_get_info): New function, modified from - S_exec_startup. - (S_exec_startup): Just call it. - * main.c (exec_demuxer): Call exec_startup_server. - -Tue Oct 24 19:21:20 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * Makefile (OBJS): Add exec_startupServer.o. - - * priv.h (struct bootinfo): Use vm_size_t for phdr_size. - -Wed Oct 18 18:36:30 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * hashexec.c (check_hashbang: prepare_args): Enable and clean up - code to guess the name of the script before resorting to /dev/fd. - -Wed Oct 18 03:05:05 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * hashexec.c: New file. - * exec.c (struct execdata): Moved to priv.h. - (std_*, finish): Make global. - (do_exec): Only reset CWDIR when null, even if secure. - Actually call check_hashbang and return success if it does. - Use new hurd_file_name_lookup protocol with private callbacks to open - interpreter file on behalf of client. - Remove `bootout' label; use `stdout' or `out' as appropriate instead. - At `out' label always deref BOOT, which cleans it up iff necessary. - (S_exec_exec): #if 0 out $EXECSERVERS processing for time being. - * priv.h: Added some #includes. - (struct execdata): Moved here from exec.c. - (std_*): Declare these. - (finish, check_hashbang): Declare them. - * Makefile (SRCS, OBJS): Add hashexec.[co]. - (DIST_FILES): Remove it from here. - -Wed Oct 11 01:45:32 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * main.c, priv.h, execmutations.h: New files. - * exec.c: Server mechanics removed; now uses libtrivfs/libports. - Main program split out into main.c. - (std_lock): New variable (rwlock). - (do_exec): Acquire reader lock to access std_ints and std_ports. - (S_exec_setexecdata): Acquire writer lock to change them. - * Makefile (OBJS): Add main.o; remove fsysServer.o, notifyServer.o. - (LCLHDRS): Add priv.h and execmutations.h. - (exec-MIGSFLAGS): New variable. - (exec): Depend on livtrivfs, libthreads, libshouldbeinlibc. - -Mon Oct 2 10:33:14 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * exec.c (do_exec): Doc fix. - -Wed Sep 27 11:21:19 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (do_exec): Don't set NEWTASK's bootstrap port until after - we have finished completely with OLDTASK. - (do_mach_notify_no_senders): Remove bogus mod_refs call on - receive_portset. - -Wed Sep 20 19:57:55 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (struct bootinfo): New members `phdr_addr', `phdr_size', - `user_entry'. - (do_exec): Set them. Code rearranged to construct bootinfo before - looking up interpreter file, keep proper track of port rights and - VM copied into bootinfo (there were leaks). - -Sat Sep 16 13:15:42 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * Makefile: Remove vpath directive. - -Fri Sep 8 17:50:03 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * Makefile (OTHERLIBS, CPPFLAGS): Disable bfd by default. - -Mon Aug 28 16:57:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (S_fsys_forward): New stub function. - -Sun Jul 30 23:49:49 1995 Michael I. Bushnell, p/BSG <mib@geech.gnu.ai.mit.edu> - * Makefile (SRCS): Added unzip.c, util.c, and inflate.c. - -Thu Jul 6 15:32:39 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * hostarch.c (bfd_mach_host_arch_mach): Remove assignment from - inside if test. - - * Makefile: Removed dependencies that are now automatically - generated. - -Wed Jul 5 18:00:49 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * Makefile (OTHERLIBS): Define var. - (all, exec): Delete targets. - -Tue Jun 27 11:48:08 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * exec.c (load_section): Remove assignments from if tests. - (map): Likewise. - (prepare): Likewise. - (load): Likewise. - (servercopy): Likewise. - (do_exec): Likewise. - (S_exec_setexecdata): Likewise. - (S_exec_exec): Put extra parens around assignment inside while - test. - -Thu Jun 8 02:57:28 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (struct execdata.info.elf): Add members `anywhere' and - `loadbase'. - (load_section): Use them; if `anywhere' set, load the section anywhere. - Record load address in `loadbase'. - (check_elf): Initialize `anywhere' and `loadbase'. - (postload): Merged into load. - (load): Perform postload functionality here, after calling - finish_mapping. - (finish): Take new flag arg; deallocate file port only if set. - (do_exec): Pass flag to finish appropriately. - Don't call finish_mapping and postload after load. KLUDGE: Load - the interpreter before the program instead of after. - -Mon Jun 5 06:42:33 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c: Majorly revamped: Now supports the ELF format directly. - Secondarily uses the BFD library #ifdef BFD. Supports gunzipping - only #ifdef GZIP. - * hostarch.c: Rewritten to unconditionally return both BFD and ELF - machine types. - -Fri May 12 18:59:21 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> - - * exec.c (S_fsys_set_options, S_fsys_mod_readonly): Change from - mod_readonly to set_options. - -Thu Apr 20 22:14:47 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (check_gzip): Rewind the stream before calling - `get_method'. Open a new BFD on the uncompressed data stream - before return. - -Sun Apr 9 01:27:10 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (struct execdata) [BFD]: New member `interp_section'. - (check_section): Notice section named ".interp" and set that pointer. - (load_section): Do nothing if the section is zero size. - When reading into our copy of the overlap page, don't read past - the end of the section. - (do_exec): Consolidate new subfunction `check_maybe_gzip'. - If there is an interpreter section, load the interpreter file too, - and use its entry point instead of the user program's. Cleaned up - and made more robust deallocation of BOOT info on error. - (deadboot): New function, split out of do_mach_port_notify_no_senders. - - * Makefile (vpath lib%.a): Add search path. - (exec): Depend on -lbfd and -liberty. - (CPPFLAGS): Append -DBFD; omit -DA_OUT_H=... - (bfdexec): Target removed. - * exec.c (load_section): fseek to desired position before freading. - (input_room): Always map a page-aligned region. - -Thu Feb 9 01:01:57 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (check_section): Don't check SEC_RELOC flag. - -Wed Feb 8 19:48:11 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * exec.c (load_section) [BFD]: BFD does not set SEC_HAS_CONTENTS - on a.out BSS's ever; don't make zeroing of bss conditional on that. - It's not clear exactly what SEC_HAS_CONTENTS is for anyhow; - perhaps the Right Thing is to set in on BSS. In any case, don't - depend on this flag here. - -Sat Jan 28 17:08:02 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (prepare): Give the stream a seek function. - -Sun Jan 22 03:16:17 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c: Update BFD code; it works now. - * hostarch.c [BFD]: Fix prototype. - -Thu Jan 19 01:24:18 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * hostarch.c: Add case for CPU_TYPE_ALPHA. - - * hostarch.c (bfd_mach_host_arch_mach, aout_mach_host_machine): - Use mach_msg_type_number_t instead of unsigned int. Cast - &HOSTINFO to (natural_t *). - -Sun Jan 15 06:29:56 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c [BFD] (bfd_mach_host_arch_mach): In decl, MACHINE arg is - `long int *' now. - [BFD] (host_bfd_arch_info): New variable. - [BFD] (host_bfd): Initialize `arch_info' member to its address. - (check) [BFD]: Use bfd_arch_get_compatible properly, rather than the - nonexistent bfd_arch_compatible. - (main) [BFD]: Fill in host_bfd.arch_info instead of old - `obj_machine' and `obj_archiecture' members, which BFD no longer has. - * hostarch.c [BFD] (bfd_mach_host_arch_mach): MACHINE arg is `long - int *' now. - -Tue Dec 13 23:28:08 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * Makefile (OBJS): Add unzip.o util.o inflate.o. - (LCLHDRS): Add gzip.h crypt.h tailor.h. - (unzip.o util.o inflate.o): Depend on those. - (CFLAGS): Use +=. - * inflate.c, unzip.c, util.c, tailor.h, gzip.h, crypt.h: New files. - -Sun Dec 11 19:49:01 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (struct execdata): New members `headbuf', `file_data', - `optimal_block'. - (load_section): Copy data from U->file_data if that is nonnull. - Use new subfunction `write_to_task' that handles non-page aligned - sections. - (input_room): Fix EOF check. - Use io_read if no memory object. - (prepare): New function, broken out of check. - Initialize E->file_data and E->optimal_block. Set - E->stream.__seen bit. - (check): No longer take FILE arg. - Use E->file_data if nonnull; else read from stream if no memory object. - (finish_mapping): Reset members after deallocating resources. - (finish): Likewise. Call fclose. Don't deallocate E->header if - it points to &E->headbuf or E->file_data. - (check_gzip): New function, implements executing gzip'd binaries. - (do_exec): Call prepare before check. - Call check_gzip if file format unrecognized. - -Wed Nov 9 01:40:28 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * exec.c (set_active_trans): Don't deallocate EXECNODE here to - work around a ufs bug. - - * exec.c: Include <hurd/paths.h> and <fcntl.h>. - (set_active_trans): New function. - (S_exec_init): Call set_active_trans. - -Wed Aug 31 11:16:04 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * exec.c (load_section): Pass address of stream in call to fread. - (input_room): Cast second arg to vm_deallocate. Dereference F - in setting __error member. - (close_exec_stream): Provide all three args to vm_deallocate - and cast the second one properly. - -Wed Aug 31 04:32:26 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c (do_exec): Do check before task_suspend. - #if 0'd out: If check gets ENOEXEC, call check_hashbang. - (struct execdata): Move member `stream' outside of [BFD]. - (load_section): Use fread instead of hand mapping and copying - unconditionally (was [BFD]); old code left #if'd out. - (close_exec_stream): Renamed from close_stdio_bfd; moved out of [BFD]. - (input_room): Define unconditionally, not [BFD]. - (check): Set up E->stream unconditionally. - -Tue Aug 30 11:58:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * exec.c (S_fsys_syncfs, S_fsys_mod_readonly): New stubs. - - * exec.c (set_init_port): Use new authentication protocol. - - * exec.c (S_exec_exec): Call hurd_file_name_lookup instead - of hurd_path_lookup. - - * exec.c (S_fsys_getroot): Return FS_RETRY_NORMAL instead - of FS_RETRY_NONE. - - * exec.c (procserver): New global variable. - (S_exec_init): Set procserver. - (do_exec): Use `procserver' instead of USEPORT macro. - (S_exec_init): Likewise. - -Mon Aug 29 13:08:44 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * exec.c (do_exec): Enable and fix up code for doing proc_reassign - in the EXEC_NEWTASK case. - (do_exec): If we don't provide the proc port, and this is a - newtask exec, then use the proc port to fetch a new one - corresponding to the new task. - -Wed Aug 17 14:59:58 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * exec.c (S_exec_exec): Bother to pass flags to do_exec. - - * exec.c (essentialstartupport, essentialhostport): Deleted vars. - (S_exec_init): Do startup_essential_task here like before, but - make sure we do it last. - (S_exec_setexecdata): Don't do startup_essential_task here. - -Tue Aug 16 10:02:50 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * exec.c (set_init_port): Don't assume that MACH_PORT_NULL == 0. - (do_exec): Likewise. - -Mon Aug 15 21:23:13 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * exec.c: Include <unistd.h> for getpid decl. - (set_init_port): Use pid_t for PID. - (S_exec_init): Pass poly arg to proc_execdata_notify. - -Mon Aug 15 15:24:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * exec.c (do_exec): Finish implementing EXEC_SECURE flag; - implement EXEC_DEFAULTS flag. - (S_exec_init): Delay startup_essential_task until after - we've received the first essential ports from the proc server. - (essentialstartupport essentialhostport): New global vars. - -Fri Jul 22 10:21:30 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * Makefile: Rewritten in accord with new scheme. - * exec.c: Include "exec_S.h" instead of "exec_server.h". - Include "notify_S.h". - -Tue Jul 19 20:51:58 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * Makefile (exec_server.h execServer.c, fsys_S.h fsysServer.c): - Find .defs file in ../hurd, not $(includedir). - -Tue Jul 19 12:42:32 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * exec.c (S_fsys_getroot): New arg `dotdot'; don't do anything - with it. - (S_fsys_startup): Removed dotdot args. - (main): Deleted var `dotdot'; don't expect it from fsys_startup. - - * Makefile (exec): Don't use variable $(link) anymore. - -Tue Jul 5 14:20:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * Makefile (SRCS, TAGSHDRS): New variables. - -Fri Jun 24 14:42:59 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * exec.c (load_section) [AOUT, mapstart > addr]: Dereference - U->header in use of N_MAGIC. - -Fri Jun 24 02:40:32 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * exec.c (load_section): Store protection of section in new local - VM_PROT. If vm_write of overlap page gets KERN_PROTECTION_FAILURE, - change protection of overlap page long enough to write it. - [AOUT]: Return ENOEXEC if there is overlap in NMAGIC or ZMAGIC. - -Thu Jun 16 16:15:17 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) - - * exec.c (S_fsys_getroot): Implement new fsys_getroot interface. - -Mon Jun 13 04:06:24 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) - - * exec.c (check): Store FILE in E->file. - -Tue May 31 17:20:24 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) - - * a.out.h (struct exec): Type removed. - (OMAGIC, NMAGIC, ZMAGIC, N_MAGIC, N_MACHTYPE, N_BADMAG): Macros - removed. Just #include "a.out.gnu.h" to get all these defined. - (N_TXTLEN, N_TXTOFF): Use N_MAGIC instead of a_magic member. - - * Makefile (DIST_FILES): Add a.out.gnu.h. - (exec.o, hostarch.o): Depend on a.out.gnu.h. - -Fri May 27 01:40:04 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * exec.c (servercopy): New function to check the servercopy flag - and possibly vm_allocate a copy of argument data. - (do_exec): Take new args DTABLE_COPY, PORTARRAY_COPY, - INTARRAY_COPY. Use servercopy for ARGV, ENVP, DTABLE, PORTARRAY, - and INTARRAY. - (S_exec_exec): Take those new args and pass them to do_exec. - (S_exec_setexecdata): Take new args PORTS_COPY and INTS_COPY. - Use servercopy for PORTS and INTS. - (S_exec_startup): Never copy from info in *BOOT, always just set - the argument pointers to the pointers in *BOOT. MiG will copy and - deallocate the space as necessary. - - * exec.c (check): Lock and unlock E->cntl->lock properly. - (finish_mapping): New function, broken out of finish. - (postload_section): New function, broken out of load_section. - (postload): New function, like load but calls postload_section. - (do_exec): Call finish_mapping and postload between load and finish. - -Tue May 24 19:49:16 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * exec.c (S_exec_exec): Use strsep instead of strtok. - (main): Keep looping after error from mach_msg_server. - -Tue May 24 14:22:16 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * exec.c (load_section): Cast arg to vm_deallocate properly. - -Tue May 24 01:05:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * exec.c (struct bootinfo): Remove members argv_vmalloc, envp_vmalloc. - (do_exec): Don't set BOOT->argv_vmalloc or BOOT->envp_vmalloc. If - ARGV_COPY is set, vm_allocate space for ARGV; likewise for - ENVP_COPY and ENVP. - (S_exec_startup): Don't test BOOT->argv_vmalloc and - BOOT->envp_vmalloc; BOOT->argv and BOOT->envp are always vm_allocate'd. - (do_mach_notify_no_senders): Likewise. - (load_section): Handle non-bss sections that are not page aligned. - -Mon May 23 22:01:11 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * exec.c (S_exec_exec): Reverse args to memmem. - (do_exec): Don't vm_deallocate DEALLOCNAMES or DESTROYNAMES; mig - deallocates the space for us. - -Tue May 17 13:33:41 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * exec.c (S_exec_init): Don't deallocate host_priv until after - we've used it in the call to startup_essential_task. - -Thu May 12 03:53:57 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * exec.c (S_fsys_init): Add reply port args. - -Wed May 11 16:03:07 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) - - * exec.c (S_exec_init): Spelling fix. - - * Makefile (exec.o): Add dependencies on fsys_S.h and notify_S.h. - (fsysServer.c, notifyServer.c): Notice that these rules build - fsys_S.h and notify_S.h respectively. - -Mon May 9 17:06:52 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) - - * exec.c (exec_version, save_argv): New variable. - (main): Set save_argv. - (S_exec_init): Give the real argv to proc. - Call proc_register_version if we can. - (S_exec_init): Call startup_essential_task if we can. - -Thu May 5 06:25:02 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * Makefile: Change uses of $(headers) to $(includedir). - - * exec.c: Change return type of all RPC server functions to - kern_return_t. error_t is not compatible with the declarations in - the mig-generated header files. - - * exec.c (do_exec): Set BOOT->stack_base and BOOT->stack_size with - mach_setup_thread. - (S_exec_exec): Pass msg type arg for FILE arg to exec_exec. - -Thu Dec 23 18:05:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * exec.c (do_exec): For a newtask exec when EXEC_SECURE is not set - and OLDTASK is not null, send the `task_create' RPC on OLDTASK - rather than mach_task_self (). diff --git a/exec/Makefile b/exec/Makefile index 6a5d9525..e7050c10 100644 --- a/exec/Makefile +++ b/exec/Makefile @@ -1,6 +1,6 @@ -# Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. +# Copyright (C) 1993,94,95,96,98,99,2000,01,02,10 Free Software Foundation, Inc. # This file is part of the GNU Hurd. -# +# # The GNU Hurd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) @@ -10,7 +10,7 @@ # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with the GNU Hurd; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. @@ -18,21 +18,27 @@ dir := exec makemode := server -SRCS = exec.c main.c hashexec.c hostarch.c unzip.c util.c inflate.c +SRCS = exec.c main.c hashexec.c hostarch.c \ + $(gzip-sources) $(bzip2-sources) OBJS = main.o hostarch.o exec.o hashexec.o \ execServer.o exec_startupServer.o \ - $(gzip-objects) -gzip-objects = unzip.o util.o inflate.o + $(gzip-objects) $(bzip2-objects) +gzip-sources = unzip.c util.c inflate.c +gzip-objects = $(gzip-sources:%.c=%.o) +bzip2-sources = do-bunzip2.c +bzip2-objects = $(bzip2-sources:%.c=%.o) + LCLHDRS = gzip.h crypt.h tailor.h priv.h execmutations.h target = exec -DIST_FILES = core.c gcore.c elfcore.c exectrans.c +#targets = exec exec.static +DIST_FILES = elfcore.c #OTHERLIBS = -lbfd -liberty +HURDLIBS = trivfs fshelp iohelp threads ports ihash shouldbeinlibc exec-MIGSFLAGS = -imacros $(srcdir)/execmutations.h include ../Makeconf -CPPFLAGS += -DGZIP # -DBFD +CPPFLAGS += -DGZIP -DBZIP2 # -DBFD -exec: ../libtrivfs/libtrivfs.so ../libthreads/libthreads.so \ - ../libshouldbeinlibc/libshouldbeinlibc.so ../libfshelp/libfshelp.so +exec.static exec: $(OBJS) $(library_deps) diff --git a/exec/core.c b/exec/core.c deleted file mode 100644 index 6d685a23..00000000 --- a/exec/core.c +++ /dev/null @@ -1,264 +0,0 @@ -/* GNU Hurd standard core server. - Copyright (C) 1992 Free Software Foundation, Inc. - Written by Roland McGrath. - -This file is part of the GNU Hurd. - -The GNU Hurd is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -The GNU Hurd is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with the GNU Hurd; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include <hurd.h> -#include "core_server.h" -#include <bfd.h> -#include <string.h> - -/* Uses nonexistent bfd function: */ -char *bfd_intuit_section_name (bfd_vma vma, bfd_size_type size, - flagword *flags); - -/* Object file format to write core files in. */ -static char *core_target = NULL; - -/* Dump a core from TASK into FILE. - SIGNO and SIGCODE indicate the signal that killed the process. */ - -error_t -core_dump_task (mach_port_t coreserver, - task_t task, - file_t file, - int signo, int sigcode, - const char *my_target) -{ - error_t err; - - processor_set_name_t pset; - host_t host; - processor_set_basic_info_data_t pinfo; - - thread_t *threads; - size_t nthreads; - - vm_address_t addr; - vm_size_t size; - vm_prot_t prot, maxprot; - vm_inherit_t inherit; - boolean_t shared; - memory_object_name_t objname; - vm_offset_t offset; - - bfd *bfd; - bfd_architecture arch; - bfd_machine machine; - asection *sec; - - /* The task is suspended while we examine it. - In the case of a post-mortem dump, the only thread not suspended will - be the signal thread, which will be blocked waiting for this RPC to - return. But for gcore, threads might be running. And Leviticus - specifies that only suspended threads be thread_info'd, anyway. */ - if (err = task_suspend (task)) - goto lose; - - /* Figure out what flavor of machine the task is on. */ - if (err = task_get_assignment (task, &pset)) - goto lose; - err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host, - &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT); - mach_port_deallocate (mach_task_self (), pset); - if (err) - goto lose; - err = bfd_mach_host_arch_mach (host, &arch, &machine); - mach_port_deallocate (mach_task_self (), host); - if (err) - goto lose; - - /* Open the BFD. */ - bfd = NULL; - { - FILE *f = fopenport (file, "w"); - if (f == NULL) - { - err = errno; - goto lose; - } - bfd = bfd_openstream (f, my_target ?: core_target); - if (bfd == NULL) - { - err = errno; - (void) fclose (f); - errno = err; - goto bfdlose; - } - } - - bfd_set_arch_mach (bfd, arch, machine); - - /* XXX How are thread states stored in bfd? */ - if (err = task_threads (task, &threads, &nthreads)) - goto lose; - - /* Create a BFD section to describe each contiguous chunk - of the task's address space with the same stats. */ - sec = NULL; - addr = 0; - while (!vm_region (task, &addr, &size, &prot, &maxprot, - &inherit, &shared, &objname, &offset)) - { - mach_port_deallocate (mach_task_self (), objname); - - if (prot != VM_PROT_NONE) - { - flagword flags = SEC_NO_FLAGS; - - if (!(prot & VM_PROT_WRITE)) - flags |= SEC_READONLY; - if (!(prot & VM_PROT_EXECUTE)) - flags |= SEC_DATA; - - if (sec != NULL && - (vm_address_t) (bfd_section_vma (bfd, sec) + - bfd_section_size (bfd, sec)) == addr && - flags == (bfd_get_section_flags (bfd, sec) & - (SEC_READONLY|SEC_DATA))) - /* Coalesce with the previous section. */ - bfd_set_section_size (bfd, sec, - bfd_section_size (bfd, sec) + size); - else - { - /* Make a new section (which might grow by - the next region being coalesced onto it). */ - char *name = bfd_intuit_section_name (addr, size, &flags); - if (name == NULL) - { - /* No guess from BFD. */ - if (asprintf (&name, "[%p,%p) %c%c%c", - (void *) addr, (void *) (addr + size), - (prot & VM_PROT_READ) ? 'r' : '-', - (prot & VM_PROT_WRITE) ? 'w' : '-', - (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1) - goto lose; - } - sec = bfd_make_section (name); - bfd_set_section_flags (bfd, sec, flags); - bfd_set_section_vma (bfd, sec, addr); - bfd_set_section_size (bfd, sec, size); - } - } - } - - /* Write all the sections' data. */ - for (sec = bfd->sections; sec != NULL; sec = sec->next) - { - void *data; - err = vm_read (task, bfd_section_vma (bfd, sec), - bfd_section_size (bfd, sec), &data); - if (err) - /* XXX What to do? - 1. lose - 2. remove this section - 3. mark this section as having ungettable contents (how?) - */ - goto lose; - err = bfd_set_section_contents (bfd, sec, data, 0, - bfd_section_size (bfd, sec)); - vm_deallocate (mach_task_self (), data, bfd_section_size (bfd, sec)); - if (err) - goto bfdlose; - } - - bfdlose: - switch (bfd_error) - { - case system_call_error: - err = errno; - break; - - case no_memory: - err = ENOMEM; - break; - - default: - err = EGRATUITOUS; - break; - } - - lose: - if (bfd != NULL) - bfd_close (bfd); - else - mach_port_deallocate (mach_task_self (), file); - task_resume (task); - mach_port_deallocate (mach_task_self (), task); - return err; -} - -error_t -fsys_getroot (fsys_t fsys, idblock_t id, file_t realnode, file_t dotdot, - file_t *root) -{ - *root = core; - mach_port_deallocate (mach_task_self (), realnode); - mach_port_deallocate (mach_task_self (), dotdot); - return POSIX_SUCCESS; -} - -mach_port_t request_portset; - -int -request_server (mach_msg_header_t *inp, - mach_msg_header_t *outp) -{ - if (inp->msgh_local_port == fsys) - return fsys_server (inp, outp); - else if (inp->msgh_local_port == core) - return (core_server (inp, outp) || - io_server (inp, outp) || - fs_server (inp, outp)); -} - -int -main (int argc, char **argv) -{ - error_t err; - fsys_t fsys; - mach_port_t boot, dotdot; - - if ((err = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_RECEIVE, &fsys)) || - (err = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_RECEIVE, &core))) - hurd_perror ("mach_port_allocate", err); - else if (err = task_get_bootstrap_port (mach_task_self (), &boot)) - hurd_perror ("task_get_bootstrap_port", err); - else if (err = fsys_startup (boot, fsys, &realnode, &dotdot)) - hurd_perror ("fsys_startup", err); - mach_port_deallocate (mach_task_self (), dotdot); - - mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_PORT_SET, &request_portset); - - mach_port_move_member (mach_task_self (), fsys, request_portset); - mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &core); - mach_port_move_member (mach_task_self (), core, request_portset); - - mach_port_mod_refs (mach_task_self (), realnode, MACH_PORT_RIGHT_SEND, 1); - - core_target = argv[1]; - - do - err = mach_msg_server (request_server, vm_page_size, request_portset); - while (!err); - hurd_perror ("mach_msg_server", err); - return 1; -} diff --git a/exec/do-bunzip2.c b/exec/do-bunzip2.c new file mode 100644 index 00000000..716a0cde --- /dev/null +++ b/exec/do-bunzip2.c @@ -0,0 +1,1745 @@ +/* bunzip2 engine, modified by okuji@kuicr.kyoto-u.ac.jp. */ + +/* Stolen from util.c. */ +#include <stdio.h> +#include <sys/types.h> + +/* I/O interface */ +extern int (*unzip_read) (char *buf, size_t maxread); +extern void (*unzip_write) (const char *buf, size_t nwrite); +extern void (*unzip_read_error) (void); +extern void (*unzip_error) (const char *msg); + +/* bzip2 doesn't require window sliding. Just for buffering. */ +#define INBUFSIZ 0x1000 +#define OUTBUFSIZ 0x1000 + +static unsigned char inbuf[INBUFSIZ]; +static unsigned char outbuf[OUTBUFSIZ]; +static unsigned inptr; +static unsigned insize; +static unsigned outcnt; + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty. + */ +static int +fill_inbuf (int eof_ok) +{ + int len; + + /* Read as much as possible */ + insize = 0; + do + { + len = (*unzip_read)((char*)inbuf+insize, INBUFSIZ-insize); + if (len == 0 || len == EOF) + break; + insize += len; + } + while (insize < INBUFSIZ); + + if (insize == 0) + { + if (eof_ok) + return EOF; + unzip_read_error(); + } + + inptr = 1; + return inbuf[0]; +} + +static void +flush_outbuf (void) +{ + if (outcnt == 0) + return; + + (*unzip_write) ((char *) outbuf, outcnt); + outcnt = 0; +} + +static inline int +bz2_getc (void *stream) +{ + return inptr < insize ? inbuf[inptr++] : fill_inbuf (1); +} + +static inline int +bz2_putc (int c, void *stream) +{ + if (outcnt == OUTBUFSIZ) + flush_outbuf (); + outbuf[outcnt++] = c; + return c; +} + +static inline int +bz2_ferror (void *stream) +{ + return 0; +} + +static inline int +bz2_fflush (void *stream) +{ + flush_outbuf (); + return 0; +} + +static inline int +bz2_fclose (void *stream) +{ + flush_outbuf (); + return 0; +} + +#define fprintf(s, f...) /**/ + + +/*-----------------------------------------------------------*/ +/*--- A block-sorting, lossless compressor bzip2.c ---*/ +/*-----------------------------------------------------------*/ + +/*-- + This program is bzip2, a lossless, block-sorting data compressor, + version 0.1pl2, dated 29-Aug-1997. + + Copyright (C) 1996, 1997 by Julian Seward. + Guildford, Surrey, UK + email: jseward@acm.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The GNU General Public License is contained in the file LICENSE. + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the file ALGORITHMS. +--*/ + +/*----------------------------------------------------*/ +/*--- IMPORTANT ---*/ +/*----------------------------------------------------*/ + +/*-- + WARNING: + This program (attempts to) compress data by performing several + non-trivial transformations on it. Unless you are 100% familiar + with *all* the algorithms contained herein, and with the + consequences of modifying them, you should NOT meddle with the + compression or decompression machinery. Incorrect changes can + and very likely *will* lead to disastrous loss of data. + + DISCLAIMER: + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the + complexity of the algorithms, and, in particular, the presence + of various special cases in the code which occur with very low + but non-zero probability make it impossible to rule out the + possibility of bugs remaining in the program. DO NOT COMPRESS + ANY DATA WITH THIS PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE + POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2 has been + carefully constructed and extensively tested. + + PATENTS: + To the best of my knowledge, bzip2 does not use any patented + algorithms. However, I do not have the resources available to + carry out a full patent search. Therefore I cannot give any + guarantee of the above statement. +--*/ + + + +/*----------------------------------------------------*/ +/*--- and now for something much more pleasant :-) ---*/ +/*----------------------------------------------------*/ + +/*---------------------------------------------*/ +/*-- + Place a 1 beside your platform, and 0 elsewhere. +--*/ + +/*-- + Generic 32-bit Unix. + Also works on 64-bit Unix boxes. +--*/ +#define BZ_UNIX 1 + +/*-- + Win32, as seen by Jacob Navia's excellent + port of (Chris Fraser & David Hanson)'s excellent + lcc compiler. +--*/ +#define BZ_LCCWIN32 0 + + + +/*---------------------------------------------*/ +/*-- + Some stuff for all platforms. +--*/ + +#include <stdio.h> +#include <stdlib.h> +#if DEBUG + #include <assert.h> +#endif +#include <string.h> +#include <signal.h> +#include <math.h> + +#define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); } +#define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); } +#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); } + + +/*---------------------------------------------*/ +/*-- + Platform-specific stuff. +--*/ + +#if BZ_UNIX + #include <sys/types.h> + #include <utime.h> + #include <unistd.h> + #include <malloc.h> + #include <sys/stat.h> + #include <sys/times.h> + + #define Int32 int + #define UInt32 unsigned int + #define Char char + #define UChar unsigned char + #define Int16 short + #define UInt16 unsigned short + + #define PATH_SEP '/' + #define MY_LSTAT lstat + #define MY_S_IFREG S_ISREG + #define MY_STAT stat + + #define APPEND_FILESPEC(root, name) \ + root=snocString((root), (name)) + + #define SET_BINARY_MODE(fd) /**/ + + /*-- + You should try very hard to persuade your C compiler + to inline the bits marked INLINE. Otherwise bzip2 will + run rather slowly. gcc version 2.x is recommended. + --*/ + #ifdef __GNUC__ + #define INLINE inline + #define NORETURN __attribute__ ((noreturn)) + #else + #define INLINE /**/ + #define NORETURN /**/ + #endif +#endif + + + +#if BZ_LCCWIN32 + #include <io.h> + #include <fcntl.h> + #include <sys\stat.h> + + #define Int32 int + #define UInt32 unsigned int + #define Int16 short + #define UInt16 unsigned short + #define Char char + #define UChar unsigned char + + #define INLINE /**/ + #define NORETURN /**/ + #define PATH_SEP '\\' + #define MY_LSTAT _stat + #define MY_STAT _stat + #define MY_S_IFREG(x) ((x) & _S_IFREG) + + #if 0 + /*-- lcc-win32 seems to expand wildcards itself --*/ + #define APPEND_FILESPEC(root, spec) \ + do { \ + if ((spec)[0] == '-') { \ + root = snocString((root), (spec)); \ + } else { \ + struct _finddata_t c_file; \ + long hFile; \ + hFile = _findfirst((spec), &c_file); \ + if ( hFile == -1L ) { \ + root = snocString ((root), (spec)); \ + } else { \ + int anInt = 0; \ + while ( anInt == 0 ) { \ + root = snocString((root), \ + &c_file.name[0]); \ + anInt = _findnext(hFile, &c_file); \ + } \ + } \ + } \ + } while ( 0 ) + #else + #define APPEND_FILESPEC(root, name) \ + root = snocString ((root), (name)) + #endif + + #define SET_BINARY_MODE(fd) \ + do { \ + int retVal = setmode ( fileno ( fd ), \ + O_BINARY ); \ + ERROR_IF_MINUS_ONE ( retVal ); \ + } while ( 0 ) + +#endif + + +/*---------------------------------------------*/ +/*-- + Some more stuff for all platforms :-) +--*/ + +#define Bool unsigned char +#define True 1 +#define False 0 + +/*-- + IntNative is your platform's `native' int size. + Only here to avoid probs with 64-bit platforms. +--*/ +#define IntNative int + + +/*-- + change to 1, or compile with -DDEBUG=1 to debug +--*/ +#ifndef DEBUG +#define DEBUG 0 +#endif + + +/*---------------------------------------------------*/ +/*--- ---*/ +/*---------------------------------------------------*/ + +/*-- + Implementation notes, July 1997 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Memory allocation + ~~~~~~~~~~~~~~~~~ + All large data structures are allocated on the C heap, + for better or for worse. That includes the various + arrays of pointers, striped words, bytes, frequency + tables and buffers for compression and decompression. + + bzip2 can operate at various block-sizes, ranging from + 100k to 900k in 100k steps, and it allocates only as + much as it needs to. When compressing, we know from the + command-line options what the block-size is going to be, + so all allocation can be done at start-up; if that + succeeds, there can be no further allocation problems. + + Decompression is more complicated. Each compressed file + contains, in its header, a byte indicating the block + size used for compression. This means bzip2 potentially + needs to reallocate memory for each file it deals with, + which in turn opens the possibility for a memory allocation + failure part way through a run of files, by encountering + a file requiring a much larger block size than all the + ones preceding it. + + The policy is to simply give up if a memory allocation + failure occurs. During decompression, it would be + possible to move on to subsequent files in the hope that + some might ask for a smaller block size, but the + complications for doing this seem more trouble than they + are worth. + + + Compressed file formats + ~~~~~~~~~~~~~~~~~~~~~~~ + [This is now entirely different from both 0.21, and from + any previous Huffman-coded variant of bzip. + See the associated file bzip2.txt for details.] + + + Error conditions + ~~~~~~~~~~~~~~~~ + Dealing with error conditions is the least satisfactory + aspect of bzip2. The policy is to try and leave the + filesystem in a consistent state, then quit, even if it + means not processing some of the files mentioned in the + command line. `A consistent state' means that a file + exists either in its compressed or uncompressed form, + but not both. This boils down to the rule `delete the + output file if an error condition occurs, leaving the + input intact'. Input files are only deleted when we can + be pretty sure the output file has been written and + closed successfully. + + Errors are a dog because there's so many things to + deal with. The following can happen mid-file, and + require cleaning up. + + internal `panics' -- indicating a bug + corrupted or inconsistent compressed file + can't allocate enough memory to decompress this file + I/O error reading/writing/opening/closing + signal catches -- Control-C, SIGTERM, SIGHUP. + + Other conditions, primarily pertaining to file names, + can be checked in-between files, which makes dealing + with them easier. +--*/ + + + +/*---------------------------------------------------*/ +/*--- Misc (file handling) data decls ---*/ +/*---------------------------------------------------*/ + +static UInt32 bytesIn, bytesOut; +static Int32 verbosity; +static Bool smallMode; +static UInt32 globalCrc; + + + + +static void panic ( Char* ); +static void ioError ( void ); +static void uncompressOutOfMemory ( Int32, Int32 ); +static void blockOverrun ( void ); +static void badBlockHeader ( void ); +static void crcError ( UInt32, UInt32 ); +static void cleanUpAndFail ( Int32 ); +static void compressedStreamEOF ( void ); + + + +/*---------------------------------------------------*/ +/*--- Data decls for the front end ---*/ +/*---------------------------------------------------*/ + +/*-- + The overshoot bytes allow us to avoid most of + the cost of pointer renormalisation during + comparison of rotations in sorting. + The figure of 20 is derived as follows: + qSort3 allows an overshoot of up to 10. + It then calls simpleSort, which calls + fullGtU, also with max overshoot 10. + fullGtU does up to 10 comparisons without + renormalising, giving 10+10 == 20. +--*/ +#define NUM_OVERSHOOT_BYTES 20 + +/*-- + These are the main data structures for + the Burrows-Wheeler transform. +--*/ + +/*-- + Pointers to compression and decompression + structures. Set by + allocateCompressStructures and + setDecompressStructureSizes + + The structures are always set to be suitable + for a block of size 100000 * blockSize100k. +--*/ +static UInt16 *ll16; /*-- small decompress --*/ +static UChar *ll4; /*-- small decompress --*/ + +static Int32 *tt; /*-- fast decompress --*/ +static UChar *ll8; /*-- fast decompress --*/ + + +/*-- + freq table collected to save a pass over the data + during decompression. +--*/ +static Int32 unzftab[256]; + + +/*-- + index of the last char in the block, so + the block size == last + 1. +--*/ +static Int32 last; + + +/*-- + index in zptr[] of original string after sorting. +--*/ +static Int32 origPtr; + + +/*-- + always: in the range 0 .. 9. + The current block size is 100000 * this number. +--*/ +static Int32 blockSize100k; + + +/*-- + Used when sorting. If too many long comparisons + happen, we stop sorting, randomise the block + slightly, and try again. +--*/ + +static Bool blockRandomised; + + + +/*---------------------------------------------------*/ +/*--- Data decls for the back end ---*/ +/*---------------------------------------------------*/ + +#define MAX_ALPHA_SIZE 258 +#define MAX_CODE_LEN 23 + +#define RUNA 0 +#define RUNB 1 + +#define N_GROUPS 6 +#define G_SIZE 50 +#define N_ITERS 4 + +#define MAX_SELECTORS (2 + (900000 / G_SIZE)) + +static Bool inUse[256]; +static Int32 nInUse; + +static UChar seqToUnseq[256]; +static UChar unseqToSeq[256]; + +static UChar selector [MAX_SELECTORS]; +static UChar selectorMtf[MAX_SELECTORS]; + +static UChar len [N_GROUPS][MAX_ALPHA_SIZE]; + +/*-- decompress only --*/ +static Int32 limit [N_GROUPS][MAX_ALPHA_SIZE]; +static Int32 base [N_GROUPS][MAX_ALPHA_SIZE]; +static Int32 perm [N_GROUPS][MAX_ALPHA_SIZE]; +static Int32 minLens[N_GROUPS]; + + +/*---------------------------------------------------*/ +/*--- 32-bit CRC grunge ---*/ +/*---------------------------------------------------*/ + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +static UInt32 crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000UL, 0x04c11db7UL, 0x09823b6eUL, 0x0d4326d9UL, + 0x130476dcUL, 0x17c56b6bUL, 0x1a864db2UL, 0x1e475005UL, + 0x2608edb8UL, 0x22c9f00fUL, 0x2f8ad6d6UL, 0x2b4bcb61UL, + 0x350c9b64UL, 0x31cd86d3UL, 0x3c8ea00aUL, 0x384fbdbdUL, + 0x4c11db70UL, 0x48d0c6c7UL, 0x4593e01eUL, 0x4152fda9UL, + 0x5f15adacUL, 0x5bd4b01bUL, 0x569796c2UL, 0x52568b75UL, + 0x6a1936c8UL, 0x6ed82b7fUL, 0x639b0da6UL, 0x675a1011UL, + 0x791d4014UL, 0x7ddc5da3UL, 0x709f7b7aUL, 0x745e66cdUL, + 0x9823b6e0UL, 0x9ce2ab57UL, 0x91a18d8eUL, 0x95609039UL, + 0x8b27c03cUL, 0x8fe6dd8bUL, 0x82a5fb52UL, 0x8664e6e5UL, + 0xbe2b5b58UL, 0xbaea46efUL, 0xb7a96036UL, 0xb3687d81UL, + 0xad2f2d84UL, 0xa9ee3033UL, 0xa4ad16eaUL, 0xa06c0b5dUL, + 0xd4326d90UL, 0xd0f37027UL, 0xddb056feUL, 0xd9714b49UL, + 0xc7361b4cUL, 0xc3f706fbUL, 0xceb42022UL, 0xca753d95UL, + 0xf23a8028UL, 0xf6fb9d9fUL, 0xfbb8bb46UL, 0xff79a6f1UL, + 0xe13ef6f4UL, 0xe5ffeb43UL, 0xe8bccd9aUL, 0xec7dd02dUL, + 0x34867077UL, 0x30476dc0UL, 0x3d044b19UL, 0x39c556aeUL, + 0x278206abUL, 0x23431b1cUL, 0x2e003dc5UL, 0x2ac12072UL, + 0x128e9dcfUL, 0x164f8078UL, 0x1b0ca6a1UL, 0x1fcdbb16UL, + 0x018aeb13UL, 0x054bf6a4UL, 0x0808d07dUL, 0x0cc9cdcaUL, + 0x7897ab07UL, 0x7c56b6b0UL, 0x71159069UL, 0x75d48ddeUL, + 0x6b93dddbUL, 0x6f52c06cUL, 0x6211e6b5UL, 0x66d0fb02UL, + 0x5e9f46bfUL, 0x5a5e5b08UL, 0x571d7dd1UL, 0x53dc6066UL, + 0x4d9b3063UL, 0x495a2dd4UL, 0x44190b0dUL, 0x40d816baUL, + 0xaca5c697UL, 0xa864db20UL, 0xa527fdf9UL, 0xa1e6e04eUL, + 0xbfa1b04bUL, 0xbb60adfcUL, 0xb6238b25UL, 0xb2e29692UL, + 0x8aad2b2fUL, 0x8e6c3698UL, 0x832f1041UL, 0x87ee0df6UL, + 0x99a95df3UL, 0x9d684044UL, 0x902b669dUL, 0x94ea7b2aUL, + 0xe0b41de7UL, 0xe4750050UL, 0xe9362689UL, 0xedf73b3eUL, + 0xf3b06b3bUL, 0xf771768cUL, 0xfa325055UL, 0xfef34de2UL, + 0xc6bcf05fUL, 0xc27dede8UL, 0xcf3ecb31UL, 0xcbffd686UL, + 0xd5b88683UL, 0xd1799b34UL, 0xdc3abdedUL, 0xd8fba05aUL, + 0x690ce0eeUL, 0x6dcdfd59UL, 0x608edb80UL, 0x644fc637UL, + 0x7a089632UL, 0x7ec98b85UL, 0x738aad5cUL, 0x774bb0ebUL, + 0x4f040d56UL, 0x4bc510e1UL, 0x46863638UL, 0x42472b8fUL, + 0x5c007b8aUL, 0x58c1663dUL, 0x558240e4UL, 0x51435d53UL, + 0x251d3b9eUL, 0x21dc2629UL, 0x2c9f00f0UL, 0x285e1d47UL, + 0x36194d42UL, 0x32d850f5UL, 0x3f9b762cUL, 0x3b5a6b9bUL, + 0x0315d626UL, 0x07d4cb91UL, 0x0a97ed48UL, 0x0e56f0ffUL, + 0x1011a0faUL, 0x14d0bd4dUL, 0x19939b94UL, 0x1d528623UL, + 0xf12f560eUL, 0xf5ee4bb9UL, 0xf8ad6d60UL, 0xfc6c70d7UL, + 0xe22b20d2UL, 0xe6ea3d65UL, 0xeba91bbcUL, 0xef68060bUL, + 0xd727bbb6UL, 0xd3e6a601UL, 0xdea580d8UL, 0xda649d6fUL, + 0xc423cd6aUL, 0xc0e2d0ddUL, 0xcda1f604UL, 0xc960ebb3UL, + 0xbd3e8d7eUL, 0xb9ff90c9UL, 0xb4bcb610UL, 0xb07daba7UL, + 0xae3afba2UL, 0xaafbe615UL, 0xa7b8c0ccUL, 0xa379dd7bUL, + 0x9b3660c6UL, 0x9ff77d71UL, 0x92b45ba8UL, 0x9675461fUL, + 0x8832161aUL, 0x8cf30badUL, 0x81b02d74UL, 0x857130c3UL, + 0x5d8a9099UL, 0x594b8d2eUL, 0x5408abf7UL, 0x50c9b640UL, + 0x4e8ee645UL, 0x4a4ffbf2UL, 0x470cdd2bUL, 0x43cdc09cUL, + 0x7b827d21UL, 0x7f436096UL, 0x7200464fUL, 0x76c15bf8UL, + 0x68860bfdUL, 0x6c47164aUL, 0x61043093UL, 0x65c52d24UL, + 0x119b4be9UL, 0x155a565eUL, 0x18197087UL, 0x1cd86d30UL, + 0x029f3d35UL, 0x065e2082UL, 0x0b1d065bUL, 0x0fdc1becUL, + 0x3793a651UL, 0x3352bbe6UL, 0x3e119d3fUL, 0x3ad08088UL, + 0x2497d08dUL, 0x2056cd3aUL, 0x2d15ebe3UL, 0x29d4f654UL, + 0xc5a92679UL, 0xc1683bceUL, 0xcc2b1d17UL, 0xc8ea00a0UL, + 0xd6ad50a5UL, 0xd26c4d12UL, 0xdf2f6bcbUL, 0xdbee767cUL, + 0xe3a1cbc1UL, 0xe760d676UL, 0xea23f0afUL, 0xeee2ed18UL, + 0xf0a5bd1dUL, 0xf464a0aaUL, 0xf9278673UL, 0xfde69bc4UL, + 0x89b8fd09UL, 0x8d79e0beUL, 0x803ac667UL, 0x84fbdbd0UL, + 0x9abc8bd5UL, 0x9e7d9662UL, 0x933eb0bbUL, 0x97ffad0cUL, + 0xafb010b1UL, 0xab710d06UL, 0xa6322bdfUL, 0xa2f33668UL, + 0xbcb4666dUL, 0xb8757bdaUL, 0xb5365d03UL, 0xb1f740b4UL +}; + + +/*---------------------------------------------*/ + +static void initialiseCRC ( void ) +{ + globalCrc = 0xffffffffUL; +} + + +/*---------------------------------------------*/ + +static UInt32 getFinalCRC ( void ) +{ + return ~globalCrc; +} + + +/*---------------------------------------------*/ + +static UInt32 getGlobalCRC ( void ) +{ + return globalCrc; +} + + +/*---------------------------------------------*/ + +static void setGlobalCRC ( UInt32 newCrc ) +{ + globalCrc = newCrc; +} + + +/*---------------------------------------------*/ + +#define UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + + +static UInt32 bsBuff; +static Int32 bsLive; +static void* bsStream; +static Bool bsWriting; + + +/*---------------------------------------------*/ + +static void bsSetStream ( void* f, Bool wr ) +{ + if (bsStream != NULL) panic ( "bsSetStream" ); + bsStream = f; + bsLive = 0; + bsBuff = 0; + bytesOut = 0; + bytesIn = 0; + bsWriting = wr; +} + + +/*---------------------------------------------*/ + +static void bsFinishedWithStream ( void ) +{ + if (bsWriting) + while (bsLive > 0) { + bz2_putc ( (UChar)(bsBuff >> 24), bsStream ); + bsBuff <<= 8; + bsLive -= 8; + bytesOut++; + } + bsStream = NULL; +} + + +/*---------------------------------------------*/ + +#define bsNEEDR(nz) \ +{ \ + while (bsLive < nz) { \ + Int32 zzi = bz2_getc ( bsStream ); \ + if (zzi == EOF) compressedStreamEOF(); \ + bsBuff = (bsBuff << 8) | (zzi & 0xffL); \ + bsLive += 8; \ + } \ +} + + +/*---------------------------------------------*/ + +#define bsR1(vz) \ +{ \ + bsNEEDR(1); \ + vz = (bsBuff >> (bsLive-1)) & 1; \ + bsLive--; \ +} + + +/*---------------------------------------------*/ + +static INLINE UInt32 bsR ( Int32 n ) +{ + UInt32 v; + bsNEEDR ( n ); + v = (bsBuff >> (bsLive-n)) & ((1 << n)-1); + bsLive -= n; + return v; +} + + +/*---------------------------------------------*/ + +static UChar bsGetUChar ( void ) +{ + return (UChar)bsR(8); +} + + + +/*---------------------------------------------*/ + +static Int32 bsGetUInt32 ( void ) +{ + UInt32 u; + u = 0; + u = (u << 8) | bsR(8); + u = (u << 8) | bsR(8); + u = (u << 8) | bsR(8); + u = (u << 8) | bsR(8); + return u; +} + + +/*---------------------------------------------*/ + +static UInt32 bsGetIntVS ( UInt32 numBits ) +{ + return (UInt32)bsR(numBits); +} + + + +/*---------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------*/ + +static void hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + + +/*---------------------------------------------------*/ +/*--- Undoing the reversible transformation ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + ll4[(i) >> 1] = (ll4[(i) >> 1] & 0xf0) | (n); else \ + ll4[(i) >> 1] = (ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + + +#define GET_LL4(i) \ + (((UInt32)(ll4[(i) >> 1])) >> (((i) << 2) & 0x4) & 0xF) + + +#define SET_LL(i,n) \ + { ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + + +#define GET_LL(i) \ + (((UInt32)ll16[i]) | (GET_LL4(i) << 16)) + + +/*---------------------------------------------*/ +/*-- + Manage memory for compression/decompression. + When compressing, a single block size applies to + all files processed, and that's set when the + program starts. But when decompressing, each file + processed could have been compressed with a + different block size, so we may have to free + and reallocate on a per-file basis. + + A call with argument of zero means + `free up everything.' And a value of zero for + blockSize100k means no memory is currently allocated. +--*/ + + +/*---------------------------------------------*/ + +static void setDecompressStructureSizes ( Int32 newSize100k ) +{ + if (! (0 <= newSize100k && newSize100k <= 9 && + 0 <= blockSize100k && blockSize100k <= 9)) + panic ( "setDecompressStructureSizes" ); + + if (newSize100k == blockSize100k) return; + + blockSize100k = newSize100k; + + if (ll16 != NULL) free ( ll16 ); + if (ll4 != NULL) free ( ll4 ); + if (ll8 != NULL) free ( ll8 ); + if (tt != NULL) free ( tt ); + + if (newSize100k == 0) return; + + if (smallMode) { + + Int32 n = 100000 * newSize100k; + ll16 = malloc ( n * sizeof(UInt16) ); + ll4 = malloc ( ((n+1) >> 1) * sizeof(UChar) ); + + if (ll4 == NULL || ll16 == NULL) { + Int32 totalDraw + = n * sizeof(Int16) + ((n+1) >> 1) * sizeof(UChar); + uncompressOutOfMemory ( totalDraw, n ); + } + + } else { + + Int32 n = 100000 * newSize100k; + ll8 = malloc ( n * sizeof(UChar) ); + tt = malloc ( n * sizeof(Int32) ); + + if (ll8 == NULL || tt == NULL) { + Int32 totalDraw + = n * sizeof(UChar) + n * sizeof(UInt32); + uncompressOutOfMemory ( totalDraw, n ); + } + + } +} + + + +/*---------------------------------------------------*/ +/*--- The new back end ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ + +static void makeMaps ( void ) +{ + Int32 i; + nInUse = 0; + for (i = 0; i < 256; i++) + if (inUse[i]) { + seqToUnseq[nInUse] = i; + unseqToSeq[i] = nInUse; + nInUse++; + } +} + + + +/*---------------------------------------------*/ + +static void recvDecodingTables ( void ) +{ + Int32 i, j, t, nGroups, nSelectors, alphaSize; + Int32 minLen, maxLen; + Bool inUse16[16]; + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) + if (bsR(1) == 1) + inUse16[i] = True; else + inUse16[i] = False; + + for (i = 0; i < 256; i++) inUse[i] = False; + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) + if (bsR(1) == 1) inUse[i * 16 + j] = True; + + makeMaps(); + alphaSize = nInUse+2; + + /*--- Now the selectors ---*/ + nGroups = bsR ( 3 ); + nSelectors = bsR ( 15 ); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (bsR(1) == 1) j++; + selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + Int32 curr = bsR ( 5 ); + for (i = 0; i < alphaSize; i++) { + while (bsR(1) == 1) { + if (bsR(1) == 0) curr++; else curr--; + } + len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (len[t][i] > maxLen) maxLen = len[t][i]; + if (len[t][i] < minLen) minLen = len[t][i]; + } + hbCreateDecodeTables ( + &limit[t][0], &base[t][0], &perm[t][0], &len[t][0], + minLen, maxLen, alphaSize + ); + minLens[t] = minLen; + } +} + + +/*---------------------------------------------*/ + +#define GET_MTF_VAL(lval) \ +{ \ + Int32 zt, zn, zvec, zj; \ + if (groupPos == 0) { \ + groupNo++; \ + groupPos = G_SIZE; \ + } \ + groupPos--; \ + zt = selector[groupNo]; \ + zn = minLens[zt]; \ + zvec = bsR ( zn ); \ + while (zvec > limit[zt][zn]) { \ + zn++; bsR1(zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + lval = perm[zt][zvec - base[zt][zn]]; \ +} + + +/*---------------------------------------------*/ + +static void getAndMoveToFrontDecode ( void ) +{ + UChar yy[256]; + Int32 i, j, nextSym, limitLast; + Int32 EOB, groupNo, groupPos; + + limitLast = 100000 * blockSize100k; + origPtr = bsGetIntVS ( 24 ); + + recvDecodingTables(); + EOB = nInUse+1; + groupNo = -1; + groupPos = 0; + + /*-- + Setting up the unzftab entries here is not strictly + necessary, but it does save having to do it later + in a separate pass, and so saves a block's worth of + cache misses. + --*/ + for (i = 0; i <= 255; i++) unzftab[i] = 0; + + for (i = 0; i <= 255; i++) yy[i] = (UChar) i; + + last = -1; + + GET_MTF_VAL(nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == RUNA || nextSym == RUNB) { + UChar ch; + Int32 s = -1; + Int32 N = 1; + do { + if (nextSym == RUNA) s = s + (0+1) * N; else + if (nextSym == RUNB) s = s + (1+1) * N; + N = N * 2; + GET_MTF_VAL(nextSym); + } + while (nextSym == RUNA || nextSym == RUNB); + + s++; + ch = seqToUnseq[yy[0]]; + unzftab[ch] += s; + + if (smallMode) + while (s > 0) { + last++; + ll16[last] = ch; + s--; + } + else + while (s > 0) { + last++; + ll8[last] = ch; + s--; + }; + + if (last >= limitLast) blockOverrun(); + continue; + + } else { + + UChar tmp; + last++; if (last >= limitLast) blockOverrun(); + + tmp = yy[nextSym-1]; + unzftab[seqToUnseq[tmp]]++; + if (smallMode) + ll16[last] = seqToUnseq[tmp]; else + ll8[last] = seqToUnseq[tmp]; + + /*-- + This loop is hammered during decompression, + hence the unrolling. + + for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1]; + --*/ + + j = nextSym-1; + for (; j > 3; j -= 4) { + yy[j] = yy[j-1]; + yy[j-1] = yy[j-2]; + yy[j-2] = yy[j-3]; + yy[j-3] = yy[j-4]; + } + for (; j > 0; j--) yy[j] = yy[j-1]; + + yy[0] = tmp; + GET_MTF_VAL(nextSym); + continue; + } + } +} + + +/*---------------------------------------------------*/ +/*--- Stuff for randomising repetitive blocks ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ +static Int32 rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +#define RAND_DECLS \ + Int32 rNToGo = 0; \ + Int32 rTPos = 0; \ + +#define RAND_MASK ((rNToGo == 1) ? 1 : 0) + +#define RAND_UPD_MASK \ + if (rNToGo == 0) { \ + rNToGo = rNums[rTPos]; \ + rTPos++; if (rTPos == 512) rTPos = 0; \ + } \ + rNToGo--; + + + +/*---------------------------------------------------*/ +/*--- The Reversible Transformation (tm) ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ + + +static INLINE Int32 indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + + +#define GET_SMALL(cccc) \ + \ + cccc = indexIntoF ( tPos, cftab ); \ + tPos = GET_LL(tPos); + + + +static void undoReversibleTransformation_small ( void* dst ) +{ + Int32 cftab[257], cftabAlso[257]; + Int32 i, j, tmp, tPos; + UChar ch; + + /*-- + We assume here that the global array unzftab will + already be holding the frequency counts for + ll8[0 .. last]. + --*/ + + /*-- Set up cftab to facilitate generation of indexIntoF --*/ + cftab[0] = 0; + for (i = 1; i <= 256; i++) cftab[i] = unzftab[i-1]; + for (i = 1; i <= 256; i++) cftab[i] += cftab[i-1]; + + /*-- Make a copy of it, used in generation of T --*/ + for (i = 0; i <= 256; i++) cftabAlso[i] = cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i <= last; i++) { + ch = (UChar)ll16[i]; + SET_LL(i, cftabAlso[ch]); + cftabAlso[ch]++; + } + + /*-- + Compute T^(-1) by pointer reversal on T. This is rather + subtle, in that, if the original block was two or more + (in general, N) concatenated copies of the same thing, + the T vector will consist of N cycles, each of length + blocksize / N, and decoding will involve traversing one + of these cycles N times. Which particular cycle doesn't + matter -- they are all equivalent. The tricky part is to + make sure that the pointer reversal creates a correct + reversed cycle for us to traverse. So, the code below + simply reverses whatever cycle origPtr happens to fall into, + without regard to the cycle length. That gives one reversed + cycle, which for normal blocks, is the entire block-size long. + For repeated blocks, it will be interspersed with the other + N-1 non-reversed cycles. Providing that the F-subscripting + phase which follows starts at origPtr, all then works ok. + --*/ + i = origPtr; + j = GET_LL(i); + do { + tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != origPtr); + + /*-- + We recreate the original by subscripting F through T^(-1). + The run-length-decoder below requires characters incrementally, + so tPos is set to a starting value, and is updated by + the GET_SMALL macro. + --*/ + tPos = origPtr; + + /*-------------------------------------------------*/ + /*-- + This is pretty much a verbatim copy of the + run-length decoder present in the distribution + bzip-0.21; it has to be here to avoid creating + block[] as an intermediary structure. As in 0.21, + this code derives from some sent to me by + Christian von Roques. + + It allows dst==NULL, so as to support the test (-t) + option without slowing down the fast decompression + code. + --*/ + { + IntNative retVal; + Int32 i2, count, chPrev, ch2; + UInt32 localCrc; + + count = 0; + i2 = 0; + ch2 = 256; /*-- not a char and not EOF --*/ + localCrc = getGlobalCRC(); + + { + RAND_DECLS; + while ( i2 <= last ) { + chPrev = ch2; + GET_SMALL(ch2); + if (blockRandomised) { + RAND_UPD_MASK; + ch2 ^= (UInt32)RAND_MASK; + } + i2++; + + if (dst) + retVal = bz2_putc ( ch2, dst ); + + UPDATE_CRC ( localCrc, (UChar)ch2 ); + + if (ch2 != chPrev) { + count = 1; + } else { + count++; + if (count >= 4) { + Int32 j2; + UChar z; + GET_SMALL(z); + if (blockRandomised) { + RAND_UPD_MASK; + z ^= RAND_MASK; + } + for (j2 = 0; j2 < (Int32)z; j2++) { + if (dst) retVal = bz2_putc (ch2, dst); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + } + i2++; + count = 0; + } + } + } + } + + setGlobalCRC ( localCrc ); + } + /*-- end of the in-line run-length-decoder. --*/ +} +#undef GET_SMALL + + +/*---------------------------------------------*/ + +#define GET_FAST(cccc) \ + \ + cccc = ll8[tPos]; \ + tPos = tt[tPos]; + + + +static void undoReversibleTransformation_fast ( void* dst ) +{ + Int32 cftab[257]; + Int32 i, tPos; + UChar ch; + + /*-- + We assume here that the global array unzftab will + already be holding the frequency counts for + ll8[0 .. last]. + --*/ + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + cftab[0] = 0; + for (i = 1; i <= 256; i++) cftab[i] = unzftab[i-1]; + for (i = 1; i <= 256; i++) cftab[i] += cftab[i-1]; + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i <= last; i++) { + ch = (UChar)ll8[i]; + tt[cftab[ch]] = i; + cftab[ch]++; + } + + /*-- + We recreate the original by subscripting L through T^(-1). + The run-length-decoder below requires characters incrementally, + so tPos is set to a starting value, and is updated by + the GET_FAST macro. + --*/ + tPos = tt[origPtr]; + + /*-------------------------------------------------*/ + /*-- + This is pretty much a verbatim copy of the + run-length decoder present in the distribution + bzip-0.21; it has to be here to avoid creating + block[] as an intermediary structure. As in 0.21, + this code derives from some sent to me by + Christian von Roques. + --*/ + { + IntNative retVal; + Int32 i2, count, chPrev, ch2; + UInt32 localCrc; + + count = 0; + i2 = 0; + ch2 = 256; /*-- not a char and not EOF --*/ + localCrc = getGlobalCRC(); + + if (blockRandomised) { + RAND_DECLS; + while ( i2 <= last ) { + chPrev = ch2; + GET_FAST(ch2); + RAND_UPD_MASK; + ch2 ^= (UInt32)RAND_MASK; + i2++; + + retVal = bz2_putc ( ch2, dst ); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + + if (ch2 != chPrev) { + count = 1; + } else { + count++; + if (count >= 4) { + Int32 j2; + UChar z; + GET_FAST(z); + RAND_UPD_MASK; + z ^= RAND_MASK; + for (j2 = 0; j2 < (Int32)z; j2++) { + retVal = bz2_putc (ch2, dst); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + } + i2++; + count = 0; + } + } + } + + } else { + + while ( i2 <= last ) { + chPrev = ch2; + GET_FAST(ch2); + i2++; + + retVal = bz2_putc ( ch2, dst ); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + + if (ch2 != chPrev) { + count = 1; + } else { + count++; + if (count >= 4) { + Int32 j2; + UChar z; + GET_FAST(z); + for (j2 = 0; j2 < (Int32)z; j2++) { + retVal = bz2_putc (ch2, dst); + UPDATE_CRC ( localCrc, (UChar)ch2 ); + } + i2++; + count = 0; + } + } + } + + } /*-- if (blockRandomised) --*/ + + setGlobalCRC ( localCrc ); + } + /*-- end of the in-line run-length-decoder. --*/ +} +#undef GET_FAST + + + +/*---------------------------------------------------*/ +/*--- Processing of complete files and streams ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------*/ + +static Bool uncompressStream ( void *zStream, void *stream ) +{ + UChar magic1, magic2, magic3, magic4; + UChar magic5, magic6; + UInt32 storedBlockCRC, storedCombinedCRC; + UInt32 computedBlockCRC, computedCombinedCRC; + Int32 currBlockNo; + IntNative retVal; + + SET_BINARY_MODE(stream); + SET_BINARY_MODE(zStream); + + ERROR_IF_NOT_ZERO ( bz2_ferror(stream) ); + ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) ); + + bsSetStream ( zStream, False ); + + /*-- + A bad magic number is `recoverable from'; + return with False so the caller skips the file. + --*/ + magic1 = bsGetUChar (); + magic2 = bsGetUChar (); + magic3 = bsGetUChar (); + magic4 = bsGetUChar (); + if (magic1 != 'B' || + magic2 != 'Z' || + magic3 != 'h' || + magic4 < '1' || + magic4 > '9') { + bsFinishedWithStream(); + retVal = bz2_fclose ( stream ); + ERROR_IF_EOF ( retVal ); + return False; + } + + setDecompressStructureSizes ( magic4 - '0' ); + computedCombinedCRC = 0; + + if (verbosity >= 2) fprintf ( stderr, "\n " ); + currBlockNo = 0; + + while (True) { + magic1 = bsGetUChar (); + magic2 = bsGetUChar (); + magic3 = bsGetUChar (); + magic4 = bsGetUChar (); + magic5 = bsGetUChar (); + magic6 = bsGetUChar (); + if (magic1 == 0x17 && magic2 == 0x72 && + magic3 == 0x45 && magic4 == 0x38 && + magic5 == 0x50 && magic6 == 0x90) break; + + if (magic1 != 0x31 || magic2 != 0x41 || + magic3 != 0x59 || magic4 != 0x26 || + magic5 != 0x53 || magic6 != 0x59) badBlockHeader(); + + storedBlockCRC = bsGetUInt32 (); + + if (bsR(1) == 1) + blockRandomised = True; else + blockRandomised = False; + + currBlockNo++; + if (verbosity >= 2) + fprintf ( stderr, "[%d: huff+mtf ", currBlockNo ); + getAndMoveToFrontDecode (); + ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) ); + + initialiseCRC(); + if (verbosity >= 2) fprintf ( stderr, "rt+rld" ); + if (smallMode) + undoReversibleTransformation_small ( stream ); + else + undoReversibleTransformation_fast ( stream ); + + ERROR_IF_NOT_ZERO ( bz2_ferror(stream) ); + + computedBlockCRC = getFinalCRC(); + if (verbosity >= 3) + fprintf ( stderr, " {0x%x, 0x%x}", storedBlockCRC, computedBlockCRC ); + if (verbosity >= 2) fprintf ( stderr, "] " ); + + /*-- A bad CRC is considered a fatal error. --*/ + if (storedBlockCRC != computedBlockCRC) + crcError ( storedBlockCRC, computedBlockCRC ); + + computedCombinedCRC = (computedCombinedCRC << 1) | (computedCombinedCRC >> 31); + computedCombinedCRC ^= computedBlockCRC; + }; + + if (verbosity >= 2) fprintf ( stderr, "\n " ); + + storedCombinedCRC = bsGetUInt32 (); + if (verbosity >= 2) + fprintf ( stderr, + "combined CRCs: stored = 0x%x, computed = 0x%x\n ", + storedCombinedCRC, computedCombinedCRC ); + if (storedCombinedCRC != computedCombinedCRC) + crcError ( storedCombinedCRC, computedCombinedCRC ); + + + bsFinishedWithStream (); + ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) ); + retVal = bz2_fclose ( zStream ); + ERROR_IF_EOF ( retVal ); + + ERROR_IF_NOT_ZERO ( bz2_ferror(stream) ); + retVal = bz2_fflush ( stream ); + ERROR_IF_NOT_ZERO ( retVal ); + return True; +} + + +#if 0 + +#endif +/*---------------------------------------------------*/ +/*--- Error [non-] handling grunge ---*/ +/*---------------------------------------------------*/ + + + +static void +myFree (void **p) +{ + free (*p); + *p = NULL; +} + +/*---------------------------------------------*/ +/* Ugg... Orignal code doesn't free dynamic allocated memories. */ + +static void cleanUpAndFail ( Int32 ec ) +{ + myFree ((void **) &ll16); + myFree ((void **) &ll4); + myFree ((void **) &ll8); + myFree ((void **) &tt); + + (*unzip_error) (NULL); +} + + +/*---------------------------------------------*/ + +static void panic ( Char* s ) +{ + cleanUpAndFail( 3 ); +} + + + +/*---------------------------------------------*/ + +static void crcError ( UInt32 crcStored, UInt32 crcComputed ) +{ + cleanUpAndFail( 2 ); +} + + +/*---------------------------------------------*/ + +static void compressedStreamEOF ( void ) +{ + cleanUpAndFail( 2 ); +} + + +/*---------------------------------------------*/ + +static void ioError ( ) +{ + cleanUpAndFail( 1 ); +} + + +/*---------------------------------------------*/ + +static void blockOverrun () +{ + cleanUpAndFail( 2 ); +} + + +/*---------------------------------------------*/ + +static void badBlockHeader () +{ + cleanUpAndFail( 2 ); +} + + + +/*---------------------------------------------*/ +static void uncompressOutOfMemory ( Int32 draw, Int32 blockSize ) +{ + cleanUpAndFail(1); +} + + + +/*-----------------------------------------------------------*/ +/*--- end bzip2.c ---*/ +/*-----------------------------------------------------------*/ + +void +do_bunzip2 (void) +{ + Bool ret; + + /*-- Initialise --*/ + ll4 = NULL; + ll16 = NULL; + ll8 = NULL; + tt = NULL; +#ifdef SMALL_BZIP2 + smallMode = True; +#else + smallMode = False; +#endif + verbosity = 0; + blockSize100k = 0; + bsStream = NULL; + + outcnt = 0; + inptr = 0; + insize = 0; + + ret = uncompressStream ((void *)1, (void *)2); /* Arguments ignored. */ + if (ret != True) + cleanUpAndFail(1); +} diff --git a/exec/elfcore.c b/exec/elfcore.c index 4388a135..f953cc76 100644 --- a/exec/elfcore.c +++ b/exec/elfcore.c @@ -1,100 +1,566 @@ +/* Write ELF core dump files for GNU Hurd. + Copyright (C) 2002, 2004, 2008 Free Software Foundation, Inc. + Written by Roland McGrath. + +This file is part of the GNU Hurd. + +The GNU Hurd is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +The GNU Hurd is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <elf.h> +#include <link.h> +#include <string.h> +#include <argz.h> +#include <sys/mman.h> +#include <sys/utsname.h> +#include <sys/procfs.h> +#include <stddef.h> + +#define ELF_CLASS PASTE (ELFCLASS, __ELF_NATIVE_CLASS) +#define PASTE(a, b) PASTE_1 (a, b) +#define PASTE_1(a, b) a##b + +#include <endian.h> +#if BYTE_ORDER == BIG_ENDIAN +#define ELF_DATA ELFDATA2MSB +#elif BYTE_ORDER == LITTLE_ENDIAN +#define ELF_DATA ELFDATA2LSB +#endif + +#include <mach/thread_status.h> +#include <assert.h> + +#ifdef i386_THREAD_STATE +# define ELF_MACHINE EM_386 + +/* The gregset_t format (compatible with Linux/x86) almost fits + the Mach i386_thread_state. */ +static inline void +fetch_thread_regset (thread_t thread, prgregset_t *gregs) +{ + union + { + struct i386_thread_state state; + prgregset_t gregs; + } *u = (void *) gregs; + mach_msg_type_number_t count = i386_THREAD_STATE_COUNT; + assert (sizeof (struct i386_thread_state) < sizeof (prgregset_t)); + assert (offsetof (struct i386_thread_state, gs) == REG_GS * 4); + assert (offsetof (struct i386_thread_state, eax) == REG_EAX * 4); + + (void) thread_get_state (thread, i386_THREAD_STATE, + (thread_state_t) &u->state, &count); + + u->gregs[REG_EIP] = u->state.eip; + u->gregs[REG_CS] = u->state.cs; + u->gregs[REG_EFL] = u->state.efl; + u->gregs[REG_UESP] = u->state.uesp; + u->gregs[REG_SS] = u->state.ss; + + /* These are the extra words that don't exist in prgregset_t. */ + u->gregs[REG_ERR] = u->gregs[REG_TRAPNO] = 0; +} + +static inline void +fetch_thread_fpregset (thread_t thread, prfpregset_t *fpregs) +{ + struct i386_float_state st; + mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT; + error_t err = thread_get_state (thread, i386_FLOAT_STATE, + (thread_state_t) &st, &count); + if (err == 0 && st.initialized) + { + assert (sizeof *fpregs >= sizeof st.hw_state); + memcpy (fpregs, st.hw_state, sizeof st.hw_state); + } +} + +#elif defined ALPHA_THREAD_STATE +# define ELF_MACHINE EM_ALPHA + +/* The gregset_t format (compatible with Linux/Alpha) almost fits + the Mach alpha_thread_state. */ +static inline void +fetch_thread_regset (thread_t thread, prgregset_t *gregs) { - processor_set_name_t pset; - host_t host; - processor_set_basic_info_data_t pinfo; + mach_msg_type_number_t count = ALPHA_THREAD_STATE_COUNT; + assert (sizeof (struct alpha_thread_state) <= sizeof (prgregset_t)); + (void) thread_get_state (thread, ALPHA_THREAD_STATE, + (thread_state_t) gregs, &count); + /* XXX + gregs[32] is process-status word: Mach doesn't return it! + It's already zero'd. + */ +} +/* The FPU state matches exactly. */ +static inline void +fetch_thread_fpregset (thread_t thread, prfpregset_t *fpregs) +{ + mach_msg_type_number_t count = ALPHA_FLOAT_STATE_COUNT; + assert (sizeof (struct alpha_float_state) == sizeof *fpregs); + (void) thread_get_state (thread, ALPHA_FLOAT_STATE, + (thread_state_t) fpregs, &count); +} + +#else +# warning "do not understand this machine flavor, no registers in dumps" +# define ELF_MACHINE EM_NONE +#endif + + +#define TIME_VALUE_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->seconds; \ + (ts)->tv_nsec = (tv)->microseconds * 1000; \ +} + +#define PAGES_TO_KB(x) ((x) * (vm_page_size / 1024)) +#define ENCODE_PCT(f) ((uint16_t) ((f) * 32768.0)) + +extern process_t procserver; /* crash.c */ + +error_t +dump_core (task_t task, file_t file, off_t corelimit, + int signo, long int sigcode, int sigerror) +{ + static float host_memory_size = -1.0; + error_t err; + ElfW(Phdr) *phdrs, *ph; + ElfW(Ehdr) hdr = /* ELF header for the core file. */ + { + e_ident: + { + [EI_MAG0] = ELFMAG0, + [EI_MAG1] = ELFMAG1, + [EI_MAG2] = ELFMAG2, + [EI_MAG3] = ELFMAG3, + [EI_CLASS] = ELF_CLASS, + [EI_DATA] = ELF_DATA, + [EI_VERSION] = EV_CURRENT, + [EI_OSABI] = ELFOSABI_SYSV, + [EI_ABIVERSION] = 0 + }, + e_type: ET_CORE, + e_version: EV_CURRENT, + e_machine: ELF_MACHINE, + e_ehsize: sizeof hdr, + e_phentsize: sizeof phdrs[0], + e_phoff: sizeof hdr, /* Fill in e_phnum later. */ + }; + off_t offset; + size_t wrote; + + pid_t pid; thread_t *threads; - size_t nthreads; - - vm_address_t addr; - vm_size_t size; - vm_prot_t prot, maxprot; - vm_inherit_t inherit; - boolean_t shared; - memory_object_name_t objname; - vm_offset_t offset; - - /* Figure out what flavor of machine the task is on. */ - if (err = task_get_assignment (task, &pset)) - goto lose; - err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host, - &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT); - mach_port_deallocate (mach_task_self (), pset); - if (err) - goto lose; - err = bfd_mach_host_arch_mach (host, &arch, &machine, &e_machine); - mach_port_deallocate (mach_task_self (), host); + size_t nthreads, i; + off_t notestart; + + /* Helper macros for writing notes. */ +#define DEFINE_NOTE(typename) struct { struct note_header hdr; typename data; } +#define WRITE_NOTE(type, var) ({ \ + (var).hdr = NOTE_HEADER ((type), sizeof (var).data); \ + write_note (&(var).hdr); \ +}) + struct note_header + { + ElfW(Nhdr) note; + char name[(sizeof "CORE" + 3) &~ 3]; + } __attribute__ ((packed)); +#define NOTE_HEADER(type, size) \ + ((struct note_header) { { sizeof "CORE", (size), (type) }, "CORE" }) + inline error_t write_note (struct note_header *hdr) + { + error_t err = 0; + char *data = (char *) hdr; + size_t size = sizeof *hdr + hdr->note.n_descsz; + if (corelimit >= 0 && offset + size > corelimit) + size = corelimit - offset; + while (size > 0) + { + err = io_write (file, data, size, offset, &wrote); + if (err) + return err; + if (wrote > size) + return EGRATUITOUS; + data += wrote; + size -= wrote; + } + offset = (offset + wrote + 3) &~ 3; /* Pad it to word alignment. */ + return 0; + } + + struct vm_region_list + { + struct vm_region_list *next; + vm_prot_t protection; + vm_address_t start; + vm_size_t length; + }; + struct vm_region_list *regions = NULL, **tailp = ®ions, *r; + unsigned int nregions = 0; + + if (corelimit >= 0 && corelimit < sizeof hdr) + return EFBIG; + + { + /* Examine the task and record the locations of contiguous memory + segments that we will dump into the core file. */ + + vm_address_t region_address, last_region_address, last_region_end; + vm_prot_t last_protection; +#define RECORD_LAST_REGION do { \ + if (last_region_end > last_region_address \ + && last_protection != VM_PROT_NONE) \ + record_last_region (alloca (sizeof (struct vm_region_list))); } while (0) + inline void record_last_region (struct vm_region_list *region) + { + *tailp = region; + tailp = ®ion->next; + region->next = NULL; + region->start = last_region_address; + region->length = last_region_end - last_region_address; + region->protection = last_protection; + ++nregions; + } + + region_address = last_region_address = last_region_end = VM_MIN_ADDRESS; + last_protection = VM_PROT_NONE; + while (region_address < VM_MAX_ADDRESS) + { + vm_prot_t protection; + vm_prot_t max_protection; + vm_inherit_t inheritance; + boolean_t shared; + mach_port_t object_name; + vm_offset_t offset; + vm_size_t region_length = VM_MAX_ADDRESS - region_address; + + err = vm_region (task, + ®ion_address, + ®ion_length, + &protection, + &max_protection, + &inheritance, + &shared, + &object_name, + &offset); + if (err == KERN_NO_SPACE) + break; + if (err != KERN_SUCCESS) + return err; + + if (protection == last_protection && region_address == last_region_end) + /* This region is contiguous with and indistinguishable from + the previous one, so we just extend that one. */ + last_region_end = region_address += region_length; + else + { + /* This region is distinct from the last one we saw, + so record that previous one. */ + RECORD_LAST_REGION; + last_region_address = region_address; + last_region_end = region_address += region_length; + last_protection = protection; + } + } + /* Record the final region. */ + RECORD_LAST_REGION; + } + + /* Now we start laying out the file. */ + offset = sizeof hdr + ((nregions + 1) * sizeof *phdrs); + + /* Final check for tiny core limit. From now on, we will simply truncate + the file at CORELIMIT but not change the contents of what we write. */ + if (corelimit >= 0 && corelimit < offset) + return EFBIG; + + /* Now we can complete the file header and write it. */ + hdr.e_phnum = nregions + 1; + err = io_write (file, (char *) &hdr, sizeof hdr, 0, &wrote); if (err) - goto lose; + return err; + if (wrote < sizeof hdr) + return EGRATUITOUS; /* XXX */ + + /* Now we can write the various notes. */ + notestart = offset; - if (err = task_threads (task, &threads, &nthreads)) - goto lose; + /* First a dull note containing the results of `uname', a la Solaris. */ + { + DEFINE_NOTE (struct utsname) note; + if (uname (¬e.data) == 0) /* XXX Use proc_uname on task's proc port? */ + err = WRITE_NOTE (NT_UTSNAME, note); + } + if (err || (corelimit >= 0 && corelimit <= offset)) + return err; - /* Create a BFD section to describe each contiguous chunk - of the task's address space with the same stats. */ - sec = NULL; - addr = 0; - while (!vm_region (task, &addr, &size, &prot, &maxprot, - &inherit, &shared, &objname, &offset)) + err = proc_task2pid (procserver, task, &pid); + if (err) + return err; + + /* Make sure we have the total RAM size of the host. + We only do this once, assuming that it won't change. + XXX this could use the task's host-self port instead. */ + if (host_memory_size <= 0.0) { - mach_port_deallocate (mach_task_self (), objname); + host_basic_info_data_t hostinfo; + mach_msg_type_number_t size = sizeof hostinfo; + error_t err = host_info (mach_host_self (), HOST_BASIC_INFO, + (host_info_t) &hostinfo, &size); + if (err == 0) + host_memory_size = hostinfo.memory_size; + } + + /* The psinfo_t note contains some process-global info we should get from + the proc server, but no thread-specific info like register state. */ + { + DEFINE_NOTE (psinfo_t) psinfo; + DEFINE_NOTE (pstatus_t) pstatus; + int flags = PI_FETCH_TASKINFO | PI_FETCH_THREADS | PI_FETCH_THREAD_BASIC; + char *waits = 0; + mach_msg_type_number_t num_waits = 0; + char pibuf[offsetof (struct procinfo, threadinfos[2])]; + struct procinfo *pi = (void *) &pibuf; + mach_msg_type_number_t pi_size = sizeof pibuf; + + memset (&pstatus.data, 0, sizeof pstatus.data); + memset (&psinfo.data, 0, sizeof psinfo.data); + pstatus.data.pr_pid = psinfo.data.pr_pid = pid; + + err = proc_getprocinfo (procserver, pid, &flags, + (procinfo_t *) &pi, &pi_size, + &waits, &num_waits); + if (err == 0) + { + if (num_waits != 0) + munmap (waits, num_waits); + + pstatus.data.pr_flags = psinfo.data.pr_flag = pi->state; + pstatus.data.pr_nlwp = psinfo.data.pr_nlwp = pi->nthreads; + pstatus.data.pr_ppid = psinfo.data.pr_ppid = pi->ppid; + pstatus.data.pr_pgid = psinfo.data.pr_pgid = pi->pgrp; + pstatus.data.pr_sid = psinfo.data.pr_sid = pi->session; + + psinfo.data.pr_euid = pi->owner; + /* XXX struct procinfo should have these */ + psinfo.data.pr_egid = psinfo.data.pr_gid = psinfo.data.pr_uid = -1; + + psinfo.data.pr_size = PAGES_TO_KB (pi->taskinfo.virtual_size); + psinfo.data.pr_rssize = PAGES_TO_KB (pi->taskinfo.resident_size); + + { + /* Sum all the threads' cpu_usage fields. */ + integer_t cpu_usage = 0; + for (i = 0; i < pi->nthreads; ++i) + cpu_usage += pi->threadinfos[i].pis_bi.cpu_usage; + psinfo.data.pr_pctcpu = ENCODE_PCT ((float) cpu_usage + / (float) TH_USAGE_SCALE); + } + if (host_memory_size > 0.0) + psinfo.data.pr_pctmem + = ENCODE_PCT + ((float) pi->taskinfo.resident_size / host_memory_size); + + TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.creation_time, + &psinfo.data.pr_start); - if (prot != VM_PROT_NONE) + TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time, + &pstatus.data.pr_utime); + TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.system_time, + &pstatus.data.pr_stime); + /* Sum the user and system time for pr_time. */ + pi->taskinfo.user_time.seconds += pi->taskinfo.system_time.seconds; + pi->taskinfo.user_time.microseconds += pi->taskinfo.system_time.microseconds; + if (pi->taskinfo.user_time.microseconds >= 1000000) + { + ++pi->taskinfo.user_time.seconds; + pi->taskinfo.user_time.microseconds -= 1000000; + } + TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time, &psinfo.data.pr_time); + /* XXX struct procinfo should have dead child info for pr_c[us]?time */ + + psinfo.data.pr_wstat = pi->exitstatus; + + if ((void *) pi != &pibuf) + munmap (pi, pi_size); + } + if (err == 0) + { + /* We have to nab the process's own proc port to get the + proc server to tell us its registered arg locations. */ + process_t proc; + err = proc_task2proc (procserver, task, &proc); + if (err == 0) + { + err = proc_get_arg_locations (proc, + &psinfo.data.pr_argv, + &psinfo.data.pr_envp); + mach_port_deallocate (mach_task_self (), proc); + } { - flagword flags = SEC_NO_FLAGS; - - if (!(prot & VM_PROT_WRITE)) - flags |= SEC_READONLY; - if (!(prot & VM_PROT_EXECUTE)) - flags |= SEC_DATA; - - if (sec != NULL && - (vm_address_t) (bfd_section_vma (bfd, sec) + - bfd_section_size (bfd, sec)) == addr && - flags == (bfd_get_section_flags (bfd, sec) & - (SEC_READONLY|SEC_DATA))) - /* Coalesce with the previous section. */ - bfd_set_section_size (bfd, sec, - bfd_section_size (bfd, sec) + size); - else + /* Now fetch the arguments. We could do this directly from the + task given the locations we now have. But we are lazy and have + the proc server do it for us. */ + char *data = psinfo.data.pr_psargs; + size_t datalen = sizeof psinfo.data.pr_psargs; + err = proc_getprocargs (procserver, pid, &data, &datalen); + if (err == 0) { - /* Make a new section (which might grow by - the next region being coalesced onto it). */ - char *name = bfd_intuit_section_name (addr, size, &flags); - if (name == NULL) + psinfo.data.pr_argc = argz_count (data, datalen); + argz_stringify (data, datalen, ' '); + if (data != psinfo.data.pr_psargs) { - /* No guess from BFD. */ - if (asprintf (&name, "[%p,%p) %c%c%c", - (void *) addr, (void *) (addr + size), - (prot & VM_PROT_READ) ? 'r' : '-', - (prot & VM_PROT_WRITE) ? 'w' : '-', - (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1) - goto lose; + memcpy (psinfo.data.pr_psargs, data, + sizeof psinfo.data.pr_psargs); + munmap (data, datalen); } - sec = bfd_make_section (name); - bfd_set_section_flags (bfd, sec, flags); - bfd_set_section_vma (bfd, sec, addr); - bfd_set_section_size (bfd, sec, size); } } + err = WRITE_NOTE (NT_PSINFO, psinfo); + } + + err = WRITE_NOTE (NT_PSTATUS, pstatus) ?: err; + } + if (err || (corelimit >= 0 && corelimit <= offset)) + return err; + + /* Now examine all the threads in the task. + For each thread we produce one or more notes. */ + err = task_threads (task, &threads, &nthreads); + if (err) + return err; + for (i = 0; i < nthreads; ++i) + { + DEFINE_NOTE (lwpstatus_t) note; + memset (¬e.data, 0, sizeof note.data); + note.data.pr_lwpid = i; + + /* We have to write the death signal into every thread's record, even + though only one thread really took the signal. This is both because + we don't know which thread it was, and because GDB blindly uses the + value from each record to clobber the last (even if it's zero). */ + note.data.pr_cursig = signo; + note.data.pr_info.si_signo = signo; + note.data.pr_info.si_code = sigcode; + note.data.pr_info.si_errno = sigerror; + + fetch_thread_regset (threads[i], ¬e.data.pr_reg); + fetch_thread_fpregset (threads[i], ¬e.data.pr_fpreg); + + err = WRITE_NOTE (NT_LWPSTATUS, note); + if (err || (corelimit >= 0 && corelimit <= offset)) + break; + + mach_port_deallocate (mach_task_self (), threads[i]); } + /* If we broke out of the loop early, deallocate remaining thread ports. */ + while (i < nthreads) + mach_port_deallocate (mach_task_self (), threads[i++]); + munmap (threads, nthreads * sizeof *threads); + if (err || (corelimit >= 0 && corelimit <= offset)) + return err; - /* Write all the sections' data. */ - for (sec = bfd->sections; sec != NULL; sec = sec->next) + /* Make an array of program headers and fill them in. + The first one describes the note segment. */ + ph = phdrs = alloca ((nregions + 1) * sizeof *phdrs); + + memset (ph, 0, sizeof *ph); + ph->p_type = PT_NOTE; + ph->p_offset = notestart; + ph->p_filesz = offset - notestart; + ++ph; + + /* Now make ELF program headers for each of the recorded memory regions. + Consistent with the Linux kernel, we create PT_LOAD headers with + p_filesz = 0 for the read-only segments that we are not dumping + into the file. */ + for (r = regions; r != NULL; r = r->next) { - void *data; - err = vm_read (task, bfd_section_vma (bfd, sec), - bfd_section_size (bfd, sec), &data); - if (err) - /* XXX What to do? - 1. lose - 2. remove this section - 3. mark this section as having ungettable contents (how?) - */ - goto lose; - err = bfd_set_section_contents (bfd, sec, data, 0, - bfd_section_size (bfd, sec)); - vm_deallocate (mach_task_self (), data, bfd_section_size (bfd, sec)); - if (err) - goto bfdlose; + memset (ph, 0, sizeof *ph); + ph->p_type = PT_LOAD; + ph->p_align = vm_page_size; + ph->p_flags = (((r->protection & VM_PROT_READ) ? PF_R : 0) + | ((r->protection & VM_PROT_WRITE) ? PF_W : 0) + | ((r->protection & VM_PROT_EXECUTE) ? PF_X : 0)); + ph->p_vaddr = r->start; + ph->p_memsz = r->length; + ph->p_filesz = (r->protection & VM_PROT_WRITE) ? ph->p_memsz : 0; + ph->p_offset = round_page (offset); + offset += ph->p_filesz; + ++ph; } + + /* Now write the memory segment data. */ + for (ph = &phdrs[1]; ph < &phdrs[nregions + 1]; ++ph) + if (ph->p_filesz > 0) + { + vm_address_t va = ph->p_vaddr; + vm_size_t sz = ph->p_memsz; + off_t ofs = ph->p_offset; + int wrote_any = 0; + do + { + pointer_t copied; + size_t copy_count; + err = vm_read (task, va, sz, &copied, ©_count); + if (err == 0) + { + char *data = (void *) copied; + size_t left = copy_count, wrote; + + va += copy_count; + sz -= copy_count; + + do + { + if (corelimit >= 0 && ofs + left > corelimit) + left = corelimit - ofs; + err = io_write (file, data, left, ofs, &wrote); + if (err) + break; + ofs += wrote; + data += wrote; + left -= wrote; + if (ofs >= corelimit) + break; + } while (left > 0); + + munmap ((void *) copied, copy_count); + + if (left < copy_count) + wrote_any = 1; + } + else + { + /* Leave a hole in the file for pages we can't read. */ + va += vm_page_size; + sz -= vm_page_size; + ofs += vm_page_size; + } + } while (sz > 0 && (corelimit < 0 || ofs < corelimit)); + + if (! wrote_any) + /* If we failed to write any contents at all, + don't claim the big hole as the contents. */ + ph->p_filesz = 0; + } + + /* Finally, we go back and write the program headers. */ + err = io_write (file, (char *) phdrs, (nregions + 1) * sizeof phdrs[0], + sizeof hdr, &wrote); + + return err; +} diff --git a/exec/exec.c b/exec/exec.c index a9de454a..4c2fcec1 100644 --- a/exec/exec.c +++ b/exec/exec.c @@ -1,5 +1,6 @@ /* GNU Hurd standard exec server. - Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1992,93,94,95,96,98,99,2000,01,02,04 + Free Software Foundation, Inc. Written by Roland McGrath. Can exec ELF format directly. @@ -10,6 +11,9 @@ Can exec any executable format the BFD library understands to be for this flavor of machine. #endif + #ifdef BZIP2 + Can bunzip2 executables into core on the fly. + #endif This file is part of the GNU Hurd. @@ -32,9 +36,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "priv.h" #include <hurd.h> #include <hurd/exec.h> -#include <hurd/shared.h> #include <sys/stat.h> +#include <sys/param.h> #include <unistd.h> +#include <stdbool.h> mach_port_t procserver; /* Our proc port. */ @@ -70,6 +75,10 @@ b2he (error_t deflt) static void check_gzip (struct execdata *); #endif +#ifdef BZIP2 +static void check_bzip2 (struct execdata *); +#endif + #ifdef BFD /* Check a section, updating the `locations' vector [BFD]. */ @@ -132,7 +141,7 @@ load_section (void *section, struct execdata *u) #ifdef BFD asection *const sec = section; #endif - const Elf32_Phdr *const ph = section; + const ElfW(Phdr) *const ph = section; if (u->error) return; @@ -173,6 +182,7 @@ load_section (void *section, struct execdata *u) if (! anywhere) addr += u->info.elf.loadbase; else +#if 0 switch (elf_machine) { case EM_386: @@ -187,6 +197,9 @@ load_section (void *section, struct execdata *u) default: break; } +#endif + if (anywhere && addr < vm_page_size) + addr = vm_page_size; } if (memsz == 0) @@ -214,16 +227,19 @@ load_section (void *section, struct execdata *u) if (! u->error && off != 0) { vm_address_t page = 0; - u->error = vm_allocate (mach_task_self (), - &page, vm_page_size, 1); + page = (vm_address_t) mmap (0, vm_page_size, + PROT_READ|PROT_WRITE, MAP_ANON, + 0, 0); + u->error = (page == -1) ? errno : 0; if (! u->error) { - memcpy ((void *) page, + u->error = hurd_safe_copyin ((void *) page, /* XXX/fault */ (void *) (contents + (size - off)), off); - u->error = vm_write (u->task, mapstart + (size - off), - page, vm_page_size); - vm_deallocate (mach_task_self (), page, vm_page_size); + if (! u->error) + u->error = vm_write (u->task, mapstart + (size - off), + page, vm_page_size); + munmap ((caddr_t) page, vm_page_size); } } /* Reset the current protections to the desired state. */ @@ -256,21 +272,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); - u->error = vm_allocate (mach_task_self (), - (vm_address_t *) &buf, size, 1); - 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); - vm_deallocate (mach_task_self (), (vm_address_t) 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; @@ -308,8 +313,12 @@ load_section (void *section, struct execdata *u) &overlap_page, vm_page_size, 0); size = vm_page_size; if (!u->error) - u->error = vm_allocate (mach_task_self (), - &ourpage, vm_page_size, 1); + { + ourpage = (vm_address_t) mmap (0, vm_page_size, + PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + u->error = (ourpage == -1) ? errno : 0; + } } if (u->error) { @@ -325,14 +334,17 @@ 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; - } + u->error = hurd_safe_copyin (readaddr, contents, + readsize); /* XXX/fault */ + if (u->error) + goto maplose; + } u->error = vm_write (u->task, overlap_page, ourpage, size); if (u->error == KERN_PROTECTION_FAILURE) { @@ -349,7 +361,7 @@ load_section (void *section, struct execdata *u) u->error = vm_protect (u->task, overlap_page, size, 0, vm_prot); } - vm_deallocate (mach_task_self (), ourpage, size); + munmap ((caddr_t) ourpage, size); if (u->error) goto maplose; } @@ -412,15 +424,122 @@ load_section (void *section, struct execdata *u) u->error = vm_write (u->task, overlap_page, ourpage, size); if (! u->error && !(vm_prot & VM_PROT_WRITE)) u->error = vm_protect (u->task, overlap_page, size, 0, vm_prot); - vm_deallocate (mach_task_self (), ourpage, size); + munmap ((caddr_t) ourpage, size); } } } -/* Make sure our mapping window (or read buffer) covers - LEN bytes of the file starting at POSN. */ +/* XXX all accesses of the mapped data need to use fault handling + to abort the RPC when mapped file data generates bad page faults. + I've marked some accesses with XXX/fault comments. + --roland */ -static void * +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 (posn + len > size) + /* The requested data wouldn't fit in the file. */ + return NULL; + else if (e->file_data != NULL) { + return e->file_data + posn; + } 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); + + assert (e->file_data == NULL); /* Must be first or second case. */ + + /* 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 + +/* We don't have a stdio stream, but we have a mapping window + we need to initialize. */ +static void +prepare_stream (struct execdata *e) +{ + e->map_buffer = NULL; + e->map_vsize = e->map_fsize = 0; + e->map_filepos = 0; +} + +static void prepare_in_memory (struct execdata *e) +{ + prepare_stream(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) { FILE *f = &e->stream; @@ -431,6 +550,13 @@ map (struct execdata *e, off_t posn, size_t len) f->__buffer + (posn + len - f->__offset) < f->__get_limit) /* The current mapping window covers it. */ offset = posn & (f->__bufsize - 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. */ + f->__eof = 1; + return NULL; + } else if (e->filemap == MACH_PORT_NULL) { /* No mapping for the file. Read the data by RPC. */ @@ -448,8 +574,7 @@ map (struct execdata *e, off_t posn, size_t len) { /* The data was returned out of line. Discard the old buffer. */ if (f->__bufsize != 0) - vm_deallocate (mach_task_self (), - (vm_address_t) f->__buffer, f->__bufsize); + munmap (f->__buffer, f->__bufsize); f->__buffer = buffer; f->__bufsize = round_page (nread); } @@ -462,8 +587,7 @@ map (struct execdata *e, off_t posn, size_t len) { /* Deallocate the old mapping area. */ if (f->__buffer != NULL) - vm_deallocate (mach_task_self (), (vm_address_t) f->__buffer, - f->__bufsize); + munmap (f->__buffer, f->__bufsize); f->__buffer = NULL; /* Make sure our mapping is page-aligned in the file. */ @@ -474,7 +598,7 @@ map (struct execdata *e, off_t posn, size_t len) /* Map the data from the file. */ if (vm_map (mach_task_self (), (vm_address_t *) &f->__buffer, f->__bufsize, 0, 1, - e->filemap, f->__target, 1, VM_PROT_READ, VM_PROT_READ, + e->filemap, f->__offset, 1, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE)) { errno = e->error = EIO; @@ -486,7 +610,7 @@ map (struct execdata *e, off_t posn, size_t len) e->cntl->accessed = 1; if (f->__offset + f->__bufsize > size) - f->__get_limit = f->__buffer + (size - f->__target); + f->__get_limit = f->__buffer + (size - f->__offset); else f->__get_limit = f->__buffer + f->__bufsize; } @@ -502,13 +626,26 @@ map (struct execdata *e, off_t posn, size_t len) return f->__bufp; } +#endif -/* stdio input-room function. */ +/* stdio input-room function. + XXX/fault in the stdio case (or libio replacement), i.e. for bfd + (if ever revived), need to check all the mapping fault issues */ 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 @@ -517,12 +654,68 @@ close_exec_stream (void *cookie) struct execdata *e = cookie; if (e->stream.__buffer != NULL) - vm_deallocate (mach_task_self (), (vm_address_t) e->stream.__buffer, - e->stream.__bufsize); + munmap (e->stream.__buffer, e->stream.__bufsize); + + return 0; +} + +/* stdio seek function. */ +static int +fake_seek (void *cookie, fpos_t *pos, int whence) +{ + struct execdata *e = cookie; + + /* Set __target to match the specifed seek location */ + switch (whence) + { + case SEEK_END: + e->stream.__target = e->file_size + *pos; + break; + case SEEK_CUR: + e->stream.__target += *pos; + break; + + case SEEK_SET: + e->stream.__target = *pos; + break; + } + *pos = e->stream.__target; return 0; } +/* Initialize E's stdio stream. */ +static void +prepare_stream (struct execdata *e) +{ + memset (&e->stream, 0, sizeof (e->stream)); + e->stream.__magic = _IOMAGIC; + e->stream.__mode.__read = 1; + e->stream.__userbuf = 1; + e->stream.__room_funcs.__input = input_room; + e->stream.__io_funcs.seek = fake_seek; + e->stream.__io_funcs.close = close_exec_stream; + e->stream.__cookie = e; + e->stream.__seen = 1; +} + +/* Point the stream at the buffer of file data. */ +static void +prepare_in_memory (struct execdata *e) +{ + memset (&e->stream, 0, sizeof (e->stream)); + e->stream.__magic = _IOMAGIC; + e->stream.__mode.__read = 1; + e->stream.__buffer = e->file_data; + e->stream.__bufsize = e->file_size; + e->stream.__get_limit = e->stream.__buffer + e->stream.__bufsize; + e->stream.__bufp = e->stream.__buffer; + e->stream.__seen = 1; +} +#endif + +#endif + /* Prepare to check and load FILE. */ static void @@ -543,16 +736,7 @@ prepare (file_t file, struct execdata *e) e->interp.section = NULL; /* Initialize E's stdio stream. */ - memset (&e->stream, 0, sizeof (e->stream)); - e->stream.__magic = _IOMAGIC; - e->stream.__mode.__read = 1; - e->stream.__userbuf = 1; - e->stream.__room_funcs.__input = input_room; - /* This never gets called, but fseek returns ESPIPE if it's null. */ - e->stream.__io_funcs.seek = __default_io_functions.seek; - e->stream.__io_funcs.close = close_exec_stream; - e->stream.__cookie = e; - e->stream.__seen = 1; + prepare_stream (e); /* Try to mmap FILE. */ e->error = io_map (file, &rd, &wr); @@ -569,17 +753,7 @@ prepare (file_t file, struct execdata *e) e->filemap = rd; e->error = /* io_map_cntl (file, &e->cntlmap) */ EOPNOTSUPP; /* XXX */ - if (e->error) - { - /* No shared page. Do a stat to find the file size. */ - struct stat st; - e->error = io_stat (file, &st); - if (e->error) - return; - e->file_size = st.st_size; - e->optimal_block = st.st_blksize; - } - else + if (!e->error) e->error = vm_map (mach_task_self (), (vm_address_t *) &e->cntl, vm_page_size, 0, 1, e->cntlmap, 0, 0, VM_PROT_READ|VM_PROT_WRITE, @@ -617,9 +791,17 @@ prepare (file_t file, struct execdata *e) break; } } - else if (e->error == EOPNOTSUPP) - /* We can't mmap FILE, but perhaps we can do normal I/O to it. */ - e->error = 0; + + if (!e->cntl && (!e->error || e->error == EOPNOTSUPP)) + { + /* No shared page. Do a stat to find the file size. */ + struct stat st; + e->error = io_stat (file, &st); + if (e->error) + return; + e->file_size = st.st_size; + e->optimal_block = st.st_blksize; + } } /* Check the magic number, etc. of the file. @@ -669,18 +851,18 @@ check_bfd (struct execdata *e) static void check_elf (struct execdata *e) { - Elf32_Ehdr *ehdr = map (e, 0, sizeof (Elf32_Ehdr)); - Elf32_Phdr *phdr; + ElfW(Ehdr) *ehdr = map (e, 0, sizeof (ElfW(Ehdr))); + ElfW(Phdr) *phdr; if (! ehdr) { - if (! ferror (&e->stream)) + if (!e->error) e->error = ENOEXEC; return; } - if (*(Elf32_Word *) ehdr != ((union { Elf32_Word word; - unsigned char string[SELFMAG]; }) + if (*(ElfW(Word) *) ehdr != ((union { ElfW(Word) word; + unsigned char string[SELFMAG]; }) { string: ELFMAG }).word) { e->error = ENOEXEC; @@ -691,13 +873,15 @@ check_elf (struct execdata *e) ehdr->e_ident[EI_DATA] != host_ELFDATA || ehdr->e_ident[EI_VERSION] != EV_CURRENT || ehdr->e_version != EV_CURRENT || - ehdr->e_machine != elf_machine || ehdr->e_ehsize < sizeof *ehdr || - ehdr->e_phentsize != sizeof (Elf32_Phdr)) + ehdr->e_phentsize != sizeof (ElfW(Phdr))) { e->error = ENOEXEC; return; } + e->error = elf_machine_matches_host (ehdr->e_machine); + if (e->error) + return; /* Extract all this information now, while EHDR is mapped. The `map' call below for the phdrs may reuse the mapping window. */ @@ -707,24 +891,33 @@ check_elf (struct execdata *e) e->info.elf.loadbase = 0; e->info.elf.phnum = ehdr->e_phnum; - phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (Elf32_Phdr)); + phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (ElfW(Phdr))); if (! phdr) { - if (! ferror (&e->stream)) + if (!e->error) e->error = ENOEXEC; return; } e->info.elf.phdr = phdr; + e->info.elf.phdr_addr = ehdr->e_phoff; } +/* Copy MAPPED_PHDR into E->info.elf.phdr, filling in E->interp.phdr + in the process. */ static void -check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr, - vm_address_t *phdr_addr, vm_size_t *phdr_size) +check_elf_phdr (struct execdata *e, const ElfW(Phdr) *mapped_phdr) { - const Elf32_Phdr *phdr; + const ElfW(Phdr) *phdr; + bool seen_phdr = false; memcpy (e->info.elf.phdr, mapped_phdr, - e->info.elf.phnum * sizeof (Elf32_Phdr)); + e->info.elf.phnum * sizeof (ElfW(Phdr))); + + /* Default state if we do not see PT_GNU_STACK telling us what to do. + Executable stack is the compatible default. + (XXX should be machine-dependent??) + */ + e->info.elf.execstack = 1; for (phdr = e->info.elf.phdr; phdr < &e->info.elf.phdr[e->info.elf.phnum]; @@ -734,26 +927,37 @@ check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr, case PT_INTERP: e->interp.phdr = phdr; break; - case PT_PHDR: - if (phdr_addr) - *phdr_addr = phdr->p_vaddr & ~(phdr->p_align - 1); - if (phdr_size) - *phdr_size = phdr->p_memsz; - break; case PT_LOAD: - /* Sanity check. */ if (e->file_size <= (off_t) (phdr->p_offset + phdr->p_filesz)) - e->error = ENOEXEC; + { + e->error = ENOEXEC; + return; + } + /* Check if this is the segment that contains the phdr image. */ + if (!seen_phdr + && (phdr->p_offset & -phdr->p_align) == 0 /* Sanity check. */ + && phdr->p_offset <= e->info.elf.phdr_addr + && e->info.elf.phdr_addr - phdr->p_offset < phdr->p_filesz) + { + e->info.elf.phdr_addr += phdr->p_vaddr - phdr->p_offset; + seen_phdr = true; + } + break; + case PT_GNU_STACK: + e->info.elf.execstack = phdr->p_flags & PF_X; break; } + + if (!seen_phdr) + e->info.elf.phdr_addr = 0; } static void check (struct execdata *e) { - check_elf (e); + check_elf (e); /* XXX/fault */ #ifdef BFD if (e->error == ENOEXEC) { @@ -781,7 +985,7 @@ finish_mapping (struct execdata *e) e->cntl->conch_status = USER_HAS_NOT_CONCH; spin_unlock (&e->cntl->lock); } - vm_deallocate (mach_task_self (), (vm_address_t) e->cntl, vm_page_size); + munmap (e->cntl, vm_page_size); e->cntl = NULL; } if (e->filemap != MACH_PORT_NULL) @@ -796,7 +1000,9 @@ finish_mapping (struct execdata *e) } } -/* Clean up after reading the file (need not be completed). */ +/* Clean up after reading the file (need not be completed). + Note: this may be called several times for the E, so it must take care + of checking what was already freed. */ void finish (struct execdata *e, int dealloc_file) { @@ -809,7 +1015,19 @@ 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); + e->file_data = NULL; + } else if (map_buffer (e) != NULL) { + munmap (map_buffer (e), map_vsize (e)); + map_buffer (e) = NULL; + } +#endif + } if (dealloc_file && e->file != MACH_PORT_NULL) { mach_port_deallocate (mach_task_self (), e->file); @@ -838,12 +1056,12 @@ load (task_t usertask, struct execdata *e) else #endif { - Elf32_Word i; + ElfW(Word) i; for (i = 0; i < e->info.elf.phnum; ++i) if (e->info.elf.phdr[i].p_type == PT_LOAD) load_section (&e->info.elf.phdr[i], e); - /* The entry point address is relative to whereever we loaded the + /* The entry point address is relative to wherever we loaded the program text. */ e->entry += e->info.elf.loadbase; } @@ -893,7 +1111,7 @@ load (task_t usertask, struct execdata *e) /* Force it to be paged in. */ (void) *(volatile int *) a; - vm_deallocate (mach_task_self (), myaddr, mysize); + munmap ((caddr_t) myaddr, mysize); } } @@ -927,9 +1145,23 @@ 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); + errno = hurd_safe_copyin (buf, contents, n); /* XXX/fault */ + if (errno) + longjmp (ziperr, 2); + + zipread_pos += n; + return n; } void zipwrite (const char *buf, size_t nwrite) { @@ -964,7 +1196,6 @@ check_gzip (struct execdata *earg) return; } - rewind (&e->stream); if (get_method (0) != 0) { /* Not a happy gzip file. */ @@ -989,41 +1220,136 @@ check_gzip (struct execdata *earg) /* The output is complete. Clean up the stream and store its resultant buffer and size in the execdata as the file contents. */ fclose (zipout); + + /* Clean up the old exec file stream's state. + Now that we have the contents all in memory (in E->file_data), + nothing will in fact ever try to use E->stream again. */ + finish (e, 0); + + /* Prepare the stream state to use the file contents already in memory. */ e->file_data = zipdata; e->file_size = zipdatasz; + prepare_in_memory (e); +} +#endif + +#ifdef BZIP2 +/* Check the file for being a bzip2'd image. Return with ENOEXEC means not + a valid bzip2 file; return with another error means lossage in decoding; + return with zero means the file was uncompressed into memory which E now + points to, and `check' can be run again. */ + +static void +check_bzip2 (struct execdata *earg) +{ + struct execdata *e = earg; + /* Entry points to bunzip2 engine. */ + void do_bunzip2 (void); + /* Callbacks from unzip for I/O and error interface. */ + extern int (*unzip_read) (char *buf, size_t maxread); + extern void (*unzip_write) (const char *buf, size_t nwrite); + extern void (*unzip_read_error) (void); + extern void (*unzip_error) (const char *msg); + + char *zipdata = NULL; + size_t zipdatasz = 0; + FILE *zipout = NULL; + jmp_buf ziperr; + off_t zipread_pos = 0; + int zipread (char *buf, size_t maxread) + { + 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); + errno = hurd_safe_copyin (buf, contents, n); /* XXX/fault */ + if (errno) + longjmp (ziperr, 2); + + zipread_pos += n; + return n; + } + void zipwrite (const char *buf, size_t nwrite) + { + if (fwrite (buf, nwrite, 1, zipout) != 1) + longjmp (ziperr, 1); + } + void ziprderr (void) + { + errno = ENOEXEC; + longjmp (ziperr, 2); + } + void ziperror (const char *msg) + { + errno = ENOEXEC; + longjmp (ziperr, 2); + } + + unzip_read = zipread; + unzip_write = zipwrite; + unzip_read_error = ziprderr; + unzip_error = ziperror; + + if (setjmp (ziperr)) + { + /* Error in unzipping jumped out. */ + if (zipout) + { + fclose (zipout); + free (zipdata); + } + e->error = errno; + return; + } + + zipout = open_memstream (&zipdata, &zipdatasz); + if (! zipout) + { + e->error = errno; + return; + } - /* Clean up the old exec file stream's state. */ + /* Call the bunzip2 engine. */ + do_bunzip2 (); + + /* The output is complete. Clean up the stream and store its resultant + buffer and size in the execdata as the file contents. */ + fclose (zipout); + + /* Clean up the old exec file stream's state. + Now that we have the contents all in memory (in E->file_data), + nothing will in fact ever try to use E->stream again. */ finish (e, 0); - /* Point the stream at the buffer of file data. */ - memset (&e->stream, 0, sizeof (e->stream)); - e->stream.__magic = _IOMAGIC; - e->stream.__mode.__read = 1; - e->stream.__buffer = e->file_data; - e->stream.__bufsize = e->file_size; - e->stream.__get_limit = e->stream.__buffer + e->stream.__bufsize; - e->stream.__bufp = e->stream.__buffer; - e->stream.__seen = 1; + /* Prepare the stream state to use the file contents already in memory. */ + e->file_data = zipdata; + e->file_size = zipdatasz; + prepare_in_memory (e); } #endif -static inline error_t -servercopy (void **arg, mach_msg_type_number_t argsize, boolean_t argcopy) +static inline void * +servercopy (void *arg, mach_msg_type_number_t argsize, boolean_t argcopy, + error_t *errorp) { - if (argcopy) - { - /* ARG came in-line, so we must copy it. */ - error_t error; - void *copy; - error = vm_allocate (mach_task_self (), - (vm_address_t *) ©, argsize, 1); - if (error) - return error; - bcopy (*arg, copy, argsize); - *arg = copy; + if (! argcopy) + return arg; + + /* ARG came in-line, so we must copy it. */ + void *copy; + copy = mmap (0, argsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (copy == MAP_FAILED) + { + *errorp = errno; + return NULL; } - return 0; + memcpy (copy, arg, argsize); + return copy; } @@ -1047,8 +1373,6 @@ do_exec (file_t file, struct bootinfo *boot = 0; int *ports_replaced; int secure, defaults; - vm_address_t phdr_addr = 0; - vm_size_t phdr_size = 0; mach_msg_type_number_t i; int intarray_dealloc = 0; /* Dealloc INTARRAY before returning? */ int oldtask_trashed = 0; /* Have we trashed the old task? */ @@ -1074,6 +1398,7 @@ do_exec (file_t file, /* The gzip code is really cheesy, not even close to thread-safe. So we serialize all uses of it. */ mutex_lock (&lock); + e->error = 0; check_gzip (e); mutex_unlock (&lock); if (e->error == 0) @@ -1083,11 +1408,30 @@ do_exec (file_t file, check (e); } #endif +#ifdef BZIP2 + if (e->error == ENOEXEC) + { + /* See if it is a compressed image. */ + static struct mutex lock = MUTEX_INITIALIZER; + /* The bzip2 code is really cheesy, not even close to thread-safe. + So we serialize all uses of it. */ + mutex_lock (&lock); + e->error = 0; + check_bzip2 (e); + mutex_unlock (&lock); + if (e->error == 0) + /* The file was uncompressed into memory, and now E describes the + uncompressed image rather than the actual file. Check it again + for a valid magic number. */ + check (e); + } +#endif } /* Here is the main body of the function. */ + interp.file = MACH_PORT_NULL; /* Catch this error now, rather than later. */ /* XXX For EXEC_DEFAULTS, this is only an error if one of the user's @@ -1135,13 +1479,11 @@ do_exec (file_t file, else #endif { - const Elf32_Phdr *phdr = e.info.elf.phdr; - e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (Elf32_Phdr)); - check_elf_phdr (&e, phdr, &phdr_addr, &phdr_size); + const ElfW(Phdr) *phdr = e.info.elf.phdr; + e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (ElfW(Phdr))); + check_elf_phdr (&e, phdr); } - interp.file = MACH_PORT_NULL; - if (oldtask == MACH_PORT_NULL) flags |= EXEC_NEWTASK; @@ -1152,6 +1494,9 @@ do_exec (file_t file, e.error = task_create (((flags & EXEC_SECURE) || oldtask == MACH_PORT_NULL) ? mach_task_self () : oldtask, +#ifdef KERN_INVALID_LEDGER + NULL, 0, /* OSF Mach */ +#endif 0, &newtask); if (e.error) goto out; @@ -1178,6 +1523,7 @@ do_exec (file_t file, if (new != MACH_PORT_NULL && reauth) { mach_port_t ref = mach_reply_port (), authed; + /* MAKE_SEND is safe here because we destroy REF ourselves. */ e.error = io_reauthenticate (new, ref, MACH_MSG_TYPE_MAKE_SEND); if (! e.error) e.error = auth_user_authenticate @@ -1209,11 +1555,6 @@ do_exec (file_t file, } bzero (&boot->pi + 1, (char *) &boot[1] - (char *) (&boot->pi + 1)); - /* First record some information about the image itself. */ - boot->phdr_addr = phdr_addr; - boot->phdr_size = phdr_size; - boot->user_entry = e.entry; - /* These flags say the information we pass through to the new program may need to be modified. */ secure = (flags & EXEC_SECURE); @@ -1225,18 +1566,18 @@ do_exec (file_t file, boot->flags = flags; - e.error = servercopy ((void **) &argv, argvlen, argv_copy); + argv = servercopy (argv, argvlen, argv_copy, &e.error); if (e.error) goto stdout; boot->argv = argv; boot->argvlen = argvlen; - e.error = servercopy ((void **) &envp, envplen, envp_copy); + envp = servercopy (envp, envplen, envp_copy, &e.error); if (e.error) goto stdout; boot->envp = envp; boot->envplen = envplen; - e.error = servercopy ((void **) &dtable, dtablesize * sizeof (mach_port_t), - dtable_copy); + dtable = servercopy (dtable, dtablesize * sizeof (mach_port_t), + dtable_copy, &e.error); if (e.error) goto stdout; boot->dtable = dtable; @@ -1249,10 +1590,8 @@ do_exec (file_t file, round_page (INIT_INT_MAX * sizeof (int)))) { /* Allocate a new vector that is big enough. */ - vm_allocate (mach_task_self (), - (vm_address_t *) &boot->intarray, - INIT_INT_MAX * sizeof (int), - 1); + boot->intarray = mmap (0, INIT_INT_MAX * sizeof (int), + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); memcpy (boot->intarray, intarray, nints * sizeof (int)); intarray_dealloc = !intarray_copy; } @@ -1262,8 +1601,8 @@ do_exec (file_t file, } else { - e.error = servercopy ((void **) &intarray, nints * sizeof (int), - intarray_copy); + intarray = servercopy (intarray, nints * sizeof (int), intarray_copy, + &e.error); if (e.error) goto stdout; boot->intarray = intarray; @@ -1276,9 +1615,8 @@ do_exec (file_t file, /* Now choose the ports to give the new program. */ boot->nports = nports < INIT_PORT_MAX ? INIT_PORT_MAX : nports; - vm_allocate (mach_task_self (), - (vm_address_t *) &boot->portarray, - boot->nports * sizeof (mach_port_t), 1); + boot->portarray = mmap (0, boot->nports * sizeof (mach_port_t), + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); /* Start by copying the array as passed. */ for (i = 0; i < nports; ++i) boot->portarray[i] = portarray[i]; @@ -1374,7 +1712,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; } @@ -1398,8 +1736,11 @@ do_exec (file_t file, errno = EBADF; return MACH_PORT_NULL; } + mach_port_mod_refs (mach_task_self (), boot->dtable[fd], + MACH_PORT_RIGHT_SEND, +1); return boot->dtable[fd]; } + /* XXX/fault */ e.error = hurd_file_name_lookup (&user_port, &user_fd, 0, name, O_READ, 0, &interp.file); } @@ -1421,10 +1762,10 @@ do_exec (file_t file, else #endif { - const Elf32_Phdr *phdr = interp.info.elf.phdr; + const ElfW(Phdr) *phdr = interp.info.elf.phdr; interp.info.elf.phdr = alloca (interp.info.elf.phnum * - sizeof (Elf32_Phdr)); - check_elf_phdr (&interp, phdr, NULL, NULL); + sizeof (ElfW(Phdr))); + check_elf_phdr (&interp, phdr); } } e.error = interp.error; @@ -1439,7 +1780,7 @@ do_exec (file_t file, if (newtask == oldtask) { - thread_array_t threads; + thread_t *threads; mach_msg_type_number_t nthreads, i; /* Terminate all the threads of the old task. */ @@ -1452,8 +1793,7 @@ do_exec (file_t file, thread_terminate (threads[i]); mach_port_deallocate (mach_task_self (), threads[i]); } - vm_deallocate (mach_task_self (), - (vm_address_t) threads, nthreads * sizeof (thread_t)); + munmap ((caddr_t) threads, nthreads * sizeof (thread_t)); /* Deallocate the entire virtual address space of the task. */ @@ -1500,6 +1840,20 @@ do_exec (file_t file, /* Clean up. */ finish (&e, 0); + /* Now record some essential addresses from the image itself that the + program's startup code will need to know. We do this after loading + the image so that a load-anywhere image gets the adjusted addresses. */ + if (e.info.elf.phdr_addr != 0) + { +#ifdef BFD + if (!e.bfd) +#endif + e.info.elf.phdr_addr += e.info.elf.loadbase; + boot->phdr_addr = e.info.elf.phdr_addr; + boot->phdr_size = e.info.elf.phnum * sizeof (ElfW(Phdr)); + } + boot->user_entry = e.entry; /* already adjusted in `load' */ + /* Create the initial thread. */ e.error = thread_create (newtask, &thread); if (e.error) @@ -1513,6 +1867,17 @@ do_exec (file_t file, &boot->stack_base, &boot->stack_size); if (e.error) goto out; +#ifdef BFD + if (!e.bfd) +#endif + { + /* It would probably be better to change mach_setup_thread so + it does a vm_map with the right permissions to start with. */ + if (!e.info.elf.execstack) + e.error = vm_protect (newtask, boot->stack_base, boot->stack_size, + 0, VM_PROT_READ | VM_PROT_WRITE); + } + if (oldtask != newtask && oldtask != MACH_PORT_NULL) { @@ -1538,8 +1903,6 @@ do_exec (file_t file, proc_reassign (proc, newtask); mach_port_deallocate (mach_task_self (), proc); } - - mach_port_deallocate (mach_task_self (), oldtask); } /* Make sure the proc server has the right idea of our identity. */ @@ -1566,36 +1929,53 @@ do_exec (file_t file, authenticated anyhow. */ proc_setowner (boot->portarray[INIT_PORT_PROC], neuids ? euids[0] : 0, !neuids); - + /* Clean up */ if (euids != euidbuf) - vm_deallocate (mach_task_self (), (vm_address_t) euids, - neuids * sizeof (uid_t)); + munmap (euids, neuids * sizeof (uid_t)); if (egids != egidbuf) - vm_deallocate (mach_task_self (), (vm_address_t) egids, - negids * sizeof (uid_t)); + munmap (egids, negids * sizeof (uid_t)); if (auids != auidbuf) - vm_deallocate (mach_task_self (), (vm_address_t) auids, - nauids * sizeof (uid_t)); + munmap (auids, nauids * sizeof (uid_t)); if (agids != agidbuf) - vm_deallocate (mach_task_self (), (vm_address_t) agids, - nagids * sizeof (uid_t)); + munmap (agids, nagids * sizeof (uid_t)); } } { - mach_port_t btport = ports_get_right (boot); - mach_port_insert_right (mach_task_self (), btport, btport, - MACH_MSG_TYPE_MAKE_SEND); + mach_port_t btport = ports_get_send_right (boot); e.error = task_set_bootstrap_port (newtask, btport); mach_port_deallocate (mach_task_self (), btport); } out: - if (e.interp.section) + if (interp.file != MACH_PORT_NULL) finish (&interp, 1); finish (&e, !e.error); + if (!e.error && (flags & EXEC_SIGTRAP)) /* XXX && !secure ? */ + { + /* This is a "traced" exec, i.e. the new task is to be debugged. The + caller has requested that the new process stop with SIGTRAP before + it starts. Since the process has no signal thread yet to do its + own POSIX signal mechanics, we simulate it by notifying the proc + server of the signal and leaving the initial thread with a suspend + count of one, as it would be if the process were stopped by a + POSIX signal. */ + mach_port_t proc; + if (boot->nports > INIT_PORT_PROC) + proc = boot->portarray[INIT_PORT_PROC]; + else + /* Ask the proc server for the proc port for this task. */ + e.error = proc_task2proc (procserver, newtask, &proc); + if (!e.error) + /* Tell the proc server that the process has stopped with the + SIGTRAP signal. Don't bother to check for errors from the RPC + here; for non-secure execs PROC may be the user's own proc + server its confusion shouldn't make the exec fail. */ + proc_mark_stop (proc, SIGTRAP, 0); + } + if (boot) { /* Release the original reference. Now there is only one @@ -1619,7 +1999,8 @@ do_exec (file_t file, if (thread != MACH_PORT_NULL) { - thread_resume (thread); + if (!e.error && !(flags & EXEC_SIGTRAP)) + thread_resume (thread); mach_port_deallocate (mach_task_self (), thread); } @@ -1666,13 +2047,9 @@ do_exec (file_t file, portarray, and we are not saving those pointers in BOOT for later transfer, deallocate the original space now. */ if (intarray_dealloc) - vm_deallocate (mach_task_self (), - (vm_address_t) intarray, - nints * sizeof intarray[0]); + munmap (intarray, nints * sizeof intarray[0]); if (!portarray_copy) - vm_deallocate (mach_task_self (), - (vm_address_t) portarray, - nports * sizeof portarray[0]); + munmap (portarray, nports * sizeof portarray[0]); } return e.error; @@ -1804,13 +2181,16 @@ S_exec_setexecdata (struct trivfs_protid *protid, if (nports < INIT_PORT_MAX || nints < INIT_INT_MAX) return EINVAL; /* */ - err = servercopy ((void **) &ports, nports * sizeof (mach_port_t), - ports_copy); + err = 0; + ports = servercopy (ports, nports * sizeof (mach_port_t), ports_copy, &err); if (err) return err; - err = servercopy ((void **) &ints, nints * sizeof (int), ints_copy); + ints = servercopy (ints, nints * sizeof (int), ints_copy, &err); if (err) - return err; + { + munmap (ports, nports * sizeof (mach_port_t)); + return err; + } rwlock_writer_lock (&std_lock); @@ -1819,16 +2199,14 @@ S_exec_setexecdata (struct trivfs_protid *protid, mach_msg_type_number_t i; for (i = 0; i < std_nports; ++i) mach_port_deallocate (mach_task_self (), std_ports[i]); - vm_deallocate (mach_task_self (), (vm_address_t)std_ports, - std_nports * sizeof (mach_port_t)); + munmap (std_ports, std_nports * sizeof (mach_port_t)); } std_ports = ports; std_nports = nports; if (std_ints) - vm_deallocate (mach_task_self (), (vm_address_t)std_ints, - std_nints * sizeof (int)); + munmap (std_ints, std_nints * sizeof (int)); std_ints = ints; std_nints = nints; diff --git a/exec/execmutations.h b/exec/execmutations.h index 62ae5c55..96b47721 100644 --- a/exec/execmutations.h +++ b/exec/execmutations.h @@ -4,3 +4,5 @@ #define FILE_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t) #define EXEC_IMPORTS import "priv.h"; + +#define SERVERCOPY 1 diff --git a/exec/exectrans.c b/exec/exectrans.c deleted file mode 100644 index 59c9cdf2..00000000 --- a/exec/exectrans.c +++ /dev/null @@ -1,81 +0,0 @@ - -#include <stdio.h> -#include <getopt.h> -#include <error.h> -#include <sys/stat.h> - -#include <hurd.h> -#include <hurd/trivfs.h> - - -/* Where to put the service ports. */ -static struct port_bucket *port_bucket; - -/* Trivfs hooks. */ -int trivfs_fstype = FSTYPE_MISC; -int trivfs_fsid = 0; -int trivfs_support_read = 1; -int trivfs_support_write = 1; -int trivfs_support_exec = 1; -int trivfs_allow_open = O_READ|O_WRITE|O_EXEC; - -struct port_class *trivfs_protid_portclasses[1]; -struct port_class *trivfs_cntl_portclasses[1]; -int trivfs_protid_nportclasses = 1; -int trivfs_cntl_nportclasses = 1; - - -static int -exec_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) -{ - extern int exec_server (mach_msg_header_t *inp, mach_msg_header_t *outp); - return exec_server (inp, outp) || trivfs_demuxer (inp, outp); -} - -void -trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) -{ - st->st_fstype = FSTYPE_MISC; -} - -error_t -trivfs_goaway (struct trivfs_control *fsys, int flags) -{ - int count; - - /* Stop new requests. */ - ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]); - ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]); - - /* Are there any extant user ports for the /servers/exec file? */ - count = ports_count_class (trivfs_protid_portclasses[0]); - if (count == 0 || (flags & FSYS_GOAWAY_FORCE)) - { - /* No users. Disconnect from the filesystem. */ - mach_port_deallocate (mach_task_self (), fsys->underlying); - - /* Are there remaining exec_startup RPCs to answer? */ - count = ports_count_class (execboot_portclass); - if (count == 0) - /* Nope. We got no reason to live. */ - exit (0); - - /* Continue servicing tasks starting up. */ - ports_enable_class (execboot_portclass); - - /* No more communication with the parent filesystem. */ - ports_destroy_right (fsys); - going_down = 1; - - return 0; - } - else - { - /* We won't go away, so start things going again... */ - ports_enable_class (trivfs_protid_portclasses[0]); - ports_resume_class_rpcs (trivfs_cntl_portclasses[0]); - ports_resume_class_rpcs (trivfs_protid_portclasses[0]); - - return EBUSY; - } -} diff --git a/exec/gcore.c b/exec/gcore.c deleted file mode 100644 index 7343516c..00000000 --- a/exec/gcore.c +++ /dev/null @@ -1,88 +0,0 @@ -/* `gcore' for GNU Hurd. - Copyright (C) 1992 Free Software Foundation - Written by Roland McGrath. - -This file is part of the GNU Hurd. - -The GNU Hurd is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -The GNU Hurd is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with the GNU Hurd; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include <stdio.h> -#include <stdlib.h> -#include <hurd.h> -#include <hurd/core.h> -#include <limits.h> - -int -main (int argc, char **argv) -{ - file_t coreserv; - int i; - - if (argc < 2) - { - usage: - fprintf (stderr, "Usage: %s PID ...\n", program_invocation_short_name); - exit (1); - } - - coreserv = path_lookup (_SERVERS_CORE, 0, 0); - if (coreserv == MACH_PORT_NULL) - { - perror (_SERVERS_CORE); - exit (1); - } - - for (i = 1; i < argc; ++i) - { - char *end; - pid_t pid; - task_t task; - - pid = strtol (&argv[i], &end, 10); - if (end == &argv[i] || *end != '\0') - goto usage; - - task = pid2task ((pid_t) pid); - if (task == MACH_PORT_NULL) - fprintf (stderr, "pid2task: %d: %s\n", pid, strerror (errno)); - else - { - char name[PATH_MAX]; - file_t file; - sprintf (name, "core.%d", pid); - file = path_lookup (name, FS_LOOKUP_WRITE|FS_LOOKUP_CREATE, - 0666 &~ getumask ()); - if (file == MACH_PORT_NULL) - perror (name); - else - { - error_t err = core_dump_task (coreserv, task, - file, - 0, 0, - getenv ("GNUTARGET")); - mach_port_deallocate (mach_task_self (), file); - if (err) - { - (void) remove (name); - fprintf (stderr, "core_dump_task: %d: %s\n", - pid, strerror (err)); - } - } - } - mach_port_deallocate (mach_task_self (), task); - } - - exit (0); -} diff --git a/exec/hashexec.c b/exec/hashexec.c index 748f8e1b..2aa3844b 100644 --- a/exec/hashexec.c +++ b/exec/hashexec.c @@ -1,5 +1,5 @@ /* GNU Hurd standard exec server, #! script execution support. - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1995,96,97,98,99,2000,02 Free Software Foundation, Inc. Written by Roland McGrath. This file is part of the GNU Hurd. @@ -18,11 +18,11 @@ You should have received a copy of the GNU General Public License along with the GNU Hurd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include "priv.h" #include <hurd/sigpreempt.h> #include <unistd.h> #include <envz.h> +#include <sys/param.h> /* This is called to check E for a #! interpreter specification. E has already been prepared (successfully) and checked (unsuccessfully). If @@ -43,13 +43,10 @@ check_hashbang (struct execdata *e, mach_port_t *deallocnames, u_int ndeallocnames, mach_port_t *destroynames, u_int ndestroynames) { - char *ibuf = NULL; - size_t ibufsiz = 0; char *p; char *interp, *arg; /* Interpreter file name, and first argument */ - size_t interp_len, len; + size_t interp_len, arg_len; file_t interp_file; /* Port open on the interpreter file. */ - FILE *f = &e->stream; char *new_argv; size_t new_argvlen; mach_port_t *new_dtable = NULL; @@ -57,12 +54,18 @@ check_hashbang (struct execdata *e, file_t user_fd (int fd) { - if (fd < 0 || fd >= dtablesize || dtable[fd] == MACH_PORT_NULL) + if (fd >= 0 && fd < dtablesize) { - errno = EBADF; - return MACH_PORT_NULL; + const file_t dport = dtable[fd]; + if (dport != MACH_PORT_NULL) + { + mach_port_mod_refs (mach_task_self (), dport, + MACH_PORT_RIGHT_SEND, +1); + return dport; + } } - return dtable[fd]; + errno = EBADF; + return MACH_PORT_NULL; } file_t user_crdir, user_cwdir; error_t user_port (int which, error_t (*operate) (mach_port_t)) @@ -71,6 +74,9 @@ check_hashbang (struct execdata *e, { error_t err; mach_port_t ref; + + /* MAKE_SEND is safe here because we destroy REF ourselves. */ + error_t uauth (auth_t auth) { return auth_user_authenticate (auth, @@ -121,50 +127,81 @@ check_hashbang (struct execdata *e, name, flags, 0, result); } - rewind (f); + const char *page; + char interp_buf[vm_page_size - 2 + 1]; - /* Check for our ``magic number''--"#!". */ + e->error = 0; + page = map (e, 0, 2); - errno = 0; - if (getc (f) != '#' || getc (f) != '!') + if (!page) { - /* No `#!' here. If there was a read error (not including EOF), - return that error indication. Otherwise return ENOEXEC to - say it's not a file we know how to execute. */ - e->error = ferror (f) ? errno : ENOEXEC; + if (!e->error) + e->error = ENOEXEC; return; } - /* Read the rest of the first line of the file. */ - - interp_len = getline (&ibuf, &ibufsiz, f); - if (ferror (f)) + /* Check for our ``magic number''--"#!". */ + if (page[0] != '#' || page[1] != '!') { - e->error = errno ?: EIO; + /* These are not the droids we're looking for. */ + e->error = ENOEXEC; return; } - if (ibuf[interp_len - 1] == '\n') - ibuf[--interp_len] = '\0'; - /* Find the name of the interpreter. */ - p = ibuf + strspn (ibuf, " \t"); - interp = strsep (&p, " \t"); + /* Read the rest of the first line of the file. + We in fact impose an arbitrary limit of about a page on this. */ - if (p) - /* Skip remaining blanks, and the rest of the line is the argument. */ + p = memccpy (interp_buf, page + 2, '\n', + MIN (map_fsize (e) - 2, sizeof interp_buf)); + if (p == NULL) { - p += strspn (p, " \t"); - arg = p; - len = interp_len - (arg - ibuf); + /* The first line went on for more than sizeof INTERP_BUF! */ + interp_len = sizeof interp_buf; + interp_buf[interp_len - 1] = '\0'; } else - /* There is no argument. */ - len = 0; + { + interp_len = p - interp_buf; /* Includes null terminator. */ + *--p = '\0'; /* Kill the newline. */ + } + + /* We are now done reading the script file. */ + finish (e, 0); + + + /* Find the name of the interpreter. */ + interp = interp_buf + strspn (interp_buf, " \t"); + p = strpbrk (interp, " \t"); + + if (p) + { + /* Terminate the interpreter name. */ + *p++ = '\0'; - if (len == 0) - arg = NULL; + /* Skip remaining blanks, and the rest of the line is the argument. */ + + arg = p + strspn (p, " \t"); + arg_len = interp_len - 1 - (arg - interp_buf); /* without null here */ + interp_len = p - interp; /* This one includes the null. */ + + if (arg_len == 0) + arg = NULL; + else + { + /* Trim trailing blanks after the argument. */ + size_t i = arg_len - 1; + while (arg[i] == ' ' || arg[i] == '\t') + arg[i--] = '\0'; + arg_len = i + 2; /* Include the terminating null. */ + } + } else - ++len; /* Include the terminating null. */ + { + /* There is no argument. */ + arg = NULL; + arg_len = 0; + interp_len -= interp - interp_buf; /* Account for blanks skipped. */ + } user_crdir = user_cwdir = MACH_PORT_NULL; @@ -179,7 +216,7 @@ check_hashbang (struct execdata *e, jmp_buf args_faulted; void fault_handler (int signo) { longjmp (args_faulted, 1); } - error_t setup_args (struct hurd_signal_preempter *preempter) + error_t setup_args (struct hurd_signal_preemptor *preemptor) { size_t namelen; char * volatile file_name = NULL; @@ -197,14 +234,13 @@ check_hashbang (struct execdata *e, char *name; int free_name = 0; /* True if we should free NAME. */ file_t name_file; - mach_port_t fileid; - dev_t filedev; + mach_port_t fileid, filefsid; ino_t fileno; /* Search $PATH for NAME, opening a port NAME_FILE on it. This is encapsulated in a function so we can catch faults reading the user's environment. */ - error_t search_path (struct hurd_signal_preempter *preempter) + error_t search_path (struct hurd_signal_preemptor *preemptor) { error_t err; char *path = envz_get (envp, envplen, "PATH"), *pfxed_name; @@ -228,9 +264,10 @@ check_hashbang (struct execdata *e, return err; } - error = io_identity (file, &fileid, &filedev, &fileno); + error = io_identity (file, &fileid, &filefsid, &fileno); if (error) goto out; + mach_port_deallocate (mach_task_self (), filefsid); if (memchr (argv, '\0', argvlen) == NULL) { @@ -251,11 +288,15 @@ check_hashbang (struct execdata *e, if (!error && name_file != MACH_PORT_NULL) { - mach_port_t id; - dev_t dev; + mach_port_t id, fsid; ino_t ino; - error = io_identity (name_file, &id, &dev, &ino); - __mach_port_deallocate (__mach_task_self (), id); + error = io_identity (name_file, &id, &fsid, &ino); + mach_port_deallocate (mach_task_self (), name_file); + if (!error) + { + mach_port_deallocate (mach_task_self (), fsid); + mach_port_deallocate (mach_task_self (), id); + } if (!error && id == fileid) { file_name = name; @@ -263,10 +304,9 @@ check_hashbang (struct execdata *e, } else if (free_name) free (name); - __mach_port_deallocate (__mach_task_self (), name_file); } - __mach_port_deallocate (__mach_task_self (), fileid); + mach_port_deallocate (mach_task_self (), fileid); } if (file_name == NULL) @@ -298,33 +338,50 @@ check_hashbang (struct execdata *e, /* Prepare the arguments to pass to the interpreter from the original arguments and the name of the script file. The args will look - like `ARGV[0] {ARG} FILE_NAME ARGV[1..n]' (ARG might have been + like `INTERP {ARG} FILE_NAME ARGV[1..n]' (ARG might have been omitted). */ namelen = strlen (file_name) + 1; - new_argvlen = argvlen + len + namelen; - e->error = vm_allocate (mach_task_self (), - (vm_address_t *) &new_argv, - new_argvlen, 1); - if (e->error) - return e->error; + new_argvlen + = (argvlen - strlen (argv) - 1) /* existing args - old argv[0] */ + + interp_len + arg_len + namelen; /* New args */ + + new_argv = mmap (0, new_argvlen, PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + if (new_argv == (caddr_t) -1) + { + e->error = errno; + return e->error; + } + else + e->error = 0; if (! setjmp (args_faulted)) { char *other_args; - other_args = memccpy (new_argv, argv, '\0', argvlen); - p = &new_argv[other_args ? other_args - new_argv : argvlen]; + + p = new_argv; + + /* INTERP */ + memcpy (p, interp, interp_len); + p += interp_len; + + /* Maybe ARG */ if (arg) { - memcpy (p, arg, len); - p += len; + memcpy (p, arg, arg_len); + p += arg_len; } + + /* FILE_NAME */ memcpy (p, file_name, namelen); p += namelen; - if (other_args) - memcpy (p, other_args - new_argv + argv, - argvlen - (other_args - new_argv)); + + /* Maybe remaining args */ + other_args = argv + strlen (argv) + 1; + if (other_args - argv < argvlen) + memcpy (p, other_args, argvlen - (other_args - argv)); } else { @@ -332,7 +389,7 @@ check_hashbang (struct execdata *e, char *n = stpncpy (new_argv, "**fault in exec server reading argv[0]**", argvlen); - memcpy (memcpy (n, arg, len) + len, file_name, namelen); + memcpy (memcpy (n, arg, arg_len) + arg_len, file_name, namelen); } if (free_file_name) @@ -347,10 +404,6 @@ check_hashbang (struct execdata *e, &setup_args, &fault_handler); } - /* We are now done reading the script file. */ - finish (e, 0); - free (ibuf); - rwlock_reader_unlock (&std_lock); if (user_crdir != MACH_PORT_NULL) @@ -384,21 +437,19 @@ check_hashbang (struct execdata *e, task_resume (oldtask); /* Our caller suspended it. */ mach_port_deallocate (mach_task_self (), oldtask); if (! argv_copy) - vm_deallocate (mach_task_self (), (vm_address_t) argv, argvlen); + munmap (argv, argvlen); if (! envp_copy) - vm_deallocate (mach_task_self (), (vm_address_t) envp, envplen); + munmap (envp, envplen); for (i = 0; i < dtablesize; ++i) - mach_port_deallocate (mach_task_self (), dtable[i]); + if (MACH_PORT_VALID (dtable[i])) + mach_port_deallocate (mach_task_self (), dtable[i]); if (! dtable_copy) - vm_deallocate (mach_task_self (), (vm_address_t) dtable, - dtablesize * sizeof *dtable); + munmap (dtable, dtablesize * sizeof *dtable); for (i = 0; i < nports; ++i) mach_port_deallocate (mach_task_self (), portarray[i]); if (! portarray_copy) - vm_deallocate (mach_task_self (), (vm_address_t) portarray, - nports * sizeof *portarray); + munmap (portarray, nports * sizeof *portarray); if (! intarray_copy) - vm_deallocate (mach_task_self (), (vm_address_t) intarray, - nints * sizeof *intarray); + munmap (intarray, nints * sizeof *intarray); } } diff --git a/exec/hostarch.c b/exec/hostarch.c index 38a38a00..ec59a417 100644 --- a/exec/hostarch.c +++ b/exec/hostarch.c @@ -1,6 +1,6 @@ /* Determine the BFD and ELF architecture and machine flavor from a Mach host port. Used by the exec and core servers. - Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc. + Copyright (C) 1992,93,95,96,99,2000,02 Free Software Foundation, Inc. Written by Roland McGrath. This file is part of the GNU Hurd. @@ -10,7 +10,7 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -The GNU Hurd is distributed in the hope that it will be useful, +The GNU Hurd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -19,17 +19,82 @@ You should have received a copy of the GNU General Public License along with the GNU Hurd; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "priv.h" #include <mach.h> #include <hurd/hurd_types.h> #include <errno.h> -#include <bfd.h> #include <elf.h> error_t +elf_machine_matches_host (ElfW(Half) e_machine) +{ + static void *host_type; /* Cached entry into the switch below. */ + struct host_basic_info hostinfo; + + if (host_type) + goto *host_type; + else + { + error_t err; + mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT; + + err = host_info (mach_host_self (), HOST_BASIC_INFO, + (natural_t *) &hostinfo, &hostinfocnt); + if (err) + return err; + assert (hostinfocnt == HOST_BASIC_INFO_COUNT); + } + +#define CACHE(test) ({ __label__ here; host_type = &&here; \ + here: return (test) ? 0 : ENOEXEC; }) + switch (hostinfo.cpu_type) + { + case CPU_TYPE_MC68020: + case CPU_TYPE_MC68030: + case CPU_TYPE_MC68040: + CACHE (e_machine == EM_68K); + + case CPU_TYPE_I860: + CACHE (e_machine == EM_860); + + case CPU_TYPE_MIPS: + CACHE (e_machine == EM_MIPS); + + case CPU_TYPE_MC88000: + CACHE (e_machine == EM_88K); + + case CPU_TYPE_SPARC: + CACHE (e_machine == EM_SPARC); + + case CPU_TYPE_I386: + case CPU_TYPE_I486: + case CPU_TYPE_PENTIUM: + case CPU_TYPE_PENTIUMPRO: + CACHE (e_machine == EM_386); + + case CPU_TYPE_POWERPC: + CACHE (e_machine == EM_PPC); + + case CPU_TYPE_ALPHA: + CACHE (e_machine == EM_ALPHA); + + case CPU_TYPE_HPPA: + CACHE (e_machine == EM_PARISC); + + default: + return EGRATUITOUS; /* XXX */ + } + + return 0; +} + +#ifdef BFD +#include <bfd.h> + +error_t bfd_mach_host_arch_mach (host_t host, enum bfd_architecture *arch, - long int *machine, - Elf32_Half *e_machine) + long int *machine) { error_t err; struct host_basic_info hostinfo; @@ -117,3 +182,5 @@ bfd_mach_host_arch_mach (host_t host, return 0; } + +#endif /* BFD */ diff --git a/exec/main.c b/exec/main.c index 809b99a8..efad85aa 100644 --- a/exec/main.c +++ b/exec/main.c @@ -1,46 +1,48 @@ /* GNU Hurd standard exec server, main program and server mechanics. - Copyright (C) 1992, 1993, 19941996 Free Software Foundation, Inc. - Written by Roland McGrath. -This file is part of the GNU Hurd. + Copyright (C) 1992,93,94,95,96,97,98,99,2000,01,02 + Free Software Foundation, Inc. + Written by Roland McGrath. + This file is part of the GNU Hurd. -The GNU Hurd is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. -The GNU Hurd is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with the GNU Hurd; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + You should have received a copy of the GNU General Public License + along with the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "priv.h" #include <error.h> #include <hurd/paths.h> #include <hurd/startup.h> +#include <argp.h> +#include <version.h> +const char *argp_program_version = STANDARD_HURD_VERSION (exec); +#ifdef BFD bfd_arch_info_type host_bfd_arch_info; bfd host_bfd = { arch_info: &host_bfd_arch_info }; -Elf32_Half elf_machine; /* ELF e_machine for the host. */ - extern error_t bfd_mach_host_arch_mach (host_t host, enum bfd_architecture *bfd_arch, long int *bfd_machine, - Elf32_Half *elf_machine); - + ElfW(Half) *elf_machine); +#endif /* Trivfs hooks. */ int trivfs_fstype = FSTYPE_MISC; int trivfs_fsid = 0; -int trivfs_support_read = 1; -int trivfs_support_write = 1; -int trivfs_support_exec = 1; -int trivfs_allow_open = O_READ|O_WRITE|O_EXEC; +int trivfs_support_read = 0; +int trivfs_support_write = 0; +int trivfs_allow_open = 0; struct port_class *trivfs_protid_portclasses[1]; struct port_class *trivfs_cntl_portclasses[1]; @@ -49,7 +51,6 @@ int trivfs_cntl_nportclasses = 1; struct trivfs_control *fsys; -char *exec_version = "0.0"; char **save_argv; @@ -72,21 +73,15 @@ deadboot (void *p) struct bootinfo *boot = p; size_t i; - vm_deallocate (mach_task_self (), - (vm_address_t) boot->argv, boot->argvlen); - vm_deallocate (mach_task_self (), - (vm_address_t) boot->envp, boot->envplen); + munmap (boot->argv, boot->argvlen); + munmap (boot->envp, boot->envplen); for (i = 0; i < boot->dtablesize; ++i) mach_port_deallocate (mach_task_self (), boot->dtable[i]); for (i = 0; i < boot->nports; ++i) mach_port_deallocate (mach_task_self (), boot->portarray[i]); - vm_deallocate (mach_task_self (), - (vm_address_t) boot->portarray, - boot->nports * sizeof (mach_port_t)); - vm_deallocate (mach_task_self (), - (vm_address_t) boot->intarray, - boot->nints * sizeof (int)); + munmap (boot->portarray, boot->nports * sizeof (mach_port_t)); + munmap (boot->intarray, boot->nints * sizeof (int)); /* See if we are going away and this was the last thing keeping us up. */ if (ports_count_class (trivfs_cntl_portclasses[0]) == 0) @@ -113,17 +108,21 @@ main (int argc, char **argv) { error_t err; mach_port_t bootstrap; + struct argp argp = { 0, 0, 0, "Hurd standard exec server." }; + + argp_parse (&argp, argc, argv, 0, 0, 0); save_argv = argv; +#ifdef BFD /* Put the Mach kernel's idea of what flavor of machine this is into the fake BFD against which architecture compatibility checks are made. */ err = bfd_mach_host_arch_mach (mach_host_self (), &host_bfd.arch_info->arch, - &host_bfd.arch_info->mach, - &elf_machine); + &host_bfd.arch_info->mach); if (err) error (1, err, "Getting host architecture from Mach"); +#endif task_get_bootstrap_port (mach_task_self (), &bootstrap); if (bootstrap == MACH_PORT_NULL) @@ -150,8 +149,7 @@ main (int argc, char **argv) /* Launch. */ ports_manage_port_operations_multithread (port_bucket, exec_demuxer, - 2 * 60 * 1000, 0, - 0, MACH_PORT_NULL); + 2 * 60 * 1000, 0, 0); return 0; } @@ -204,24 +202,6 @@ trivfs_goaway (struct trivfs_control *fsys, int flags) } } -/* Attempt to set the active translator for the exec server so that - filesystems other than the bootstrap can find it. */ -void -set_active_trans () -{ - file_t execnode; - - execnode = file_name_lookup (_SERVERS_EXEC, O_NOTRANS | O_CREAT, 0666); - if (execnode == MACH_PORT_NULL) - return; - - file_set_translator (execnode, 0, FS_TRANS_SET, 0, 0, 0, - ports_get_right (fsys), MACH_MSG_TYPE_MAKE_SEND); - /* Don't deallocate EXECNODE here. If we drop the last reference, - a bug in ufs might throw away the active translator. XXX */ -} - - /* Sent by the bootstrap filesystem after the other essential servers have been started up. */ @@ -229,7 +209,7 @@ kern_return_t S_exec_init (struct trivfs_protid *protid, auth_t auth, process_t proc) { - mach_port_t host_priv, dev_master, startup; + mach_port_t host_priv, startup; error_t err; if (! protid || ! protid->isroot) @@ -239,50 +219,45 @@ S_exec_init (struct trivfs_protid *protid, _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], auth); /* Consume. */ /* Do initial setup with the proc server. */ - _hurd_proc_init (save_argv); - - /* Set the active translator on /servers/exec. */ - set_active_trans (); + _hurd_proc_init (save_argv, NULL, 0); procserver = getproc (); - err = get_privileged_ports (&host_priv, &dev_master); - if (!err) - { - proc_register_version (procserver, host_priv, "exec", HURD_RELEASE, - exec_version); - mach_port_deallocate (mach_task_self (), dev_master); - err = proc_getmsgport (procserver, 1, &startup); - if (err) - { - mach_port_deallocate (mach_task_self (), host_priv); - host_priv = MACH_PORT_NULL; - } - } - else - host_priv = MACH_PORT_NULL; - + /* Have the proc server notify us when the canonical ints and ports + change. This will generate an immediate callback giving us the + initial boot-time canonical sets. */ { - /* Have the proc server notify us when the canonical ints and ports - change. */ - + struct iouser *user; struct trivfs_protid *cred; - err = trivfs_open (fsys, 0, 0, 0, 0, 0, MACH_PORT_NULL, &cred); + mach_port_t right; + + err = iohelp_create_empty_iouser (&user); + assert_perror (err); + err = trivfs_open (fsys, user, 0, MACH_PORT_NULL, &cred); assert_perror (err); - proc_execdata_notify (procserver, ports_get_right (cred), - MACH_MSG_TYPE_MAKE_SEND); + right = ports_get_send_right (cred); + proc_execdata_notify (procserver, right, MACH_MSG_TYPE_COPY_SEND); + mach_port_deallocate (mach_task_self (), right); } + err = get_privileged_ports (&host_priv, NULL); + assert_perror (err); + + proc_register_version (procserver, host_priv, "exec", "", HURD_VERSION); + + err = proc_getmsgport (procserver, 1, &startup); + assert_perror (err); + mach_port_deallocate (mach_task_self (), procserver); + /* Call startup_essential task last; init assumes we are ready to run once we call it. */ - if (host_priv != MACH_PORT_NULL) - { - startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL, - "exec", host_priv); - mach_port_deallocate (mach_task_self (), startup); - mach_port_deallocate (mach_task_self (), host_priv); - } + err = startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL, + "exec", host_priv); + assert_perror (err); + mach_port_deallocate (mach_task_self (), startup); + + mach_port_deallocate (mach_task_self (), host_priv); return 0; } diff --git a/exec/priv.h b/exec/priv.h index 0ded21eb..7cee15e4 100644 --- a/exec/priv.h +++ b/exec/priv.h @@ -1,5 +1,5 @@ /* GNU Hurd standard exec server, private declarations. - Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Copyright (C) 1992,93,94,95,96,99,2000,02, 04 Free Software Foundation, Inc. Written by Roland McGrath. This file is part of the GNU Hurd. @@ -9,7 +9,7 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -The GNU Hurd is distributed in the hope that it will be useful, +The GNU Hurd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -22,12 +22,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include <hurd/trivfs.h> #include <hurd/ports.h> #include <hurd/lookup.h> #include <rwlock.h> + +#ifdef BFD #include <bfd.h> +#endif + #include <elf.h> +#include <link.h> /* This gives us the ElfW macro. */ #include <fcntl.h> #include "exec_S.h" @@ -35,11 +41,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef exec_priv_h #define exec_priv_h +#ifdef BFD /* A BFD whose architecture and machine type are those of the host system. */ extern bfd_arch_info_type host_bfd_arch_info; extern bfd host_bfd; -extern Elf32_Half elf_machine; /* ELF e_machine for the host. */ - +#endif /* Information kept around to be given to a new task in response to a message on the task's bootstrap port. */ @@ -62,11 +68,14 @@ struct bootinfo struct port_bucket *port_bucket; struct port_class *execboot_portclass; - -typedef struct trivfs_protid *trivfs_protid_t; /* For MiG. */ - extern mach_port_t procserver; /* Our proc port. */ +#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. */ @@ -77,16 +86,46 @@ struct execdata /* Set by check. */ vm_address_t entry; - FILE stream; 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 bfd *bfd; #endif + union /* Interpreter section giving name of file. */ { asection *section; - const Elf32_Phdr *phdr; + const ElfW(Phdr) *phdr; } interp; memory_object_t filemap, cntlmap; struct shared_io *cntl; @@ -108,16 +147,26 @@ struct execdata /* Program header table read from the executable. After `check' this is a pointer into the mapping window. By `load' it is local alloca'd storage. */ - Elf32_Phdr *phdr; - Elf32_Word phnum; /* Number of program header table elements. */ + ElfW(Phdr) *phdr; + ElfW(Addr) phdr_addr; + ElfW(Word) phnum; /* Number of program header table elements. */ int anywhere; /* Nonzero if image can go anywhere. */ vm_address_t loadbase; /* Actual mapping location. */ + int execstack; /* Zero if stack can be nonexecutable. */ } elf; } info; }; +error_t elf_machine_matches_host (ElfW(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, 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, |