summaryrefslogtreecommitdiff
path: root/exec
diff options
context:
space:
mode:
authorMichael I. Bushnell <mib@gnu.org>1996-07-18 04:35:29 +0000
committerMichael I. Bushnell <mib@gnu.org>1996-07-18 04:35:29 +0000
commit94cef36797600d11a50d09828fa80df8a73dfd1c (patch)
treeb7cba9afef95489eedef534d3e6946eb13f595ba /exec
parent88dbbbf9e48e24f1ac007c1e4eeffd9caf8e2fad (diff)
*** empty log message ***
Diffstat (limited to 'exec')
-rw-r--r--exec/core.c264
-rw-r--r--exec/elfcore.c100
-rw-r--r--exec/exectrans.c81
-rw-r--r--exec/gcore.c88
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);
+}