ruby/ruby-dwarf5-avoid_crash-r1.patch
2021-07-08 23:59:03 +02:00

217 lines
6.1 KiB
Diff

--- a/addr2line.c
+++ b/addr2line.c
@@ -163,11 +163,12 @@
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)
@@ -177,6 +177,7 @@
&obj->debug_info,
&obj->debug_line,
&obj->debug_ranges,
+ &obj->debug_rnglists,
&obj->debug_str
};
if (n < 0 || DWARF_SECTION_COUNT <= n) {
@@ -415,7 +415,7 @@
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: {
@@ -454,7 +454,7 @@
/* 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:
@@ -768,6 +768,18 @@
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,
@@ -921,6 +921,23 @@
}
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)
{
uint64_t prev = 0;
@@ -934,12 +934,7 @@
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);
}
}
@@ -1203,12 +1203,7 @@
/* 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);
@@ -1216,12 +1216,7 @@
}
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;
}
@@ -1349,6 +1349,21 @@
}
}
+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)
{
@@ -1362,8 +1362,50 @@
}
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);
@@ -1701,6 +1701,7 @@
".debug_info",
".debug_line",
".debug_ranges",
+ ".debug_rnglists",
".debug_str"
};
@@ -1950,6 +1950,7 @@
"__debug_info",
"__debug_line",
"__debug_ranges",
+ "__debug_rnglists",
"__debug_str"
};
struct LP(segment_command) *scmd = (struct LP(segment_command) *)lcmd;