bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: core file writing


From: Roland McGrath
Subject: Re: core file writing
Date: Mon, 11 Mar 2002 04:18:41 -0500 (EST)

We now have core dumps!  Many thanks to Jon Arney for his hacking on this
that spurred me to write some new code, and for helping to debug it.

I have now added a sys/procfs.h header file installed by the hurd package
(it's in hurd/include/sys/procfs.h).  This defines the data structures used
in the note segment in ELF core files.  I've added new code to the crash
server to write ELF core files using these data structures.  The note
formats are patterned after those used by Solaris, for which the gdb code
to read the formats based on sys/procfs.h types already exists and handles
multiple threads.

Please test the core file writing code.  Once you've installed the new
crash server, and set /servers/crash using --core-file, you can test it
using the /bin/gcore command you already have.  For actual crashes to
create core files properly, you need the libc fix (which is in cvs for both
branches).

An old gdb probably ought to be able to read one of these core dumps enough
to tell you about the memory regions with `info files'.  You can also use
objdump and elfdump to see that the contents look sane for the process you
dumped.

gdb should understand these core files every bit as well as it does on any
other platform if you make sure that the hurd's new sys/procfs.h is
installed (there are no other related header changes, so you can just copy
it into /include) and rebuild gdb with the following patches.  (These
patches are against the current gdb in cvs, but they should apply fine to
5.1 as well.)  Make sure you re-run configure you don't have an old
../config.cache file in your gdb build, since it will contain lies about
sys/procfs.h and its contents.

This should also be enough for gdb's "gcore" command to work.  It creates a
core file with less complete information than the crash server's core files
will contain, but it should be enough for gdb to read it back in again.

I have compiled all this code but much of it is not fully tested.
Please test it and post your results here.  I would like to get these gdb
changes integrated upstream as soon as we know they work.


Thanks,
Roland




Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.2312
diff -b -p -u -r1.2312 ChangeLog
--- ChangeLog 2002/03/11 00:01:07 1.2312
+++ ChangeLog 2002/03/11 08:47:33
@@ -1,3 +1,13 @@
+2002-03-10  Roland McGrath  <roland@frob.com>
+
+       * config/i386/i386gnu.mh (NATDEPFILES): Add core-regset.o here.
+       * i386gnu-nat.c [HAVE_SYS_PROCFS_H]
+       (supply_gregset, supply_fpregset): New functions.
+
+       * gnu-nat.c (gnu_find_memory_regions): New function.
+       (init_gnu_ops): Set `to_find_memory_regions' hook to that.
+       (gnu_xfer_memory): Add a cast.
+
 2002-03-10  Daniel Jacobowitz  <drow@mvista.com>
 
        * Makefile.in (defs_h): Add $(INCLUDE_DIR)/gdb/signals.h.
Index: gnu-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/gnu-nat.c,v
retrieving revision 1.18
diff -b -p -u -r1.18 gnu-nat.c
--- gnu-nat.c 2002/01/06 19:18:28 1.18
+++ gnu-nat.c 2002/03/11 08:47:35
@@ -2458,7 +2458,7 @@ gnu_xfer_memory (CORE_ADDR memaddr, char
   else
     {
       inf_debug (current_inferior, "%s %p[%d] %s %p",
-                write ? "writing" : "reading", memaddr, len,
+                write ? "writing" : "reading", (void *) memaddr, len,
                 write ? "<--" : "-->", myaddr);
       if (write)
        return gnu_write_inferior (task, memaddr, myaddr, len);
@@ -2467,6 +2467,86 @@ gnu_xfer_memory (CORE_ADDR memaddr, char
     }
 }
 
+/* Call FUNC on each memory region in the task.  */
+static int
+gnu_find_memory_regions (int (*func) (CORE_ADDR,
+                                     unsigned long,
+                                     int, int, int,
+                                     void *),
+                          void *data)
+{
+  error_t err;
+  task_t task;
+  vm_address_t region_address, last_region_address, last_region_end;
+  vm_prot_t last_protection;
+
+  if (current_inferior == 0 || current_inferior->task == 0)
+    return 0;
+  task = current_inferior->task->port;
+  if (task == MACH_PORT_NULL)
+    return 0;
+
+  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;
+      vm_address_t old_address = region_address;
+
+      err = vm_region (task,
+                      &region_address,
+                      &region_length,
+                      &protection,
+                      &max_protection,
+                      &inheritance,
+                      &shared,
+                      &object_name,
+                      &offset);
+      if (err == KERN_NO_SPACE)
+       break;
+      if (err != KERN_SUCCESS)
+       {
+         warning ("vm_region failed: %s", mach_error_string (err));
+         return -1;
+       }
+
+      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 report
+            that previous one.  */
+         if (last_protection != VM_PROT_NONE)
+           (*func) (last_region_address,
+                    last_region_end - last_region_address,
+                    last_protection & VM_PROT_READ,
+                    last_protection & VM_PROT_WRITE,
+                    last_protection & VM_PROT_EXECUTE,
+                    data);
+         last_region_address = region_address;
+         last_region_end = region_address += region_length;
+         last_protection = protection;
+       }
+    }
+
+  /* Report the final region.  */
+  if (last_region_end > last_region_address && last_protection != VM_PROT_NONE)
+    (*func) (last_region_address, last_region_end - last_region_address,
+            last_protection & VM_PROT_READ,
+            last_protection & VM_PROT_WRITE,
+            last_protection & VM_PROT_EXECUTE,
+            data);
+
+  return 0;
+}
 
 /* Return printable description of proc.  */
 char *
