Skip to content

Commit 644b665

Browse files
committed
Support cross-CU DW_FORM_ref_addr in addr2line's abstract_origin
Under GCC LTO the C-level backtrace in a crash report printed only bare hex addresses (e.g. "ruby(0x...) [0x...]") for every ruby frame, even though gdb resolved the same binary fine. The concrete out-of-line function DIE carries DW_AT_low_pc, so the crash PC matches a DIE and the DWARF parse "succeeds"; but its name is reached only through a DW_AT_abstract_origin encoded as DW_FORM_ref_addr, a section-relative reference into another CU (LTO emits the concrete and abstract instances in separate CUs). addr2line.c handled the CU-relative ref forms but had DW_FORM_ref_addr as "not supported yet". [Bug #22188]
1 parent c6e3e8c commit 644b665

1 file changed

Lines changed: 55 additions & 9 deletions

File tree

addr2line.c

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,7 +1749,7 @@ ranges_inspect(DebugInfoReader *reader, ranges_t *ptr, FILE *errout)
17491749
#endif
17501750

17511751
static int
1752-
di_read_cu(DebugInfoReader *reader, FILE *errout)
1752+
di_read_cu_context(DebugInfoReader *reader, FILE *errout)
17531753
{
17541754
uint64_t unit_length;
17551755
uint16_t version;
@@ -1784,7 +1784,6 @@ di_read_cu(DebugInfoReader *reader, FILE *errout)
17841784

17851785
reader->level = 0;
17861786
di_read_debug_abbrev_cu(reader);
1787-
if (di_read_debug_line_cu(reader, errout)) return -1;
17881787

17891788
do {
17901789
DIE die;
@@ -1840,12 +1839,57 @@ di_read_cu(DebugInfoReader *reader, FILE *errout)
18401839
return 0;
18411840
}
18421841

1842+
static int
1843+
di_read_cu(DebugInfoReader *reader, FILE *errout)
1844+
{
1845+
/* Keep di_read_cu_context separate so that it can be reused by di_read_cu_at
1846+
* to set up arbitrary CUs without disturbing the .debug_line traversal. */
1847+
if (di_read_cu_context(reader, errout)) return -1;
1848+
if (di_read_debug_line_cu(reader, errout)) return -1;
1849+
return 0;
1850+
}
1851+
1852+
/* Find the .debug_info compilation unit containing the section-relative DIE
1853+
* offset `die_offset`, initialize `reader` with that unit's abbrev/base context,
1854+
* and leave reader->p pointing at the referenced DIE. Type units, split DWARF,
1855+
* and supplementary debug objects are outside this parser's current scope. */
1856+
static bool
1857+
di_read_cu_at(DebugInfoReader *reader, uint64_t die_offset, FILE *errout)
1858+
{
1859+
const uint64_t debug_info_size = reader->obj->debug_info.size;
1860+
if (die_offset >= debug_info_size) return false;
1861+
1862+
const char *const info = reader->obj->debug_info.ptr;
1863+
const char *const pend = reader->pend;
1864+
const char *const target = info + die_offset;
1865+
const char *cu = info;
1866+
1867+
while (pend - cu >= 4) {
1868+
const char *hp = cu;
1869+
uint64_t unit_length = read_uint32(&hp);
1870+
1871+
if (unit_length == 0xffffffff) {
1872+
if (pend - hp < 8) return false;
1873+
unit_length = read_uint64(&hp);
1874+
}
1875+
if (unit_length == 0 || unit_length > (uint64_t)(pend - hp)) return false;
1876+
1877+
const char *cu_end = hp + unit_length;
1878+
if (target >= cu && target < cu_end) {
1879+
reader->p = cu;
1880+
if (di_read_cu_context(reader, errout)) return false;
1881+
reader->p = target;
1882+
return true;
1883+
}
1884+
cu = cu_end;
1885+
}
1886+
return false;
1887+
}
1888+
18431889
static void
18441890
read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line, FILE *errout)
18451891
{
1846-
const char *p = reader->p;
1847-
const char *q = reader->q;
1848-
int level = reader->level;
1892+
DebugInfoReader saved = *reader; /* CU-scoped state may be rewritten below */
18491893
DIE die;
18501894

18511895
switch (form) {
@@ -1857,7 +1901,11 @@ read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_o
18571901
reader->p = reader->current_cu + abstract_origin;
18581902
break;
18591903
case DW_FORM_ref_addr:
1860-
goto finish; /* not supported yet */
1904+
/* Section-relative; target may be in another CU.
1905+
* Switch to that CU's context.
1906+
* di_read_cu_at leaves p at the target DIE. */
1907+
if (!di_read_cu_at(reader, abstract_origin, errout)) goto finish;
1908+
break;
18611909
case DW_FORM_ref_sig8:
18621910
goto finish; /* not supported yet */
18631911
case DW_FORM_ref_sup4:
@@ -1880,9 +1928,7 @@ read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_o
18801928
}
18811929

18821930
finish:
1883-
reader->p = p;
1884-
reader->q = q;
1885-
reader->level = level;
1931+
*reader = saved;
18861932
}
18871933

18881934
static bool

0 commit comments

Comments
 (0)