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