]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fix bug 69872. This change adds a coredumper to vg_signal.c. This means
authorJeremy Fitzhardinge <jeremy@valgrind.org>
Sat, 13 Mar 2004 02:06:58 +0000 (02:06 +0000)
committerJeremy Fitzhardinge <jeremy@valgrind.org>
Sat, 13 Mar 2004 02:06:58 +0000 (02:06 +0000)
that when the client is killed by a coredumping signal, Valgrind will
generate the coredump itself, which is full of client state, rather than
Valgrind state; this core file will therefore be useful to the developer
in debugging their program.

The corefile generated is named vgcore.pidNNNNN (and maybe with .M on
the end in case of duplicates).  If you set a logfile with --logfile,
then this name will be used as the basename for the core file, so that
both the core and the logs will be next to each other.

Valgrind respects the RLIMIT_CORE limit when generating the file; if the
limit is set to 0, then it will not generate one.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2312

coregrind/vg_include.h
coregrind/vg_main.c
coregrind/vg_memory.c
coregrind/vg_signals.c
coregrind/vg_syscalls.c
coregrind/vg_unsafe.h
include/vg_kerneliface.h

index dc32f0c43ec1349767428f387f848edd3476eb4e..143f9f3630a0e663a6d859417e36a696b65bdb9c 100644 (file)
@@ -1566,6 +1566,7 @@ extern void VG_(mprotect_range)(Addr addr, UInt len, UInt prot);
 extern Addr VG_(find_map_space)(Addr base, UInt len, Bool for_client);
 
 extern Segment *VG_(find_segment)(Addr a);
+extern Segment *VG_(first_segment)(void);
 extern Segment *VG_(next_segment)(Segment *);
 
 extern Bool     VG_(seg_contains)(const Segment *s, Addr ptr, UInt size);
index 516a3efb8792ee2e8c6e547b74cf3e0a0b54c81b..384ec9a716b3fb13796c21796fbcad0e708f0970 100644 (file)
@@ -47,7 +47,6 @@
 #include <sys/stat.h>
 #include <sys/ptrace.h>
 #include <sys/signal.h>
-#include <sys/user.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
@@ -311,12 +310,12 @@ void VG_(start_debugger) ( Int tid )
       Int res;
 
       if (VG_(is_running_thread)( tid )) {
-         regs.xcs = VG_(baseBlock)[VGOFF_(m_cs)];
-         regs.xss = VG_(baseBlock)[VGOFF_(m_ss)];
-         regs.xds = VG_(baseBlock)[VGOFF_(m_ds)];
-         regs.xes = VG_(baseBlock)[VGOFF_(m_es)];
-         regs.xfs = VG_(baseBlock)[VGOFF_(m_fs)];
-         regs.xgs = VG_(baseBlock)[VGOFF_(m_gs)];
+         regs.cs  = VG_(baseBlock)[VGOFF_(m_cs)];
+         regs.ss  = VG_(baseBlock)[VGOFF_(m_ss)];
+         regs.ds  = VG_(baseBlock)[VGOFF_(m_ds)];
+         regs.es  = VG_(baseBlock)[VGOFF_(m_es)];
+         regs.fs  = VG_(baseBlock)[VGOFF_(m_fs)];
+         regs.gs  = VG_(baseBlock)[VGOFF_(m_gs)];
          regs.eax = VG_(baseBlock)[VGOFF_(m_eax)];
          regs.ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
          regs.ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
@@ -330,12 +329,12 @@ void VG_(start_debugger) ( Int tid )
       } else {
          ThreadState* tst = & VG_(threads)[ tid ];
          
-         regs.xcs = tst->m_cs;
-         regs.xss = tst->m_ss;
-         regs.xds = tst->m_ds;
-         regs.xes = tst->m_es;
-         regs.xfs = tst->m_fs;
-         regs.xgs = tst->m_gs;
+         regs.cs  = tst->m_cs;
+         regs.ss  = tst->m_ss;
+         regs.ds  = tst->m_ds;
+         regs.es  = tst->m_es;
+         regs.fs  = tst->m_fs;
+         regs.gs  = tst->m_gs;
          regs.eax = tst->m_eax;
          regs.ebx = tst->m_ebx;
          regs.ecx = tst->m_ecx;
index 7f5121baebecbd548f44c29b7d1ce14a9fbbed43..629837f080064609c9fefce2b9d74791a3b73dfa 100644 (file)
@@ -551,6 +551,11 @@ Segment *VG_(find_segment)(Addr a)
    return VG_(SkipList_Find)(&sk_segments, &a);
 }
 
