bug-hurd
[Top][All Lists]
Advanced

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

Re: core file writing


From: Jon Arney
Subject: Re: core file writing
Date: Thu, 07 Mar 2002 18:42:35 -0700

Hurah!

At long last, I have succeeded in getting the following program
to produce and read a core file under the Hurd:

int main(int argc, char **argv){char *p = NULL; *p = '\0';}

This is not a done project, but I think enough is working to
upload some patches.  There are some known issues/limitations
which I have tried my best to document below.

I can't take much credit for this work at all since Roland McGrath has
done a lot of the heavy lifting.   I also want to say thanks
for the help he has given me and his patience with me.  I now have
a much greater appreciation for the chain of events following
a dereference of an invalid pointer. :)

There are three (count them three) patches involved.  One to
'hurd/trans/*' to write the core file.  One to 'glibc' to properly
call '__dir_link' and one to 'gdb' to read it semi-cleanly.
Note that the 'gdb' patch INCLUDES Roland's original patch
for gnu_find_memory_regions(), so you won't be able to apply
both at the same time.  My patch includes his in addition
to code required to properly read the general purpose register
set from the core file.

Total patch inventory:
GDB:
src/gdb/gnu-nat.c

GLIBC:
glibc-2.2.5/hurd/hurdsig.c

HURD:
hurd/trans/Makefile
hurd/trans/elfcore.c
hurd/trans/procfs.h
hurd/trans/procfs-i386-gnu.h

Just as a teaser, here is a gdb session from a simple example:

