diff --git a/elf/output-chunks.cc b/elf/output-chunks.cc index 64b598f6..ac5b7b1d 100644 --- a/elf/output-chunks.cc +++ b/elf/output-chunks.cc @@ -2125,6 +2125,8 @@ template void GdbIndexSection::construct(Context &ctx) { Timer t(ctx, "GdbIndexSection::construct"); + std::atomic_bool has_debug_info = false; + // Read debug sections tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) { if (file->debug_info) { @@ -2133,9 +2135,13 @@ void GdbIndexSection::construct(Context &ctx) { // Count the number of address areas contained in this file. file->num_areas = estimate_address_areas(ctx, *file); + has_debug_info = true; } }); + if (!has_debug_info) + return; + // Initialize `area_offset` and `compunits_idx`. for (i64 i = 0; i < ctx.objs.size() - 1; i++) { ctx.objs[i + 1]->area_offset = @@ -2325,6 +2331,10 @@ void GdbIndexSection::copy_buf(Context &ctx) { template void GdbIndexSection::write_address_areas(Context &ctx) { Timer t(ctx, "GdbIndexSection::write_address_areas"); + + if (this->shdr.sh_size == 0) + return; + u8 *base = ctx.buf + this->shdr.sh_offset; for (Chunk *chunk : ctx.chunks) { @@ -2341,6 +2351,9 @@ void GdbIndexSection::write_address_areas(Context &ctx) { ctx.debug_rnglists = chunk; } + assert(ctx.debug_info); + assert(ctx.debug_abbrev); + struct Entry { ul64 start; ul64 end; @@ -2349,33 +2362,32 @@ void GdbIndexSection::write_address_areas(Context &ctx) { // Read address ranges from debug sections and copy them to .gdb_index. tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) { + if (!file->debug_info) + return; + Entry *begin = (Entry *)(base + header.areas_offset + file->area_offset); Entry *e = begin; + u64 offset = file->debug_info->offset; - if (file->debug_info && ctx.debug_abbrev) { + for (i64 i = 0; i < file->compunits.size(); i++) { + std::vector addrs = read_address_areas(ctx, *file, offset); - u64 offset = file->debug_info->offset; + for (i64 j = 0; j < addrs.size(); j += 2) { + // Skip an empty range + if (addrs[j] == addrs[j + 1]) + continue; - for (i64 i = 0; i < file->compunits.size(); i++) { - std::vector addrs = read_address_areas(ctx, *file, offset); + // Gdb crashes if there are entries with address 0. + if (addrs[j] == 0) + continue; - for (i64 j = 0; j < addrs.size(); j += 2) { - // Skip an empty range - if (addrs[j] == addrs[j + 1]) - continue; - - // Gdb crashes if there are entries with address 0. - if (addrs[j] == 0) - continue; - - assert(e < begin + file->num_areas); - e->start = addrs[j]; - e->end = addrs[j + 1]; - e->attr = file->compunits_idx + i; - e++; - } - offset += file->compunits[i].size(); + assert(e < begin + file->num_areas); + e->start = addrs[j]; + e->end = addrs[j + 1]; + e->attr = file->compunits_idx + i; + e++; } + offset += file->compunits[i].size(); } // Fill trailing null entries with dummy values because gdb diff --git a/test/elf/gdb-index-empty.sh b/test/elf/gdb-index-empty.sh new file mode 100755 index 00000000..a866e4f2 --- /dev/null +++ b/test/elf/gdb-index-empty.sh @@ -0,0 +1,21 @@ +#!/bin/bash +export LC_ALL=C +set -e +CC="${TEST_CC:-cc}" +CXX="${TEST_CXX:-c++}" +GCC="${TEST_GCC:-gcc}" +GXX="${TEST_GXX:-g++}" +OBJDUMP="${OBJDUMP:-objdump}" +MACHINE="${MACHINE:-$(uname -m)}" +testname=$(basename "$0" .sh) +echo -n "Testing $testname ... " +cd "$(dirname "$0")"/../.. +t=out/test/elf/$testname +mkdir -p $t + +echo 'void _start() {}' | $CC -c -o $t/a.o -xc - +./mold -o $t/exe $t/a.o -gdb-index +readelf -WS $t/exe > $t/log +! fgrep -q .gdb_index $t/log || false + +echo OK