+Segment *VG_(first_segment)(void)
+{
+   return VG_(SkipNode_First)(&sk_segments);
+}
+
 Segment *VG_(next_segment)(Segment *s)
 {
    return VG_(SkipNode_Next)(&sk_segments, s);
index da0e396594da982a9facd3c04064a83ddfe34bea..bf9f8ce0d8695ccceedb52cbd1090e59a664c8cd 100644 (file)
@@ -1276,6 +1276,395 @@ void VG_(kill_self)(Int sigNo)
    VG_(ksigprocmask)(VKI_SIG_SETMASK, &origmask, NULL);
 }
 
+/*
+  Dump core
+   
+  Generate a standard ELF core file corresponding to the client state
+  at the time of a crash.
+ */
+#include <elf.h>
+#ifndef NT_PRXFPREG
+#define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
+#endif /* NT_PRXFPREG */
+
+/* If true, then this Segment may be mentioned in the core */
+static Bool may_dump(const Segment *seg)
+{
+   return (seg->flags & SF_VALGRIND) == 0 && VG_(is_client_addr)(seg->addr);
+}
+
+/* If true, then this Segment's contents will be in the core */
+static Bool should_dump(const Segment *seg)
+{
+   return may_dump(seg); // && (seg->prot & VKI_PROT_WRITE);
+}
+
+static void fill_ehdr(Elf32_Ehdr *ehdr, Int num_phdrs)
+{
+   VG_(memset)(ehdr, 0, sizeof(ehdr));
+
+   VG_(memcpy)(ehdr->e_ident, ELFMAG, SELFMAG);
+   ehdr->e_ident[EI_CLASS] = ELFCLASS32;
+   ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+   ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+   ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX;
+
+   ehdr->e_type = ET_CORE;
+   ehdr->e_machine = EM_386;
+   ehdr->e_version = EV_CURRENT;
+   ehdr->e_entry = 0;
+   ehdr->e_phoff = sizeof(Elf32_Ehdr);
+   ehdr->e_shoff = 0;
+   ehdr->e_flags = 0;
+   ehdr->e_ehsize = sizeof(Elf32_Ehdr);
+   ehdr->e_phentsize = sizeof(Elf32_Phdr);
+   ehdr->e_phnum = num_phdrs;
+   ehdr->e_shentsize = 0;
+   ehdr->e_shnum = 0;
+   ehdr->e_shstrndx = 0;
+
+}
+
+static void fill_phdr(Elf32_Phdr *phdr, const Segment *seg, UInt off, Bool write)
+{
+   write = write && should_dump(seg);
+
+   VG_(memset)(phdr, 0, sizeof(*phdr));
+
+   phdr->p_type = PT_LOAD;
+   phdr->p_offset = off;
+   phdr->p_vaddr = seg->addr;
+   phdr->p_paddr = 0;
+   phdr->p_filesz = write ? seg->len : 0;
+   phdr->p_memsz = seg->len;
+   phdr->p_flags = 0;
+
+   if (seg->prot & VKI_PROT_READ)
+      phdr->p_flags |= PF_R;
+   if (seg->prot & VKI_PROT_WRITE)
+      phdr->p_flags |= PF_W;
+   if (seg->prot & VKI_PROT_EXEC)
+      phdr->p_flags |= PF_X;
+
+   phdr->p_align = VKI_BYTES_PER_PAGE;
+}
+
+struct note {
+   struct note *next;
+   Elf32_Nhdr note;
+   Char name[0];
+};
+
+static UInt note_size(const struct note *n)
+{
+   return sizeof(Elf32_Nhdr) + ROUNDUP(VG_(strlen)(n->name)+1, 4) + ROUNDUP(n->note.n_descsz, 4);
+}
+
+static void add_note(struct note **list, const Char *name, UInt type, const void *data, UInt datasz)
+{
+   Int namelen = VG_(strlen)(name)+1;
+   Int notelen = sizeof(struct note) + 
+      ROUNDUP(namelen, 4) + 
+      ROUNDUP(datasz, 4);
+   struct note *n = VG_(arena_malloc)(VG_AR_CORE, notelen);
+
+   VG_(memset)(n, 0, notelen);
+
+   n->next = *list;
+   *list = n;
+
+   n->note.n_type = type;
+   n->note.n_namesz = namelen;
+   n->note.n_descsz = datasz;
+
+   VG_(memcpy)(n->name, name, namelen);
+   VG_(memcpy)(n->name+ROUNDUP(namelen,4), data, datasz);
+}
+
+static void write_note(Int fd, const struct note *n)
+{
+   VG_(write)(fd, &n->note, note_size(n));
+}
+
+static void fill_prpsinfo(const ThreadState *tst, struct elf_prpsinfo *prpsinfo)
+{
+   Char *name;
+
+   VG_(memset)(prpsinfo, 0, sizeof(*prpsinfo));
+
+   switch(tst->status) {
+   case VgTs_Runnable:
+      prpsinfo->pr_sname = 'R';
+      break;
+
+   case VgTs_WaitJoinee:
+      prpsinfo->pr_sname = 'Z';
+      prpsinfo->pr_zomb = 1;
+      break;
+
+   case VgTs_WaitJoiner:
+   case VgTs_WaitMX:
+   case VgTs_WaitCV:
+   case VgTs_WaitSys:
+   case VgTs_Sleeping:
+      prpsinfo->pr_sname = 'S';
+      break;
+
+   case VgTs_Empty:
+      /* ? */
+      break;
+   }
+
+   prpsinfo->pr_uid = 0;
+   prpsinfo->pr_gid = 0;
+   
+   name = VG_(resolve_filename)(VG_(clexecfd));
+
+   if (name != NULL) {
+      Char *n = name+VG_(strlen)(name)-1;
+
+      while(n > name && *n != '/')
+        n--;
+      if (n != name)
+        n++;
+
+      VG_(strncpy)(prpsinfo->pr_fname, n, sizeof(prpsinfo->pr_fname));
+   }
+}
+
+static void fill_prstatus(const ThreadState *tst, struct elf_prstatus *prs, const vki_ksiginfo_t *si)
+{
+   struct user_regs_struct *regs;
+
+   VG_(memset)(prs, 0, sizeof(*prs));
+
+   prs->pr_info.si_signo = si->si_signo;
+   prs->pr_info.si_code = si->si_code;
+   prs->pr_info.si_errno = 0;
+
+   prs->pr_cursig = si->si_signo;
+
+   prs->pr_pid = VG_(main_pid) + tst->tid;     /* just to distinguish threads from each other */
+   prs->pr_ppid = 0;
+   prs->pr_pgrp = VG_(main_pgrp);
+   prs->pr_sid = VG_(main_pgrp);
+   
+   regs = (struct user_regs_struct *)prs->pr_reg;
+
+   vg_assert(sizeof(*regs) == sizeof(prs->pr_reg));
+
+   if (VG_(is_running_thread)(tst->tid)) {
+      regs->eflags = VG_(baseBlock)[VGOFF_(m_eflags)];
+      regs->esp = VG_(baseBlock)[VGOFF_(m_esp)];
+      regs->eip = VG_(baseBlock)[VGOFF_(m_eip)];
+
+      regs->ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
+      regs->ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
+      regs->edx = VG_(baseBlock)[VGOFF_(m_edx)];
+      regs->esi = VG_(baseBlock)[VGOFF_(m_esi)];
+      regs->edi = VG_(baseBlock)[VGOFF_(m_edi)];
+      regs->ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
+      regs->eax = VG_(baseBlock)[VGOFF_(m_eax)];
+
+      regs->cs = VG_(baseBlock)[VGOFF_(m_cs)];
+      regs->ds = VG_(baseBlock)[VGOFF_(m_ds)];
+      regs->ss = VG_(baseBlock)[VGOFF_(m_ss)];
+      regs->es = VG_(baseBlock)[VGOFF_(m_es)];
+      regs->fs = VG_(baseBlock)[VGOFF_(m_fs)];
+      regs->gs = VG_(baseBlock)[VGOFF_(m_gs)];
+   } else {
+      regs->eflags = tst->m_eflags;
+      regs->esp = tst->m_esp;
+      regs->eip = tst->m_eip;
+
+      regs->ebx = tst->m_ebx;
+      regs->ecx = tst->m_ecx;
+      regs->edx = tst->m_edx;
+      regs->esi = tst->m_esi;
+      regs->edi = tst->m_edi;
+      regs->ebp = tst->m_ebp;
+      regs->eax = tst->m_eax;
+
+      regs->cs = tst->m_cs;
+      regs->ds = tst->m_ds;
+      regs->ss = tst->m_ss;
+      regs->es = tst->m_es;
+      regs->fs = tst->m_fs;
+      regs->gs = tst->m_gs;
+   }
+}
+
+static void fill_fpu(const ThreadState *tst, elf_fpregset_t *fpu)
+{
+   const Char *from;
+
+   if (VG_(is_running_thread)(tst->tid)) {
+      from = (const Char *)&VG_(baseBlock)[VGOFF_(m_ssestate)];
+   } else {
+      from = (const Char *)&tst->m_sse;
+   }
+
+   if (VG_(have_ssestate)) {
+      UShort *to;
+      Int i;
+
+      /* This is what the kernel does */
+      VG_(memcpy)(fpu, from, 7*sizeof(long));
+   
+      to = (UShort *)&fpu->st_space[0];
+      from += 18 * sizeof(UShort);
+
+      for(i = 0; i < 8; i++, to += 5, from += 8) 
+        VG_(memcpy)(to, from, 5*sizeof(UShort));
+   } else
+      VG_(memcpy)(fpu, from, sizeof(*fpu));
+}
+
+static void fill_xfpu(const ThreadState *tst, elf_fpxregset_t *xfpu)
+{
+   UShort *from;
+
+   if (VG_(is_running_thread)(tst->tid)) 
+      from = (UShort *)&VG_(baseBlock)[VGOFF_(m_ssestate)];
+   else 
+      from = (UShort *)tst->m_sse;
+
+   VG_(memcpy)(xfpu, from, sizeof(*xfpu));
+}
+
+static void make_coredump(ThreadId tid, const vki_ksiginfo_t *si, UInt max_size)
+{
+   Char buf[1000];
+   Char *basename = "vgcore";
+   Char *coreext = "";
+   Int seq = 0;
+   Int core_fd;
+   Segment *seg;
+   Elf32_Ehdr ehdr;
+   Elf32_Phdr *phdrs;
+   Int num_phdrs;
+   Int i;
+   UInt off;
+   struct note *notelist, *note;
+   UInt notesz;
+   struct elf_prpsinfo prpsinfo;
+   struct elf_prstatus prstatus;
+
+   if (VG_(clo_logfile_name) != NULL) {
+      coreext = ".core";
+      basename = VG_(clo_logfile_name);
+   }
+
+   for(;;) {
+      if (seq == 0)
+        VG_(sprintf)(buf, "%s%s.pid%d",
+                     basename, coreext, VG_(main_pid));
+      else
+        VG_(sprintf)(buf, "%s%s.pid%d.%d",
+                     basename, coreext, VG_(main_pid), seq);
+      seq++;
+
+      core_fd = VG_(open)(buf,                            
+                         VKI_O_CREAT|VKI_O_WRONLY|VKI_O_EXCL|VKI_O_TRUNC, 
+                         VKI_S_IRUSR|VKI_S_IWUSR);
+      if (core_fd >= 0)
+        break;
+
+      if (core_fd != -VKI_EEXIST)
+        return;                /* can't create file */
+   }
+
+   /* First, count how many memory segments to dump */
+   num_phdrs = 1;              /* start with notes */
+   for(seg = VG_(first_segment)();
+       seg != NULL;
+       seg = VG_(next_segment)(seg)) {
+      if (!may_dump(seg))
+        continue;
+
+      num_phdrs++;
+   }
+
+   fill_ehdr(&ehdr, num_phdrs);
+
+   /* Second, work out their layout */
+   phdrs = VG_(arena_malloc)(VG_AR_CORE, sizeof(*phdrs) * num_phdrs);
+
+   for(i = 1; i < VG_N_THREADS; i++) {
+      elf_fpregset_t fpu;
+
+      if (VG_(threads)[i].status == VgTs_Empty)
+        continue;
+
+      if (VG_(have_ssestate)) {
+        elf_fpxregset_t xfpu;
+
+        fill_xfpu(&VG_(threads)[i], &xfpu);
+        add_note(&notelist, "LINUX", NT_PRXFPREG, &xfpu, sizeof(xfpu));
+      }
+
+      fill_fpu(&VG_(threads)[i], &fpu);
+      add_note(&notelist, "CORE", NT_FPREGSET, &fpu, sizeof(fpu));
+
+      fill_prstatus(&VG_(threads)[i], &prstatus, si);
+      add_note(&notelist, "CORE", NT_PRSTATUS, &prstatus, sizeof(prstatus));
+   }
+
+   fill_prpsinfo(&VG_(threads)[tid], &prpsinfo);
+   add_note(&notelist, "CORE", NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo));
+
+   for(note = notelist, notesz = 0; note != NULL; note = note->next)
+      notesz += note_size(note);
+
+   off = sizeof(ehdr) + sizeof(*phdrs) * num_phdrs;
+
+   phdrs[0].p_type = PT_NOTE;
+   phdrs[0].p_offset = off;
+   phdrs[0].p_vaddr = 0;
+   phdrs[0].p_paddr = 0;
+   phdrs[0].p_filesz = notesz;
+   phdrs[0].p_memsz = 0;
+   phdrs[0].p_flags = 0;
+   phdrs[0].p_align = 0;
+
+   off += notesz;
+
+   off = PGROUNDUP(off);
+
+   for(seg = VG_(first_segment)(), i = 1;
+       seg != NULL;
+       seg = VG_(next_segment)(seg), i++) {
+      if (!may_dump(seg))
+        continue;
+
+      fill_phdr(&phdrs[i], seg, off, (seg->len + off) < max_size);
+      
+      off += phdrs[i].p_filesz;
+   }
+
+   /* write everything out */
+   VG_(write)(core_fd, &ehdr, sizeof(ehdr));
+   VG_(write)(core_fd, phdrs, sizeof(*phdrs) * num_phdrs);
+
+   for(note = notelist; note != NULL; note = note->next)
+      write_note(core_fd, note);
+   
+   VG_(lseek)(core_fd, phdrs[1].p_offset, VKI_SEEK_SET);
+
+   for(seg = VG_(first_segment)(), i = 1;
+       seg != NULL;
+       seg = VG_(next_segment)(seg), i++) {
+      if (!should_dump(seg))
+        continue;
+
+      vg_assert(VG_(lseek)(core_fd, 0, VKI_SEEK_CUR) == phdrs[i].p_offset);
+      if (phdrs[i].p_filesz > 0)
+        VG_(write)(core_fd, (void *)seg->addr, seg->len);
+   }
+
+   VG_(close)(core_fd);
+}
+
 /* 
    Perform the default action of a signal.  Returns if the default
    action isn't fatal.
@@ -1395,6 +1784,19 @@ static void vg_default_action(const vki_ksiginfo_t *info, ThreadId tid)
          VG_(start_debugger)( tid );
       }
 
+      if (core) {
+        static struct vki_rlimit zero = { 0, 0 };
+        struct vki_rlimit corelim;
+
+        VG_(getrlimit)(VKI_RLIMIT_CORE, &corelim);
+
+        if (corelim.rlim_cur > 0)
+           make_coredump(tid, info, corelim.rlim_cur);
+
+        /* make sure we don't get a confusing kernel-generated coredump */
+        VG_(setrlimit)(VKI_RLIMIT_CORE, &zero);
+      }
+
       if (VG_(fatal_signal_set)) {
         VG_(fatal_sigNo) = sigNo;
         __builtin_longjmp(VG_(fatal_signal_jmpbuf), 1);
index 1623d7dd5e2dcc811665f7e223f8eac2d5834277..4e104da96ded7bfbe85a258701c7bbdbaeb3952b 100644 (file)
@@ -1147,7 +1147,7 @@ PRE(ptrace)
       break;
    case 14:   /* PTRACE_GETFPREGS */
       SYSCALL_TRACK( pre_mem_write, tid, "ptrace(getfpregs)", arg4, 
-                    sizeof (struct user_fpregs_struct));
+                    sizeof (struct user_i387_struct));
       break;
    case 18:   /* PTRACE_GETFPXREGS */
       SYSCALL_TRACK( pre_mem_write, tid, "ptrace(getfpxregs)", arg4, 
@@ -1163,7 +1163,7 @@ PRE(ptrace)
       break;
    case 15:   /* PTRACE_SETFPREGS */
       SYSCALL_TRACK( pre_mem_read, tid, "ptrace(setfpregs)", arg4, 
-                    sizeof (struct user_fpregs_struct));
+                    sizeof (struct user_i387_struct));
       break;
    case 19:   /* PTRACE_SETFPXREGS */
       SYSCALL_TRACK( pre_mem_read, tid, "ptrace(setfpxregs)", arg4, 
@@ -1187,7 +1187,7 @@ POST(ptrace)
       break;
    case 14:  /* PTRACE_GETFPREGS */
       VG_TRACK( post_mem_write, arg4, 
-               sizeof (struct user_fpregs_struct));
+               sizeof (struct user_i387_struct));
       break;
    case 18:  /* PTRACE_GETFPXREGS */
       VG_TRACK( post_mem_write, arg4, 
index faf26e89e49532ef60eddd3ff9e316258231e101..65c451ec678db05f536b645e39004eae06af4139 100644 (file)
@@ -61,7 +61,6 @@
 #include <sched.h>        /* for struct sched_param */
 #include <linux/sysctl.h> /* for struct __sysctl_args */
 #include <linux/cdrom.h>  /* for cd-rom ioctls */
-#include <sys/user.h>     /* for struct user_regs_struct et al */
 #include <signal.h>       /* for siginfo_t */
 #include <linux/timex.h>  /* for adjtimex */
 
index 2cd7c0f16d86267484f58d25a86554e87dc901fe..89c0998cbabe5f5eaf51530b028d828f54f8f690 100644 (file)
@@ -763,6 +763,124 @@ struct statfs64 {
 #define VKI_FUTEX_FD      2
 #define VKI_FUTEX_REQUEUE 3
 
+/* 
+ * linux/elfcore.h
+ */
+
+struct elf_siginfo
+{
+       int     si_signo;                       /* signal number */
+       int     si_code;                        /* extra code */
+       int     si_errno;                       /* errno */
+};
+
+/*
+ * This is the old layout of "struct pt_regs", and
+ * is still the layout used by user mode (the new
+ * pt_regs doesn't have all registers as the kernel
+ * doesn't use the extra segment registers)
+ */
+struct user_regs_struct {
+       long ebx, ecx, edx, esi, edi, ebp, eax;
+       unsigned short ds, __ds, es, __es;
+       unsigned short fs, __fs, gs, __gs;
+       long orig_eax, eip;
+       unsigned short cs, __cs;
+       long eflags, esp;
+       unsigned short ss, __ss;
+};
+
+struct user_i387_struct {
+       long    cwd;
+       long    swd;
+       long    twd;
+       long    fip;
+       long    fcs;
+       long    foo;
+       long    fos;
+       long    st_space[20];   /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+struct user_fxsr_struct {
+       unsigned short  cwd;
+       unsigned short  swd;
+       unsigned short  twd;
+       unsigned short  fop;
+       long    fip;
+       long    fcs;
+       long    foo;
+       long    fos;
+       long    mxcsr;
+       long    reserved;
+       long    st_space[32];   /* 8*16 bytes for each FP-reg = 128 bytes */
+       long    xmm_space[32];  /* 8*16 bytes for each XMM-reg = 128 bytes */
+       long    padding[56];
+};
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_i387_struct elf_fpregset_t;
+typedef struct user_fxsr_struct elf_fpxregset_t;
+
+
+/*
+ * Definitions to generate Intel SVR4-like core files.
+ * These mostly have the same names as the SVR4 types with "elf_"
+ * tacked on the front to prevent clashes with linux definitions,
+ * and the typedef forms have been avoided.  This is mostly like
+ * the SVR4 structure, but more Linuxy, with things that Linux does
+ * not support and which gdb doesn't really use excluded.
+ * Fields present but not used are marked with "XXX".
+ */
+struct elf_prstatus
+{
+#if 0
+       long    pr_flags;       /* XXX Process flags */
+       short   pr_why;         /* XXX Reason for process halt */
+       short   pr_what;        /* XXX More detailed reason */
+#endif
+       struct elf_siginfo pr_info;     /* Info associated with signal */
+       short   pr_cursig;              /* Current signal */
+       unsigned long pr_sigpend;       /* Set of pending signals */
+       unsigned long pr_sighold;       /* Set of held signals */
+#if 0
+       struct sigaltstack pr_altstack; /* Alternate stack info */
+       struct sigaction pr_action;     /* Signal action for current sig */
+#endif
+       Int     pr_pid;
+       Int     pr_ppid;
+       Int     pr_pgrp;
+       Int     pr_sid;
+       struct vki_timeval pr_utime;    /* User time */
+       struct vki_timeval pr_stime;    /* System time */
+       struct vki_timeval pr_cutime;   /* Cumulative user time */
+       struct vki_timeval pr_cstime;   /* Cumulative system time */
+#if 0
+       long    pr_instr;               /* Current instruction */
+#endif
+       elf_gregset_t pr_reg;   /* GP registers */
+       int pr_fpvalid;         /* True if math co-processor being used.  */
+};
+
+#define ELF_PRARGSZ    (80)    /* Number of chars for args */
+
+struct elf_prpsinfo
+{
+       char    pr_state;       /* numeric process state */
+       char    pr_sname;       /* char for pr_state */
+       char    pr_zomb;        /* zombie */
+       char    pr_nice;        /* nice val */
+       unsigned long pr_flag;  /* flags */
+       Int     pr_uid;
+       Int     pr_gid;
+       Int     pr_pid, pr_ppid, pr_pgrp, pr_sid;
+       /* Lots missing */
+       char    pr_fname[16];   /* filename of executable */
+       char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
 
 #endif /*  __VG_KERNELIFACE_H */