| /* DWARF 2 debugging format support for GDB. |
| |
| Copyright (C) 1994-2024 Free Software Foundation, Inc. |
| |
| Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, |
| Inc. with support from Florida State University (under contract |
| with the Ada Joint Program Office), and Silicon Graphics, Inc. |
| Initial contribution by Brent Benson, Harris Computer Systems, Inc., |
| based on Fred Fish's (Cygnus Support) implementation of DWARF 1 |
| support. |
| |
| 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/>. */ |
| |
| /* FIXME: Various die-reading functions need to be more careful with |
| reading off the end of the section. */ |
| |
| #include "dwarf2/read.h" |
| #include "dwarf2/abbrev.h" |
| #include "dwarf2/aranges.h" |
| #include "dwarf2/attribute.h" |
| #include "dwarf2/comp-unit-head.h" |
| #include "dwarf2/cu.h" |
| #include "dwarf2/index-cache.h" |
| #include "dwarf2/index-common.h" |
| #include "dwarf2/leb.h" |
| #include "dwarf2/line-header.h" |
| #include "dwarf2/dwz.h" |
| #include "dwarf2/macro.h" |
| #include "dwarf2/die.h" |
| #include "dwarf2/read-debug-names.h" |
| #include "dwarf2/read-gdb-index.h" |
| #include "dwarf2/sect-names.h" |
| #include "dwarf2/stringify.h" |
| #include "dwarf2/public.h" |
| #include "bfd.h" |
| #include "elf-bfd.h" |
| #include "event-top.h" |
| #include "gdbsupport/task-group.h" |
| #include "symtab.h" |
| #include "gdbtypes.h" |
| #include "objfiles.h" |
| #include "dwarf2.h" |
| #include "demangle.h" |
| #include "gdb-demangle.h" |
| #include "filenames.h" |
| #include "language.h" |
| #include "complaints.h" |
| #include "dwarf2/expr.h" |
| #include "dwarf2/loc.h" |
| #include "cp-support.h" |
| #include "hashtab.h" |
| #include "command.h" |
| #include "cli/cli-cmds.h" |
| #include "block.h" |
| #include "addrmap.h" |
| #include "typeprint.h" |
| #include "c-lang.h" |
| #include "go-lang.h" |
| #include "valprint.h" |
| #include "gdbcore.h" |
| #include "gdb_bfd.h" |
| #include "f-lang.h" |
| #include "source.h" |
| #include "build-id.h" |
| #include "namespace.h" |
| #include "gdbsupport/function-view.h" |
| #include <optional> |
| #include "gdbsupport/underlying.h" |
| #include "gdbsupport/hash_enum.h" |
| #include "filename-seen-cache.h" |
| #include "producer.h" |
| #include <fcntl.h> |
| #include <algorithm> |
| #include <unordered_map> |
| #include "gdbsupport/selftest.h" |
| #include "rust-lang.h" |
| #include "gdbsupport/pathstuff.h" |
| #include "count-one-bits.h" |
| #include <unordered_set> |
| #include "dwarf2/abbrev-cache.h" |
| #include "cooked-index.h" |
| #include "gdbsupport/thread-pool.h" |
| #include "run-on-main-thread.h" |
| #include "dwarf2/parent-map.h" |
| #include "dwarf2/error.h" |
| |
| /* When == 1, print basic high level tracing messages. |
| When > 1, be more verbose. |
| This is in contrast to the low level DIE reading of dwarf_die_debug. */ |
| static unsigned int dwarf_read_debug = 0; |
| |
| /* Print a "dwarf-read" debug statement if dwarf_read_debug is >= 1. */ |
| |
| #define dwarf_read_debug_printf(fmt, ...) \ |
| debug_prefixed_printf_cond (dwarf_read_debug >= 1, "dwarf-read", fmt, \ |
| ##__VA_ARGS__) |
| |
| /* Print a "dwarf-read" debug statement if dwarf_read_debug is >= 2. */ |
| |
| #define dwarf_read_debug_printf_v(fmt, ...) \ |
| debug_prefixed_printf_cond (dwarf_read_debug >= 2, "dwarf-read", fmt, \ |
| ##__VA_ARGS__) |
| |
| /* When non-zero, dump DIEs after they are read in. */ |
| static unsigned int dwarf_die_debug = 0; |
| |
| /* When non-zero, dump line number entries as they are read in. */ |
| unsigned int dwarf_line_debug = 0; |
| |
| /* When true, cross-check physname against demangler. */ |
| static bool check_physname = false; |
| |
| /* This is used to store the data that is always per objfile. */ |
| static const registry<objfile>::key<dwarf2_per_objfile> |
| dwarf2_objfile_data_key; |
| |
| /* These are used to store the dwarf2_per_bfd objects. |
| |
| objfiles having the same BFD, which doesn't require relocations, are going to |
| share a dwarf2_per_bfd object, which is held in the _bfd_data_key version. |
| |
| Other objfiles are not going to share a dwarf2_per_bfd with any other |
| objfiles, so they'll have their own version kept in the _objfile_data_key |
| version. */ |
| static const registry<bfd>::key<dwarf2_per_bfd> dwarf2_per_bfd_bfd_data_key; |
| static const registry<objfile>::key<dwarf2_per_bfd> |
| dwarf2_per_bfd_objfile_data_key; |
| |
| /* The "aclass" indices for various kinds of computed DWARF symbols. */ |
| |
| static int dwarf2_locexpr_index; |
| static int dwarf2_loclist_index; |
| static int ada_imported_index; |
| static int dwarf2_locexpr_block_index; |
| static int dwarf2_loclist_block_index; |
| static int ada_block_index; |
| |
| static bool producer_is_gas_lt_2_38 (struct dwarf2_cu *cu); |
| static bool producer_is_gas_ge_2_39 (struct dwarf2_cu *cu); |
| |
| /* Size of .debug_loclists section header for 32-bit DWARF format. */ |
| #define LOCLIST_HEADER_SIZE32 12 |
| |
| /* Size of .debug_loclists section header for 64-bit DWARF format. */ |
| #define LOCLIST_HEADER_SIZE64 20 |
| |
| /* Size of .debug_rnglists section header for 32-bit DWARF format. */ |
| #define RNGLIST_HEADER_SIZE32 12 |
| |
| /* Size of .debug_rnglists section header for 64-bit DWARF format. */ |
| #define RNGLIST_HEADER_SIZE64 20 |
| |
| /* See dwarf2/read.h. */ |
| |
| dwarf2_per_objfile * |
| get_dwarf2_per_objfile (struct objfile *objfile) |
| { |
| return dwarf2_objfile_data_key.get (objfile); |
| } |
| |
| /* Default names of the debugging sections. */ |
| |
| /* Note that if the debugging section has been compressed, it might |
| have a name like .zdebug_info. */ |
| |
| const struct dwarf2_debug_sections dwarf2_elf_names = |
| { |
| { ".debug_info", ".zdebug_info" }, |
| { ".debug_abbrev", ".zdebug_abbrev" }, |
| { ".debug_line", ".zdebug_line" }, |
| { ".debug_loc", ".zdebug_loc" }, |
| { ".debug_loclists", ".zdebug_loclists" }, |
| { ".debug_macinfo", ".zdebug_macinfo" }, |
| { ".debug_macro", ".zdebug_macro" }, |
| { ".debug_str", ".zdebug_str" }, |
| { ".debug_str_offsets", ".zdebug_str_offsets" }, |
| { ".debug_line_str", ".zdebug_line_str" }, |
| { ".debug_ranges", ".zdebug_ranges" }, |
| { ".debug_rnglists", ".zdebug_rnglists" }, |
| { ".debug_types", ".zdebug_types" }, |
| { ".debug_addr", ".zdebug_addr" }, |
| { ".debug_frame", ".zdebug_frame" }, |
| { ".eh_frame", NULL }, |
| { ".gdb_index", ".zgdb_index" }, |
| { ".debug_names", ".zdebug_names" }, |
| { ".debug_aranges", ".zdebug_aranges" }, |
| 23 |
| }; |
| |
| /* List of DWO/DWP sections. */ |
| |
| static const struct dwop_section_names |
| { |
| struct dwarf2_section_names abbrev_dwo; |
| struct dwarf2_section_names info_dwo; |
| struct dwarf2_section_names line_dwo; |
| struct dwarf2_section_names loc_dwo; |
| struct dwarf2_section_names loclists_dwo; |
| struct dwarf2_section_names macinfo_dwo; |
| struct dwarf2_section_names macro_dwo; |
| struct dwarf2_section_names rnglists_dwo; |
| struct dwarf2_section_names str_dwo; |
| struct dwarf2_section_names str_offsets_dwo; |
| struct dwarf2_section_names types_dwo; |
| struct dwarf2_section_names cu_index; |
| struct dwarf2_section_names tu_index; |
| } |
| dwop_section_names = |
| { |
| { ".debug_abbrev.dwo", ".zdebug_abbrev.dwo" }, |
| { ".debug_info.dwo", ".zdebug_info.dwo" }, |
| { ".debug_line.dwo", ".zdebug_line.dwo" }, |
| { ".debug_loc.dwo", ".zdebug_loc.dwo" }, |
| { ".debug_loclists.dwo", ".zdebug_loclists.dwo" }, |
| { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo" }, |
| { ".debug_macro.dwo", ".zdebug_macro.dwo" }, |
| { ".debug_rnglists.dwo", ".zdebug_rnglists.dwo" }, |
| { ".debug_str.dwo", ".zdebug_str.dwo" }, |
| { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo" }, |
| { ".debug_types.dwo", ".zdebug_types.dwo" }, |
| { ".debug_cu_index", ".zdebug_cu_index" }, |
| { ".debug_tu_index", ".zdebug_tu_index" }, |
| }; |
| |
| /* local data types */ |
| |
| /* The location list and range list sections (.debug_loclists & .debug_rnglists) |
| begin with a header, which contains the following information. */ |
| struct loclists_rnglists_header |
| { |
| /* A 4-byte or 12-byte length containing the length of the |
| set of entries for this compilation unit, not including the |
| length field itself. */ |
| unsigned int length; |
| |
| /* A 2-byte version identifier. */ |
| short version; |
| |
| /* A 1-byte unsigned integer containing the size in bytes of an address on |
| the target system. */ |
| unsigned char addr_size; |
| |
| /* A 1-byte unsigned integer containing the size in bytes of a segment selector |
| on the target system. */ |
| unsigned char segment_collector_size; |
| |
| /* A 4-byte count of the number of offsets that follow the header. */ |
| unsigned int offset_entry_count; |
| }; |
| |
| /* A struct that can be used as a hash key for tables based on DW_AT_stmt_list. |
| This includes type_unit_group and quick_file_names. */ |
| |
| struct stmt_list_hash |
| { |
| /* The DWO unit this table is from or NULL if there is none. */ |
| struct dwo_unit *dwo_unit; |
| |
| /* Offset in .debug_line or .debug_line.dwo. */ |
| sect_offset line_sect_off; |
| }; |
| |
| /* Each element of dwarf2_per_bfd->type_unit_groups is a pointer to |
| an object of this type. This contains elements of type unit groups |
| that can be shared across objfiles. The non-shareable parts are in |
| type_unit_group_unshareable. */ |
| |
| struct type_unit_group |
| { |
| /* The data used to construct the hash key. */ |
| struct stmt_list_hash hash {}; |
| }; |
| |
| /* These sections are what may appear in a (real or virtual) DWO file. */ |
| |
| struct dwo_sections |
| { |
| struct dwarf2_section_info abbrev; |
| struct dwarf2_section_info line; |
| struct dwarf2_section_info loc; |
| struct dwarf2_section_info loclists; |
| struct dwarf2_section_info macinfo; |
| struct dwarf2_section_info macro; |
| struct dwarf2_section_info rnglists; |
| struct dwarf2_section_info str; |
| struct dwarf2_section_info str_offsets; |
| /* In the case of a virtual DWO file, these two are unused. */ |
| struct dwarf2_section_info info; |
| std::vector<dwarf2_section_info> types; |
| }; |
| |
| /* CUs/TUs in DWP/DWO files. */ |
| |
| struct dwo_unit |
| { |
| /* Backlink to the containing struct dwo_file. */ |
| struct dwo_file *dwo_file; |
| |
| /* The "id" that distinguishes this CU/TU. |
| .debug_info calls this "dwo_id", .debug_types calls this "signature". |
| Since signatures came first, we stick with it for consistency. */ |
| ULONGEST signature; |
| |
| /* The section this CU/TU lives in, in the DWO file. */ |
| struct dwarf2_section_info *section; |
| |
| /* Same as dwarf2_per_cu_data:{sect_off,length} but in the DWO section. */ |
| sect_offset sect_off; |
| unsigned int length; |
| |
| /* For types, offset in the type's DIE of the type defined by this TU. */ |
| cu_offset type_offset_in_tu; |
| }; |
| |
| /* include/dwarf2.h defines the DWP section codes. |
| It defines a max value but it doesn't define a min value, which we |
| use for error checking, so provide one. */ |
| |
| enum dwp_v2_section_ids |
| { |
| DW_SECT_MIN = 1 |
| }; |
| |
| /* Data for one DWO file. |
| |
| This includes virtual DWO files (a virtual DWO file is a DWO file as it |
| appears in a DWP file). DWP files don't really have DWO files per se - |
| comdat folding of types "loses" the DWO file they came from, and from |
| a high level view DWP files appear to contain a mass of random types. |
| However, to maintain consistency with the non-DWP case we pretend DWP |
| files contain virtual DWO files, and we assign each TU with one virtual |
| DWO file (generally based on the line and abbrev section offsets - |
| a heuristic that seems to work in practice). */ |
| |
| struct dwo_file |
| { |
| dwo_file () = default; |
| DISABLE_COPY_AND_ASSIGN (dwo_file); |
| |
| /* The DW_AT_GNU_dwo_name or DW_AT_dwo_name attribute. |
| For virtual DWO files the name is constructed from the section offsets |
| of abbrev,line,loc,str_offsets so that we combine virtual DWO files |
| from related CU+TUs. */ |
| std::string dwo_name; |
| |
| /* The DW_AT_comp_dir attribute. */ |
| const char *comp_dir = nullptr; |
| |
| /* The bfd, when the file is open. Otherwise this is NULL. |
| This is unused(NULL) for virtual DWO files where we use dwp_file.dbfd. */ |
| gdb_bfd_ref_ptr dbfd; |
| |
| /* The sections that make up this DWO file. |
| Remember that for virtual DWO files in DWP V2 or DWP V5, these are virtual |
| sections (for lack of a better name). */ |
| struct dwo_sections sections {}; |
| |
| /* The CUs in the file. |
| Each element is a struct dwo_unit. Multiple CUs per DWO are supported as |
| an extension to handle LLVM's Link Time Optimization output (where |
| multiple source files may be compiled into a single object/dwo pair). */ |
| htab_up cus; |
| |
| /* Table of TUs in the file. |
| Each element is a struct dwo_unit. */ |
| htab_up tus; |
| }; |
| |
| /* These sections are what may appear in a DWP file. */ |
| |
| struct dwp_sections |
| { |
| /* These are used by all DWP versions (1, 2 and 5). */ |
| struct dwarf2_section_info str; |
| struct dwarf2_section_info cu_index; |
| struct dwarf2_section_info tu_index; |
| |
| /* These are only used by DWP version 2 and version 5 files. |
| In DWP version 1 the .debug_info.dwo, .debug_types.dwo, and other |
| sections are referenced by section number, and are not recorded here. |
| In DWP version 2 or 5 there is at most one copy of all these sections, |
| each section being (effectively) comprised of the concatenation of all of |
| the individual sections that exist in the version 1 format. |
| To keep the code simple we treat each of these concatenated pieces as a |
| section itself (a virtual section?). */ |
| struct dwarf2_section_info abbrev; |
| struct dwarf2_section_info info; |
| struct dwarf2_section_info line; |
| struct dwarf2_section_info loc; |
| struct dwarf2_section_info loclists; |
| struct dwarf2_section_info macinfo; |
| struct dwarf2_section_info macro; |
| struct dwarf2_section_info rnglists; |
| struct dwarf2_section_info str_offsets; |
| struct dwarf2_section_info types; |
| }; |
| |
| /* These sections are what may appear in a virtual DWO file in DWP version 1. |
| A virtual DWO file is a DWO file as it appears in a DWP file. */ |
| |
| struct virtual_v1_dwo_sections |
| { |
| struct dwarf2_section_info abbrev; |
| struct dwarf2_section_info line; |
| struct dwarf2_section_info loc; |
| struct dwarf2_section_info macinfo; |
| struct dwarf2_section_info macro; |
| struct dwarf2_section_info str_offsets; |
| /* Each DWP hash table entry records one CU or one TU. |
| That is recorded here, and copied to dwo_unit.section. */ |
| struct dwarf2_section_info info_or_types; |
| }; |
| |
| /* Similar to virtual_v1_dwo_sections, but for DWP version 2 or 5. |
| In version 2, the sections of the DWO files are concatenated together |
| and stored in one section of that name. Thus each ELF section contains |
| several "virtual" sections. */ |
| |
| struct virtual_v2_or_v5_dwo_sections |
| { |
| bfd_size_type abbrev_offset; |
| bfd_size_type abbrev_size; |
| |
| bfd_size_type line_offset; |
| bfd_size_type line_size; |
| |
| bfd_size_type loc_offset; |
| bfd_size_type loc_size; |
| |
| bfd_size_type loclists_offset; |
| bfd_size_type loclists_size; |
| |
| bfd_size_type macinfo_offset; |
| bfd_size_type macinfo_size; |
| |
| bfd_size_type macro_offset; |
| bfd_size_type macro_size; |
| |
| bfd_size_type rnglists_offset; |
| bfd_size_type rnglists_size; |
| |
| bfd_size_type str_offsets_offset; |
| bfd_size_type str_offsets_size; |
| |
| /* Each DWP hash table entry records one CU or one TU. |
| That is recorded here, and copied to dwo_unit.section. */ |
| bfd_size_type info_or_types_offset; |
| bfd_size_type info_or_types_size; |
| }; |
| |
| /* Contents of DWP hash tables. */ |
| |
| struct dwp_hash_table |
| { |
| uint32_t version, nr_columns; |
| uint32_t nr_units, nr_slots; |
| const gdb_byte *hash_table, *unit_table; |
| union |
| { |
| struct |
| { |
| const gdb_byte *indices; |
| } v1; |
| struct |
| { |
| /* This is indexed by column number and gives the id of the section |
| in that column. */ |
| #define MAX_NR_V2_DWO_SECTIONS \ |
| (1 /* .debug_info or .debug_types */ \ |
| + 1 /* .debug_abbrev */ \ |
| + 1 /* .debug_line */ \ |
| + 1 /* .debug_loc */ \ |
| + 1 /* .debug_str_offsets */ \ |
| + 1 /* .debug_macro or .debug_macinfo */) |
| int section_ids[MAX_NR_V2_DWO_SECTIONS]; |
| const gdb_byte *offsets; |
| const gdb_byte *sizes; |
| } v2; |
| struct |
| { |
| /* This is indexed by column number and gives the id of the section |
| in that column. */ |
| #define MAX_NR_V5_DWO_SECTIONS \ |
| (1 /* .debug_info */ \ |
| + 1 /* .debug_abbrev */ \ |
| + 1 /* .debug_line */ \ |
| + 1 /* .debug_loclists */ \ |
| + 1 /* .debug_str_offsets */ \ |
| + 1 /* .debug_macro */ \ |
| + 1 /* .debug_rnglists */) |
| int section_ids[MAX_NR_V5_DWO_SECTIONS]; |
| const gdb_byte *offsets; |
| const gdb_byte *sizes; |
| } v5; |
| } section_pool; |
| }; |
| |
| /* Data for one DWP file. */ |
| |
| struct dwp_file |
| { |
| dwp_file (const char *name_, gdb_bfd_ref_ptr &&abfd) |
| : name (name_), |
| dbfd (std::move (abfd)) |
| { |
| } |
| |
| /* Name of the file. */ |
| const char *name; |
| |
| /* File format version. */ |
| int version = 0; |
| |
| /* The bfd. */ |
| gdb_bfd_ref_ptr dbfd; |
| |
| /* Section info for this file. */ |
| struct dwp_sections sections {}; |
| |
| /* Table of CUs in the file. */ |
| const struct dwp_hash_table *cus = nullptr; |
| |
| /* Table of TUs in the file. */ |
| const struct dwp_hash_table *tus = nullptr; |
| |
| /* Tables of loaded CUs/TUs. Each entry is a struct dwo_unit *. */ |
| htab_up loaded_cus; |
| htab_up loaded_tus; |
| |
| /* Table to map ELF section numbers to their sections. |
| This is only needed for the DWP V1 file format. */ |
| unsigned int num_sections = 0; |
| asection **elf_sections = nullptr; |
| }; |
| |
| /* Struct used to pass misc. parameters to read_die_and_children, et |
| al. which are used for both .debug_info and .debug_types dies. |
| All parameters here are unchanging for the life of the call. This |
| struct exists to abstract away the constant parameters of die reading. */ |
| |
| struct die_reader_specs |
| { |
| /* The bfd of die_section. */ |
| bfd *abfd; |
| |
| /* The CU of the DIE we are parsing. */ |
| struct dwarf2_cu *cu; |
| |
| /* Non-NULL if reading a DWO file (including one packaged into a DWP). */ |
| struct dwo_file *dwo_file; |
| |
| /* The section the die comes from. |
| This is either .debug_info or .debug_types, or the .dwo variants. */ |
| struct dwarf2_section_info *die_section; |
| |
| /* die_section->buffer. */ |
| const gdb_byte *buffer; |
| |
| /* The end of the buffer. */ |
| const gdb_byte *buffer_end; |
| |
| /* The abbreviation table to use when reading the DIEs. */ |
| struct abbrev_table *abbrev_table; |
| }; |
| |
| /* A subclass of die_reader_specs that holds storage and has complex |
| constructor and destructor behavior. */ |
| |
| class cutu_reader : public die_reader_specs |
| { |
| public: |
| |
| cutu_reader (dwarf2_per_cu_data *this_cu, |
| dwarf2_per_objfile *per_objfile, |
| struct abbrev_table *abbrev_table, |
| dwarf2_cu *existing_cu, |
| bool skip_partial, |
| abbrev_cache *cache = nullptr); |
| |
| explicit cutu_reader (struct dwarf2_per_cu_data *this_cu, |
| dwarf2_per_objfile *per_objfile, |
| struct dwarf2_cu *parent_cu = nullptr, |
| struct dwo_file *dwo_file = nullptr); |
| |
| DISABLE_COPY_AND_ASSIGN (cutu_reader); |
| |
| cutu_reader (cutu_reader &&) = default; |
| |
| const gdb_byte *info_ptr = nullptr; |
| struct die_info *comp_unit_die = nullptr; |
| bool dummy_p = false; |
| |
| /* Release the new CU, putting it on the chain. This cannot be done |
| for dummy CUs. */ |
| void keep (); |
| |
| /* Release the abbrev table, transferring ownership to the |
| caller. */ |
| abbrev_table_up release_abbrev_table () |
| { |
| return std::move (m_abbrev_table_holder); |
| } |
| |
| private: |
| void init_tu_and_read_dwo_dies (dwarf2_per_cu_data *this_cu, |
| dwarf2_per_objfile *per_objfile, |
| dwarf2_cu *existing_cu); |
| |
| struct dwarf2_per_cu_data *m_this_cu; |
| std::unique_ptr<dwarf2_cu> m_new_cu; |
| |
| /* The ordinary abbreviation table. */ |
| abbrev_table_up m_abbrev_table_holder; |
| |
| /* The DWO abbreviation table. */ |
| abbrev_table_up m_dwo_abbrev_table; |
| }; |
| |
| /* FIXME: We might want to set this from BFD via bfd_arch_bits_per_byte, |
| but this would require a corresponding change in unpack_field_as_long |
| and friends. */ |
| static int bits_per_byte = 8; |
| |
| struct variant_part_builder; |
| |
| /* When reading a variant, we track a bit more information about the |
| field, and store it in an object of this type. */ |
| |
| struct variant_field |
| { |
| int first_field = -1; |
| int last_field = -1; |
| |
| /* A variant can contain other variant parts. */ |
| std::vector<variant_part_builder> variant_parts; |
| |
| /* If we see a DW_TAG_variant, then this will be set if this is the |
| default branch. */ |
| bool default_branch = false; |
| /* If we see a DW_AT_discr_value, then this will be the discriminant |
| value. */ |
| ULONGEST discriminant_value = 0; |
| /* If we see a DW_AT_discr_list, then this is a pointer to the list |
| data. */ |
| struct dwarf_block *discr_list_data = nullptr; |
| }; |
| |
| /* This represents a DW_TAG_variant_part. */ |
| |
| struct variant_part_builder |
| { |
| /* The offset of the discriminant field. */ |
| sect_offset discriminant_offset {}; |
| |
| /* Variants that are direct children of this variant part. */ |
| std::vector<variant_field> variants; |
| |
| /* True if we're currently reading a variant. */ |
| bool processing_variant = false; |
| }; |
| |
| struct nextfield |
| { |
| /* Variant parts need to find the discriminant, which is a DIE |
| reference. We track the section offset of each field to make |
| this link. */ |
| sect_offset offset; |
| struct field field {}; |
| }; |
| |
| struct fnfieldlist |
| { |
| const char *name = nullptr; |
| std::vector<struct fn_field> fnfields; |
| }; |
| |
| /* The routines that read and process dies for a C struct or C++ class |
| pass lists of data member fields and lists of member function fields |
| in an instance of a field_info structure, as defined below. */ |
| struct field_info |
| { |
| /* List of data member and baseclasses fields. */ |
| std::vector<struct nextfield> fields; |
| std::vector<struct nextfield> baseclasses; |
| |
| /* Member function fieldlist array, contains name of possibly overloaded |
| member function, number of overloaded member functions and a pointer |
| to the head of the member function field chain. */ |
| std::vector<struct fnfieldlist> fnfieldlists; |
| |
| /* typedefs defined inside this class. TYPEDEF_FIELD_LIST contains head of |
| a NULL terminated list of TYPEDEF_FIELD_LIST_COUNT elements. */ |
| std::vector<struct decl_field> typedef_field_list; |
| |
| /* Nested types defined by this class and the number of elements in this |
| list. */ |
| std::vector<struct decl_field> nested_types_list; |
| |
| /* If non-null, this is the variant part we are currently |
| reading. */ |
| variant_part_builder *current_variant_part = nullptr; |
| /* This holds all the top-level variant parts attached to the type |
| we're reading. */ |
| std::vector<variant_part_builder> variant_parts; |
| |
| /* Return the total number of fields (including baseclasses). */ |
| int nfields () const |
| { |
| return fields.size () + baseclasses.size (); |
| } |
| }; |
| |
| /* Loaded secondary compilation units are kept in memory until they |
| have not been referenced for the processing of this many |
| compilation units. Set this to zero to disable caching. Cache |
| sizes of up to at least twenty will improve startup time for |
| typical inter-CU-reference binaries, at an obvious memory cost. */ |
| static int dwarf_max_cache_age = 5; |
| static void |
| show_dwarf_max_cache_age (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, const char *value) |
| { |
| gdb_printf (file, _("The upper bound on the age of cached " |
| "DWARF compilation units is %s.\n"), |
| value); |
| } |
| |
| /* When true, wait for DWARF reading to be complete. */ |
| static bool dwarf_synchronous = true; |
| |
| /* "Show" callback for "maint set dwarf synchronous". */ |
| static void |
| show_dwarf_synchronous (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, const char *value) |
| { |
| gdb_printf (file, _("Whether DWARF reading is synchronous is %s.\n"), |
| value); |
| } |
| |
| /* local function prototypes */ |
| |
| static void dwarf2_find_base_address (struct die_info *die, |
| struct dwarf2_cu *cu); |
| |
| static void build_type_psymtabs_reader (cutu_reader *reader, |
| cooked_index_storage *storage); |
| |
| static void var_decode_location (struct attribute *attr, |
| struct symbol *sym, |
| struct dwarf2_cu *cu); |
| |
| static unsigned int peek_abbrev_code (bfd *, const gdb_byte *); |
| |
| static const gdb_byte *read_attribute (const struct die_reader_specs *, |
| struct attribute *, |
| const struct attr_abbrev *, |
| const gdb_byte *, |
| bool allow_reprocess = true); |
| |
| /* Note that the default for TAG is chosen because it only matters |
| when reading the top-level DIE, and that function is careful to |
| pass the correct tag. */ |
| static void read_attribute_reprocess (const struct die_reader_specs *reader, |
| struct attribute *attr, |
| dwarf_tag tag = DW_TAG_padding); |
| |
| static unrelocated_addr read_addr_index (struct dwarf2_cu *cu, |
| unsigned int addr_index); |
| |
| static sect_offset read_abbrev_offset (dwarf2_per_objfile *per_objfile, |
| dwarf2_section_info *, sect_offset); |
| |
| static const char *read_indirect_string |
| (dwarf2_per_objfile *per_objfile, bfd *, const gdb_byte *, |
| const struct comp_unit_head *, unsigned int *); |
| |
| static unrelocated_addr read_addr_index_from_leb128 (struct dwarf2_cu *, |
| const gdb_byte *, |
| unsigned int *); |
| |
| static const char *read_dwo_str_index (const struct die_reader_specs *reader, |
| ULONGEST str_index); |
| |
| static const char *read_stub_str_index (struct dwarf2_cu *cu, |
| ULONGEST str_index); |
| |
| static struct attribute *dwarf2_attr (struct die_info *, unsigned int, |
| struct dwarf2_cu *); |
| |
| static const char *dwarf2_string_attr (struct die_info *die, unsigned int name, |
| struct dwarf2_cu *cu); |
| |
| static const char *dwarf2_dwo_name (struct die_info *die, struct dwarf2_cu *cu); |
| |
| static int dwarf2_flag_true_p (struct die_info *die, unsigned name, |
| struct dwarf2_cu *cu); |
| |
| static int die_is_declaration (struct die_info *, struct dwarf2_cu *cu); |
| |
| static struct die_info *die_specification (struct die_info *die, |
| struct dwarf2_cu **); |
| |
| static line_header_up dwarf_decode_line_header (sect_offset sect_off, |
| struct dwarf2_cu *cu, |
| const char *comp_dir); |
| |
| static void dwarf_decode_lines (struct line_header *, |
| struct dwarf2_cu *, |
| unrelocated_addr, int decode_mapping); |
| |
| static void dwarf2_start_subfile (dwarf2_cu *cu, const file_entry &fe, |
| const line_header &lh); |
| |
| static struct symbol *new_symbol (struct die_info *, struct type *, |
| struct dwarf2_cu *, struct symbol * = NULL); |
| |
| static void dwarf2_const_value (const struct attribute *, struct symbol *, |
| struct dwarf2_cu *); |
| |
| static void dwarf2_const_value_attr (const struct attribute *attr, |
| struct type *type, |
| const char *name, |
| struct obstack *obstack, |
| struct dwarf2_cu *cu, LONGEST *value, |
| const gdb_byte **bytes, |
| struct dwarf2_locexpr_baton **baton); |
| |
| static struct type *read_subrange_index_type (struct die_info *die, |
| struct dwarf2_cu *cu); |
| |
| static struct type *die_type (struct die_info *, struct dwarf2_cu *); |
| |
| static int need_gnat_info (struct dwarf2_cu *); |
| |
| static struct type *die_descriptive_type (struct die_info *, |
| struct dwarf2_cu *); |
| |
| static void set_descriptive_type (struct type *, struct die_info *, |
| struct dwarf2_cu *); |
| |
| static struct type *die_containing_type (struct die_info *, |
| struct dwarf2_cu *); |
| |
| static struct type *lookup_die_type (struct die_info *, const struct attribute *, |
| struct dwarf2_cu *); |
| |
| static struct type *read_type_die (struct die_info *, struct dwarf2_cu *); |
| |
| static struct type *read_type_die_1 (struct die_info *, struct dwarf2_cu *); |
| |
| static const char *determine_prefix (struct die_info *die, struct dwarf2_cu *); |
| |
| static gdb::unique_xmalloc_ptr<char> typename_concat (const char *prefix, |
| const char *suffix, |
| int physname, |
| struct dwarf2_cu *cu); |
| |
| static void read_file_scope (struct die_info *, struct dwarf2_cu *); |
| |
| static void read_type_unit_scope (struct die_info *, struct dwarf2_cu *); |
| |
| static void read_func_scope (struct die_info *, struct dwarf2_cu *); |
| |
| static void read_lexical_block_scope (struct die_info *, struct dwarf2_cu *); |
| |
| static void read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu); |
| |
| static void read_variable (struct die_info *die, struct dwarf2_cu *cu); |
| |
| /* Return the .debug_loclists section to use for cu. */ |
| static struct dwarf2_section_info *cu_debug_loc_section (struct dwarf2_cu *cu); |
| |
| /* Return the .debug_rnglists section to use for cu. */ |
| static struct dwarf2_section_info *cu_debug_rnglists_section |
| (struct dwarf2_cu *cu, dwarf_tag tag); |
| |
| /* How dwarf2_get_pc_bounds constructed its *LOWPC and *HIGHPC return |
| values. Keep the items ordered with increasing constraints compliance. */ |
| enum pc_bounds_kind |
| { |
| /* No attribute DW_AT_low_pc, DW_AT_high_pc or DW_AT_ranges was found. */ |
| PC_BOUNDS_NOT_PRESENT, |
| |
| /* Some of the attributes DW_AT_low_pc, DW_AT_high_pc or DW_AT_ranges |
| were present but they do not form a valid range of PC addresses. */ |
| PC_BOUNDS_INVALID, |
| |
| /* Discontiguous range was found - that is DW_AT_ranges was found. */ |
| PC_BOUNDS_RANGES, |
| |
| /* Contiguous range was found - DW_AT_low_pc and DW_AT_high_pc were found. */ |
| PC_BOUNDS_HIGH_LOW, |
| }; |
| |
| static enum pc_bounds_kind dwarf2_get_pc_bounds (struct die_info *, |
| unrelocated_addr *, |
| unrelocated_addr *, |
| struct dwarf2_cu *, |
| addrmap_mutable *, |
| void *); |
| |
| static void get_scope_pc_bounds (struct die_info *, |
| unrelocated_addr *, unrelocated_addr *, |
| struct dwarf2_cu *); |
| |
| static void dwarf2_record_block_ranges (struct die_info *, struct block *, |
| struct dwarf2_cu *); |
| |
| static void dwarf2_add_field (struct field_info *, struct die_info *, |
| struct dwarf2_cu *); |
| |
| static void dwarf2_attach_fields_to_type (struct field_info *, |
| struct type *, struct dwarf2_cu *); |
| |
| static void dwarf2_add_member_fn (struct field_info *, |
| struct die_info *, struct type *, |
| struct dwarf2_cu *); |
| |
| static void dwarf2_attach_fn_fields_to_type (struct field_info *, |
| struct type *, |
| struct dwarf2_cu *); |
| |
| static void process_structure_scope (struct die_info *, struct dwarf2_cu *); |
| |
| static void read_common_block (struct die_info *, struct dwarf2_cu *); |
| |
| static void read_namespace (struct die_info *die, struct dwarf2_cu *); |
| |
| static void read_module (struct die_info *die, struct dwarf2_cu *cu); |
| |
| static struct using_direct **using_directives (struct dwarf2_cu *cu); |
| |
| static void read_import_statement (struct die_info *die, struct dwarf2_cu *); |
| |
| static bool read_alias (struct die_info *die, struct dwarf2_cu *cu); |
| |
| static struct type *read_module_type (struct die_info *die, |
| struct dwarf2_cu *cu); |
| |
| static const char *namespace_name (struct die_info *die, |
| int *is_anonymous, struct dwarf2_cu *); |
| |
| static void process_enumeration_scope (struct die_info *, struct dwarf2_cu *); |
| |
| static bool decode_locdesc (struct dwarf_block *, struct dwarf2_cu *, |
| CORE_ADDR *addr); |
| |
| static enum dwarf_array_dim_ordering read_array_order (struct die_info *, |
| struct dwarf2_cu *); |
| |
| static struct die_info *read_die_and_siblings_1 |
| (const struct die_reader_specs *, const gdb_byte *, const gdb_byte **, |
| struct die_info *); |
| |
| static struct die_info *read_die_and_siblings (const struct die_reader_specs *, |
| const gdb_byte *info_ptr, |
| const gdb_byte **new_info_ptr, |
| struct die_info *parent); |
| |
| static const gdb_byte *read_full_die_1 (const struct die_reader_specs *, |
| struct die_info **, const gdb_byte *, |
| int, bool); |
| |
| static const gdb_byte *read_toplevel_die (const struct die_reader_specs *, |
| struct die_info **, |
| const gdb_byte *, |
| gdb::array_view<attribute *> = {}); |
| |
| static void process_die (struct die_info *, struct dwarf2_cu *); |
| |
| static const char *dwarf2_canonicalize_name (const char *, struct dwarf2_cu *, |
| struct objfile *); |
| |
| static const char *dwarf2_name (struct die_info *die, struct dwarf2_cu *); |
| |
| static const char *dwarf2_full_name (const char *name, |
| struct die_info *die, |
| struct dwarf2_cu *cu); |
| |
| static const char *dwarf2_physname (const char *name, struct die_info *die, |
| struct dwarf2_cu *cu); |
| |
| static struct die_info *dwarf2_extension (struct die_info *die, |
| struct dwarf2_cu **); |
| |
| static struct die_info *follow_die_ref_or_sig (struct die_info *, |
| const struct attribute *, |
| struct dwarf2_cu **); |
| |
| static struct die_info *follow_die_ref (struct die_info *, |
| const struct attribute *, |
| struct dwarf2_cu **); |
| |
| static struct die_info *follow_die_sig (struct die_info *, |
| const struct attribute *, |
| struct dwarf2_cu **); |
| |
| static struct type *get_signatured_type (struct die_info *, ULONGEST, |
| struct dwarf2_cu *); |
| |
| static struct type *get_DW_AT_signature_type (struct die_info *, |
| const struct attribute *, |
| struct dwarf2_cu *); |
| |
| static void load_full_type_unit (dwarf2_per_cu_data *per_cu, |
| dwarf2_per_objfile *per_objfile); |
| |
| static void read_signatured_type (signatured_type *sig_type, |
| dwarf2_per_objfile *per_objfile); |
| |
| static int attr_to_dynamic_prop (const struct attribute *attr, |
| struct die_info *die, struct dwarf2_cu *cu, |
| struct dynamic_prop *prop, struct type *type); |
| |
| /* memory allocation interface */ |
| |
| static struct dwarf_block *dwarf_alloc_block (struct dwarf2_cu *); |
| |
| static void dwarf_decode_macros (struct dwarf2_cu *, unsigned int, int); |
| |
| static void fill_in_loclist_baton (struct dwarf2_cu *cu, |
| struct dwarf2_loclist_baton *baton, |
| const struct attribute *attr); |
| |
| static void dwarf2_symbol_mark_computed (const struct attribute *attr, |
| struct symbol *sym, |
| struct dwarf2_cu *cu, |
| int is_block); |
| |
| static const gdb_byte *skip_one_die (const struct die_reader_specs *reader, |
| const gdb_byte *info_ptr, |
| const struct abbrev_info *abbrev, |
| bool do_skip_children = true); |
| |
| static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit |
| (sect_offset sect_off, unsigned int offset_in_dwz, |
| dwarf2_per_bfd *per_bfd); |
| |
| static void prepare_one_comp_unit (struct dwarf2_cu *cu, |
| struct die_info *comp_unit_die, |
| enum language pretend_language); |
| |
| static struct type *set_die_type (struct die_info *, struct type *, |
| struct dwarf2_cu *, bool = false); |
| |
| static void load_full_comp_unit (dwarf2_per_cu_data *per_cu, |
| dwarf2_per_objfile *per_objfile, |
| dwarf2_cu *existing_cu, |
| bool skip_partial, |
| enum language pretend_language); |
| |
| static void process_full_comp_unit (dwarf2_cu *cu, |
| enum language pretend_language); |
| |
| static void process_full_type_unit (dwarf2_cu *cu, |
| enum language pretend_language); |
| |
| static struct type *get_die_type_at_offset (sect_offset, |
| dwarf2_per_cu_data *per_cu, |
| dwarf2_per_objfile *per_objfile); |
| |
| static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu); |
| |
| static void queue_comp_unit (dwarf2_per_cu_data *per_cu, |
| dwarf2_per_objfile *per_objfile, |
| enum language pretend_language); |
| |
| static void process_queue (dwarf2_per_objfile *per_objfile); |
| |
| static bool is_ada_import_or_export (dwarf2_cu *cu, const char *name, |
| const char *linkagename); |
| |
| /* Class, the destructor of which frees all allocated queue entries. This |
| will only have work to do if an error was thrown while processing the |
| dwarf. If no error was thrown then the queue entries should have all |
| been processed, and freed, as we went along. */ |
| |
| class dwarf2_queue_guard |
| { |
| public: |
| explicit dwarf2_queue_guard (dwarf2_per_objfile *per_objfile) |
| : m_per_objfile (per_objfile) |
| { |
| gdb_assert (!m_per_objfile->queue.has_value ()); |
| |
| m_per_objfile->queue.emplace (); |
| } |
| |
| /* Free any entries remaining on the queue. There should only be |
| entries left if we hit an error while processing the dwarf. */ |
| ~dwarf2_queue_guard () |
| { |
| gdb_assert (m_per_objfile->queue.has_value ()); |
| |
| m_per_objfile->queue.reset (); |
| } |
| |
| DISABLE_COPY_AND_ASSIGN (dwarf2_queue_guard); |
| |
| private: |
| dwarf2_per_objfile *m_per_objfile; |
| }; |
| |
| dwarf2_queue_item::~dwarf2_queue_item () |
| { |
| /* Anything still marked queued is likely to be in an |
| inconsistent state, so discard it. */ |
| if (per_cu->queued) |
| { |
| per_objfile->remove_cu (per_cu); |
| per_cu->queued = 0; |
| } |
| } |
| |
| /* See dwarf2/read.h. */ |
| |
| void |
| dwarf2_per_cu_data_deleter::operator() (dwarf2_per_cu_data *data) |
| { |
| if (data->is_debug_types) |
| delete static_cast<signatured_type *> (data); |
| else |
| delete data; |
| } |
| |
| static file_and_directory &find_file_and_directory |
| (struct die_info *die, struct dwarf2_cu *cu); |
| |
| static const char *compute_include_file_name |
| (const struct line_header *lh, |
| const file_entry &fe, |
| const file_and_directory &cu_info, |
| std::string &name_holder); |
| |
| static htab_up allocate_dwo_unit_table (); |
| |
| static struct dwo_unit *lookup_dwo_unit_in_dwp |
| (dwarf2_per_objfile *per_objfile, struct dwp_file *dwp_file, |
| const char *comp_dir, ULONGEST signature, int is_debug_types); |
| |
| static struct dwp_file *get_dwp_file (dwarf2_per_objfile *per_objfile); |
| |
| static struct dwo_unit *lookup_dwo_comp_unit |
| (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, |
| ULONGEST signature); |
| |
| static struct dwo_unit *lookup_dwo_type_unit |
| (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir); |
| |
| static void queue_and_load_all_dwo_tus (dwarf2_cu *cu); |
| |
| /* A unique pointer to a dwo_file. */ |
| |
| typedef std::unique_ptr<struct dwo_file> dwo_file_up; |
| |
| static void process_cu_includes (dwarf2_per_objfile *per_objfile); |
| |
| static void check_producer (struct dwarf2_cu *cu); |
| |
| /* Various complaints about symbol reading that don't abort the process. */ |
| |
| static void |
| dwarf2_debug_line_missing_file_complaint (void) |
| { |
| complaint (_(".debug_line section has line data without a file")); |
| } |
| |
| static void |
| dwarf2_debug_line_missing_end_sequence_complaint (void) |
| { |
| complaint (_(".debug_line section has line " |
| "program sequence without an end")); |
| } |
| |
| static void |
| dwarf2_complex_location_expr_complaint (void) |
| { |
| complaint (_("location expression too complex")); |
| } |
| |
| static void |
| dwarf2_const_value_length_mismatch_complaint (const char *arg1, int arg2, |
| int arg3) |
| { |
| complaint (_("const value length mismatch for '%s', got %d, expected %d"), |
| arg1, arg2, arg3); |
| } |
| |
| static void |
| dwarf2_invalid_attrib_class_complaint (const char *arg1, const char *arg2) |
| { |
| complaint (_("invalid attribute class or form for '%s' in '%s'"), |
| arg1, arg2); |
| } |
| |
| /* See read.h. */ |
| |
| CORE_ADDR |
| dwarf2_per_objfile::relocate (unrelocated_addr addr) |
| { |
| CORE_ADDR baseaddr = objfile->text_section_offset (); |
| CORE_ADDR tem = (CORE_ADDR) addr + baseaddr; |
| return gdbarch_adjust_dwarf2_addr (objfile->arch (), tem); |
| } |
| |
| /* Hash function for line_header_hash. */ |
| |
| static hashval_t |
| line_header_hash (const struct line_header *ofs) |
| { |
| return to_underlying (ofs->sect_off) ^ ofs->offset_in_dwz; |
| } |
| |
| /* Hash function for htab_create_alloc_ex for line_header_hash. */ |
| |
| static hashval_t |
| line_header_hash_voidp (const void *item) |
| { |
| const struct line_header *ofs = (const struct line_header *) item; |
| |
| return line_header_hash (ofs); |
| } |
| |
| /* Equality function for line_header_hash. */ |
| |
| static int |
| line_header_eq_voidp (const void *item_lhs, const void *item_rhs) |
| { |
| const struct line_header *ofs_lhs = (const struct line_header *) item_lhs; |
| const struct line_header *ofs_rhs = (const struct line_header *) item_rhs; |
| |
| return (ofs_lhs->sect_off == ofs_rhs->sect_off |
| && ofs_lhs->offset_in_dwz == ofs_rhs->offset_in_dwz); |
| } |
| |
| /* See declaration. */ |
| |
| dwarf2_per_bfd::dwarf2_per_bfd (bfd *obfd, const dwarf2_debug_sections *names, |
| bool can_copy_) |
| : obfd (obfd), |
| can_copy (can_copy_) |
| { |
| if (names == NULL) |
| names = &dwarf2_elf_names; |
| |
| for (asection *sec = obfd->sections; sec != NULL; sec = sec->next) |
| locate_sections (obfd, sec, *names); |
| } |
| |
| dwarf2_per_bfd::~dwarf2_per_bfd () |
| { |
| /* Data from the per-BFD may be needed when finalizing the cooked |
| index table, so wait here while this happens. */ |
| if (index_table != nullptr) |
| index_table->wait_completely (); |
| |
| for (auto &per_cu : all_units) |
| per_cu->free_cached_file_names (); |
| |
| /* Everything else should be on this->obstack. */ |
| } |
| |
| /* See read.h. */ |
| |
| void |
| dwarf2_per_objfile::remove_all_cus () |
| { |
| gdb_assert (!queue.has_value ()); |
| |
| m_dwarf2_cus.clear (); |
| } |
| |
| /* A helper class that calls free_cached_comp_units on |
| destruction. */ |
| |
| class free_cached_comp_units |
| { |
| public: |
| |
| explicit free_cached_comp_units (dwarf2_per_objfile *per_objfile) |
| : m_per_objfile (per_objfile) |
| { |
| } |
| |
| ~free_cached_comp_units () |
| { |
| m_per_objfile->remove_all_cus (); |
| } |
| |
| DISABLE_COPY_AND_ASSIGN (free_cached_comp_units); |
| |
| private: |
| |
| dwarf2_per_objfile *m_per_objfile; |
| }; |
| |
| /* See read.h. */ |
| |
| bool |
| dwarf2_per_objfile::symtab_set_p (const dwarf2_per_cu_data *per_cu) const |
| { |
| if (per_cu->index < this->m_symtabs.size ()) |
| return this->m_symtabs[per_cu->index] != nullptr; |
| return false; |
| } |
| |
| /* See read.h. */ |
| |
| compunit_symtab * |
| dwarf2_per_objfile::get_symtab (const dwarf2_per_cu_data *per_cu) const |
| { |
| if (per_cu->index < this->m_symtabs.size ()) |
| return this->m_symtabs[per_cu->index]; |
| return nullptr; |
| } |
| |
| /* See read.h. */ |
| |
| void |
| dwarf2_per_objfile::set_symtab (const dwarf2_per_cu_data *per_cu, |
| compunit_symtab *symtab) |
| { |
| if (per_cu->index >= this->m_symtabs.size ()) |
| this->m_symtabs.resize (per_cu->index + 1); |
| gdb_assert (this->m_symtabs[per_cu->index] == nullptr); |
| this->m_symtabs[per_cu->index] = symtab; |
| } |
| |
| /* Helper function for dwarf2_initialize_objfile that creates the |
| per-BFD object. */ |
| |
| static bool |
| dwarf2_has_info (struct objfile *objfile, |
| const struct dwarf2_debug_sections *names, |
| bool can_copy) |
| { |
| if (objfile->flags & OBJF_READNEVER) |
| return false; |
| |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| bool just_created = false; |
| |
| if (per_objfile == NULL) |
| { |
| dwarf2_per_bfd *per_bfd; |
| |
| /* We can share a "dwarf2_per_bfd" with other objfiles if the |
| BFD doesn't require relocations. |
| |
| We don't share with objfiles for which -readnow was requested, |
| because it would complicate things when loading the same BFD with |
| -readnow and then without -readnow. */ |
| if (!gdb_bfd_requires_relocations (objfile->obfd.get ()) |
| && (objfile->flags & OBJF_READNOW) == 0) |
| { |
| /* See if one has been created for this BFD yet. */ |
| per_bfd = dwarf2_per_bfd_bfd_data_key.get (objfile->obfd.get ()); |
| |
| if (per_bfd == nullptr) |
| { |
| /* No, create it now. */ |
| per_bfd = new dwarf2_per_bfd (objfile->obfd.get (), names, |
| can_copy); |
| dwarf2_per_bfd_bfd_data_key.set (objfile->obfd.get (), per_bfd); |
| just_created = true; |
| } |
| } |
| else |
| { |
| /* No sharing possible, create one specifically for this objfile. */ |
| per_bfd = new dwarf2_per_bfd (objfile->obfd.get (), names, can_copy); |
| dwarf2_per_bfd_objfile_data_key.set (objfile, per_bfd); |
| just_created = true; |
| } |
| |
| per_objfile = dwarf2_objfile_data_key.emplace (objfile, objfile, per_bfd); |
| } |
| |
| const bool has_info = (!per_objfile->per_bfd->info.is_virtual |
| && per_objfile->per_bfd->info.s.section != nullptr |
| && !per_objfile->per_bfd->abbrev.is_virtual |
| && per_objfile->per_bfd->abbrev.s.section != nullptr); |
| |
| if (just_created && has_info) |
| { |
| /* Try to fetch any potential dwz file early, while still on |
| the main thread. Also, be sure to do it just once per |
| BFD, to avoid races. */ |
| try |
| { |
| dwarf2_read_dwz_file (per_objfile); |
| } |
| catch (const gdb_exception_error &err) |
| { |
| warning (_("%s"), err.what ()); |
| } |
| } |
| |
| return has_info; |
| } |
| |
| /* See declaration. */ |
| |
| void |
| dwarf2_per_bfd::locate_sections (bfd *abfd, asection *sectp, |
| const dwarf2_debug_sections &names) |
| { |
| flagword aflag = bfd_section_flags (sectp); |
| |
| if ((aflag & SEC_HAS_CONTENTS) == 0) |
| { |
| } |
| else if (bfd_section_size_insane (abfd, sectp)) |
| { |
| bfd_size_type size = sectp->size; |
| warning (_("Discarding section %s which has an invalid size (%s) " |
| "[in module %s]"), |
| bfd_section_name (sectp), phex_nz (size, sizeof (size)), |
| bfd_get_filename (abfd)); |
| } |
| else if (names.info.matches (sectp->name)) |
| { |
| this->info.s.section = sectp; |
| this->info.size = bfd_section_size (sectp); |
| } |
| else if (names.abbrev.matches (sectp->name)) |
| { |
| this->abbrev.s.section = sectp; |
| this->abbrev.size = bfd_section_size (sectp); |
| } |
| else if (names.line.matches (sectp->name)) |
| { |
| this->line.s.section = sectp; |
| this->line.size = bfd_section_size (sectp); |
| } |
| else if (names.loc.matches (sectp->name)) |
| { |
| this->loc.s.section = sectp; |
| this->loc.size = bfd_section_size (sectp); |
| } |
| else if (names.loclists.matches (sectp->name)) |
| { |
| this->loclists.s.section = sectp; |
| this->loclists.size = bfd_section_size (sectp); |
| } |
| else if (names.macinfo.matches (sectp->name)) |
| { |
| this->macinfo.s.section = sectp; |
| this->macinfo.size = bfd_section_size (sectp); |
| } |
| else if (names.macro.matches (sectp->name)) |
| { |
| this->macro.s.section = sectp; |
| this->macro.size = bfd_section_size (sectp); |
| } |
| else if (names.str.matches (sectp->name)) |
| { |
| this->str.s.section = sectp; |
| this->str.size = bfd_section_size (sectp); |
| } |
| else if (names.str_offsets.matches (sectp->name)) |
| { |
| this->str_offsets.s.section = sectp; |
| this->str_offsets.size = bfd_section_size (sectp); |
| } |
| else if (names.line_str.matches (sectp->name)) |
| { |
| this->line_str.s.section = sectp; |
| this->line_str.size = bfd_section_size (sectp); |
| } |
| else if (names.addr.matches (sectp->name)) |
| { |
| this->addr.s.section = sectp; |
| this->addr.size = bfd_section_size (sectp); |
| } |
| else if (names.frame.matches (sectp->name)) |
| { |
| this->frame.s.section = sectp; |
| this->frame.size = bfd_section_size (sectp); |
| } |
| else if (names.eh_frame.matches (sectp->name)) |
| { |
| this->eh_frame.s.section = sectp; |
| this->eh_frame.size = bfd_section_size (sectp); |
| } |
| else if (names.ranges.matches (sectp->name)) |
| { |
| this->ranges.s.section = sectp; |
| this->ranges.size = bfd_section_size (sectp); |
| } |
| else if (names.rnglists.matches (sectp->name)) |
| { |
| this->rnglists.s.section = sectp; |
| this->rnglists.size = bfd_section_size (sectp); |
| } |
| else if (names.types.matches (sectp->name)) |
| { |
| struct dwarf2_section_info type_section; |
| |
| memset (&type_section, 0, sizeof (type_section)); |
| type_section.s.section = sectp; |
| type_section.size = bfd_section_size (sectp); |
| |
| this->types.push_back (type_section); |
| } |
| else if (names.gdb_index.matches (sectp->name)) |
| { |
| this->gdb_index.s.section = sectp; |
| this->gdb_index.size = bfd_section_size (sectp); |
| } |
| else if (names.debug_names.matches (sectp->name)) |
| { |
| this->debug_names.s.section = sectp; |
| this->debug_names.size = bfd_section_size (sectp); |
| } |
| else if (names.debug_aranges.matches (sectp->name)) |
| { |
| this->debug_aranges.s.section = sectp; |
| this->debug_aranges.size = bfd_section_size (sectp); |
| } |
| |
| if ((bfd_section_flags (sectp) & (SEC_LOAD | SEC_ALLOC)) |
| && bfd_section_vma (sectp) == 0) |
| this->has_section_at_zero = true; |
| } |
| |
| /* Fill in SECTP, BUFP and SIZEP with section info, given OBJFILE and |
| SECTION_NAME. */ |
| |
| void |
| dwarf2_get_section_info (struct objfile *objfile, |
| enum dwarf2_section_enum sect, |
| asection **sectp, const gdb_byte **bufp, |
| bfd_size_type *sizep) |
| { |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| struct dwarf2_section_info *info; |
| |
| /* We may see an objfile without any DWARF, in which case we just |
| return nothing. */ |
| if (per_objfile == NULL) |
| { |
| *sectp = NULL; |
| *bufp = NULL; |
| *sizep = 0; |
| return; |
| } |
| switch (sect) |
| { |
| case DWARF2_DEBUG_FRAME: |
| info = &per_objfile->per_bfd->frame; |
| break; |
| case DWARF2_EH_FRAME: |
| info = &per_objfile->per_bfd->eh_frame; |
| break; |
| default: |
| gdb_assert_not_reached ("unexpected section"); |
| } |
| |
| info->read (objfile); |
| |
| *sectp = info->get_bfd_section (); |
| *bufp = info->buffer; |
| *sizep = info->size; |
| } |
| |
| /* See dwarf2/read.h. */ |
| |
| void |
| dwarf2_per_bfd::map_info_sections (struct objfile *objfile) |
| { |
| info.read (objfile); |
| abbrev.read (objfile); |
| line.read (objfile); |
| str.read (objfile); |
| str_offsets.read (objfile); |
| line_str.read (objfile); |
| ranges.read (objfile); |
| rnglists.read (objfile); |
| addr.read (objfile); |
| debug_aranges.read (objfile); |
| |
| for (auto §ion : types) |
| section.read (objfile); |
| } |
| |
| |
| /* DWARF quick_symbol_functions support. */ |
| |
| /* TUs can share .debug_line entries, and there can be a lot more TUs than |
| unique line tables, so we maintain a separate table of all .debug_line |
| derived entries to support the sharing. |
| All the quick functions need is the list of file names. We discard the |
| line_header when we're done and don't need to record it here. */ |
| struct quick_file_names |
| { |
| /* The data used to construct the hash key. */ |
| struct stmt_list_hash hash; |
| |
| /* The number of entries in file_names, real_names. */ |
| unsigned int num_file_names; |
| |
| /* The CU directory, as given by DW_AT_comp_dir. May be |
| nullptr. */ |
| const char *comp_dir; |
| |
| /* The file names from the line table, after being run through |
| file_full_name. */ |
| const char **file_names; |
| |
| /* The file names from the line table after being run through |
| gdb_realpath. These are computed lazily. */ |
| const char **real_names; |
| }; |
| |
| /* With OBJF_READNOW, the DWARF reader expands all CUs immediately. |
| It's handy in this case to have an empty implementation of the |
| quick symbol functions, to avoid special cases in the rest of the |
| code. */ |
| |
| struct readnow_functions : public dwarf2_base_index_functions |
| { |
| void dump (struct objfile *objfile) 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_search_flags domain) override |
| { |
| return true; |
| } |
| }; |
| |
| /* Utility hash function for a stmt_list_hash. */ |
| |
| static hashval_t |
| hash_stmt_list_entry (const struct stmt_list_hash *stmt_list_hash) |
| { |
| hashval_t v = 0; |
| |
| if (stmt_list_hash->dwo_unit != NULL) |
| v += (uintptr_t) stmt_list_hash->dwo_unit->dwo_file; |
| v += to_underlying (stmt_list_hash->line_sect_off); |
| return v; |
| } |
| |
| /* Utility equality function for a stmt_list_hash. */ |
| |
| static int |
| eq_stmt_list_entry (const struct stmt_list_hash *lhs, |
| const struct stmt_list_hash *rhs) |
| { |
| if ((lhs->dwo_unit != NULL) != (rhs->dwo_unit != NULL)) |
| return 0; |
| if (lhs->dwo_unit != NULL |
| && lhs->dwo_unit->dwo_file != rhs->dwo_unit->dwo_file) |
| return 0; |
| |
| return lhs->line_sect_off == rhs->line_sect_off; |
| } |
| |
| /* Hash function for a quick_file_names. */ |
| |
| static hashval_t |
| hash_file_name_entry (const void *e) |
| { |
| const struct quick_file_names *file_data |
| = (const struct quick_file_names *) e; |
| |
| return hash_stmt_list_entry (&file_data->hash); |
| } |
| |
| /* Equality function for a quick_file_names. */ |
| |
| static int |
| eq_file_name_entry (const void *a, const void *b) |
| { |
| const struct quick_file_names *ea = (const struct quick_file_names *) a; |
| const struct quick_file_names *eb = (const struct quick_file_names *) b; |
| |
| return eq_stmt_list_entry (&ea->hash, &eb->hash); |
| } |
| |
| /* See read.h. */ |
| |
| htab_up |
| create_quick_file_names_table (unsigned int nr_initial_entries) |
| { |
| return htab_up (htab_create_alloc (nr_initial_entries, |
| hash_file_name_entry, eq_file_name_entry, |
| nullptr, xcalloc, xfree)); |
| } |
| |
| /* Read in CU (dwarf2_cu object) for PER_CU in the context of PER_OBJFILE. This |
| function is unrelated to symtabs, symtab would have to be created afterwards. |
| You should call age_cached_comp_units after processing the CU. */ |
| |
| static dwarf2_cu * |
| load_cu (dwarf2_per_cu_data *per_cu, dwarf2_per_objfile *per_objfile, |
| bool skip_partial) |
| { |
| if (per_cu->is_debug_types) |
| load_full_type_unit (per_cu, per_objfile); |
| else |
| load_full_comp_unit (per_cu, per_objfile, per_objfile->get_cu (per_cu), |
| skip_partial, language_minimal); |
| |
| dwarf2_cu *cu = per_objfile->get_cu (per_cu); |
| if (cu == nullptr) |
| return nullptr; /* Dummy CU. */ |
| |
| dwarf2_find_base_address (cu->dies, cu); |
| |
| return cu; |
| } |
| |
| /* Read in the symbols for PER_CU in the context of PER_OBJFILE. */ |
| |
| static void |
| dw2_do_instantiate_symtab (dwarf2_per_cu_data *per_cu, |
| dwarf2_per_objfile *per_objfile, bool skip_partial) |
| { |
| { |
| /* The destructor of dwarf2_queue_guard frees any entries left on |
| the queue. After this point we're guaranteed to leave this function |
| with the dwarf queue empty. */ |
| dwarf2_queue_guard q_guard (per_objfile); |
| |
| if (!per_objfile->symtab_set_p (per_cu)) |
| { |
| queue_comp_unit (per_cu, per_objfile, language_minimal); |
| dwarf2_cu *cu = load_cu (per_cu, per_objfile, skip_partial); |
| |
| /* If we just loaded a CU from a DWO, and we're working with an index |
| that may badly handle TUs, load all the TUs in that DWO as well. |
| http://sourceware.org/bugzilla/show_bug.cgi?id=15021 */ |
| if (!per_cu->is_debug_types |
| && cu != NULL |
| && cu->dwo_unit != NULL |
| && per_objfile->per_bfd->index_table != NULL |
| && !per_objfile->per_bfd->index_table->version_check () |
| /* DWP files aren't supported yet. */ |
| && get_dwp_file (per_objfile) == NULL) |
| queue_and_load_all_dwo_tus (cu); |
| } |
| |
| process_queue (per_objfile); |
| } |
| |
| /* Age the cache, releasing compilation units that have not |
| been used recently. */ |
| per_objfile->age_comp_units (); |
| } |
| |
| /* Ensure that the symbols for PER_CU have been read in. DWARF2_PER_OBJFILE is |
| the per-objfile for which this symtab is instantiated. |
| |
| Returns the resulting symbol table. */ |
| |
| static struct compunit_symtab * |
| dw2_instantiate_symtab (dwarf2_per_cu_data *per_cu, |
| dwarf2_per_objfile *per_objfile, |
| bool skip_partial) |
| { |
| if (!per_objfile->symtab_set_p (per_cu)) |
| { |
| free_cached_comp_units freer (per_objfile); |
| scoped_restore decrementer = increment_reading_symtab (); |
| dw2_do_instantiate_symtab (per_cu, per_objfile, skip_partial); |
| process_cu_includes (per_objfile); |
| } |
| |
| return per_objfile->get_symtab (per_cu); |
| } |
| |
| /* See read.h. */ |
| |
| dwarf2_per_cu_data_up |
| dwarf2_per_bfd::allocate_per_cu () |
| { |
| dwarf2_per_cu_data_up result (new dwarf2_per_cu_data); |
| result->per_bfd = this; |
| result->index = all_units.size (); |
| return result; |
| } |
| |
| /* See read.h. */ |
| |
| signatured_type_up |
| dwarf2_per_bfd::allocate_signatured_type (ULONGEST signature) |
| { |
| signatured_type_up result (new signatured_type (signature)); |
| result->per_bfd = this; |
| result->index = all_units.size (); |
| result->is_debug_types = true; |
| tu_stats.nr_tus++; |
| return result; |
| } |
| |
| /* See read.h. */ |
| |
| dwarf2_per_cu_data_up |
| create_cu_from_index_list (dwarf2_per_bfd *per_bfd, |
| struct dwarf2_section_info *section, |
| int is_dwz, |
| sect_offset sect_off, ULONGEST length) |
| { |
| dwarf2_per_cu_data_up the_cu = per_bfd->allocate_per_cu (); |
| the_cu->sect_off = sect_off; |
| the_cu->set_length (length); |
| the_cu->section = section; |
| the_cu->is_dwz = is_dwz; |
| return the_cu; |
| } |
| |
| /* die_reader_func for dw2_get_file_names. */ |
| |
| static void |
| dw2_get_file_names_reader (const struct die_reader_specs *reader, |
| struct die_info *comp_unit_die) |
| { |
| struct dwarf2_cu *cu = reader->cu; |
| struct dwarf2_per_cu_data *this_cu = cu->per_cu; |
| dwarf2_per_objfile *per_objfile = cu->per_objfile; |
| struct dwarf2_per_cu_data *lh_cu; |
| struct attribute *attr; |
| void **slot; |
| struct quick_file_names *qfn; |
| |
| gdb_assert (! this_cu->is_debug_types); |
| |
| this_cu->files_read = true; |
| /* 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) |
| return; |
| |
| lh_cu = this_cu; |
| slot = NULL; |
| |
| line_header_up lh; |
| sect_offset line_offset {}; |
| |
| file_and_directory &fnd = find_file_and_directory (comp_unit_die, cu); |
| |
| attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu); |
| if (attr != nullptr && attr->form_is_unsigned ()) |
| { |
| struct quick_file_names find_entry; |
| |
| line_offset = (sect_offset) attr->as_unsigned (); |
| |
| /* 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 (per_objfile->per_bfd->quick_file_names_table.get (), |
| &find_entry, INSERT); |
| if (*slot != NULL) |
| { |
| lh_cu->file_names = (struct quick_file_names *) *slot; |
| return; |
| } |
| |
| lh = dwarf_decode_line_header (line_offset, cu, fnd.get_comp_dir ()); |
| } |
| |
| int offset = 0; |
| if (!fnd.is_unknown ()) |
| ++offset; |
| else if (lh == nullptr) |
| return; |
| |
| qfn = XOBNEW (&per_objfile->per_bfd->obstack, struct quick_file_names); |
| qfn->hash.dwo_unit = cu->dwo_unit; |
| qfn->hash.line_sect_off = line_offset; |
| /* There may not be a DW_AT_stmt_list. */ |
| if (slot != nullptr) |
| *slot = qfn; |
| |
| std::vector<const char *> include_names; |
| if (lh != nullptr) |
| { |
| for (const auto &entry : lh->file_names ()) |
| { |
| std::string name_holder; |
| const char *include_name = |
| compute_include_file_name (lh.get (), entry, fnd, name_holder); |
| if (include_name != nullptr) |
| { |
| include_name = per_objfile->objfile->intern (include_name); |
| include_names.push_back (include_name); |
| } |
| } |
| } |
| |
| qfn->num_file_names = offset + include_names.size (); |
| qfn->comp_dir = fnd.intern_comp_dir (per_objfile->objfile); |
| qfn->file_names = |
| XOBNEWVEC (&per_objfile->per_bfd->obstack, const char *, |
| qfn->num_file_names); |
| if (offset != 0) |
| qfn->file_names[0] = per_objfile->objfile->intern (fnd.get_name ()); |
| |
| if (!include_names.empty ()) |
| memcpy (&qfn->file_names[offset], include_names.data (), |
| include_names.size () * sizeof (const char *)); |
| |
| qfn->real_names = NULL; |
| |
| lh_cu->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 (dwarf2_per_cu_data *this_cu, |
| dwarf2_per_objfile *per_objfile) |
| { |
| /* This should never be called for TUs. */ |
| gdb_assert (! this_cu->is_debug_types); |
| |
| if (this_cu->files_read) |
| return this_cu->file_names; |
| |
| cutu_reader reader (this_cu, per_objfile); |
| if (!reader.dummy_p) |
| dw2_get_file_names_reader (&reader, reader.comp_unit_die); |
| |
| return this_cu->file_names; |
| } |
| |
| /* A helper for the "quick" functions which computes and caches the |
| real path for a given file name from the line table. */ |
| |
| static const char * |
| dw2_get_real_path (dwarf2_per_objfile *per_objfile, |
| struct quick_file_names *qfn, int index) |
| { |
| if (qfn->real_names == NULL) |
| qfn->real_names = OBSTACK_CALLOC (&per_objfile->per_bfd->obstack, |
| qfn->num_file_names, const char *); |
| |
| if (qfn->real_names[index] == NULL) |
| { |
| const char *dirname = nullptr; |
| |
| if (!IS_ABSOLUTE_PATH (qfn->file_names[index])) |
| dirname = qfn->comp_dir; |
| |
| gdb::unique_xmalloc_ptr<char> fullname; |
| fullname = find_source_or_rewrite (qfn->file_names[index], dirname); |
| |
| qfn->real_names[index] = fullname.release (); |
| } |
| |
| return qfn->real_names[index]; |
| } |
| |
| struct symtab * |
| dwarf2_base_index_functions::find_last_source_symtab (struct objfile *objfile) |
| { |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| dwarf2_per_cu_data *dwarf_cu |
| = per_objfile->per_bfd->all_units.back ().get (); |
| compunit_symtab *cust = dw2_instantiate_symtab (dwarf_cu, per_objfile, false); |
| |
| if (cust == NULL) |
| return NULL; |
| |
| return cust->primary_filetab (); |
| } |
| |
| /* See read.h. */ |
| |
| void |
| dwarf2_per_cu_data::free_cached_file_names () |
| { |
| if (fnd != nullptr) |
| fnd->forget_fullname (); |
| |
| if (per_bfd == nullptr) |
| return; |
| |
| struct quick_file_names *file_data = file_names; |
| if (file_data != nullptr && file_data->real_names != nullptr) |
| { |
| for (int i = 0; i < file_data->num_file_names; ++i) |
| { |
| xfree ((void *) file_data->real_names[i]); |
| file_data->real_names[i] = nullptr; |
| } |
| } |
| } |
| |
| void |
| dwarf2_base_index_functions::forget_cached_source_info |
| (struct objfile *objfile) |
| { |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| |
| for (auto &per_cu : per_objfile->per_bfd->all_units) |
| per_cu->free_cached_file_names (); |
| } |
| |
| void |
| dwarf2_base_index_functions::print_stats (struct objfile *objfile, |
| bool print_bcache) |
| { |
| if (print_bcache) |
| return; |
| |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| int total = per_objfile->per_bfd->all_units.size (); |
| int count = 0; |
| |
| for (int i = 0; i < total; ++i) |
| { |
| dwarf2_per_cu_data *per_cu = per_objfile->per_bfd->get_cu (i); |
| |
| if (!per_objfile->symtab_set_p (per_cu)) |
| ++count; |
| } |
| gdb_printf (_(" Number of read CUs: %d\n"), total - count); |
| gdb_printf (_(" Number of unread CUs: %d\n"), count); |
| } |
| |
| void |
| dwarf2_base_index_functions::expand_all_symtabs (struct objfile *objfile) |
| { |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| int total_units = per_objfile->per_bfd->all_units.size (); |
| |
| for (int i = 0; i < total_units; ++i) |
| { |
| dwarf2_per_cu_data *per_cu = per_objfile->per_bfd->get_cu (i); |
| |
| /* We don't want to directly expand a partial CU, because if we |
| read it with the wrong language, then assertion failures can |
| be triggered later on. See PR symtab/23010. So, tell |
| dw2_instantiate_symtab to skip partial CUs -- any important |
| partial CU will be read via DW_TAG_imported_unit anyway. */ |
| dw2_instantiate_symtab (per_cu, per_objfile, true); |
| } |
| } |
| |
| |
| /* Starting from a search name, return the string that finds the upper |
| bound of all strings that start with SEARCH_NAME in a sorted name |
| list. Returns the empty string to indicate that the upper bound is |
| the end of the list. */ |
| |
| static std::string |
| make_sort_after_prefix_name (const char *search_name) |
| { |
| /* When looking to complete "func", we find the upper bound of all |
| symbols that start with "func" by looking for where we'd insert |
| the closest string that would follow "func" in lexicographical |
| order. Usually, that's "func"-with-last-character-incremented, |
| i.e. "fund". Mind non-ASCII characters, though. Usually those |
| will be UTF-8 multi-byte sequences, but we can't be certain. |
| Especially mind the 0xff character, which is a valid character in |
| non-UTF-8 source character sets (e.g. Latin1 'ÿ'), and we can't |
| rule out compilers allowing it in identifiers. Note that |
| conveniently, strcmp/strcasecmp are specified to compare |
| characters interpreted as unsigned char. So what we do is treat |
| the whole string as a base 256 number composed of a sequence of |
| base 256 "digits" and add 1 to it. I.e., adding 1 to 0xff wraps |
| to 0, and carries 1 to the following more-significant position. |
| If the very first character in SEARCH_NAME ends up incremented |
| and carries/overflows, then the upper bound is the end of the |
| list. The string after the empty string is also the empty |
| string. |
| |
| Some examples of this operation: |
| |
| SEARCH_NAME => "+1" RESULT |
| |
| "abc" => "abd" |
| "ab\xff" => "ac" |
| "\xff" "a" "\xff" => "\xff" "b" |
| "\xff" => "" |
| "\xff\xff" => "" |
| "" => "" |
| |
| Then, with these symbols for example: |
| |
| func |
| func1 |
| fund |
| |
| completing "func" looks for symbols between "func" and |
| "func"-with-last-character-incremented, i.e. "fund" (exclusive), |
| which finds "func" and "func1", but not "fund". |
| |
| And with: |
| |
| funcÿ (Latin1 'ÿ' [0xff]) |
| funcÿ1 |
| fund |
| |
| completing "funcÿ" looks for symbols between "funcÿ" and "fund" |
| (exclusive), which finds "funcÿ" and "funcÿ1", but not "fund". |
| |
| And with: |
| |
| ÿÿ (Latin1 'ÿ' [0xff]) |
| ÿÿ1 |
| |
| completing "ÿ" or "ÿÿ" looks for symbols between between "ÿÿ" and |
| the end of the list. |
| */ |
| std::string after = search_name; |
| while (!after.empty () && (unsigned char) after.back () == 0xff) |
| after.pop_back (); |
| if (!after.empty ()) |
| after.back () = (unsigned char) after.back () + 1; |
| return after; |
| } |
| |
| /* See declaration. */ |
| |
| std::pair<std::vector<name_component>::const_iterator, |
| std::vector<name_component>::const_iterator> |
| mapped_index_base::find_name_components_bounds |
| (const lookup_name_info &lookup_name_without_params, language lang, |
| dwarf2_per_objfile *per_objfile) const |
| { |
| auto *name_cmp |
| = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp; |
| |
| const char *lang_name |
| = lookup_name_without_params.language_lookup_name (lang); |
| |
| /* Comparison function object for lower_bound that matches against a |
| given symbol name. */ |
| auto lookup_compare_lower = [&] (const name_component &elem, |
| const char *name) |
| { |
| const char *elem_qualified = this->symbol_name_at (elem.idx, per_objfile); |
| const char *elem_name = elem_qualified + elem.name_offset; |
| return name_cmp (elem_name, name) < 0; |
| }; |
| |
| /* Comparison function object for upper_bound that matches against a |
| given symbol name. */ |
| auto lookup_compare_upper = [&] (const char *name, |
| const name_component &elem) |
| { |
| const char *elem_qualified = this->symbol_name_at (elem.idx, per_objfile); |
| const char *elem_name = elem_qualified + elem.name_offset; |
| return name_cmp (name, elem_name) < 0; |
| }; |
| |
| auto begin = this->name_components.begin (); |
| auto end = this->name_components.end (); |
| |
| /* Find the lower bound. */ |
| auto lower = [&] () |
| { |
| if (lookup_name_without_params.completion_mode () && lang_name[0] == '\0') |
| return begin; |
| else |
| return std::lower_bound (begin, end, lang_name, lookup_compare_lower); |
| } (); |
| |
| /* Find the upper bound. */ |
| auto upper = [&] () |
| { |
| if (lookup_name_without_params.completion_mode ()) |
| { |
| /* In completion mode, we want UPPER to point past all |
| symbols names that have the same prefix. I.e., with |
| these symbols, and completing "func": |
| |
| function << lower bound |
| function1 |
| other_function << upper bound |
| |
| We find the upper bound by looking for the insertion |
| point of "func"-with-last-character-incremented, |
| i.e. "fund". */ |
| std::string after = make_sort_after_prefix_name (lang_name); |
| if (after.empty ()) |
| return end; |
| return std::lower_bound (lower, end, after.c_str (), |
| lookup_compare_lower); |
| } |
| else |
| return std::upper_bound (lower, end, lang_name, lookup_compare_upper); |
| } (); |
| |
| return {lower, upper}; |
| } |
| |
| /* See declaration. */ |
| |
| void |
| mapped_index_base::build_name_components (dwarf2_per_objfile *per_objfile) |
| { |
| if (!this->name_components.empty ()) |
| return; |
| |
| this->name_components_casing = case_sensitivity; |
| auto *name_cmp |
| = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp; |
| |
| /* The code below only knows how to break apart components of C++ |
| symbol names (and other languages that use '::' as |
| namespace/module separator) and Ada symbol names. */ |
| auto count = this->symbol_name_count (); |
| for (offset_type idx = 0; idx < count; idx++) |
| { |
| if (this->symbol_name_slot_invalid (idx)) |
| continue; |
| |
| const char *name = this->symbol_name_at (idx, per_objfile); |
| |
| /* Add each name component to the name component table. */ |
| unsigned int previous_len = 0; |
| |
| if (strstr (name, "::") != nullptr) |
| { |
| for (unsigned int current_len = cp_find_first_component (name); |
| name[current_len] != '\0'; |
| current_len += cp_find_first_component (name + current_len)) |
| { |
| gdb_assert (name[current_len] == ':'); |
| this->name_components.push_back ({previous_len, idx}); |
| /* Skip the '::'. */ |
| current_len += 2; |
| previous_len = current_len; |
| } |
| } |
| else |
| { |
| /* Handle the Ada encoded (aka mangled) form here. */ |
| for (const char *iter = strstr (name, "__"); |
| iter != nullptr; |
| iter = strstr (iter, "__")) |
| { |
| this->name_components.push_back ({previous_len, idx}); |
| iter += 2; |
| previous_len = iter - name; |
| } |
| } |
| |
| this->name_components.push_back ({previous_len, idx}); |
| } |
| |
| /* Sort name_components elements by name. */ |
| auto name_comp_compare = [&] (const name_component &left, |
| const name_component &right) |
| { |
| const char *left_qualified |
| = this->symbol_name_at (left.idx, per_objfile); |
| const char *right_qualified |
| = this->symbol_name_at (right.idx, per_objfile); |
| |
| const char *left_name = left_qualified + left.name_offset; |
| const char *right_name = right_qualified + right.name_offset; |
| |
| return name_cmp (left_name, right_name) < 0; |
| }; |
| |
| std::sort (this->name_components.begin (), |
| this->name_components.end (), |
| name_comp_compare); |
| } |
| |
| /* See read.h. */ |
| |
| bool |
| dw2_expand_symtabs_matching_symbol |
| (mapped_index_base &index, |
| const lookup_name_info &lookup_name_in, |
| gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher, |
| gdb::function_view<bool (offset_type)> match_callback, |
| dwarf2_per_objfile *per_objfile) |
| { |
| lookup_name_info lookup_name_without_params |
| = lookup_name_in.make_ignore_params (); |
| |
| /* Build the symbol name component sorted vector, if we haven't |
| yet. */ |
| index.build_name_components (per_objfile); |
| |
| /* The same symbol may appear more than once in the range though. |
| E.g., if we're looking for symbols that complete "w", and we have |
| a symbol named "w1::w2", we'll find the two name components for |
| that same symbol in the range. To be sure we only call the |
| callback once per symbol, we first collect the symbol name |
| indexes that matched in a temporary vector and ignore |
| duplicates. */ |
| std::vector<offset_type> matches; |
| |
| struct name_and_matcher |
| { |
| symbol_name_matcher_ftype *matcher; |
| const char *name; |
| |
| bool operator== (const name_and_matcher &other) const |
| { |
| return matcher == other.matcher && strcmp (name, other.name) == 0; |
| } |
| }; |
| |
| /* A vector holding all the different symbol name matchers, for all |
| languages. */ |
| std::vector<name_and_matcher> matchers; |
| |
| for (int i = 0; i < nr_languages; i++) |
| { |
| enum language lang_e = (enum language) i; |
| |
| const language_defn *lang = language_def (lang_e); |
| symbol_name_matcher_ftype *name_matcher |
| = lang->get_symbol_name_matcher (lookup_name_without_params); |
| |
| name_and_matcher key { |
| name_matcher, |
| lookup_name_without_params.language_lookup_name (lang_e) |
| }; |
| |
| /* Don't insert the same comparison routine more than once. |
| Note that we do this linear walk. This is not a problem in |
| practice because the number of supported languages is |
| low. */ |
| if (std::find (matchers.begin (), matchers.end (), key) |
| != matchers.end ()) |
| continue; |
| matchers.push_back (std::move (key)); |
| |
| auto bounds |
| = index.find_name_components_bounds (lookup_name_without_params, |
| lang_e, per_objfile); |
| |
| /* Now for each symbol name in range, check to see if we have a name |
| match, and if so, call the MATCH_CALLBACK callback. */ |
| |
| for (; bounds.first != bounds.second; ++bounds.first) |
| { |
| const char *qualified |
| = index.symbol_name_at (bounds.first->idx, per_objfile); |
| |
| if (!name_matcher (qualified, lookup_name_without_params, NULL) |
| || (symbol_matcher != NULL && !symbol_matcher (qualified))) |
| continue; |
| |
| matches.push_back (bounds.first->idx); |
| } |
| } |
| |
| std::sort (matches.begin (), matches.end ()); |
| |
| /* Finally call the callback, once per match. */ |
| ULONGEST prev = -1; |
| bool result = true; |
| for (offset_type idx : matches) |
| { |
| if (prev != idx) |
| { |
| if (!match_callback (idx)) |
| { |
| result = false; |
| break; |
| } |
| prev = idx; |
| } |
| } |
| |
| /* Above we use a type wider than idx's for 'prev', since 0 and |
| (offset_type)-1 are both possible values. */ |
| static_assert (sizeof (prev) > sizeof (offset_type), ""); |
| |
| return result; |
| } |
| |
| #if GDB_SELF_TEST |
| |
| namespace selftests { namespace dw2_expand_symtabs_matching { |
| |
| /* A mock .gdb_index/.debug_names-like name index table, enough to |
| exercise dw2_expand_symtabs_matching_symbol, which works with the |
| mapped_index_base interface. Builds an index from the symbol list |
| passed as parameter to the constructor. */ |
| class mock_mapped_index : public mapped_index_base |
| { |
| public: |
| mock_mapped_index (gdb::array_view<const char *> symbols) |
| : m_symbol_table (symbols) |
| {} |
| |
| DISABLE_COPY_AND_ASSIGN (mock_mapped_index); |
| |
| /* Return the number of names in the symbol table. */ |
| size_t symbol_name_count () const override |
| { |
| return m_symbol_table.size (); |
| } |
| |
| /* Get the name of the symbol at IDX in the symbol table. */ |
| const char *symbol_name_at |
| (offset_type idx, dwarf2_per_objfile *per_objfile) const override |
| { |
| return m_symbol_table[idx]; |
| } |
| |
| quick_symbol_functions_up make_quick_functions () const override |
| { |
| return nullptr; |
| } |
| |
| private: |
| gdb::array_view<const char *> m_symbol_table; |
| }; |
| |
| /* Convenience function that converts a NULL pointer to a "<null>" |
| string, to pass to print routines. */ |
| |
| static const char * |
| string_or_null (const char *str) |
| { |
| return str != NULL ? str : "<null>"; |
| } |
| |
| /* Check if a lookup_name_info built from |
| NAME/MATCH_TYPE/COMPLETION_MODE matches the symbols in the mock |
| index. EXPECTED_LIST is the list of expected matches, in expected |
| matching order. If no match expected, then an empty list is |
| specified. Returns true on success. On failure prints a warning |
| indicating the file:line that failed, and returns false. */ |
| |
| static bool |
| check_match (const char *file, int line, |
| mock_mapped_index &mock_index, |
| const char *name, symbol_name_match_type match_type, |
| bool completion_mode, |
| std::initializer_list<const char *> expected_list, |
| dwarf2_per_objfile *per_objfile) |
| { |
| lookup_name_info lookup_name (name, match_type, completion_mode); |
| |
| bool matched = true; |
| |
| auto mismatch = [&] (const char *expected_str, |
| const char *got) |
| { |
| warning (_("%s:%d: match_type=%s, looking-for=\"%s\", " |
| "expected=\"%s\", got=\"%s\"\n"), |
| file, line, |
| (match_type == symbol_name_match_type::FULL |
| ? "FULL" : "WILD"), |
| name, string_or_null (expected_str), string_or_null (got)); |
| matched = false; |
| }; |
| |
| auto expected_it = expected_list.begin (); |
| auto expected_end = expected_list.end (); |
| |
| dw2_expand_symtabs_matching_symbol (mock_index, lookup_name, |
| nullptr, |
| [&] (offset_type idx) |
| { |
| const char *matched_name = mock_index.symbol_name_at (idx, per_objfile); |
| const char *expected_str |
| = expected_it == expected_end ? NULL : *expected_it++; |
| |
| if (expected_str == NULL || strcmp (expected_str, matched_name) != 0) |
| mismatch (expected_str, matched_name); |
| return true; |
| }, per_objfile); |
| |
| const char *expected_str |
| = expected_it == expected_end ? NULL : *expected_it++; |
| if (expected_str != NULL) |
| mismatch (expected_str, NULL); |
| |
| return matched; |
| } |
| |
| /* The symbols added to the mock mapped_index for testing (in |
| canonical form). */ |
| static const char *test_symbols[] = { |
| "function", |
| "std::bar", |
| "std::zfunction", |
| "std::zfunction2", |
| "w1::w2", |
| "ns::foo<char*>", |
| "ns::foo<int>", |
| "ns::foo<long>", |
| "ns2::tmpl<int>::foo2", |
| "(anonymous namespace)::A::B::C", |
| |
| /* These are used to check that the increment-last-char in the |
| matching algorithm for completion doesn't match "t1_fund" when |
| completing "t1_func". */ |
| "t1_func", |
| "t1_func1", |
| "t1_fund", |
| "t1_fund1", |
| |
| /* A UTF-8 name with multi-byte sequences to make sure that |
| cp-name-parser understands this as a single identifier ("função" |
| is "function" in PT). */ |
| (const char *)u8"u8função", |
| |
| /* Test a symbol name that ends with a 0xff character, which is a |
| valid character in non-UTF-8 source character sets (e.g. Latin1 |
| 'ÿ'), and we can't rule out compilers allowing it in identifiers. |
| We test this because the completion algorithm finds the upper |
| bound of symbols by looking for the insertion point of |
| "func"-with-last-character-incremented, i.e. "fund", and adding 1 |
| to 0xff should wraparound and carry to the previous character. |
| See comments in make_sort_after_prefix_name. */ |
| "yfunc\377", |
| |
| /* Some more symbols with \377 (0xff). See above. */ |
| "\377", |
| "\377\377123", |
| |
| /* A name with all sorts of complications. Starts with "z" to make |
| it easier for the completion tests below. */ |
| #define Z_SYM_NAME \ |
| "z::std::tuple<(anonymous namespace)::ui*, std::bar<(anonymous namespace)::ui> >" \ |
| "::tuple<(anonymous namespace)::ui*, " \ |
| "std::default_delete<(anonymous namespace)::ui>, void>" |
| |
| Z_SYM_NAME |
| }; |
| |
| /* Returns true if the mapped_index_base::find_name_component_bounds |
| method finds EXPECTED_SYMS in INDEX when looking for SEARCH_NAME, |
| in completion mode. */ |
| |
| static bool |
| check_find_bounds_finds (mapped_index_base &index, |
| const char *search_name, |
| gdb::array_view<const char *> expected_syms, |
| dwarf2_per_objfile *per_objfile) |
| { |
| lookup_name_info lookup_name (search_name, |
| symbol_name_match_type::FULL, true); |
| |
| auto bounds = index.find_name_components_bounds (lookup_name, |
| language_cplus, |
| per_objfile); |
| |
| size_t distance = std::distance (bounds.first, bounds.second); |
| if (distance != expected_syms.size ()) |
| return false; |
| |
| for (size_t exp_elem = 0; exp_elem < distance; exp_elem++) |
| { |
| auto nc_elem = bounds.first + exp_elem; |
| const char *qualified = index.symbol_name_at (nc_elem->idx, per_objfile); |
| if (strcmp (qualified, expected_syms[exp_elem]) != 0) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Test the lower-level mapped_index::find_name_component_bounds |
| method. */ |
| |
| static void |
| test_mapped_index_find_name_component_bounds () |
| { |
| mock_mapped_index mock_index (test_symbols); |
| |
| mock_index.build_name_components (NULL /* per_objfile */); |
| |
| /* Test the lower-level mapped_index::find_name_component_bounds |
| method in completion mode. */ |
| { |
| static const char *expected_syms[] = { |
| "t1_func", |
| "t1_func1", |
| }; |
| |
| SELF_CHECK (check_find_bounds_finds |
| (mock_index, "t1_func", expected_syms, |
| NULL /* per_objfile */)); |
| } |
| |
| /* Check that the increment-last-char in the name matching algorithm |
| for completion doesn't get confused with Ansi1 'ÿ' / 0xff. See |
| make_sort_after_prefix_name. */ |
| { |
| static const char *expected_syms1[] = { |
| "\377", |
| "\377\377123", |
| }; |
| SELF_CHECK (check_find_bounds_finds |
| (mock_index, "\377", expected_syms1, NULL /* per_objfile */)); |
| |
| static const char *expected_syms2[] = { |
| "\377\377123", |
| }; |
| SELF_CHECK (check_find_bounds_finds |
| (mock_index, "\377\377", expected_syms2, |
| NULL /* per_objfile */)); |
| } |
| } |
| |
| /* Test dw2_expand_symtabs_matching_symbol. */ |
| |
| static void |
| test_dw2_expand_symtabs_matching_symbol () |
| { |
| mock_mapped_index mock_index (test_symbols); |
| |
| /* We let all tests run until the end even if some fails, for debug |
| convenience. */ |
| bool any_mismatch = false; |
| |
| /* Create the expected symbols list (an initializer_list). Needed |
| because lists have commas, and we need to pass them to CHECK, |
| which is a macro. */ |
| #define EXPECT(...) { __VA_ARGS__ } |
| |
| /* Wrapper for check_match that passes down the current |
| __FILE__/__LINE__. */ |
| #define CHECK_MATCH(NAME, MATCH_TYPE, COMPLETION_MODE, EXPECTED_LIST) \ |
| any_mismatch |= !check_match (__FILE__, __LINE__, \ |
| mock_index, \ |
| NAME, MATCH_TYPE, COMPLETION_MODE, \ |
| EXPECTED_LIST, NULL) |
| |
| /* Identity checks. */ |
| for (const char *sym : test_symbols) |
| { |
| /* Should be able to match all existing symbols. */ |
| CHECK_MATCH (sym, symbol_name_match_type::FULL, false, |
| EXPECT (sym)); |
| |
| /* Should be able to match all existing symbols with |
| parameters. */ |
| std::string with_params = std::string (sym) + "(int)"; |
| CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, |
| EXPECT (sym)); |
| |
| /* Should be able to match all existing symbols with |
| parameters and qualifiers. */ |
| with_params = std::string (sym) + " ( int ) const"; |
| CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, |
| EXPECT (sym)); |
| |
| /* This should really find sym, but cp-name-parser.y doesn't |
| know about lvalue/rvalue qualifiers yet. */ |
| with_params = std::string (sym) + " ( int ) &&"; |
| CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, |
| {}); |
| } |
| |
| /* Check that the name matching algorithm for completion doesn't get |
| confused with Latin1 'ÿ' / 0xff. See |
| make_sort_after_prefix_name. */ |
| { |
| static const char str[] = "\377"; |
| CHECK_MATCH (str, symbol_name_match_type::FULL, true, |
| EXPECT ("\377", "\377\377123")); |
| } |
| |
| /* Check that the increment-last-char in the matching algorithm for |
| completion doesn't match "t1_fund" when completing "t1_func". */ |
| { |
| static const char str[] = "t1_func"; |
| CHECK_MATCH (str, symbol_name_match_type::FULL, true, |
| EXPECT ("t1_func", "t1_func1")); |
| } |
| |
| /* Check that completion mode works at each prefix of the expected |
| symbol name. */ |
| { |
| static const char str[] = "function(int)"; |
| size_t len = strlen (str); |
| std::string lookup; |
| |
| for (size_t i = 1; i < len; i++) |
| { |
| lookup.assign (str, i); |
| CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true, |
| EXPECT ("function")); |
| } |
| } |
| |
| /* While "w" is a prefix of both components, the match function |
| should still only be called once. */ |
| { |
| CHECK_MATCH ("w", symbol_name_match_type::FULL, true, |
| EXPECT ("w1::w2")); |
| CHECK_MATCH ("w", symbol_name_match_type::WILD, true, |
| EXPECT ("w1::w2")); |
| } |
| |
| /* Same, with a "complicated" symbol. */ |
| { |
| static const char str[] = Z_SYM_NAME; |
| size_t len = strlen (str); |
| std::string lookup; |
| |
| for (size_t i = 1; i < len; i++) |
| { |
| lookup.assign (str, i); |
| CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true, |
| EXPECT (Z_SYM_NAME)); |
| } |
| } |
| |
| /* In FULL mode, an incomplete symbol doesn't match. */ |
| { |
| CHECK_MATCH ("std::zfunction(int", symbol_name_match_type::FULL, false, |
| {}); |
| } |
| |
| /* A complete symbol with parameters matches any overload, since the |
| index has no overload info. */ |
| { |
| CHECK_MATCH ("std::zfunction(int)", symbol_name_match_type::FULL, true, |
| EXPECT ("std::zfunction", "std::zfunction2")); |
| CHECK_MATCH ("zfunction(int)", symbol_name_match_type::WILD, true, |
| EXPECT ("std::zfunction", "std::zfunction2")); |
| CHECK_MATCH ("zfunc", symbol_name_match_type::WILD, true, |
| EXPECT ("std::zfunction", "std::zfunction2")); |
| } |
| |
| /* Check that whitespace is ignored appropriately. A symbol with a |
| template argument list. */ |
| { |
| static const char expected[] = "ns::foo<int>"; |
| CHECK_MATCH ("ns :: foo < int > ", symbol_name_match_type::FULL, false, |
| EXPECT (expected)); |
| CHECK_MATCH ("foo < int > ", symbol_name_match_type::WILD, false, |
| EXPECT (expected)); |
| } |
| |
| /* Check that whitespace is ignored appropriately. A symbol with a |
| template argument list that includes a pointer. */ |
| { |
| static const char expected[] = "ns::foo<char*>"; |
| /* Try both completion and non-completion modes. */ |
| static const bool completion_mode[2] = {false, true}; |
| for (size_t i = 0; i < 2; i++) |
| { |
| CHECK_MATCH ("ns :: foo < char * >", symbol_name_match_type::FULL, |
| completion_mode[i], EXPECT (expected)); |
| CHECK_MATCH ("foo < char * >", symbol_name_match_type::WILD, |
| completion_mode[i], EXPECT (expected)); |
| |
| CHECK_MATCH ("ns :: foo < char * > (int)", symbol_name_match_type::FULL, |
| completion_mode[i], EXPECT (expected)); |
| CHECK_MATCH ("foo < char * > (int)", symbol_name_match_type::WILD, |
| completion_mode[i], EXPECT (expected)); |
| } |
| } |
| |
| { |
| /* Check method qualifiers are ignored. */ |
| static const char expected[] = "ns::foo<char*>"; |
| CHECK_MATCH ("ns :: foo < char * > ( int ) const", |
| symbol_name_match_type::FULL, true, EXPECT (expected)); |
| CHECK_MATCH ("ns :: foo < char * > ( int ) &&", |
| symbol_name_match_type::FULL, true, EXPECT (expected)); |
| CHECK_MATCH ("foo < char * > ( int ) const", |
| symbol_name_match_type::WILD, true, EXPECT (expected)); |
| CHECK_MATCH ("foo < char * > ( int ) &&", |
| symbol_name_match_type::WILD, true, EXPECT (expected)); |
| } |
| |
| /* Test lookup names that don't match anything. */ |
| { |
| CHECK_MATCH ("bar2", symbol_name_match_type::WILD, false, |
| {}); |
| |
| CHECK_MATCH ("doesntexist", symbol_name_match_type::FULL, false, |
| {}); |
| } |
| |
| /* Some wild matching tests, exercising "(anonymous namespace)", |
| which should not be confused with a parameter list. */ |
| { |
| static const char *syms[] = { |
| "A::B::C", |
| "B::C", |
| "C", |
| "A :: B :: C ( int )", |
| "B :: C ( int )", |
| "C ( int )", |
| }; |
| |
| for (const char *s : syms) |
| { |
| CHECK_MATCH (s, symbol_name_match_type::WILD, false, |
| EXPECT ("(anonymous namespace)::A::B::C")); |
| } |
| } |
| |
| { |
| static const char expected[] = "ns2::tmpl<int>::foo2"; |
| CHECK_MATCH ("tmp", symbol_name_match_type::WILD, true, |
| EXPECT (expected)); |
| CHECK_MATCH ("tmpl<", symbol_name_match_type::WILD, true, |
| EXPECT (expected)); |
| } |
| |
| SELF_CHECK (!any_mismatch); |
| |
| #undef EXPECT |
| #undef CHECK_MATCH |
| } |
| |
| static void |
| run_test () |
| { |
| test_mapped_index_find_name_component_bounds (); |
| test_dw2_expand_symtabs_matching_symbol (); |
| } |
| |
| }} // namespace selftests::dw2_expand_symtabs_matching |
| |
| #endif /* GDB_SELF_TEST */ |
| |
| /* See read.h. */ |
| |
| bool |
| dw2_expand_symtabs_matching_one |
| (dwarf2_per_cu_data *per_cu, |
| dwarf2_per_objfile *per_objfile, |
| gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher, |
| gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify) |
| { |
| if (file_matcher == NULL || per_cu->mark) |
| { |
| bool symtab_was_null = !per_objfile->symtab_set_p (per_cu); |
| |
| compunit_symtab *symtab |
| = dw2_instantiate_symtab (per_cu, per_objfile, false); |
| gdb_assert (symtab != nullptr); |
| |
| if (expansion_notify != NULL && symtab_was_null) |
| return expansion_notify (symtab); |
| } |
| return true; |
| } |
| |
| /* See read.h. */ |
| |
| void |
| dw_expand_symtabs_matching_file_matcher |
| (dwarf2_per_objfile *per_objfile, |
| gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher) |
| { |
| if (file_matcher == NULL) |
| return; |
| |
| htab_up visited_found (htab_create_alloc (10, htab_hash_pointer, |
| htab_eq_pointer, |
| NULL, xcalloc, xfree)); |
| htab_up visited_not_found (htab_create_alloc (10, htab_hash_pointer, |
| htab_eq_pointer, |
| NULL, xcalloc, xfree)); |
| |
| /* The rule is CUs specify all the files, including those used by |
| any TU, so there's no need to scan TUs here. */ |
| |
| for (const auto &per_cu : per_objfile->per_bfd->all_units) |
| { |
| QUIT; |
| |
| if (per_cu->is_debug_types) |
| continue; |
| per_cu->mark = 0; |
| |
| /* We only need to look at symtabs not already expanded. */ |
| if (per_objfile->symtab_set_p (per_cu.get ())) |
| continue; |
| |
| if (per_cu->fnd != nullptr) |
| { |
| file_and_directory *fnd = per_cu->fnd.get (); |
| |
| if (file_matcher (fnd->get_name (), false)) |
| { |
| per_cu->mark = 1; |
| continue; |
| } |
| |
| /* Before we invoke realpath, which can get expensive when many |
| files are involved, do a quick comparison of the basenames. */ |
| if ((basenames_may_differ |
| || file_matcher (lbasename (fnd->get_name ()), true)) |
| && file_matcher (fnd->get_fullname (), false)) |
| { |
| per_cu->mark = 1; |
| continue; |
| } |
| } |
| |
| quick_file_names *file_data = dw2_get_file_names (per_cu.get (), |
| per_objfile); |
| if (file_data == NULL) |
| continue; |
| |
| if (htab_find (visited_not_found.get (), file_data) != NULL) |
| continue; |
| else if (htab_find (visited_found.get (), file_data) != NULL) |
| { |
| per_cu->mark = 1; |
| continue; |
| } |
| |
| for (int j = 0; j < file_data->num_file_names; ++j) |
| { |
| const char *this_real_name; |
| |
| if (file_matcher (file_data->file_names[j], false)) |
| { |
| per_cu->mark = 1; |
| break; |
| } |
| |
| /* Before we invoke realpath, which can get expensive when many |
| files are involved, do a quick comparison of the basenames. */ |
| if (!basenames_may_differ |
| && !file_matcher (lbasename (file_data->file_names[j]), |
| true)) |
| continue; |
| |
| this_real_name = dw2_get_real_path (per_objfile, file_data, j); |
| if (file_matcher (this_real_name, false)) |
| { |
| per_cu->mark = 1; |
| break; |
| } |
| } |
| |
| void **slot = htab_find_slot (per_cu->mark |
| ? visited_found.get () |
| : visited_not_found.get (), |
| file_data, INSERT); |
| *slot = file_data; |
| } |
| } |
| |
| |
| /* 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 (cust->blockvector () != nullptr |
| && blockvector_contains_pc (cust->blockvector (), 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; |
| } |
| |
| struct compunit_symtab * |
| dwarf2_base_index_functions::find_pc_sect_compunit_symtab |
| (struct objfile *objfile, |
| bound_minimal_symbol msymbol, |
| CORE_ADDR pc, |
| struct obj_section *section, |
| int warn_if_readin) |
| { |
| struct compunit_symtab *result; |
| |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; |
| |
| if (per_bfd->index_table == nullptr) |
| return nullptr; |
| |
| CORE_ADDR baseaddr = objfile->text_section_offset (); |
| struct dwarf2_per_cu_data *data |
| = per_bfd->index_table->lookup ((unrelocated_addr) (pc - baseaddr)); |
| if (data == nullptr) |
| return nullptr; |
| |
| if (warn_if_readin && per_objfile->symtab_set_p (data)) |
| warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"), |
| paddress (objfile->arch (), pc)); |
| |
| result = recursively_find_pc_sect_compunit_symtab |
| (dw2_instantiate_symtab (data, per_objfile, false), pc); |
| |
| if (warn_if_readin && result == nullptr) |
| warning (_("(Error: pc %s in address map, but not in symtab.)"), |
| paddress (objfile->arch (), pc)); |
| |
| return result; |
| } |
| |
| void |
| dwarf2_base_index_functions::map_symbol_filenames |
| (struct objfile *objfile, |
| gdb::function_view<symbol_filename_ftype> fun, |
| bool need_fullname) |
| { |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| |
| /* Use caches to ensure we only call FUN once for each filename. */ |
| filename_seen_cache filenames_cache; |
| std::unordered_set<quick_file_names *> qfn_cache; |
| |
| /* 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. It is possible that an expanded CU might |
| reuse the file names data from a currently unexpanded CU, in this |
| case we don't want to report the files from the unexpanded CU. */ |
| |
| for (const auto &per_cu : per_objfile->per_bfd->all_units) |
| { |
| if (!per_cu->is_debug_types |
| && per_objfile->symtab_set_p (per_cu.get ())) |
| { |
| if (per_cu->file_names != nullptr) |
| qfn_cache.insert (per_cu->file_names); |
| } |
| } |
| |
| for (dwarf2_per_cu_data *per_cu |
| : all_units_range (per_objfile->per_bfd)) |
| { |
| /* We only need to look at symtabs not already expanded. */ |
| if (per_cu->is_debug_types || per_objfile->symtab_set_p (per_cu)) |
| continue; |
| |
| if (per_cu->fnd != nullptr) |
| { |
| file_and_directory *fnd = per_cu->fnd.get (); |
| |
| const char *filename = fnd->get_name (); |
| const char *key = filename; |
| const char *fullname = nullptr; |
| |
| if (need_fullname) |
| { |
| fullname = fnd->get_fullname (); |
| key = fullname; |
| } |
| |
| if (!filenames_cache.seen (key)) |
| fun (filename, fullname); |
| } |
| |
| quick_file_names *file_data = dw2_get_file_names (per_cu, per_objfile); |
| if (file_data == nullptr |
| || qfn_cache.find (file_data) != qfn_cache.end ()) |
| continue; |
| |
| for (int j = 0; j < file_data->num_file_names; ++j) |
| { |
| const char *filename = file_data->file_names[j]; |
| const char *key = filename; |
| const char *fullname = nullptr; |
| |
| if (need_fullname) |
| { |
| fullname = dw2_get_real_path (per_objfile, file_data, j); |
| key = fullname; |
| } |
| |
| if (!filenames_cache.seen (key)) |
| fun (filename, fullname); |
| } |
| } |
| } |
| |
| bool |
| dwarf2_base_index_functions::has_symbols (struct objfile *objfile) |
| { |
| return true; |
| } |
| |
| /* See quick_symbol_functions::has_unexpanded_symtabs in quick-symbol.h. */ |
| |
| bool |
| dwarf2_base_index_functions::has_unexpanded_symtabs (struct objfile *objfile) |
| { |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| |
| for (const auto &per_cu : per_objfile->per_bfd->all_units) |
| { |
| /* Is this already expanded? */ |
| if (per_objfile->symtab_set_p (per_cu.get ())) |
| continue; |
| |
| /* It has not yet been expanded. */ |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /* Get the content of the .gdb_index section of OBJ. SECTION_OWNER should point |
| to either a dwarf2_per_bfd or dwz_file object. */ |
| |
| template <typename T> |
| static gdb::array_view<const gdb_byte> |
| get_gdb_index_contents_from_section (objfile *obj, T *section_owner) |
| { |
| dwarf2_section_info *section = §ion_owner->gdb_index; |
| |
| if (section->empty ()) |
| return {}; |
| |
| /* 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 {}; |
| |
| section->read (obj); |
| |
| /* dwarf2_section_info::size is a bfd_size_type, while |
| gdb::array_view works with size_t. On 32-bit hosts, with |
| --enable-64-bit-bfd, bfd_size_type is a 64-bit type, while size_t |
| is 32-bit. So we need an explicit narrowing conversion here. |
| This is fine, because it's impossible to allocate or mmap an |
| array/buffer larger than what size_t can represent. */ |
| return gdb::make_array_view (section->buffer, section->size); |
| } |
| |
| /* Lookup the index cache for the contents of the index associated to |
| DWARF2_OBJ. */ |
| |
| static gdb::array_view<const gdb_byte> |
| get_gdb_index_contents_from_cache (objfile *obj, dwarf2_per_bfd *dwarf2_per_bfd) |
| { |
| const bfd_build_id *build_id = build_id_bfd_get (obj->obfd.get ()); |
| if (build_id == nullptr) |
| return {}; |
| |
| return global_index_cache.lookup_gdb_index (build_id, |
| &dwarf2_per_bfd->index_cache_res); |
| } |
| |
| /* Same as the above, but for DWZ. */ |
| |
| static gdb::array_view<const gdb_byte> |
| get_gdb_index_contents_from_cache_dwz (objfile *obj, dwz_file *dwz) |
| { |
| const bfd_build_id *build_id = build_id_bfd_get (dwz->dwz_bfd.get ()); |
| if (build_id == nullptr) |
| return {}; |
| |
| return global_index_cache.lookup_gdb_index (build_id, &dwz->index_cache_res); |
| } |
| |
| static void start_debug_info_reader (dwarf2_per_objfile *); |
| |
| /* See dwarf2/public.h. */ |
| |
| bool |
| dwarf2_initialize_objfile (struct objfile *objfile, |
| const struct dwarf2_debug_sections *names, |
| bool can_copy) |
| { |
| if (!dwarf2_has_info (objfile, names, can_copy)) |
| return false; |
| |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; |
| |
| dwarf_read_debug_printf ("called"); |
| |
| /* If we're about to read full symbols, don't bother with the |
| indices. In this case we also don't care if some other debug |
| format is making psymtabs, because they are all about to be |
| expanded anyway. */ |
| if ((objfile->flags & OBJF_READNOW)) |
| { |
| dwarf_read_debug_printf ("readnow requested"); |
| |
| create_all_units (per_objfile); |
| per_bfd->quick_file_names_table |
| = create_quick_file_names_table (per_bfd->all_units.size ()); |
| |
| objfile->qf.emplace_front (new readnow_functions); |
| } |
| /* Was a GDB index already read when we processed an objfile sharing |
| PER_BFD? */ |
| else if (per_bfd->index_table != nullptr) |
| dwarf_read_debug_printf ("re-using symbols"); |
| else if (dwarf2_read_debug_names (per_objfile)) |
| dwarf_read_debug_printf ("found debug names"); |
| else if (dwarf2_read_gdb_index (per_objfile, |
| get_gdb_index_contents_from_section<struct dwarf2_per_bfd>, |
| get_gdb_index_contents_from_section<dwz_file>)) |
| dwarf_read_debug_printf ("found gdb index from file"); |
| /* ... otherwise, try to find the index in the index cache. */ |
| else if (dwarf2_read_gdb_index (per_objfile, |
| get_gdb_index_contents_from_cache, |
| get_gdb_index_contents_from_cache_dwz)) |
| { |
| dwarf_read_debug_printf ("found gdb index from cache"); |
| global_index_cache.hit (); |
| } |
| else |
| { |
| global_index_cache.miss (); |
| start_debug_info_reader ( |