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);
}