mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
2ffd1d6e42
Move everything related to reading .debug_names from read.c to read-debug-names.c. The only entry point exposed by read-debug-names.{c,h} is dwarf2_read_debug_names. Change-Id: I18b23f3c7a61b14abc3a46e4bf559bc2d078e8bc Approved-By: Tom Tromey <tom@tromey.com>
1053 lines
29 KiB
C
1053 lines
29 KiB
C
/* Reading code for .debug_names
|
|
|
|
Copyright (C) 2023 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 "defs.h"
|
|
#include "read-debug-names.h"
|
|
|
|
#include "complaints.h"
|
|
#include "cp-support.h"
|
|
#include "dwz.h"
|
|
#include "mapped-index.h"
|
|
#include "read.h"
|
|
#include "stringify.h"
|
|
|
|
/* A description of the mapped .debug_names.
|
|
Uninitialized map has CU_COUNT 0. */
|
|
|
|
struct mapped_debug_names final : public mapped_index_base
|
|
{
|
|
bfd_endian dwarf5_byte_order;
|
|
bool dwarf5_is_dwarf64;
|
|
bool augmentation_is_gdb;
|
|
uint8_t offset_size;
|
|
uint32_t cu_count = 0;
|
|
uint32_t tu_count, bucket_count, name_count;
|
|
const gdb_byte *cu_table_reordered, *tu_table_reordered;
|
|
const uint32_t *bucket_table_reordered, *hash_table_reordered;
|
|
const gdb_byte *name_table_string_offs_reordered;
|
|
const gdb_byte *name_table_entry_offs_reordered;
|
|
const gdb_byte *entry_pool;
|
|
|
|
struct index_val
|
|
{
|
|
ULONGEST dwarf_tag;
|
|
struct attr
|
|
{
|
|
/* Attribute name DW_IDX_*. */
|
|
ULONGEST dw_idx;
|
|
|
|
/* Attribute form DW_FORM_*. */
|
|
ULONGEST form;
|
|
|
|
/* Value if FORM is DW_FORM_implicit_const. */
|
|
LONGEST implicit_const;
|
|
};
|
|
std::vector<attr> attr_vec;
|
|
};
|
|
|
|
std::unordered_map<ULONGEST, index_val> abbrev_map;
|
|
|
|
const char *namei_to_name
|
|
(uint32_t namei, dwarf2_per_objfile *per_objfile) const;
|
|
|
|
/* Implementation of the mapped_index_base virtual interface, for
|
|
the name_components cache. */
|
|
|
|
const char *symbol_name_at
|
|
(offset_type idx, dwarf2_per_objfile *per_objfile) const override
|
|
{ return namei_to_name (idx, per_objfile); }
|
|
|
|
size_t symbol_name_count () const override
|
|
{ return this->name_count; }
|
|
|
|
quick_symbol_functions_up make_quick_functions () const override;
|
|
};
|
|
|
|
struct dwarf2_debug_names_index : public dwarf2_base_index_functions
|
|
{
|
|
void dump (struct objfile *objfile) override;
|
|
|
|
void expand_matching_symbols
|
|
(struct objfile *,
|
|
const lookup_name_info &lookup_name,
|
|
domain_enum domain,
|
|
int global,
|
|
symbol_compare_ftype *ordered_compare) override;
|
|
|
|
bool expand_symtabs_matching
|
|
(struct objfile *objfile,
|
|
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
|
const lookup_name_info *lookup_name,
|
|
gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
|
|
gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
|
|
block_search_flags search_flags,
|
|
domain_enum domain,
|
|
enum search_domain kind) override;
|
|
};
|
|
|
|
quick_symbol_functions_up
|
|
mapped_debug_names::make_quick_functions () const
|
|
{
|
|
return quick_symbol_functions_up (new dwarf2_debug_names_index);
|
|
}
|
|
|
|
/* Create the signatured type hash table from .debug_names. */
|
|
|
|
static void
|
|
create_signatured_type_table_from_debug_names
|
|
(dwarf2_per_objfile *per_objfile,
|
|
const mapped_debug_names &map,
|
|
struct dwarf2_section_info *section,
|
|
struct dwarf2_section_info *abbrev_section)
|
|
{
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
|
|
section->read (objfile);
|
|
abbrev_section->read (objfile);
|
|
|
|
htab_up sig_types_hash = allocate_signatured_type_table ();
|
|
|
|
for (uint32_t i = 0; i < map.tu_count; ++i)
|
|
{
|
|
signatured_type_up sig_type;
|
|
void **slot;
|
|
|
|
sect_offset sect_off
|
|
= (sect_offset) (extract_unsigned_integer
|
|
(map.tu_table_reordered + i * map.offset_size,
|
|
map.offset_size,
|
|
map.dwarf5_byte_order));
|
|
|
|
comp_unit_head cu_header;
|
|
read_and_check_comp_unit_head (per_objfile, &cu_header, section,
|
|
abbrev_section,
|
|
section->buffer + to_underlying (sect_off),
|
|
rcuh_kind::TYPE);
|
|
|
|
sig_type = per_objfile->per_bfd->allocate_signatured_type
|
|
(cu_header.signature);
|
|
sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu;
|
|
sig_type->section = section;
|
|
sig_type->sect_off = sect_off;
|
|
|
|
slot = htab_find_slot (sig_types_hash.get (), sig_type.get (), INSERT);
|
|
*slot = sig_type.get ();
|
|
|
|
per_objfile->per_bfd->all_units.emplace_back (sig_type.release ());
|
|
}
|
|
|
|
per_objfile->per_bfd->signatured_types = std::move (sig_types_hash);
|
|
}
|
|
|
|
/* Read the address map data from DWARF-5 .debug_aranges, and use it to
|
|
populate the index_addrmap. */
|
|
|
|
static void
|
|
create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
|
|
struct dwarf2_section_info *section)
|
|
{
|
|
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
|
|
|
addrmap_mutable mutable_map;
|
|
|
|
if (read_addrmap_from_aranges (per_objfile, section, &mutable_map))
|
|
per_bfd->index_addrmap
|
|
= new (&per_bfd->obstack) addrmap_fixed (&per_bfd->obstack,
|
|
&mutable_map);
|
|
}
|
|
|
|
/* DWARF-5 debug_names reader. */
|
|
|
|
/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension. */
|
|
static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 };
|
|
|
|
/* A helper function that reads the .debug_names section in SECTION
|
|
and fills in MAP. FILENAME is the name of the file containing the
|
|
section; it is used for error reporting.
|
|
|
|
Returns true if all went well, false otherwise. */
|
|
|
|
static bool
|
|
read_debug_names_from_section (struct objfile *objfile,
|
|
const char *filename,
|
|
struct dwarf2_section_info *section,
|
|
mapped_debug_names &map)
|
|
{
|
|
if (section->empty ())
|
|
return false;
|
|
|
|
/* Older elfutils strip versions could keep the section in the main
|
|
executable while splitting it for the separate debug info file. */
|
|
if ((section->get_flags () & SEC_HAS_CONTENTS) == 0)
|
|
return false;
|
|
|
|
section->read (objfile);
|
|
|
|
map.dwarf5_byte_order = gdbarch_byte_order (objfile->arch ());
|
|
|
|
const gdb_byte *addr = section->buffer;
|
|
|
|
bfd *const abfd = section->get_bfd_owner ();
|
|
|
|
unsigned int bytes_read;
|
|
LONGEST length = read_initial_length (abfd, addr, &bytes_read);
|
|
addr += bytes_read;
|
|
|
|
map.dwarf5_is_dwarf64 = bytes_read != 4;
|
|
map.offset_size = map.dwarf5_is_dwarf64 ? 8 : 4;
|
|
if (bytes_read + length != section->size)
|
|
{
|
|
/* There may be multiple per-CU indices. */
|
|
warning (_("Section .debug_names in %s length %s does not match "
|
|
"section length %s, ignoring .debug_names."),
|
|
filename, plongest (bytes_read + length),
|
|
pulongest (section->size));
|
|
return false;
|
|
}
|
|
|
|
/* The version number. */
|
|
uint16_t version = read_2_bytes (abfd, addr);
|
|
addr += 2;
|
|
if (version != 5)
|
|
{
|
|
warning (_("Section .debug_names in %s has unsupported version %d, "
|
|
"ignoring .debug_names."),
|
|
filename, version);
|
|
return false;
|
|
}
|
|
|
|
/* Padding. */
|
|
uint16_t padding = read_2_bytes (abfd, addr);
|
|
addr += 2;
|
|
if (padding != 0)
|
|
{
|
|
warning (_("Section .debug_names in %s has unsupported padding %d, "
|
|
"ignoring .debug_names."),
|
|
filename, padding);
|
|
return false;
|
|
}
|
|
|
|
/* comp_unit_count - The number of CUs in the CU list. */
|
|
map.cu_count = read_4_bytes (abfd, addr);
|
|
addr += 4;
|
|
|
|
/* local_type_unit_count - The number of TUs in the local TU
|
|
list. */
|
|
map.tu_count = read_4_bytes (abfd, addr);
|
|
addr += 4;
|
|
|
|
/* foreign_type_unit_count - The number of TUs in the foreign TU
|
|
list. */
|
|
uint32_t foreign_tu_count = read_4_bytes (abfd, addr);
|
|
addr += 4;
|
|
if (foreign_tu_count != 0)
|
|
{
|
|
warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, "
|
|
"ignoring .debug_names."),
|
|
filename, static_cast<unsigned long> (foreign_tu_count));
|
|
return false;
|
|
}
|
|
|
|
/* bucket_count - The number of hash buckets in the hash lookup
|
|
table. */
|
|
map.bucket_count = read_4_bytes (abfd, addr);
|
|
addr += 4;
|
|
|
|
/* name_count - The number of unique names in the index. */
|
|
map.name_count = read_4_bytes (abfd, addr);
|
|
addr += 4;
|
|
|
|
/* abbrev_table_size - The size in bytes of the abbreviations
|
|
table. */
|
|
uint32_t abbrev_table_size = read_4_bytes (abfd, addr);
|
|
addr += 4;
|
|
|
|
/* augmentation_string_size - The size in bytes of the augmentation
|
|
string. This value is rounded up to a multiple of 4. */
|
|
uint32_t augmentation_string_size = read_4_bytes (abfd, addr);
|
|
addr += 4;
|
|
map.augmentation_is_gdb = ((augmentation_string_size
|
|
== sizeof (dwarf5_augmentation))
|
|
&& memcmp (addr, dwarf5_augmentation,
|
|
sizeof (dwarf5_augmentation)) == 0);
|
|
augmentation_string_size += (-augmentation_string_size) & 3;
|
|
addr += augmentation_string_size;
|
|
|
|
/* List of CUs */
|
|
map.cu_table_reordered = addr;
|
|
addr += map.cu_count * map.offset_size;
|
|
|
|
/* List of Local TUs */
|
|
map.tu_table_reordered = addr;
|
|
addr += map.tu_count * map.offset_size;
|
|
|
|
/* Hash Lookup Table */
|
|
map.bucket_table_reordered = reinterpret_cast<const uint32_t *> (addr);
|
|
addr += map.bucket_count * 4;
|
|
map.hash_table_reordered = reinterpret_cast<const uint32_t *> (addr);
|
|
addr += map.name_count * 4;
|
|
|
|
/* Name Table */
|
|
map.name_table_string_offs_reordered = addr;
|
|
addr += map.name_count * map.offset_size;
|
|
map.name_table_entry_offs_reordered = addr;
|
|
addr += map.name_count * map.offset_size;
|
|
|
|
const gdb_byte *abbrev_table_start = addr;
|
|
for (;;)
|
|
{
|
|
const ULONGEST index_num = read_unsigned_leb128 (abfd, addr, &bytes_read);
|
|
addr += bytes_read;
|
|
if (index_num == 0)
|
|
break;
|
|
|
|
const auto insertpair
|
|
= map.abbrev_map.emplace (index_num, mapped_debug_names::index_val ());
|
|
if (!insertpair.second)
|
|
{
|
|
warning (_("Section .debug_names in %s has duplicate index %s, "
|
|
"ignoring .debug_names."),
|
|
filename, pulongest (index_num));
|
|
return false;
|
|
}
|
|
mapped_debug_names::index_val &indexval = insertpair.first->second;
|
|
indexval.dwarf_tag = read_unsigned_leb128 (abfd, addr, &bytes_read);
|
|
addr += bytes_read;
|
|
|
|
for (;;)
|
|
{
|
|
mapped_debug_names::index_val::attr attr;
|
|
attr.dw_idx = read_unsigned_leb128 (abfd, addr, &bytes_read);
|
|
addr += bytes_read;
|
|
attr.form = read_unsigned_leb128 (abfd, addr, &bytes_read);
|
|
addr += bytes_read;
|
|
if (attr.form == DW_FORM_implicit_const)
|
|
{
|
|
attr.implicit_const = read_signed_leb128 (abfd, addr,
|
|
&bytes_read);
|
|
addr += bytes_read;
|
|
}
|
|
if (attr.dw_idx == 0 && attr.form == 0)
|
|
break;
|
|
indexval.attr_vec.push_back (std::move (attr));
|
|
}
|
|
}
|
|
if (addr != abbrev_table_start + abbrev_table_size)
|
|
{
|
|
warning (_("Section .debug_names in %s has abbreviation_table "
|
|
"of size %s vs. written as %u, ignoring .debug_names."),
|
|
filename, plongest (addr - abbrev_table_start),
|
|
abbrev_table_size);
|
|
return false;
|
|
}
|
|
map.entry_pool = addr;
|
|
|
|
return true;
|
|
}
|
|
|
|
/* A helper for create_cus_from_debug_names that handles the MAP's CU
|
|
list. */
|
|
|
|
static bool
|
|
create_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd,
|
|
const mapped_debug_names &map,
|
|
dwarf2_section_info §ion,
|
|
bool is_dwz)
|
|
{
|
|
if (!map.augmentation_is_gdb)
|
|
{
|
|
for (uint32_t i = 0; i < map.cu_count; ++i)
|
|
{
|
|
sect_offset sect_off
|
|
= (sect_offset) (extract_unsigned_integer
|
|
(map.cu_table_reordered + i * map.offset_size,
|
|
map.offset_size,
|
|
map.dwarf5_byte_order));
|
|
/* We don't know the length of the CU, because the CU list in a
|
|
.debug_names index can be incomplete, so we can't use the start
|
|
of the next CU as end of this CU. We create the CUs here with
|
|
length 0, and in cutu_reader::cutu_reader we'll fill in the
|
|
actual length. */
|
|
dwarf2_per_cu_data_up per_cu
|
|
= create_cu_from_index_list (per_bfd, §ion, is_dwz,
|
|
sect_off, 0);
|
|
per_bfd->all_units.push_back (std::move (per_cu));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
sect_offset sect_off_prev;
|
|
for (uint32_t i = 0; i <= map.cu_count; ++i)
|
|
{
|
|
sect_offset sect_off_next;
|
|
if (i < map.cu_count)
|
|
{
|
|
sect_off_next
|
|
= (sect_offset) (extract_unsigned_integer
|
|
(map.cu_table_reordered + i * map.offset_size,
|
|
map.offset_size,
|
|
map.dwarf5_byte_order));
|
|
}
|
|
else
|
|
sect_off_next = (sect_offset) section.size;
|
|
if (i >= 1)
|
|
{
|
|
if (sect_off_next == sect_off_prev)
|
|
{
|
|
warning (_("Section .debug_names has duplicate entry in CU table,"
|
|
" ignoring .debug_names."));
|
|
return false;
|
|
}
|
|
if (sect_off_next < sect_off_prev)
|
|
{
|
|
warning (_("Section .debug_names has non-ascending CU table,"
|
|
" ignoring .debug_names."));
|
|
return false;
|
|
}
|
|
/* Note: we're not using length = sect_off_next - sect_off_prev,
|
|
to gracefully handle an incomplete CU list. */
|
|
const ULONGEST length = 0;
|
|
dwarf2_per_cu_data_up per_cu
|
|
= create_cu_from_index_list (per_bfd, §ion, is_dwz,
|
|
sect_off_prev, length);
|
|
per_bfd->all_units.push_back (std::move (per_cu));
|
|
}
|
|
sect_off_prev = sect_off_next;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Read the CU list from the mapped index, and use it to create all
|
|
the CU objects for this dwarf2_per_objfile. */
|
|
|
|
static bool
|
|
create_cus_from_debug_names (dwarf2_per_bfd *per_bfd,
|
|
const mapped_debug_names &map,
|
|
const mapped_debug_names &dwz_map)
|
|
{
|
|
gdb_assert (per_bfd->all_units.empty ());
|
|
per_bfd->all_units.reserve (map.cu_count + dwz_map.cu_count);
|
|
|
|
if (!create_cus_from_debug_names_list (per_bfd, map, per_bfd->info,
|
|
false /* is_dwz */))
|
|
return false;
|
|
|
|
if (dwz_map.cu_count == 0)
|
|
return true;
|
|
|
|
dwz_file *dwz = dwarf2_get_dwz_file (per_bfd);
|
|
return create_cus_from_debug_names_list (per_bfd, dwz_map, dwz->info,
|
|
true /* is_dwz */);
|
|
}
|
|
|
|
/* See read-debug-names.h. */
|
|
|
|
bool
|
|
dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
std::unique_ptr<mapped_debug_names> map (new mapped_debug_names);
|
|
mapped_debug_names dwz_map;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
|
|
|
if (!read_debug_names_from_section (objfile, objfile_name (objfile),
|
|
&per_bfd->debug_names, *map))
|
|
return false;
|
|
|
|
/* Don't use the index if it's empty. */
|
|
if (map->name_count == 0)
|
|
return false;
|
|
|
|
/* If there is a .dwz file, read it so we can get its CU list as
|
|
well. */
|
|
dwz_file *dwz = dwarf2_get_dwz_file (per_bfd);
|
|
if (dwz != NULL)
|
|
{
|
|
if (!read_debug_names_from_section (objfile,
|
|
bfd_get_filename (dwz->dwz_bfd.get ()),
|
|
&dwz->debug_names, dwz_map))
|
|
{
|
|
warning (_("could not read '.debug_names' section from %s; skipping"),
|
|
bfd_get_filename (dwz->dwz_bfd.get ()));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!create_cus_from_debug_names (per_bfd, *map, dwz_map))
|
|
{
|
|
per_bfd->all_units.clear ();
|
|
return false;
|
|
}
|
|
|
|
if (map->tu_count != 0)
|
|
{
|
|
/* We can only handle a single .debug_types when we have an
|
|
index. */
|
|
if (per_bfd->types.size () > 1)
|
|
{
|
|
per_bfd->all_units.clear ();
|
|
return false;
|
|
}
|
|
|
|
dwarf2_section_info *section
|
|
= (per_bfd->types.size () == 1
|
|
? &per_bfd->types[0]
|
|
: &per_bfd->info);
|
|
|
|
create_signatured_type_table_from_debug_names
|
|
(per_objfile, *map, section, &per_bfd->abbrev);
|
|
}
|
|
|
|
finalize_all_units (per_bfd);
|
|
|
|
create_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges);
|
|
|
|
per_bfd->index_table = std::move (map);
|
|
per_bfd->quick_file_names_table =
|
|
create_quick_file_names_table (per_bfd->all_units.size ());
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Type used to manage iterating over all CUs looking for a symbol for
|
|
.debug_names. */
|
|
|
|
class dw2_debug_names_iterator
|
|
{
|
|
public:
|
|
dw2_debug_names_iterator (const mapped_debug_names &map,
|
|
block_search_flags block_index,
|
|
domain_enum domain,
|
|
const char *name, dwarf2_per_objfile *per_objfile)
|
|
: m_map (map), m_block_index (block_index), m_domain (domain),
|
|
m_addr (find_vec_in_debug_names (map, name, per_objfile)),
|
|
m_per_objfile (per_objfile)
|
|
{}
|
|
|
|
dw2_debug_names_iterator (const mapped_debug_names &map,
|
|
search_domain search, uint32_t namei,
|
|
dwarf2_per_objfile *per_objfile,
|
|
domain_enum domain = UNDEF_DOMAIN)
|
|
: m_map (map),
|
|
m_domain (domain),
|
|
m_search (search),
|
|
m_addr (find_vec_in_debug_names (map, namei, per_objfile)),
|
|
m_per_objfile (per_objfile)
|
|
{}
|
|
|
|
dw2_debug_names_iterator (const mapped_debug_names &map,
|
|
block_search_flags block_index, domain_enum domain,
|
|
uint32_t namei, dwarf2_per_objfile *per_objfile)
|
|
: m_map (map), m_block_index (block_index), m_domain (domain),
|
|
m_addr (find_vec_in_debug_names (map, namei, per_objfile)),
|
|
m_per_objfile (per_objfile)
|
|
{}
|
|
|
|
/* Return the next matching CU or NULL if there are no more. */
|
|
dwarf2_per_cu_data *next ();
|
|
|
|
private:
|
|
static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map,
|
|
const char *name,
|
|
dwarf2_per_objfile *per_objfile);
|
|
static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map,
|
|
uint32_t namei,
|
|
dwarf2_per_objfile *per_objfile);
|
|
|
|
/* The internalized form of .debug_names. */
|
|
const mapped_debug_names &m_map;
|
|
|
|
/* Restrict the search to these blocks. */
|
|
block_search_flags m_block_index = (SEARCH_GLOBAL_BLOCK
|
|
| SEARCH_STATIC_BLOCK);
|
|
|
|
/* The kind of symbol we're looking for. */
|
|
const domain_enum m_domain = UNDEF_DOMAIN;
|
|
const search_domain m_search = ALL_DOMAIN;
|
|
|
|
/* The list of CUs from the index entry of the symbol, or NULL if
|
|
not found. */
|
|
const gdb_byte *m_addr;
|
|
|
|
dwarf2_per_objfile *m_per_objfile;
|
|
};
|
|
|
|
const char *
|
|
mapped_debug_names::namei_to_name
|
|
(uint32_t namei, dwarf2_per_objfile *per_objfile) const
|
|
{
|
|
const ULONGEST namei_string_offs
|
|
= extract_unsigned_integer ((name_table_string_offs_reordered
|
|
+ namei * offset_size),
|
|
offset_size,
|
|
dwarf5_byte_order);
|
|
return read_indirect_string_at_offset (per_objfile, namei_string_offs);
|
|
}
|
|
|
|
/* Find a slot in .debug_names for the object named NAME. If NAME is
|
|
found, return pointer to its pool data. If NAME cannot be found,
|
|
return NULL. */
|
|
|
|
const gdb_byte *
|
|
dw2_debug_names_iterator::find_vec_in_debug_names
|
|
(const mapped_debug_names &map, const char *name,
|
|
dwarf2_per_objfile *per_objfile)
|
|
{
|
|
int (*cmp) (const char *, const char *);
|
|
|
|
gdb::unique_xmalloc_ptr<char> without_params;
|
|
if (current_language->la_language == language_cplus
|
|
|| current_language->la_language == language_fortran
|
|
|| current_language->la_language == language_d)
|
|
{
|
|
/* NAME is already canonical. Drop any qualifiers as
|
|
.debug_names does not contain any. */
|
|
|
|
if (strchr (name, '(') != NULL)
|
|
{
|
|
without_params = cp_remove_params (name);
|
|
if (without_params != NULL)
|
|
name = without_params.get ();
|
|
}
|
|
}
|
|
|
|
cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
|
|
|
|
const uint32_t full_hash = dwarf5_djb_hash (name);
|
|
uint32_t namei
|
|
= extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
|
|
(map.bucket_table_reordered
|
|
+ (full_hash % map.bucket_count)), 4,
|
|
map.dwarf5_byte_order);
|
|
if (namei == 0)
|
|
return NULL;
|
|
--namei;
|
|
if (namei >= map.name_count)
|
|
{
|
|
complaint (_("Wrong .debug_names with name index %u but name_count=%u "
|
|
"[in module %s]"),
|
|
namei, map.name_count,
|
|
objfile_name (per_objfile->objfile));
|
|
return NULL;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
const uint32_t namei_full_hash
|
|
= extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
|
|
(map.hash_table_reordered + namei), 4,
|
|
map.dwarf5_byte_order);
|
|
if (full_hash % map.bucket_count != namei_full_hash % map.bucket_count)
|
|
return NULL;
|
|
|
|
if (full_hash == namei_full_hash)
|
|
{
|
|
const char *const namei_string = map.namei_to_name (namei, per_objfile);
|
|
|
|
#if 0 /* An expensive sanity check. */
|
|
if (namei_full_hash != dwarf5_djb_hash (namei_string))
|
|
{
|
|
complaint (_("Wrong .debug_names hash for string at index %u "
|
|
"[in module %s]"),
|
|
namei, objfile_name (dwarf2_per_objfile->objfile));
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
if (cmp (namei_string, name) == 0)
|
|
{
|
|
const ULONGEST namei_entry_offs
|
|
= extract_unsigned_integer ((map.name_table_entry_offs_reordered
|
|
+ namei * map.offset_size),
|
|
map.offset_size, map.dwarf5_byte_order);
|
|
return map.entry_pool + namei_entry_offs;
|
|
}
|
|
}
|
|
|
|
++namei;
|
|
if (namei >= map.name_count)
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
const gdb_byte *
|
|
dw2_debug_names_iterator::find_vec_in_debug_names
|
|
(const mapped_debug_names &map, uint32_t namei, dwarf2_per_objfile *per_objfile)
|
|
{
|
|
if (namei >= map.name_count)
|
|
{
|
|
complaint (_("Wrong .debug_names with name index %u but name_count=%u "
|
|
"[in module %s]"),
|
|
namei, map.name_count,
|
|
objfile_name (per_objfile->objfile));
|
|
return NULL;
|
|
}
|
|
|
|
const ULONGEST namei_entry_offs
|
|
= extract_unsigned_integer ((map.name_table_entry_offs_reordered
|
|
+ namei * map.offset_size),
|
|
map.offset_size, map.dwarf5_byte_order);
|
|
return map.entry_pool + namei_entry_offs;
|
|
}
|
|
|
|
/* See dw2_debug_names_iterator. */
|
|
|
|
dwarf2_per_cu_data *
|
|
dw2_debug_names_iterator::next ()
|
|
{
|
|
if (m_addr == NULL)
|
|
return NULL;
|
|
|
|
dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
|
|
struct objfile *objfile = m_per_objfile->objfile;
|
|
bfd *const abfd = objfile->obfd.get ();
|
|
|
|
again:
|
|
|
|
unsigned int bytes_read;
|
|
const ULONGEST abbrev = read_unsigned_leb128 (abfd, m_addr, &bytes_read);
|
|
m_addr += bytes_read;
|
|
if (abbrev == 0)
|
|
return NULL;
|
|
|
|
const auto indexval_it = m_map.abbrev_map.find (abbrev);
|
|
if (indexval_it == m_map.abbrev_map.cend ())
|
|
{
|
|
complaint (_("Wrong .debug_names undefined abbrev code %s "
|
|
"[in module %s]"),
|
|
pulongest (abbrev), objfile_name (objfile));
|
|
return NULL;
|
|
}
|
|
const mapped_debug_names::index_val &indexval = indexval_it->second;
|
|
enum class symbol_linkage {
|
|
unknown,
|
|
static_,
|
|
extern_,
|
|
} symbol_linkage_ = symbol_linkage::unknown;
|
|
dwarf2_per_cu_data *per_cu = NULL;
|
|
for (const mapped_debug_names::index_val::attr &attr : indexval.attr_vec)
|
|
{
|
|
ULONGEST ull;
|
|
switch (attr.form)
|
|
{
|
|
case DW_FORM_implicit_const:
|
|
ull = attr.implicit_const;
|
|
break;
|
|
case DW_FORM_flag_present:
|
|
ull = 1;
|
|
break;
|
|
case DW_FORM_udata:
|
|
ull = read_unsigned_leb128 (abfd, m_addr, &bytes_read);
|
|
m_addr += bytes_read;
|
|
break;
|
|
case DW_FORM_ref4:
|
|
ull = read_4_bytes (abfd, m_addr);
|
|
m_addr += 4;
|
|
break;
|
|
case DW_FORM_ref8:
|
|
ull = read_8_bytes (abfd, m_addr);
|
|
m_addr += 8;
|
|
break;
|
|
case DW_FORM_ref_sig8:
|
|
ull = read_8_bytes (abfd, m_addr);
|
|
m_addr += 8;
|
|
break;
|
|
default:
|
|
complaint (_("Unsupported .debug_names form %s [in module %s]"),
|
|
dwarf_form_name (attr.form),
|
|
objfile_name (objfile));
|
|
return NULL;
|
|
}
|
|
switch (attr.dw_idx)
|
|
{
|
|
case DW_IDX_compile_unit:
|
|
{
|
|
/* Don't crash on bad data. */
|
|
if (ull >= per_bfd->all_comp_units.size ())
|
|
{
|
|
complaint (_(".debug_names entry has bad CU index %s"
|
|
" [in module %s]"),
|
|
pulongest (ull),
|
|
objfile_name (objfile));
|
|
continue;
|
|
}
|
|
}
|
|
per_cu = per_bfd->get_cu (ull);
|
|
break;
|
|
case DW_IDX_type_unit:
|
|
/* Don't crash on bad data. */
|
|
if (ull >= per_bfd->all_type_units.size ())
|
|
{
|
|
complaint (_(".debug_names entry has bad TU index %s"
|
|
" [in module %s]"),
|
|
pulongest (ull),
|
|
objfile_name (objfile));
|
|
continue;
|
|
}
|
|
{
|
|
int nr_cus = per_bfd->all_comp_units.size ();
|
|
per_cu = per_bfd->get_cu (nr_cus + ull);
|
|
}
|
|
break;
|
|
case DW_IDX_die_offset:
|
|
/* In a per-CU index (as opposed to a per-module index), index
|
|
entries without CU attribute implicitly refer to the single CU. */
|
|
if (per_cu == NULL)
|
|
per_cu = per_bfd->get_cu (0);
|
|
break;
|
|
case DW_IDX_GNU_internal:
|
|
if (!m_map.augmentation_is_gdb)
|
|
break;
|
|
symbol_linkage_ = symbol_linkage::static_;
|
|
break;
|
|
case DW_IDX_GNU_external:
|
|
if (!m_map.augmentation_is_gdb)
|
|
break;
|
|
symbol_linkage_ = symbol_linkage::extern_;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Skip if we couldn't find a valid CU/TU index. */
|
|
if (per_cu == nullptr)
|
|
goto again;
|
|
|
|
/* Skip if already read in. */
|
|
if (m_per_objfile->symtab_set_p (per_cu))
|
|
goto again;
|
|
|
|
/* Check static vs global. */
|
|
if (symbol_linkage_ != symbol_linkage::unknown)
|
|
{
|
|
if (symbol_linkage_ == symbol_linkage::static_)
|
|
{
|
|
if ((m_block_index & SEARCH_STATIC_BLOCK) == 0)
|
|
goto again;
|
|
}
|
|
else
|
|
{
|
|
if ((m_block_index & SEARCH_GLOBAL_BLOCK) == 0)
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
/* Match dw2_symtab_iter_next, symbol_kind
|
|
and debug_names::psymbol_tag. */
|
|
switch (m_domain)
|
|
{
|
|
case VAR_DOMAIN:
|
|
switch (indexval.dwarf_tag)
|
|
{
|
|
case DW_TAG_variable:
|
|
case DW_TAG_subprogram:
|
|
/* Some types are also in VAR_DOMAIN. */
|
|
case DW_TAG_typedef:
|
|
case DW_TAG_structure_type:
|
|
break;
|
|
default:
|
|
goto again;
|
|
}
|
|
break;
|
|
case STRUCT_DOMAIN:
|
|
switch (indexval.dwarf_tag)
|
|
{
|
|
case DW_TAG_typedef:
|
|
case DW_TAG_structure_type:
|
|
break;
|
|
default:
|
|
goto again;
|
|
}
|
|
break;
|
|
case LABEL_DOMAIN:
|
|
switch (indexval.dwarf_tag)
|
|
{
|
|
case 0:
|
|
case DW_TAG_variable:
|
|
break;
|
|
default:
|
|
goto again;
|
|
}
|
|
break;
|
|
case MODULE_DOMAIN:
|
|
switch (indexval.dwarf_tag)
|
|
{
|
|
case DW_TAG_module:
|
|
break;
|
|
default:
|
|
goto again;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Match dw2_expand_symtabs_matching, symbol_kind and
|
|
debug_names::psymbol_tag. */
|
|
switch (m_search)
|
|
{
|
|
case VARIABLES_DOMAIN:
|
|
switch (indexval.dwarf_tag)
|
|
{
|
|
case DW_TAG_variable:
|
|
break;
|
|
default:
|
|
goto again;
|
|
}
|
|
break;
|
|
case FUNCTIONS_DOMAIN:
|
|
switch (indexval.dwarf_tag)
|
|
{
|
|
case DW_TAG_subprogram:
|
|
break;
|
|
default:
|
|
goto again;
|
|
}
|
|
break;
|
|
case TYPES_DOMAIN:
|
|
switch (indexval.dwarf_tag)
|
|
{
|
|
case DW_TAG_typedef:
|
|
case DW_TAG_structure_type:
|
|
break;
|
|
default:
|
|
goto again;
|
|
}
|
|
break;
|
|
case MODULES_DOMAIN:
|
|
switch (indexval.dwarf_tag)
|
|
{
|
|
case DW_TAG_module:
|
|
break;
|
|
default:
|
|
goto again;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return per_cu;
|
|
}
|
|
|
|
/* This dumps minimal information about .debug_names. It is called
|
|
via "mt print objfiles". The gdb.dwarf2/gdb-index.exp testcase
|
|
uses this to verify that .debug_names has been loaded. */
|
|
|
|
void
|
|
dwarf2_debug_names_index::dump (struct objfile *objfile)
|
|
{
|
|
gdb_printf (".debug_names: exists\n");
|
|
}
|
|
|
|
void
|
|
dwarf2_debug_names_index::expand_matching_symbols
|
|
(struct objfile *objfile,
|
|
const lookup_name_info &name, domain_enum domain,
|
|
int global,
|
|
symbol_compare_ftype *ordered_compare)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
|
|
|
|
mapped_debug_names &map
|
|
= *(gdb::checked_static_cast<mapped_debug_names *>
|
|
(per_objfile->per_bfd->index_table.get ()));
|
|
const block_search_flags block_flags
|
|
= global ? SEARCH_GLOBAL_BLOCK : SEARCH_STATIC_BLOCK;
|
|
|
|
const char *match_name = name.ada ().lookup_name ().c_str ();
|
|
auto matcher = [&] (const char *symname)
|
|
{
|
|
if (ordered_compare == nullptr)
|
|
return true;
|
|
return ordered_compare (symname, match_name) == 0;
|
|
};
|
|
|
|
dw2_expand_symtabs_matching_symbol (map, name, matcher,
|
|
[&] (offset_type namei)
|
|
{
|
|
/* The name was matched, now expand corresponding CUs that were
|
|
marked. */
|
|
dw2_debug_names_iterator iter (map, block_flags, domain, namei,
|
|
per_objfile);
|
|
|
|
struct dwarf2_per_cu_data *per_cu;
|
|
while ((per_cu = iter.next ()) != NULL)
|
|
dw2_expand_symtabs_matching_one (per_cu, per_objfile, nullptr,
|
|
nullptr);
|
|
return true;
|
|
}, per_objfile);
|
|
}
|
|
|
|
bool
|
|
dwarf2_debug_names_index::expand_symtabs_matching
|
|
(struct objfile *objfile,
|
|
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
|
|
const lookup_name_info *lookup_name,
|
|
gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
|
|
gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
|
|
block_search_flags search_flags,
|
|
domain_enum domain,
|
|
enum search_domain kind)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
|
|
|
|
dw_expand_symtabs_matching_file_matcher (per_objfile, file_matcher);
|
|
|
|
/* This invariant is documented in quick-functions.h. */
|
|
gdb_assert (lookup_name != nullptr || symbol_matcher == nullptr);
|
|
if (lookup_name == nullptr)
|
|
{
|
|
for (dwarf2_per_cu_data *per_cu
|
|
: all_units_range (per_objfile->per_bfd))
|
|
{
|
|
QUIT;
|
|
|
|
if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile,
|
|
file_matcher,
|
|
expansion_notify))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
mapped_debug_names &map
|
|
= *(gdb::checked_static_cast<mapped_debug_names *>
|
|
(per_objfile->per_bfd->index_table.get ()));
|
|
|
|
bool result
|
|
= dw2_expand_symtabs_matching_symbol (map, *lookup_name,
|
|
symbol_matcher,
|
|
[&] (offset_type namei)
|
|
{
|
|
/* The name was matched, now expand corresponding CUs that were
|
|
marked. */
|
|
dw2_debug_names_iterator iter (map, kind, namei, per_objfile, domain);
|
|
|
|
struct dwarf2_per_cu_data *per_cu;
|
|
while ((per_cu = iter.next ()) != NULL)
|
|
if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile,
|
|
file_matcher,
|
|
expansion_notify))
|
|
return false;
|
|
return true;
|
|
}, per_objfile);
|
|
|
|
return result;
|
|
}
|