@@ -2524,6 +2604,7 @@ init_gnu_ops (void)
   gnu_ops.to_store_registers = gnu_store_registers;    /* to_store_registers */
   gnu_ops.to_prepare_to_store = gnu_prepare_to_store; /* to_prepare_to_store */
   gnu_ops.to_xfer_memory = gnu_xfer_memory; /* to_xfer_memory */
+  gnu_ops.to_find_memory_regions = gnu_find_memory_regions;
   gnu_ops.to_files_info = 0;           /* to_files_info */
   gnu_ops.to_insert_breakpoint = memory_insert_breakpoint;
   gnu_ops.to_remove_breakpoint = memory_remove_breakpoint;
Index: i386gnu-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386gnu-nat.c,v
retrieving revision 1.8
diff -b -p -u -r1.8 i386gnu-nat.c
--- i386gnu-nat.c 2002/01/19 12:51:04 1.8
+++ i386gnu-nat.c 2002/03/11 08:47:35
@@ -38,6 +38,10 @@
 #include "gnu-nat.h"
 #include "i387-nat.h"
 
+#ifdef HAVE_SYS_PROCFS_H
+# include <sys/procfs.h>
+# include "gregset.h"
+#endif
 
 /* Offset to the thread_state_t location where REG is stored.  */
 #define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)
@@ -87,6 +91,24 @@ fetch_fpregs (struct proc *thread)
   /* Supply the floating-point registers.  */
   i387_supply_fsave (state.hw_state);
 }
+
+#ifdef HAVE_SYS_PROCFS_H
+/* These two calls are used by the core-regset.c code for
+   reading ELF core files.  */
+void
+supply_gregset (gdb_gregset_t *gregs)
+{
+  int i;
+  for (i = 0; i < NUM_GREGS; i++)
+    supply_register (i, REG_ADDR (gregs, i));
+}
+
+void
+supply_fpregset (gdb_fpregset_t *fpregs)
+{
+  i387_supply_fsave ((char *) fpregs);
+}
+#endif
 
 /* Fetch register REGNO, or all regs if REGNO is -1.  */
 void
Index: config/i386/i386gnu.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/i386gnu.mh,v
retrieving revision 1.6
diff -b -p -u -r1.6 i386gnu.mh
--- config/i386/i386gnu.mh 2002/01/18 04:50:59 1.6
+++ config/i386/i386gnu.mh 2002/03/11 08:47:35
@@ -1,5 +1,8 @@
 # Host: Intel 386 running the GNU Hurd
-NATDEPFILES= i386gnu-nat.o i387-nat.o gnu-nat.o fork-child.o solib.o 
solib-svr4.o solib-legacy.o corelow.o notify_S.o process_reply_S.o 
msg_reply_S.o msg_U.o exc_request_U.o exc_request_S.o
+NATDEPFILES= i386gnu-nat.o i387-nat.o gnu-nat.o corelow.o core-regset.o \
+            fork-child.o solib.o solib-svr4.o solib-legacy.o \
+            notify_S.o process_reply_S.o msg_reply_S.o \
+            msg_U.o exc_request_U.o exc_request_S.o
 XM_FILE= xm-i386gnu.h
 NAT_FILE= nm-gnu.h
 MH_CFLAGS = -D_GNU_SOURCE



reply via email to

[Prev in Thread] Current Thread [Next in Thread]