Fix bug 69872.  This change adds a coredumper to vg_signal.c.  This means
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 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index dc32f0c..143f9f3 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -1566,6 +1566,7 @@
 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);
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index 516a3ef..384ec9a 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -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 @@
       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 @@
       } 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;
diff --git a/coregrind/vg_memory.c b/coregrind/vg_memory.c
index 7f5121b..629837f 100644
--- a/coregrind/vg_memory.c
+++ b/coregrind/vg_memory.c
@@ -551,6 +551,11 @@
    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);
diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c
index da0e396..bf9f8ce 100644
--- a/coregrind/vg_signals.c
+++ b/coregrind/vg_signals.c
@@ -1276,6 +1276,395 @@
    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 @@
          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);
diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c
index 1623d7d..4e104da 100644
--- a/coregrind/vg_syscalls.c
+++ b/coregrind/vg_syscalls.c
@@ -1147,7 +1147,7 @@
       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 @@
       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 @@
       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, 
diff --git a/coregrind/vg_unsafe.h b/coregrind/vg_unsafe.h
index faf26e8..65c451e 100644
--- a/coregrind/vg_unsafe.h
+++ b/coregrind/vg_unsafe.h
@@ -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 */
 
diff --git a/include/vg_kerneliface.h b/include/vg_kerneliface.h
index 2cd7c0f..89c0998 100644
--- a/include/vg_kerneliface.h
+++ b/include/vg_kerneliface.h
@@ -763,6 +763,124 @@
 #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 */