1
1
mirror of https://github.com/rui314/mold.git synced 2024-10-04 08:37:28 +03:00

[ELF] Fix .debug_rnglists reader

Fixes https://github.com/rui314/mold/issues/453
This commit is contained in:
Rui Ueyama 2022-04-22 13:59:39 +08:00
parent b101bfbf5f
commit 6baef60a48
2 changed files with 91 additions and 43 deletions

View File

@ -368,10 +368,15 @@ read_address_areas(Context<E> &ctx, ObjectFile<E> &file, i64 offset) {
DebugInfoReader<E> reader{ctx, file, cu};
std::pair<u64, u64> low_pc;
std::pair<u64, u64> high_pc;
std::optional<u64> ranges;
u64 rnglists_base = 0;
struct Record {
u64 form = 0;
u64 value = 0;
};
Record low_pc;
Record high_pc;
Record ranges;
std::optional<u64> rnglists_base;
typename E::WordTy *addrx = nullptr;
// Read all interesting debug records.
@ -397,61 +402,68 @@ read_address_areas(Context<E> &ctx, ObjectFile<E> &file, i64 offset) {
addrx = (typename E::WordTy *)(get_buffer(ctx, ctx.debug_addr) + val);
break;
case DW_AT_ranges:
ranges = val;
ranges = {form, val};
break;
}
}
// Handle non-contiguous address ranges.
if (ranges) {
if (ranges.form) {
if (dwarf_version <= 4) {
typename E::WordTy *range_begin =
(typename E::WordTy *)(get_buffer(ctx, ctx.debug_ranges) + *ranges);
(typename E::WordTy *)(get_buffer(ctx, ctx.debug_ranges) + ranges.value);
return read_debug_range(ctx, file, range_begin);
}
assert(dwarf_version == 5);
u8 *buf = get_buffer(ctx, ctx.debug_rnglists) + rnglists_base;
u64 offset = *(u32 *)(buf + *ranges * 4);
return read_rnglist_range(ctx, file, buf + offset, addrx);
u8 *buf = get_buffer(ctx, ctx.debug_rnglists);
if (ranges.form == DW_FORM_sec_offset)
return read_rnglist_range(ctx, file, buf + ranges.value, addrx);
if (!rnglists_base)
Fatal(ctx) << file << ": --gdb-index: missing DW_AT_rnglists_base";
u8 *base = buf + *rnglists_base;
return read_rnglist_range(ctx, file, base + *(u32 *)base, addrx);
}
// Handle a contiguous address range.
if (low_pc.first && high_pc.first) {
if (low_pc.form && high_pc.form) {
u64 lo;
switch (low_pc.first) {
switch (low_pc.form) {
case DW_FORM_addr:
lo = low_pc.second;
lo = low_pc.value;
break;
case DW_FORM_addrx:
case DW_FORM_addrx1:
case DW_FORM_addrx2:
case DW_FORM_addrx4:
lo = addrx[low_pc.second];
lo = addrx[low_pc.value];
break;
default:
Fatal(ctx) << file << ": --gdb-index: unhandled form for DW_AT_low_pc: 0x"
<< std::hex << high_pc.first;
<< std::hex << high_pc.form;
}
switch (high_pc.first) {
switch (high_pc.form) {
case DW_FORM_addr:
return {lo, high_pc.second};
return {lo, high_pc.value};
case DW_FORM_addrx:
case DW_FORM_addrx1:
case DW_FORM_addrx2:
case DW_FORM_addrx4:
return {lo, addrx[high_pc.second]};
return {lo, addrx[high_pc.value]};
case DW_FORM_udata:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
case DW_FORM_data8:
return {lo, lo + high_pc.second};
return {lo, lo + high_pc.value};
default:
Fatal(ctx) << file << ": --gdb-index: unhandled form for DW_AT_high_pc: 0x"
<< std::hex << high_pc.first;
<< std::hex << high_pc.form;
}
}

View File

@ -21,41 +21,73 @@ which gdb >& /dev/null || { echo skipped; exit; }
echo 'int main() {}' | $CC -o /dev/null -xc -gdwarf-5 -g - >& /dev/null ||
{ echo skipped; exit; }
cat <<EOF | $CC -c -o $t/a.o -fPIC -g -ggnu-pubnames -gdwarf-5 -xc - -ffunction-sections
void hello2();
cat <<EOF > $t/a.c
void fn3();
static void hello() {
hello2();
static void fn2() {
fn3();
}
void greet() {
hello();
void fn1() {
fn2();
}
EOF
cat <<EOF | $CC -c -o $t/b.o -fPIC -g -ggnu-pubnames -gdwarf-4 -xc - -ffunction-sections
#include <stdio.h>
cat <<EOF > $t/b.c
void fn5();
static void fn4() {
fn5();
}
void fn3() {
fn4();
}
EOF
cat <<EOF > $t/c.c
void fn7();
static void fn6() {
fn7();
}
void fn5() {
fn6();
}
EOF
cat <<EOF > $t/d.c
#include <stdio.h>
void trap() {}
void hello2() {
static void fn8() {
printf("Hello world\n");
trap();
}
EOF
$CC -B. -shared -o $t/c.so $t/a.o $t/b.o -Wl,--gdb-index
readelf -WS $t/c.so 2> /dev/null | fgrep -q .gdb_index
cat <<EOF | $CC -c -o $t/d.o -fPIC -g -ggnu-pubnames -gdwarf-5 -xc - -gz
void greet();
int main() {
greet();
void fn7() {
fn8();
}
EOF
$CC -B. -o $t/exe $t/c.so $t/d.o -Wl,--gdb-index
$CC -c -o $t/a.o $t/a.c -fPIC -g -ggnu-pubnames -gdwarf-5 -ffunction-sections
$CC -c -o $t/b.o $t/b.c -fPIC -g -ggnu-pubnames -gdwarf-4 -ffunction-sections
$CC -c -o $t/c.o $t/c.c -fPIC -g -ggnu-pubnames -gdwarf-5
$CC -c -o $t/d.o $t/d.c -fPIC -g -ggnu-pubnames -gdwarf-5 -ffunction-sections
$CC -B. -shared -o $t/e.so $t/a.o $t/b.o $t/c.o $t/d.o -Wl,--gdb-index
readelf -WS $t/e.so 2> /dev/null | fgrep -q .gdb_index
cat <<EOF | $CC -c -o $t/f.o -fPIC -g -ggnu-pubnames -gdwarf-5 -xc - -gz
void fn1();
int main() {
fn1();
}
EOF
$CC -B. -o $t/exe $t/e.so $t/f.o -Wl,--gdb-index
readelf -WS $t/exe 2> /dev/null | fgrep -q .gdb_index
$QEMU $t/exe | grep -q 'Hello world'
@ -63,9 +95,13 @@ $QEMU $t/exe | grep -q 'Hello world'
DEBUGINFOD_URLS= gdb $t/exe -batch -ex 'b main' -ex r -ex 'b trap' \
-ex c -ex bt -ex quit >& $t/log
grep -Pq 'hello2 \(\) at .*<stdin>:7' $t/log
grep -Pq 'hello \(\) at .*<stdin>:4' $t/log
grep -Pq 'greet \(\) at .*<stdin>:8' $t/log
grep -Pq 'main \(\) at .*<stdin>:4' $t/log
grep -Pq 'fn8 \(\) at .*/d.c:6' $t/log
grep -Pq 'fn7 \(\) at .*/d.c:10' $t/log
grep -Pq 'fn6 \(\) at .*/c.c:4' $t/log
grep -Pq 'fn5 \(\) at .*/c.c:8' $t/log
grep -Pq 'fn4 \(\) at .*/b.c:4' $t/log
grep -Pq 'fn3 \(\) at .*/b.c:8' $t/log
grep -Pq 'fn2 \(\) at .*/a.c:4' $t/log
grep -Pq 'fn1 \(\) at .*/a.c:8' $t/log
echo OK