mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
91fc201ed4
dwarf2_per_objfile::adjust applies gdbarch_adjust_dwarf2_addr to an address, leaving the result unrelocated. However, this adjustment is only needed for text-section symbols -- it isn't needed for any sort of address mapping. Therefore, these calls can be removed from read_addrmap_from_aranges and create_addrmap_from_gdb_index. Approved-By: Andrew Burgess <aburgess@redhat.com>
201 lines
6.6 KiB
C
201 lines
6.6 KiB
C
/* DWARF aranges handling
|
|
|
|
Copyright (C) 1994-2024 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "dwarf2/aranges.h"
|
|
#include "dwarf2/read.h"
|
|
|
|
/* See aranges.h. */
|
|
|
|
bool
|
|
read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
|
|
dwarf2_section_info *section,
|
|
addrmap_mutable *mutable_map,
|
|
deferred_warnings *warn)
|
|
{
|
|
/* Caller must ensure that the section has already been read. */
|
|
gdb_assert (section->readin);
|
|
if (section->empty ())
|
|
return false;
|
|
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
bfd *abfd = objfile->obfd.get ();
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
|
|
|
std::unordered_map<sect_offset,
|
|
dwarf2_per_cu_data *,
|
|
gdb::hash_enum<sect_offset>>
|
|
debug_info_offset_to_per_cu;
|
|
for (const auto &per_cu : per_bfd->all_units)
|
|
{
|
|
/* A TU will not need aranges, and skipping them here is an easy
|
|
way of ignoring .debug_types -- and possibly seeing a
|
|
duplicate section offset -- entirely. The same applies to
|
|
units coming from a dwz file. */
|
|
if (per_cu->is_debug_types || per_cu->is_dwz)
|
|
continue;
|
|
|
|
const auto insertpair
|
|
= debug_info_offset_to_per_cu.emplace (per_cu->sect_off,
|
|
per_cu.get ());
|
|
|
|
/* Assume no duplicate offsets in all_units. */
|
|
gdb_assert (insertpair.second);
|
|
}
|
|
|
|
std::set<sect_offset> debug_info_offset_seen;
|
|
const bfd_endian dwarf5_byte_order = gdbarch_byte_order (gdbarch);
|
|
const gdb_byte *addr = section->buffer;
|
|
while (addr < section->buffer + section->size)
|
|
{
|
|
const gdb_byte *const entry_addr = addr;
|
|
unsigned int bytes_read;
|
|
|
|
const LONGEST entry_length = read_initial_length (abfd, addr,
|
|
&bytes_read);
|
|
addr += bytes_read;
|
|
|
|
const gdb_byte *const entry_end = addr + entry_length;
|
|
const bool dwarf5_is_dwarf64 = bytes_read != 4;
|
|
const uint8_t offset_size = dwarf5_is_dwarf64 ? 8 : 4;
|
|
if (addr + entry_length > section->buffer + section->size)
|
|
{
|
|
warn->warn (_("Section .debug_aranges in %s entry at offset %s "
|
|
"length %s exceeds section length %s, "
|
|
"ignoring .debug_aranges."),
|
|
objfile_name (objfile),
|
|
plongest (entry_addr - section->buffer),
|
|
plongest (bytes_read + entry_length),
|
|
pulongest (section->size));
|
|
return false;
|
|
}
|
|
|
|
/* The version number. */
|
|
const uint16_t version = read_2_bytes (abfd, addr);
|
|
addr += 2;
|
|
if (version != 2)
|
|
{
|
|
warn->warn
|
|
(_("Section .debug_aranges in %s entry at offset %s "
|
|
"has unsupported version %d, ignoring .debug_aranges."),
|
|
objfile_name (objfile),
|
|
plongest (entry_addr - section->buffer), version);
|
|
return false;
|
|
}
|
|
|
|
const uint64_t debug_info_offset
|
|
= extract_unsigned_integer (addr, offset_size, dwarf5_byte_order);
|
|
addr += offset_size;
|
|
const auto per_cu_it
|
|
= debug_info_offset_to_per_cu.find (sect_offset (debug_info_offset));
|
|
if (per_cu_it == debug_info_offset_to_per_cu.cend ())
|
|
{
|
|
warn->warn (_("Section .debug_aranges in %s entry at offset %s "
|
|
"debug_info_offset %s does not exists, "
|
|
"ignoring .debug_aranges."),
|
|
objfile_name (objfile),
|
|
plongest (entry_addr - section->buffer),
|
|
pulongest (debug_info_offset));
|
|
return false;
|
|
}
|
|
const auto insertpair
|
|
= debug_info_offset_seen.insert (sect_offset (debug_info_offset));
|
|
if (!insertpair.second)
|
|
{
|
|
warn->warn (_("Section .debug_aranges in %s has duplicate "
|
|
"debug_info_offset %s, ignoring .debug_aranges."),
|
|
objfile_name (objfile),
|
|
sect_offset_str (sect_offset (debug_info_offset)));
|
|
return false;
|
|
}
|
|
dwarf2_per_cu_data *const per_cu = per_cu_it->second;
|
|
|
|
const uint8_t address_size = *addr++;
|
|
if (address_size < 1 || address_size > 8)
|
|
{
|
|
warn->warn
|
|
(_("Section .debug_aranges in %s entry at offset %s "
|
|
"address_size %u is invalid, ignoring .debug_aranges."),
|
|
objfile_name (objfile),
|
|
plongest (entry_addr - section->buffer), address_size);
|
|
return false;
|
|
}
|
|
|
|
const uint8_t segment_selector_size = *addr++;
|
|
if (segment_selector_size != 0)
|
|
{
|
|
warn->warn (_("Section .debug_aranges in %s entry at offset %s "
|
|
"segment_selector_size %u is not supported, "
|
|
"ignoring .debug_aranges."),
|
|
objfile_name (objfile),
|
|
plongest (entry_addr - section->buffer),
|
|
segment_selector_size);
|
|
return false;
|
|
}
|
|
|
|
/* Must pad to an alignment boundary that is twice the address
|
|
size. It is undocumented by the DWARF standard but GCC does
|
|
use it. However, not every compiler does this. We can see
|
|
whether it has happened by looking at the total length of the
|
|
contents of the aranges for this CU -- it if isn't a multiple
|
|
of twice the address size, then we skip any leftover
|
|
bytes. */
|
|
addr += (entry_end - addr) % (2 * address_size);
|
|
|
|
while (addr < entry_end)
|
|
{
|
|
if (addr + 2 * address_size > entry_end)
|
|
{
|
|
warn->warn (_("Section .debug_aranges in %s entry at offset %s "
|
|
"address list is not properly terminated, "
|
|
"ignoring .debug_aranges."),
|
|
objfile_name (objfile),
|
|
plongest (entry_addr - section->buffer));
|
|
return false;
|
|
}
|
|
ULONGEST start = extract_unsigned_integer (addr, address_size,
|
|
dwarf5_byte_order);
|
|
addr += address_size;
|
|
ULONGEST length = extract_unsigned_integer (addr, address_size,
|
|
dwarf5_byte_order);
|
|
addr += address_size;
|
|
if (start == 0 && length == 0)
|
|
{
|
|
/* This can happen on some targets with --gc-sections.
|
|
This pair of values is also used to mark the end of
|
|
the entries for a given CU, but we ignore it and
|
|
instead handle termination using the check at the top
|
|
of the loop. */
|
|
continue;
|
|
}
|
|
if (start == 0 && !per_bfd->has_section_at_zero)
|
|
{
|
|
/* Symbol was eliminated due to a COMDAT group. */
|
|
continue;
|
|
}
|
|
ULONGEST end = start + length;
|
|
mutable_map->set_empty (start, end - 1, per_cu);
|
|
}
|
|
|
|
per_cu->addresses_seen = true;
|
|
}
|
|
|
|
return true;
|
|
}
|