diff options
author | Tom de Vries <tdevries@suse.de> | 2024-09-24 10:50:44 +0200 |
---|---|---|
committer | Tom de Vries <tdevries@suse.de> | 2024-09-24 10:50:44 +0200 |
commit | 6848938272157eb6532c189d6fcebec9d2dc33e8 (patch) | |
tree | 27b005aaa15b1f62644dee212bab724f5d8d091f /gdb/dwarf2 | |
parent | 510ecbcdfbf3c90761eb9f1d08d63a84999a8b9b (diff) | |
download | gdb-6848938272157eb6532c189d6fcebec9d2dc33e8.zip gdb-6848938272157eb6532c189d6fcebec9d2dc33e8.tar.gz gdb-6848938272157eb6532c189d6fcebec9d2dc33e8.tar.bz2 |
[gdb/symtab] Fix segfault on invalid debug info
While looking at PR symtab/31478 (a problem in the cooked indexer with invalid
dwarf) it occurred to me that I could trigger a similar problem using:
...
Compilation Unit @ offset 0xb2:
Length: 0x1f (32-bit)
Version: 4
Abbrev Offset: 0x6c
Pointer Size: 8
<0><bd>: Abbrev Number: 1 (DW_TAG_compile_unit)
<be> DW_AT_language : 2 (non-ANSI C)
<1><bf>: Abbrev Number: 2 (DW_TAG_subprogram)
<c0> DW_AT_low_pc : 0x4004a7
<c8> DW_AT_high_pc : 0x4004b2
<d0> DW_AT_specification: <0xd5>
<1><d4>: Abbrev Number: 0
Compilation Unit @ offset 0xd5:
Length: 0x7 (32-bit)
Version: 4
Abbrev Offset: 0x7f
Pointer Size: 8
...
and indeed I get:
...
$ gdb -q -batch outputs/gdb.dwarf2/dw2-inter-cu-error-2/dw2-inter-cu-error-2
Fatal signal: Segmentation fault
...
The problem is that we're calling prepare_one_comp_unit with cu == nullptr and
comp_unit_die == nullptr here in cooked_indexer::ensure_cu_exists:
...
cutu_reader new_reader (per_cu, per_objfile, nullptr, nullptr, false,
m_index_storage->get_abbrev_cache ());
prepare_one_comp_unit (new_reader.cu, new_reader.comp_unit_die,
language_minimal);
...
Fix this by bailing out for various types of dummy CUs:
...
if (new_reader.dummy_p || new_reader.comp_unit_die == nullptr
|| !new_reader.comp_unit_die->has_children)
return nullptr;
...
Also make sure in scan_attributes that this triggers a dwarf error:
...
$ gdb -q -batch dw2-inter-cu-error-2
DWARF Error: cannot follow reference to DIE at 0xd5 \
[in module dw2-inter-cu-error-2]
...
With target board readnow, the test-case triggers an assertion failure in
follow_die_offset, so fix this by throwing the same dwarf error.
While we're at it, make the other check for dummy CUs in
cooked_indexer::ensure_cu_exists more robust by adding an intermediate test
for comp_unit_die:
...
- if (result->dummy_p || !result->comp_unit_die->has_children)
+ if (result->dummy_p || result->comp_unit_die == nullptr
+ || !result->comp_unit_die->has_children)
return nullptr;
...
Tested on x86_64-linux.
Approved-By: Tom Tromey <tom@tromey.com>
Diffstat (limited to 'gdb/dwarf2')
-rw-r--r-- | gdb/dwarf2/read.c | 92 |
1 files changed, 53 insertions, 39 deletions
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index ca27391..193a52e 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -16078,6 +16078,10 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader, cutu_reader new_reader (per_cu, per_objfile, nullptr, nullptr, false, m_index_storage->get_abbrev_cache ()); + if (new_reader.dummy_p || new_reader.comp_unit_die == nullptr + || !new_reader.comp_unit_die->has_children) + return nullptr; + prepare_one_comp_unit (new_reader.cu, new_reader.comp_unit_die, language_minimal); std::unique_ptr<cutu_reader> copy @@ -16085,7 +16089,8 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader, result = m_index_storage->preserve (std::move (copy)); } - if (result->dummy_p || !result->comp_unit_die->has_children) + if (result->dummy_p || result->comp_unit_die == nullptr + || !result->comp_unit_die->has_children) return nullptr; if (for_scanning) @@ -16271,49 +16276,53 @@ cooked_indexer::scan_attributes (dwarf2_per_cu_data *scanning_per_cu, cutu_reader *new_reader = ensure_cu_exists (reader, reader->cu->per_objfile, origin_offset, origin_is_dwz, false); - if (new_reader != nullptr) - { - const gdb_byte *new_info_ptr = (new_reader->buffer - + to_underlying (origin_offset)); + if (new_reader == nullptr) + error (_(DWARF_ERROR_PREFIX + "cannot follow reference to DIE at %s" + " [in module %s]"), + sect_offset_str (origin_offset), + bfd_get_filename (reader->abfd)); - if (*parent_entry == nullptr) - { - /* We only perform immediate lookups of parents for DIEs - from earlier in this CU. This avoids any problem - with a NULL result when when we see a reference to a - DIE in another CU that we may or may not have - imported locally. */ - parent_map::addr_type addr - = parent_map::form_addr (origin_offset, origin_is_dwz); - if (new_reader->cu != reader->cu || new_info_ptr > watermark_ptr) - *maybe_defer = addr; - else - *parent_entry = m_die_range_map->find (addr); - } + const gdb_byte *new_info_ptr = (new_reader->buffer + + to_underlying (origin_offset)); - unsigned int bytes_read; - const abbrev_info *new_abbrev = peek_die_abbrev (*new_reader, - new_info_ptr, - &bytes_read); + if (*parent_entry == nullptr) + { + /* We only perform immediate lookups of parents for DIEs + from earlier in this CU. This avoids any problem + with a NULL result when when we see a reference to a + DIE in another CU that we may or may not have + imported locally. */ + parent_map::addr_type addr + = parent_map::form_addr (origin_offset, origin_is_dwz); + if (new_reader->cu != reader->cu || new_info_ptr > watermark_ptr) + *maybe_defer = addr; + else + *parent_entry = m_die_range_map->find (addr); + } - if (new_abbrev == nullptr) - error (_(DWARF_ERROR_PREFIX - "Unexpected null DIE at offset %s [in module %s]"), - sect_offset_str (origin_offset), - bfd_get_filename (new_reader->abfd)); + unsigned int bytes_read; + const abbrev_info *new_abbrev = peek_die_abbrev (*new_reader, + new_info_ptr, + &bytes_read); - new_info_ptr += bytes_read; + if (new_abbrev == nullptr) + error (_(DWARF_ERROR_PREFIX + "Unexpected null DIE at offset %s [in module %s]"), + sect_offset_str (origin_offset), + bfd_get_filename (new_reader->abfd)); - if (new_reader->cu == reader->cu && new_info_ptr == watermark_ptr) - { - /* Self-reference, we're done. */ - } - else - scan_attributes (scanning_per_cu, new_reader, new_info_ptr, - new_info_ptr, new_abbrev, name, linkage_name, - flags, nullptr, parent_entry, maybe_defer, - is_enum_class, true); + new_info_ptr += bytes_read; + + if (new_reader->cu == reader->cu && new_info_ptr == watermark_ptr) + { + /* Self-reference, we're done. */ } + else + scan_attributes (scanning_per_cu, new_reader, new_info_ptr, + new_info_ptr, new_abbrev, name, linkage_name, + flags, nullptr, parent_entry, maybe_defer, + is_enum_class, true); } if (!for_specification) @@ -20415,7 +20424,12 @@ follow_die_offset (sect_offset sect_off, int offset_in_dwz, false, cu->lang ()); target_cu = per_objfile->get_cu (per_cu); - gdb_assert (target_cu != nullptr); + if (target_cu == nullptr) + error (_(DWARF_ERROR_PREFIX + "cannot follow reference to DIE at %s" + " [in module %s]"), + sect_offset_str (sect_off), + objfile_name (per_objfile->objfile)); } else if (cu->dies == NULL) { |