aboutsummaryrefslogtreecommitdiff
path: root/gdb/dwarf2
diff options
context:
space:
mode:
authorTom de Vries <tdevries@suse.de>2024-09-24 10:50:44 +0200
committerTom de Vries <tdevries@suse.de>2024-09-24 10:50:44 +0200
commit6848938272157eb6532c189d6fcebec9d2dc33e8 (patch)
tree27b005aaa15b1f62644dee212bab724f5d8d091f /gdb/dwarf2
parent510ecbcdfbf3c90761eb9f1d08d63a84999a8b9b (diff)
downloadgdb-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.c92
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)
{