Core was generated by `'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.0.2...done.
Loaded symbols for /lib/libc.so.0.2
Reading symbols from /lib/ld.so...done.
Loaded symbols for /lib/ld.so
Reading symbols from /lib/libmachuser.so.1...done.
Loaded symbols for /lib/libmachuser.so.1
Reading symbols from /lib/libhurduser.so.0.0...done.
Loaded symbols for /lib/libhurduser.so.0.0
#0  0x00000000 in ?? ()
(gdb) info threads
  3 process 7089578  0x0104a70c in __mach_msg_trap () from
/lib/libc.so.0.2
  2 process 7024042  0x08048570 in main (argc=1, argv=0x1026c30)
    at make-core.c:6
* 1 process 11690  0x00000000 in ?? ()
(gdb) thread 2
[Switching to thread 2 (process 7024042)]#0  0x08048570 in main (argc=1, 
    argv=0x1026c30) at make-core.c:6
6         *p = '\0';
(gdb) bt
#0  0x08048570 in main (argc=1, argv=0x1026c30) at make-core.c:6
#1  0x0106d6e2 in __libc_start_main (main=0x8048560 <main>, argc=1, 
    ubp_av=0x1026c30, init=0x80483c0 <_init>, fini=0x80485d0 <_fini>, 
    rtld_fini=0xc744 <_dl_fini>, stack_end=0x1026c2c)
    at ../sysdeps/generic/libc-start.c:129
(gdb) list
1       #include <stdio.h>
2
3       int main(int argc, char **argv)
4       {
5         char *p = NULL;
6         *p = '\0';
7       }
(gdb) q

KNOWN ISSUES

The call to '__dir_link' in 'glibc/hurd/hurdsig.c' can fail,
and if it does, we may end up orphaning the core file (I had
that happen a couple of times).

GDB and crash need to agree on more particulars of the thread
and process information.  As you can see from the above trace,
some of the thread information came out in GDB as a little
garbled.

The core files are way too big.  In general, we need a way to avoid
dumping shared libraries and other information not absolutely required
to use GDB.  I haven't yet figured out how to tell shared library
space from normal user space through vm_region().  Perhaps we should
in general not dump anything with the 'X' attribute?

Floating point registers not working--yet.

If a filesystem crashes (like ext2fs), it can dump a core and
if it does, we may have a problem with the crash server trying
to dump core through a dead filesystem server.  Hopefully this
won't happen too often.


Have fun!


Jonathan S. Arney
Software Engineer
jarney1@cox.net
------------------------------------------------------------------------
*** hurd/trans/Makefile Thu Mar  7 16:45:02 2002
--- hurd/trans.new/Makefile     Thu Mar  7 16:42:36 2002
***************
*** 20,27 ****
  
  targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
          password hello hello-mt streamio
! SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
!       crash.c firmlink.c password.c hello.c hello-mt.c streamio.c
  OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
        crashServer.o crash_replyUser.o msgServer.o \
        device_replyServer.o
--- 20,27 ----
  
  targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
          password hello hello-mt streamio
! SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c elfcore.c
!       crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \
  OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
        crashServer.o crash_replyUser.o msgServer.o \
        device_replyServer.o
***************
*** 32,40 ****
  
  symlink: fsysServer.o
  ifsock: ifsockServer.o
! crash: crashServer.o crash_replyUser.o msgServer.o
  password: passwordServer.o
  streamio: device_replyServer.o
  
  crash password streamio: ../libthreads/libthreads.a ../libports/libports.a 
../libtrivfs/libtrivfs.a ../libthreads/libthreads.a ../libfshelp/libfshelp.a
  fifo new-fifo: ../libpipe/libpipe.a
--- 32,55 ----
  
  symlink: fsysServer.o
  ifsock: ifsockServer.o
! crash: crashServer.o crash_replyUser.o msgServer.o elfcore.o
  password: passwordServer.o
  streamio: device_replyServer.o
+ 
+ #
+ # GDB needs/expects to see these structures
+ # defined in <sys/procfs.h>.  Putting them
+ # there was simpler than modifying GDB,
+ # it's configure, and other stuff.
+ #
+ INSTHDRS = procfs.h procfs-i386-gnu.h
+ 
+ install-headers install: $(includedir)/sys \
+       $(addprefix $(includedir)/sys/,$(INSTHDRS))
+ 
+ $(includedir)/sys/%: $(srcdir)/%; $(INSTALL_DATA) $< $@
+ 
+ $(includedir)/sys:;mkdir -p $@
  
  crash password streamio: ../libthreads/libthreads.a ../libports/libports.a 
../libtrivfs/libtrivfs.a ../libthreads/libthreads.a ../libfshelp/libfshelp.a
  fifo new-fifo: ../libpipe/libpipe.a
*** hurd/trans/elfcore.c        Thu Mar  7 23:46:27 2002
--- hurd/trans.new/elfcore.c    Fri Mar  8 00:42:19 2002
***************
*** 0 ****
--- 1,458 ----
+ #include <hurd.h>
+ #include <elf.h>
+ #include <link.h>
+ #include <string.h>
+ #include <sys/mman.h>
+ #include <sys/utsname.h>
+ 
+ /*
+  * TODO:
+  *   * Clean up some of the data that gets put into
+  *     the notes files--particularly with respect to
+  *     the thread and process information.
+  *
+  *   *
+  */
+ 
+ #define _IN_CRASH_SERVER
+ #include "procfs.h"
+ 
+ extern process_t procserver;          /* Our proc port, for easy access.  */
+ 
+ /* The size of the initial buffer malloced to try and avoid getting
+    vm_alloced memory for the procinfo structure returned by getprocinfo.
+    Here we just give enough for four threads.  */
+ #define PROCINFO_MALLOC_SIZE \
+   (sizeof (struct procinfo) + 4 * sizeof (threadinfo_data_t))
+ 
+ #define WAITS_MALLOC_SIZE     128
+ 
+ error_t
+ dump_core (task_t task, file_t file, off_t corelimit,
+          int signo, long int sigcode, int sigerror)
+ {
+   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_ARCH,
+     e_ehsize: sizeof hdr,
+     e_phentsize: sizeof phdrs[0],
+     e_phoff: sizeof hdr,      /* Fill in e_phnum later.  */
+   };
+   off_t offset;
+   size_t wrote;
+ 
+   thread_t *threads;
+   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[4];
+   };
+ #define NOTE_HEADER(type, size) \
+   ((struct note_header) { { 4, (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;
+         offset = (offset + wrote + 3) &~ 3; /* Pad it to word alignment.  */
+         if (wrote > size)
+           break;
+         data += wrote;
+         size -= wrote;
+       }
+       return err;
+     }
+ 
+   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 = &regions, *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 = &region->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,
+                        &region_address,
+                        &region_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 = round_page (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)
+     return err;
+   if (wrote < sizeof hdr)
+     return EGRATUITOUS;               /* XXX */
+ 
+   /* Now we can write the various notes.  */
+   notestart = offset;
+ 
+   /* First a dull note containing the results of `uname', a la Solaris.  */
+   {
+     DEFINE_NOTE (struct utsname) note;
+     if (uname (&note.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;
+ 
+   /* The pstatus_t note should contain the death info and some process-global
+      info we should get from the proc server, but no thread-specific info
+      like register state.  We need to define this type.  */
+   {
+     DEFINE_NOTE (prstatus_t) prstatus_note;
+     DEFINE_NOTE (prpsinfo_t) psinfo_note;
+     struct procinfo *pi;
+     u_int pi_size;
+     int pi_flags;
+     char *waits;
+     u_int waits_len;
+     pid_t pid;
+     pid_t ppid;
+     pid_t orphaned;
+     mach_port_t userproc = MACH_PORT_NULL;
+     thread_t thread = 0;
+ 
+     pi = malloc (PROCINFO_MALLOC_SIZE);
+     if (!pi) {
+       return ENOMEM;
+     }
+     pi_size = PROCINFO_MALLOC_SIZE/sizeof(int);
+ 
+     waits = malloc(WAITS_MALLOC_SIZE);
+     if (!waits) {
+       free(pi);
+       return ENOMEM;
+     }
+     waits_len = WAITS_MALLOC_SIZE;
+     
+     err = proc_task2proc (procserver, task, &userproc);
+     if (err) {
+       free(pi);
+       free(waits);
+       return err;
+     }
+ 
+     err = proc_getpids (userproc, &pid, &ppid, &orphaned);
+     if (err) {
+       free(pi);
+       free(waits);
+       return err;
+     }
+ 
+     err = proc_getprocinfo(procserver, pid, &pi_flags, (procinfo_t *)&pi, 
&pi_size, &waits, &waits_len);
+     if (err) {
+       free(pi);
+       free(waits);
+       return err;
+     }
+ 
+     memset(&psinfo_note.data, 0, sizeof(psinfo_note.data));
+     memset(&prstatus_note.data, 0, sizeof(prstatus_note.data));
+ 
+     prstatus_note.data.pr_info.si_signo = prstatus_note.data.pr_cursig = 
signo;
+     prstatus_note.data.pr_info.si_code = sigcode;
+     prstatus_note.data.pr_info.si_errno = sigerror;
+     prstatus_note.data.pr_sigpend = 0; /*XXX*/
+     prstatus_note.data.pr_sighold = 0; /*XXX*/
+ 
+     psinfo_note.data.pr_pid = prstatus_note.data.pr_pid = pid;
+     psinfo_note.data.pr_ppid = prstatus_note.data.pr_ppid = pi->ppid;
+     psinfo_note.data.pr_pgrp = prstatus_note.data.pr_pgrp = pi->pgrp;
+     psinfo_note.data.pr_sid = prstatus_note.data.pr_sid = pi->session;
+     prstatus_note.data.pr_utime.tv_usec = pi->taskinfo.user_time.microseconds;
+     prstatus_note.data.pr_utime.tv_sec = pi->taskinfo.user_time.seconds;
+     prstatus_note.data.pr_stime.tv_usec = pi->taskinfo.user_time.microseconds;
+     prstatus_note.data.pr_stime.tv_sec = pi->taskinfo.user_time.seconds;
+     
+     /*
+      * <XXX>
+      * is there any more info available under
+      * the Hurd about process accounting/time usage?
+      */
+     prstatus_note.data.pr_cutime.tv_usec = 0;
+     prstatus_note.data.pr_cutime.tv_sec = 0;
+     prstatus_note.data.pr_cstime.tv_usec = 0;
+     prstatus_note.data.pr_cstime.tv_sec = 0;
+     /*
+      * </XXX>
+      */
+     
+     i = pi->state;
+     psinfo_note.data.pr_state = i; /*XXX*/
+     psinfo_note.data.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
+     psinfo_note.data.pr_zomb = psinfo_note.data.pr_sname == 'Z';
+     psinfo_note.data.pr_nice = pi->taskinfo.base_priority;
+     psinfo_note.data.pr_flag = 0; /*XXX*/
+     psinfo_note.data.pr_uid = pi->owner;
+     psinfo_note.data.pr_gid = 0; /*XXX*/
+     strcpy(psinfo_note.data.pr_psargs, ""); /*XXX*/
+     strcpy(psinfo_note.data.pr_fname, "fooprogram"); /*XXX*/
+ 
+     free(pi);
+     free(waits);
+ 
+     err = WRITE_NOTE (NT_PRSTATUS, prstatus_note);
+     if (!err) {
+       err = WRITE_NOTE (NT_PRPSINFO, psinfo_note);
+     }
+   }
+   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)
+     {
+       {
+       /* lwpinfo_t a la Solaris gives thread's CPU time and such.  */
+       DEFINE_NOTE (struct thread_basic_info) note;
+       mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
+       err = thread_info (threads[i], THREAD_BASIC_INFO,
+                          (thread_info_t)&note.data, &count);
+       if (err == 0)
+         err = WRITE_NOTE (NT_LWPSINFO, note);
+       else                    /* Just skip it if we can't get the info.  */
+         err = 0;
+       }
+       if (err || (corelimit >= 0 && corelimit <= offset))
+       break;
+ 
+       {
+       DEFINE_NOTE (lwpstatus_t) lwpstatus_note;
+       int thread_state_size;
+       
+       thread_state_size = sizeof(struct i386_thread_state);
+       err = thread_get_state(threads[i],
+                              i386_THREAD_STATE,
+                              (thread_state_t )&lwpstatus_note.data.pr_reg,
+                              &thread_state_size);
+       if (err) {
+         break;
+       }
+ 
+       err = thread_get_state(threads[i],
+                              i386_FLOAT_STATE,
+                              (thread_state_t )&lwpstatus_note.data.pr_fpreg,
+                              &thread_state_size);
+       /* If we can't get FP info, no biggie, not everyone has one */
+       if (err) err = 0;
+ 
+       lwpstatus_note.data.pr_lwpid = threads[i];
+       lwpstatus_note.data.pr_cursig = signo;
+ 
+       err = WRITE_NOTE(NT_LWPSTATUS, lwpstatus_note);
+       if (err || (corelimit >= 0 && corelimit <= offset))
+         break;
+       }
+       if (err || (corelimit >= 0 && corelimit <= offset))
+       break;
+       mach_port_deallocate (mach_task_self (), threads[i]);
+     }
+   while (i < nthreads)
+     mach_port_deallocate (mach_task_self (), threads[i++]);
+   munmap (threads, nthreads * sizeof *threads);
+   if (err || (corelimit >= 0 && corelimit <= offset))
+     return err;
+ 
+   /* 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 record 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)
+     {
+       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 = 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;
+           int copy_count;
+           err = vm_read (task, va, sz, &copied, &copy_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;
+ }
+ 
*** hurd/trans/procfs.h Thu Mar  7 23:46:33 2002
--- hurd/trans.new/procfs.h     Thu Mar  7 23:18:09 2002
***************
*** 0 ****
--- 1,84 ----
+ /*
+  * Core dump stuff for the Hurd.
+  * Borrowed with apologies from Linux.
+  */
+ #ifndef ELF_CORE_H
+ #define ELF_CORE_H
+ 
+ #define ELF_PRARGSZ (80)
+ 
+ struct elf_siginfo {
+   int si_signo;
+   int si_code;
+   int si_errno;
+ };
+ 
+ #ifdef _IN_CRASH_SERVER
+ #include "procfs-i386-gnu.h"
+ #else
+ #include <features.h>
+ #include <sys/time.h>
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <sys/procfs-i386-gnu.h>
+ #endif
+ 
+ typedef struct prstatus_st {
+   struct elf_siginfo pr_info;
+   short pr_cursig;
+   unsigned long pr_sigpend;
+   unsigned long pr_sighold;
+   unsigned long pr_pid;
+   unsigned long pr_ppid;
+   unsigned long pr_pgrp;
+   unsigned long pr_sid;
+   struct timeval pr_utime;
+   struct timeval pr_stime;
+   struct timeval pr_cutime;
+   struct timeval pr_cstime;
+   elf_gregset_t pr_reg;
+   int pr_fpvalid;
+ } prstatus_t;
+ 
+ typedef struct prpsinfo_st {
+   char pr_state;
+   char pr_sname;
+   char pr_zomb;
+   char pr_nice;
+   unsigned long pr_flag;
+   uid_t pr_uid;
+   gid_t pr_gid;
+   pid_t pr_pid;
+   pid_t pr_ppid;
+   pid_t pr_pgrp;
+   pid_t pr_sid;
+   char pr_fname[16];
+   char pr_psargs[ELF_PRARGSZ];
+ } prpsinfo_t;
+ 
+ typedef struct lwpstatus_st {
+   struct i386_thread_state pr_reg;
+   struct i386_float_state pr_fpreg;
+   pid_t pr_lwpid;
+   int pr_cursig;
+ } lwpstatus_t;
+ 
+ #define EAX (offsetof(struct i386_thread_state, eax)>>2)
+ #define ECX (offsetof(struct i386_thread_state, ecx)>>2)
+ #define EDX (offsetof(struct i386_thread_state, edx)>>2)
+ #define EBX (offsetof(struct i386_thread_state, ebx)>>2)
+ #define EIP (offsetof(struct i386_thread_state, eip)>>2)
+ #define UESP (offsetof(struct i386_thread_state, uesp)>>2)
+ #define EBP (offsetof(struct i386_thread_state, ebp)>>2)
+ #define ESI (offsetof(struct i386_thread_state, esi)>>2)
+ #define EDI (offsetof(struct i386_thread_state, edi)>>2)
+ #define EIP (offsetof(struct i386_thread_state, eip)>>2)
+ #define EFL (offsetof(struct i386_thread_state, efl)>>2)
+ #define CS (offsetof(struct i386_thread_state, cs)>>2)
+ #define SS (offsetof(struct i386_thread_state, ss)>>2)
+ #define DS (offsetof(struct i386_thread_state, ds)>>2)
+ #define ES (offsetof(struct i386_thread_state, es)>>2)
+ #define FS (offsetof(struct i386_thread_state, fs)>>2)
+ #define GS (offsetof(struct i386_thread_state, gs)>>2)
+ 
+ #endif
*** hurd/trans/procfs-i386-gnu.h        Thu Mar  7 23:46:41 2002
--- hurd/trans.new/procfs-i386-gnu.h    Fri Mar  8 00:42:23 2002
***************
*** 0 ****
--- 1,25 ----
+ #include <mach/machine/thread_status.h>
+ 
+ #define ELF_CLASS ELFCLASS32
+ #define ELF_DATA ELFDATA2LSB
+ #define ELF_ARCH EM_386
+ #define ELF_EXEC_PAGESIZE 4096
+ 
+ #include <endian.h>
+ #if BYTE_ORDER == BIG_ENDIAN
+ #define ELF_DATA ELFDATA2MSB
+ #elif BYTE_ORDER == LITTLE_ENDIAN
+ #define ELF_DATA ELFDATA2LSB
+ #endif
+ 
+ #define ELF_CLASS     PASTE (ELFCLASS, __ELF_NATIVE_CLASS)
+ #define PASTE(a, b)   PASTE_1 (a, b)
+ #define PASTE_1(a, b) a##b
+ 
+ #define NT_PRFPREG 2
+ #define NT_TASKSTRUCT 4
+ 
+ typedef unsigned long elf_greg_t;
+ 
+ typedef struct i386_thread_state elf_gregset_t;
+ typedef struct i386_float_state elf_fpregset_t;
*** glibc-2.2.5/hurd/hurdsig.c.orig     Fri Mar  8 00:10:50 2002
--- glibc-2.2.5/hurd/hurdsig.c  Fri Mar  8 00:17:56 2002
***************
*** 198,204 ****
    if (! err && file != MACH_PORT_NULL) {
      /* The core dump into FILE succeeded, so now link it into the
         directory.  */
!     err = __dir_link (file, coredir, name, 1);
    }
    else {
      fprintf(stderr, "Error %i, mach port %p\n", err, file);
--- 198,204 ----
    if (! err && file != MACH_PORT_NULL) {
      /* The core dump into FILE succeeded, so now link it into the
         directory.  */
!     err = __dir_link (coredir, file, name, 1);
    }
    else {
      fprintf(stderr, "Error %i, mach port %p\n", err, file);
*** src/gdb/gnu-nat.c   Thu Mar  7 16:48:47 2002
--- src/gdb/gnu-nat.c.new       Thu Mar  7 16:52:20 2002
***************
*** 32,37 ****
--- 32,38 ----
  #include <stdio.h>
  #include "gdb_string.h"
  #include <sys/ptrace.h>
+ #include <sys/procfs.h>
  
  #include <mach.h>
  #include <mach_error.h>
***************
*** 2467,2472 ****
--- 2468,2553 ----
      }
  }
  
+ /* 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,2529 ****
--- 2605,2611 ----
    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;
***************
*** 3317,3322 ****
--- 3399,3502 ----
           &thread_cmd_list);
  }
  
+ /* Mapping between the general-purpose registers in `struct user'
+    format and GDB's register array layout.  */
+ static int regmap[] = 
+ {
+   EAX, ECX, EDX, EBX,
+   UESP, EBP, ESI, EDI,
+   EIP, EFL, CS, SS,
+   DS, ES, FS, GS
+ };
+ 
+ void
+ supply_gregset (struct i386_thread_state *pr_reg)
+ {
+   unsigned long *regp = (unsigned long *)pr_reg;
+   int i;
+   for (i = 0; i < sizeof(struct i386_thread_state)/sizeof(int); i++)
+     supply_register (i, (char *) (regp + regmap[i]));
+ }
+ 
+ /* Provide registers to GDB from a core file.
+ 
+    (We can't use the generic version of this function in
+    core-regset.c, because Linux has *three* different kinds of
+    register set notes.  core-regset.c would have to call
+    supply_fpxregset, which most platforms don't have.)
+ 
+    CORE_REG_SECT points to an array of bytes, which are the contents
+    of a `note' from a core file which BFD thinks might contain
+    register contents.  CORE_REG_SIZE is its size.
+ 
+    WHICH says which register set corelow suspects this is:
+      0 --- the general-purpose register set, in elf_gregset_t format
+      2 --- the floating-point register set, in elf_fpregset_t format
+      3 --- the extended floating-point register set, in elf_fpxregset_t format
+ 
+    REG_ADDR isn't used on the Hurd.  */
+ 
+ static void
+ fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+                     int which, CORE_ADDR reg_addr)
+ {
+   struct i386_thread_state gregset;
+   struct i386_float_state fpregset;
+ 
+   switch (which)
+     {
+     case 0:
+       if (core_reg_size != sizeof(gregset))
+       warning ("Wrong size gregset in core file.");
+       else
+       {
+         supply_gregset ((struct i386_thread_state *)core_reg_sect);
+       }
+       break;
+ 
+     case 2:
+       if (core_reg_size != sizeof(fpregset))
+       warning ("Wrong size fpregset in core file.");
+       else
+       {
+         memcpy (&fpregset, core_reg_sect, sizeof (fpregset));
+         //      supply_fpregset (&fpregset);
+       }
+       break;
+ 
+ #ifdef HAVE_PTRACE_GETFPXREGS
+       {
+       elf_fpxregset_t fpxregset;
+ 
+       case 3:
+       if (core_reg_size != sizeof (fpxregset))
+         warning ("Wrong size fpxregset in core file.");
+       else
+         {
+           memcpy (&fpxregset, core_reg_sect, sizeof (fpxregset));
+           supply_fpxregset (&fpxregset);
+         }
+       break;
+       }
+ #endif
+ 
+     default:
+       /* We've covered all the kinds of registers we know about here,
+          so this must be something we wouldn't know what to do with
+          anyway.  Just ignore it.  */
+       break;
+     }
+ }
+ 
+ static struct core_fns gnu_elf_core_fns =
+ {
+   bfd_target_elf_flavour,             /* core_flavour */
+   default_check_format,                       /* check_format */
+   default_core_sniffer,                       /* core_sniffer */
+   fetch_core_registers,                       /* core_read_registers */
+   NULL                                        /* next */
+ };
+ 
  
  void
  _initialize_gnu_nat (void)
***************
*** 3325,3330 ****
--- 3505,3512 ----
    
    init_gnu_ops ();
    add_target (&gnu_ops);
+ 
+   add_core_fns (&gnu_elf_core_fns);
  
    add_task_commands ();
    add_thread_commands ();

reply via email to

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