You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
7.2 KiB
229 lines
7.2 KiB
From 3b91792d3d644d6d6b0059cb315c9fe5d3626bab Mon Sep 17 00:00:00 2001 |
|
From: Yusuke Endoh <mame@ruby-lang.org> |
|
Date: Sat, 6 Mar 2021 00:03:57 +0900 |
|
Subject: [PATCH] Support GCC's DWARF 5 [Bug #17585] |
|
|
|
Co-Authored-By: xtkoba (Tee KOBAYASHI) <xtkoba+ruby@gmail.com> |
|
--- |
|
addr2line.c | 119 ++++++++++++++++++++++++++++++++++++++++++---------- |
|
1 file changed, 97 insertions(+), 22 deletions(-) |
|
|
|
diff --git a/addr2line.c b/addr2line.c |
|
index 0029cffbca..855efb40d4 100644 |
|
--- a/addr2line.c |
|
+++ b/addr2line.c |
|
@@ -159,11 +159,12 @@ typedef struct obj_info { |
|
struct dwarf_section debug_info; |
|
struct dwarf_section debug_line; |
|
struct dwarf_section debug_ranges; |
|
+ struct dwarf_section debug_rnglists; |
|
struct dwarf_section debug_str; |
|
struct obj_info *next; |
|
} obj_info_t; |
|
|
|
-#define DWARF_SECTION_COUNT 5 |
|
+#define DWARF_SECTION_COUNT 6 |
|
|
|
static struct dwarf_section * |
|
obj_dwarf_section_at(obj_info_t *obj, int n) |
|
@@ -173,6 +174,7 @@ obj_dwarf_section_at(obj_info_t *obj, int n) |
|
&obj->debug_info, |
|
&obj->debug_line, |
|
&obj->debug_ranges, |
|
+ &obj->debug_rnglists, |
|
&obj->debug_str |
|
}; |
|
if (n < 0 || DWARF_SECTION_COUNT <= n) { |
|
@@ -411,7 +413,7 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line, |
|
FILL_LINE(); |
|
break; |
|
case DW_LNS_advance_pc: |
|
- a = uleb128((char **)&p); |
|
+ a = uleb128((char **)&p) * header.minimum_instruction_length; |
|
addr += a; |
|
break; |
|
case DW_LNS_advance_line: { |
|
@@ -451,7 +453,7 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line, |
|
/* isa = (unsigned int)*/(void)uleb128((char **)&p); |
|
break; |
|
case 0: |
|
- a = *(unsigned char *)p++; |
|
+ a = uleb128((char **)&p); |
|
op = *p++; |
|
switch (op) { |
|
case DW_LNE_end_sequence: |
|
@@ -808,6 +810,18 @@ enum |
|
DW_FORM_addrx4 = 0x2c |
|
}; |
|
|
|
+/* Range list entry encodings */ |
|
+enum { |
|
+ DW_RLE_end_of_list = 0x00, |
|
+ DW_RLE_base_addressx = 0x01, |
|
+ DW_RLE_startx_endx = 0x02, |
|
+ DW_RLE_startx_length = 0x03, |
|
+ DW_RLE_offset_pair = 0x04, |
|
+ DW_RLE_base_address = 0x05, |
|
+ DW_RLE_start_end = 0x06, |
|
+ DW_RLE_start_length = 0x07 |
|
+}; |
|
+ |
|
enum { |
|
VAL_none = 0, |
|
VAL_cstr = 1, |
|
@@ -961,6 +975,23 @@ debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj) |
|
reader->current_low_pc = 0; |
|
} |
|
|
|
+static void |
|
+di_skip_die_attributes(char **p) |
|
+{ |
|
+ for (;;) { |
|
+ uint64_t at = uleb128(p); |
|
+ uint64_t form = uleb128(p); |
|
+ if (!at && !form) break; |
|
+ switch (form) { |
|
+ default: |
|
+ break; |
|
+ case DW_FORM_implicit_const: |
|
+ sleb128(p); |
|
+ break; |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
static void |
|
di_read_debug_abbrev_cu(DebugInfoReader *reader) |
|
{ |
|
@@ -975,12 +1006,7 @@ di_read_debug_abbrev_cu(DebugInfoReader *reader) |
|
prev = abbrev_number; |
|
uleb128(&p); /* tag */ |
|
p++; /* has_children */ |
|
- /* skip content */ |
|
- for (;;) { |
|
- uint64_t at = uleb128(&p); |
|
- uint64_t form = uleb128(&p); |
|
- if (!at && !form) break; |
|
- } |
|
+ di_skip_die_attributes(&p); |
|
} |
|
} |
|
|
|
@@ -1244,12 +1270,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number) |
|
/* skip 255th record */ |
|
uleb128(&p); /* tag */ |
|
p++; /* has_children */ |
|
- /* skip content */ |
|
- for (;;) { |
|
- uint64_t at = uleb128(&p); |
|
- uint64_t form = uleb128(&p); |
|
- if (!at && !form) break; |
|
- } |
|
+ di_skip_die_attributes(&p); |
|
for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) { |
|
if (n == 0) { |
|
fprintf(stderr,"%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number); |
|
@@ -1257,12 +1278,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number) |
|
} |
|
uleb128(&p); /* tag */ |
|
p++; /* has_children */ |
|
- /* skip content */ |
|
- for (;;) { |
|
- uint64_t at = uleb128(&p); |
|
- uint64_t form = uleb128(&p); |
|
- if (!at && !form) break; |
|
- } |
|
+ di_skip_die_attributes(&p); |
|
} |
|
return p; |
|
} |
|
@@ -1390,6 +1406,21 @@ ranges_set(ranges_t *ptr, DebugInfoValue *v) |
|
} |
|
} |
|
|
|
+static uint64_t |
|
+read_dw_form_addr(DebugInfoReader *reader, char **ptr) |
|
+{ |
|
+ char *p = *ptr; |
|
+ *ptr = p + reader->format; |
|
+ if (reader->format == 4) { |
|
+ return read_uint32(&p); |
|
+ } else if (reader->format == 8) { |
|
+ return read_uint64(&p); |
|
+ } else { |
|
+ fprintf(stderr,"unknown address_size:%d", reader->address_size); |
|
+ abort(); |
|
+ } |
|
+} |
|
+ |
|
static uintptr_t |
|
ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr) |
|
{ |
|
@@ -1403,8 +1434,50 @@ 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; |
|
+ char *p; |
|
uint64_t base = ptr->low_pc_set ? ptr->low_pc : reader->current_low_pc; |
|
+ if (reader->obj->debug_rnglists.ptr) { |
|
+ p = reader->obj->debug_rnglists.ptr + ptr->ranges; |
|
+ for (;;) { |
|
+ uint8_t rle = read_uint8(&p); |
|
+ uintptr_t base_address = 0; |
|
+ uintptr_t from, to; |
|
+ if (rle == DW_RLE_end_of_list) break; |
|
+ switch (rle) { |
|
+ case DW_RLE_base_addressx: |
|
+ uleb128(&p); |
|
+ break; |
|
+ case DW_RLE_startx_endx: |
|
+ uleb128(&p); |
|
+ uleb128(&p); |
|
+ break; |
|
+ case DW_RLE_startx_length: |
|
+ uleb128(&p); |
|
+ uleb128(&p); |
|
+ break; |
|
+ case DW_RLE_offset_pair: |
|
+ from = base_address + uleb128(&p); |
|
+ to = base_address + uleb128(&p); |
|
+ if (base + from <= addr && addr < base + to) { |
|
+ return from; |
|
+ } |
|
+ break; |
|
+ case DW_RLE_base_address: |
|
+ base_address = read_dw_form_addr(reader, &p); |
|
+ break; |
|
+ case DW_RLE_start_end: |
|
+ read_dw_form_addr(reader, &p); |
|
+ read_dw_form_addr(reader, &p); |
|
+ break; |
|
+ case DW_RLE_start_length: |
|
+ read_dw_form_addr(reader, &p); |
|
+ uleb128(&p); |
|
+ break; |
|
+ } |
|
+ } |
|
+ return false; |
|
+ } |
|
+ p = reader->obj->debug_ranges.ptr + ptr->ranges; |
|
for (;;) { |
|
uintptr_t from = read_uintptr(&p); |
|
uintptr_t to = read_uintptr(&p); |
|
@@ -1750,6 +1823,7 @@ fill_lines(int num_traces, void **traces, int check_debuglink, |
|
".debug_info", |
|
".debug_line", |
|
".debug_ranges", |
|
+ ".debug_rnglists", |
|
".debug_str" |
|
}; |
|
|
|
@@ -2006,6 +2080,7 @@ found_mach_header: |
|
"__debug_info", |
|
"__debug_line", |
|
"__debug_ranges", |
|
+ "__debug_rnglists", |
|
"__debug_str" |
|
}; |
|
struct LP(segment_command) *scmd = (struct LP(segment_command) *)lcmd;
|
|
|