diff options
author | Michael I. Bushnell <mib@gnu.org> | 1996-07-18 04:35:29 +0000 |
---|---|---|
committer | Michael I. Bushnell <mib@gnu.org> | 1996-07-18 04:35:29 +0000 |
commit | 94cef36797600d11a50d09828fa80df8a73dfd1c (patch) | |
tree | b7cba9afef95489eedef534d3e6946eb13f595ba /exec | |
parent | 88dbbbf9e48e24f1ac007c1e4eeffd9caf8e2fad (diff) |
*** empty log message ***
Diffstat (limited to 'exec')
-rw-r--r-- | exec/core.c | 264 | ||||
-rw-r--r-- | exec/elfcore.c | 100 | ||||
-rw-r--r-- | exec/exectrans.c | 81 | ||||
-rw-r--r-- | exec/gcore.c | 88 |
4 files changed, 533 insertions, 0 deletions
diff --git a/exec/core.c b/exec/core.c new file mode 100644 index 00000000..6d685a23 --- /dev/null +++ b/exec/core.c @@ -0,0 +1,264 @@ +/* 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/elfcore.c b/exec/elfcore.c new file mode 100644 index 00000000..4388a135 --- /dev/null +++ b/exec/elfcore.c @@ -0,0 +1,100 @@ +{ + 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; + + /* 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); + if (err) + goto lose; + + 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; + } diff --git a/exec/exectrans.c b/exec/exectrans.c new file mode 100644 index 00000000..59c9cdf2 --- /dev/null +++ b/exec/exectrans.c @@ -0,0 +1,81 @@ + +#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 new file mode 100644 index 00000000..7343516c --- /dev/null +++ b/exec/gcore.c @@ -0,0 +1,88 @@ +/* `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); +} |