Re: ddb: ELF line decoding in stack traces

2014-07-10 Thread Matthew Dempsky
On Mon, Jun 23, 2014 at 06:46:27AM -0700, Matthew Dempsky wrote:
 I did this mostly for fun / personal enlightenment, so I haven't put
 too much effort into polishing it yet.

I got some positive feedback about the direction of this diff, so
tonight I finally got around to polishing it some more.

In particular, db_dwarf.c now includes a stand-alone addr2line clone
that can be compiled separately with cc -o ddb-addr2line db_dwarf.c,
and the output should match addr2line(1)'s.  I've extensively tested
it against amd64's bsd.gdb, but I'd love testing feedback on
big-endian and LP32 platforms.

Unless anyone objects, I plan to commit the db_dwarf.{c,h} additions
tomorrow (i.e., not wired into the build) so they can be
developed/tested further in tree.  The other bits I'll split out and
post for separate review as appropriate.  (I at least need to first
ensure new bsd.gdb kernels will gracefully handle being loaded by old
boot loaders.)


Index: ddb/db_dwarf.h
===
RCS file: ddb/db_dwarf.h
diff -N ddb/db_dwarf.h
--- /dev/null   1 Jan 1970 00:00:00 -
+++ ddb/db_dwarf.h  10 Jul 2014 07:14:26 -
@@ -0,0 +1,24 @@
+/* $OpenBSD$*/
+/*
+ * Copyright (c) 2014 Matthew Dempsky matt...@dempsky.org
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DDB_DB_DWARF_H_
+#define _DDB_DB_DWARF_H_
+
+bool db_dwarf_line_at_pc(const char *, size_t, uintptr_t,
+const char **, const char **, int *);
+
+#endif /* _DDB_DB_DWARF_H_ */
Index: ddb/db_dwarf.c
===
RCS file: ddb/db_dwarf.c
diff -N ddb/db_dwarf.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ ddb/db_dwarf.c  10 Jul 2014 07:49:07 -
@@ -0,0 +1,550 @@
+/* $OpenBSD$*/
+/*
+ * Copyright (c) 2014 Matthew Dempsky matt...@dempsky.org
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef _KERNEL
+#include sys/types.h
+#include sys/stdint.h
+#include sys/param.h
+#include sys/systm.h  
+#include ddb/db_dwarf.h
+#ifdef DIAGNOSTIC
+#define DWARN(fmt, ...) printf(ddb:  fmt \n, __VA_ARGS__)
+#else
+#define DWARN(fmt, ...) ((void)0)
+#endif
+#else /* _KERNEL */
+#include err.h
+#include stdbool.h
+#include stdint.h
+#include string.h
+#define DWARN warnx
+#endif /* _KERNEL */
+
+enum {
+   DW_LNS_copy = 1,
+   DW_LNS_advance_pc   = 2,
+   DW_LNS_advance_line = 3,
+   DW_LNS_set_file = 4,
+   DW_LNS_set_column   = 5,
+   DW_LNS_negate_stmt  = 6,
+   DW_LNS_set_basic_block  = 7,
+   DW_LNS_const_add_pc = 8,
+   DW_LNS_fixed_advance_pc = 9,
+   DW_LNS_set_prologue_end = 10,
+   DW_LNS_set_epilogue_begin   = 11,
+};
+
+enum {
+   DW_LNE_end_sequence = 1,
+   DW_LNE_set_address  = 2,
+   DW_LNE_define_file  = 3,
+};
+
+struct dwbuf {
+   const char *buf;
+   size_t len;
+};
+
+static bool
+read_bytes(struct dwbuf *d, void *v, size_t n)
+{
+   if (d-len  n)
+   return (false);
+   memcpy(v, d-buf, n);
+   d-buf += n;
+   d-len -= n;
+   return (true);
+}
+
+static bool
+read_s8(struct dwbuf *d, int8_t *v)
+{
+   return (read_bytes(d, v, sizeof(*v)));
+}
+
+static bool
+read_u8(struct dwbuf *d, uint8_t *v)
+{
+   return (read_bytes(d, v, sizeof(*v)));
+}
+
+static bool
+read_u16(struct dwbuf *d, uint16_t *v)
+{
+   return (read_bytes(d, v, sizeof(*v)));
+}
+
+static bool

ddb: ELF line decoding in stack traces

2014-06-23 Thread Matthew Dempsky
Diff below implements file/line number decoding in ddb for ELF; e.g.,

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

It works by modifying boot(8) to copy the .debug_line DWARF section
into memory when present (same as it does currently for symbol and
string table sections), and then ddb's ELF symbol format handler code
makes use of it to translate program counters into file/line pairs
just like addr2line would.

For line decoding to work, the kernel must have been compiled with -g.
Normal and/or stripped kernels continue to work as they do now, just
won't produce file/line information.

Only lightly tested on amd64 so far, but might work on other platforms
too.  If you're brave, you can try it out thusly:

  1. Apply patch.
  2. Build boot(8), copy to /boot, and run installboot(8).
  3. Configure kernel with 'makeoptions DEBUG=-g'.
  4. Build kernel and install bsd.gdb (not bsd!).
  5. Reboot.

I did this mostly for fun / personal enlightenment, so I haven't put
too much effort into polishing it yet.


Index: ddb/db_elf.c
===
RCS file: /home/matthew/anoncvs/cvs/src/sys/ddb/db_elf.c,v
retrieving revision 1.10
diff -u -p -r1.10 db_elf.c
--- ddb/db_elf.c16 Mar 2014 20:31:46 -  1.10
+++ ddb/db_elf.c23 Jun 2014 12:27:26 -
@@ -46,6 +46,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 *);
 
 #defineSTAB_TO_SYMSTART(stab)  ((Elf_Sym *)((stab)-start))
 #defineSTAB_TO_SYMEND(stab)((Elf_Sym *)((stab)-end))
@@ -111,10 +112,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
 */
 
/*
@@ -233,6 +234,29 @@ 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 (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
@@ -343,6 +367,8 @@ db_elf_symbol_values(db_symtab_t *symtab
*valuep = symp-st_value;
 }
 
+#include db_elf_dwarf.c
+
 /*
  * Return the file and line number of the current program counter
  * if we can find the appropriate debugging symbol.
@@ -351,11 +377,15 @@ 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);
+
+   return (db_elf_dwarf_line_at_pc(linetab, linetab_size, off,
+   filename, linenum));
 }
 
 /*
Index: ddb/db_elf_dwarf.c
===
RCS file: ddb/db_elf_dwarf.c
diff -N ddb/db_elf_dwarf.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ ddb/db_elf_dwarf.c  23 Jun 2014 13:37:34 -
@@ -0,0 +1,404 @@
+/* $OpenBSD$*/
+/*
+ * Copyright (c) 2014 Matthew Dempsky matt...@dempsky.org
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS