Subject: Changes to new-toolchain to support NetBSD ELF core files
To: None <tech-toolchain@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-toolchain
Date: 12/07/2001 17:33:05
--CUfgB8w4ZwR/yMy5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

I just posted to tech-kern about a new ELF-based core file format
for NetBSD.  Obviously this new core file format requires support
in the toolchain so that the debugger can cope with it.

Attached are patches to the new-toolchain that:

	* Add support for the new NetBSD ELF core file format
	  to BFD.  These changes were made in such a way that
	  it will be possible to cross-debug userland core files
	  (when GDB is capable of doing that).

	* Add support for using ELF core files in the GDB i386-netbsd
	  target.  (This is just an example; other targets will
	  require very similar changes, which are quite easy to
	  make).

I did NOT add support for the new core file format to the old-toolchain
because I think all of our ELF platforms can now use the new-toolchain
(or, are at least very very close).

Once the new ELF core file format is finalized, these changes will be
fed back to the master GNU sources.

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>

--CUfgB8w4ZwR/yMy5
Content-Type: text/plain; charset=us-ascii
Content-Description: elfcore-tc.diffs
Content-Disposition: attachment; filename=foo

Index: bfd/elf.c
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/bfd/elf.c,v
retrieving revision 1.6
diff -c -r1.6 elf.c
*** bfd/elf.c	2001/08/14 04:43:06	1.6
--- bfd/elf.c	2001/12/08 01:17:30
***************
*** 5514,5521 ****
  #endif
  #endif
  
- #if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
- 
  /* return a malloc'ed copy of a string at START which is at
     most MAX bytes long, possibly without a terminating '\0'.
     the copy will always have a terminating '\0'.  */
--- 5514,5519 ----
***************
*** 5545,5550 ****
--- 5543,5550 ----
    return dup;
  }
  
+ #if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+ 
  static boolean
  elfcore_grok_psinfo (abfd, note)
       bfd *abfd;
***************
*** 5850,5855 ****
--- 5850,5961 ----
  }
  
  static boolean
+ elfcore_netbsd_get_lwpid (abfd, note, lwpidp)
+      bfd *abfd;
+      Elf_Internal_Note *note;
+      int *lwpidp;
+ {
+   char *cp;
+ 
+   cp = strchr (note->namedata, '@');
+   if (cp != NULL)
+     {
+       *lwpidp = atoi(cp);
+       return true;
+     }
+   return false;
+ }
+ 
+ static boolean
+ elfcore_grok_netbsd_procinfo (abfd, note)
+      bfd *abfd;
+      Elf_Internal_Note *note;
+ {
+ 
+   /* Signal number at offset 0x08. */
+   elf_tdata (abfd)->core_signal
+     = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08);
+ 
+   /* Process ID at offset 0x50. */
+   elf_tdata (abfd)->core_pid
+     = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x50);
+ 
+   /* Command name at 0x7c (max 32 bytes, including nul). */
+   elf_tdata (abfd)->core_command
+     = elfcore_strndup (abfd, note->descdata + 0x7c, 31);
+ 
+   return true;
+ }
+ 
+ static boolean
+ elfcore_grok_netbsd_note (abfd, note)
+      bfd *abfd;
+      Elf_Internal_Note *note;
+ {
+   int lwp;
+ 
+   if (elfcore_netbsd_get_lwpid (abfd, note, &lwp))
+     elf_tdata (abfd)->core_lwpid = lwp;
+ 
+   if (note->type == 1)
+     {
+       /* NetBSD-specific core "procinfo".  Note that we expect to
+          find this note before any of the others, which is fine,
+          since the kernel writes this note out first when it
+          creates a core file.  */
+ 
+       return elfcore_grok_netbsd_procinfo (abfd, note);
+     }
+ 
+   /* There are not currently any other machine-independent notes defined
+      for NetBSD ELF core files.  If the note type is less than the start
+      of the machine-dependent note types, we don't understand it.  */
+ 
+   if (note->type < 32)
+     {
+       return true;
+     }
+ 
+ 
+   switch (bfd_get_arch (abfd))
+     {
+     /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and
+        PT_GETFPREGS == mach+2.  */
+ 
+     case bfd_arch_alpha:
+     case bfd_arch_sparc:
+       switch (note->type)
+         {
+         case 32+0:
+           return elfcore_make_note_pseudosection (abfd, ".reg", note);
+ 
+         case 32+2:
+           return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+ 
+         default:
+           return true;
+         }
+ 
+     /* On all other arch's, PT_GETREGS == mach+1 and
+        PT_GETFPREGS == mach+3.  */
+ 
+     default:
+       switch (note->type)
+         {
+         case 32+1:
+           return elfcore_make_note_pseudosection (abfd, ".reg", note);
+ 
+         case 32+3:
+           return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+ 
+         default:
+           return true;
+         }
+     }
+     /* NOTREACHED */
+ }
+ 
+ static boolean
  elfcore_read_notes (abfd, offset, size)
       bfd *abfd;
       bfd_vma offset;
***************
*** 5891,5898 ****
        in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
        in.descpos = offset + (in.descdata - buf);
  
!       if (! elfcore_grok_note (abfd, &in))
! 	goto error;
  
        p = in.descdata + BFD_ALIGN (in.descsz, 4);
      }
--- 5997,6012 ----
        in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
        in.descpos = offset + (in.descdata - buf);
  
!       if (strncmp (in.namedata, "NetBSD-CORE", 11) == 0)
!         {
!           if (! elfcore_grok_netbsd_note (abfd, &in))
!             goto error;
!         }
!       else
!         {
!           if (! elfcore_grok_note (abfd, &in))
!             goto error;
!         }
  
        p = in.descdata + BFD_ALIGN (in.descsz, 4);
      }
Index: gdb/i386nbsd-nat.c
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/gdb/i386nbsd-nat.c,v
retrieving revision 1.4
diff -c -r1.4 i386nbsd-nat.c
*** gdb/i386nbsd-nat.c	2001/12/06 02:07:03	1.4
--- gdb/i386nbsd-nat.c	2001/12/08 01:17:45
***************
*** 55,61 ****
      unsigned char regs[8][10];
    };
  
- #ifdef PT_GETXMMREGS
  struct xmmctx
    {
      unsigned short control;
--- 55,60 ----
***************
*** 82,88 ****
        } sseregs[8];
      unsigned char r4[16 * 14];
    };
- #endif /* PT_GETXMMREGS */
  
  static void
  supply_regs (regs)
--- 81,86 ----
***************
*** 376,386 ****
    supply_387regs (&core_reg->freg);
  }
  
! /*
!  * kernel_u_size() is not helpful on NetBSD because
!  * the "u" struct is NOT in the core dump file.
!  */
  
  #ifdef FETCH_KCORE_REGISTERS
  /*
   * Get registers from a kernel crash dump or live kernel.
--- 374,431 ----
    supply_387regs (&core_reg->freg);
  }
  
! static void
! fetch_elfcore_registers (core_reg_sect, core_reg_size, which, ignore)
!      char *core_reg_sect;
!      unsigned core_reg_size;
!      int which;
!      CORE_ADDR ignore;
! {
!   struct reg intreg;
!   struct env387 freg;
!   struct xmmctx xmm;
! 
!   switch (which)
!     {
!     case 0:  /* Integer registers */
!       if (core_reg_size != sizeof (intreg))
!         warning ("Wrong size register set in core file.");
!       else
!         {
!           memcpy (&intreg, core_reg_sect, sizeof (intreg));
!           supply_regs (&intreg);
!         }
!       break;
  
+     case 2:  /* Floating point registers */
+       if (core_reg_size != sizeof (freg))
+         warning ("Wrong size FP register set in core file.");
+       else
+         {
+           memcpy (&freg, core_reg_sect, sizeof (freg));
+           supply_387regs (&freg);
+         }
+       break;
+ 
+     case 3:  /* "Extended" floating point registers.  This is gdb-speak
+                 for SSE/SSE2.  */
+       if (core_reg_size != sizeof (xmm))
+         warning ("Wrong size XMM register set in core file.");
+       else
+         {
+           memcpy (&xmm, core_reg_sect, sizeof (xmm));
+           supply_xmmregs (&xmm);
+         }
+       break;
+ 
+     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;
+     }
+ }
+ 
  #ifdef FETCH_KCORE_REGISTERS
  /*
   * Get registers from a kernel crash dump or live kernel.
***************
*** 430,437 ****
--- 475,492 ----
    NULL					/* next */
  };
  
+ static struct core_fns i386nbsd_elfcore_fns =
+ {
+   bfd_target_elf_flavour,		/* core_flavour */
+   default_check_format,			/* check_format */
+   default_core_sniffer,			/* core_sniffer */
+   fetch_elfcore_registers,		/* core_read_registers */
+   NULL					/* next */
+ };
+ 
  void
  _initialize_i386nbsd_nat ()
  {
    add_core_fns (&i386nbsd_core_fns);
+   add_core_fns (&i386nbsd_elfcore_fns);
  }

--CUfgB8w4ZwR/yMy5--