Enable DWARF line decoding in ddb

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Enable DWARF line decoding in ddb

Matthew Dempsky-3
Patch below enables DWARF line decoding in ddb; e.g.,

  ddb{0}> trace
  Debugger() at Debugger+0x9 [../../../../arch/amd64/amd64/db_interface.c:405]
  ddb_sysctl() at ddb_sysctl+0x1b4 [../../../../ddb/db_usrreq.c:104]
  sys___sysctl() at sys___sysctl+0x216 [../../../../kern/kern_sysctl.c:229]
  syscall() at syscall+0x297 [../../../../sys/syscall_mi.h:84]
  --- syscall (number 202) ---
  end of kernel
  end trace frame: 0x7f7ffffcf1d7, count: -4
  acpi_pdirpa+0x4117aa:

Full set of instructions to apply and test (assuming amd64 MP):

  # Apply patch
  cd /usr/src/sys
  patch < /path/to/diff

  # Enable DEBUG="-g"
  $EDITOR conf/GENERIC
  # uncomment ``makeoptions DEBUG="-g"'' line and save

  # Build new kernel
  cd arch/amd64/conf
  config GENERIC.MP
  cd ../compile/GENERIC.MP
  make clean
  make

  # Build new boot(8)
  cd ../../stand/boot
  make install

  # Install new boot(8)
  cp /usr/mdec/boot /boot
  installboot -v /boot /usr/mdec/biosboot sd0

Now reboot and boot the "nbsd" kernel.  Stack traces in ddb should
include file and line numbers.

For file/line numbers to appear, all of the following are necessary:

  1. New boot(8)
  2. New kernel
  3. Kernel built with DEBUG="-g"
  4. Boot bsd.gdb instead of bsd

Under any other conditions, ddb should gracefully fall back to bare
stack traces.  I've tested most combinations, but additional testing
is appreciated.


Implementation details:

  - boot(8) now loads the ELF header string table so it can identify
    section names. It also now loads the ".debug_line" section into
    memory, and marks loaded sections with SHF_ALLOC.

  - ddb when generating stack traces now checks if there's a section
    named ".debug_line" that's marked SHF_ALLOC; and if so, ddb parses
    the section contents to translate program counter values into
    file/line pairs.

  - New boot(8) should be backwards compatible with old kernels, because
    they won't care if ".debug_line" is loaded; new bsd.gdb should be
    compatible with old boot(8) because ".debug_line" isn't normally
    marked SHF_ALLOC.

Index: conf/files
===================================================================
RCS file: /home/matthew/anoncvs/cvs/src/sys/conf/files,v
retrieving revision 1.577
diff -u -p -r1.577 files
--- conf/files 8 Sep 2014 04:40:30 -0000 1.577
+++ conf/files 29 Sep 2014 02:46:16 -0000
@@ -611,6 +611,7 @@ file net/if_pppoe.c pppoe needs-flag
 file ddb/db_access.c ddb | kgdb
 file ddb/db_break.c ddb
 file ddb/db_command.c ddb
+file ddb/db_dwarf.c ddb
 file ddb/db_elf.c ddb
 file ddb/db_examine.c ddb
 file ddb/db_expr.c ddb
Index: ddb/db_elf.c
===================================================================
RCS file: /home/matthew/anoncvs/cvs/src/sys/ddb/db_elf.c,v
retrieving revision 1.11
diff -u -p -r1.11 db_elf.c
--- ddb/db_elf.c 14 Sep 2014 14:17:24 -0000 1.11
+++ ddb/db_elf.c 29 Sep 2014 02:46:16 -0000
@@ -32,12 +32,14 @@
  */
 
 #include <sys/types.h>
+#include <sys/stdint.h>
 #include <sys/param.h>
 #include <sys/systm.h>  
 #include <sys/exec.h>
 
 #include <machine/db_machdep.h>
 
+#include <ddb/db_dwarf.h>
 #include <ddb/db_sym.h>
 #include <ddb/db_output.h>
 #include <ddb/db_extern.h>
@@ -45,6 +47,7 @@
 #include <sys/exec_elf.h>
 
 static char *db_elf_find_strtab(db_symtab_t *);
+static char *db_elf_find_linetab(db_symtab_t *, size_t *);
 
 #define STAB_TO_SYMSTART(stab) ((Elf_Sym *)((stab)->start))
 #define STAB_TO_SYMEND(stab) ((Elf_Sym *)((stab)->end))
