--- Begin Message ---
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- Date: Sat, 1 Jul 2017 17:24:41 +0200
- Subject: [PATCH] DWARF-5: .debug_names index consumer
Hi,
it is not regression-free against no-index but it is regression-free against
.gdb_index. That is because .gdb_index is not regression-free against
no-index.
Some testcases needed to be updated as they were missing .debug_aranges.
While that does not matter for no-index (as GDB builds the mapping internally
during dwarf2_build_psymtabs_hard) and neither for .gdb_index (as GDB uses that
internally built mapping which it stores into .gdb_index) it does matter for
.debug_names as that simply assumes existing .debug_aranges from GCC.
I tried some performance checking but the index handling speed is negligible
compared to the CU expansion associated with it. .debug_names looked even as
a bit faster to me than .gdb_index which rather surprised me but I did not
investigate it more.
Jan
gdb/ChangeLog
2017-05-26 Jan Kratochvil <jan.kratochvil@redhat.com>
* defs.h (elf_sym_fns_debug_names): New declaration.
* dwarf2read.c (mapped_debug_names): New.
(struct dwarf2_per_objfile): Add debug_names, debug_aranges and
debug_names_table.
(dwarf2_elf_names): Add debug_names and debug_aranges.
(struct dwz_file): Add debug_names.
(dwarf2_locate_sections): Add debug_names and debug_aranges.
(locate_dwz_sections): Add debug_names.
(create_signatured_type_table_from_debug_names)
(create_addrmap_from_aranges): New.
(dwarf2_read_index): Update function comment.
(dwarf5_augmentation): New from write_debug_names.
(read_debug_names_from_section, create_cus_from_debug_names_list)
(create_cus_from_debug_names, dwarf2_read_debug_names): New.
(dwarf5_djb_hash): Function renamed from DebugNamesNameTable::djb_hash.
(dw2_debug_names_iterator): New.
(read_indirect_string_at_offset): New declaration.
(mapped_debug_names::namei_to_name)
(dw2_debug_names_iterator::find_vec_in_debug_names)
(dw2_debug_names_iterator::find_vec_in_debug_names)
(dw2_debug_names_iterator::next, dw2_debug_names_lookup_symbol)
(dw2_debug_names_dump, dw2_debug_names_expand_symtabs_for_function)
(dw2_debug_names_expand_symtabs_matching, dwarf2_debug_names_functions):
New.
(dwarf2_initialize_objfile): Return also elf_sym_fns_debug_names.
(dwarf2_free_objfile): Delete also debug_names_table;
(debug_names::djb_hash): Rename it to dwarf5_djb_hash.
(debug_names::build): Update djb_hash caller.
(write_debug_names): Move out and rename augmentation to
dwarf5_augmentation.
* elfread.c (elf_sym_fns_debug_names): New.
* psymtab.h (dwarf2_debug_names_functions): New declaration.
* symfile.h (struct dwarf2_debug_sections): Add debug_names and
debug_aranges.
* xcoffread.c (dwarf2_xcoff_names): Add debug_names and debug_aranges.
gdb/testsuite/ChangeLog
2017-05-26 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/maint.exp (check for .gdb_index): Check also for
.debug_names.
* gdb.dlang/watch-loc.c (.debug_aranges): New.
* gdb.dwarf2/dw2-case-insensitive-debug.S: Likewise.
* gdb.dwarf2/gdb-index.exp (check if index present, .gdb_index used)
(.gdb_index used after symbol reloading): Support also .debug_names.
* gdb.mi/dw2-ref-missing-frame-func.c (.debug_aranges): New.
---
gdb/defs.h | 1 +
gdb/dwarf2read.c | 1481 +++++++++++++++++---
gdb/elfread.c | 17 +
gdb/psymtab.h | 1 +
gdb/symfile.h | 2 +
gdb/testsuite/gdb.base/maint.exp | 7 +-
gdb/testsuite/gdb.dlang/watch-loc.c | 19 +
.../gdb.dwarf2/dw2-case-insensitive-debug.S | 17 +
gdb/testsuite/gdb.dwarf2/gdb-index.exp | 7 +-
gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c | 20 +
gdb/xcoffread.c | 2 +
11 files changed, 1382 insertions(+), 192 deletions(-)
diff --git a/gdb/defs.h b/gdb/defs.h
index 516c234..7916b99 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -762,6 +762,7 @@ extern void initialize_inferiors (void);
extern const struct sym_fns elf_sym_fns_lazy_psyms;
extern const struct sym_fns elf_sym_fns_gdb_index;
+extern const struct sym_fns elf_sym_fns_debug_names;
/* * Special block numbers */
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 9fbdb55..fb671f8 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -211,6 +211,42 @@ struct mapped_index
const char *constant_pool;
};
+/* A description of the mapped .debug_names.
+ Uninitialized map has CU_COUNT 0. */
+class mapped_debug_names
+{
+public:
+ 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;
+ class index_val
+ {
+ public:
+ ULONGEST dwarf_tag;
+ class attr
+ {
+ public:
+ /* 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) const;
+};
+
typedef struct dwarf2_per_cu_data *dwarf2_per_cu_ptr;
DEF_VEC_P (dwarf2_per_cu_ptr);
@@ -243,6 +279,8 @@ struct dwarf2_per_objfile
struct dwarf2_section_info frame;
struct dwarf2_section_info eh_frame;
struct dwarf2_section_info gdb_index;
+ struct dwarf2_section_info debug_names;
+ struct dwarf2_section_info debug_aranges;
VEC (dwarf2_section_info_def) *types;
@@ -308,6 +346,9 @@ struct dwarf2_per_objfile
/* The mapped index, or NULL if .gdb_index is missing or not being used. */
struct mapped_index *index_table;
+ /* The mapped index, or NULL if .debug_names is missing or not being used. */
+ mapped_debug_names *debug_names_table;
+
/* When using index_table, this keeps track of all quick_file_names entries.
TUs typically share line table entries with a CU, so we maintain a
separate table of all line table entries to support the sharing.
@@ -358,6 +399,8 @@ static const struct dwarf2_debug_sections dwarf2_elf_names =
{ ".debug_frame", ".zdebug_frame" },
{ ".eh_frame", NULL },
{ ".gdb_index", ".zgdb_index" },
+ { ".debug_names", ".zdebug_names" },
+ { ".debug_aranges", ".zdebug_aranges" },
23
};
@@ -1019,6 +1062,7 @@ struct dwz_file
struct dwarf2_section_info line;
struct dwarf2_section_info macro;
struct dwarf2_section_info gdb_index;
+ struct dwarf2_section_info debug_names;
/* The dwz's BFD. */
bfd *dwz_bfd;
@@ -2424,6 +2468,16 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames)
dwarf2_per_objfile->gdb_index.s.section = sectp;
dwarf2_per_objfile->gdb_index.size = bfd_get_section_size (sectp);
}
+ else if (section_is_p (sectp->name, &names->debug_names))
+ {
+ dwarf2_per_objfile->debug_names.s.section = sectp;
+ dwarf2_per_objfile->debug_names.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->debug_aranges))
+ {
+ dwarf2_per_objfile->debug_aranges.s.section = sectp;
+ dwarf2_per_objfile->debug_aranges.size = bfd_get_section_size (sectp);
+ }
if ((bfd_get_section_flags (abfd, sectp) & (SEC_LOAD | SEC_ALLOC))
&& bfd_section_vma (abfd, sectp) == 0)
@@ -2620,6 +2674,11 @@ locate_dwz_sections (bfd *abfd, asection *sectp, void *arg)
dwz_file->gdb_index.s.section = sectp;
dwz_file->gdb_index.size = bfd_get_section_size (sectp);
}
+ else if (section_is_p (sectp->name, &dwarf2_elf_names.debug_names))
+ {
+ dwz_file->debug_names.s.section = sectp;
+ dwz_file->debug_names.size = bfd_get_section_size (sectp);
+ }
}
/* Open the separate '.dwz' debug file, if needed. Return NULL if
@@ -3071,6 +3130,66 @@ create_signatured_type_table_from_index (struct objfile *objfile,
dwarf2_per_objfile->signatured_types = sig_types_hash;
}
+/* Create the signatured type hash table from .debug_names. */
+
+static void
+create_signatured_type_table_from_debug_names (struct objfile *objfile,
+ const mapped_debug_names &map,
+ struct dwarf2_section_info *section,
+ struct dwarf2_section_info *abbrev_section)
+{
+ uint32_t i;
+ htab_t sig_types_hash;
+
+ dwarf2_read_section (objfile, section);
+ dwarf2_read_section (objfile, abbrev_section);
+
+ dwarf2_per_objfile->n_type_units
+ = dwarf2_per_objfile->n_allocated_type_units
+ = map.tu_count;
+ dwarf2_per_objfile->all_type_units =
+ XNEWVEC (struct signatured_type *, dwarf2_per_objfile->n_type_units);
+
+ sig_types_hash = allocate_signatured_type_table (objfile);
+
+ for (i = 0; i < map.tu_count; ++i)
+ {
+ struct signatured_type *sig_type;
+ ULONGEST signature;
+ void **slot;
+ cu_offset type_offset_in_tu;
+
+ 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 (&cu_header, section, abbrev_section,
+ section->buffer + to_underlying (sect_off),
+ rcuh_kind::TYPE);
+
+ sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct signatured_type);
+ sig_type->signature = cu_header.signature;
+ sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu;
+ sig_type->per_cu.is_debug_types = 1;
+ sig_type->per_cu.section = section;
+ sig_type->per_cu.sect_off = sect_off;
+ sig_type->per_cu.objfile = objfile;
+ sig_type->per_cu.v.quick
+ = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct dwarf2_per_cu_quick_data);
+
+ slot = htab_find_slot (sig_types_hash, sig_type, INSERT);
+ *slot = sig_type;
+
+ dwarf2_per_objfile->all_type_units[i] = sig_type;
+ }
+
+ dwarf2_per_objfile->signatured_types = sig_types_hash;
+}
+
/* Read the address map data from the mapped index, and use it to
populate the objfile's psymtabs_addrmap. */
@@ -3126,6 +3245,165 @@ create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index)
&objfile->objfile_obstack);
}
+/* Read the address map data from DWARF-5 .debug_aranges, and use it to
+ populate the objfile's psymtabs_addrmap. */
+
+static void
+create_addrmap_from_aranges (struct objfile *objfile,
+ struct dwarf2_section_info *section)
+{
+ bfd *abfd = objfile->obfd;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ const gdb_byte *iter, *end;
+ struct addrmap *mutable_map;
+ const CORE_ADDR baseaddr (ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile)));
+
+ auto_obstack temp_obstack;
+
+ mutable_map = addrmap_create_mutable (&temp_obstack);
+
+ std::unordered_map<sect_offset,
+ dwarf2_per_cu_data *> debug_info_offset_to_per_cu;
+ for (int cui = 0; cui < dwarf2_per_objfile->n_comp_units; ++cui)
+ {
+ dwarf2_per_cu_data *per_cu (dw2_get_cutu (cui));
+ const auto insertpair
+ (debug_info_offset_to_per_cu.emplace (per_cu->sect_off, per_cu));
+ if (!insertpair.second)
+ {
+ warning (_("Section .debug_aranges in %s has duplicate "
+ "debug_info_offset %u, ignoring .debug_aranges."),
+ objfile_name (objfile), to_underlying (per_cu->sect_off));
+ return;
+ }
+ }
+
+ dwarf2_read_section (objfile, section);
+
+ const bfd_endian dwarf5_byte_order
+ (gdbarch_byte_order (get_objfile_arch (objfile)));
+
+ 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)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "length %s exceeds section length %s, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ plongest (bytes_read + entry_length),
+ pulongest (section->size));
+ return;
+ }
+
+ /* The version number. */
+ const uint16_t version (read_2_bytes (abfd, addr));
+ addr += 2;
+ if (version != 2)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "has unsupported version %d, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ version);
+ return;
+ }
+
+ 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 ())
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "debug_info_offset %s does not exists, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ pulongest (debug_info_offset));
+ return;
+ }
+ dwarf2_per_cu_data *const per_cu (per_cu_it->second);
+
+ const uint8_t address_size (*addr++);
+ if (address_size < 1 || address_size > 8)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "address_size %u is invalid, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ address_size);
+ return;
+ }
+
+ const uint8_t segment_selector_size (*addr++);
+ if (segment_selector_size != 0)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "segment_selector_size %u is not supported, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ segment_selector_size);
+ return;
+ }
+
+ /* Must pad to an alignment boundary that is twice the address size.
+ It is undocumented by the DWARF standard but GCC does use it. */
+ for (size_t padding = ((-(addr - section->buffer))
+ & (2 * address_size - 1));
+ padding > 0; padding--)
+ if (*addr++ != 0)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "padding is not zero, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer);
+ return;
+ }
+
+ for (;;)
+ {
+ if (addr + 2 * address_size > entry_end)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "address list is not properly terminated, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer);
+ return;
+ }
+ 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)
+ break;
+ if (start == 0 && !dwarf2_per_objfile->has_section_at_zero)
+ {
+ /* Symbol was eliminated due to a COMDAT group. */
+ continue;
+ }
+ ULONGEST end (start + length);
+ start = gdbarch_adjust_dwarf2_addr (gdbarch, start + baseaddr);
+ end = gdbarch_adjust_dwarf2_addr (gdbarch, end + baseaddr);
+ addrmap_set_empty (mutable_map, start, end - 1, per_cu);
+ }
+ }
+
+ objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map,
+ &objfile->objfile_obstack);
+}
+
/* The hash function for strings in the mapped index. This is the same as
SYMBOL_HASH_NEXT, but we keep a separate copy to maintain control over the
implementation. This is necessary because the hash function is tied to the
@@ -3342,8 +3620,7 @@ to use the section anyway."),
return 1;
}
-
-/* Read the index file. If everything went ok, initialize the "quick"
+/* Read .gdb_index. If everything went ok, initialize the "quick"
elements of all the CUs and return 1. Otherwise, return 0. */
static int
@@ -3419,99 +3696,417 @@ dwarf2_read_index (struct objfile *objfile)
return 1;
}
-/* A helper for the "quick" functions which sets the global
- dwarf2_per_objfile according to OBJFILE. */
+/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension. */
+static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 };
-static void
-dw2_setup (struct objfile *objfile)
-{
- dwarf2_per_objfile = ((struct dwarf2_per_objfile *)
- objfile_data (objfile, dwarf2_objfile_data_key));
- gdb_assert (dwarf2_per_objfile);
-}
+/* A helper function that reads the .debug_names from SECTION and fills
+ in MAP. FILENAME is the name of the file containing the section;
+ it is used for error reporting.
-/* die_reader_func for dw2_get_file_names. */
+ CU_LIST, CU_LIST_ELEMENTS, TYPES_LIST, and TYPES_LIST_ELEMENTS are
+ out parameters that are filled in with information about the CU and
+ TU lists in the section.
-static void
-dw2_get_file_names_reader (const struct die_reader_specs *reader,
- const gdb_byte *info_ptr,
- struct die_info *comp_unit_die,
- int has_children,
- void *data)
+ 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)
{
- struct dwarf2_cu *cu = reader->cu;
- struct dwarf2_per_cu_data *this_cu = cu->per_cu;
- struct objfile *objfile = dwarf2_per_objfile->objfile;
- struct dwarf2_per_cu_data *lh_cu;
- struct attribute *attr;
+ const gdb_byte *addr, *abbrev_table_start;
+ offset_type *metadata;
int i;
- void **slot;
- struct quick_file_names *qfn;
+ unsigned int bytes_read;
+ LONGEST length;
+ uint16_t version, padding;
+ uint32_t foreign_tu_count;
+ uint32_t abbrev_table_size, augmentation_string_size;
- gdb_assert (! this_cu->is_debug_types);
+ if (dwarf2_section_empty_p (section))
+ return false;
- /* Our callers never want to match partial units -- instead they
- will match the enclosing full CU. */
- if (comp_unit_die->tag == DW_TAG_partial_unit)
+ /* Older elfutils strip versions could keep the section in the main
+ executable while splitting it for the separate debug info file. */
+ if ((get_section_flags (section) & SEC_HAS_CONTENTS) == 0)
+ return false;
+
+ dwarf2_read_section (objfile, section);
+
+ map.dwarf5_byte_order = gdbarch_byte_order (get_objfile_arch (objfile));
+
+ addr = section->buffer;
+
+ bfd *const abfd (get_section_bfd_owner (section));
+ 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. */
+ version = read_2_bytes (abfd, addr);
+ addr += 2;
+ if (version != 5)
{
- this_cu->v.quick->no_file_data = 1;
- return;
+ warning (_("Section .debug_names in %s has unsupported version %d, "
+ "ignoring .debug_names."),
+ filename, version);
+ return false;
}
- lh_cu = this_cu;
- slot = NULL;
+ /* Padding. */
+ 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;
+ }
- line_header_up lh;
- sect_offset line_offset {};
+ /* comp_unit_count - The number of CUs in the CU list. */
+ map.cu_count = read_4_bytes (abfd, addr);
+ addr += 4;
- attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu);
- if (attr)
+ /* 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. */
+ foreign_tu_count = read_4_bytes (abfd, addr);
+ addr += 4;
+ if (foreign_tu_count != 0)
{
- struct quick_file_names find_entry;
+ warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, "
+ "ignoring .debug_names."),
+ filename, static_cast<unsigned long> (foreign_tu_count));
+ return false;
+ }
- line_offset = (sect_offset) DW_UNSND (attr);
+ /* bucket_count - The number of hash buckets
+ in the hash lookup table. */
+ map.bucket_count = read_4_bytes (abfd, addr);
+ addr += 4;
- /* We may have already read in this line header (TU line header sharing).
- If we have we're done. */
- find_entry.hash.dwo_unit = cu->dwo_unit;
- find_entry.hash.line_sect_off = line_offset;
- slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table,
- &find_entry, INSERT);
- if (*slot != NULL)
+ /* 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. */
+ 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. */
+ 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;
+
+ abbrev_table_start = addr;
+ for (;;)
+ {
+ unsigned int bytes_read;
+ 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)
{
- lh_cu->v.quick->file_names = (struct quick_file_names *) *slot;
- return;
+ 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;
- lh = dwarf_decode_line_header (line_offset, cu);
+ 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 (lh == NULL)
+ if (addr != abbrev_table_start + abbrev_table_size)
{
- lh_cu->v.quick->no_file_data = 1;
- return;
+ warning (_("Section .debug_names in %s has abbreviation_table "
+ "of size %zu vs. written as %u, ignoring .debug_names."),
+ filename, addr - abbrev_table_start, abbrev_table_size);
+ return false;
}
+ map.entry_pool = addr;
- qfn = XOBNEW (&objfile->objfile_obstack, struct quick_file_names);
- qfn->hash.dwo_unit = cu->dwo_unit;
- qfn->hash.line_sect_off = line_offset;
- gdb_assert (slot != NULL);
- *slot = qfn;
-
- file_and_directory fnd = find_file_and_directory (comp_unit_die, cu);
-
- qfn->num_file_names = lh->file_names.size ();
- qfn->file_names =
- XOBNEWVEC (&objfile->objfile_obstack, const char *, lh->file_names.size ());
- for (i = 0; i < lh->file_names.size (); ++i)
- qfn->file_names[i] = file_full_name (i + 1, lh.get (), fnd.comp_dir);
- qfn->real_names = NULL;
-
- lh_cu->v.quick->file_names = qfn;
+ return true;
}
-/* A helper for the "quick" functions which attempts to read the line
- table for THIS_CU. */
-
+/* A helper for create_cus_from_index that handles a given list of
+ CUs. */
+
+static void
+create_cus_from_debug_names_list (struct objfile *objfile,
+ const mapped_debug_names &map,
+ dwarf2_section_info §ion,
+ int is_dwz, int base_offset)
+{
+ 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)
+ {
+ const ULONGEST length (sect_off_next - sect_off_prev);
+ dwarf2_per_objfile->all_comp_units[base_offset + (i - 1)] =
+ create_cu_from_index_list (objfile, §ion, is_dwz,
+ sect_off_prev, length);
+ }
+ sect_off_prev = sect_off_next;
+ }
+}
+
+/* Read the CU list from the mapped index, and use it to create all
+ the CU objects for this objfile. */
+
+static void
+create_cus_from_debug_names (struct objfile *objfile,
+ const mapped_debug_names &map,
+ const mapped_debug_names &dwz_map)
+{
+ struct dwz_file *dwz;
+
+ dwarf2_per_objfile->n_comp_units = map.cu_count + dwz_map.cu_count;
+ dwarf2_per_objfile->all_comp_units =
+ XOBNEWVEC (&objfile->objfile_obstack, struct dwarf2_per_cu_data *,
+ dwarf2_per_objfile->n_comp_units);
+
+ create_cus_from_debug_names_list (objfile, map, dwarf2_per_objfile->info,
+ 0 /* is_dwz */, 0 /* base_offset */);
+
+ if (dwz_map.cu_count == 0)
+ return;
+
+ dwz = dwarf2_get_dwz_file ();
+ create_cus_from_debug_names_list (objfile, dwz_map, dwz->info, 1 /* is_dwz */,
+ map.cu_count /* base_offset */);
+}
+
+/* Read .debug_names. If everything went ok, initialize the "quick"
+ elements of all the CUs and return true. Otherwise, return false. */
+
+static bool
+dwarf2_read_debug_names (struct objfile *objfile)
+{
+ mapped_debug_names local_map, dwz_map;
+ const gdb_byte *dwz_list = NULL;
+ offset_type dwz_list_elements = 0;
+ struct dwz_file *dwz;
+
+ if (!read_debug_names_from_section (objfile, objfile_name (objfile),
+ &dwarf2_per_objfile->debug_names,
+ local_map))
+ return false;
+
+ /* Don't use the index if it's empty. */
+ if (local_map.name_count == 0)
+ return false;
+
+ /* If there is a .dwz file, read it so we can get its CU list as
+ well. */
+ dwz = dwarf2_get_dwz_file ();
+ if (dwz != NULL)
+ {
+ if (!read_debug_names_from_section (objfile,
+ bfd_get_filename (dwz->dwz_bfd),
+ &dwz->debug_names, dwz_map))
+ {
+ warning (_("could not read '.debug_names' section from %s; skipping"),
+ bfd_get_filename (dwz->dwz_bfd));
+ return false;
+ }
+ }
+
+ create_cus_from_debug_names (objfile, local_map, dwz_map);
+
+ if (local_map.tu_count != 0)
+ {
+ struct dwarf2_section_info *section;
+
+ /* We can only handle a single .debug_types when we have an
+ index. */
+ if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) != 1)
+ return false;
+
+ section = VEC_index (dwarf2_section_info_def,
+ dwarf2_per_objfile->types, 0);
+
+ create_signatured_type_table_from_debug_names (objfile, local_map,
+ section,
+ &dwarf2_per_objfile->abbrev);
+ }
+
+ create_addrmap_from_aranges (objfile, &dwarf2_per_objfile->debug_aranges);
+
+ dwarf2_per_objfile->debug_names_table = new mapped_debug_names;
+ *dwarf2_per_objfile->debug_names_table = std::move (local_map);
+ dwarf2_per_objfile->using_index = 1;
+ dwarf2_per_objfile->quick_file_names_table =
+ create_quick_file_names_table (dwarf2_per_objfile->n_comp_units);
+
+ return true;
+}
+
+/* A helper for the "quick" functions which sets the global
+ dwarf2_per_objfile according to OBJFILE. */
+
+static void
+dw2_setup (struct objfile *objfile)
+{
+ dwarf2_per_objfile = ((struct dwarf2_per_objfile *)
+ objfile_data (objfile, dwarf2_objfile_data_key));
+ gdb_assert (dwarf2_per_objfile);
+}
+
+/* die_reader_func for dw2_get_file_names. */
+
+static void
+dw2_get_file_names_reader (const struct die_reader_specs *reader,
+ const gdb_byte *info_ptr,
+ struct die_info *comp_unit_die,
+ int has_children,
+ void *data)
+{
+ struct dwarf2_cu *cu = reader->cu;
+ struct dwarf2_per_cu_data *this_cu = cu->per_cu;
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ struct dwarf2_per_cu_data *lh_cu;
+ struct attribute *attr;
+ int i;
+ void **slot;
+ struct quick_file_names *qfn;
+
+ gdb_assert (! this_cu->is_debug_types);
+
+ /* Our callers never want to match partial units -- instead they
+ will match the enclosing full CU. */
+ if (comp_unit_die->tag == DW_TAG_partial_unit)
+ {
+ this_cu->v.quick->no_file_data = 1;
+ return;
+ }
+
+ lh_cu = this_cu;
+ slot = NULL;
+
+ line_header_up lh;
+ sect_offset line_offset {};
+
+ attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu);
+ if (attr)
+ {
+ struct quick_file_names find_entry;
+
+ line_offset = (sect_offset) DW_UNSND (attr);
+
+ /* We may have already read in this line header (TU line header sharing).
+ If we have we're done. */
+ find_entry.hash.dwo_unit = cu->dwo_unit;
+ find_entry.hash.line_sect_off = line_offset;
+ slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table,
+ &find_entry, INSERT);
+ if (*slot != NULL)
+ {
+ lh_cu->v.quick->file_names = (struct quick_file_names *) *slot;
+ return;
+ }
+
+ lh = dwarf_decode_line_header (line_offset, cu);
+ }
+ if (lh == NULL)
+ {
+ lh_cu->v.quick->no_file_data = 1;
+ return;
+ }
+
+ qfn = XOBNEW (&objfile->objfile_obstack, struct quick_file_names);
+ qfn->hash.dwo_unit = cu->dwo_unit;
+ qfn->hash.line_sect_off = line_offset;
+ gdb_assert (slot != NULL);
+ *slot = qfn;
+
+ file_and_directory fnd = find_file_and_directory (comp_unit_die, cu);
+
+ qfn->num_file_names = lh->file_names.size ();
+ qfn->file_names =
+ XOBNEWVEC (&objfile->objfile_obstack, const char *, lh->file_names.size ());
+ for (i = 0; i < lh->file_names.size (); ++i)
+ qfn->file_names[i] = file_full_name (i + 1, lh.get (), fnd.comp_dir);
+ qfn->real_names = NULL;
+
+ lh_cu->v.quick->file_names = qfn;
+}
+
+/* A helper for the "quick" functions which attempts to read the line
+ table for THIS_CU. */
+
static struct quick_file_names *
dw2_get_file_names (struct dwarf2_per_cu_data *this_cu)
{
@@ -4235,157 +4830,675 @@ dw2_expand_symtabs_matching
continue;
}
- per_cu = dw2_get_cutu (cu_index);
- dw2_expand_symtabs_matching_one (per_cu, file_matcher,
- expansion_notify);
+ per_cu = dw2_get_cutu (cu_index);
+ dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+ expansion_notify);
+ }
+ }
+}
+
+/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific
+ symtab. */
+
+static struct compunit_symtab *
+recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust,
+ CORE_ADDR pc)
+{
+ int i;
+
+ if (COMPUNIT_BLOCKVECTOR (cust) != NULL
+ && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc))
+ return cust;
+
+ if (cust->includes == NULL)
+ return NULL;
+
+ for (i = 0; cust->includes[i]; ++i)
+ {
+ struct compunit_symtab *s = cust->includes[i];
+
+ s = recursively_find_pc_sect_compunit_symtab (s, pc);
+ if (s != NULL)
+ return s;
+ }
+
+ return NULL;
+}
+
+static struct compunit_symtab *
+dw2_find_pc_sect_compunit_symtab (struct objfile *objfile,
+ struct bound_minimal_symbol msymbol,
+ CORE_ADDR pc,
+ struct obj_section *section,
+ int warn_if_readin)
+{
+ struct dwarf2_per_cu_data *data;
+ struct compunit_symtab *result;
+
+ dw2_setup (objfile);
+
+ if (!objfile->psymtabs_addrmap)
+ return NULL;
+
+ data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap,
+ pc);
+ if (!data)
+ return NULL;
+
+ if (warn_if_readin && data->v.quick->compunit_symtab)
+ warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
+ paddress (get_objfile_arch (objfile), pc));
+
+ result
+ = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data),
+ pc);
+ gdb_assert (result != NULL);
+ return result;
+}
+
+static void
+dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun,
+ void *data, int need_fullname)
+{
+ int i;
+ htab_up visited (htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer,
+ NULL, xcalloc, xfree));
+
+ dw2_setup (objfile);
+
+ /* The rule is CUs specify all the files, including those used by
+ any TU, so there's no need to scan TUs here.
+ We can ignore file names coming from already-expanded CUs. */
+
+ for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
+
+ if (per_cu->v.quick->compunit_symtab)
+ {
+ void **slot = htab_find_slot (visited.get (),
+ per_cu->v.quick->file_names,
+ INSERT);
+
+ *slot = per_cu->v.quick->file_names;
+ }
+ }
+
+ for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ int j;
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+ struct quick_file_names *file_data;
+ void **slot;
+
+ /* We only need to look at symtabs not already expanded. */
+ if (per_cu->v.quick->compunit_symtab)
+ continue;
+
+ file_data = dw2_get_file_names (per_cu);
+ if (file_data == NULL)
+ continue;
+
+ slot = htab_find_slot (visited.get (), file_data, INSERT);
+ if (*slot)
+ {
+ /* Already visited. */
+ continue;
+ }
+ *slot = file_data;
+
+ for (j = 0; j < file_data->num_file_names; ++j)
+ {
+ const char *this_real_name;
+
+ if (need_fullname)
+ this_real_name = dw2_get_real_path (objfile, file_data, j);
+ else
+ this_real_name = NULL;
+ (*fun) (file_data->file_names[j], this_real_name, data);
+ }
+ }
+}
+
+static int
+dw2_has_symbols (struct objfile *objfile)
+{
+ return 1;
+}
+
+const struct quick_symbol_functions dwarf2_gdb_index_functions =
+{
+ dw2_has_symbols,
+ dw2_find_last_source_symtab,
+ dw2_forget_cached_source_info,
+ dw2_map_symtabs_matching_filename,
+ dw2_lookup_symbol,
+ dw2_print_stats,
+ dw2_dump,
+ dw2_relocate,
+ dw2_expand_symtabs_for_function,
+ dw2_expand_all_symtabs,
+ dw2_expand_symtabs_with_fullname,
+ dw2_map_matching_symbols,
+ dw2_expand_symtabs_matching,
+ dw2_find_pc_sect_compunit_symtab,
+ dw2_map_symbol_filenames
+};
+
+/* Symbol name hashing function as specified by DWARF-5. */
+
+static uint32_t
+dwarf5_djb_hash (const unsigned char *str)
+{
+ uint32_t hash = 5381;
+ while (int c = *str++)
+ {
+ /* FIXME: std::bad_cast for: std::tolower (c, std::locale::classic ())
+ FIXME: Is unicode supported for symbol names by GDB? */
+ hash = hash * 33 + tolower (c);
+ }
+ return hash;
+}
+
+/* Struct used to manage iterating over all CUs looking for a symbol
+ for .debug_names. */
+
+class dw2_debug_names_iterator
+{
+private:
+ /* The internalized form of .debug_names. */
+ const mapped_debug_names ↦
+ /* If true, only look for symbols that match BLOCK_INDEX. */
+ const bool want_specific_block = false;
+ /* One of GLOBAL_BLOCK or STATIC_BLOCK.
+ Unused if !WANT_SPECIFIC_BLOCK - FIRST_LOCAL_BLOCK is an invalid value. */
+ const block_enum block_index = FIRST_LOCAL_BLOCK;
+ /* The kind of symbol we're looking for. */
+ const domain_enum domain = UNDEF_DOMAIN;
+ const search_domain search = ALL_DOMAIN;
+ /* The list of CUs from the index entry of the symbol,
+ or NULL if not found. */
+ const gdb_byte *addr;
+ static const gdb_byte *find_vec_in_debug_names
+ (const mapped_debug_names &map, const char *name);
+ static const gdb_byte *find_vec_in_debug_names
+ (const mapped_debug_names &map, uint32_t namei);
+public:
+
+ /* If WANT_SPECIFIC_BLOCK is non-zero, only look for symbols
+ in block BLOCK_INDEX. Otherwise BLOCK_INDEX is ignored. */
+ dw2_debug_names_iterator
+ (const mapped_debug_names &map_, bool want_specific_block_,
+ block_enum block_index_, domain_enum domain_, const char *name)
+ : map (map_), want_specific_block (want_specific_block_),
+ block_index (block_index_), domain (domain_),
+ addr (find_vec_in_debug_names (map, name))
+ {
+ }
+
+ dw2_debug_names_iterator
+ (const mapped_debug_names &map_, search_domain search_, uint32_t namei)
+ : map (map_), search (search_), addr (find_vec_in_debug_names (map, namei))
+ {
+ }
+
+ /* Return the next matching CU or NULL if there are no more. */
+ dwarf2_per_cu_data *next ();
+};
+
+static const char *read_indirect_string_at_offset (bfd *abfd,
+ LONGEST str_offset);
+
+const char *
+mapped_debug_names::namei_to_name (uint32_t namei) 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
+ (dwarf2_per_objfile->objfile->obfd, 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)
+{
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+ int (*cmp) (const char *, const char *);
+
+ 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 .gdb_index does
+ not contain any. */
+
+ if (strchr (name, '(') != NULL)
+ {
+ char *without_params = cp_remove_params (name);
+
+ if (without_params != NULL)
+ {
+ make_cleanup (xfree, without_params);
+ name = without_params;
+ }
+ }
+ }
+
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+
+ const uint32_t full_hash
+ (dwarf5_djb_hash (reinterpret_cast<const unsigned char *> (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)
+ {
+ do_cleanups (back_to);
+ return NULL;
+ }
+ --namei;
+ if (namei >= map.name_count)
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names with name index %u but name_count=%u "
+ "[in module %s]"),
+ namei, map.name_count,
+ objfile_name (dwarf2_per_objfile->objfile));
+ do_cleanups (back_to);
+ 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)
+ {
+ do_cleanups (back_to);
+ return NULL;
+ }
+
+ if (full_hash == namei_full_hash)
+ {
+ const char *const namei_string (map.namei_to_name (namei));
+
+#if 0 /* An expensive sanity check. */
+ if (namei_full_hash != dwarf5_djb_hash
+ (reinterpret_cast<const unsigned char *> (namei_string)))
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names hash for string at index %u "
+ "[in module %s]"),
+ namei, objfile_name (dwarf2_per_objfile->objfile));
+ do_cleanups (back_to);
+ 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));
+ do_cleanups (back_to);
+ return map.entry_pool + namei_entry_offs;
+ }
+ }
+
+ ++namei;
+ if (namei >= map.name_count)
+ {
+ do_cleanups (back_to);
+ return NULL;
}
}
}
-/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific
- symtab. */
-
-static struct compunit_symtab *
-recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust,
- CORE_ADDR pc)
+const gdb_byte *
+dw2_debug_names_iterator::find_vec_in_debug_names
+ (const mapped_debug_names &map, uint32_t namei)
{
- int i;
+ if (namei >= map.name_count)
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names with name index %u but name_count=%u "
+ "[in module %s]"),
+ namei, map.name_count,
+ objfile_name (dwarf2_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;
+}
- if (COMPUNIT_BLOCKVECTOR (cust) != NULL
- && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc))
- return cust;
+/* See dw2_debug_names_iterator. */
- if (cust->includes == NULL)
+dwarf2_per_cu_data *
+dw2_debug_names_iterator::next ()
+{
+ if (addr == NULL)
return NULL;
+ bfd *const abfd (dwarf2_per_objfile->objfile->obfd);
+ unsigned int bytes_read;
+ const ULONGEST abbrev (read_unsigned_leb128 (abfd, addr, &bytes_read));
+ addr += bytes_read;
+ if (abbrev == 0)
+ return NULL;
+ const auto indexval_it (map.abbrev_map.find (abbrev));
+ if (indexval_it == map.abbrev_map.cend ())
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names undefined abbrev code %s "
+ "[in module %s]"),
+ pulongest (abbrev), objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+ const mapped_debug_names::index_val &indexval (indexval_it->second);
+ bool have_is_static (false);
+ bool is_static;
+ 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, addr, &bytes_read);
+ addr += bytes_read;
+ break;
+ default:
+ complaint (&symfile_complaints,
+ _("Unsupported .debug_names form %s [in module %s]"),
+ dwarf_form_name (attr.form),
+ objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+ switch (attr.dw_idx)
+ {
+ case DW_IDX_compile_unit:
+ /* Don't crash on bad data. */
+ if (ull >= (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_units))
+ {
+ complaint (&symfile_complaints,
+ _(".gdb_index entry has bad CU index %s"
+ " [in module %s]"),
+ pulongest (ull),
+ objfile_name (dwarf2_per_objfile->objfile));
+ continue;
+ }
+ per_cu = dw2_get_cutu (ull);
+ break;
+ case DW_IDX_GNU_static:
+ if (!map.augmentation_is_gdb)
+ break;
+ have_is_static = true;
+ is_static = true;
+ break;
+ case DW_IDX_GNU_external:
+ if (!map.augmentation_is_gdb)
+ break;
+ have_is_static = true;
+ is_static = false;
+ break;
+ }
+ }
- for (i = 0; cust->includes[i]; ++i)
+ /* Skip if already read in. */
+ if (per_cu->v.quick->compunit_symtab)
+ return next ();
+
+ /* Check static vs global. */
+ if (have_is_static)
{
- struct compunit_symtab *s = cust->includes[i];
+ const bool want_static (block_index != GLOBAL_BLOCK);
+ if (want_specific_block && want_static != is_static)
+ return next ();
+ }
- s = recursively_find_pc_sect_compunit_symtab (s, pc);
- if (s != NULL)
- return s;
+ /* Match dw2_symtab_iter_next, symbol_kind
+ and DebugNamesNameTable::psymbol_tag. */
+ switch (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:
+ return next ();
+ }
+ break;
+ case STRUCT_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_structure_type:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ case LABEL_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case 0:
+ case DW_TAG_variable:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ default:
+ break;
}
- return NULL;
+ /* Match dw2_expand_symtabs_matching, symbol_kind
+ and DebugNamesNameTable::psymbol_tag. */
+ switch (search)
+ {
+ case VARIABLES_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_variable:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ case FUNCTIONS_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_subprogram:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ case TYPES_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_structure_type:
+ break;
+ default:
+ return next ();
+ }
+ break;
+ default:
+ break;
+ }
+
+ return per_cu;
}
static struct compunit_symtab *
-dw2_find_pc_sect_compunit_symtab (struct objfile *objfile,
- struct bound_minimal_symbol msymbol,
- CORE_ADDR pc,
- struct obj_section *section,
- int warn_if_readin)
+dw2_debug_names_lookup_symbol (struct objfile *objfile, int block_index_int,
+ const char *name, domain_enum domain)
{
- struct dwarf2_per_cu_data *data;
- struct compunit_symtab *result;
-
+ const block_enum block_index (static_cast<block_enum> (block_index_int));
dw2_setup (objfile);
- if (!objfile->psymtabs_addrmap)
- return NULL;
+ const auto &mapp (dwarf2_per_objfile->debug_names_table);
+ if (!mapp)
+ {
+ /* index is NULL if OBJF_READNOW. */
+ return NULL;
+ }
+ const auto &map (*mapp);
- data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap,
- pc);
- if (!data)
- return NULL;
+ dw2_debug_names_iterator iter (map, 1 /* want_specific_block */, block_index,
+ domain, name);
- if (warn_if_readin && data->v.quick->compunit_symtab)
- warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
- paddress (get_objfile_arch (objfile), pc));
+ struct compunit_symtab *stab_best = NULL;
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ {
+ struct symbol *sym, *with_opaque = NULL;
+ struct compunit_symtab *stab = dw2_instantiate_symtab (per_cu);
+ const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (stab);
+ struct block *block = BLOCKVECTOR_BLOCK (bv, block_index);
- result
- = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data),
- pc);
- gdb_assert (result != NULL);
- return result;
+ sym = block_find_symbol (block, name, domain,
+ block_find_non_opaque_type_preferred,
+ &with_opaque);
+
+ /* Some caution must be observed with overloaded functions
+ and methods, since the index will not contain any overload
+ information (but NAME might contain it). */
+
+ if (sym != NULL
+ && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
+ return stab;
+ if (with_opaque != NULL
+ && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0)
+ stab_best = stab;
+
+ /* Keep looking through other CUs. */
+ }
+
+ return stab_best;
}
+/* This dumps minimal information about .debug_names.
+ It is called via "mt print objfiles".
+ One use is to verify .debug_names has been loaded by the
+ gdb.dwarf2/gdb-index.exp testcase. */
+
static void
-dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun,
- void *data, int need_fullname)
+dw2_debug_names_dump (struct objfile *objfile)
{
- int i;
- htab_up visited (htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer,
- NULL, xcalloc, xfree));
-
dw2_setup (objfile);
+ gdb_assert (dwarf2_per_objfile->using_index);
+ printf_filtered (".debug_names:");
+ if (dwarf2_per_objfile->debug_names_table)
+ printf_filtered (" exists\n");
+ else
+ printf_filtered (" faked for \"readnow\"\n");
+ printf_filtered ("\n");
+}
- /* The rule is CUs specify all the files, including those used by
- any TU, so there's no need to scan TUs here.
- We can ignore file names coming from already-expanded CUs. */
+static void
+dw2_debug_names_expand_symtabs_for_function (struct objfile *objfile,
+ const char *func_name)
+{
+ struct mapped_index *index;
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ dw2_setup (objfile);
+
+ /* dwarf2_per_objfile->debug_names_table is NULL if OBJF_READNOW. */
+ if (dwarf2_per_objfile->debug_names_table)
{
- struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
+ const mapped_debug_names &map (*dwarf2_per_objfile->debug_names_table);
- if (per_cu->v.quick->compunit_symtab)
- {
- void **slot = htab_find_slot (visited.get (),
- per_cu->v.quick->file_names,
- INSERT);
+ /* Note: It doesn't matter what we pass for block_index here. */
+ dw2_debug_names_iterator iter (map, 0 /* want_specific_block */,
+ GLOBAL_BLOCK, VAR_DOMAIN, func_name);
- *slot = per_cu->v.quick->file_names;
- }
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ dw2_instantiate_symtab (per_cu);
}
+}
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+static void
+dw2_debug_names_expand_symtabs_matching
+ (struct objfile *objfile,
+ gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
+ gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
+ gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
+ enum search_domain kind)
+{
+ dw2_setup (objfile);
+
+ /* debug_names_table is NULL if OBJF_READNOW. */
+ if (!dwarf2_per_objfile->debug_names_table)
+ return;
+ const mapped_debug_names &map (*dwarf2_per_objfile->debug_names_table);
+
+ dw_expand_symtabs_matching_file_matcher (file_matcher);
+
+ for (uint32_t namei = 0; namei < map.name_count; ++namei)
{
- int j;
- struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
- struct quick_file_names *file_data;
- void **slot;
+ const char *name;
+ offset_type *vec, vec_len, vec_idx;
+ int global_seen = 0;
- /* We only need to look at symtabs not already expanded. */
- if (per_cu->v.quick->compunit_symtab)
- continue;
+ QUIT;
- file_data = dw2_get_file_names (per_cu);
- if (file_data == NULL)
+ const char *const namei_string (map.namei_to_name (namei));
+ if (!symbol_matcher (namei_string))
continue;
- slot = htab_find_slot (visited.get (), file_data, INSERT);
- if (*slot)
- {
- /* Already visited. */
- continue;
- }
- *slot = file_data;
-
- for (j = 0; j < file_data->num_file_names; ++j)
- {
- const char *this_real_name;
+ /* The name was matched, now expand corresponding CUs that were
+ marked. */
+ dw2_debug_names_iterator iter (map, kind, namei);
- if (need_fullname)
- this_real_name = dw2_get_real_path (objfile, file_data, j);
- else
- this_real_name = NULL;
- (*fun) (file_data->file_names[j], this_real_name, data);
- }
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+ expansion_notify);
}
}
-static int
-dw2_has_symbols (struct objfile *objfile)
-{
- return 1;
-}
-
-const struct quick_symbol_functions dwarf2_gdb_index_functions =
+const struct quick_symbol_functions dwarf2_debug_names_functions =
{
dw2_has_symbols,
dw2_find_last_source_symtab,
dw2_forget_cached_source_info,
dw2_map_symtabs_matching_filename,
- dw2_lookup_symbol,
+ dw2_debug_names_lookup_symbol,
dw2_print_stats,
- dw2_dump,
+ dw2_debug_names_dump,
dw2_relocate,
- dw2_expand_symtabs_for_function,
+ dw2_debug_names_expand_symtabs_for_function,
dw2_expand_all_symtabs,
dw2_expand_symtabs_with_fullname,
dw2_map_matching_symbols,
- dw2_expand_symtabs_matching,
+ dw2_debug_names_expand_symtabs_matching,
dw2_find_pc_sect_compunit_symtab,
dw2_map_symbol_filenames
};
@@ -4425,6 +5538,9 @@ dwarf2_initialize_objfile (struct objfile *objfile)
return elf_sym_fns_gdb_index;
}
+ if (dwarf2_read_debug_names (objfile))
+ return elf_sym_fns_debug_names;
+
if (dwarf2_read_index (objfile))
return elf_sym_fns_gdb_index;
@@ -22903,6 +24019,8 @@ dwarf2_free_objfile (struct objfile *objfile)
htab_delete (dwarf2_per_objfile->line_header_hash);
/* Everything else should be on the objfile obstack. */
+
+ delete dwarf2_per_objfile->debug_names_table;
}
/* A set of CU "per_cu" pointer, DIE offset, and GDB type pointer.
@@ -23897,7 +25015,7 @@ public:
const char *const name (it->first);
const unsigned char *const nameuc
(reinterpret_cast<const unsigned char *> (name));
- const uint32_t hash (djb_hash (nameuc));
+ const uint32_t hash (dwarf5_djb_hash (nameuc));
hash_it_pair hashitpair;
hashitpair.hash = hash;
hashitpair.it = it;
@@ -24269,19 +25387,6 @@ private:
m_name_table_entry_offs;
};
- /* Symbol name hashing function as specified by DWARF-5. */
- static uint32_t djb_hash (const unsigned char *str)
- {
- uint32_t hash = 5381;
- while (int c = *str++)
- {
- /* FIXME: std::bad_cast for: std::tolower (c, std::locale::classic ())
- FIXME: Is unicode supported for symbol names by GDB? */
- hash = hash * 33 + tolower (c);
- }
- return hash;
- }
-
/* Try to reconstruct original DWARF tag for given partial_symbol.
This function is not DWARF-5 compliant but it is sufficient for GDB
as a DWARF-5 index consumer. */
@@ -24575,9 +25680,9 @@ write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
to_underlying (per_cu.sect_off));
}
- const gdb_byte augmentation[] = { 'G', 'D', 'B', 0 };
const offset_type bytes_of_header ((dwarf5_is_dwarf64 ? 12 : 4)
- + 2 + 2 + 7 * 4 + sizeof (augmentation));
+ + 2 + 2 + 7 * 4
+ + sizeof (dwarf5_augmentation));
size_t expected_bytes (0);
expected_bytes += bytes_of_header;
expected_bytes += cu_list.size ();
@@ -24627,9 +25732,9 @@ write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
/* augmentation_string_size - The size in bytes of the augmentation
string. This value is rounded up to a multiple of 4. */
- static_assert (sizeof (augmentation) % 4 == 0);
- header.append_uint (4, dwarf5_byte_order, sizeof (augmentation));
- header.append_data (augmentation);
+ static_assert (sizeof (dwarf5_augmentation) % 4 == 0);
+ header.append_uint (4, dwarf5_byte_order, sizeof (dwarf5_augmentation));
+ header.append_data (dwarf5_augmentation);
gdb_assert (header.size () == bytes_of_header);
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 9ae0432..6f992d7 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -1431,6 +1431,23 @@ const struct sym_fns elf_sym_fns_gdb_index =
&dwarf2_gdb_index_functions
};
+/* The same as elf_sym_fns, but not registered and uses the
+ DWARF-specific .debug_names index rather than psymtab. */
+const struct sym_fns elf_sym_fns_debug_names =
+{
+ elf_new_init, /* init anything gbl to entire symab */
+ elf_symfile_init, /* read initial info, setup for sym_red() */
+ elf_symfile_read, /* read a symbol file into symtab */
+ NULL, /* sym_read_psymbols */
+ elf_symfile_finish, /* finished with file, cleanup */
+ default_symfile_offsets, /* Translate ext. to int. relocatin */
+ elf_symfile_segments, /* Get segment information from a file. */
+ NULL,
+ default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
+ &dwarf2_debug_names_functions
+};
+
/* STT_GNU_IFUNC resolver vector to be installed to gnu_ifunc_fns_p. */
static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
diff --git a/gdb/psymtab.h b/gdb/psymtab.h
index f0c9ae7..17ceb22 100644
--- a/gdb/psymtab.h
+++ b/gdb/psymtab.h
@@ -33,6 +33,7 @@ extern struct bcache *psymbol_bcache_get_bcache (struct psymbol_bcache *);
extern const struct quick_symbol_functions psym_functions;
extern const struct quick_symbol_functions dwarf2_gdb_index_functions;
+extern const struct quick_symbol_functions dwarf2_debug_names_functions;
/* Ensure that the partial symbols for OBJFILE have been loaded. If
VERBOSE is non-zero, then this will print a message when symbols
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 8e51d41..847358f 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -606,6 +606,8 @@ struct dwarf2_debug_sections {
struct dwarf2_section_names frame;
struct dwarf2_section_names eh_frame;
struct dwarf2_section_names gdb_index;
+ struct dwarf2_section_names debug_names;
+ struct dwarf2_section_names debug_aranges;
/* This field has no meaning, but exists solely to catch changes to
this structure which are not reflected in some instance. */
int sentinel;
diff --git a/gdb/testsuite/gdb.base/maint.exp b/gdb/testsuite/gdb.base/maint.exp
index 782a21c..8e79451 100644
--- a/gdb/testsuite/gdb.base/maint.exp
+++ b/gdb/testsuite/gdb.base/maint.exp
@@ -91,8 +91,11 @@ if ![runto_main] then {
# If we're using .gdb_index there will be no psymtabs.
set have_gdb_index 0
-gdb_test_multiple "maint info sections .gdb_index" "check for .gdb_index" {
- -re ": .gdb_index.*$gdb_prompt $" {
+gdb_test_multiple "maint info sections .gdb_index .debug_names" "check for .gdb_index" {
+ -re ": \\.gdb_index .*\r\n$gdb_prompt $" {
+ set have_gdb_index 1
+ }
+ -re ": \\.debug_names .*\r\n$gdb_prompt $" {
set have_gdb_index 1
}
-re ".*$gdb_prompt $" {
diff --git a/gdb/testsuite/gdb.dlang/watch-loc.c b/gdb/testsuite/gdb.dlang/watch-loc.c
index 0ffc377..a1f3caa 100644
--- a/gdb/testsuite/gdb.dlang/watch-loc.c
+++ b/gdb/testsuite/gdb.dlang/watch-loc.c
@@ -34,3 +34,22 @@ main (void)
return _Dmain ();
}
+// .gdb_index contained this map but .debug_names is generated by GDB
+// while it depends on .debug_aranges generated by GCC.
+asm (
+" .pushsection .debug_aranges,\"\",@progbits \n"
+" .4byte .Laranges_end - .Laranges_start \n" // Length of Address Ranges Info
+".Laranges_start: \n"
+" .2byte 0x2 \n" // DWARF Version
+" .4byte 0 \n" // .Ldebug_info0 - Offset of Compilation Unit Info
+" .byte 4 \n" // Size of Address
+" .byte 0 \n" // Size of Segment Descriptor
+" .2byte 0 \n" // Pad to 16 byte boundary
+" .2byte 0 \n"
+" .4byte _Dmain \n" // Address
+" .4byte 0x1000 \n" // Length
+" .4byte 0 \n"
+" .4byte 0 \n"
+".Laranges_end: \n"
+" .popsection \n"
+);
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
index 3bbd725..5a968bd 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
+++ b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
@@ -57,6 +57,23 @@
.byte 0 /* End of children of CU */
.Lcu1_end:
+ // .gdb_index contained this map but .debug_names is generated by GDB
+ // while it depends on .debug_aranges generated by GCC.
+ .section .debug_aranges,"",@progbits
+ .4byte .Laranges_end - .Laranges_start // Length of Address Ranges Info
+.Laranges_start:
+ .2byte 0x2 // DWARF Version
+ .4byte 0 // .Ldebug_info0 - Offset of Compilation Unit Info
+ .byte PTRBITS / 8 // Size of Address
+ .byte 0 // Size of Segment Descriptor
+ .2byte 0 // Pad to 16 byte boundary
+ .2byte 0
+ PTRBYTE cu_text_start // Address
+ PTRBYTE 0x1000 // cu_text_end - cu_text_start // Length
+ PTRBYTE 0
+ PTRBYTE 0
+.Laranges_end:
+
/* Abbrev table */
.section .debug_abbrev
.Labbrev1_begin:
diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index.exp b/gdb/testsuite/gdb.dwarf2/gdb-index.exp
index c925b1e..54725cd 100644
--- a/gdb/testsuite/gdb.dwarf2/gdb-index.exp
+++ b/gdb/testsuite/gdb.dwarf2/gdb-index.exp
@@ -67,6 +67,9 @@ gdb_test_multiple "mt print objfiles ${testfile}" $test {
-re "gdb_index.*${gdb_prompt} $" {
set binfile_with_index $binfile
}
+ -re "debug_names.*${gdb_prompt} $" {
+ set binfile_with_index $binfile
+ }
-re "Psymtabs.*${gdb_prompt} $" {
set binfile_with_index [add_gdb_index $binfile]
if { ${binfile_with_index} == "" } {
@@ -80,7 +83,7 @@ gdb_test_multiple "mt print objfiles ${testfile}" $test {
clean_restart ${binfile_with_index}
gdb_test "mt print objfiles ${testfile}" \
- "gdb_index.*" \
+ "(gdb_index|debug_names).*" \
".gdb_index used"
# Make gdb re-read symbols and see if .gdb_index still gets used.
@@ -98,5 +101,5 @@ if ![runto_main] {
return -1
}
gdb_test "mt print objfiles ${testfile}" \
- "gdb_index.*" \
+ "(gdb_index|debug_names).*" \
".gdb_index used after symbol reloading"
diff --git a/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c b/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c
index 0c2a153..bf1fea6 100644
--- a/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c
+++ b/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c
@@ -52,3 +52,23 @@ asm ("func_loopfb_end:");
asm (".globl cu_text_end");
asm ("cu_text_end:");
+
+// .gdb_index contained this map but .debug_names is generated by GDB
+// while it depends on .debug_aranges generated by GCC.
+asm (
+" .pushsection .debug_aranges,\"\",@progbits \n"
+" .4byte .Laranges_end - .Laranges_start \n" // Length of Address Ranges Info
+".Laranges_start: \n"
+" .2byte 0x2 \n" // DWARF Version
+" .4byte 0 \n" // .Ldebug_info0 - Offset of Compilation Unit Info
+" .byte 4 \n" // Size of Address
+" .byte 0 \n" // Size of Segment Descriptor
+" .2byte 0 \n" // Pad to 16 byte boundary
+" .2byte 0 \n"
+" .4byte cu_text_start \n" // Address
+" .4byte cu_text_end - cu_text_start \n" // Length
+" .4byte 0 \n"
+" .4byte 0 \n"
+".Laranges_end: \n"
+" .popsection \n"
+);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 138f941..e6298b4 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -174,6 +174,8 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_names = {
{ ".dwframe", NULL },
{ NULL, NULL }, /* eh_frame */
{ NULL, NULL }, /* gdb_index */
+ { NULL, NULL }, /* debug_names */
+ { NULL, NULL }, /* debug_aranges */
23
};
--
2.9.4
--- End Message ---