mirror of
https://github.com/rui314/mold.git
synced 2024-10-04 16:48:04 +03:00
[ELF] Write tombstone values to dead debug info records
This is an attempt to fix https://github.com/rui314/mold/issues/357.
This commit is contained in:
parent
4df5d6497a
commit
e448e0eb2b
@ -339,9 +339,15 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_ARM_ABS32:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u32 *)loc = *val;
|
||||
else
|
||||
*(u32 *)loc = S + A;
|
||||
break;
|
||||
case R_ARM_TLS_LDO32:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u32 *)loc = *val;
|
||||
else
|
||||
*(u32 *)loc = S + A - ctx.tls_begin;
|
||||
break;
|
||||
default:
|
||||
|
@ -369,6 +369,9 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_AARCH64_ABS64:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u64 *)loc = *val;
|
||||
else
|
||||
*(u64 *)loc = S + A;
|
||||
continue;
|
||||
case R_AARCH64_ABS32:
|
||||
|
@ -384,6 +384,9 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
write16(S + A);
|
||||
continue;
|
||||
case R_386_32:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u32 *)loc = *val;
|
||||
else
|
||||
*(u32 *)loc = S + A;
|
||||
continue;
|
||||
case R_386_PC8:
|
||||
@ -402,6 +405,9 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
*(u32 *)loc = S + A - GOT;
|
||||
continue;
|
||||
case R_386_TLS_LDO_32:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u32 *)loc = *val;
|
||||
else
|
||||
*(u32 *)loc = S + A - ctx.tls_begin;
|
||||
continue;
|
||||
case R_386_SIZE32:
|
||||
|
@ -434,6 +434,9 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
*(u32 *)loc = S + A;
|
||||
break;
|
||||
case R_RISCV_64:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u64 *)loc = *val;
|
||||
else
|
||||
*(u64 *)loc = S + A;
|
||||
break;
|
||||
case R_RISCV_ADD8:
|
||||
|
@ -608,12 +608,21 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
write32s(S + A);
|
||||
break;
|
||||
case R_X86_64_64:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u64 *)loc = *val;
|
||||
else
|
||||
*(u64 *)loc = S + A;
|
||||
break;
|
||||
case R_X86_64_DTPOFF32:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u32 *)loc = *val;
|
||||
else
|
||||
write32s(S + A - ctx.tls_begin);
|
||||
break;
|
||||
case R_X86_64_DTPOFF64:
|
||||
if (std::optional<u64> val = get_tombstone(sym))
|
||||
*(u64 *)loc = *val;
|
||||
else
|
||||
*(u64 *)loc = S + A - ctx.tls_begin;
|
||||
break;
|
||||
case R_X86_64_SIZE32:
|
||||
|
35
elf/mold.h
35
elf/mold.h
@ -322,6 +322,7 @@ private:
|
||||
std::pair<SectionFragment<E> *, i64>
|
||||
get_fragment(Context<E> &ctx, const ElfRel<E> &rel);
|
||||
|
||||
std::optional<u64> get_tombstone(Symbol<E> &sym);
|
||||
bool is_relr_reloc(Context<E> &ctx, const ElfRel<E> &rel);
|
||||
};
|
||||
|
||||
@ -2204,6 +2205,40 @@ InputSection<E>::get_fragment(Context<E> &ctx, const ElfRel<E> &rel) {
|
||||
return {m->fragments[idx], offset - offsets[idx]};
|
||||
}
|
||||
|
||||
// Input object files may contain duplicate code for inline functions
|
||||
// and such. Linkers de-duplicate them at link-time. However, linkers
|
||||
// generaly don't remove debug info for de-duplicated functions because
|
||||
// doing that requires parsing the entire debug section.
|
||||
//
|
||||
// Instead, linkers write "tombstone" values to dead debug info records
|
||||
// instead of bogus values so that debuggers can skip them.
|
||||
//
|
||||
// This function returns a tombstone value for the symbol if the symbol
|
||||
// refers a dead debug info section.
|
||||
template <typename E>
|
||||
inline std::optional<u64> InputSection<E>::get_tombstone(Symbol<E> &sym) {
|
||||
InputSection<E> *isec = sym.get_input_section();
|
||||
|
||||
// Setting a tombstone is a special feature for a dead debug section.
|
||||
if (!isec || isec->is_alive)
|
||||
return {};
|
||||
|
||||
std::string_view s = name();
|
||||
if (!s.starts_with(".debug"))
|
||||
return {};
|
||||
|
||||
// If the section was dead due to ICF, we don't want to emit debug
|
||||
// info for that section but want to set real values to .debug_line so
|
||||
// that users can set a breakpoint inside a merged section.
|
||||
if (isec->killed_by_icf && s == ".debug_line")
|
||||
return {};
|
||||
|
||||
// 0 is an invalid value in most debug info sections, so we use it
|
||||
// as a tombstone value. .debug_loc and .debug_ranges reserve 0 as
|
||||
// the terminator marker, so we use 1 if that's the case.
|
||||
return (s == ".debug_loc" || s == ".debug_ranges") ? 1 : 0;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
inline bool InputSection<E>::is_relr_reloc(Context<E> &ctx, const ElfRel<E> &rel) {
|
||||
return ctx.arg.pack_dyn_relocs_relr &&
|
||||
|
42
test/elf/dead-debug-sections.sh
Executable file
42
test/elf/dead-debug-sections.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
export LC_ALL=C
|
||||
set -e
|
||||
CC="${CC:-cc}"
|
||||
CXX="${CXX:-c++}"
|
||||
GCC="${GCC:-gcc}"
|
||||
GXX="${GXX:-g++}"
|
||||
OBJDUMP="${OBJDUMP:-objdump}"
|
||||
MACHINE="${MACHINE:-$(uname -m)}"
|
||||
testname=$(basename "$0" .sh)
|
||||
echo -n "Testing $testname ... "
|
||||
cd "$(dirname "$0")"/../..
|
||||
mold="$(pwd)/mold"
|
||||
t=out/test/elf/$testname
|
||||
mkdir -p $t
|
||||
|
||||
cat <<EOF | $CXX -c -o $t/a.o -g -xc++ -
|
||||
#include <iostream>
|
||||
struct Foo {
|
||||
Foo() { std::cout << "Hello world\n"; }
|
||||
};
|
||||
Foo x;
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CXX -c -o $t/b.o -g -xc++ -
|
||||
#include <iostream>
|
||||
struct Foo {
|
||||
Foo() { std::cout << "Hello world\n"; }
|
||||
};
|
||||
Foo y;
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CXX -o $t/c.o -c -xc++ -g -
|
||||
int main() {}
|
||||
EOF
|
||||
|
||||
$CXX -B. -o $t/exe $t/a.o $t/b.o $t/c.o -g
|
||||
$QEMU $t/exe | grep -q 'Hello world'
|
||||
|
||||
dwarfdump $t/exe | fgrep -q 'range entry 0x00000001 0x00000001'
|
||||
|
||||
echo OK
|
Loading…
Reference in New Issue
Block a user