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:
parent
b101bfbf5f
commit
6baef60a48
52
elf/dwarf.cc
52
elf/dwarf.cc
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user