summaryrefslogtreecommitdiff
path: root/addr2line.c
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-10-16 23:52:28 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-10-16 23:52:28 +0000
commite9a284ab94d1168467a917667a7d1a33185fcfcd (patch)
treeca39dc789669aec329431838b83264e90417bd97 /addr2line.c
parent447d7a394fb01b2fe86f4130517f32d7c177d9f9 (diff)
Correct the handling of .debug_ranges
Though DWARF specifies "the applicable base address defaults to the base address of the compilation unit", but GCC seems to use zero as default. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65103 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'addr2line.c')
-rw-r--r--addr2line.c91
1 files changed, 60 insertions, 31 deletions
diff --git a/addr2line.c b/addr2line.c
index 8df0247ed2..ae21f7cbdb 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -138,6 +138,7 @@ typedef struct obj_info {
size_t mapped_size;
void *uncompressed;
uintptr_t base_addr;
+ uintptr_t vmaddr;
struct dwarf_section debug_abbrev;
struct dwarf_section debug_info;
struct dwarf_section debug_line;
@@ -249,7 +250,7 @@ fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
obj_info_t *obj, line_info_t *lines, int offset)
{
int i;
- addr += obj->base_addr;
+ addr += obj->base_addr - obj->vmaddr;
for (i = offset; i < num_traces; i++) {
uintptr_t a = (uintptr_t)traces[i];
/* We assume one line code doesn't result >100 bytes of native code.
@@ -506,6 +507,7 @@ follow_debuglink(const char *debuglink, int num_traces, void **traces,
enum
{
+ DW_TAG_compile_unit = 0x11,
DW_TAG_inlined_subroutine = 0x1d,
DW_TAG_subprogram = 0x2e,
};
@@ -734,6 +736,7 @@ typedef struct {
obj_info_t *obj;
char *file;
char *current_cu;
+ uint64_t current_low_pc;
char *debug_line_cu_end;
char *debug_line_files;
char *debug_line_directories;
@@ -937,31 +940,6 @@ di_read_debug_line_cu(DebugInfoReader *reader)
reader->debug_line_files = p;
}
-
-static int
-di_read_cu(DebugInfoReader *reader)
-{
- DW_CompilationUnitHeader32 *hdr32 = (DW_CompilationUnitHeader32 *)reader->p;
- reader->current_cu = reader->p;
- if (hdr32->unit_length == 0xffffffff) {
- DW_CompilationUnitHeader64 *hdr = (DW_CompilationUnitHeader64 *)hdr32;
- reader->p += 23;
- reader->q0 = reader->obj->debug_abbrev.ptr + hdr->debug_abbrev_offset;
- reader->address_size = hdr->address_size;
- reader->format = 64;
- } else {
- DW_CompilationUnitHeader32 *hdr = hdr32;
- reader->p += 11;
- reader->q0 = reader->obj->debug_abbrev.ptr + hdr->debug_abbrev_offset;
- reader->address_size = hdr->address_size;
- reader->format = 32;
- }
- reader->level = 0;
- di_read_debug_abbrev_cu(reader);
- di_read_debug_line_cu(reader);
- return 0;
-}
-
static void
set_uint_value(DebugInfoValue *v, uint64_t n)
{
@@ -1363,12 +1341,14 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr)
}
}
else if (ptr->ranges_set) {
+ /* TODO: support base address selection entry */
char *p = reader->obj->debug_ranges.ptr + ptr->ranges;
+ uint64_t base = ptr->low_pc_set ? ptr->low_pc : reader->current_low_pc;
for (;;) {
uintptr_t from = read_uintptr(&p);
uintptr_t to = read_uintptr(&p);
if (!from && !to) break;
- if (from <= addr && addr <= to) {
+ if (base + from <= addr && addr <= base + to) {
return from;
}
}
@@ -1414,6 +1394,56 @@ ranges_inspect(DebugInfoReader *reader, ranges_t *ptr)
#endif
static void
+di_read_cu(DebugInfoReader *reader)
+{
+ DW_CompilationUnitHeader32 *hdr32 = (DW_CompilationUnitHeader32 *)reader->p;
+ reader->current_cu = reader->p;
+ if (hdr32->unit_length == 0xffffffff) {
+ DW_CompilationUnitHeader64 *hdr = (DW_CompilationUnitHeader64 *)hdr32;
+ reader->p += 23;
+ reader->q0 = reader->obj->debug_abbrev.ptr + hdr->debug_abbrev_offset;
+ reader->address_size = hdr->address_size;
+ reader->format = 64;
+ } else {
+ DW_CompilationUnitHeader32 *hdr = hdr32;
+ reader->p += 11;
+ reader->q0 = reader->obj->debug_abbrev.ptr + hdr->debug_abbrev_offset;
+ reader->address_size = hdr->address_size;
+ reader->format = 32;
+ }
+ reader->level = 0;
+ di_read_debug_abbrev_cu(reader);
+ di_read_debug_line_cu(reader);
+
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER_BUILD_DATE)
+ /* Though DWARF specifies "the applicable base address defaults to the base
+ address of the compilation unit", but GCC seems to use zero as default */
+#else
+ do {
+ DIE die;
+
+ if (!di_read_die(reader, &die)) continue;
+
+ if (die.tag != DW_TAG_compile_unit) {
+ di_skip_records(reader);
+ break;
+ }
+
+ /* enumerate abbrev */
+ for (;;) {
+ DebugInfoValue v = {{}};
+ if (!di_read_record(reader, &v)) break;
+ switch (v.at) {
+ case DW_AT_low_pc:
+ reader->current_low_pc = v.as.uint64;
+ break;
+ }
+ }
+ } while (0);
+#endif
+}
+
+static void
read_abstract_origin(DebugInfoReader *reader, uint64_t abstract_origin, line_info_t *line)
{
char *p = reader->p;
@@ -1494,10 +1524,10 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
/* fprintf(stderr,"%d:%tx: %x ",__LINE__,diepos,die.tag); */
for (int i=offset; i < num_traces; i++) {
uintptr_t addr = (uintptr_t)traces[i];
- uintptr_t offset = addr - reader->obj->base_addr;
+ uintptr_t offset = addr - reader->obj->base_addr + reader->obj->vmaddr;
uintptr_t saddr = ranges_include(reader, &ranges, offset);
if (saddr) {
- //fprintf(stderr, "%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname);
+ /* fprintf(stderr, "%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname); */
if (lines[i].sname) {
line_info_t *lp = malloc(sizeof(line_info_t));
memcpy(lp, &lines[i], sizeof(line_info_t));
@@ -1702,13 +1732,12 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
i = 0;
while (reader.p < reader.pend) {
//fprintf(stderr, "%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info, i++);
- if (di_read_cu(&reader)) goto use_symtab;
+ di_read_cu(&reader);
debug_info_read(&reader, num_traces, traces, lines, offset);
}
}
else {
/* This file doesn't have dwarf, use symtab or dynsym */
- use_symtab:
if (!symtab_shdr) {
/* This file doesn't have symtab, use dynsym instead */
symtab_shdr = dynsym_shdr;