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 -0000
+++ ddb/db_dwarf.h 10 Jul 2014 07:14:26 -0000
@@ -0,0 +1,24 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2014 Matthew Dempsky <[email protected]>
+ *
+ * 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 -0000
+++ ddb/db_dwarf.c 10 Jul 2014 07:49:07 -0000
@@ -0,0 +1,550 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2014 Matthew Dempsky <[email protected]>
+ *
+ * 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
+read_u32(struct dwbuf *d, uint32_t *v)
+{
+ return (read_bytes(d, v, sizeof(*v)));
+}
+
+static bool
+read_u64(struct dwbuf *d, uint64_t *v)
+{
+ return (read_bytes(d, v, sizeof(*v)));
+}
+
+static bool
+read_sleb128(struct dwbuf *d, int64_t *v)
+{
+ unsigned int shift = 0;
+ int64_t res = 0;
+ for (;;) {
+ uint8_t x;
+ if (!read_u8(d, &x))
+ return (false);
+ res |= (int64_t)(x & 0x7f) << shift;
+ shift += 7;
+ if ((x & 0x80) == 0) {
+ if (x & 0x40 && shift < 64)
+ res |= ~(int64_t)0 << shift;
+ *v = res;
+ return (true);
+ }
+ if (shift >= 64)
+ return (false);
+ }
+}
+
+static bool
+read_uleb128(struct dwbuf *d, uint64_t *v)
+{
+ unsigned int shift = 0;
+ uint64_t res = 0;
+ for (;;) {
+ uint8_t x;
+ if (!read_u8(d, &x))
+ return (false);
+ res |= (uint64_t)(x & 0x7f) << shift;
+ shift += 7;
+ if ((x & 0x80) == 0) {
+ *v = res;
+ return (true);
+ }
+ if (shift >= 64)
+ return (false);
+ }
+}
+
+static bool
+read_string(struct dwbuf *d, const char **s)
+{
+ const char *end = memchr(d->buf, '\0', d->len);
+ if (end == NULL)
+ return (false);
+ size_t n = end - d->buf + 1;
+ *s = d->buf;
+ d->buf += n;
+ d->len -= n;
+ return (true);
+}
+
+static bool
+read_buf(struct dwbuf *d, struct dwbuf *v, size_t n)
+{
+ if (d->len < n)
+ return (false);
+ v->buf = d->buf;
+ v->len = n;
+ d->buf += n;
+ d->len -= n;
+ return (true);
+}
+
+static bool
+skip_bytes(struct dwbuf *d, size_t n)
+{
+ if (d->len < n)
+ return (false);
+ d->buf += n;
+ d->len -= n;
+ return (true);
+}
+
+static bool
+read_filename(struct dwbuf *unit, const char **outdirname,
+ const char **outbasename, uint8_t opcode_base, uint64_t file)
+{
+ /* Skip over opcode table. */
+ size_t i;
+ for (i = 1; i < opcode_base; i++) {
+ uint64_t dummy;
+ if (!read_uleb128(unit, &dummy))
+ return (false);
+ }
+
+ /* Skip over directory name table for now. */
+ struct dwbuf dirs = *unit;
+ for (;;) {
+ const char *name;
+ if (!read_string(unit, &name))
+ return (false);
+ if (*name == '\0')
+ break;
+ }
+
+ /* Locate file entry. */
+ const char *basename = NULL;
+ uint64_t dir = 0;
+ for (i = 0; i < file; i++) {
+ if (!read_string(unit, &basename))
+ return (false);
+ if (*basename == '\0')
+ return (false);
+ uint64_t mtime, size;
+ if (!read_uleb128(unit, &dir) ||
+ !read_uleb128(unit, &mtime) ||
+ !read_uleb128(unit, &size))
+ return (false);
+ }
+
+ const char *dirname = NULL;
+ for (i = 0; i < dir; i++) {
+ if (!read_string(&dirs, &dirname))
+ return (false);
+ if (*dirname == '\0')
+ return (false);
+ }
+
+ *outdirname = dirname;
+ *outbasename = basename;
+ return (true);
+}
+
+bool
+db_dwarf_line_at_pc(const char *tab, size_t tabsize, uintptr_t pc,
+ const char **outdirname, const char **outbasename, int *outline)
+{
+ struct dwbuf table = { .buf = tab, .len = tabsize };
+
+ /*
+ * For simplicity and memory conservation, we simply brute force search
+ * through the entire line table each time.
+ */
+ uint32_t unitsize;
+next:
+ if (!read_u32(&table, &unitsize))
+ return (false);
+ if (unitsize >= 0xfffffff0)
+ return (false);
+
+ struct dwbuf unit;
+ if (!read_buf(&table, &unit, unitsize))
+ return (false);
+
+ uint16_t version;
+ if (!read_u16(&unit, &version))
+ goto next;
+ if (version > 2)
+ goto next;
+ uint32_t header_size;
+ if (!read_u32(&unit, &header_size))
+ goto next;
+
+ struct dwbuf header = unit;
+ uint8_t min_insn_length, default_is_stmt, line_range, opcode_base;
+ int8_t line_base;
+ if (!read_u8(&unit, &min_insn_length) ||
+ !read_u8(&unit, &default_is_stmt) ||
+ !read_s8(&unit, &line_base) ||
+ !read_u8(&unit, &line_range) ||
+ !read_u8(&unit, &opcode_base))
+ goto next;
+
+ /*
+ * Files are next in the header, but for now we want to skip past the
+ * rest of the header and go directly to the line number table.
+ */
+ struct dwbuf files = unit;
+ unit = header;
+ if (!skip_bytes(&unit, header_size))
+ return (false);
+
+ /* VM registers. */
+ uint64_t address = 0, file = 1, line = 1, column = 0;
+ uint8_t is_stmt = default_is_stmt;
+ bool basic_block = false, end_sequence = false;
+ bool prologue_end = false, epilogue_begin = false;
+
+ /* Previous line table entry. */
+ bool have_prev = false;
+ uint64_t prev_line = 0, prev_file = 0;
+
+ /* Time to run the line program. */
+ uint8_t opcode;
+ while (read_u8(&unit, &opcode)) {
+ bool emit = false, reset_basic_block = false;
+
+ if (opcode >= opcode_base) {
+ /* "Special" opcodes. */
+ uint8_t diff = opcode - opcode_base;
+ address += diff / line_range;
+ line += line_base + diff % line_range;
+ emit = true;
+ } else if (opcode == 0) {
+ /* "Extended" opcodes. */
+ uint64_t extsize;
+ struct dwbuf extra;
+ if (!read_uleb128(&unit, &extsize) ||
+ !read_buf(&unit, &extra, extsize) ||
+ !read_u8(&extra, &opcode))
+ goto next;
+ switch (opcode) {
+ case DW_LNE_end_sequence:
+ emit = true;
+ end_sequence = true;
+ break;
+ case DW_LNE_set_address:
+ switch (extra.len) {
+ case 4: {
+ uint32_t address32;
+ if (!read_u32(&extra, &address32))
+ goto next;
+ address = address32;
+ break;
+ }
+ case 8:
+ if (!read_u64(&extra, &address))
+ goto next;
+ break;
+ default:
+ DWARN("unexpected address length: %zu",
+ extra.len);
+ goto next;
+ }
+ break;
+ case DW_LNE_define_file:
+ /* XXX: hope this isn't needed */
+ default:
+ DWARN("unknown extended opcode: %d", opcode);
+ goto next;
+ }
+ } else {
+ /* "Standard" opcodes. */
+ switch (opcode) {
+ case DW_LNS_copy:
+ emit = true;
+ reset_basic_block = true;
+ break;
+ case DW_LNS_advance_pc: {
+ uint64_t delta;
+ if (!read_uleb128(&unit, &delta))
+ goto next;
+ address += delta * min_insn_length;
+ break;
+ }
+ case DW_LNS_advance_line: {
+ int64_t delta;
+ if (!read_sleb128(&unit, &delta))
+ goto next;
+ line += delta;
+ break;
+ }
+ case DW_LNS_set_file:
+ if (!read_uleb128(&unit, &file))
+ goto next;
+ break;
+ case DW_LNS_set_column:
+ if (!read_uleb128(&unit, &column))
+ goto next;
+ break;
+ case DW_LNS_negate_stmt:
+ is_stmt = !is_stmt;
+ break;
+ case DW_LNS_set_basic_block:
+ basic_block = true;
+ break;
+ case DW_LNS_const_add_pc:
+ address += (255 - opcode_base) / line_range;
+ break;
+ case DW_LNS_set_prologue_end:
+ prologue_end = true;
+ break;
+ case DW_LNS_set_epilogue_begin:
+ epilogue_begin = true;
+ break;
+ default:
+ DWARN("unknown standard opcode: %d", opcode);
+ goto next;
+ }
+ }
+
+ if (emit) {
+ if (address > pc) {
+ /* Found an entry after our target PC. */
+ if (!have_prev) {
+ /* Give up on this program. */
+ break;
+ }
+ /* Return the previous entry. */
+ *outline = prev_line;
+ return (read_filename(&files, outdirname,
+ outbasename, opcode_base, file));
+ }
+
+ prev_file = file;
+ prev_line = line;
+ have_prev = true;
+ }
+
+ if (reset_basic_block)
+ basic_block = false;
+ }
+
+ goto next;
+}
+
+#ifndef _KERNEL
+#include <sys/endian.h>
+#include <sys/exec_elf.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef ELFDATA
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ELFDATA ELFDATA2LSB
+#elif BYTE_ORDER == BIG_ENDIAN
+#define ELFDATA ELFDATA2MSB
+#else
+#error Unsupported byte order
+#endif
+#endif
+
+void
+usage()
+{
+ extern const char *__progname;
+ errx(1, "usage: %s [-s] [-e filename] [addr addr ...]", __progname);
+}
+
+/*
+ * Basic addr2line clone for stand-alone testing.
+ */
+int
+main(int argc, char *argv[])
+{
+ const char *filename = "a.out";
+
+ int ch;
+ bool showdir = true;
+ while ((ch = getopt(argc, argv, "e:s")) != EOF) {
+ switch (ch) {
+ case 'e':
+ filename = optarg;
+ break;
+ case 's':
+ showdir = false;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ int fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ err(1, "open");
+
+ struct stat st;
+ if (fstat(fd, &st) == -1)
+ err(1, "fstat");
+ if (st.st_size < (off_t)sizeof(Elf_Ehdr))
+ errx(1, "file too small");
+ if ((uintmax_t)st.st_size > SIZE_MAX)
+ errx(1, "file larger than memory");
+ size_t filesize = st.st_size;
+
+ const char *p = mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0);
+ if (p == MAP_FAILED)
+ err(1, "mmap");
+
+ close(fd);
+
+ Elf_Ehdr ehdr;
+ memcpy(&ehdr, p, sizeof(ehdr));
+ if (!IS_ELF(ehdr))
+ errx(1, "file is not ELF");
+ if (ehdr.e_ident[EI_CLASS] != ELFCLASS)
+ errx(1, "unexpected word size");
+ if (ehdr.e_ident[EI_DATA] != ELFDATA)
+ errx(1, "unexpected data format");
+ if (ehdr.e_shoff > filesize)
+ errx(1, "bogus section table offset");
+ if (ehdr.e_shentsize < sizeof(Elf_Shdr))
+ errx(1, "unexpected section header size");
+ if (ehdr.e_shnum > (filesize - ehdr.e_shoff) / ehdr.e_shentsize)
+ errx(1, "bogus section header count");
+ if (ehdr.e_shstrndx >= ehdr.e_shnum)
+ errx(1, "bogus string table index");
+
+ Elf_Shdr shdr;
+ memcpy(&shdr, p + ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize,
+ sizeof(shdr));
+ if (shdr.sh_type != SHT_STRTAB)
+ errx(1, "unexpected string table type");
+ if (shdr.sh_offset > filesize)
+ errx(1, "bogus string table offset");
+ if (shdr.sh_size > filesize - shdr.sh_offset)
+ errx(1, "bogus string table size");
+ const char *shstrtab = p + shdr.sh_offset;
+ size_t shstrtabsize = shdr.sh_size;
+
+ size_t i;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ memcpy(&shdr, p + ehdr.e_shoff + i * ehdr.e_shentsize,
+ sizeof(shdr));
+ if (0 == strncmp(".debug_line", shstrtab + shdr.sh_name,
+ shstrtabsize - shdr.sh_name))
+ break;
+ }
+ if (i == ehdr.e_shnum)
+ errx(1, "no DWARF line number table found");
+ if (shdr.sh_offset > filesize)
+ errx(1, "bogus line table offset");
+ if (shdr.sh_size > filesize - shdr.sh_offset)
+ errx(1, "bogus line table size");
+ const char *linetab = p + shdr.sh_offset;
+ size_t linetabsize = shdr.sh_size;
+
+ const char *addrstr;
+ while ((addrstr = *argv++) != NULL) {
+ unsigned long addr = strtoul(addrstr, NULL, 16);
+
+ const char *dir, *file;
+ int line;
+ if (!db_dwarf_line_at_pc(linetab, linetabsize, addr,
+ &dir, &file, &line)) {
+ dir = NULL;
+ file = "??";
+ line = 0;
+ }
+ if (showdir && dir != NULL)
+ printf("%s/", dir);
+ printf("%s:%d\n", file, line);
+ }
+
+ return (0);
+}
+#endif
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.c 16 Mar 2014 20:31:46 -0000 1.10
+++ ddb/db_elf.c 10 Jul 2014 07:14:39 -0000
@@ -32,6 +32,7 @@
*/
#include <sys/types.h>
+#include <sys/stdint.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
@@ -39,6 +40,7 @@
#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>
@@ -46,6 +48,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))
@@ -111,10 +114,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 +236,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
@@ -351,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: conf/files
===================================================================
RCS file: /home/matthew/anoncvs/cvs/src/sys/conf/files,v
retrieving revision 1.572
diff -u -p -r1.572 files
--- conf/files 19 Apr 2014 12:27:06 -0000 1.572
+++ conf/files 10 Jul 2014 07:47:43 -0000
@@ -612,6 +612,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: 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 23 Jun 2014 09:38:46 -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;
}
@@ -242,6 +260,7 @@ ELFNAME(exec)(int fd, Elf_Ehdr *elf, u_l
if (havesyms && first == 0)
PROGRESS(("]"));
}
+ FREE(shstr, shstrsz);
FREE(shp, sz);
}