@@ -110,10 +113,10 @@ db_elf_sym_init(int symsize, void *symta
  * . . .
  * . . .
  * last section header
- * first symbol or string table section
+ * first symbol, string, or line table section
  * . . .
  * . . .
- * last symbol or string table section
+ * last symbol, string, or line table section
  */
 
  /*
@@ -232,6 +235,30 @@ db_elf_find_strtab(db_symtab_t *stab)
 }
 
 /*
+ * Internal helper function - return a pointer to the line table
+ * for the current symbol table.
+ */
+static char *
+db_elf_find_linetab(db_symtab_t *stab, size_t *size)
+{
+ Elf_Ehdr *elf = STAB_TO_EHDR(stab);
+ Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
+ char *shstrtab;
+ int i;
+
+ shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
+ for (i = 0; i < elf->e_shnum; i++) {
+ if ((shp[i].sh_flags & SHF_ALLOC) != 0 &&
+    strcmp(".debug_line", shstrtab+shp[i].sh_name) == 0) {
+ *size = shp[i].sh_size;
+ return ((char *)elf + shp[i].sh_offset);
+ }
+ }
+
+ return (NULL);
+}
+
+/*
  * Lookup the symbol with the given name.
  */
 db_sym_t
@@ -350,11 +377,25 @@ boolean_t
 db_elf_line_at_pc(db_symtab_t *symtab, db_sym_t cursym, char **filename,
     int *linenum, db_expr_t off)
 {
+ const char *linetab;
+ size_t linetab_size;
 
- /*
- * XXX We don't support this (yet).
- */
- return (FALSE);
+ linetab = db_elf_find_linetab(symtab, &linetab_size);
+ if (linetab == NULL)
+ return (FALSE);
+
+ const char *dirname, *basename;
+ if (!db_dwarf_line_at_pc(linetab, linetab_size, off,
+    &dirname, &basename, linenum))
+ return (FALSE);
+
+ static char path[PATH_MAX];
+ if (dirname == NULL)
+ strlcpy(path, basename, sizeof(path));
+ else
+ snprintf(path, sizeof(path), "%s/%s", dirname, basename);
+ *filename = path;
+ return (TRUE);
 }
 
 /*
Index: lib/libsa/loadfile_elf.c
===================================================================
RCS file: /home/matthew/anoncvs/cvs/src/sys/lib/libsa/loadfile_elf.c,v
retrieving revision 1.8
diff -u -p -r1.8 loadfile_elf.c
--- lib/libsa/loadfile_elf.c 25 Feb 2014 21:40:39 -0000 1.8
+++ lib/libsa/loadfile_elf.c 11 Jul 2014 08:38:41 -0000
@@ -76,7 +76,7 @@ ELFNAME(exec)(int fd, Elf_Ehdr *elf, u_l
  int i;
  size_t sz;
  int first;
- int havesyms;
+ int havesyms, havelines;
  paddr_t minp = ~0, maxp = 0, pos = 0;
  paddr_t offset = marks[MARK_START], shpp, elfp;
 
@@ -199,6 +199,21 @@ ELFNAME(exec)(int fd, Elf_Ehdr *elf, u_l
  shpp = maxp;
  maxp += roundup(sz, sizeof(Elf_Addr));
 
+ size_t shstrsz = shp[elf->e_shstrndx].sh_size;
+ char *shstr = ALLOC(shstrsz);
+ if (lseek(fd, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) {
+ WARN(("lseek section header string table"));
+ FREE(shstr, shstrsz);
+ FREE(shp, sz);
+ return 1;
+ }
+ if (READ(fd, shstr, shstrsz) != shstrsz) {
+ WARN(("read section header string table"));
+ FREE(shstr, shstrsz);
+ FREE(shp, sz);
+ return 1;
+ }
+
  /*
  * Now load the symbol sections themselves. Make sure the
  * sections are aligned. Don't bother with string tables if
@@ -206,25 +221,28 @@ ELFNAME(exec)(int fd, Elf_Ehdr *elf, u_l
  */
  off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr));
 
- for (havesyms = i = 0; i < elf->e_shnum; i++)
+ for (havesyms = havelines = i = 0; i < elf->e_shnum; i++)
  if (shp[i].sh_type == SHT_SYMTAB)
  havesyms = 1;
 
  for (first = 1, i = 0; i < elf->e_shnum; i++) {
  if (shp[i].sh_type == SHT_SYMTAB ||
-    shp[i].sh_type == SHT_STRTAB) {
+    shp[i].sh_type == SHT_STRTAB ||
+    !strcmp(shstr + shp[i].sh_name, ".debug_line")) {
  if (havesyms && (flags & LOAD_SYM)) {
  PROGRESS(("%s%ld", first ? " [" : "+",
     (u_long)shp[i].sh_size));
  if (lseek(fd, (off_t)shp[i].sh_offset,
     SEEK_SET) == -1) {
  WARN(("lseek symbols"));
+ FREE(shstr, shstrsz);
  FREE(shp, sz);
  return 1;
  }
  if (READ(fd, maxp, shp[i].sh_size) !=
     shp[i].sh_size) {
  WARN(("read symbols"));
+ FREE(shstr, shstrsz);
  FREE(shp, sz);
  return 1;
  }
@@ -232,6 +250,7 @@ ELFNAME(exec)(int fd, Elf_Ehdr *elf, u_l
  maxp += roundup(shp[i].sh_size,
     sizeof(Elf_Addr));
  shp[i].sh_offset = off;
+ shp[i].sh_flags |= SHF_ALLOC;
  off += roundup(shp[i].sh_size, sizeof(Elf_Addr));
  first = 0;
  }
@@ -242,6 +261,7 @@ ELFNAME(exec)(int fd, Elf_Ehdr *elf, u_l
  if (havesyms && first == 0)
  PROGRESS(("]"));
  }
+ FREE(shstr, shstrsz);
  FREE(shp, sz);
  }
 

Reply | Threaded
Open this post in threaded view
|

Re: Enable DWARF line decoding in ddb

Philip Guenther-2
To correct the instructions slightly...

On Sun, Sep 28, 2014 at 11:00 PM, Matthew Dempsky <[hidden email]> wrote:
...
>   # Build new boot(8)
>   cd ../../stand/boot
>   make install

Change that last line to
    make obj && make depend && make && make install


>   # Install new boot(8)
>   cp /usr/mdec/boot /boot
>   installboot -v /boot /usr/mdec/biosboot sd0

That should be
    installboot -v sd0 /usr/mdec/biosboot /boot

(and if your boot drive isn't sd0 then change the line as appropriate,
of course.)


Philip Guenther