CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
22430 lines
689 KiB
C
22430 lines
689 KiB
C
/* DWARF 2 debugging format support for GDB.
|
|
|
|
Copyright (C) 1994-2024 Free Software Foundation, Inc.
|
|
Copyright (C) 2019-2024 Advanced Micro Devices, Inc. All rights reserved.
|
|
|
|
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 "gdb-hip-test-mode.h"
|
|
#include "dwarf2/read.h"
|
|
#include "dwarf2/abbrev.h"
|
|
#include "dwarf2/aranges.h"
|
|
#include "dwarf2/attribute.h"
|
|
#include "dwarf2/comp-unit-head.h"
|
|
#include "dwarf2/cooked-index.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/parallel-for.h"
|
|
#include "maint.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 "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-table-cache.h"
|
|
#include "cooked-index.h"
|
|
#include "run-on-main-thread.h"
|
|
#include "dwarf2/parent-map.h"
|
|
#include "dwarf2/error.h"
|
|
#include <variant>
|
|
#include "gdbsupport/unordered_set.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. */
|
|
std::vector<dwarf2_section_info> infos;
|
|
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. */
|
|
const 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,
|
|
const struct abbrev_table *abbrev_table,
|
|
dwarf2_cu *existing_cu,
|
|
bool skip_partial,
|
|
const abbrev_table_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_),
|
|
captured_cwd (current_directory),
|
|
captured_debug_dir (debug_file_directory)
|
|
{
|
|
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);
|
|
}
|
|
|
|
/* Virtual sections are created from DWP files. It's not clear those
|
|
can occur here, so perhaps the is_virtual checks here are dead code. */
|
|
const bool has_info = (!per_objfile->per_bfd->infos.empty ()
|
|
&& !per_objfile->per_bfd->infos[0].is_virtual
|
|
&& per_objfile->per_bfd->infos[0].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))
|
|
{
|
|
struct dwarf2_section_info info_section;
|
|
memset (&info_section, 0, sizeof (info_section));
|
|
info_section.s.section = sectp;
|
|
info_section.size = bfd_section_size (sectp);
|
|
this->infos.push_back (info_section);
|
|
}
|
|
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)
|
|
{
|
|
for (auto §ion : infos)
|
|
section.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,
|
|
gdb::function_view<expand_symtabs_lang_matcher_ftype> lang_matcher)
|
|
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,
|
|
gdb::function_view<expand_symtabs_lang_matcher_ftype> lang_matcher)
|
|
{
|
|
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;
|
|
if (lang_matcher != nullptr && !lang_matcher (lang_e))
|
|
continue;
|
|
|
|
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, nullptr);
|
|
|
|
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,
|
|
gdb::function_view<expand_symtabs_lang_matcher_ftype> lang_matcher)
|
|
{
|
|
if (file_matcher != nullptr && !per_cu->mark)
|
|
return true;
|
|
|
|
if (lang_matcher != nullptr)
|
|
{
|
|
/* Try to skip CUs with non-matching language. */
|
|
per_cu->ensure_lang (per_objfile);
|
|
if (!per_cu->maybe_multi_language ()
|
|
&& !lang_matcher (per_cu->lang ()))
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
|
|
gdb::unordered_set<quick_file_names *> visited_found;
|
|
gdb::unordered_set<quick_file_names *> visited_not_found;
|
|
|
|
/* 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 (visited_not_found.contains (file_data))
|
|
continue;
|
|
else if (visited_found.contains (file_data))
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (per_cu->mark)
|
|
visited_found.insert (file_data);
|
|
else
|
|
visited_not_found.insert (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 (per_objfile);
|
|
}
|
|
|
|
if (per_bfd->index_table != nullptr)
|
|
{
|
|
if (dwarf_synchronous)
|
|
per_bfd->index_table->wait_completely ();
|
|
objfile->qf.push_front (per_bfd->index_table->make_quick_functions ());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/* Find the base address of the compilation unit for range lists and
|
|
location lists. It will normally be specified by DW_AT_low_pc.
|
|
In DWARF-3 draft 4, the base address could be overridden by
|
|
DW_AT_entry_pc. It's been removed, but GCC still uses this for
|
|
compilation units with discontinuous ranges. */
|
|
|
|
static void
|
|
dwarf2_find_base_address (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
cu->base_address.reset ();
|
|
|
|
attr = dwarf2_attr (die, DW_AT_entry_pc, cu);
|
|
if (attr != nullptr)
|
|
cu->base_address = attr->as_address ();
|
|
else
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_low_pc, cu);
|
|
if (attr != nullptr)
|
|
cu->base_address = attr->as_address ();
|
|
}
|
|
}
|
|
|
|
/* Helper function that returns the proper abbrev section for
|
|
THIS_CU. */
|
|
|
|
static struct dwarf2_section_info *
|
|
get_abbrev_section_for_cu (struct dwarf2_per_cu_data *this_cu)
|
|
{
|
|
struct dwarf2_section_info *abbrev;
|
|
dwarf2_per_bfd *per_bfd = this_cu->per_bfd;
|
|
|
|
if (this_cu->is_dwz)
|
|
abbrev = &dwarf2_get_dwz_file (per_bfd, true)->abbrev;
|
|
else
|
|
abbrev = &per_bfd->abbrev;
|
|
|
|
return abbrev;
|
|
}
|
|
|
|
/* Fetch the abbreviation table offset from a comp or type unit header. */
|
|
|
|
static sect_offset
|
|
read_abbrev_offset (dwarf2_per_objfile *per_objfile,
|
|
struct dwarf2_section_info *section,
|
|
sect_offset sect_off)
|
|
{
|
|
bfd *abfd = section->get_bfd_owner ();
|
|
const gdb_byte *info_ptr;
|
|
unsigned int initial_length_size, offset_size;
|
|
uint16_t version;
|
|
|
|
section->read (per_objfile->objfile);
|
|
info_ptr = section->buffer + to_underlying (sect_off);
|
|
read_initial_length (abfd, info_ptr, &initial_length_size);
|
|
offset_size = initial_length_size == 4 ? 4 : 8;
|
|
info_ptr += initial_length_size;
|
|
|
|
version = read_2_bytes (abfd, info_ptr);
|
|
info_ptr += 2;
|
|
if (version >= 5)
|
|
{
|
|
/* Skip unit type and address size. */
|
|
info_ptr += 2;
|
|
}
|
|
|
|
return (sect_offset) read_offset (abfd, info_ptr, offset_size);
|
|
}
|
|
|
|
static hashval_t
|
|
hash_signatured_type (const void *item)
|
|
{
|
|
const struct signatured_type *sig_type
|
|
= (const struct signatured_type *) item;
|
|
|
|
/* This drops the top 32 bits of the signature, but is ok for a hash. */
|
|
return sig_type->signature;
|
|
}
|
|
|
|
static int
|
|
eq_signatured_type (const void *item_lhs, const void *item_rhs)
|
|
{
|
|
const struct signatured_type *lhs = (const struct signatured_type *) item_lhs;
|
|
const struct signatured_type *rhs = (const struct signatured_type *) item_rhs;
|
|
|
|
return lhs->signature == rhs->signature;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
htab_up
|
|
allocate_signatured_type_table ()
|
|
{
|
|
return htab_up (htab_create_alloc (41,
|
|
hash_signatured_type,
|
|
eq_signatured_type,
|
|
NULL, xcalloc, xfree));
|
|
}
|
|
|
|
/* A helper for create_debug_types_hash_table. Read types from SECTION
|
|
and fill them into DWO_FILE's type unit hash table. It will process only
|
|
type units, therefore DW_UT_type. */
|
|
|
|
static void
|
|
create_debug_type_hash_table (dwarf2_per_objfile *per_objfile,
|
|
dwo_file *dwo_file, dwarf2_section_info *section,
|
|
rcuh_kind section_kind)
|
|
{
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct dwarf2_section_info *abbrev_section;
|
|
bfd *abfd;
|
|
const gdb_byte *info_ptr, *end_ptr;
|
|
|
|
abbrev_section = &dwo_file->sections.abbrev;
|
|
|
|
dwarf_read_debug_printf ("Reading %s for %s",
|
|
section->get_name (),
|
|
abbrev_section->get_file_name ());
|
|
|
|
section->read (objfile);
|
|
info_ptr = section->buffer;
|
|
|
|
if (info_ptr == NULL)
|
|
return;
|
|
|
|
/* We can't set abfd until now because the section may be empty or
|
|
not present, in which case the bfd is unknown. */
|
|
abfd = section->get_bfd_owner ();
|
|
|
|
/* We don't use cutu_reader here because we don't need to read
|
|
any dies: the signature is in the header. */
|
|
|
|
end_ptr = info_ptr + section->size;
|
|
while (info_ptr < end_ptr)
|
|
{
|
|
signatured_type_up sig_type;
|
|
struct dwo_unit *dwo_tu;
|
|
void **slot;
|
|
const gdb_byte *ptr = info_ptr;
|
|
struct comp_unit_head header;
|
|
unsigned int length;
|
|
|
|
sect_offset sect_off = (sect_offset) (ptr - section->buffer);
|
|
|
|
/* Initialize it due to a false compiler warning. */
|
|
header.signature = -1;
|
|
header.type_cu_offset_in_tu = (cu_offset) -1;
|
|
|
|
/* We need to read the type's signature in order to build the hash
|
|
table, but we don't need anything else just yet. */
|
|
|
|
ptr = read_and_check_comp_unit_head (per_objfile, &header, section,
|
|
abbrev_section, ptr, section_kind);
|
|
|
|
length = header.get_length_with_initial ();
|
|
|
|
/* Skip dummy type units. */
|
|
if (ptr >= info_ptr + length
|
|
|| peek_abbrev_code (abfd, ptr) == 0
|
|
|| (header.unit_type != DW_UT_type
|
|
&& header.unit_type != DW_UT_split_type))
|
|
{
|
|
info_ptr += length;
|
|
continue;
|
|
}
|
|
|
|
if (dwo_file->tus == nullptr)
|
|
dwo_file->tus = allocate_dwo_unit_table ();
|
|
|
|
dwo_tu = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, dwo_unit);
|
|
dwo_tu->dwo_file = dwo_file;
|
|
dwo_tu->signature = header.signature;
|
|
dwo_tu->type_offset_in_tu = header.type_cu_offset_in_tu;
|
|
dwo_tu->section = section;
|
|
dwo_tu->sect_off = sect_off;
|
|
dwo_tu->length = length;
|
|
|
|
slot = htab_find_slot (dwo_file->tus.get (), dwo_tu, INSERT);
|
|
gdb_assert (slot != NULL);
|
|
if (*slot != NULL)
|
|
complaint (_("debug type entry at offset %s is duplicate to"
|
|
" the entry at offset %s, signature %s"),
|
|
sect_offset_str (sect_off),
|
|
sect_offset_str (dwo_tu->sect_off),
|
|
hex_string (header.signature));
|
|
*slot = dwo_tu;
|
|
|
|
dwarf_read_debug_printf_v (" offset %s, signature %s",
|
|
sect_offset_str (sect_off),
|
|
hex_string (header.signature));
|
|
|
|
info_ptr += length;
|
|
}
|
|
}
|
|
|
|
/* Create the hash table of all entries in the .debug_types
|
|
(or .debug_types.dwo) section(s).
|
|
DWO_FILE is a pointer to the DWO file object.
|
|
|
|
Note: This function processes DWO files only, not DWP files. */
|
|
|
|
static void
|
|
create_debug_types_hash_table
|
|
(dwarf2_per_objfile *per_objfile, dwo_file *dwo_file,
|
|
gdb::array_view<dwarf2_section_info> type_sections)
|
|
{
|
|
for (dwarf2_section_info §ion : type_sections)
|
|
create_debug_type_hash_table (per_objfile, dwo_file, §ion,
|
|
rcuh_kind::TYPE);
|
|
}
|
|
|
|
/* Add an entry for signature SIG to dwarf2_per_objfile->per_bfd->signatured_types.
|
|
If SLOT is non-NULL, it is the entry to use in the hash table.
|
|
Otherwise we find one. */
|
|
|
|
static struct signatured_type *
|
|
add_type_unit (dwarf2_per_objfile *per_objfile, ULONGEST sig, void **slot)
|
|
{
|
|
if (per_objfile->per_bfd->all_units.size ()
|
|
== per_objfile->per_bfd->all_units.capacity ())
|
|
++per_objfile->per_bfd->tu_stats.nr_all_type_units_reallocs;
|
|
|
|
signatured_type_up sig_type_holder
|
|
= per_objfile->per_bfd->allocate_signatured_type (sig);
|
|
signatured_type *sig_type = sig_type_holder.get ();
|
|
|
|
per_objfile->per_bfd->all_units.emplace_back
|
|
(sig_type_holder.release ());
|
|
|
|
if (slot == NULL)
|
|
{
|
|
slot = htab_find_slot (per_objfile->per_bfd->signatured_types.get (),
|
|
sig_type, INSERT);
|
|
}
|
|
gdb_assert (*slot == NULL);
|
|
*slot = sig_type;
|
|
/* The rest of sig_type must be filled in by the caller. */
|
|
return sig_type;
|
|
}
|
|
|
|
/* Subroutine of lookup_dwo_signatured_type and lookup_dwp_signatured_type.
|
|
Fill in SIG_ENTRY with DWO_ENTRY. */
|
|
|
|
static void
|
|
fill_in_sig_entry_from_dwo_entry (dwarf2_per_objfile *per_objfile,
|
|
struct signatured_type *sig_entry,
|
|
struct dwo_unit *dwo_entry)
|
|
{
|
|
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
|
|
|
/* Make sure we're not clobbering something we don't expect to. */
|
|
gdb_assert (! sig_entry->queued);
|
|
gdb_assert (per_objfile->get_cu (sig_entry) == NULL);
|
|
gdb_assert (!per_objfile->symtab_set_p (sig_entry));
|
|
gdb_assert (sig_entry->signature == dwo_entry->signature);
|
|
gdb_assert (to_underlying (sig_entry->type_offset_in_section) == 0
|
|
|| (to_underlying (sig_entry->type_offset_in_section)
|
|
== to_underlying (dwo_entry->type_offset_in_tu)));
|
|
gdb_assert (sig_entry->type_unit_group == NULL);
|
|
gdb_assert (sig_entry->dwo_unit == NULL
|
|
|| sig_entry->dwo_unit == dwo_entry);
|
|
|
|
sig_entry->section = dwo_entry->section;
|
|
sig_entry->sect_off = dwo_entry->sect_off;
|
|
sig_entry->set_length (dwo_entry->length, false);
|
|
sig_entry->reading_dwo_directly = 1;
|
|
sig_entry->per_bfd = per_bfd;
|
|
sig_entry->type_offset_in_tu = dwo_entry->type_offset_in_tu;
|
|
sig_entry->dwo_unit = dwo_entry;
|
|
}
|
|
|
|
/* Subroutine of lookup_signatured_type.
|
|
If we haven't read the TU yet, create the signatured_type data structure
|
|
for a TU to be read in directly from a DWO file, bypassing the stub.
|
|
This is the "Stay in DWO Optimization": When there is no DWP file and we're
|
|
using .gdb_index, then when reading a CU we want to stay in the DWO file
|
|
containing that CU. Otherwise we could end up reading several other DWO
|
|
files (due to comdat folding) to process the transitive closure of all the
|
|
mentioned TUs, and that can be slow. The current DWO file will have every
|
|
type signature that it needs.
|
|
We only do this for .gdb_index because in the psymtab case we already have
|
|
to read all the DWOs to build the type unit groups. */
|
|
|
|
static struct signatured_type *
|
|
lookup_dwo_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct dwo_file *dwo_file;
|
|
struct dwo_unit find_dwo_entry, *dwo_entry;
|
|
void **slot;
|
|
|
|
gdb_assert (cu->dwo_unit);
|
|
|
|
/* If TU skeletons have been removed then we may not have read in any
|
|
TUs yet. */
|
|
if (per_objfile->per_bfd->signatured_types == NULL)
|
|
per_objfile->per_bfd->signatured_types = allocate_signatured_type_table ();
|
|
|
|
/* We only ever need to read in one copy of a signatured type.
|
|
Use the global signatured_types array to do our own comdat-folding
|
|
of types. If this is the first time we're reading this TU, and
|
|
the TU has an entry in .gdb_index, replace the recorded data from
|
|
.gdb_index with this TU. */
|
|
|
|
signatured_type find_sig_entry (sig);
|
|
slot = htab_find_slot (per_objfile->per_bfd->signatured_types.get (),
|
|
&find_sig_entry, INSERT);
|
|
signatured_type *sig_entry = (struct signatured_type *) *slot;
|
|
|
|
/* We can get here with the TU already read, *or* in the process of being
|
|
read. Don't reassign the global entry to point to this DWO if that's
|
|
the case. Also note that if the TU is already being read, it may not
|
|
have come from a DWO, the program may be a mix of Fission-compiled
|
|
code and non-Fission-compiled code. */
|
|
|
|
/* Have we already tried to read this TU?
|
|
Note: sig_entry can be NULL if the skeleton TU was removed (thus it
|
|
needn't exist in the global table yet). */
|
|
if (sig_entry != NULL && sig_entry->tu_read)
|
|
return sig_entry;
|
|
|
|
/* Note: cu->dwo_unit is the dwo_unit that references this TU, not the
|
|
dwo_unit of the TU itself. */
|
|
dwo_file = cu->dwo_unit->dwo_file;
|
|
|
|
/* Ok, this is the first time we're reading this TU. */
|
|
if (dwo_file->tus == NULL)
|
|
return NULL;
|
|
find_dwo_entry.signature = sig;
|
|
dwo_entry = (struct dwo_unit *) htab_find (dwo_file->tus.get (),
|
|
&find_dwo_entry);
|
|
if (dwo_entry == NULL)
|
|
return NULL;
|
|
|
|
/* If the global table doesn't have an entry for this TU, add one. */
|
|
if (sig_entry == NULL)
|
|
sig_entry = add_type_unit (per_objfile, sig, slot);
|
|
|
|
if (sig_entry->dwo_unit == nullptr)
|
|
fill_in_sig_entry_from_dwo_entry (per_objfile, sig_entry, dwo_entry);
|
|
sig_entry->tu_read = 1;
|
|
return sig_entry;
|
|
}
|
|
|
|
/* Subroutine of lookup_signatured_type.
|
|
Look up the type for signature SIG, and if we can't find SIG in .gdb_index
|
|
then try the DWP file. If the TU stub (skeleton) has been removed then
|
|
it won't be in .gdb_index. */
|
|
|
|
static struct signatured_type *
|
|
lookup_dwp_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct dwp_file *dwp_file = get_dwp_file (per_objfile);
|
|
struct dwo_unit *dwo_entry;
|
|
void **slot;
|
|
|
|
gdb_assert (cu->dwo_unit);
|
|
gdb_assert (dwp_file != NULL);
|
|
|
|
/* If TU skeletons have been removed then we may not have read in any
|
|
TUs yet. */
|
|
if (per_objfile->per_bfd->signatured_types == NULL)
|
|
per_objfile->per_bfd->signatured_types = allocate_signatured_type_table ();
|
|
|
|
signatured_type find_sig_entry (sig);
|
|
slot = htab_find_slot (per_objfile->per_bfd->signatured_types.get (),
|
|
&find_sig_entry, INSERT);
|
|
signatured_type *sig_entry = (struct signatured_type *) *slot;
|
|
|
|
/* Have we already tried to read this TU?
|
|
Note: sig_entry can be NULL if the skeleton TU was removed (thus it
|
|
needn't exist in the global table yet). */
|
|
if (sig_entry != NULL)
|
|
return sig_entry;
|
|
|
|
if (dwp_file->tus == NULL)
|
|
return NULL;
|
|
dwo_entry = lookup_dwo_unit_in_dwp (per_objfile, dwp_file, NULL, sig,
|
|
1 /* is_debug_types */);
|
|
if (dwo_entry == NULL)
|
|
return NULL;
|
|
|
|
sig_entry = add_type_unit (per_objfile, sig, slot);
|
|
fill_in_sig_entry_from_dwo_entry (per_objfile, sig_entry, dwo_entry);
|
|
|
|
return sig_entry;
|
|
}
|
|
|
|
/* Lookup a signature based type for DW_FORM_ref_sig8.
|
|
Returns NULL if signature SIG is not present in the table.
|
|
It is up to the caller to complain about this. */
|
|
|
|
static struct signatured_type *
|
|
lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
if (cu->dwo_unit)
|
|
{
|
|
/* We're in a DWO/DWP file, and we're using .gdb_index.
|
|
These cases require special processing. */
|
|
if (get_dwp_file (per_objfile) == NULL)
|
|
return lookup_dwo_signatured_type (cu, sig);
|
|
else
|
|
return lookup_dwp_signatured_type (cu, sig);
|
|
}
|
|
else
|
|
{
|
|
if (per_objfile->per_bfd->signatured_types == NULL)
|
|
return NULL;
|
|
signatured_type find_entry (sig);
|
|
return ((struct signatured_type *)
|
|
htab_find (per_objfile->per_bfd->signatured_types.get (),
|
|
&find_entry));
|
|
}
|
|
}
|
|
|
|
/* Low level DIE reading support. */
|
|
|
|
/* Initialize a die_reader_specs struct from a dwarf2_cu struct. */
|
|
|
|
static void
|
|
init_cu_die_reader (struct die_reader_specs *reader,
|
|
struct dwarf2_cu *cu,
|
|
struct dwarf2_section_info *section,
|
|
struct dwo_file *dwo_file,
|
|
const abbrev_table *abbrev_table)
|
|
{
|
|
gdb_assert (section->readin && section->buffer != NULL);
|
|
reader->abfd = section->get_bfd_owner ();
|
|
reader->cu = cu;
|
|
reader->dwo_file = dwo_file;
|
|
reader->die_section = section;
|
|
reader->buffer = section->buffer;
|
|
reader->buffer_end = section->buffer + section->size;
|
|
reader->abbrev_table = abbrev_table;
|
|
}
|
|
|
|
/* Subroutine of cutu_reader to simplify it.
|
|
Read in the rest of a CU/TU top level DIE from DWO_UNIT.
|
|
There's just a lot of work to do, and cutu_reader is big enough
|
|
already.
|
|
|
|
STUB_COMP_UNIT_DIE is for the stub DIE, we copy over certain attributes
|
|
from it to the DIE in the DWO. If NULL we are skipping the stub.
|
|
STUB_COMP_DIR is similar to STUB_COMP_UNIT_DIE: When reading a TU directly
|
|
from the DWO file, bypassing the stub, it contains the DW_AT_comp_dir
|
|
attribute of the referencing CU. At most one of STUB_COMP_UNIT_DIE and
|
|
STUB_COMP_DIR may be non-NULL.
|
|
*RESULT_READER,*RESULT_INFO_PTR,*RESULT_COMP_UNIT_DIE
|
|
are filled in with the info of the DIE from the DWO file.
|
|
*RESULT_DWO_ABBREV_TABLE will be filled in with the abbrev table allocated
|
|
from the dwo. Since *RESULT_READER references this abbrev table, it must be
|
|
kept around for at least as long as *RESULT_READER.
|
|
|
|
The result is non-zero if a valid (non-dummy) DIE was found. */
|
|
|
|
static int
|
|
read_cutu_die_from_dwo (dwarf2_cu *cu,
|
|
struct dwo_unit *dwo_unit,
|
|
struct die_info *stub_comp_unit_die,
|
|
const char *stub_comp_dir,
|
|
struct die_reader_specs *result_reader,
|
|
const gdb_byte **result_info_ptr,
|
|
struct die_info **result_comp_unit_die,
|
|
abbrev_table_up *result_dwo_abbrev_table)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
dwarf2_per_cu_data *per_cu = cu->per_cu;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
bfd *abfd;
|
|
const gdb_byte *begin_info_ptr, *info_ptr;
|
|
struct dwarf2_section_info *dwo_abbrev_section;
|
|
|
|
/* At most one of these may be provided. */
|
|
gdb_assert ((stub_comp_unit_die != NULL) + (stub_comp_dir != NULL) <= 1);
|
|
|
|
/* These attributes aren't processed until later: DW_AT_stmt_list,
|
|
DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_comp_dir.
|
|
However, these attributes are found in the stub which we won't
|
|
have later. In order to not impose this complication on the rest
|
|
of the code, we read them here and copy them to the DWO CU/TU
|
|
die. */
|
|
|
|
/* We store them all in an array. */
|
|
struct attribute *attributes[5] {};
|
|
/* Next available element of the attributes array. */
|
|
int next_attr_idx = 0;
|
|
|
|
/* Push an element into ATTRIBUTES. */
|
|
auto push_back = [&] (struct attribute *attr)
|
|
{
|
|
gdb_assert (next_attr_idx < ARRAY_SIZE (attributes));
|
|
if (attr != nullptr)
|
|
attributes[next_attr_idx++] = attr;
|
|
};
|
|
|
|
if (stub_comp_unit_die != NULL)
|
|
{
|
|
/* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the
|
|
DWO file. */
|
|
if (!per_cu->is_debug_types)
|
|
push_back (dwarf2_attr (stub_comp_unit_die, DW_AT_stmt_list, cu));
|
|
push_back (dwarf2_attr (stub_comp_unit_die, DW_AT_low_pc, cu));
|
|
push_back (dwarf2_attr (stub_comp_unit_die, DW_AT_high_pc, cu));
|
|
push_back (dwarf2_attr (stub_comp_unit_die, DW_AT_ranges, cu));
|
|
push_back (dwarf2_attr (stub_comp_unit_die, DW_AT_comp_dir, cu));
|
|
|
|
cu->addr_base = stub_comp_unit_die->addr_base ();
|
|
|
|
/* There should be a DW_AT_GNU_ranges_base attribute here (if needed).
|
|
We need the value before we can process DW_AT_ranges values from the
|
|
DWO. */
|
|
cu->gnu_ranges_base = stub_comp_unit_die->gnu_ranges_base ();
|
|
|
|
/* For DWARF5: record the DW_AT_rnglists_base value from the skeleton. If
|
|
there are attributes of form DW_FORM_rnglistx in the skeleton, they'll
|
|
need the rnglists base. Attributes of form DW_FORM_rnglistx in the
|
|
split unit don't use it, as the DWO has its own .debug_rnglists.dwo
|
|
section. */
|
|
cu->rnglists_base = stub_comp_unit_die->rnglists_base ();
|
|
}
|
|
else if (stub_comp_dir != NULL)
|
|
{
|
|
/* Reconstruct the comp_dir attribute to simplify the code below. */
|
|
struct attribute *comp_dir = OBSTACK_ZALLOC (&cu->comp_unit_obstack,
|
|
struct attribute);
|
|
comp_dir->name = DW_AT_comp_dir;
|
|
comp_dir->form = DW_FORM_string;
|
|
comp_dir->set_string_noncanonical (stub_comp_dir);
|
|
push_back (comp_dir);
|
|
}
|
|
|
|
/* Set up for reading the DWO CU/TU. */
|
|
cu->dwo_unit = dwo_unit;
|
|
dwarf2_section_info *section = dwo_unit->section;
|
|
section->read (objfile);
|
|
abfd = section->get_bfd_owner ();
|
|
begin_info_ptr = info_ptr = (section->buffer
|
|
+ to_underlying (dwo_unit->sect_off));
|
|
dwo_abbrev_section = &dwo_unit->dwo_file->sections.abbrev;
|
|
|
|
if (per_cu->is_debug_types)
|
|
{
|
|
signatured_type *sig_type = (struct signatured_type *) per_cu;
|
|
|
|
info_ptr = read_and_check_comp_unit_head (per_objfile, &cu->header,
|
|
section, dwo_abbrev_section,
|
|
info_ptr, rcuh_kind::TYPE);
|
|
/* This is not an assert because it can be caused by bad debug info. */
|
|
if (sig_type->signature != cu->header.signature)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"signature mismatch %s vs %s while reading TU at offset %s"
|
|
" [in module %s]"),
|
|
hex_string (sig_type->signature),
|
|
hex_string (cu->header.signature),
|
|
sect_offset_str (dwo_unit->sect_off),
|
|
bfd_get_filename (abfd));
|
|
}
|
|
gdb_assert (dwo_unit->sect_off == cu->header.sect_off);
|
|
/* For DWOs coming from DWP files, we don't know the CU length
|
|
nor the type's offset in the TU until now. */
|
|
dwo_unit->length = cu->header.get_length_with_initial ();
|
|
dwo_unit->type_offset_in_tu = cu->header.type_cu_offset_in_tu;
|
|
|
|
/* Establish the type offset that can be used to lookup the type.
|
|
For DWO files, we don't know it until now. */
|
|
sig_type->type_offset_in_section
|
|
= dwo_unit->sect_off + to_underlying (dwo_unit->type_offset_in_tu);
|
|
}
|
|
else
|
|
{
|
|
info_ptr = read_and_check_comp_unit_head (per_objfile, &cu->header,
|
|
section, dwo_abbrev_section,
|
|
info_ptr, rcuh_kind::COMPILE);
|
|
gdb_assert (dwo_unit->sect_off == cu->header.sect_off);
|
|
/* For DWOs coming from DWP files, we don't know the CU length
|
|
until now. */
|
|
dwo_unit->length = cu->header.get_length_with_initial ();
|
|
}
|
|
|
|
dwo_abbrev_section->read (objfile);
|
|
*result_dwo_abbrev_table
|
|
= abbrev_table::read (dwo_abbrev_section, cu->header.abbrev_sect_off);
|
|
init_cu_die_reader (result_reader, cu, section, dwo_unit->dwo_file,
|
|
result_dwo_abbrev_table->get ());
|
|
|
|
/* Read in the die, filling in the attributes from the stub. This
|
|
has the benefit of simplifying the rest of the code - all the
|
|
work to maintain the illusion of a single
|
|
DW_TAG_{compile,type}_unit DIE is done here. */
|
|
info_ptr = read_toplevel_die (result_reader, result_comp_unit_die, info_ptr,
|
|
gdb::make_array_view (attributes,
|
|
next_attr_idx));
|
|
|
|
/* Skip dummy compilation units. */
|
|
if (info_ptr >= begin_info_ptr + dwo_unit->length
|
|
|| peek_abbrev_code (abfd, info_ptr) == 0)
|
|
return 0;
|
|
|
|
*result_info_ptr = info_ptr;
|
|
return 1;
|
|
}
|
|
|
|
/* Return the signature of the compile unit, if found. In DWARF 4 and before,
|
|
the signature is in the DW_AT_GNU_dwo_id attribute. In DWARF 5 and later, the
|
|
signature is part of the header. */
|
|
static std::optional<ULONGEST>
|
|
lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die)
|
|
{
|
|
if (cu->header.version >= 5)
|
|
return cu->header.signature;
|
|
struct attribute *attr;
|
|
attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_id, cu);
|
|
if (attr == nullptr || !attr->form_is_unsigned ())
|
|
return std::optional<ULONGEST> ();
|
|
return attr->as_unsigned ();
|
|
}
|
|
|
|
/* Subroutine of cutu_reader to simplify it.
|
|
Look up the DWO unit specified by COMP_UNIT_DIE of THIS_CU.
|
|
Returns NULL if the specified DWO unit cannot be found. */
|
|
|
|
static struct dwo_unit *
|
|
lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, const char *dwo_name)
|
|
{
|
|
#if CXX_STD_THREAD
|
|
/* We need a lock here to handle the DWO hash table. */
|
|
static std::mutex dwo_lock;
|
|
|
|
std::lock_guard<std::mutex> guard (dwo_lock);
|
|
#endif
|
|
|
|
dwarf2_per_cu_data *per_cu = cu->per_cu;
|
|
struct dwo_unit *dwo_unit;
|
|
const char *comp_dir;
|
|
|
|
gdb_assert (cu != NULL);
|
|
|
|
/* Yeah, we look dwo_name up again, but it simplifies the code. */
|
|
dwo_name = dwarf2_dwo_name (comp_unit_die, cu);
|
|
comp_dir = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
|
|
|
|
if (per_cu->is_debug_types)
|
|
dwo_unit = lookup_dwo_type_unit (cu, dwo_name, comp_dir);
|
|
else
|
|
{
|
|
std::optional<ULONGEST> signature = lookup_dwo_id (cu, comp_unit_die);
|
|
|
|
if (!signature.has_value ())
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"missing dwo_id for dwo_name %s"
|
|
" [in module %s]"),
|
|
dwo_name, bfd_get_filename (per_cu->per_bfd->obfd));
|
|
|
|
dwo_unit = lookup_dwo_comp_unit (cu, dwo_name, comp_dir, *signature);
|
|
}
|
|
|
|
return dwo_unit;
|
|
}
|
|
|
|
/* Subroutine of cutu_reader to simplify it.
|
|
See it for a description of the parameters.
|
|
Read a TU directly from a DWO file, bypassing the stub. */
|
|
|
|
void
|
|
cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu_data *this_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
dwarf2_cu *existing_cu)
|
|
{
|
|
struct signatured_type *sig_type;
|
|
|
|
/* Verify we can do the following downcast, and that we have the
|
|
data we need. */
|
|
gdb_assert (this_cu->is_debug_types && this_cu->reading_dwo_directly);
|
|
sig_type = (struct signatured_type *) this_cu;
|
|
gdb_assert (sig_type->dwo_unit != NULL);
|
|
|
|
dwarf2_cu *cu;
|
|
|
|
if (existing_cu != nullptr)
|
|
{
|
|
cu = existing_cu;
|
|
gdb_assert (cu->dwo_unit == sig_type->dwo_unit);
|
|
/* There's no need to do the rereading_dwo_cu handling that
|
|
cutu_reader does since we don't read the stub. */
|
|
}
|
|
else
|
|
{
|
|
/* If an existing_cu is provided, a dwarf2_cu must not exist for this_cu
|
|
in per_objfile yet. */
|
|
gdb_assert (per_objfile->get_cu (this_cu) == nullptr);
|
|
m_new_cu = std::make_unique<dwarf2_cu> (this_cu, per_objfile);
|
|
cu = m_new_cu.get ();
|
|
}
|
|
|
|
/* A future optimization, if needed, would be to use an existing
|
|
abbrev table. When reading DWOs with skeletonless TUs, all the TUs
|
|
could share abbrev tables. */
|
|
|
|
if (read_cutu_die_from_dwo (cu, sig_type->dwo_unit,
|
|
NULL /* stub_comp_unit_die */,
|
|
sig_type->dwo_unit->dwo_file->comp_dir,
|
|
this, &info_ptr,
|
|
&comp_unit_die,
|
|
&m_dwo_abbrev_table) == 0)
|
|
{
|
|
/* Dummy die. */
|
|
dummy_p = true;
|
|
}
|
|
}
|
|
|
|
/* Initialize a CU (or TU) and read its DIEs.
|
|
If the CU defers to a DWO file, read the DWO file as well.
|
|
|
|
ABBREV_TABLE, if non-NULL, is the abbreviation table to use.
|
|
Otherwise the table specified in the comp unit header is read in and used.
|
|
This is an optimization for when we already have the abbrev table.
|
|
|
|
If EXISTING_CU is non-NULL, then use it. Otherwise, a new CU is
|
|
allocated. */
|
|
|
|
cutu_reader::cutu_reader (dwarf2_per_cu_data *this_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
const struct abbrev_table *abbrev_table,
|
|
dwarf2_cu *existing_cu,
|
|
bool skip_partial,
|
|
const abbrev_table_cache *cache)
|
|
: die_reader_specs {},
|
|
m_this_cu (this_cu)
|
|
{
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct dwarf2_section_info *section = this_cu->section;
|
|
bfd *abfd = section->get_bfd_owner ();
|
|
const gdb_byte *begin_info_ptr;
|
|
struct signatured_type *sig_type = NULL;
|
|
struct dwarf2_section_info *abbrev_section;
|
|
/* Non-zero if CU currently points to a DWO file and we need to
|
|
reread it. When this happens we need to reread the skeleton die
|
|
before we can reread the DWO file (this only applies to CUs, not TUs). */
|
|
int rereading_dwo_cu = 0;
|
|
|
|
if (dwarf_die_debug)
|
|
gdb_printf (gdb_stdlog, "Reading %s unit at offset %s\n",
|
|
this_cu->is_debug_types ? "type" : "comp",
|
|
sect_offset_str (this_cu->sect_off));
|
|
|
|
/* If we're reading a TU directly from a DWO file, including a virtual DWO
|
|
file (instead of going through the stub), short-circuit all of this. */
|
|
if (this_cu->reading_dwo_directly)
|
|
{
|
|
/* Narrow down the scope of possibilities to have to understand. */
|
|
gdb_assert (this_cu->is_debug_types);
|
|
gdb_assert (abbrev_table == NULL);
|
|
init_tu_and_read_dwo_dies (this_cu, per_objfile, existing_cu);
|
|
return;
|
|
}
|
|
|
|
/* This is cheap if the section is already read in. */
|
|
section->read (objfile);
|
|
|
|
begin_info_ptr = info_ptr = section->buffer + to_underlying (this_cu->sect_off);
|
|
|
|
abbrev_section = get_abbrev_section_for_cu (this_cu);
|
|
|
|
dwarf2_cu *cu;
|
|
|
|
if (existing_cu != nullptr)
|
|
{
|
|
cu = existing_cu;
|
|
/* If this CU is from a DWO file we need to start over, we need to
|
|
refetch the attributes from the skeleton CU.
|
|
This could be optimized by retrieving those attributes from when we
|
|
were here the first time: the previous comp_unit_die was stored in
|
|
comp_unit_obstack. But there's no data yet that we need this
|
|
optimization. */
|
|
if (cu->dwo_unit != NULL)
|
|
rereading_dwo_cu = 1;
|
|
}
|
|
else
|
|
{
|
|
/* If an existing_cu is provided, a dwarf2_cu must not exist for
|
|
this_cu in per_objfile yet. Here, CACHE doubles as a flag to
|
|
let us know that the CU is being scanned using the parallel
|
|
indexer. This assert is avoided in this case because (1) it
|
|
is irrelevant, and (2) the get_cu method is not
|
|
thread-safe. */
|
|
gdb_assert (cache != nullptr
|
|
|| per_objfile->get_cu (this_cu) == nullptr);
|
|
m_new_cu = std::make_unique<dwarf2_cu> (this_cu, per_objfile);
|
|
cu = m_new_cu.get ();
|
|
}
|
|
|
|
/* Get the header. */
|
|
if (to_underlying (cu->header.first_die_cu_offset) != 0 && !rereading_dwo_cu)
|
|
{
|
|
/* We already have the header, there's no need to read it in again. */
|
|
info_ptr += to_underlying (cu->header.first_die_cu_offset);
|
|
}
|
|
else
|
|
{
|
|
if (this_cu->is_debug_types)
|
|
{
|
|
info_ptr = read_and_check_comp_unit_head (per_objfile, &cu->header,
|
|
section, abbrev_section,
|
|
info_ptr, rcuh_kind::TYPE);
|
|
|
|
/* Since per_cu is the first member of struct signatured_type,
|
|
we can go from a pointer to one to a pointer to the other. */
|
|
sig_type = (struct signatured_type *) this_cu;
|
|
gdb_assert (sig_type->signature == cu->header.signature);
|
|
gdb_assert (sig_type->type_offset_in_tu
|
|
== cu->header.type_cu_offset_in_tu);
|
|
gdb_assert (this_cu->sect_off == cu->header.sect_off);
|
|
|
|
/* LENGTH has not been set yet for type units if we're
|
|
using .gdb_index. */
|
|
this_cu->set_length (cu->header.get_length_with_initial ());
|
|
|
|
/* Establish the type offset that can be used to lookup the type. */
|
|
sig_type->type_offset_in_section =
|
|
this_cu->sect_off + to_underlying (sig_type->type_offset_in_tu);
|
|
}
|
|
else
|
|
{
|
|
info_ptr = read_and_check_comp_unit_head (per_objfile, &cu->header,
|
|
section, abbrev_section,
|
|
info_ptr,
|
|
rcuh_kind::COMPILE);
|
|
|
|
gdb_assert (this_cu->sect_off == cu->header.sect_off);
|
|
this_cu->set_length (cu->header.get_length_with_initial ());
|
|
}
|
|
}
|
|
|
|
/* Skip dummy compilation units. */
|
|
if (info_ptr >= begin_info_ptr + this_cu->length ()
|
|
|| peek_abbrev_code (abfd, info_ptr) == 0)
|
|
{
|
|
dummy_p = true;
|
|
return;
|
|
}
|
|
|
|
/* If we don't have them yet, read the abbrevs for this compilation unit.
|
|
And if we need to read them now, make sure they're freed when we're
|
|
done. */
|
|
if (abbrev_table != NULL)
|
|
gdb_assert (cu->header.abbrev_sect_off == abbrev_table->sect_off);
|
|
else
|
|
{
|
|
if (cache != nullptr)
|
|
abbrev_table = cache->find (abbrev_section,
|
|
cu->header.abbrev_sect_off);
|
|
if (abbrev_table == nullptr)
|
|
{
|
|
abbrev_section->read (objfile);
|
|
m_abbrev_table_holder
|
|
= abbrev_table::read (abbrev_section, cu->header.abbrev_sect_off);
|
|
abbrev_table = m_abbrev_table_holder.get ();
|
|
}
|
|
}
|
|
|
|
/* Read the top level CU/TU die. */
|
|
init_cu_die_reader (this, cu, section, NULL, abbrev_table);
|
|
info_ptr = read_toplevel_die (this, &comp_unit_die, info_ptr);
|
|
|
|
if (skip_partial && comp_unit_die->tag == DW_TAG_partial_unit)
|
|
{
|
|
dummy_p = true;
|
|
return;
|
|
}
|
|
|
|
/* If we are in a DWO stub, process it and then read in the "real" CU/TU
|
|
from the DWO file. read_cutu_die_from_dwo will allocate the abbreviation
|
|
table from the DWO file and pass the ownership over to us. It will be
|
|
referenced from READER, so we must make sure to free it after we're done
|
|
with READER.
|
|
|
|
Note that if USE_EXISTING_OK != 0, and THIS_CU->cu already contains a
|
|
DWO CU, that this test will fail (the attribute will not be present). */
|
|
const char *dwo_name = dwarf2_dwo_name (comp_unit_die, cu);
|
|
if (dwo_name != nullptr)
|
|
{
|
|
struct dwo_unit *dwo_unit;
|
|
struct die_info *dwo_comp_unit_die;
|
|
|
|
if (comp_unit_die->has_children)
|
|
{
|
|
complaint (_("compilation unit with DW_AT_GNU_dwo_name"
|
|
" has children (offset %s) [in module %s]"),
|
|
sect_offset_str (this_cu->sect_off),
|
|
bfd_get_filename (abfd));
|
|
}
|
|
dwo_unit = lookup_dwo_unit (cu, comp_unit_die, dwo_name);
|
|
if (dwo_unit != NULL)
|
|
{
|
|
if (read_cutu_die_from_dwo (cu, dwo_unit,
|
|
comp_unit_die, NULL,
|
|
this, &info_ptr,
|
|
&dwo_comp_unit_die,
|
|
&m_dwo_abbrev_table) == 0)
|
|
{
|
|
/* Dummy die. */
|
|
dummy_p = true;
|
|
return;
|
|
}
|
|
comp_unit_die = dwo_comp_unit_die;
|
|
}
|
|
else
|
|
{
|
|
/* Yikes, we couldn't find the rest of the DIE, we only have
|
|
the stub. A complaint has already been logged. There's
|
|
not much more we can do except pass on the stub DIE to
|
|
die_reader_func. We don't want to throw an error on bad
|
|
debug info. */
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
cutu_reader::keep ()
|
|
{
|
|
/* Done, clean up. */
|
|
gdb_assert (!dummy_p);
|
|
if (m_new_cu != NULL)
|
|
{
|
|
/* Save this dwarf2_cu in the per_objfile. The per_objfile owns it
|
|
now. */
|
|
dwarf2_per_objfile *per_objfile = m_new_cu->per_objfile;
|
|
per_objfile->set_cu (m_this_cu, std::move (m_new_cu));
|
|
}
|
|
}
|
|
|
|
/* Read CU/TU THIS_CU but do not follow DW_AT_GNU_dwo_name (DW_AT_dwo_name)
|
|
if present. DWO_FILE, if non-NULL, is the DWO file to read (the caller is
|
|
assumed to have already done the lookup to find the DWO file).
|
|
|
|
The caller is required to fill in THIS_CU->section, THIS_CU->offset, and
|
|
THIS_CU->is_debug_types, but nothing else.
|
|
|
|
We fill in THIS_CU->length.
|
|
|
|
THIS_CU->cu is always freed when done.
|
|
This is done in order to not leave THIS_CU->cu in a state where we have
|
|
to care whether it refers to the "main" CU or the DWO CU.
|
|
|
|
When parent_cu is passed, it is used to provide a default value for
|
|
str_offsets_base and addr_base from the parent. */
|
|
|
|
cutu_reader::cutu_reader (dwarf2_per_cu_data *this_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
struct dwarf2_cu *parent_cu,
|
|
struct dwo_file *dwo_file)
|
|
: die_reader_specs {},
|
|
m_this_cu (this_cu)
|
|
{
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct dwarf2_section_info *section = this_cu->section;
|
|
bfd *abfd = section->get_bfd_owner ();
|
|
struct dwarf2_section_info *abbrev_section;
|
|
const gdb_byte *begin_info_ptr, *info_ptr;
|
|
|
|
if (dwarf_die_debug)
|
|
gdb_printf (gdb_stdlog, "Reading %s unit at offset %s\n",
|
|
this_cu->is_debug_types ? "type" : "comp",
|
|
sect_offset_str (this_cu->sect_off));
|
|
|
|
gdb_assert (per_objfile->get_cu (this_cu) == nullptr);
|
|
|
|
abbrev_section = (dwo_file != NULL
|
|
? &dwo_file->sections.abbrev
|
|
: get_abbrev_section_for_cu (this_cu));
|
|
|
|
/* This is cheap if the section is already read in. */
|
|
section->read (objfile);
|
|
|
|
m_new_cu = std::make_unique<dwarf2_cu> (this_cu, per_objfile);
|
|
|
|
begin_info_ptr = info_ptr = section->buffer + to_underlying (this_cu->sect_off);
|
|
info_ptr = read_and_check_comp_unit_head (per_objfile, &m_new_cu->header,
|
|
section, abbrev_section, info_ptr,
|
|
(this_cu->is_debug_types
|
|
? rcuh_kind::TYPE
|
|
: rcuh_kind::COMPILE));
|
|
|
|
if (parent_cu != nullptr)
|
|
{
|
|
m_new_cu->str_offsets_base = parent_cu->str_offsets_base;
|
|
m_new_cu->addr_base = parent_cu->addr_base;
|
|
}
|
|
this_cu->set_length (m_new_cu->header.get_length_with_initial ());
|
|
|
|
/* Skip dummy compilation units. */
|
|
if (info_ptr >= begin_info_ptr + this_cu->length ()
|
|
|| peek_abbrev_code (abfd, info_ptr) == 0)
|
|
{
|
|
dummy_p = true;
|
|
return;
|
|
}
|
|
|
|
abbrev_section->read (objfile);
|
|
m_abbrev_table_holder
|
|
= abbrev_table::read (abbrev_section, m_new_cu->header.abbrev_sect_off);
|
|
|
|
init_cu_die_reader (this, m_new_cu.get (), section, dwo_file,
|
|
m_abbrev_table_holder.get ());
|
|
info_ptr = read_toplevel_die (this, &comp_unit_die, info_ptr);
|
|
}
|
|
|
|
|
|
/* Type Unit Groups.
|
|
|
|
Type Unit Groups are a way to collapse the set of all TUs (type units) into
|
|
a more manageable set. The grouping is done by DW_AT_stmt_list entry
|
|
so that all types coming from the same compilation (.o file) are grouped
|
|
together. A future step could be to put the types in the same symtab as
|
|
the CU the types ultimately came from. */
|
|
|
|
static hashval_t
|
|
hash_type_unit_group (const void *item)
|
|
{
|
|
const struct type_unit_group *tu_group
|
|
= (const struct type_unit_group *) item;
|
|
|
|
return hash_stmt_list_entry (&tu_group->hash);
|
|
}
|
|
|
|
static int
|
|
eq_type_unit_group (const void *item_lhs, const void *item_rhs)
|
|
{
|
|
const struct type_unit_group *lhs = (const struct type_unit_group *) item_lhs;
|
|
const struct type_unit_group *rhs = (const struct type_unit_group *) item_rhs;
|
|
|
|
return eq_stmt_list_entry (&lhs->hash, &rhs->hash);
|
|
}
|
|
|
|
/* Allocate a hash table for type unit groups. */
|
|
|
|
static htab_up
|
|
allocate_type_unit_groups_table ()
|
|
{
|
|
return htab_up (htab_create_alloc (3,
|
|
hash_type_unit_group,
|
|
eq_type_unit_group,
|
|
htab_delete_entry<type_unit_group>,
|
|
xcalloc, xfree));
|
|
}
|
|
|
|
/* Type units that don't have DW_AT_stmt_list are grouped into their own
|
|
partial symtabs. We combine several TUs per psymtab to not let the size
|
|
of any one psymtab grow too big. */
|
|
#define NO_STMT_LIST_TYPE_UNIT_PSYMTAB (1 << 31)
|
|
#define NO_STMT_LIST_TYPE_UNIT_PSYMTAB_SIZE 10
|
|
|
|
/* Helper routine for get_type_unit_group.
|
|
Create the type_unit_group object used to hold one or more TUs. */
|
|
|
|
static std::unique_ptr<type_unit_group>
|
|
create_type_unit_group (struct dwarf2_cu *cu, sect_offset line_offset_struct)
|
|
{
|
|
auto tu_group = std::make_unique<type_unit_group> ();
|
|
|
|
tu_group->hash.dwo_unit = cu->dwo_unit;
|
|
tu_group->hash.line_sect_off = line_offset_struct;
|
|
|
|
return tu_group;
|
|
}
|
|
|
|
/* Look up the type_unit_group for type unit CU, and create it if necessary.
|
|
STMT_LIST is a DW_AT_stmt_list attribute. */
|
|
|
|
static struct type_unit_group *
|
|
get_type_unit_group (struct dwarf2_cu *cu, const struct attribute *stmt_list)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats;
|
|
struct type_unit_group *tu_group;
|
|
void **slot;
|
|
unsigned int line_offset;
|
|
struct type_unit_group type_unit_group_for_lookup;
|
|
|
|
if (per_objfile->per_bfd->type_unit_groups == NULL)
|
|
per_objfile->per_bfd->type_unit_groups = allocate_type_unit_groups_table ();
|
|
|
|
/* Do we need to create a new group, or can we use an existing one? */
|
|
|
|
if (stmt_list != nullptr && stmt_list->form_is_unsigned ())
|
|
{
|
|
line_offset = stmt_list->as_unsigned ();
|
|
++tu_stats->nr_symtab_sharers;
|
|
}
|
|
else
|
|
{
|
|
/* Ugh, no stmt_list. Rare, but we have to handle it.
|
|
We can do various things here like create one group per TU or
|
|
spread them over multiple groups to split up the expansion work.
|
|
To avoid worst case scenarios (too many groups or too large groups)
|
|
we, umm, group them in bunches. */
|
|
line_offset = (NO_STMT_LIST_TYPE_UNIT_PSYMTAB
|
|
| (tu_stats->nr_stmt_less_type_units
|
|
/ NO_STMT_LIST_TYPE_UNIT_PSYMTAB_SIZE));
|
|
++tu_stats->nr_stmt_less_type_units;
|
|
}
|
|
|
|
type_unit_group_for_lookup.hash.dwo_unit = cu->dwo_unit;
|
|
type_unit_group_for_lookup.hash.line_sect_off = (sect_offset) line_offset;
|
|
slot = htab_find_slot (per_objfile->per_bfd->type_unit_groups.get (),
|
|
&type_unit_group_for_lookup, INSERT);
|
|
if (*slot == nullptr)
|
|
{
|
|
sect_offset line_offset_struct = (sect_offset) line_offset;
|
|
std::unique_ptr<type_unit_group> grp
|
|
= create_type_unit_group (cu, line_offset_struct);
|
|
*slot = grp.release ();
|
|
++tu_stats->nr_symtabs;
|
|
}
|
|
|
|
tu_group = (struct type_unit_group *) *slot;
|
|
gdb_assert (tu_group != nullptr);
|
|
return tu_group;
|
|
}
|
|
|
|
|
|
cooked_index_storage::cooked_index_storage ()
|
|
: m_reader_hash (htab_create_alloc (10, hash_cutu_reader,
|
|
eq_cutu_reader,
|
|
htab_delete_entry<cutu_reader>,
|
|
xcalloc, xfree)),
|
|
m_index (new cooked_index_shard)
|
|
{
|
|
}
|
|
|
|
cutu_reader *
|
|
cooked_index_storage::get_reader (dwarf2_per_cu_data *per_cu)
|
|
{
|
|
int index = per_cu->index;
|
|
return (cutu_reader *) htab_find_with_hash (m_reader_hash.get (),
|
|
&index, index);
|
|
}
|
|
|
|
cutu_reader *
|
|
cooked_index_storage::preserve (std::unique_ptr<cutu_reader> reader)
|
|
{
|
|
m_abbrev_table_cache.add (reader->release_abbrev_table ());
|
|
|
|
int index = reader->cu->per_cu->index;
|
|
void **slot = htab_find_slot_with_hash (m_reader_hash.get (), &index,
|
|
index, INSERT);
|
|
gdb_assert (*slot == nullptr);
|
|
cutu_reader *result = reader.get ();
|
|
*slot = reader.release ();
|
|
return result;
|
|
}
|
|
|
|
/* Hash function for a cutu_reader. */
|
|
hashval_t
|
|
cooked_index_storage::hash_cutu_reader (const void *a)
|
|
{
|
|
const cutu_reader *reader = (const cutu_reader *) a;
|
|
return reader->cu->per_cu->index;
|
|
}
|
|
|
|
/* Equality function for cutu_reader. */
|
|
int
|
|
cooked_index_storage::eq_cutu_reader (const void *a, const void *b)
|
|
{
|
|
const cutu_reader *ra = (const cutu_reader *) a;
|
|
const int *rb = (const int *) b;
|
|
return ra->cu->per_cu->index == *rb;
|
|
}
|
|
|
|
/* Dump MAP as parent_map. */
|
|
|
|
static void
|
|
dump_parent_map (dwarf2_per_bfd *per_bfd, const struct addrmap *map)
|
|
{
|
|
auto_obstack temp_storage;
|
|
|
|
auto annotate_cooked_index_entry
|
|
= [&] (struct ui_file *outfile, CORE_ADDR start_addr, const void *value)
|
|
{
|
|
const cooked_index_entry *parent_entry
|
|
= (const cooked_index_entry *)value;
|
|
|
|
gdb_printf (outfile, "\n\t");
|
|
|
|
bool found = false;
|
|
for (auto sections : {per_bfd->infos, per_bfd->types})
|
|
for (auto section : sections)
|
|
if ((CORE_ADDR)section.buffer <= start_addr
|
|
&& start_addr < (CORE_ADDR) (section.buffer + section.size))
|
|
{
|
|
gdb_printf (outfile, "(section: %s, offset: 0x%" PRIx64 ")",
|
|
section.get_name (),
|
|
start_addr - (CORE_ADDR)section.buffer);
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
if (!found)
|
|
gdb_printf (outfile, "()");
|
|
|
|
if (parent_entry == nullptr)
|
|
{
|
|
gdb_printf (outfile, " -> ()");
|
|
return;
|
|
}
|
|
|
|
gdb_printf (outfile, " -> (0x%" PRIx64 ": %s)",
|
|
to_underlying (parent_entry->die_offset),
|
|
parent_entry->full_name (&temp_storage, false));
|
|
};
|
|
|
|
addrmap_dump (const_cast<addrmap *> (map), gdb_stdlog, nullptr,
|
|
annotate_cooked_index_entry);
|
|
}
|
|
|
|
/* See parent-map.h. */
|
|
|
|
void
|
|
parent_map::dump (dwarf2_per_bfd *per_bfd) const
|
|
{
|
|
dump_parent_map (per_bfd, &m_map);
|
|
}
|
|
|
|
/* See parent-map.h. */
|
|
|
|
void
|
|
parent_map_map::dump (dwarf2_per_bfd *per_bfd) const
|
|
{
|
|
for (const auto &iter : m_maps)
|
|
{
|
|
gdb_printf (gdb_stdlog, "map start:\n");
|
|
dump_parent_map (per_bfd, iter);
|
|
}
|
|
}
|
|
|
|
/* An instance of this is created to index a CU. */
|
|
|
|
class cooked_indexer
|
|
{
|
|
public:
|
|
|
|
cooked_indexer (cooked_index_storage *storage,
|
|
dwarf2_per_cu_data *per_cu,
|
|
enum language language)
|
|
: m_index_storage (storage),
|
|
m_per_cu (per_cu),
|
|
m_language (language),
|
|
m_die_range_map (storage->get_parent_map ())
|
|
{
|
|
}
|
|
|
|
DISABLE_COPY_AND_ASSIGN (cooked_indexer);
|
|
|
|
/* Index the given CU. */
|
|
void make_index (cutu_reader *reader);
|
|
|
|
private:
|
|
|
|
/* A helper function to scan the PC bounds of READER and record them
|
|
in the storage's addrmap. */
|
|
void check_bounds (cutu_reader *reader);
|
|
|
|
/* Ensure that the indicated CU exists. The cutu_reader for it is
|
|
returned. FOR_SCANNING is true if the caller intends to scan all
|
|
the DIEs in the CU; when false, this use is assumed to be to look
|
|
up just a single DIE. */
|
|
cutu_reader *ensure_cu_exists (cutu_reader *reader,
|
|
dwarf2_per_objfile *per_objfile,
|
|
sect_offset sect_off,
|
|
bool is_dwz,
|
|
bool for_scanning);
|
|
|
|
/* Index DIEs in the READER starting at INFO_PTR. PARENT is
|
|
the entry for the enclosing scope (nullptr at top level). FULLY
|
|
is true when a full scan must be done -- in some languages,
|
|
function scopes must be fully explored in order to find nested
|
|
functions. This returns a pointer to just after the spot where
|
|
reading stopped. */
|
|
const gdb_byte *index_dies (cutu_reader *reader,
|
|
const gdb_byte *info_ptr,
|
|
std::variant<const cooked_index_entry *,
|
|
parent_map::addr_type> parent,
|
|
bool fully);
|
|
|
|
/* Scan the attributes for a given DIE and update the out
|
|
parameters. Returns a pointer to the byte after the DIE. */
|
|
const gdb_byte *scan_attributes (dwarf2_per_cu_data *scanning_per_cu,
|
|
cutu_reader *reader,
|
|
const gdb_byte *watermark_ptr,
|
|
const gdb_byte *info_ptr,
|
|
const abbrev_info *abbrev,
|
|
const char **name,
|
|
const char **linkage_name,
|
|
cooked_index_flag *flags,
|
|
sect_offset *sibling_offset,
|
|
const cooked_index_entry **parent_entry,
|
|
parent_map::addr_type *maybe_defer,
|
|
bool *is_enum_class,
|
|
bool for_specification);
|
|
|
|
/* Handle DW_TAG_imported_unit, by scanning the DIE to find
|
|
DW_AT_import, and then scanning the referenced CU. Returns a
|
|
pointer to the byte after the DIE. */
|
|
const gdb_byte *index_imported_unit (cutu_reader *reader,
|
|
const gdb_byte *info_ptr,
|
|
const abbrev_info *abbrev);
|
|
|
|
/* Recursively read DIEs, recording the section offsets in
|
|
m_die_range_map and then calling index_dies. */
|
|
const gdb_byte *recurse (cutu_reader *reader,
|
|
const gdb_byte *info_ptr,
|
|
std::variant<const cooked_index_entry *,
|
|
parent_map::addr_type> parent_entry,
|
|
bool fully);
|
|
|
|
/* The storage object, where the results are kept. */
|
|
cooked_index_storage *m_index_storage;
|
|
/* The CU that we are reading on behalf of. This object might be
|
|
asked to index one CU but to treat the results as if they come
|
|
from some including CU; in this case the including CU would be
|
|
recorded here. */
|
|
dwarf2_per_cu_data *m_per_cu;
|
|
/* The language that we're assuming when reading. */
|
|
enum language m_language;
|
|
|
|
/* Map from DIE ranges to newly-created entries. */
|
|
parent_map *m_die_range_map;
|
|
};
|
|
|
|
/* Subroutine of dwarf2_build_psymtabs_hard to simplify it.
|
|
Process compilation unit THIS_CU for a psymtab. */
|
|
|
|
static void
|
|
process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
cooked_index_storage *storage)
|
|
{
|
|
cutu_reader *reader = storage->get_reader (this_cu);
|
|
if (reader == nullptr)
|
|
{
|
|
cutu_reader new_reader (this_cu, per_objfile, nullptr, nullptr, false,
|
|
&storage->get_abbrev_table_cache ());
|
|
|
|
if (new_reader.comp_unit_die == nullptr || new_reader.dummy_p)
|
|
return;
|
|
|
|
std::unique_ptr<cutu_reader> copy
|
|
(new cutu_reader (std::move (new_reader)));
|
|
reader = storage->preserve (std::move (copy));
|
|
}
|
|
|
|
if (reader->comp_unit_die == nullptr || reader->dummy_p)
|
|
return;
|
|
|
|
if (this_cu->is_debug_types)
|
|
build_type_psymtabs_reader (reader, storage);
|
|
else if (reader->comp_unit_die->tag != DW_TAG_partial_unit)
|
|
{
|
|
bool nope = false;
|
|
if (this_cu->scanned.compare_exchange_strong (nope, true))
|
|
{
|
|
prepare_one_comp_unit (reader->cu, reader->comp_unit_die,
|
|
language_minimal);
|
|
gdb_assert (storage != nullptr);
|
|
cooked_indexer indexer (storage, this_cu, reader->cu->lang ());
|
|
indexer.make_index (reader);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Reader function for build_type_psymtabs. */
|
|
|
|
static void
|
|
build_type_psymtabs_reader (cutu_reader *reader,
|
|
cooked_index_storage *storage)
|
|
{
|
|
struct dwarf2_cu *cu = reader->cu;
|
|
struct dwarf2_per_cu_data *per_cu = cu->per_cu;
|
|
struct die_info *type_unit_die = reader->comp_unit_die;
|
|
|
|
gdb_assert (per_cu->is_debug_types);
|
|
|
|
if (! type_unit_die->has_children)
|
|
return;
|
|
|
|
prepare_one_comp_unit (cu, type_unit_die, language_minimal);
|
|
|
|
gdb_assert (storage != nullptr);
|
|
cooked_indexer indexer (storage, per_cu, cu->lang ());
|
|
indexer.make_index (reader);
|
|
}
|
|
|
|
/* Struct used to sort TUs by their abbreviation table offset. */
|
|
|
|
struct tu_abbrev_offset
|
|
{
|
|
tu_abbrev_offset (signatured_type *sig_type_, sect_offset abbrev_offset_)
|
|
: sig_type (sig_type_), abbrev_offset (abbrev_offset_)
|
|
{}
|
|
|
|
/* This is used when sorting. */
|
|
bool operator< (const tu_abbrev_offset &other) const
|
|
{
|
|
return abbrev_offset < other.abbrev_offset;
|
|
}
|
|
|
|
signatured_type *sig_type;
|
|
sect_offset abbrev_offset;
|
|
};
|
|
|
|
/* Efficiently read all the type units.
|
|
|
|
The efficiency is because we sort TUs by the abbrev table they use and
|
|
only read each abbrev table once. In one program there are 200K TUs
|
|
sharing 8K abbrev tables.
|
|
|
|
The main purpose of this function is to support building the
|
|
dwarf2_per_objfile->per_bfd->type_unit_groups table.
|
|
TUs typically share the DW_AT_stmt_list of the CU they came from, so we
|
|
can collapse the search space by grouping them by stmt_list.
|
|
The savings can be significant, in the same program from above the 200K TUs
|
|
share 8K stmt_list tables.
|
|
|
|
FUNC is expected to call get_type_unit_group, which will create the
|
|
struct type_unit_group if necessary and add it to
|
|
dwarf2_per_objfile->per_bfd->type_unit_groups. */
|
|
|
|
static void
|
|
build_type_psymtabs (dwarf2_per_objfile *per_objfile,
|
|
cooked_index_storage *storage)
|
|
{
|
|
struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats;
|
|
abbrev_table_up abbrev_table;
|
|
sect_offset abbrev_offset;
|
|
|
|
/* It's up to the caller to not call us multiple times. */
|
|
gdb_assert (per_objfile->per_bfd->type_unit_groups == NULL);
|
|
|
|
if (per_objfile->per_bfd->all_type_units.size () == 0)
|
|
return;
|
|
|
|
/* TUs typically share abbrev tables, and there can be way more TUs than
|
|
abbrev tables. Sort by abbrev table to reduce the number of times we
|
|
read each abbrev table in.
|
|
Alternatives are to punt or to maintain a cache of abbrev tables.
|
|
This is simpler and efficient enough for now.
|
|
|
|
Later we group TUs by their DW_AT_stmt_list value (as this defines the
|
|
symtab to use). Typically TUs with the same abbrev offset have the same
|
|
stmt_list value too so in practice this should work well.
|
|
|
|
The basic algorithm here is:
|
|
|
|
sort TUs by abbrev table
|
|
for each TU with same abbrev table:
|
|
read abbrev table if first user
|
|
read TU top level DIE
|
|
[IWBN if DWO skeletons had DW_AT_stmt_list]
|
|
call FUNC */
|
|
|
|
dwarf_read_debug_printf ("Building type unit groups ...");
|
|
|
|
/* Sort in a separate table to maintain the order of all_units
|
|
for .gdb_index: TU indices directly index all_type_units. */
|
|
std::vector<tu_abbrev_offset> sorted_by_abbrev;
|
|
sorted_by_abbrev.reserve (per_objfile->per_bfd->all_type_units.size ());
|
|
|
|
for (const auto &cu : per_objfile->per_bfd->all_units)
|
|
{
|
|
if (cu->is_debug_types)
|
|
{
|
|
auto sig_type = static_cast<signatured_type *> (cu.get ());
|
|
sorted_by_abbrev.emplace_back
|
|
(sig_type, read_abbrev_offset (per_objfile, sig_type->section,
|
|
sig_type->sect_off));
|
|
}
|
|
}
|
|
|
|
std::sort (sorted_by_abbrev.begin (), sorted_by_abbrev.end ());
|
|
|
|
abbrev_offset = (sect_offset) ~(unsigned) 0;
|
|
|
|
for (const tu_abbrev_offset &tu : sorted_by_abbrev)
|
|
{
|
|
/* Switch to the next abbrev table if necessary. */
|
|
if (abbrev_table == NULL
|
|
|| tu.abbrev_offset != abbrev_offset)
|
|
{
|
|
abbrev_offset = tu.abbrev_offset;
|
|
per_objfile->per_bfd->abbrev.read (per_objfile->objfile);
|
|
abbrev_table =
|
|
abbrev_table::read (&per_objfile->per_bfd->abbrev, abbrev_offset);
|
|
++tu_stats->nr_uniq_abbrev_tables;
|
|
}
|
|
|
|
cutu_reader reader (tu.sig_type, per_objfile,
|
|
abbrev_table.get (), nullptr, false);
|
|
if (!reader.dummy_p)
|
|
build_type_psymtabs_reader (&reader, storage);
|
|
}
|
|
}
|
|
|
|
/* Print collected type unit statistics. */
|
|
|
|
static void
|
|
print_tu_stats (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats;
|
|
|
|
dwarf_read_debug_printf ("Type unit statistics:");
|
|
dwarf_read_debug_printf (" %d TUs", tu_stats->nr_tus);
|
|
dwarf_read_debug_printf (" %d uniq abbrev tables",
|
|
tu_stats->nr_uniq_abbrev_tables);
|
|
dwarf_read_debug_printf (" %d symtabs from stmt_list entries",
|
|
tu_stats->nr_symtabs);
|
|
dwarf_read_debug_printf (" %d symtab sharers",
|
|
tu_stats->nr_symtab_sharers);
|
|
dwarf_read_debug_printf (" %d type units without a stmt_list",
|
|
tu_stats->nr_stmt_less_type_units);
|
|
dwarf_read_debug_printf (" %d all_type_units reallocs",
|
|
tu_stats->nr_all_type_units_reallocs);
|
|
}
|
|
|
|
struct skeleton_data
|
|
{
|
|
dwarf2_per_objfile *per_objfile;
|
|
cooked_index_storage *storage;
|
|
};
|
|
|
|
/* Traversal function for process_skeletonless_type_unit.
|
|
Read a TU in a DWO file and build partial symbols for it. */
|
|
|
|
static int
|
|
process_skeletonless_type_unit (void **slot, void *info)
|
|
{
|
|
struct dwo_unit *dwo_unit = (struct dwo_unit *) *slot;
|
|
skeleton_data *data = (skeleton_data *) info;
|
|
|
|
/* If this TU doesn't exist in the global table, add it and read it in. */
|
|
|
|
if (data->per_objfile->per_bfd->signatured_types == NULL)
|
|
data->per_objfile->per_bfd->signatured_types
|
|
= allocate_signatured_type_table ();
|
|
|
|
signatured_type find_entry (dwo_unit->signature);
|
|
slot = htab_find_slot (data->per_objfile->per_bfd->signatured_types.get (),
|
|
&find_entry, INSERT);
|
|
/* If we've already seen this type there's nothing to do. What's happening
|
|
is we're doing our own version of comdat-folding here. */
|
|
if (*slot != NULL)
|
|
return 1;
|
|
|
|
/* This does the job that create_all_units would have done for
|
|
this TU. */
|
|
signatured_type *entry
|
|
= add_type_unit (data->per_objfile, dwo_unit->signature, slot);
|
|
fill_in_sig_entry_from_dwo_entry (data->per_objfile, entry, dwo_unit);
|
|
*slot = entry;
|
|
|
|
/* This does the job that build_type_psymtabs would have done. */
|
|
cutu_reader reader (entry, data->per_objfile, nullptr, nullptr, false);
|
|
if (!reader.dummy_p)
|
|
build_type_psymtabs_reader (&reader, data->storage);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Traversal function for process_skeletonless_type_units. */
|
|
|
|
static int
|
|
process_dwo_file_for_skeletonless_type_units (void **slot, void *info)
|
|
{
|
|
struct dwo_file *dwo_file = (struct dwo_file *) *slot;
|
|
|
|
if (dwo_file->tus != NULL)
|
|
htab_traverse_noresize (dwo_file->tus.get (),
|
|
process_skeletonless_type_unit, info);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Scan all TUs of DWO files, verifying we've processed them.
|
|
This is needed in case a TU was emitted without its skeleton.
|
|
Note: This can't be done until we know what all the DWO files are. */
|
|
|
|
static void
|
|
process_skeletonless_type_units (dwarf2_per_objfile *per_objfile,
|
|
cooked_index_storage *storage,
|
|
bool m_per_command_time)
|
|
{
|
|
skeleton_data data { per_objfile, storage };
|
|
scoped_time_it time_it ("DWARF skeletonless type units", m_per_command_time);
|
|
|
|
/* Skeletonless TUs in DWP files without .gdb_index is not supported yet. */
|
|
if (get_dwp_file (per_objfile) == NULL
|
|
&& per_objfile->per_bfd->dwo_files != NULL)
|
|
{
|
|
htab_traverse_noresize (per_objfile->per_bfd->dwo_files.get (),
|
|
process_dwo_file_for_skeletonless_type_units,
|
|
&data);
|
|
}
|
|
}
|
|
|
|
/* A subclass of cooked_index_worker that handles scanning
|
|
.debug_info. */
|
|
|
|
class cooked_index_debug_info : public cooked_index_worker
|
|
{
|
|
public:
|
|
cooked_index_debug_info (dwarf2_per_objfile *per_objfile)
|
|
: cooked_index_worker (per_objfile)
|
|
{
|
|
gdb_assert (is_main_thread ());
|
|
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
|
|
|
dwarf_read_debug_printf ("Building psymtabs of objfile %s ...",
|
|
objfile_name (objfile));
|
|
|
|
per_bfd->map_info_sections (objfile);
|
|
}
|
|
|
|
private:
|
|
/* The task for parallel workers that index units. */
|
|
struct parallel_indexing_worker
|
|
{
|
|
parallel_indexing_worker (const char *step_name,
|
|
cooked_index_debug_info *parent)
|
|
: m_scoped_time_it (step_name, parent->m_per_command_time),
|
|
m_parent (parent)
|
|
{
|
|
}
|
|
|
|
DISABLE_COPY_AND_ASSIGN (parallel_indexing_worker);
|
|
|
|
~parallel_indexing_worker ()
|
|
{
|
|
bfd_thread_cleanup ();
|
|
|
|
/* Append the results of this worker to the parent instance. */
|
|
#if CXX_STD_THREAD
|
|
std::lock_guard<std::mutex> lock (m_parent->m_results_mutex);
|
|
#endif
|
|
m_parent->m_results.emplace_back (result_type (m_thread_storage.release (),
|
|
m_complaint_handler.release (),
|
|
std::move (m_errors),
|
|
m_thread_storage.release_parent_map ()));
|
|
}
|
|
|
|
void operator() (iterator_range<dwarf2_per_cu_data_up *> range)
|
|
{
|
|
for (auto &per_cu : range)
|
|
{
|
|
try
|
|
{
|
|
process_psymtab_comp_unit (per_cu.get (),
|
|
m_parent->m_per_objfile,
|
|
&m_thread_storage);
|
|
}
|
|
catch (gdb_exception &except)
|
|
{
|
|
m_errors.push_back (std::move (except));
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
/* Measures the execution time of this worker. */
|
|
scoped_time_it m_scoped_time_it;
|
|
|
|
/* Delayed complaints and errors recorded while indexing units. */
|
|
complaint_interceptor m_complaint_handler;
|
|
std::vector<gdb_exception> m_errors;
|
|
|
|
/* Index storage for this worker. */
|
|
cooked_index_storage m_thread_storage;
|
|
|
|
/* The instance that spawned this worker. */
|
|
cooked_index_debug_info *m_parent;
|
|
};
|
|
|
|
void do_reading () override;
|
|
|
|
void print_stats () override
|
|
{
|
|
if (dwarf_read_debug > 0)
|
|
print_tu_stats (m_per_objfile);
|
|
if (dwarf_read_debug > 1)
|
|
{
|
|
dwarf_read_debug_printf_v ("Final m_all_parents_map:");
|
|
m_all_parents_map.dump (m_per_objfile->per_bfd);
|
|
}
|
|
}
|
|
|
|
/* After the last DWARF-reading task has finished, this function
|
|
does the remaining work to finish the scan. */
|
|
void done_reading ();
|
|
|
|
/* An iterator for the comp units. */
|
|
typedef std::vector<dwarf2_per_cu_data_up>::iterator unit_iterator;
|
|
|
|
/* A storage object for "leftovers" -- see the 'start' method, but
|
|
essentially things not parsed during the normal CU parsing
|
|
passes. */
|
|
cooked_index_storage m_index_storage;
|
|
};
|
|
|
|
void
|
|
cooked_index_debug_info::done_reading ()
|
|
{
|
|
/* Only handle the scanning results here. Complaints and exceptions
|
|
can only be dealt with on the main thread. */
|
|
std::vector<std::unique_ptr<cooked_index_shard>> indexes;
|
|
|
|
{
|
|
scoped_time_it time_it ("DWARF add parent map");
|
|
|
|
for (auto &one_result : m_results)
|
|
{
|
|
indexes.push_back (std::move (std::get<0> (one_result)));
|
|
m_all_parents_map.add_map (std::get<3> (one_result));
|
|
}
|
|
}
|
|
|
|
/* This has to wait until we read the CUs, we need the list of DWOs. */
|
|
process_skeletonless_type_units (m_per_objfile, &m_index_storage,
|
|
m_per_command_time);
|
|
|
|
indexes.push_back (m_index_storage.release ());
|
|
indexes.shrink_to_fit ();
|
|
|
|
m_all_parents_map.add_map (m_index_storage.release_parent_map ());
|
|
|
|
dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
|
|
cooked_index *table
|
|
= (gdb::checked_static_cast<cooked_index *>
|
|
(per_bfd->index_table.get ()));
|
|
table->set_contents (std::move (indexes), &m_warnings,
|
|
&m_all_parents_map);
|
|
}
|
|
|
|
void
|
|
cooked_index_debug_info::do_reading ()
|
|
{
|
|
dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
|
|
|
|
create_all_units (m_per_objfile);
|
|
build_type_psymtabs (m_per_objfile, &m_index_storage);
|
|
|
|
per_bfd->quick_file_names_table
|
|
= create_quick_file_names_table (per_bfd->all_units.size ());
|
|
if (!per_bfd->debug_aranges.empty ())
|
|
read_addrmap_from_aranges (m_per_objfile, &per_bfd->debug_aranges,
|
|
m_index_storage.get_addrmap (),
|
|
&m_warnings);
|
|
|
|
/* Launch parallel tasks to index units.
|
|
|
|
The (unfortunate) reason why we don't use
|
|
std::vector<dwarf2_per_cu_up>::iterator as the parallel-for-each iterator
|
|
type is that std::atomic won't work with that type when building with
|
|
-D_GLIBCXX_DEBUG. */
|
|
gdb::parallel_for_each_async<1, dwarf2_per_cu_data_up *, parallel_indexing_worker>
|
|
(per_bfd->all_units.data (),
|
|
per_bfd->all_units.data () + per_bfd->all_units.size (),
|
|
[this] () { this->done_reading (); }, "DWARF indexing worker", this);
|
|
}
|
|
|
|
static void
|
|
read_comp_units_from_section (dwarf2_per_objfile *per_objfile,
|
|
struct dwarf2_section_info *section,
|
|
struct dwarf2_section_info *abbrev_section,
|
|
unsigned int is_dwz,
|
|
htab_up &types_htab,
|
|
rcuh_kind section_kind)
|
|
{
|
|
const gdb_byte *info_ptr;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
|
|
dwarf_read_debug_printf ("Reading %s for %s",
|
|
section->get_name (),
|
|
section->get_file_name ());
|
|
|
|
section->read (objfile);
|
|
|
|
info_ptr = section->buffer;
|
|
|
|
while (info_ptr < section->buffer + section->size)
|
|
{
|
|
dwarf2_per_cu_data_up this_cu;
|
|
|
|
sect_offset sect_off = (sect_offset) (info_ptr - section->buffer);
|
|
|
|
comp_unit_head cu_header;
|
|
read_and_check_comp_unit_head (per_objfile, &cu_header, section,
|
|
abbrev_section, info_ptr,
|
|
section_kind);
|
|
|
|
/* Save the compilation unit for later lookup. */
|
|
if (cu_header.unit_type != DW_UT_type)
|
|
this_cu = per_objfile->per_bfd->allocate_per_cu ();
|
|
else
|
|
{
|
|
if (types_htab == nullptr)
|
|
types_htab = allocate_signatured_type_table ();
|
|
|
|
auto sig_type = per_objfile->per_bfd->allocate_signatured_type
|
|
(cu_header.signature);
|
|
signatured_type *sig_ptr = sig_type.get ();
|
|
sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu;
|
|
this_cu.reset (sig_type.release ());
|
|
|
|
void **slot = htab_find_slot (types_htab.get (), sig_ptr, INSERT);
|
|
gdb_assert (slot != nullptr);
|
|
if (*slot != nullptr)
|
|
complaint (_("debug type entry at offset %s is duplicate to"
|
|
" the entry at offset %s, signature %s"),
|
|
sect_offset_str (sect_off),
|
|
sect_offset_str (sig_ptr->sect_off),
|
|
hex_string (sig_ptr->signature));
|
|
*slot = sig_ptr;
|
|
}
|
|
this_cu->sect_off = sect_off;
|
|
this_cu->set_length (cu_header.get_length_with_initial ());
|
|
this_cu->is_dwz = is_dwz;
|
|
this_cu->section = section;
|
|
|
|
info_ptr = info_ptr + this_cu->length ();
|
|
per_objfile->per_bfd->all_units.push_back (std::move (this_cu));
|
|
}
|
|
}
|
|
|
|
/* Initialize the views on all_units. */
|
|
|
|
void
|
|
finalize_all_units (dwarf2_per_bfd *per_bfd)
|
|
{
|
|
size_t nr_tus = per_bfd->tu_stats.nr_tus;
|
|
size_t nr_cus = per_bfd->all_units.size () - nr_tus;
|
|
gdb::array_view<dwarf2_per_cu_data_up> tmp = per_bfd->all_units;
|
|
per_bfd->all_comp_units = tmp.slice (0, nr_cus);
|
|
per_bfd->all_type_units = tmp.slice (nr_cus, nr_tus);
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
void
|
|
create_all_units (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
htab_up types_htab;
|
|
gdb_assert (per_objfile->per_bfd->all_units.empty ());
|
|
|
|
for (dwarf2_section_info §ion : per_objfile->per_bfd->infos)
|
|
read_comp_units_from_section (per_objfile, §ion,
|
|
&per_objfile->per_bfd->abbrev, 0,
|
|
types_htab, rcuh_kind::COMPILE);
|
|
for (dwarf2_section_info §ion : per_objfile->per_bfd->types)
|
|
read_comp_units_from_section (per_objfile, §ion,
|
|
&per_objfile->per_bfd->abbrev, 0,
|
|
types_htab, rcuh_kind::TYPE);
|
|
|
|
dwz_file *dwz = dwarf2_get_dwz_file (per_objfile->per_bfd);
|
|
if (dwz != NULL)
|
|
{
|
|
read_comp_units_from_section (per_objfile, &dwz->info, &dwz->abbrev, 1,
|
|
types_htab, rcuh_kind::COMPILE);
|
|
|
|
if (!dwz->types.empty ())
|
|
{
|
|
per_objfile->per_bfd->all_units.clear ();
|
|
|
|
/* See enhancement PR symtab/30838. */
|
|
error (_(DWARF_ERROR_PREFIX
|
|
".debug_types section not supported in dwz file"));
|
|
}
|
|
}
|
|
|
|
per_objfile->per_bfd->signatured_types = std::move (types_htab);
|
|
|
|
finalize_all_units (per_objfile->per_bfd);
|
|
}
|
|
|
|
/* Return the initial uleb128 in the die at INFO_PTR. */
|
|
|
|
static unsigned int
|
|
peek_abbrev_code (bfd *abfd, const gdb_byte *info_ptr)
|
|
{
|
|
unsigned int bytes_read;
|
|
|
|
return read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
|
|
}
|
|
|
|
/* Read the initial uleb128 in the die at INFO_PTR in compilation unit
|
|
READER::CU. Use READER::ABBREV_TABLE to lookup any abbreviation.
|
|
|
|
Return the corresponding abbrev, or NULL if the number is zero (indicating
|
|
an empty DIE). In either case *BYTES_READ will be set to the length of
|
|
the initial number. */
|
|
|
|
static const struct abbrev_info *
|
|
peek_die_abbrev (const die_reader_specs &reader,
|
|
const gdb_byte *info_ptr, unsigned int *bytes_read)
|
|
{
|
|
dwarf2_cu *cu = reader.cu;
|
|
bfd *abfd = reader.abfd;
|
|
unsigned int abbrev_number
|
|
= read_unsigned_leb128 (abfd, info_ptr, bytes_read);
|
|
|
|
if (abbrev_number == 0)
|
|
return NULL;
|
|
|
|
const abbrev_info *abbrev
|
|
= reader.abbrev_table->lookup_abbrev (abbrev_number);
|
|
if (!abbrev)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Could not find abbrev number %d in %s at offset %s"
|
|
" [in module %s]"),
|
|
abbrev_number, cu->per_cu->is_debug_types ? "TU" : "CU",
|
|
sect_offset_str (cu->header.sect_off), bfd_get_filename (abfd));
|
|
}
|
|
|
|
return abbrev;
|
|
}
|
|
|
|
/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER.
|
|
Returns a pointer to the end of a series of DIEs, terminated by an empty
|
|
DIE. Any children of the skipped DIEs will also be skipped. */
|
|
|
|
static const gdb_byte *
|
|
skip_children (const struct die_reader_specs *reader, const gdb_byte *info_ptr)
|
|
{
|
|
while (1)
|
|
{
|
|
unsigned int bytes_read;
|
|
const abbrev_info *abbrev = peek_die_abbrev (*reader, info_ptr,
|
|
&bytes_read);
|
|
|
|
if (abbrev == NULL)
|
|
return info_ptr + bytes_read;
|
|
else
|
|
info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev);
|
|
}
|
|
}
|
|
|
|
/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER.
|
|
INFO_PTR should point just after the initial uleb128 of a DIE, and the
|
|
abbrev corresponding to that skipped uleb128 should be passed in
|
|
ABBREV.
|
|
|
|
If DO_SKIP_CHILDREN is true, or if the DIE has no children, this
|
|
returns a pointer to this DIE's sibling, skipping any children.
|
|
Otherwise, returns a pointer to the DIE's first child. */
|
|
|
|
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)
|
|
{
|
|
unsigned int bytes_read;
|
|
struct attribute attr;
|
|
bfd *abfd = reader->abfd;
|
|
struct dwarf2_cu *cu = reader->cu;
|
|
const gdb_byte *buffer = reader->buffer;
|
|
const gdb_byte *buffer_end = reader->buffer_end;
|
|
unsigned int form, i;
|
|
|
|
if (do_skip_children && abbrev->sibling_offset != (unsigned short) -1)
|
|
{
|
|
/* We only handle DW_FORM_ref4 here. */
|
|
const gdb_byte *sibling_data = info_ptr + abbrev->sibling_offset;
|
|
unsigned int offset = read_4_bytes (abfd, sibling_data);
|
|
const gdb_byte *sibling_ptr
|
|
= buffer + to_underlying (cu->header.sect_off) + offset;
|
|
if (sibling_ptr >= info_ptr && sibling_ptr < reader->buffer_end)
|
|
return sibling_ptr;
|
|
/* Fall through to the slow way. */
|
|
}
|
|
else if (abbrev->size_if_constant != 0)
|
|
{
|
|
info_ptr += abbrev->size_if_constant;
|
|
if (do_skip_children && abbrev->has_children)
|
|
return skip_children (reader, info_ptr);
|
|
return info_ptr;
|
|
}
|
|
|
|
for (i = 0; i < abbrev->num_attrs; i++)
|
|
{
|
|
/* The only abbrev we care about is DW_AT_sibling. */
|
|
if (do_skip_children && abbrev->attrs[i].name == DW_AT_sibling)
|
|
{
|
|
/* Note there is no need for the extra work of
|
|
"reprocessing" here, so we pass false for that
|
|
argument. */
|
|
read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr, false);
|
|
if (attr.form == DW_FORM_ref_addr)
|
|
complaint (_("ignoring absolute DW_AT_sibling"));
|
|
else
|
|
{
|
|
sect_offset off = attr.get_ref_die_offset ();
|
|
const gdb_byte *sibling_ptr = buffer + to_underlying (off);
|
|
|
|
if (sibling_ptr < info_ptr)
|
|
complaint (_("DW_AT_sibling points backwards"));
|
|
else if (sibling_ptr > reader->buffer_end)
|
|
reader->die_section->overflow_complaint ();
|
|
else
|
|
return sibling_ptr;
|
|
}
|
|
}
|
|
|
|
/* If it isn't DW_AT_sibling, skip this attribute. */
|
|
form = abbrev->attrs[i].form;
|
|
skip_attribute:
|
|
switch (form)
|
|
{
|
|
case DW_FORM_ref_addr:
|
|
/* In DWARF 2, DW_FORM_ref_addr is address sized; in DWARF 3
|
|
and later it is offset sized. */
|
|
if (cu->header.version == 2)
|
|
info_ptr += cu->header.addr_size;
|
|
else
|
|
info_ptr += cu->header.offset_size;
|
|
break;
|
|
case DW_FORM_GNU_ref_alt:
|
|
info_ptr += cu->header.offset_size;
|
|
break;
|
|
case DW_FORM_addr:
|
|
info_ptr += cu->header.addr_size;
|
|
break;
|
|
case DW_FORM_data1:
|
|
case DW_FORM_ref1:
|
|
case DW_FORM_flag:
|
|
case DW_FORM_strx1:
|
|
info_ptr += 1;
|
|
break;
|
|
case DW_FORM_flag_present:
|
|
case DW_FORM_implicit_const:
|
|
break;
|
|
case DW_FORM_data2:
|
|
case DW_FORM_ref2:
|
|
case DW_FORM_strx2:
|
|
info_ptr += 2;
|
|
break;
|
|
case DW_FORM_strx3:
|
|
info_ptr += 3;
|
|
break;
|
|
case DW_FORM_data4:
|
|
case DW_FORM_ref4:
|
|
case DW_FORM_strx4:
|
|
info_ptr += 4;
|
|
break;
|
|
case DW_FORM_data8:
|
|
case DW_FORM_ref8:
|
|
case DW_FORM_ref_sig8:
|
|
info_ptr += 8;
|
|
break;
|
|
case DW_FORM_data16:
|
|
info_ptr += 16;
|
|
break;
|
|
case DW_FORM_string:
|
|
read_direct_string (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_sec_offset:
|
|
case DW_FORM_strp:
|
|
case DW_FORM_GNU_strp_alt:
|
|
info_ptr += cu->header.offset_size;
|
|
break;
|
|
case DW_FORM_exprloc:
|
|
case DW_FORM_block:
|
|
info_ptr += read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_block1:
|
|
info_ptr += 1 + read_1_byte (abfd, info_ptr);
|
|
break;
|
|
case DW_FORM_block2:
|
|
info_ptr += 2 + read_2_bytes (abfd, info_ptr);
|
|
break;
|
|
case DW_FORM_block4:
|
|
info_ptr += 4 + read_4_bytes (abfd, info_ptr);
|
|
break;
|
|
case DW_FORM_addrx:
|
|
case DW_FORM_strx:
|
|
case DW_FORM_sdata:
|
|
case DW_FORM_udata:
|
|
case DW_FORM_ref_udata:
|
|
case DW_FORM_GNU_addr_index:
|
|
case DW_FORM_GNU_str_index:
|
|
case DW_FORM_rnglistx:
|
|
case DW_FORM_loclistx:
|
|
info_ptr = safe_skip_leb128 (info_ptr, buffer_end);
|
|
break;
|
|
case DW_FORM_indirect:
|
|
form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
/* We need to continue parsing from here, so just go back to
|
|
the top. */
|
|
goto skip_attribute;
|
|
|
|
default:
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Cannot handle %s in DWARF reader [in module %s]"),
|
|
dwarf_form_name (form),
|
|
bfd_get_filename (abfd));
|
|
}
|
|
}
|
|
|
|
if (do_skip_children && abbrev->has_children)
|
|
return skip_children (reader, info_ptr);
|
|
else
|
|
return info_ptr;
|
|
}
|
|
|
|
/* Reading in full CUs. */
|
|
|
|
/* Add PER_CU to the queue. */
|
|
|
|
static void
|
|
queue_comp_unit (dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
enum language pretend_language)
|
|
{
|
|
per_cu->queued = 1;
|
|
|
|
gdb_assert (per_objfile->queue.has_value ());
|
|
per_objfile->queue->emplace (per_cu, per_objfile, pretend_language);
|
|
}
|
|
|
|
/* If PER_CU is not yet expanded of queued for expansion, add it to the queue.
|
|
|
|
If DEPENDENT_CU is non-NULL, it has a reference to PER_CU so add a
|
|
dependency.
|
|
|
|
Return true if maybe_queue_comp_unit requires the caller to load the CU's
|
|
DIEs, false otherwise.
|
|
|
|
Explanation: there is an invariant that if a CU is queued for expansion
|
|
(present in `dwarf2_per_bfd::queue`), then its DIEs are loaded
|
|
(a dwarf2_cu object exists for this CU, and `dwarf2_per_objfile::get_cu`
|
|
returns non-nullptr). If the CU gets enqueued by this function but its DIEs
|
|
are not yet loaded, the the caller must load the CU's DIEs to ensure the
|
|
invariant is respected.
|
|
|
|
The caller is therefore not required to load the CU's DIEs (we return false)
|
|
if:
|
|
|
|
- the CU is already expanded, and therefore does not get enqueued
|
|
- the CU gets enqueued for expansion, but its DIEs are already loaded
|
|
|
|
Note that the caller should not use this function's return value as an
|
|
indicator of whether the CU's DIEs are loaded right now, it should check
|
|
that by calling `dwarf2_per_objfile::get_cu` instead. */
|
|
|
|
static int
|
|
maybe_queue_comp_unit (struct dwarf2_cu *dependent_cu,
|
|
dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
enum language pretend_language)
|
|
{
|
|
/* Mark the dependence relation so that we don't flush PER_CU
|
|
too early. */
|
|
if (dependent_cu != NULL)
|
|
dependent_cu->add_dependence (per_cu);
|
|
|
|
/* If it's already on the queue, we have nothing to do. */
|
|
if (per_cu->queued)
|
|
{
|
|
/* Verify the invariant that if a CU is queued for expansion, its DIEs are
|
|
loaded. */
|
|
gdb_assert (per_objfile->get_cu (per_cu) != nullptr);
|
|
|
|
/* If the CU is queued for expansion, it should not already be
|
|
expanded. */
|
|
gdb_assert (!per_objfile->symtab_set_p (per_cu));
|
|
|
|
/* The DIEs are already loaded, the caller doesn't need to do it. */
|
|
return 0;
|
|
}
|
|
|
|
bool queued = false;
|
|
if (!per_objfile->symtab_set_p (per_cu))
|
|
{
|
|
/* Add it to the queue. */
|
|
queue_comp_unit (per_cu, per_objfile, pretend_language);
|
|
queued = true;
|
|
}
|
|
|
|
/* If the compilation unit is already loaded, just mark it as
|
|
used. */
|
|
dwarf2_cu *cu = per_objfile->get_cu (per_cu);
|
|
if (cu != nullptr)
|
|
cu->last_used = 0;
|
|
|
|
/* Ask the caller to load the CU's DIEs if the CU got enqueued for expansion
|
|
and the DIEs are not already loaded. */
|
|
return queued && cu == nullptr;
|
|
}
|
|
|
|
/* Process the queue. */
|
|
|
|
static void
|
|
process_queue (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
dwarf_read_debug_printf ("Expanding one or more symtabs of objfile %s ...",
|
|
objfile_name (per_objfile->objfile));
|
|
|
|
/* The queue starts out with one item, but following a DIE reference
|
|
may load a new CU, adding it to the end of the queue. */
|
|
while (!per_objfile->queue->empty ())
|
|
{
|
|
dwarf2_queue_item &item = per_objfile->queue->front ();
|
|
dwarf2_per_cu_data *per_cu = item.per_cu;
|
|
|
|
if (!per_objfile->symtab_set_p (per_cu))
|
|
{
|
|
dwarf2_cu *cu = per_objfile->get_cu (per_cu);
|
|
|
|
/* Skip dummy CUs. */
|
|
if (cu != nullptr)
|
|
{
|
|
unsigned int debug_print_threshold;
|
|
char buf[100];
|
|
|
|
if (per_cu->is_debug_types)
|
|
{
|
|
struct signatured_type *sig_type =
|
|
(struct signatured_type *) per_cu;
|
|
|
|
sprintf (buf, "TU %s at offset %s",
|
|
hex_string (sig_type->signature),
|
|
sect_offset_str (per_cu->sect_off));
|
|
/* There can be 100s of TUs.
|
|
Only print them in verbose mode. */
|
|
debug_print_threshold = 2;
|
|
}
|
|
else
|
|
{
|
|
sprintf (buf, "CU at offset %s",
|
|
sect_offset_str (per_cu->sect_off));
|
|
debug_print_threshold = 1;
|
|
}
|
|
|
|
if (dwarf_read_debug >= debug_print_threshold)
|
|
dwarf_read_debug_printf ("Expanding symtab of %s", buf);
|
|
|
|
if (per_cu->is_debug_types)
|
|
process_full_type_unit (cu, item.pretend_language);
|
|
else
|
|
process_full_comp_unit (cu, item.pretend_language);
|
|
|
|
if (dwarf_read_debug >= debug_print_threshold)
|
|
dwarf_read_debug_printf ("Done expanding %s", buf);
|
|
}
|
|
}
|
|
|
|
per_cu->queued = 0;
|
|
per_objfile->queue->pop ();
|
|
}
|
|
|
|
dwarf_read_debug_printf ("Done expanding symtabs of %s.",
|
|
objfile_name (per_objfile->objfile));
|
|
}
|
|
|
|
/* Load the DIEs associated with PER_CU into memory.
|
|
|
|
In some cases, the caller, while reading partial symbols, will need to load
|
|
the full symbols for the CU for some reason. It will already have a
|
|
dwarf2_cu object for THIS_CU and pass it as EXISTING_CU, so it can be re-used
|
|
rather than creating a new one. */
|
|
|
|
static void
|
|
load_full_comp_unit (dwarf2_per_cu_data *this_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
dwarf2_cu *existing_cu,
|
|
bool skip_partial,
|
|
enum language pretend_language)
|
|
{
|
|
gdb_assert (! this_cu->is_debug_types);
|
|
|
|
cutu_reader reader (this_cu, per_objfile, NULL, existing_cu, skip_partial);
|
|
if (reader.dummy_p)
|
|
return;
|
|
|
|
struct dwarf2_cu *cu = reader.cu;
|
|
const gdb_byte *info_ptr = reader.info_ptr;
|
|
|
|
gdb_assert (cu->die_hash.empty ());
|
|
cu->die_hash.reserve (cu->header.get_length_without_initial () / 12);
|
|
|
|
if (reader.comp_unit_die->has_children)
|
|
reader.comp_unit_die->child
|
|
= read_die_and_siblings (&reader, reader.info_ptr,
|
|
&info_ptr, reader.comp_unit_die);
|
|
cu->dies = reader.comp_unit_die;
|
|
/* comp_unit_die is not stored in die_hash, no need. */
|
|
|
|
/* We try not to read any attributes in this function, because not
|
|
all CUs needed for references have been loaded yet, and symbol
|
|
table processing isn't initialized. But we have to set the CU language,
|
|
or we won't be able to build types correctly.
|
|
Similarly, if we do not read the producer, we can not apply
|
|
producer-specific interpretation. */
|
|
prepare_one_comp_unit (cu, cu->dies, pretend_language);
|
|
|
|
reader.keep ();
|
|
}
|
|
|
|
/* Add a DIE to the delayed physname list. */
|
|
|
|
static void
|
|
add_to_method_list (struct type *type, int fnfield_index, int index,
|
|
const char *name, struct die_info *die,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct delayed_method_info mi;
|
|
mi.type = type;
|
|
mi.fnfield_index = fnfield_index;
|
|
mi.index = index;
|
|
mi.name = name;
|
|
mi.die = die;
|
|
cu->method_list.push_back (mi);
|
|
}
|
|
|
|
/* Check whether [PHYSNAME, PHYSNAME+LEN) ends with a modifier like
|
|
"const" / "volatile". If so, decrements LEN by the length of the
|
|
modifier and return true. Otherwise return false. */
|
|
|
|
template<size_t N>
|
|
static bool
|
|
check_modifier (const char *physname, size_t &len, const char (&mod)[N])
|
|
{
|
|
size_t mod_len = sizeof (mod) - 1;
|
|
if (len > mod_len && startswith (physname + (len - mod_len), mod))
|
|
{
|
|
len -= mod_len;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Compute the physnames of any methods on the CU's method list.
|
|
|
|
The computation of method physnames is delayed in order to avoid the
|
|
(bad) condition that one of the method's formal parameters is of an as yet
|
|
incomplete type. */
|
|
|
|
static void
|
|
compute_delayed_physnames (struct dwarf2_cu *cu)
|
|
{
|
|
/* Only C++ delays computing physnames. */
|
|
if (cu->method_list.empty ())
|
|
return;
|
|
gdb_assert (is_cplus_dialect (cu->lang ()));
|
|
|
|
for (const delayed_method_info &mi : cu->method_list)
|
|
{
|
|
const char *physname;
|
|
struct fn_fieldlist *fn_flp
|
|
= &TYPE_FN_FIELDLIST (mi.type, mi.fnfield_index);
|
|
physname = dwarf2_physname (mi.name, mi.die, cu);
|
|
TYPE_FN_FIELD_PHYSNAME (fn_flp->fn_fields, mi.index)
|
|
= physname ? physname : "";
|
|
|
|
/* Since there's no tag to indicate whether a method is a
|
|
const/volatile overload, extract that information out of the
|
|
demangled name. */
|
|
if (physname != NULL)
|
|
{
|
|
size_t len = strlen (physname);
|
|
|
|
while (1)
|
|
{
|
|
if (physname[len - 1] == ')') /* shortcut */
|
|
break;
|
|
else if (check_modifier (physname, len, " const"))
|
|
TYPE_FN_FIELD_CONST (fn_flp->fn_fields, mi.index) = 1;
|
|
else if (check_modifier (physname, len, " volatile"))
|
|
TYPE_FN_FIELD_VOLATILE (fn_flp->fn_fields, mi.index) = 1;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The list is no longer needed. */
|
|
cu->method_list.clear ();
|
|
}
|
|
|
|
/* Go objects should be embedded in a DW_TAG_module DIE,
|
|
and it's not clear if/how imported objects will appear.
|
|
To keep Go support simple until that's worked out,
|
|
go back through what we've read and create something usable.
|
|
We could do this while processing each DIE, and feels kinda cleaner,
|
|
but that way is more invasive.
|
|
This is to, for example, allow the user to type "p var" or "b main"
|
|
without having to specify the package name, and allow lookups
|
|
of module.object to work in contexts that use the expression
|
|
parser. */
|
|
|
|
static void
|
|
fixup_go_packaging (struct dwarf2_cu *cu)
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> package_name;
|
|
struct pending *list;
|
|
int i;
|
|
|
|
for (list = *cu->get_builder ()->get_global_symbols ();
|
|
list != NULL;
|
|
list = list->next)
|
|
{
|
|
for (i = 0; i < list->nsyms; ++i)
|
|
{
|
|
struct symbol *sym = list->symbol[i];
|
|
|
|
if (sym->language () == language_go
|
|
&& sym->aclass () == LOC_BLOCK)
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> this_package_name
|
|
= go_symbol_package_name (sym);
|
|
|
|
if (this_package_name == NULL)
|
|
continue;
|
|
if (package_name == NULL)
|
|
package_name = std::move (this_package_name);
|
|
else
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
if (strcmp (package_name.get (), this_package_name.get ()) != 0)
|
|
complaint (_("Symtab %s has objects from two different Go packages: %s and %s"),
|
|
(sym->symtab () != NULL
|
|
? symtab_to_filename_for_display
|
|
(sym->symtab ())
|
|
: objfile_name (objfile)),
|
|
this_package_name.get (), package_name.get ());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (package_name != NULL)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
const char *saved_package_name = objfile->intern (package_name.get ());
|
|
struct type *type
|
|
= type_allocator (objfile, cu->lang ()).new_type (TYPE_CODE_MODULE, 0,
|
|
saved_package_name);
|
|
struct symbol *sym;
|
|
|
|
sym = new (&objfile->objfile_obstack) symbol;
|
|
sym->set_language (language_go, &objfile->objfile_obstack);
|
|
sym->compute_and_set_names (saved_package_name, false, objfile->per_bfd);
|
|
sym->set_domain (TYPE_DOMAIN);
|
|
sym->set_aclass_index (LOC_TYPEDEF);
|
|
sym->set_type (type);
|
|
|
|
add_symbol_to_list (sym, cu->get_builder ()->get_global_symbols ());
|
|
}
|
|
}
|
|
|
|
/* Allocate a fully-qualified name consisting of the two parts on the
|
|
obstack. */
|
|
|
|
static const char *
|
|
rust_fully_qualify (struct obstack *obstack, const char *p1, const char *p2)
|
|
{
|
|
return obconcat (obstack, p1, "::", p2, (char *) NULL);
|
|
}
|
|
|
|
/* A helper that allocates a variant part to attach to a Rust enum
|
|
type. OBSTACK is where the results should be allocated. TYPE is
|
|
the type we're processing. DISCRIMINANT_INDEX is the index of the
|
|
discriminant. It must be the index of one of the fields of TYPE,
|
|
or -1 to mean there is no discriminant (univariant enum).
|
|
DEFAULT_INDEX is the index of the default field; or -1 if there is
|
|
no default. RANGES is indexed by "effective" field number (the
|
|
field index, but omitting the discriminant and default fields) and
|
|
must hold the discriminant values used by the variants. Note that
|
|
RANGES must have a lifetime at least as long as OBSTACK -- either
|
|
already allocated on it, or static. */
|
|
|
|
static void
|
|
alloc_rust_variant (struct obstack *obstack, struct type *type,
|
|
int discriminant_index, int default_index,
|
|
gdb::array_view<discriminant_range> ranges)
|
|
{
|
|
/* When DISCRIMINANT_INDEX == -1, we have a univariant enum. */
|
|
gdb_assert (discriminant_index == -1
|
|
|| (discriminant_index >= 0
|
|
&& discriminant_index < type->num_fields ()));
|
|
gdb_assert (default_index == -1
|
|
|| (default_index >= 0 && default_index < type->num_fields ()));
|
|
|
|
/* We have one variant for each non-discriminant field. */
|
|
int n_variants = type->num_fields ();
|
|
if (discriminant_index != -1)
|
|
--n_variants;
|
|
|
|
variant *variants = new (obstack) variant[n_variants];
|
|
int var_idx = 0;
|
|
int range_idx = 0;
|
|
for (int i = 0; i < type->num_fields (); ++i)
|
|
{
|
|
if (i == discriminant_index)
|
|
continue;
|
|
|
|
variants[var_idx].first_field = i;
|
|
variants[var_idx].last_field = i + 1;
|
|
|
|
/* The default field does not need a range, but other fields do.
|
|
We skipped the discriminant above. */
|
|
if (i != default_index)
|
|
{
|
|
variants[var_idx].discriminants = ranges.slice (range_idx, 1);
|
|
++range_idx;
|
|
}
|
|
|
|
++var_idx;
|
|
}
|
|
|
|
gdb_assert (range_idx == ranges.size ());
|
|
gdb_assert (var_idx == n_variants);
|
|
|
|
variant_part *part = new (obstack) variant_part;
|
|
part->discriminant_index = discriminant_index;
|
|
/* If there is no discriminant, then whether it is signed is of no
|
|
consequence. */
|
|
part->is_unsigned
|
|
= (discriminant_index == -1
|
|
? false
|
|
: type->field (discriminant_index).type ()->is_unsigned ());
|
|
part->variants = gdb::array_view<variant> (variants, n_variants);
|
|
|
|
void *storage = obstack_alloc (obstack, sizeof (gdb::array_view<variant_part>));
|
|
gdb::array_view<variant_part> *prop_value
|
|
= new (storage) gdb::array_view<variant_part> (part, 1);
|
|
|
|
struct dynamic_prop prop;
|
|
prop.set_variant_parts (prop_value);
|
|
|
|
type->add_dyn_prop (DYN_PROP_VARIANT_PARTS, prop);
|
|
}
|
|
|
|
/* Some versions of rustc emitted enums in an unusual way.
|
|
|
|
Ordinary enums were emitted as unions. The first element of each
|
|
structure in the union was named "RUST$ENUM$DISR". This element
|
|
held the discriminant.
|
|
|
|
These versions of Rust also implemented the "non-zero"
|
|
optimization. When the enum had two values, and one is empty and
|
|
the other holds a pointer that cannot be zero, the pointer is used
|
|
as the discriminant, with a zero value meaning the empty variant.
|
|
Here, the union's first member is of the form
|
|
RUST$ENCODED$ENUM$<fieldno>$<fieldno>$...$<variantname>
|
|
where the fieldnos are the indices of the fields that should be
|
|
traversed in order to find the field (which may be several fields deep)
|
|
and the variantname is the name of the variant of the case when the
|
|
field is zero.
|
|
|
|
This function recognizes whether TYPE is of one of these forms,
|
|
and, if so, smashes it to be a variant type. */
|
|
|
|
static void
|
|
quirk_rust_enum (struct type *type, struct objfile *objfile)
|
|
{
|
|
gdb_assert (type->code () == TYPE_CODE_UNION);
|
|
|
|
/* We don't need to deal with empty enums. */
|
|
if (type->num_fields () == 0)
|
|
return;
|
|
|
|
#define RUST_ENUM_PREFIX "RUST$ENCODED$ENUM$"
|
|
if (type->num_fields () == 1
|
|
&& startswith (type->field (0).name (), RUST_ENUM_PREFIX))
|
|
{
|
|
const char *name = type->field (0).name () + strlen (RUST_ENUM_PREFIX);
|
|
|
|
/* Decode the field name to find the offset of the
|
|
discriminant. */
|
|
ULONGEST bit_offset = 0;
|
|
struct type *field_type = type->field (0).type ();
|
|
while (name[0] >= '0' && name[0] <= '9')
|
|
{
|
|
char *tail;
|
|
unsigned long index = strtoul (name, &tail, 10);
|
|
name = tail;
|
|
if (*name != '$'
|
|
|| index >= field_type->num_fields ()
|
|
|| (field_type->field (index).loc_kind ()
|
|
!= FIELD_LOC_KIND_BITPOS))
|
|
{
|
|
complaint (_("Could not parse Rust enum encoding string \"%s\""
|
|
"[in module %s]"),
|
|
type->field (0).name (),
|
|
objfile_name (objfile));
|
|
return;
|
|
}
|
|
++name;
|
|
|
|
bit_offset += field_type->field (index).loc_bitpos ();
|
|
field_type = field_type->field (index).type ();
|
|
}
|
|
|
|
/* Smash this type to be a structure type. We have to do this
|
|
because the type has already been recorded. */
|
|
type->set_code (TYPE_CODE_STRUCT);
|
|
/* Save the field we care about. */
|
|
struct field saved_field = type->field (0);
|
|
type->alloc_fields (3);
|
|
|
|
/* Put the discriminant at index 0. */
|
|
type->field (0).set_type (field_type);
|
|
type->field (0).set_is_artificial (true);
|
|
type->field (0).set_name ("<<discriminant>>");
|
|
type->field (0).set_loc_bitpos (bit_offset);
|
|
|
|
/* The order of fields doesn't really matter, so put the real
|
|
field at index 1 and the data-less field at index 2. */
|
|
type->field (1) = saved_field;
|
|
type->field (1).set_name
|
|
(rust_last_path_segment (type->field (1).type ()->name ()));
|
|
type->field (1).type ()->set_name
|
|
(rust_fully_qualify (&objfile->objfile_obstack, type->name (),
|
|
type->field (1).name ()));
|
|
|
|
const char *dataless_name
|
|
= rust_fully_qualify (&objfile->objfile_obstack, type->name (),
|
|
name);
|
|
struct type *dataless_type
|
|
= type_allocator (type).new_type (TYPE_CODE_VOID, 0,
|
|
dataless_name);
|
|
type->field (2).set_type (dataless_type);
|
|
/* NAME points into the original discriminant name, which
|
|
already has the correct lifetime. */
|
|
type->field (2).set_name (name);
|
|
type->field (2).set_loc_bitpos (0);
|
|
|
|
/* Indicate that this is a variant type. */
|
|
static discriminant_range ranges[1] = { { 0, 0 } };
|
|
alloc_rust_variant (&objfile->objfile_obstack, type, 0, 1, ranges);
|
|
}
|
|
/* A union with a single anonymous field is probably an old-style
|
|
univariant enum. */
|
|
else if (type->num_fields () == 1 && streq (type->field (0).name (), ""))
|
|
{
|
|
/* Smash this type to be a structure type. We have to do this
|
|
because the type has already been recorded. */
|
|
type->set_code (TYPE_CODE_STRUCT);
|
|
|
|
struct type *field_type = type->field (0).type ();
|
|
const char *variant_name
|
|
= rust_last_path_segment (field_type->name ());
|
|
type->field (0).set_name (variant_name);
|
|
field_type->set_name
|
|
(rust_fully_qualify (&objfile->objfile_obstack,
|
|
type->name (), variant_name));
|
|
|
|
alloc_rust_variant (&objfile->objfile_obstack, type, -1, 0, {});
|
|
}
|
|
else
|
|
{
|
|
struct type *disr_type = nullptr;
|
|
for (int i = 0; i < type->num_fields (); ++i)
|
|
{
|
|
disr_type = type->field (i).type ();
|
|
|
|
if (disr_type->code () != TYPE_CODE_STRUCT)
|
|
{
|
|
/* All fields of a true enum will be structs. */
|
|
return;
|
|
}
|
|
else if (disr_type->num_fields () == 0)
|
|
{
|
|
/* Could be data-less variant, so keep going. */
|
|
disr_type = nullptr;
|
|
}
|
|
else if (strcmp (disr_type->field (0).name (),
|
|
"RUST$ENUM$DISR") != 0)
|
|
{
|
|
/* Not a Rust enum. */
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
/* Found one. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If we got here without a discriminant, then it's probably
|
|
just a union. */
|
|
if (disr_type == nullptr)
|
|
return;
|
|
|
|
/* Smash this type to be a structure type. We have to do this
|
|
because the type has already been recorded. */
|
|
type->set_code (TYPE_CODE_STRUCT);
|
|
|
|
/* Make space for the discriminant field. */
|
|
struct field *disr_field = &disr_type->field (0);
|
|
field *new_fields
|
|
= (struct field *) TYPE_ZALLOC (type, ((type->num_fields () + 1)
|
|
* sizeof (struct field)));
|
|
memcpy (new_fields + 1, type->fields (),
|
|
type->num_fields () * sizeof (struct field));
|
|
type->set_fields (new_fields);
|
|
type->set_num_fields (type->num_fields () + 1);
|
|
|
|
/* Install the discriminant at index 0 in the union. */
|
|
type->field (0) = *disr_field;
|
|
type->field (0).set_is_artificial (true);
|
|
type->field (0).set_name ("<<discriminant>>");
|
|
|
|
/* We need a way to find the correct discriminant given a
|
|
variant name. For convenience we build a map here. */
|
|
struct type *enum_type = disr_field->type ();
|
|
std::unordered_map<std::string_view, ULONGEST> discriminant_map;
|
|
for (int i = 0; i < enum_type->num_fields (); ++i)
|
|
{
|
|
if (enum_type->field (i).loc_kind () == FIELD_LOC_KIND_ENUMVAL)
|
|
{
|
|
const char *name
|
|
= rust_last_path_segment (enum_type->field (i).name ());
|
|
discriminant_map[name] = enum_type->field (i).loc_enumval ();
|
|
}
|
|
}
|
|
|
|
int n_fields = type->num_fields ();
|
|
/* We don't need a range entry for the discriminant, but we do
|
|
need one for every other field, as there is no default
|
|
variant. */
|
|
discriminant_range *ranges = XOBNEWVEC (&objfile->objfile_obstack,
|
|
discriminant_range,
|
|
n_fields - 1);
|
|
/* Skip the discriminant here. */
|
|
for (int i = 1; i < n_fields; ++i)
|
|
{
|
|
/* Find the final word in the name of this variant's type.
|
|
That name can be used to look up the correct
|
|
discriminant. */
|
|
const char *variant_name
|
|
= rust_last_path_segment (type->field (i).type ()->name ());
|
|
|
|
auto iter = discriminant_map.find (variant_name);
|
|
if (iter != discriminant_map.end ())
|
|
{
|
|
ranges[i - 1].low = iter->second;
|
|
ranges[i - 1].high = iter->second;
|
|
}
|
|
|
|
/* In Rust, each element should have the size of the
|
|
enclosing enum. */
|
|
type->field (i).type ()->set_length (type->length ());
|
|
|
|
/* Remove the discriminant field, if it exists. */
|
|
struct type *sub_type = type->field (i).type ();
|
|
if (sub_type->num_fields () > 0)
|
|
{
|
|
sub_type->set_num_fields (sub_type->num_fields () - 1);
|
|
sub_type->set_fields (sub_type->fields () + 1);
|
|
}
|
|
type->field (i).set_name (variant_name);
|
|
sub_type->set_name
|
|
(rust_fully_qualify (&objfile->objfile_obstack,
|
|
type->name (), variant_name));
|
|
}
|
|
|
|
/* Indicate that this is a variant type. */
|
|
alloc_rust_variant (&objfile->objfile_obstack, type, 0, -1,
|
|
gdb::array_view<discriminant_range> (ranges,
|
|
n_fields - 1));
|
|
}
|
|
}
|
|
|
|
/* Rewrite some Rust unions to be structures with variants parts. */
|
|
|
|
static void
|
|
rust_union_quirks (struct dwarf2_cu *cu)
|
|
{
|
|
gdb_assert (cu->lang () == language_rust);
|
|
for (type *type_ : cu->rust_unions)
|
|
quirk_rust_enum (type_, cu->per_objfile->objfile);
|
|
/* We don't need this any more. */
|
|
cu->rust_unions.clear ();
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
type_unit_group_unshareable *
|
|
dwarf2_per_objfile::get_type_unit_group_unshareable (type_unit_group *tu_group)
|
|
{
|
|
auto iter = this->m_type_units.find (tu_group);
|
|
if (iter != this->m_type_units.end ())
|
|
return iter->second.get ();
|
|
|
|
type_unit_group_unshareable_up uniq (new type_unit_group_unshareable);
|
|
type_unit_group_unshareable *result = uniq.get ();
|
|
this->m_type_units[tu_group] = std::move (uniq);
|
|
return result;
|
|
}
|
|
|
|
struct type *
|
|
dwarf2_per_objfile::get_type_for_signatured_type
|
|
(signatured_type *sig_type) const
|
|
{
|
|
auto iter = this->m_type_map.find (sig_type);
|
|
if (iter == this->m_type_map.end ())
|
|
return nullptr;
|
|
|
|
return iter->second;
|
|
}
|
|
|
|
void dwarf2_per_objfile::set_type_for_signatured_type
|
|
(signatured_type *sig_type, struct type *type)
|
|
{
|
|
gdb_assert (this->m_type_map.find (sig_type) == this->m_type_map.end ());
|
|
|
|
this->m_type_map[sig_type] = type;
|
|
}
|
|
|
|
/* A helper function for computing the list of all symbol tables
|
|
included by PER_CU. */
|
|
|
|
static void
|
|
recursively_compute_inclusions
|
|
(std::vector<compunit_symtab *> *result,
|
|
gdb::unordered_set<dwarf2_per_cu_data *> &all_children,
|
|
gdb::unordered_set<compunit_symtab *> &all_type_symtabs,
|
|
dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
struct compunit_symtab *immediate_parent)
|
|
{
|
|
if (bool inserted = all_children.emplace (per_cu).second;
|
|
!inserted)
|
|
{
|
|
/* This inclusion and its children have been processed. */
|
|
return;
|
|
}
|
|
|
|
/* Only add a CU if it has a symbol table. */
|
|
compunit_symtab *cust = per_objfile->get_symtab (per_cu);
|
|
if (cust != NULL)
|
|
{
|
|
/* If this is a type unit only add its symbol table if we haven't
|
|
seen it yet (type unit per_cu's can share symtabs). */
|
|
if (per_cu->is_debug_types)
|
|
{
|
|
if (bool inserted = all_type_symtabs.insert (cust).second;
|
|
inserted)
|
|
{
|
|
result->push_back (cust);
|
|
if (cust->user == NULL)
|
|
cust->user = immediate_parent;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->push_back (cust);
|
|
if (cust->user == NULL)
|
|
cust->user = immediate_parent;
|
|
}
|
|
}
|
|
|
|
for (dwarf2_per_cu_data *ptr : per_cu->imported_symtabs)
|
|
recursively_compute_inclusions (result, all_children,
|
|
all_type_symtabs, ptr, per_objfile,
|
|
cust);
|
|
}
|
|
|
|
/* Compute the compunit_symtab 'includes' fields for the compunit_symtab of
|
|
PER_CU. */
|
|
|
|
static void
|
|
compute_compunit_symtab_includes (dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile)
|
|
{
|
|
gdb_assert (! per_cu->is_debug_types);
|
|
|
|
if (!per_cu->imported_symtabs.empty ())
|
|
{
|
|
int len;
|
|
std::vector<compunit_symtab *> result_symtabs;
|
|
compunit_symtab *cust = per_objfile->get_symtab (per_cu);
|
|
|
|
/* If we don't have a symtab, we can just skip this case. */
|
|
if (cust == NULL)
|
|
return;
|
|
|
|
gdb::unordered_set<dwarf2_per_cu_data *> all_children;
|
|
gdb::unordered_set<compunit_symtab *> all_type_symtabs;
|
|
|
|
for (dwarf2_per_cu_data *ptr : per_cu->imported_symtabs)
|
|
recursively_compute_inclusions (&result_symtabs, all_children,
|
|
all_type_symtabs, ptr,
|
|
per_objfile, cust);
|
|
|
|
/* Now we have a transitive closure of all the included symtabs. */
|
|
len = result_symtabs.size ();
|
|
cust->includes
|
|
= XOBNEWVEC (&per_objfile->objfile->objfile_obstack,
|
|
struct compunit_symtab *, len + 1);
|
|
memcpy (cust->includes, result_symtabs.data (),
|
|
len * sizeof (compunit_symtab *));
|
|
cust->includes[len] = NULL;
|
|
}
|
|
}
|
|
|
|
/* Compute the 'includes' field for the symtabs of all the CUs we just
|
|
read. */
|
|
|
|
static void
|
|
process_cu_includes (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
for (dwarf2_per_cu_data *iter : per_objfile->per_bfd->just_read_cus)
|
|
{
|
|
if (! iter->is_debug_types)
|
|
compute_compunit_symtab_includes (iter, per_objfile);
|
|
}
|
|
|
|
per_objfile->per_bfd->just_read_cus.clear ();
|
|
}
|
|
|
|
/* Generate full symbol information for CU, whose DIEs have
|
|
already been loaded into memory. */
|
|
|
|
static void
|
|
process_full_comp_unit (dwarf2_cu *cu, enum language pretend_language)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
unrelocated_addr lowpc, highpc;
|
|
struct compunit_symtab *cust;
|
|
struct block *static_block;
|
|
CORE_ADDR addr;
|
|
|
|
/* Clear the list here in case something was left over. */
|
|
cu->method_list.clear ();
|
|
|
|
dwarf2_find_base_address (cu->dies, cu);
|
|
|
|
/* Before we start reading the top-level DIE, ensure it has a valid tag
|
|
type. */
|
|
switch (cu->dies->tag)
|
|
{
|
|
case DW_TAG_compile_unit:
|
|
case DW_TAG_partial_unit:
|
|
case DW_TAG_type_unit:
|
|
break;
|
|
default:
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"unexpected tag '%s' at offset %s [in module %s]"),
|
|
dwarf_tag_name (cu->dies->tag),
|
|
sect_offset_str (cu->per_cu->sect_off),
|
|
objfile_name (per_objfile->objfile));
|
|
}
|
|
|
|
/* Do line number decoding in read_file_scope () */
|
|
process_die (cu->dies, cu);
|
|
|
|
/* For now fudge the Go package. */
|
|
if (cu->lang () == language_go)
|
|
fixup_go_packaging (cu);
|
|
|
|
/* Now that we have processed all the DIEs in the CU, all the types
|
|
should be complete, and it should now be safe to compute all of the
|
|
physnames. */
|
|
compute_delayed_physnames (cu);
|
|
|
|
if (cu->lang () == language_rust)
|
|
rust_union_quirks (cu);
|
|
|
|
/* Some compilers don't define a DW_AT_high_pc attribute for the
|
|
compilation unit. If the DW_AT_high_pc is missing, synthesize
|
|
it, by scanning the DIE's below the compilation unit. */
|
|
get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu);
|
|
|
|
addr = per_objfile->relocate (highpc);
|
|
static_block
|
|
= cu->get_builder ()->end_compunit_symtab_get_static_block (addr, 0, 1);
|
|
|
|
/* If the comp unit has DW_AT_ranges, it may have discontiguous ranges.
|
|
Also, DW_AT_ranges may record ranges not belonging to any child DIEs
|
|
(such as virtual method tables). Record the ranges in STATIC_BLOCK's
|
|
addrmap to help ensure it has an accurate map of pc values belonging to
|
|
this comp unit. */
|
|
dwarf2_record_block_ranges (cu->dies, static_block, cu);
|
|
|
|
cust = cu->get_builder ()->end_compunit_symtab_from_static_block
|
|
(static_block, 0);
|
|
|
|
if (cust != NULL)
|
|
{
|
|
int gcc_4_minor = producer_is_gcc_ge_4 (cu->producer);
|
|
|
|
/* Set symtab language to language from DW_AT_language. If the
|
|
compilation is from a C file generated by language preprocessors, do
|
|
not set the language if it was already deduced by start_subfile. */
|
|
if (!(cu->lang () == language_c
|
|
&& cust->primary_filetab ()->language () != language_unknown))
|
|
cust->primary_filetab ()->set_language (cu->lang ());
|
|
|
|
/* GCC-4.0 has started to support -fvar-tracking. GCC-3.x still can
|
|
produce DW_AT_location with location lists but it can be possibly
|
|
invalid without -fvar-tracking. Still up to GCC-4.4.x incl. 4.4.0
|
|
there were bugs in prologue debug info, fixed later in GCC-4.5
|
|
by "unwind info for epilogues" patch (which is not directly related).
|
|
|
|
For -gdwarf-4 type units LOCATIONS_VALID indication is fortunately not
|
|
needed, it would be wrong due to missing DW_AT_producer there.
|
|
|
|
Still one can confuse GDB by using non-standard GCC compilation
|
|
options - this waits on GCC PR other/32998 (-frecord-gcc-switches).
|
|
*/
|
|
if (cu->has_loclist && gcc_4_minor >= 5)
|
|
cust->set_locations_valid (true);
|
|
|
|
int major, minor;
|
|
if (cu->producer != nullptr
|
|
&& producer_is_gcc (cu->producer, &major, &minor)
|
|
&& (major < 4 || (major == 4 && minor < 5)))
|
|
/* Don't trust gcc < 4.5.x. */
|
|
cust->set_epilogue_unwind_valid (false);
|
|
else
|
|
cust->set_epilogue_unwind_valid (true);
|
|
|
|
cust->set_call_site_htab (std::move (cu->call_site_htab));
|
|
}
|
|
|
|
per_objfile->set_symtab (cu->per_cu, cust);
|
|
|
|
/* Push it for inclusion processing later. */
|
|
per_objfile->per_bfd->just_read_cus.push_back (cu->per_cu);
|
|
|
|
/* Not needed any more. */
|
|
cu->reset_builder ();
|
|
}
|
|
|
|
/* Generate full symbol information for type unit CU, whose DIEs have
|
|
already been loaded into memory. */
|
|
|
|
static void
|
|
process_full_type_unit (dwarf2_cu *cu,
|
|
enum language pretend_language)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct compunit_symtab *cust;
|
|
struct signatured_type *sig_type;
|
|
|
|
gdb_assert (cu->per_cu->is_debug_types);
|
|
sig_type = (struct signatured_type *) cu->per_cu;
|
|
|
|
/* Clear the list here in case something was left over. */
|
|
cu->method_list.clear ();
|
|
|
|
/* The symbol tables are set up in read_type_unit_scope. */
|
|
process_die (cu->dies, cu);
|
|
|
|
/* For now fudge the Go package. */
|
|
if (cu->lang () == language_go)
|
|
fixup_go_packaging (cu);
|
|
|
|
/* Now that we have processed all the DIEs in the CU, all the types
|
|
should be complete, and it should now be safe to compute all of the
|
|
physnames. */
|
|
compute_delayed_physnames (cu);
|
|
|
|
if (cu->lang () == language_rust)
|
|
rust_union_quirks (cu);
|
|
|
|
/* TUs share symbol tables.
|
|
If this is the first TU to use this symtab, complete the construction
|
|
of it with end_expandable_symtab. Otherwise, complete the addition of
|
|
this TU's symbols to the existing symtab. */
|
|
type_unit_group_unshareable *tug_unshare =
|
|
per_objfile->get_type_unit_group_unshareable (sig_type->type_unit_group);
|
|
if (tug_unshare->compunit_symtab == NULL)
|
|
{
|
|
buildsym_compunit *builder = cu->get_builder ();
|
|
cust = builder->end_expandable_symtab (0);
|
|
tug_unshare->compunit_symtab = cust;
|
|
|
|
if (cust != NULL)
|
|
{
|
|
/* Set symtab language to language from DW_AT_language. If the
|
|
compilation is from a C file generated by language preprocessors,
|
|
do not set the language if it was already deduced by
|
|
start_subfile. */
|
|
if (!(cu->lang () == language_c
|
|
&& cust->primary_filetab ()->language () != language_c))
|
|
cust->primary_filetab ()->set_language (cu->lang ());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cu->get_builder ()->augment_type_symtab ();
|
|
cust = tug_unshare->compunit_symtab;
|
|
}
|
|
|
|
per_objfile->set_symtab (cu->per_cu, cust);
|
|
|
|
/* Not needed any more. */
|
|
cu->reset_builder ();
|
|
}
|
|
|
|
/* Process an imported unit DIE. */
|
|
|
|
static void
|
|
process_imported_unit_die (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
/* For now we don't handle imported units in type units. */
|
|
if (cu->per_cu->is_debug_types)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"DW_TAG_imported_unit is not supported in type units"
|
|
" [in module %s]"),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_import, cu);
|
|
if (attr != NULL)
|
|
{
|
|
sect_offset sect_off = attr->get_ref_die_offset ();
|
|
bool is_dwz = (attr->form == DW_FORM_GNU_ref_alt || cu->per_cu->is_dwz);
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
dwarf2_per_cu_data *per_cu
|
|
= dwarf2_find_containing_comp_unit (sect_off, is_dwz,
|
|
per_objfile->per_bfd);
|
|
|
|
/* We're importing a C++ compilation unit with tag DW_TAG_compile_unit
|
|
into another compilation unit, at root level. Regard this as a hint,
|
|
and ignore it. This is a best effort, it only works if unit_type and
|
|
lang are already set. */
|
|
if (die->parent && die->parent->parent == NULL
|
|
&& per_cu->unit_type (false) == DW_UT_compile
|
|
&& is_cplus_dialect (per_cu->lang (false)))
|
|
return;
|
|
|
|
/* If necessary, add it to the queue and load its DIEs. */
|
|
if (maybe_queue_comp_unit (cu, per_cu, per_objfile,
|
|
cu->lang ()))
|
|
load_full_comp_unit (per_cu, per_objfile, per_objfile->get_cu (per_cu),
|
|
false, cu->lang ());
|
|
|
|
cu->per_cu->imported_symtabs.push_back (per_cu);
|
|
}
|
|
}
|
|
|
|
/* RAII object that represents a process_die scope: i.e.,
|
|
starts/finishes processing a DIE. */
|
|
class process_die_scope
|
|
{
|
|
public:
|
|
process_die_scope (die_info *die, dwarf2_cu *cu)
|
|
: m_die (die), m_cu (cu)
|
|
{
|
|
/* We should only be processing DIEs not already in process. */
|
|
gdb_assert (!m_die->in_process);
|
|
m_die->in_process = true;
|
|
}
|
|
|
|
~process_die_scope ()
|
|
{
|
|
m_die->in_process = false;
|
|
|
|
/* If we're done processing the DIE for the CU that owns the line
|
|
header, we don't need the line header anymore. */
|
|
if (m_cu->line_header_die_owner == m_die)
|
|
{
|
|
delete m_cu->line_header;
|
|
m_cu->line_header = NULL;
|
|
m_cu->line_header_die_owner = NULL;
|
|
}
|
|
}
|
|
|
|
private:
|
|
die_info *m_die;
|
|
dwarf2_cu *m_cu;
|
|
};
|
|
|
|
/* Process a die and its children. */
|
|
|
|
static void
|
|
process_die (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
process_die_scope scope (die, cu);
|
|
|
|
switch (die->tag)
|
|
{
|
|
case DW_TAG_padding:
|
|
break;
|
|
case DW_TAG_compile_unit:
|
|
case DW_TAG_partial_unit:
|
|
read_file_scope (die, cu);
|
|
break;
|
|
case DW_TAG_type_unit:
|
|
read_type_unit_scope (die, cu);
|
|
break;
|
|
case DW_TAG_subprogram:
|
|
/* Nested subprograms in Fortran get a prefix. */
|
|
if (cu->lang () == language_fortran
|
|
&& die->parent != NULL
|
|
&& die->parent->tag == DW_TAG_subprogram)
|
|
cu->processing_has_namespace_info = true;
|
|
[[fallthrough]];
|
|
/* Fall through. */
|
|
case DW_TAG_entry_point:
|
|
case DW_TAG_inlined_subroutine:
|
|
read_func_scope (die, cu);
|
|
break;
|
|
case DW_TAG_lexical_block:
|
|
case DW_TAG_try_block:
|
|
case DW_TAG_catch_block:
|
|
read_lexical_block_scope (die, cu);
|
|
break;
|
|
case DW_TAG_call_site:
|
|
case DW_TAG_GNU_call_site:
|
|
read_call_site_scope (die, cu);
|
|
break;
|
|
case DW_TAG_class_type:
|
|
case DW_TAG_interface_type:
|
|
case DW_TAG_structure_type:
|
|
case DW_TAG_union_type:
|
|
case DW_TAG_namelist:
|
|
process_structure_scope (die, cu);
|
|
break;
|
|
case DW_TAG_enumeration_type:
|
|
process_enumeration_scope (die, cu);
|
|
break;
|
|
|
|
/* These dies have a type, but processing them does not create
|
|
a symbol or recurse to process the children. Therefore we can
|
|
read them on-demand through read_type_die. */
|
|
case DW_TAG_subroutine_type:
|
|
case DW_TAG_set_type:
|
|
case DW_TAG_pointer_type:
|
|
case DW_TAG_ptr_to_member_type:
|
|
case DW_TAG_reference_type:
|
|
case DW_TAG_rvalue_reference_type:
|
|
case DW_TAG_string_type:
|
|
break;
|
|
|
|
case DW_TAG_array_type:
|
|
/* We only need to handle this case for Ada -- in other
|
|
languages, it's normal for the compiler to emit a typedef
|
|
instead. */
|
|
if (cu->lang () != language_ada)
|
|
break;
|
|
[[fallthrough]];
|
|
case DW_TAG_base_type:
|
|
case DW_TAG_subrange_type:
|
|
case DW_TAG_generic_subrange:
|
|
case DW_TAG_typedef:
|
|
case DW_TAG_unspecified_type:
|
|
/* Add a typedef symbol for the type definition, if it has a
|
|
DW_AT_name. */
|
|
new_symbol (die, read_type_die (die, cu), cu);
|
|
break;
|
|
case DW_TAG_common_block:
|
|
read_common_block (die, cu);
|
|
break;
|
|
case DW_TAG_common_inclusion:
|
|
break;
|
|
case DW_TAG_namespace:
|
|
cu->processing_has_namespace_info = true;
|
|
read_namespace (die, cu);
|
|
break;
|
|
case DW_TAG_module:
|
|
cu->processing_has_namespace_info = true;
|
|
read_module (die, cu);
|
|
break;
|
|
case DW_TAG_imported_declaration:
|
|
cu->processing_has_namespace_info = true;
|
|
if (read_alias (die, cu))
|
|
break;
|
|
/* The declaration is neither a global namespace nor a variable
|
|
alias. */
|
|
[[fallthrough]];
|
|
case DW_TAG_imported_module:
|
|
cu->processing_has_namespace_info = true;
|
|
if (die->child != NULL && (die->tag == DW_TAG_imported_declaration
|
|
|| cu->lang () != language_fortran))
|
|
complaint (_("Tag '%s' has unexpected children"),
|
|
dwarf_tag_name (die->tag));
|
|
read_import_statement (die, cu);
|
|
break;
|
|
|
|
case DW_TAG_imported_unit:
|
|
process_imported_unit_die (die, cu);
|
|
break;
|
|
|
|
case DW_TAG_variable:
|
|
read_variable (die, cu);
|
|
break;
|
|
|
|
default:
|
|
new_symbol (die, NULL, cu);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* DWARF name computation. */
|
|
|
|
/* A helper function for dwarf2_compute_name which determines whether DIE
|
|
needs to have the name of the scope prepended to the name listed in the
|
|
die. */
|
|
|
|
static int
|
|
die_needs_namespace (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
switch (die->tag)
|
|
{
|
|
case DW_TAG_namespace:
|
|
case DW_TAG_typedef:
|
|
case DW_TAG_class_type:
|
|
case DW_TAG_interface_type:
|
|
case DW_TAG_structure_type:
|
|
case DW_TAG_union_type:
|
|
case DW_TAG_enumeration_type:
|
|
case DW_TAG_enumerator:
|
|
case DW_TAG_subprogram:
|
|
case DW_TAG_inlined_subroutine:
|
|
case DW_TAG_entry_point:
|
|
case DW_TAG_member:
|
|
case DW_TAG_imported_declaration:
|
|
return 1;
|
|
|
|
case DW_TAG_variable:
|
|
case DW_TAG_constant:
|
|
/* We only need to prefix "globally" visible variables. These include
|
|
any variable marked with DW_AT_external or any variable that
|
|
lives in a namespace. [Variables in anonymous namespaces
|
|
require prefixing, but they are not DW_AT_external.] */
|
|
|
|
if (dwarf2_attr (die, DW_AT_specification, cu))
|
|
{
|
|
struct dwarf2_cu *spec_cu = cu;
|
|
|
|
return die_needs_namespace (die_specification (die, &spec_cu),
|
|
spec_cu);
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_external, cu);
|
|
if (attr == NULL && die->parent->tag != DW_TAG_namespace
|
|
&& die->parent->tag != DW_TAG_module)
|
|
return 0;
|
|
/* A variable in a lexical block of some kind does not need a
|
|
namespace, even though in C++ such variables may be external
|
|
and have a mangled name. */
|
|
if (die->parent->tag == DW_TAG_lexical_block
|
|
|| die->parent->tag == DW_TAG_try_block
|
|
|| die->parent->tag == DW_TAG_catch_block
|
|
|| die->parent->tag == DW_TAG_subprogram)
|
|
return 0;
|
|
return 1;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Return the DIE's linkage name attribute, either DW_AT_linkage_name
|
|
or DW_AT_MIPS_linkage_name. Returns NULL if the attribute is not
|
|
defined for the given DIE. */
|
|
|
|
static struct attribute *
|
|
dw2_linkage_name_attr (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_linkage_name, cu);
|
|
if (attr == NULL)
|
|
attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu);
|
|
|
|
return attr;
|
|
}
|
|
|
|
/* Return the DIE's linkage name as a string, either DW_AT_linkage_name
|
|
or DW_AT_MIPS_linkage_name. Returns NULL if the attribute is not
|
|
defined for the given DIE. */
|
|
|
|
static const char *
|
|
dw2_linkage_name (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
const char *linkage_name;
|
|
|
|
linkage_name = dwarf2_string_attr (die, DW_AT_linkage_name, cu);
|
|
if (linkage_name == NULL)
|
|
linkage_name = dwarf2_string_attr (die, DW_AT_MIPS_linkage_name, cu);
|
|
|
|
/* rustc emits invalid values for DW_AT_linkage_name. Ignore these.
|
|
See https://github.com/rust-lang/rust/issues/32925. */
|
|
if (cu->lang () == language_rust && linkage_name != NULL
|
|
&& strchr (linkage_name, '{') != NULL)
|
|
linkage_name = NULL;
|
|
|
|
if (linkage_name != nullptr)
|
|
{
|
|
linkage_name = gdb_hip_test_mode_frob_names (cu->per_objfile->objfile,
|
|
linkage_name);
|
|
}
|
|
|
|
return linkage_name;
|
|
}
|
|
|
|
/* Compute the fully qualified name of DIE in CU. If PHYSNAME is nonzero,
|
|
compute the physname for the object, which include a method's:
|
|
- formal parameters (C++),
|
|
- receiver type (Go),
|
|
|
|
The term "physname" is a bit confusing.
|
|
For C++, for example, it is the demangled name.
|
|
For Go, for example, it's the mangled name.
|
|
|
|
For Ada, return the DIE's linkage name rather than the fully qualified
|
|
name. PHYSNAME is ignored..
|
|
|
|
The result is allocated on the objfile->per_bfd's obstack and
|
|
canonicalized. */
|
|
|
|
static const char *
|
|
dwarf2_compute_name (const char *name,
|
|
struct die_info *die, struct dwarf2_cu *cu,
|
|
int physname)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
|
|
if (name == NULL)
|
|
name = dwarf2_name (die, cu);
|
|
|
|
enum language lang = cu->lang ();
|
|
|
|
/* For Fortran GDB prefers DW_AT_*linkage_name for the physname if present
|
|
but otherwise compute it by typename_concat inside GDB.
|
|
FIXME: Actually this is not really true, or at least not always true.
|
|
It's all very confusing. compute_and_set_names doesn't try to demangle
|
|
Fortran names because there is no mangling standard. So new_symbol
|
|
will set the demangled name to the result of dwarf2_full_name, and it is
|
|
the demangled name that GDB uses if it exists. */
|
|
if (lang == language_ada
|
|
|| (lang == language_fortran && physname))
|
|
{
|
|
/* For Ada unit, we prefer the linkage name over the name, as
|
|
the former contains the exported name, which the user expects
|
|
to be able to reference. Ideally, we want the user to be able
|
|
to reference this entity using either natural or linkage name,
|
|
but we haven't started looking at this enhancement yet. */
|
|
const char *linkage_name = dw2_linkage_name (die, cu);
|
|
|
|
if (linkage_name != NULL)
|
|
return linkage_name;
|
|
}
|
|
|
|
/* These are the only languages we know how to qualify names in. */
|
|
if (name != NULL
|
|
&& (is_cplus_dialect (lang)
|
|
|| lang == language_fortran || lang == language_d
|
|
|| lang == language_rust))
|
|
{
|
|
if (die_needs_namespace (die, cu))
|
|
{
|
|
const char *prefix;
|
|
|
|
string_file buf;
|
|
|
|
prefix = determine_prefix (die, cu);
|
|
if (*prefix != '\0')
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> prefixed_name
|
|
= typename_concat (prefix, name, physname, cu);
|
|
|
|
buf.puts (prefixed_name.get ());
|
|
}
|
|
else
|
|
buf.puts (name);
|
|
|
|
/* Template parameters may be specified in the DIE's DW_AT_name, or
|
|
as children with DW_TAG_template_type_param or
|
|
DW_TAG_value_type_param. If the latter, add them to the name
|
|
here. If the name already has template parameters, then
|
|
skip this step; some versions of GCC emit both, and
|
|
it is more efficient to use the pre-computed name.
|
|
|
|
Something to keep in mind about this process: it is very
|
|
unlikely, or in some cases downright impossible, to produce
|
|
something that will match the mangled name of a function.
|
|
If the definition of the function has the same debug info,
|
|
we should be able to match up with it anyway. But fallbacks
|
|
using the minimal symbol, for instance to find a method
|
|
implemented in a stripped copy of libstdc++, will not work.
|
|
If we do not have debug info for the definition, we will have to
|
|
match them up some other way.
|
|
|
|
When we do name matching there is a related problem with function
|
|
templates; two instantiated function templates are allowed to
|
|
differ only by their return types, which we do not add here. */
|
|
|
|
if (is_cplus_dialect (lang) && strchr (name, '<') == NULL)
|
|
{
|
|
struct attribute *attr;
|
|
struct die_info *child;
|
|
int first = 1;
|
|
|
|
die->building_fullname = 1;
|
|
|
|
for (child = die->child; child != NULL; child = child->sibling)
|
|
{
|
|
struct type *type;
|
|
LONGEST value;
|
|
const gdb_byte *bytes;
|
|
struct dwarf2_locexpr_baton *baton;
|
|
struct value *v;
|
|
|
|
if (child->tag != DW_TAG_template_type_param
|
|
&& child->tag != DW_TAG_template_value_param)
|
|
continue;
|
|
|
|
if (first)
|
|
{
|
|
buf.puts ("<");
|
|
first = 0;
|
|
}
|
|
else
|
|
buf.puts (", ");
|
|
|
|
attr = dwarf2_attr (child, DW_AT_type, cu);
|
|
if (attr == NULL)
|
|
{
|
|
complaint (_("template parameter missing DW_AT_type"));
|
|
buf.puts ("UNKNOWN_TYPE");
|
|
continue;
|
|
}
|
|
type = die_type (child, cu);
|
|
|
|
if (child->tag == DW_TAG_template_type_param)
|
|
{
|
|
cu->language_defn->print_type (type, "", &buf, -1, 0,
|
|
&type_print_raw_options);
|
|
continue;
|
|
}
|
|
|
|
attr = dwarf2_attr (child, DW_AT_const_value, cu);
|
|
if (attr == NULL)
|
|
{
|
|
complaint (_("template parameter missing "
|
|
"DW_AT_const_value"));
|
|
buf.puts ("UNKNOWN_VALUE");
|
|
continue;
|
|
}
|
|
|
|
dwarf2_const_value_attr (attr, type, name,
|
|
&cu->comp_unit_obstack, cu,
|
|
&value, &bytes, &baton);
|
|
|
|
if (type->has_no_signedness ())
|
|
/* GDB prints characters as NUMBER 'CHAR'. If that's
|
|
changed, this can use value_print instead. */
|
|
cu->language_defn->printchar (value, type, &buf);
|
|
else
|
|
{
|
|
struct value_print_options opts;
|
|
|
|
if (baton != NULL)
|
|
v = dwarf2_evaluate_loc_desc (type, NULL,
|
|
baton->data,
|
|
baton->size,
|
|
baton->per_cu,
|
|
baton->per_objfile);
|
|
else if (bytes != NULL)
|
|
{
|
|
v = value::allocate (type);
|
|
memcpy (v->contents_writeable ().data (), bytes,
|
|
type->length ());
|
|
}
|
|
else
|
|
v = value_from_longest (type, value);
|
|
|
|
/* Specify decimal so that we do not depend on
|
|
the radix. */
|
|
get_formatted_print_options (&opts, 'd');
|
|
opts.raw = true;
|
|
value_print (v, &buf, &opts);
|
|
release_value (v);
|
|
}
|
|
}
|
|
|
|
die->building_fullname = 0;
|
|
|
|
if (!first)
|
|
{
|
|
/* Close the argument list, with a space if necessary
|
|
(nested templates). */
|
|
if (!buf.empty () && buf.string ().back () == '>')
|
|
buf.puts (" >");
|
|
else
|
|
buf.puts (">");
|
|
}
|
|
}
|
|
|
|
/* For C++ methods, append formal parameter type
|
|
information, if PHYSNAME. */
|
|
|
|
if (physname && die->tag == DW_TAG_subprogram
|
|
&& is_cplus_dialect (lang))
|
|
{
|
|
struct type *type = read_type_die (die, cu);
|
|
|
|
c_type_print_args (type, &buf, 1, lang,
|
|
&type_print_raw_options);
|
|
|
|
if (is_cplus_dialect (lang))
|
|
{
|
|
/* Assume that an artificial first parameter is
|
|
"this", but do not crash if it is not. RealView
|
|
marks unnamed (and thus unused) parameters as
|
|
artificial; there is no way to differentiate
|
|
the two cases. */
|
|
if (type->num_fields () > 0
|
|
&& type->field (0).is_artificial ()
|
|
&& type->field (0).type ()->code () == TYPE_CODE_PTR
|
|
&& TYPE_CONST (type->field (0).type ()->target_type ()))
|
|
buf.puts (" const");
|
|
}
|
|
}
|
|
|
|
const std::string &intermediate_name = buf.string ();
|
|
|
|
const char *canonical_name
|
|
= dwarf2_canonicalize_name (intermediate_name.c_str (), cu,
|
|
objfile);
|
|
|
|
/* If we only computed INTERMEDIATE_NAME, or if
|
|
INTERMEDIATE_NAME is already canonical, then we need to
|
|
intern it. */
|
|
if (canonical_name == NULL || canonical_name == intermediate_name.c_str ())
|
|
name = objfile->intern (intermediate_name);
|
|
else
|
|
name = canonical_name;
|
|
}
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
/* Return the fully qualified name of DIE, based on its DW_AT_name.
|
|
If scope qualifiers are appropriate they will be added. The result
|
|
will be allocated on the storage_obstack, or NULL if the DIE does
|
|
not have a name. NAME may either be from a previous call to
|
|
dwarf2_name or NULL.
|
|
|
|
The output string will be canonicalized (if C++). */
|
|
|
|
static const char *
|
|
dwarf2_full_name (const char *name, struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
return dwarf2_compute_name (name, die, cu, 0);
|
|
}
|
|
|
|
/* Construct a physname for the given DIE in CU. NAME may either be
|
|
from a previous call to dwarf2_name or NULL. The result will be
|
|
allocated on the objfile_obstack or NULL if the DIE does not have a
|
|
name.
|
|
|
|
The output string will be canonicalized (if C++). */
|
|
|
|
static const char *
|
|
dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
const char *retval, *mangled = NULL, *canon = NULL;
|
|
int need_copy = 1;
|
|
|
|
/* In this case dwarf2_compute_name is just a shortcut not building anything
|
|
on its own. */
|
|
if (!die_needs_namespace (die, cu))
|
|
return dwarf2_compute_name (name, die, cu, 1);
|
|
|
|
if (cu->lang () != language_rust)
|
|
mangled = dw2_linkage_name (die, cu);
|
|
|
|
/* DW_AT_linkage_name is missing in some cases - depend on what GDB
|
|
has computed. */
|
|
gdb::unique_xmalloc_ptr<char> demangled;
|
|
if (mangled != NULL)
|
|
{
|
|
if (cu->language_defn->store_sym_names_in_linkage_form_p ())
|
|
{
|
|
/* Do nothing (do not demangle the symbol name). */
|
|
}
|
|
else
|
|
{
|
|
/* Use DMGL_RET_DROP for C++ template functions to suppress
|
|
their return type. It is easier for GDB users to search
|
|
for such functions as `name(params)' than `long name(params)'.
|
|
In such case the minimal symbol names do not match the full
|
|
symbol names but for template functions there is never a need
|
|
to look up their definition from their declaration so
|
|
the only disadvantage remains the minimal symbol variant
|
|
`long name(params)' does not have the proper inferior type. */
|
|
demangled = gdb_demangle (mangled, (DMGL_PARAMS | DMGL_ANSI
|
|
| DMGL_RET_DROP));
|
|
}
|
|
if (demangled)
|
|
canon = demangled.get ();
|
|
else
|
|
{
|
|
canon = mangled;
|
|
need_copy = 0;
|
|
}
|
|
}
|
|
|
|
if (canon == NULL || check_physname)
|
|
{
|
|
const char *physname = dwarf2_compute_name (name, die, cu, 1);
|
|
|
|
if (canon != NULL && strcmp (physname, canon) != 0)
|
|
{
|
|
/* It may not mean a bug in GDB. The compiler could also
|
|
compute DW_AT_linkage_name incorrectly. But in such case
|
|
GDB would need to be bug-to-bug compatible. */
|
|
|
|
complaint (_("Computed physname <%s> does not match demangled <%s> "
|
|
"(from linkage <%s>) - DIE at %s [in module %s]"),
|
|
physname, canon, mangled, sect_offset_str (die->sect_off),
|
|
objfile_name (objfile));
|
|
|
|
/* Prefer DW_AT_linkage_name (in the CANON form) - when it
|
|
is available here - over computed PHYSNAME. It is safer
|
|
against both buggy GDB and buggy compilers. */
|
|
|
|
retval = canon;
|
|
}
|
|
else
|
|
{
|
|
retval = physname;
|
|
need_copy = 0;
|
|
}
|
|
}
|
|
else
|
|
retval = canon;
|
|
|
|
if (need_copy)
|
|
retval = objfile->intern (retval);
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* Inspect DIE in CU for a namespace alias or a variable with alias
|
|
attribute. If one exists, record a new symbol for it.
|
|
|
|
Returns true if an alias was recorded, false otherwise. */
|
|
|
|
static bool
|
|
read_alias (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
/* If the die does not have a name, this is neither a namespace
|
|
alias nor a variable alias. */
|
|
attr = dwarf2_attr (die, DW_AT_name, cu);
|
|
if (attr != NULL)
|
|
{
|
|
int num;
|
|
struct die_info *d = die;
|
|
struct dwarf2_cu *imported_cu = cu;
|
|
|
|
/* If the compiler has nested DW_AT_imported_declaration DIEs,
|
|
keep inspecting DIEs until we hit the underlying import. */
|
|
#define MAX_NESTED_IMPORTED_DECLARATIONS 100
|
|
for (num = 0; num < MAX_NESTED_IMPORTED_DECLARATIONS; ++num)
|
|
{
|
|
attr = dwarf2_attr (d, DW_AT_import, cu);
|
|
if (attr == NULL)
|
|
break;
|
|
|
|
d = follow_die_ref (d, attr, &imported_cu);
|
|
if (d->tag != DW_TAG_imported_declaration)
|
|
break;
|
|
}
|
|
|
|
if (num == MAX_NESTED_IMPORTED_DECLARATIONS)
|
|
{
|
|
complaint (_("DIE at %s has too many recursively imported "
|
|
"declarations"), sect_offset_str (d->sect_off));
|
|
return false;
|
|
}
|
|
|
|
if (attr != NULL)
|
|
{
|
|
struct type *type;
|
|
if (d->tag == DW_TAG_variable)
|
|
{
|
|
/* This declaration is a C/C++ global variable alias.
|
|
Add a symbol for it whose type is the same as the
|
|
aliased variable's. */
|
|
type = die_type (d, imported_cu);
|
|
struct symbol *sym = new_symbol (die, type, cu);
|
|
attr = dwarf2_attr (d, DW_AT_location, imported_cu);
|
|
sym->set_aclass_index (LOC_UNRESOLVED);
|
|
if (attr != nullptr)
|
|
var_decode_location (attr, sym, cu);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
sect_offset sect_off = attr->get_ref_die_offset ();
|
|
type = get_die_type_at_offset (sect_off, cu->per_cu,
|
|
cu->per_objfile);
|
|
if (type != nullptr && type->code () == TYPE_CODE_NAMESPACE)
|
|
{
|
|
/* This declaration is a global namespace alias. Add
|
|
a symbol for it whose type is the aliased
|
|
namespace. */
|
|
new_symbol (die, type, cu);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Return the using directives repository (global or local?) to use in the
|
|
current context for CU.
|
|
|
|
For Ada, imported declarations can materialize renamings, which *may* be
|
|
global. However it is impossible (for now?) in DWARF to distinguish
|
|
"external" imported declarations and "static" ones. As all imported
|
|
declarations seem to be static in all other languages, make them all CU-wide
|
|
global only in Ada. */
|
|
|
|
static struct using_direct **
|
|
using_directives (struct dwarf2_cu *cu)
|
|
{
|
|
if (cu->lang () == language_ada
|
|
&& cu->get_builder ()->outermost_context_p ())
|
|
return cu->get_builder ()->get_global_using_directives ();
|
|
else
|
|
return cu->get_builder ()->get_local_using_directives ();
|
|
}
|
|
|
|
/* Read the DW_ATTR_decl_line attribute for the given DIE in the
|
|
given CU. If the format is not recognized or the attribute is
|
|
not present, set it to 0. */
|
|
|
|
static unsigned int
|
|
read_decl_line (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *decl_line = dwarf2_attr (die, DW_AT_decl_line, cu);
|
|
if (decl_line == nullptr)
|
|
return 0;
|
|
if (decl_line->form_is_constant ())
|
|
{
|
|
LONGEST val = decl_line->constant_value (0);
|
|
if (0 <= val && val <= UINT_MAX)
|
|
return (unsigned int) val;
|
|
|
|
complaint (_("Declared line for using directive is too large"));
|
|
return 0;
|
|
}
|
|
|
|
complaint (_("Declared line for using directive is of incorrect format"));
|
|
return 0;
|
|
}
|
|
|
|
/* Read the import statement specified by the given die and record it. */
|
|
|
|
static void
|
|
read_import_statement (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct attribute *import_attr;
|
|
struct die_info *imported_die, *child_die;
|
|
struct dwarf2_cu *imported_cu;
|
|
const char *imported_name;
|
|
const char *imported_name_prefix;
|
|
const char *canonical_name;
|
|
const char *import_alias;
|
|
const char *imported_declaration = NULL;
|
|
const char *import_prefix;
|
|
std::vector<const char *> excludes;
|
|
|
|
import_attr = dwarf2_attr (die, DW_AT_import, cu);
|
|
if (import_attr == NULL)
|
|
{
|
|
complaint (_("Tag '%s' has no DW_AT_import"),
|
|
dwarf_tag_name (die->tag));
|
|
return;
|
|
}
|
|
|
|
imported_cu = cu;
|
|
imported_die = follow_die_ref_or_sig (die, import_attr, &imported_cu);
|
|
imported_name = dwarf2_name (imported_die, imported_cu);
|
|
if (imported_name == NULL)
|
|
{
|
|
/* GCC bug: https://bugzilla.redhat.com/show_bug.cgi?id=506524
|
|
|
|
The import in the following code:
|
|
namespace A
|
|
{
|
|
typedef int B;
|
|
}
|
|
|
|
int main ()
|
|
{
|
|
using A::B;
|
|
B b;
|
|
return b;
|
|
}
|
|
|
|
...
|
|
<2><51>: Abbrev Number: 3 (DW_TAG_imported_declaration)
|
|
<52> DW_AT_decl_file : 1
|
|
<53> DW_AT_decl_line : 6
|
|
<54> DW_AT_import : <0x75>
|
|
<2><58>: Abbrev Number: 4 (DW_TAG_typedef)
|
|
<59> DW_AT_name : B
|
|
<5b> DW_AT_decl_file : 1
|
|
<5c> DW_AT_decl_line : 2
|
|
<5d> DW_AT_type : <0x6e>
|
|
...
|
|
<1><75>: Abbrev Number: 7 (DW_TAG_base_type)
|
|
<76> DW_AT_byte_size : 4
|
|
<77> DW_AT_encoding : 5 (signed)
|
|
|
|
imports the wrong die ( 0x75 instead of 0x58 ).
|
|
This case will be ignored until the gcc bug is fixed. */
|
|
return;
|
|
}
|
|
|
|
/* Figure out the local name after import. */
|
|
import_alias = dwarf2_name (die, cu);
|
|
|
|
/* Figure out where the statement is being imported to. */
|
|
import_prefix = determine_prefix (die, cu);
|
|
|
|
/* Figure out what the scope of the imported die is and prepend it
|
|
to the name of the imported die. */
|
|
imported_name_prefix = determine_prefix (imported_die, imported_cu);
|
|
|
|
if (imported_die->tag != DW_TAG_namespace
|
|
&& imported_die->tag != DW_TAG_module)
|
|
{
|
|
imported_declaration = imported_name;
|
|
canonical_name = imported_name_prefix;
|
|
}
|
|
else if (strlen (imported_name_prefix) > 0)
|
|
canonical_name = obconcat (&objfile->objfile_obstack,
|
|
imported_name_prefix,
|
|
(cu->lang () == language_d
|
|
? "."
|
|
: "::"),
|
|
imported_name, (char *) NULL);
|
|
else
|
|
canonical_name = imported_name;
|
|
|
|
if (die->tag == DW_TAG_imported_module
|
|
&& cu->lang () == language_fortran)
|
|
for (child_die = die->child; child_die && child_die->tag;
|
|
child_die = child_die->sibling)
|
|
{
|
|
/* DWARF-4: A Fortran use statement with a “rename list” may be
|
|
represented by an imported module entry with an import attribute
|
|
referring to the module and owned entries corresponding to those
|
|
entities that are renamed as part of being imported. */
|
|
|
|
if (child_die->tag != DW_TAG_imported_declaration)
|
|
{
|
|
complaint (_("child DW_TAG_imported_declaration expected "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (child_die->sect_off),
|
|
objfile_name (objfile));
|
|
continue;
|
|
}
|
|
|
|
import_attr = dwarf2_attr (child_die, DW_AT_import, cu);
|
|
if (import_attr == NULL)
|
|
{
|
|
complaint (_("Tag '%s' has no DW_AT_import"),
|
|
dwarf_tag_name (child_die->tag));
|
|
continue;
|
|
}
|
|
|
|
imported_cu = cu;
|
|
imported_die = follow_die_ref_or_sig (child_die, import_attr,
|
|
&imported_cu);
|
|
imported_name = dwarf2_name (imported_die, imported_cu);
|
|
if (imported_name == NULL)
|
|
{
|
|
complaint (_("child DW_TAG_imported_declaration has unknown "
|
|
"imported name - DIE at %s [in module %s]"),
|
|
sect_offset_str (child_die->sect_off),
|
|
objfile_name (objfile));
|
|
continue;
|
|
}
|
|
|
|
excludes.push_back (imported_name);
|
|
|
|
process_die (child_die, cu);
|
|
}
|
|
|
|
add_using_directive (using_directives (cu),
|
|
import_prefix,
|
|
canonical_name,
|
|
import_alias,
|
|
imported_declaration,
|
|
excludes,
|
|
read_decl_line (die, cu),
|
|
&objfile->objfile_obstack);
|
|
}
|
|
|
|
/* ICC<14 does not output the required DW_AT_declaration on incomplete
|
|
types, but gives them a size of zero. Starting with version 14,
|
|
ICC is compatible with GCC. */
|
|
|
|
static bool
|
|
producer_is_icc_lt_14 (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_icc_lt_14;
|
|
}
|
|
|
|
/* ICC generates a DW_AT_type for C void functions. This was observed on
|
|
ICC 14.0.5.212, and appears to be against the DWARF spec (V5 3.3.2)
|
|
which says that void functions should not have a DW_AT_type. */
|
|
|
|
static bool
|
|
producer_is_icc (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_icc;
|
|
}
|
|
|
|
/* Check for possibly missing DW_AT_comp_dir with relative .debug_line
|
|
directory paths. GCC SVN r127613 (new option -fdebug-prefix-map) fixed
|
|
this, it was first present in GCC release 4.3.0. */
|
|
|
|
static bool
|
|
producer_is_gcc_lt_4_3 (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_gcc_lt_4_3;
|
|
}
|
|
|
|
/* See dwarf2/read.h. */
|
|
bool
|
|
producer_is_clang (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_clang;
|
|
}
|
|
|
|
static file_and_directory &
|
|
find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
if (cu->per_cu->fnd != nullptr)
|
|
return *cu->per_cu->fnd;
|
|
|
|
/* Find the filename. Do not use dwarf2_name here, since the filename
|
|
is not a source language identifier. */
|
|
file_and_directory res (dwarf2_string_attr (die, DW_AT_name, cu),
|
|
dwarf2_string_attr (die, DW_AT_comp_dir, cu));
|
|
|
|
if (res.get_comp_dir () == nullptr
|
|
&& producer_is_gcc_lt_4_3 (cu)
|
|
&& res.get_name () != nullptr
|
|
&& IS_ABSOLUTE_PATH (res.get_name ()))
|
|
{
|
|
res.set_comp_dir (ldirname (res.get_name ()));
|
|
res.set_name (make_unique_xstrdup (lbasename (res.get_name ())));
|
|
}
|
|
|
|
cu->per_cu->fnd = std::make_unique<file_and_directory> (std::move (res));
|
|
return *cu->per_cu->fnd;
|
|
}
|
|
|
|
/* Handle DW_AT_stmt_list for a compilation unit.
|
|
DIE is the DW_TAG_compile_unit die for CU.
|
|
COMP_DIR is the compilation directory. LOWPC is passed to
|
|
dwarf_decode_lines. See dwarf_decode_lines comments about it. */
|
|
|
|
static void
|
|
handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu,
|
|
const file_and_directory &fnd, unrelocated_addr lowpc,
|
|
bool have_code) /* ARI: editCase function */
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct attribute *attr;
|
|
hashval_t line_header_local_hash;
|
|
void **slot;
|
|
int decode_mapping;
|
|
|
|
gdb_assert (! cu->per_cu->is_debug_types);
|
|
|
|
attr = dwarf2_attr (die, DW_AT_stmt_list, cu);
|
|
if (attr == NULL || !attr->form_is_unsigned ())
|
|
return;
|
|
|
|
sect_offset line_offset = (sect_offset) attr->as_unsigned ();
|
|
|
|
/* The line header hash table is only created if needed (it exists to
|
|
prevent redundant reading of the line table for partial_units).
|
|
If we're given a partial_unit, we'll need it. If we're given a
|
|
compile_unit, then use the line header hash table if it's already
|
|
created, but don't create one just yet. */
|
|
|
|
if (per_objfile->line_header_hash == NULL
|
|
&& die->tag == DW_TAG_partial_unit)
|
|
{
|
|
per_objfile->line_header_hash
|
|
.reset (htab_create_alloc (127, line_header_hash_voidp,
|
|
line_header_eq_voidp,
|
|
htab_delete_entry<line_header>,
|
|
xcalloc, xfree));
|
|
}
|
|
|
|
line_header line_header_local (line_offset, cu->per_cu->is_dwz);
|
|
line_header_local_hash = line_header_hash (&line_header_local);
|
|
if (per_objfile->line_header_hash != NULL)
|
|
{
|
|
slot = htab_find_slot_with_hash (per_objfile->line_header_hash.get (),
|
|
&line_header_local,
|
|
line_header_local_hash, NO_INSERT);
|
|
|
|
/* For DW_TAG_compile_unit we need info like symtab::linetable which
|
|
is not present in *SLOT (since if there is something in *SLOT then
|
|
it will be for a partial_unit). */
|
|
if (die->tag == DW_TAG_partial_unit && slot != NULL)
|
|
{
|
|
gdb_assert (*slot != NULL);
|
|
cu->line_header = (struct line_header *) *slot;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* dwarf_decode_line_header does not yet provide sufficient information.
|
|
We always have to call also dwarf_decode_lines for it. */
|
|
line_header_up lh = dwarf_decode_line_header (line_offset, cu,
|
|
fnd.get_comp_dir ());
|
|
if (lh == NULL)
|
|
return;
|
|
|
|
cu->line_header = lh.release ();
|
|
cu->line_header_die_owner = die;
|
|
|
|
if (per_objfile->line_header_hash == NULL)
|
|
slot = NULL;
|
|
else
|
|
{
|
|
slot = htab_find_slot_with_hash (per_objfile->line_header_hash.get (),
|
|
&line_header_local,
|
|
line_header_local_hash, INSERT);
|
|
gdb_assert (slot != NULL);
|
|
}
|
|
if (slot != NULL && *slot == NULL)
|
|
{
|
|
/* This newly decoded line number information unit will be owned
|
|
by line_header_hash hash table. */
|
|
*slot = cu->line_header;
|
|
cu->line_header_die_owner = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* We cannot free any current entry in (*slot) as that struct line_header
|
|
may be already used by multiple CUs. Create only temporary decoded
|
|
line_header for this CU - it may happen at most once for each line
|
|
number information unit. And if we're not using line_header_hash
|
|
then this is what we want as well. */
|
|
gdb_assert (die->tag != DW_TAG_partial_unit);
|
|
}
|
|
decode_mapping = (die->tag != DW_TAG_partial_unit);
|
|
/* The have_code check is here because, if LOWPC and HIGHPC are both 0x0,
|
|
then there won't be any interesting code in the CU, but a check later on
|
|
(in lnp_state_machine::check_line_address) will fail to properly exclude
|
|
an entry that was removed via --gc-sections. */
|
|
dwarf_decode_lines (cu->line_header, cu, lowpc, decode_mapping && have_code);
|
|
}
|
|
|
|
/* Process DW_TAG_compile_unit or DW_TAG_partial_unit. */
|
|
|
|
static void
|
|
read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
CORE_ADDR lowpc;
|
|
struct attribute *attr;
|
|
struct die_info *child_die;
|
|
|
|
prepare_one_comp_unit (cu, die, cu->lang ());
|
|
|
|
unrelocated_addr unrel_low, unrel_high;
|
|
get_scope_pc_bounds (die, &unrel_low, &unrel_high, cu);
|
|
|
|
/* If we didn't find a lowpc, set it to highpc to avoid complaints
|
|
from finish_block. */
|
|
if (unrel_low == ((unrelocated_addr) -1))
|
|
unrel_low = unrel_high;
|
|
lowpc = per_objfile->relocate (unrel_low);
|
|
|
|
file_and_directory &fnd = find_file_and_directory (die, cu);
|
|
|
|
/* GAS supports generating dwarf-5 info starting version 2.35. Versions
|
|
2.35-2.37 generate an incorrect CU name attribute: it's relative,
|
|
implicitly prefixing it with the compilation dir. Work around this by
|
|
prefixing it with the source dir instead. */
|
|
if (cu->header.version == 5 && !IS_ABSOLUTE_PATH (fnd.get_name ())
|
|
&& producer_is_gas_lt_2_38 (cu))
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_stmt_list, cu);
|
|
if (attr != nullptr && attr->form_is_unsigned ())
|
|
{
|
|
sect_offset line_offset = (sect_offset) attr->as_unsigned ();
|
|
line_header_up lh = dwarf_decode_line_header (line_offset, cu,
|
|
fnd.get_comp_dir ());
|
|
if (lh->version == 5 && lh->is_valid_file_index (1))
|
|
{
|
|
std::string dir = lh->include_dir_at (1);
|
|
fnd.set_comp_dir (std::move (dir));
|
|
}
|
|
}
|
|
}
|
|
|
|
cu->start_compunit_symtab (fnd.get_name (), fnd.intern_comp_dir (objfile),
|
|
lowpc);
|
|
|
|
gdb_assert (per_objfile->sym_cu == nullptr);
|
|
scoped_restore restore_sym_cu
|
|
= make_scoped_restore (&per_objfile->sym_cu, cu);
|
|
|
|
/* Decode line number information if present. We do this before
|
|
processing child DIEs, so that the line header table is available
|
|
for DW_AT_decl_file. */
|
|
handle_DW_AT_stmt_list (die, cu, fnd, unrel_low, unrel_low != unrel_high);
|
|
|
|
/* Process all dies in compilation unit. */
|
|
if (die->child != NULL)
|
|
{
|
|
child_die = die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
process_die (child_die, cu);
|
|
child_die = child_die->sibling;
|
|
}
|
|
}
|
|
per_objfile->sym_cu = nullptr;
|
|
|
|
/* Decode macro information, if present. Dwarf 2 macro information
|
|
refers to information in the line number info statement program
|
|
header, so we can only read it if we've read the header
|
|
successfully. */
|
|
attr = dwarf2_attr (die, DW_AT_macros, cu);
|
|
if (attr == NULL)
|
|
attr = dwarf2_attr (die, DW_AT_GNU_macros, cu);
|
|
if (attr != nullptr && attr->form_is_unsigned () && cu->line_header)
|
|
{
|
|
if (dwarf2_attr (die, DW_AT_macro_info, cu))
|
|
complaint (_("CU refers to both DW_AT_macros and DW_AT_macro_info"));
|
|
|
|
dwarf_decode_macros (cu, attr->as_unsigned (), 1);
|
|
}
|
|
else
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_macro_info, cu);
|
|
if (attr != nullptr && attr->form_is_unsigned () && cu->line_header)
|
|
{
|
|
unsigned int macro_offset = attr->as_unsigned ();
|
|
|
|
dwarf_decode_macros (cu, macro_offset, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
dwarf2_cu::setup_type_unit_groups (struct die_info *die)
|
|
{
|
|
struct type_unit_group *tu_group;
|
|
int first_time;
|
|
struct attribute *attr;
|
|
unsigned int i;
|
|
struct signatured_type *sig_type;
|
|
|
|
gdb_assert (per_cu->is_debug_types);
|
|
sig_type = (struct signatured_type *) per_cu;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_stmt_list, this);
|
|
|
|
/* If we're using .gdb_index (includes -readnow) then
|
|
per_cu->type_unit_group may not have been set up yet. */
|
|
if (sig_type->type_unit_group == NULL)
|
|
sig_type->type_unit_group = get_type_unit_group (this, attr);
|
|
tu_group = sig_type->type_unit_group;
|
|
|
|
/* If we've already processed this stmt_list there's no real need to
|
|
do it again, we could fake it and just recreate the part we need
|
|
(file name,index -> symtab mapping). If data shows this optimization
|
|
is useful we can do it then. */
|
|
type_unit_group_unshareable *tug_unshare
|
|
= per_objfile->get_type_unit_group_unshareable (tu_group);
|
|
first_time = tug_unshare->compunit_symtab == NULL;
|
|
|
|
/* We have to handle the case of both a missing DW_AT_stmt_list or bad
|
|
debug info. */
|
|
line_header_up lh;
|
|
if (attr != NULL && attr->form_is_unsigned ())
|
|
{
|
|
sect_offset line_offset = (sect_offset) attr->as_unsigned ();
|
|
lh = dwarf_decode_line_header (line_offset, this, nullptr);
|
|
}
|
|
if (lh == NULL)
|
|
{
|
|
if (first_time)
|
|
start_compunit_symtab ("", NULL, 0);
|
|
else
|
|
{
|
|
gdb_assert (tug_unshare->symtabs == NULL);
|
|
gdb_assert (m_builder == nullptr);
|
|
struct compunit_symtab *cust = tug_unshare->compunit_symtab;
|
|
m_builder = std::make_unique<buildsym_compunit>
|
|
(cust->objfile (), "",
|
|
cust->dirname (),
|
|
cust->language (),
|
|
0, cust);
|
|
list_in_scope = get_builder ()->get_file_symbols ();
|
|
}
|
|
return;
|
|
}
|
|
|
|
line_header = lh.release ();
|
|
line_header_die_owner = die;
|
|
|
|
if (first_time)
|
|
{
|
|
struct compunit_symtab *cust = start_compunit_symtab ("", NULL, 0);
|
|
|
|
/* Note: We don't assign tu_group->compunit_symtab yet because we're
|
|
still initializing it, and our caller (a few levels up)
|
|
process_full_type_unit still needs to know if this is the first
|
|
time. */
|
|
|
|
tug_unshare->symtabs
|
|
= XOBNEWVEC (&cust->objfile ()->objfile_obstack,
|
|
struct symtab *, line_header->file_names_size ());
|
|
|
|
auto &file_names = line_header->file_names ();
|
|
for (i = 0; i < file_names.size (); ++i)
|
|
{
|
|
file_entry &fe = file_names[i];
|
|
dwarf2_start_subfile (this, fe, *line_header);
|
|
buildsym_compunit *b = get_builder ();
|
|
subfile *sf = b->get_current_subfile ();
|
|
|
|
if (sf->symtab == nullptr)
|
|
{
|
|
/* NOTE: start_subfile will recognize when it's been
|
|
passed a file it has already seen. So we can't
|
|
assume there's a simple mapping from
|
|
cu->line_header->file_names to subfiles, plus
|
|
cu->line_header->file_names may contain dups. */
|
|
const char *name = sf->name.c_str ();
|
|
const char *name_for_id = sf->name_for_id.c_str ();
|
|
sf->symtab = allocate_symtab (cust, name, name_for_id);
|
|
}
|
|
|
|
fe.symtab = b->get_current_subfile ()->symtab;
|
|
tug_unshare->symtabs[i] = fe.symtab;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gdb_assert (m_builder == nullptr);
|
|
struct compunit_symtab *cust = tug_unshare->compunit_symtab;
|
|
m_builder = std::make_unique<buildsym_compunit>
|
|
(cust->objfile (), "",
|
|
cust->dirname (),
|
|
cust->language (),
|
|
0, cust);
|
|
list_in_scope = get_builder ()->get_file_symbols ();
|
|
|
|
auto &file_names = line_header->file_names ();
|
|
for (i = 0; i < file_names.size (); ++i)
|
|
{
|
|
file_entry &fe = file_names[i];
|
|
fe.symtab = tug_unshare->symtabs[i];
|
|
}
|
|
}
|
|
|
|
/* The main symtab is allocated last. Type units don't have DW_AT_name
|
|
so they don't have a "real" (so to speak) symtab anyway.
|
|
There is later code that will assign the main symtab to all symbols
|
|
that don't have one. We need to handle the case of a symbol with a
|
|
missing symtab (DW_AT_decl_file) anyway. */
|
|
}
|
|
|
|
/* Process DW_TAG_type_unit.
|
|
For TUs we want to skip the first top level sibling if it's not the
|
|
actual type being defined by this TU. In this case the first top
|
|
level sibling is there to provide context only. */
|
|
|
|
static void
|
|
read_type_unit_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct die_info *child_die;
|
|
|
|
prepare_one_comp_unit (cu, die, language_minimal);
|
|
|
|
/* Initialize (or reinitialize) the machinery for building symtabs.
|
|
We do this before processing child DIEs, so that the line header table
|
|
is available for DW_AT_decl_file. */
|
|
cu->setup_type_unit_groups (die);
|
|
|
|
if (die->child != NULL)
|
|
{
|
|
child_die = die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
process_die (child_die, cu);
|
|
child_die = child_die->sibling;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* DWO/DWP files.
|
|
|
|
http://gcc.gnu.org/wiki/DebugFission
|
|
http://gcc.gnu.org/wiki/DebugFissionDWP
|
|
|
|
To simplify handling of both DWO files ("object" files with the DWARF info)
|
|
and DWP files (a file with the DWOs packaged up into one file), we treat
|
|
DWP files as having a collection of virtual DWO files. */
|
|
|
|
/* A helper function to hash two file names. This is a separate
|
|
function because the hash table uses a search with a different
|
|
type. The second file may be NULL. */
|
|
|
|
static hashval_t
|
|
hash_two_files (const char *one, const char *two)
|
|
{
|
|
hashval_t hash = htab_hash_string (one);
|
|
if (two != nullptr)
|
|
hash += htab_hash_string (two);
|
|
return hash;
|
|
}
|
|
|
|
static hashval_t
|
|
hash_dwo_file (const void *item)
|
|
{
|
|
const struct dwo_file *dwo_file = (const struct dwo_file *) item;
|
|
return hash_two_files (dwo_file->dwo_name.c_str (), dwo_file->comp_dir);
|
|
}
|
|
|
|
/* This is used when looking up entries in the DWO hash table. */
|
|
|
|
struct dwo_file_search
|
|
{
|
|
/* Name of the DWO to look for. */
|
|
const char *dwo_name;
|
|
/* Compilation directory to look for. */
|
|
const char *comp_dir;
|
|
|
|
/* Return a hash value compatible with the table. */
|
|
hashval_t hash () const
|
|
{
|
|
return hash_two_files (dwo_name, comp_dir);
|
|
}
|
|
};
|
|
|
|
static int
|
|
eq_dwo_file (const void *item_lhs, const void *item_rhs)
|
|
{
|
|
const struct dwo_file *lhs = (const struct dwo_file *) item_lhs;
|
|
const struct dwo_file_search *rhs
|
|
= (const struct dwo_file_search *) item_rhs;
|
|
|
|
if (lhs->dwo_name != rhs->dwo_name)
|
|
return 0;
|
|
if (lhs->comp_dir == NULL || rhs->comp_dir == NULL)
|
|
return lhs->comp_dir == rhs->comp_dir;
|
|
return strcmp (lhs->comp_dir, rhs->comp_dir) == 0;
|
|
}
|
|
|
|
/* Allocate a hash table for DWO files. */
|
|
|
|
static htab_up
|
|
allocate_dwo_file_hash_table ()
|
|
{
|
|
return htab_up (htab_create_alloc (41,
|
|
hash_dwo_file,
|
|
eq_dwo_file,
|
|
htab_delete_entry<dwo_file>,
|
|
xcalloc, xfree));
|
|
}
|
|
|
|
/* Lookup DWO file DWO_NAME. */
|
|
|
|
static void **
|
|
lookup_dwo_file_slot (dwarf2_per_objfile *per_objfile,
|
|
const char *dwo_name,
|
|
const char *comp_dir)
|
|
{
|
|
struct dwo_file_search find_entry;
|
|
void **slot;
|
|
|
|
if (per_objfile->per_bfd->dwo_files == NULL)
|
|
per_objfile->per_bfd->dwo_files = allocate_dwo_file_hash_table ();
|
|
|
|
find_entry.dwo_name = dwo_name;
|
|
find_entry.comp_dir = comp_dir;
|
|
slot = htab_find_slot_with_hash (per_objfile->per_bfd->dwo_files.get (),
|
|
&find_entry, find_entry.hash (),
|
|
INSERT);
|
|
|
|
return slot;
|
|
}
|
|
|
|
static hashval_t
|
|
hash_dwo_unit (const void *item)
|
|
{
|
|
const struct dwo_unit *dwo_unit = (const struct dwo_unit *) item;
|
|
|
|
/* This drops the top 32 bits of the id, but is ok for a hash. */
|
|
return dwo_unit->signature;
|
|
}
|
|
|
|
static int
|
|
eq_dwo_unit (const void *item_lhs, const void *item_rhs)
|
|
{
|
|
const struct dwo_unit *lhs = (const struct dwo_unit *) item_lhs;
|
|
const struct dwo_unit *rhs = (const struct dwo_unit *) item_rhs;
|
|
|
|
/* The signature is assumed to be unique within the DWO file.
|
|
So while object file CU dwo_id's always have the value zero,
|
|
that's OK, assuming each object file DWO file has only one CU,
|
|
and that's the rule for now. */
|
|
return lhs->signature == rhs->signature;
|
|
}
|
|
|
|
/* Allocate a hash table for DWO CUs,TUs.
|
|
There is one of these tables for each of CUs,TUs for each DWO file. */
|
|
|
|
static htab_up
|
|
allocate_dwo_unit_table ()
|
|
{
|
|
/* Start out with a pretty small number.
|
|
Generally DWO files contain only one CU and maybe some TUs. */
|
|
return htab_up (htab_create_alloc (3,
|
|
hash_dwo_unit,
|
|
eq_dwo_unit,
|
|
NULL, xcalloc, xfree));
|
|
}
|
|
|
|
/* die_reader_func for create_dwo_cu. */
|
|
|
|
static void
|
|
create_dwo_cu_reader (const struct die_reader_specs *reader,
|
|
const gdb_byte *info_ptr,
|
|
struct die_info *comp_unit_die,
|
|
struct dwo_file *dwo_file,
|
|
struct dwo_unit *dwo_unit)
|
|
{
|
|
struct dwarf2_cu *cu = reader->cu;
|
|
sect_offset sect_off = cu->per_cu->sect_off;
|
|
struct dwarf2_section_info *section = cu->per_cu->section;
|
|
|
|
std::optional<ULONGEST> signature = lookup_dwo_id (cu, comp_unit_die);
|
|
if (!signature.has_value ())
|
|
{
|
|
complaint (_(DWARF_ERROR_PREFIX
|
|
"debug entry at offset %s is missing its dwo_id"
|
|
" [in module %s]"),
|
|
sect_offset_str (sect_off), dwo_file->dwo_name.c_str ());
|
|
return;
|
|
}
|
|
|
|
dwo_unit->dwo_file = dwo_file;
|
|
dwo_unit->signature = *signature;
|
|
dwo_unit->section = section;
|
|
dwo_unit->sect_off = sect_off;
|
|
dwo_unit->length = cu->per_cu->length ();
|
|
|
|
dwarf_read_debug_printf (" offset %s, dwo_id %s",
|
|
sect_offset_str (sect_off),
|
|
hex_string (dwo_unit->signature));
|
|
}
|
|
|
|
/* Create the dwo_units for the CUs in a DWO_FILE.
|
|
Note: This function processes DWO files only, not DWP files. */
|
|
|
|
static void
|
|
create_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file,
|
|
dwarf2_section_info §ion)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
|
const gdb_byte *info_ptr, *end_ptr;
|
|
|
|
section.read (objfile);
|
|
info_ptr = section.buffer;
|
|
|
|
if (info_ptr == NULL)
|
|
return;
|
|
|
|
dwarf_read_debug_printf ("Reading %s for %s:",
|
|
section.get_name (),
|
|
section.get_file_name ());
|
|
|
|
end_ptr = info_ptr + section.size;
|
|
while (info_ptr < end_ptr)
|
|
{
|
|
struct dwo_unit read_unit {};
|
|
struct dwo_unit *dwo_unit;
|
|
void **slot;
|
|
sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
|
|
|
|
if (cu->header.version < 5)
|
|
{
|
|
struct dwarf2_per_cu_data per_cu;
|
|
per_cu.per_bfd = per_bfd;
|
|
per_cu.is_debug_types = 0;
|
|
per_cu.sect_off = sect_offset (info_ptr - section.buffer);
|
|
per_cu.section = §ion;
|
|
|
|
cutu_reader reader (&per_cu, per_objfile, cu, &dwo_file);
|
|
if (!reader.dummy_p)
|
|
create_dwo_cu_reader (&reader, reader.info_ptr,
|
|
reader.comp_unit_die, &dwo_file, &read_unit);
|
|
info_ptr += per_cu.length ();
|
|
|
|
/* If the unit could not be parsed, skip it. */
|
|
if (read_unit.dwo_file == NULL)
|
|
continue;
|
|
|
|
/* DWARF 5 .debug_info.dwo sections may contain some type units. Skip
|
|
everything that is not a compile unit. */
|
|
if (const auto ut = reader.cu->header.unit_type;
|
|
ut != DW_UT_compile && ut != DW_UT_split_compile)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
comp_unit_head header;
|
|
dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
|
|
const gdb_byte *info_ptr_post_header
|
|
= read_and_check_comp_unit_head (cu->per_objfile, &header,
|
|
§ion, abbrev_section,
|
|
info_ptr, rcuh_kind::COMPILE);
|
|
|
|
unsigned int length = header.get_length_with_initial ();
|
|
info_ptr += length;
|
|
|
|
/* Skip dummy units. */
|
|
if (info_ptr_post_header >= info_ptr
|
|
|| peek_abbrev_code (section.get_bfd_owner (),
|
|
info_ptr_post_header)
|
|
== 0)
|
|
continue;
|
|
|
|
/* DWARF 5 .debug_info.dwo sections may contain some type units. Skip
|
|
everything that is not a compile unit. */
|
|
if (header.unit_type != DW_UT_split_compile)
|
|
continue;
|
|
|
|
read_unit.dwo_file = &dwo_file;
|
|
read_unit.signature = header.signature;
|
|
read_unit.section = §ion;
|
|
read_unit.sect_off = sect_off;
|
|
read_unit.length = cu->per_cu->length ();
|
|
}
|
|
|
|
if (dwo_file.cus == nullptr)
|
|
dwo_file.cus = allocate_dwo_unit_table ();
|
|
|
|
dwo_unit = OBSTACK_ZALLOC (&per_bfd->obstack,
|
|
struct dwo_unit);
|
|
*dwo_unit = read_unit;
|
|
slot = htab_find_slot (dwo_file.cus.get (), dwo_unit, INSERT);
|
|
gdb_assert (slot != NULL);
|
|
if (*slot != NULL)
|
|
{
|
|
const struct dwo_unit *dup_cu = (const struct dwo_unit *)*slot;
|
|
sect_offset dup_sect_off = dup_cu->sect_off;
|
|
|
|
complaint (_("debug cu entry at offset %s is duplicate to"
|
|
" the entry at offset %s, signature %s"),
|
|
sect_offset_str (sect_off), sect_offset_str (dup_sect_off),
|
|
hex_string (dwo_unit->signature));
|
|
}
|
|
*slot = (void *)dwo_unit;
|
|
}
|
|
}
|
|
|
|
/* DWP file .debug_{cu,tu}_index section format:
|
|
[ref: http://gcc.gnu.org/wiki/DebugFissionDWP]
|
|
[ref: http://dwarfstd.org/doc/DWARF5.pdf, sect 7.3.5 "DWARF Package Files"]
|
|
|
|
DWP Versions 1 & 2 are older, pre-standard format versions. The first
|
|
officially standard DWP format was published with DWARF v5 and is called
|
|
Version 5. There are no versions 3 or 4.
|
|
|
|
DWP Version 1:
|
|
|
|
Both index sections have the same format, and serve to map a 64-bit
|
|
signature to a set of section numbers. Each section begins with a header,
|
|
followed by a hash table of 64-bit signatures, a parallel table of 32-bit
|
|
indexes, and a pool of 32-bit section numbers. The index sections will be
|
|
aligned at 8-byte boundaries in the file.
|
|
|
|
The index section header consists of:
|
|
|
|
V, 32 bit version number
|
|
-, 32 bits unused
|
|
N, 32 bit number of compilation units or type units in the index
|
|
M, 32 bit number of slots in the hash table
|
|
|
|
Numbers are recorded using the byte order of the application binary.
|
|
|
|
The hash table begins at offset 16 in the section, and consists of an array
|
|
of M 64-bit slots. Each slot contains a 64-bit signature (using the byte
|
|
order of the application binary). Unused slots in the hash table are 0.
|
|
(We rely on the extreme unlikeliness of a signature being exactly 0.)
|
|
|
|
The parallel table begins immediately after the hash table
|
|
(at offset 16 + 8 * M from the beginning of the section), and consists of an
|
|
array of 32-bit indexes (using the byte order of the application binary),
|
|
corresponding 1-1 with slots in the hash table. Each entry in the parallel
|
|
table contains a 32-bit index into the pool of section numbers. For unused
|
|
hash table slots, the corresponding entry in the parallel table will be 0.
|
|
|
|
The pool of section numbers begins immediately following the hash table
|
|
(at offset 16 + 12 * M from the beginning of the section). The pool of
|
|
section numbers consists of an array of 32-bit words (using the byte order
|
|
of the application binary). Each item in the array is indexed starting
|
|
from 0. The hash table entry provides the index of the first section
|
|
number in the set. Additional section numbers in the set follow, and the
|
|
set is terminated by a 0 entry (section number 0 is not used in ELF).
|
|
|
|
In each set of section numbers, the .debug_info.dwo or .debug_types.dwo
|
|
section must be the first entry in the set, and the .debug_abbrev.dwo must
|
|
be the second entry. Other members of the set may follow in any order.
|
|
|
|
---
|
|
|
|
DWP Versions 2 and 5:
|
|
|
|
DWP Versions 2 and 5 combine all the .debug_info, etc. sections into one,
|
|
and the entries in the index tables are now offsets into these sections.
|
|
CU offsets begin at 0. TU offsets begin at the size of the .debug_info
|
|
section.
|
|
|
|
Index Section Contents:
|
|
Header
|
|
Hash Table of Signatures dwp_hash_table.hash_table
|
|
Parallel Table of Indices dwp_hash_table.unit_table
|
|
Table of Section Offsets dwp_hash_table.{v2|v5}.{section_ids,offsets}
|
|
Table of Section Sizes dwp_hash_table.{v2|v5}.sizes
|
|
|
|
The index section header consists of:
|
|
|
|
V, 32 bit version number
|
|
L, 32 bit number of columns in the table of section offsets
|
|
N, 32 bit number of compilation units or type units in the index
|
|
M, 32 bit number of slots in the hash table
|
|
|
|
Numbers are recorded using the byte order of the application binary.
|
|
|
|
The hash table has the same format as version 1.
|
|
The parallel table of indices has the same format as version 1,
|
|
except that the entries are origin-1 indices into the table of sections
|
|
offsets and the table of section sizes.
|
|
|
|
The table of offsets begins immediately following the parallel table
|
|
(at offset 16 + 12 * M from the beginning of the section). The table is
|
|
a two-dimensional array of 32-bit words (using the byte order of the
|
|
application binary), with L columns and N+1 rows, in row-major order.
|
|
Each row in the array is indexed starting from 0. The first row provides
|
|
a key to the remaining rows: each column in this row provides an identifier
|
|
for a debug section, and the offsets in the same column of subsequent rows
|
|
refer to that section. The section identifiers for Version 2 are:
|
|
|
|
DW_SECT_INFO 1 .debug_info.dwo
|
|
DW_SECT_TYPES 2 .debug_types.dwo
|
|
DW_SECT_ABBREV 3 .debug_abbrev.dwo
|
|
DW_SECT_LINE 4 .debug_line.dwo
|
|
DW_SECT_LOC 5 .debug_loc.dwo
|
|
DW_SECT_STR_OFFSETS 6 .debug_str_offsets.dwo
|
|
DW_SECT_MACINFO 7 .debug_macinfo.dwo
|
|
DW_SECT_MACRO 8 .debug_macro.dwo
|
|
|
|
The section identifiers for Version 5 are:
|
|
|
|
DW_SECT_INFO_V5 1 .debug_info.dwo
|
|
DW_SECT_RESERVED_V5 2 --
|
|
DW_SECT_ABBREV_V5 3 .debug_abbrev.dwo
|
|
DW_SECT_LINE_V5 4 .debug_line.dwo
|
|
DW_SECT_LOCLISTS_V5 5 .debug_loclists.dwo
|
|
DW_SECT_STR_OFFSETS_V5 6 .debug_str_offsets.dwo
|
|
DW_SECT_MACRO_V5 7 .debug_macro.dwo
|
|
DW_SECT_RNGLISTS_V5 8 .debug_rnglists.dwo
|
|
|
|
The offsets provided by the CU and TU index sections are the base offsets
|
|
for the contributions made by each CU or TU to the corresponding section
|
|
in the package file. Each CU and TU header contains an abbrev_offset
|
|
field, used to find the abbreviations table for that CU or TU within the
|
|
contribution to the .debug_abbrev.dwo section for that CU or TU, and should
|
|
be interpreted as relative to the base offset given in the index section.
|
|
Likewise, offsets into .debug_line.dwo from DW_AT_stmt_list attributes
|
|
should be interpreted as relative to the base offset for .debug_line.dwo,
|
|
and offsets into other debug sections obtained from DWARF attributes should
|
|
also be interpreted as relative to the corresponding base offset.
|
|
|
|
The table of sizes begins immediately following the table of offsets.
|
|
Like the table of offsets, it is a two-dimensional array of 32-bit words,
|
|
with L columns and N rows, in row-major order. Each row in the array is
|
|
indexed starting from 1 (row 0 is shared by the two tables).
|
|
|
|
---
|
|
|
|
Hash table lookup is handled the same in version 1 and 2:
|
|
|
|
We assume that N and M will not exceed 2^32 - 1.
|
|
The size of the hash table, M, must be 2^k such that 2^k > 3*N/2.
|
|
|
|
Given a 64-bit compilation unit signature or a type signature S, an entry
|
|
in the hash table is located as follows:
|
|
|
|
1) Calculate a primary hash H = S & MASK(k), where MASK(k) is a mask with
|
|
the low-order k bits all set to 1.
|
|
|
|
2) Calculate a secondary hash H' = (((S >> 32) & MASK(k)) | 1).
|
|
|
|
3) If the hash table entry at index H matches the signature, use that
|
|
entry. If the hash table entry at index H is unused (all zeroes),
|
|
terminate the search: the signature is not present in the table.
|
|
|
|
4) Let H = (H + H') modulo M. Repeat at Step 3.
|
|
|
|
Because M > N and H' and M are relatively prime, the search is guaranteed
|
|
to stop at an unused slot or find the match. */
|
|
|
|
/* Create a hash table to map DWO IDs to their CU/TU entry in
|
|
.debug_{info,types}.dwo in DWP_FILE.
|
|
Returns NULL if there isn't one.
|
|
Note: This function processes DWP files only, not DWO files. */
|
|
|
|
static struct dwp_hash_table *
|
|
create_dwp_hash_table (dwarf2_per_objfile *per_objfile,
|
|
struct dwp_file *dwp_file, int is_debug_types)
|
|
{
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
bfd *dbfd = dwp_file->dbfd.get ();
|
|
const gdb_byte *index_ptr, *index_end;
|
|
struct dwarf2_section_info *index;
|
|
uint32_t version, nr_columns, nr_units, nr_slots;
|
|
struct dwp_hash_table *htab;
|
|
|
|
if (is_debug_types)
|
|
index = &dwp_file->sections.tu_index;
|
|
else
|
|
index = &dwp_file->sections.cu_index;
|
|
|
|
if (index->empty ())
|
|
return NULL;
|
|
index->read (objfile);
|
|
|
|
index_ptr = index->buffer;
|
|
index_end = index_ptr + index->size;
|
|
|
|
/* For Version 5, the version is really 2 bytes of data & 2 bytes of padding.
|
|
For now it's safe to just read 4 bytes (particularly as it's difficult to
|
|
tell if you're dealing with Version 5 before you've read the version). */
|
|
version = read_4_bytes (dbfd, index_ptr);
|
|
index_ptr += 4;
|
|
if (version == 2 || version == 5)
|
|
nr_columns = read_4_bytes (dbfd, index_ptr);
|
|
else
|
|
nr_columns = 0;
|
|
index_ptr += 4;
|
|
nr_units = read_4_bytes (dbfd, index_ptr);
|
|
index_ptr += 4;
|
|
nr_slots = read_4_bytes (dbfd, index_ptr);
|
|
index_ptr += 4;
|
|
|
|
if (version != 1 && version != 2 && version != 5)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"unsupported DWP file version (%s) [in module %s]"),
|
|
pulongest (version), dwp_file->name);
|
|
}
|
|
if (nr_slots != (nr_slots & -nr_slots))
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"number of slots in DWP hash table (%s) is not power of 2"
|
|
" [in module %s]"),
|
|
pulongest (nr_slots), dwp_file->name);
|
|
}
|
|
|
|
htab = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, struct dwp_hash_table);
|
|
htab->version = version;
|
|
htab->nr_columns = nr_columns;
|
|
htab->nr_units = nr_units;
|
|
htab->nr_slots = nr_slots;
|
|
htab->hash_table = index_ptr;
|
|
htab->unit_table = htab->hash_table + sizeof (uint64_t) * nr_slots;
|
|
|
|
/* Exit early if the table is empty. */
|
|
if (nr_slots == 0 || nr_units == 0
|
|
|| (version == 2 && nr_columns == 0)
|
|
|| (version == 5 && nr_columns == 0))
|
|
{
|
|
/* All must be zero. */
|
|
if (nr_slots != 0 || nr_units != 0
|
|
|| (version == 2 && nr_columns != 0)
|
|
|| (version == 5 && nr_columns != 0))
|
|
{
|
|
complaint (_("Empty DWP but nr_slots,nr_units,nr_columns not"
|
|
" all zero [in modules %s]"),
|
|
dwp_file->name);
|
|
}
|
|
return htab;
|
|
}
|
|
|
|
if (version == 1)
|
|
{
|
|
htab->section_pool.v1.indices =
|
|
htab->unit_table + sizeof (uint32_t) * nr_slots;
|
|
/* It's harder to decide whether the section is too small in v1.
|
|
V1 is deprecated anyway so we punt. */
|
|
}
|
|
else if (version == 2)
|
|
{
|
|
const gdb_byte *ids_ptr = htab->unit_table + sizeof (uint32_t) * nr_slots;
|
|
int *ids = htab->section_pool.v2.section_ids;
|
|
size_t sizeof_ids = sizeof (htab->section_pool.v2.section_ids);
|
|
/* Reverse map for error checking. */
|
|
int ids_seen[DW_SECT_MAX + 1];
|
|
int i;
|
|
|
|
if (nr_columns < 2)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, too few columns in section table"
|
|
" [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
if (nr_columns > MAX_NR_V2_DWO_SECTIONS)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, too many columns in section table"
|
|
" [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
memset (ids, 255, sizeof_ids);
|
|
memset (ids_seen, 255, sizeof (ids_seen));
|
|
for (i = 0; i < nr_columns; ++i)
|
|
{
|
|
int id = read_4_bytes (dbfd, ids_ptr + i * sizeof (uint32_t));
|
|
|
|
if (id < DW_SECT_MIN || id > DW_SECT_MAX)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, bad section id %d in section table"
|
|
" [in module %s]"),
|
|
id, dwp_file->name);
|
|
}
|
|
if (ids_seen[id] != -1)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, duplicate section"
|
|
" id %d in section table [in module %s]"),
|
|
id, dwp_file->name);
|
|
}
|
|
ids_seen[id] = i;
|
|
ids[i] = id;
|
|
}
|
|
/* Must have exactly one info or types section. */
|
|
if (((ids_seen[DW_SECT_INFO] != -1)
|
|
+ (ids_seen[DW_SECT_TYPES] != -1))
|
|
!= 1)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, missing/duplicate"
|
|
" DWO info/types section [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
/* Must have an abbrev section. */
|
|
if (ids_seen[DW_SECT_ABBREV] == -1)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, missing DWO abbrev section"
|
|
" [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
htab->section_pool.v2.offsets = ids_ptr + sizeof (uint32_t) * nr_columns;
|
|
htab->section_pool.v2.sizes =
|
|
htab->section_pool.v2.offsets + (sizeof (uint32_t)
|
|
* nr_units * nr_columns);
|
|
if ((htab->section_pool.v2.sizes + (sizeof (uint32_t)
|
|
* nr_units * nr_columns))
|
|
> index_end)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"DWP index section is corrupt (too small) [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
}
|
|
else /* version == 5 */
|
|
{
|
|
const gdb_byte *ids_ptr = htab->unit_table + sizeof (uint32_t) * nr_slots;
|
|
int *ids = htab->section_pool.v5.section_ids;
|
|
size_t sizeof_ids = sizeof (htab->section_pool.v5.section_ids);
|
|
/* Reverse map for error checking. */
|
|
int ids_seen[DW_SECT_MAX_V5 + 1];
|
|
|
|
if (nr_columns < 2)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, too few columns in section table"
|
|
" [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
if (nr_columns > MAX_NR_V5_DWO_SECTIONS)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, too many columns in section table"
|
|
" [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
memset (ids, 255, sizeof_ids);
|
|
memset (ids_seen, 255, sizeof (ids_seen));
|
|
for (int i = 0; i < nr_columns; ++i)
|
|
{
|
|
int id = read_4_bytes (dbfd, ids_ptr + i * sizeof (uint32_t));
|
|
|
|
if (id < DW_SECT_MIN || id > DW_SECT_MAX_V5)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, bad section id %d in section table"
|
|
" [in module %s]"),
|
|
id, dwp_file->name);
|
|
}
|
|
if (ids_seen[id] != -1)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, duplicate section"
|
|
" id %d in section table [in module %s]"),
|
|
id, dwp_file->name);
|
|
}
|
|
ids_seen[id] = i;
|
|
ids[i] = id;
|
|
}
|
|
/* Must have seen an info section. */
|
|
if (ids_seen[DW_SECT_INFO_V5] == -1)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, missing/duplicate"
|
|
" DWO info/types section [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
/* Must have an abbrev section. */
|
|
if (ids_seen[DW_SECT_ABBREV_V5] == -1)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, missing DWO abbrev section"
|
|
" [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
htab->section_pool.v5.offsets = ids_ptr + sizeof (uint32_t) * nr_columns;
|
|
htab->section_pool.v5.sizes
|
|
= htab->section_pool.v5.offsets + (sizeof (uint32_t)
|
|
* nr_units * nr_columns);
|
|
if ((htab->section_pool.v5.sizes + (sizeof (uint32_t)
|
|
* nr_units * nr_columns))
|
|
> index_end)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"DWP index section is corrupt (too small) [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
}
|
|
|
|
return htab;
|
|
}
|
|
|
|
/* Update SECTIONS with the data from SECTP.
|
|
|
|
This function is like the other "locate" section routines, but in
|
|
this context the sections to read comes from the DWP V1 hash table,
|
|
not the full ELF section table.
|
|
|
|
The result is non-zero for success, or zero if an error was found. */
|
|
|
|
static int
|
|
locate_v1_virtual_dwo_sections (asection *sectp,
|
|
struct virtual_v1_dwo_sections *sections)
|
|
{
|
|
const struct dwop_section_names *names = &dwop_section_names;
|
|
|
|
if (names->abbrev_dwo.matches (sectp->name))
|
|
{
|
|
/* There can be only one. */
|
|
if (sections->abbrev.s.section != NULL)
|
|
return 0;
|
|
sections->abbrev.s.section = sectp;
|
|
sections->abbrev.size = bfd_section_size (sectp);
|
|
}
|
|
else if (names->info_dwo.matches (sectp->name)
|
|
|| names->types_dwo.matches (sectp->name))
|
|
{
|
|
/* There can be only one. */
|
|
if (sections->info_or_types.s.section != NULL)
|
|
return 0;
|
|
sections->info_or_types.s.section = sectp;
|
|
sections->info_or_types.size = bfd_section_size (sectp);
|
|
}
|
|
else if (names->line_dwo.matches (sectp->name))
|
|
{
|
|
/* There can be only one. */
|
|
if (sections->line.s.section != NULL)
|
|
return 0;
|
|
sections->line.s.section = sectp;
|
|
sections->line.size = bfd_section_size (sectp);
|
|
}
|
|
else if (names->loc_dwo.matches (sectp->name))
|
|
{
|
|
/* There can be only one. */
|
|
if (sections->loc.s.section != NULL)
|
|
return 0;
|
|
sections->loc.s.section = sectp;
|
|
sections->loc.size = bfd_section_size (sectp);
|
|
}
|
|
else if (names->macinfo_dwo.matches (sectp->name))
|
|
{
|
|
/* There can be only one. */
|
|
if (sections->macinfo.s.section != NULL)
|
|
return 0;
|
|
sections->macinfo.s.section = sectp;
|
|
sections->macinfo.size = bfd_section_size (sectp);
|
|
}
|
|
else if (names->macro_dwo.matches (sectp->name))
|
|
{
|
|
/* There can be only one. */
|
|
if (sections->macro.s.section != NULL)
|
|
return 0;
|
|
sections->macro.s.section = sectp;
|
|
sections->macro.size = bfd_section_size (sectp);
|
|
}
|
|
else if (names->str_offsets_dwo.matches (sectp->name))
|
|
{
|
|
/* There can be only one. */
|
|
if (sections->str_offsets.s.section != NULL)
|
|
return 0;
|
|
sections->str_offsets.s.section = sectp;
|
|
sections->str_offsets.size = bfd_section_size (sectp);
|
|
}
|
|
else
|
|
{
|
|
/* No other kind of section is valid. */
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Create a dwo_unit object for the DWO unit with signature SIGNATURE.
|
|
UNIT_INDEX is the index of the DWO unit in the DWP hash table.
|
|
COMP_DIR is the DW_AT_comp_dir attribute of the referencing CU.
|
|
This is for DWP version 1 files. */
|
|
|
|
static struct dwo_unit *
|
|
create_dwo_unit_in_dwp_v1 (dwarf2_per_objfile *per_objfile,
|
|
struct dwp_file *dwp_file,
|
|
uint32_t unit_index,
|
|
const char *comp_dir,
|
|
ULONGEST signature, int is_debug_types)
|
|
{
|
|
const struct dwp_hash_table *dwp_htab =
|
|
is_debug_types ? dwp_file->tus : dwp_file->cus;
|
|
bfd *dbfd = dwp_file->dbfd.get ();
|
|
const char *kind = is_debug_types ? "TU" : "CU";
|
|
struct dwo_file *dwo_file;
|
|
struct dwo_unit *dwo_unit;
|
|
struct virtual_v1_dwo_sections sections;
|
|
void **dwo_file_slot;
|
|
int i;
|
|
|
|
gdb_assert (dwp_file->version == 1);
|
|
|
|
dwarf_read_debug_printf ("Reading %s %s/%s in DWP V1 file: %s",
|
|
kind, pulongest (unit_index), hex_string (signature),
|
|
dwp_file->name);
|
|
|
|
/* Fetch the sections of this DWO unit.
|
|
Put a limit on the number of sections we look for so that bad data
|
|
doesn't cause us to loop forever. */
|
|
|
|
#define MAX_NR_V1_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 */ \
|
|
+ 1 /* trailing zero */)
|
|
|
|
memset (§ions, 0, sizeof (sections));
|
|
|
|
for (i = 0; i < MAX_NR_V1_DWO_SECTIONS; ++i)
|
|
{
|
|
asection *sectp;
|
|
uint32_t section_nr =
|
|
read_4_bytes (dbfd,
|
|
dwp_htab->section_pool.v1.indices
|
|
+ (unit_index + i) * sizeof (uint32_t));
|
|
|
|
if (section_nr == 0)
|
|
break;
|
|
if (section_nr >= dwp_file->num_sections)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, section number too large"
|
|
" [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
|
|
sectp = dwp_file->elf_sections[section_nr];
|
|
if (! locate_v1_virtual_dwo_sections (sectp, §ions))
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, invalid section found [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
}
|
|
|
|
if (i < 2
|
|
|| sections.info_or_types.empty ()
|
|
|| sections.abbrev.empty ())
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, missing DWO sections [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
if (i == MAX_NR_V1_DWO_SECTIONS)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, too many DWO sections [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
|
|
/* It's easier for the rest of the code if we fake a struct dwo_file and
|
|
have dwo_unit "live" in that. At least for now.
|
|
|
|
The DWP file can be made up of a random collection of CUs and TUs.
|
|
However, for each CU + set of TUs that came from the same original DWO
|
|
file, we can combine them back into a virtual DWO file to save space
|
|
(fewer struct dwo_file objects to allocate). Remember that for really
|
|
large apps there can be on the order of 8K CUs and 200K TUs, or more. */
|
|
|
|
std::string virtual_dwo_name =
|
|
string_printf ("virtual-dwo/%d-%d-%d-%d",
|
|
sections.abbrev.get_id (),
|
|
sections.line.get_id (),
|
|
sections.loc.get_id (),
|
|
sections.str_offsets.get_id ());
|
|
/* Can we use an existing virtual DWO file? */
|
|
dwo_file_slot = lookup_dwo_file_slot (per_objfile, virtual_dwo_name.c_str (),
|
|
comp_dir);
|
|
/* Create one if necessary. */
|
|
if (*dwo_file_slot == NULL)
|
|
{
|
|
dwarf_read_debug_printf ("Creating virtual DWO: %s",
|
|
virtual_dwo_name.c_str ());
|
|
|
|
dwo_file = new struct dwo_file;
|
|
dwo_file->dwo_name = std::move (virtual_dwo_name);
|
|
dwo_file->comp_dir = comp_dir;
|
|
dwo_file->sections.abbrev = sections.abbrev;
|
|
dwo_file->sections.line = sections.line;
|
|
dwo_file->sections.loc = sections.loc;
|
|
dwo_file->sections.macinfo = sections.macinfo;
|
|
dwo_file->sections.macro = sections.macro;
|
|
dwo_file->sections.str_offsets = sections.str_offsets;
|
|
/* The "str" section is global to the entire DWP file. */
|
|
dwo_file->sections.str = dwp_file->sections.str;
|
|
/* The info or types section is assigned below to dwo_unit,
|
|
there's no need to record it in dwo_file.
|
|
Also, we can't simply record type sections in dwo_file because
|
|
we record a pointer into the vector in dwo_unit. As we collect more
|
|
types we'll grow the vector and eventually have to reallocate space
|
|
for it, invalidating all copies of pointers into the previous
|
|
contents. */
|
|
*dwo_file_slot = dwo_file;
|
|
}
|
|
else
|
|
{
|
|
dwarf_read_debug_printf ("Using existing virtual DWO: %s",
|
|
virtual_dwo_name.c_str ());
|
|
|
|
dwo_file = (struct dwo_file *) *dwo_file_slot;
|
|
}
|
|
|
|
dwo_unit = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, struct dwo_unit);
|
|
dwo_unit->dwo_file = dwo_file;
|
|
dwo_unit->signature = signature;
|
|
dwo_unit->section =
|
|
XOBNEW (&per_objfile->per_bfd->obstack, struct dwarf2_section_info);
|
|
*dwo_unit->section = sections.info_or_types;
|
|
/* dwo_unit->{offset,length,type_offset_in_tu} are set later. */
|
|
|
|
return dwo_unit;
|
|
}
|
|
|
|
/* Subroutine of create_dwo_unit_in_dwp_v2 and create_dwo_unit_in_dwp_v5 to
|
|
simplify them. Given a pointer to the containing section SECTION, and
|
|
OFFSET,SIZE of the piece within that section used by a TU/CU, return a
|
|
virtual section of just that piece. */
|
|
|
|
static struct dwarf2_section_info
|
|
create_dwp_v2_or_v5_section (dwarf2_per_objfile *per_objfile,
|
|
struct dwarf2_section_info *section,
|
|
bfd_size_type offset, bfd_size_type size)
|
|
{
|
|
struct dwarf2_section_info result;
|
|
asection *sectp;
|
|
|
|
gdb_assert (section != NULL);
|
|
gdb_assert (!section->is_virtual);
|
|
|
|
memset (&result, 0, sizeof (result));
|
|
result.s.containing_section = section;
|
|
result.is_virtual = true;
|
|
|
|
if (size == 0)
|
|
return result;
|
|
|
|
sectp = section->get_bfd_section ();
|
|
|
|
/* Flag an error if the piece denoted by OFFSET,SIZE is outside the
|
|
bounds of the real section. This is a pretty-rare event, so just
|
|
flag an error (easier) instead of a warning and trying to cope. */
|
|
if (sectp == NULL
|
|
|| offset + size > bfd_section_size (sectp))
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Bad DWP V2 or V5 section info, doesn't fit in section %s"
|
|
" [in module %s]"),
|
|
sectp ? bfd_section_name (sectp) : "<unknown>",
|
|
objfile_name (per_objfile->objfile));
|
|
}
|
|
|
|
result.virtual_offset = offset;
|
|
result.size = size;
|
|
gdb_assert (section->readin);
|
|
result.readin = true;
|
|
result.buffer = section->buffer + offset;
|
|
return result;
|
|
}
|
|
|
|
/* Create a dwo_unit object for the DWO unit with signature SIGNATURE.
|
|
UNIT_INDEX is the index of the DWO unit in the DWP hash table.
|
|
COMP_DIR is the DW_AT_comp_dir attribute of the referencing CU.
|
|
This is for DWP version 2 files. */
|
|
|
|
static struct dwo_unit *
|
|
create_dwo_unit_in_dwp_v2 (dwarf2_per_objfile *per_objfile,
|
|
struct dwp_file *dwp_file,
|
|
uint32_t unit_index,
|
|
const char *comp_dir,
|
|
ULONGEST signature, int is_debug_types)
|
|
{
|
|
const struct dwp_hash_table *dwp_htab =
|
|
is_debug_types ? dwp_file->tus : dwp_file->cus;
|
|
bfd *dbfd = dwp_file->dbfd.get ();
|
|
const char *kind = is_debug_types ? "TU" : "CU";
|
|
struct dwo_file *dwo_file;
|
|
struct dwo_unit *dwo_unit;
|
|
struct virtual_v2_or_v5_dwo_sections sections;
|
|
void **dwo_file_slot;
|
|
int i;
|
|
|
|
gdb_assert (dwp_file->version == 2);
|
|
|
|
dwarf_read_debug_printf ("Reading %s %s/%s in DWP V2 file: %s",
|
|
kind, pulongest (unit_index), hex_string (signature),
|
|
dwp_file->name);
|
|
|
|
/* Fetch the section offsets of this DWO unit. */
|
|
|
|
memset (§ions, 0, sizeof (sections));
|
|
|
|
for (i = 0; i < dwp_htab->nr_columns; ++i)
|
|
{
|
|
uint32_t offset = read_4_bytes (dbfd,
|
|
dwp_htab->section_pool.v2.offsets
|
|
+ (((unit_index - 1) * dwp_htab->nr_columns
|
|
+ i)
|
|
* sizeof (uint32_t)));
|
|
uint32_t size = read_4_bytes (dbfd,
|
|
dwp_htab->section_pool.v2.sizes
|
|
+ (((unit_index - 1) * dwp_htab->nr_columns
|
|
+ i)
|
|
* sizeof (uint32_t)));
|
|
|
|
switch (dwp_htab->section_pool.v2.section_ids[i])
|
|
{
|
|
case DW_SECT_INFO:
|
|
case DW_SECT_TYPES:
|
|
sections.info_or_types_offset = offset;
|
|
sections.info_or_types_size = size;
|
|
break;
|
|
case DW_SECT_ABBREV:
|
|
sections.abbrev_offset = offset;
|
|
sections.abbrev_size = size;
|
|
break;
|
|
case DW_SECT_LINE:
|
|
sections.line_offset = offset;
|
|
sections.line_size = size;
|
|
break;
|
|
case DW_SECT_LOC:
|
|
sections.loc_offset = offset;
|
|
sections.loc_size = size;
|
|
break;
|
|
case DW_SECT_STR_OFFSETS:
|
|
sections.str_offsets_offset = offset;
|
|
sections.str_offsets_size = size;
|
|
break;
|
|
case DW_SECT_MACINFO:
|
|
sections.macinfo_offset = offset;
|
|
sections.macinfo_size = size;
|
|
break;
|
|
case DW_SECT_MACRO:
|
|
sections.macro_offset = offset;
|
|
sections.macro_size = size;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* It's easier for the rest of the code if we fake a struct dwo_file and
|
|
have dwo_unit "live" in that. At least for now.
|
|
|
|
The DWP file can be made up of a random collection of CUs and TUs.
|
|
However, for each CU + set of TUs that came from the same original DWO
|
|
file, we can combine them back into a virtual DWO file to save space
|
|
(fewer struct dwo_file objects to allocate). Remember that for really
|
|
large apps there can be on the order of 8K CUs and 200K TUs, or more. */
|
|
|
|
std::string virtual_dwo_name =
|
|
string_printf ("virtual-dwo/%ld-%ld-%ld-%ld",
|
|
(long) (sections.abbrev_size ? sections.abbrev_offset : 0),
|
|
(long) (sections.line_size ? sections.line_offset : 0),
|
|
(long) (sections.loc_size ? sections.loc_offset : 0),
|
|
(long) (sections.str_offsets_size
|
|
? sections.str_offsets_offset : 0));
|
|
/* Can we use an existing virtual DWO file? */
|
|
dwo_file_slot = lookup_dwo_file_slot (per_objfile, virtual_dwo_name.c_str (),
|
|
comp_dir);
|
|
/* Create one if necessary. */
|
|
if (*dwo_file_slot == NULL)
|
|
{
|
|
dwarf_read_debug_printf ("Creating virtual DWO: %s",
|
|
virtual_dwo_name.c_str ());
|
|
|
|
dwo_file = new struct dwo_file;
|
|
dwo_file->dwo_name = std::move (virtual_dwo_name);
|
|
dwo_file->comp_dir = comp_dir;
|
|
dwo_file->sections.abbrev =
|
|
create_dwp_v2_or_v5_section (per_objfile, &dwp_file->sections.abbrev,
|
|
sections.abbrev_offset,
|
|
sections.abbrev_size);
|
|
dwo_file->sections.line =
|
|
create_dwp_v2_or_v5_section (per_objfile, &dwp_file->sections.line,
|
|
sections.line_offset,
|
|
sections.line_size);
|
|
dwo_file->sections.loc =
|
|
create_dwp_v2_or_v5_section (per_objfile, &dwp_file->sections.loc,
|
|
sections.loc_offset, sections.loc_size);
|
|
dwo_file->sections.macinfo =
|
|
create_dwp_v2_or_v5_section (per_objfile, &dwp_file->sections.macinfo,
|
|
sections.macinfo_offset,
|
|
sections.macinfo_size);
|
|
dwo_file->sections.macro =
|
|
create_dwp_v2_or_v5_section (per_objfile, &dwp_file->sections.macro,
|
|
sections.macro_offset,
|
|
sections.macro_size);
|
|
dwo_file->sections.str_offsets =
|
|
create_dwp_v2_or_v5_section (per_objfile,
|
|
&dwp_file->sections.str_offsets,
|
|
sections.str_offsets_offset,
|
|
sections.str_offsets_size);
|
|
/* The "str" section is global to the entire DWP file. */
|
|
dwo_file->sections.str = dwp_file->sections.str;
|
|
/* The info or types section is assigned below to dwo_unit,
|
|
there's no need to record it in dwo_file.
|
|
Also, we can't simply record type sections in dwo_file because
|
|
we record a pointer into the vector in dwo_unit. As we collect more
|
|
types we'll grow the vector and eventually have to reallocate space
|
|
for it, invalidating all copies of pointers into the previous
|
|
contents. */
|
|
*dwo_file_slot = dwo_file;
|
|
}
|
|
else
|
|
{
|
|
dwarf_read_debug_printf ("Using existing virtual DWO: %s",
|
|
virtual_dwo_name.c_str ());
|
|
|
|
dwo_file = (struct dwo_file *) *dwo_file_slot;
|
|
}
|
|
|
|
dwo_unit = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, struct dwo_unit);
|
|
dwo_unit->dwo_file = dwo_file;
|
|
dwo_unit->signature = signature;
|
|
dwo_unit->section =
|
|
XOBNEW (&per_objfile->per_bfd->obstack, struct dwarf2_section_info);
|
|
*dwo_unit->section = create_dwp_v2_or_v5_section
|
|
(per_objfile,
|
|
is_debug_types
|
|
? &dwp_file->sections.types
|
|
: &dwp_file->sections.info,
|
|
sections.info_or_types_offset,
|
|
sections.info_or_types_size);
|
|
/* dwo_unit->{offset,length,type_offset_in_tu} are set later. */
|
|
|
|
return dwo_unit;
|
|
}
|
|
|
|
/* Create a dwo_unit object for the DWO unit with signature SIGNATURE.
|
|
UNIT_INDEX is the index of the DWO unit in the DWP hash table.
|
|
COMP_DIR is the DW_AT_comp_dir attribute of the referencing CU.
|
|
This is for DWP version 5 files. */
|
|
|
|
static struct dwo_unit *
|
|
create_dwo_unit_in_dwp_v5 (dwarf2_per_objfile *per_objfile,
|
|
struct dwp_file *dwp_file,
|
|
uint32_t unit_index,
|
|
const char *comp_dir,
|
|
ULONGEST signature, int is_debug_types)
|
|
{
|
|
const struct dwp_hash_table *dwp_htab
|
|
= is_debug_types ? dwp_file->tus : dwp_file->cus;
|
|
bfd *dbfd = dwp_file->dbfd.get ();
|
|
const char *kind = is_debug_types ? "TU" : "CU";
|
|
struct dwo_file *dwo_file;
|
|
struct dwo_unit *dwo_unit;
|
|
struct virtual_v2_or_v5_dwo_sections sections {};
|
|
void **dwo_file_slot;
|
|
|
|
gdb_assert (dwp_file->version == 5);
|
|
|
|
dwarf_read_debug_printf ("Reading %s %s/%s in DWP V5 file: %s",
|
|
kind, pulongest (unit_index), hex_string (signature),
|
|
dwp_file->name);
|
|
|
|
/* Fetch the section offsets of this DWO unit. */
|
|
|
|
/* memset (§ions, 0, sizeof (sections)); */
|
|
|
|
for (int i = 0; i < dwp_htab->nr_columns; ++i)
|
|
{
|
|
uint32_t offset = read_4_bytes (dbfd,
|
|
dwp_htab->section_pool.v5.offsets
|
|
+ (((unit_index - 1)
|
|
* dwp_htab->nr_columns
|
|
+ i)
|
|
* sizeof (uint32_t)));
|
|
uint32_t size = read_4_bytes (dbfd,
|
|
dwp_htab->section_pool.v5.sizes
|
|
+ (((unit_index - 1) * dwp_htab->nr_columns
|
|
+ i)
|
|
* sizeof (uint32_t)));
|
|
|
|
switch (dwp_htab->section_pool.v5.section_ids[i])
|
|
{
|
|
case DW_SECT_ABBREV_V5:
|
|
sections.abbrev_offset = offset;
|
|
sections.abbrev_size = size;
|
|
break;
|
|
case DW_SECT_INFO_V5:
|
|
sections.info_or_types_offset = offset;
|
|
sections.info_or_types_size = size;
|
|
break;
|
|
case DW_SECT_LINE_V5:
|
|
sections.line_offset = offset;
|
|
sections.line_size = size;
|
|
break;
|
|
case DW_SECT_LOCLISTS_V5:
|
|
sections.loclists_offset = offset;
|
|
sections.loclists_size = size;
|
|
break;
|
|
case DW_SECT_MACRO_V5:
|
|
sections.macro_offset = offset;
|
|
sections.macro_size = size;
|
|
break;
|
|
case DW_SECT_RNGLISTS_V5:
|
|
sections.rnglists_offset = offset;
|
|
sections.rnglists_size = size;
|
|
break;
|
|
case DW_SECT_STR_OFFSETS_V5:
|
|
sections.str_offsets_offset = offset;
|
|
sections.str_offsets_size = size;
|
|
break;
|
|
case DW_SECT_RESERVED_V5:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* It's easier for the rest of the code if we fake a struct dwo_file and
|
|
have dwo_unit "live" in that. At least for now.
|
|
|
|
The DWP file can be made up of a random collection of CUs and TUs.
|
|
However, for each CU + set of TUs that came from the same original DWO
|
|
file, we can combine them back into a virtual DWO file to save space
|
|
(fewer struct dwo_file objects to allocate). Remember that for really
|
|
large apps there can be on the order of 8K CUs and 200K TUs, or more. */
|
|
|
|
std::string virtual_dwo_name =
|
|
string_printf ("virtual-dwo/%ld-%ld-%ld-%ld-%ld-%ld",
|
|
(long) (sections.abbrev_size ? sections.abbrev_offset : 0),
|
|
(long) (sections.line_size ? sections.line_offset : 0),
|
|
(long) (sections.loclists_size ? sections.loclists_offset : 0),
|
|
(long) (sections.str_offsets_size
|
|
? sections.str_offsets_offset : 0),
|
|
(long) (sections.macro_size ? sections.macro_offset : 0),
|
|
(long) (sections.rnglists_size ? sections.rnglists_offset: 0));
|
|
/* Can we use an existing virtual DWO file? */
|
|
dwo_file_slot = lookup_dwo_file_slot (per_objfile,
|
|
virtual_dwo_name.c_str (),
|
|
comp_dir);
|
|
/* Create one if necessary. */
|
|
if (*dwo_file_slot == NULL)
|
|
{
|
|
dwarf_read_debug_printf ("Creating virtual DWO: %s",
|
|
virtual_dwo_name.c_str ());
|
|
|
|
dwo_file = new struct dwo_file;
|
|
dwo_file->dwo_name = std::move (virtual_dwo_name);
|
|
dwo_file->comp_dir = comp_dir;
|
|
dwo_file->sections.abbrev =
|
|
create_dwp_v2_or_v5_section (per_objfile,
|
|
&dwp_file->sections.abbrev,
|
|
sections.abbrev_offset,
|
|
sections.abbrev_size);
|
|
dwo_file->sections.line =
|
|
create_dwp_v2_or_v5_section (per_objfile,
|
|
&dwp_file->sections.line,
|
|
sections.line_offset, sections.line_size);
|
|
dwo_file->sections.macro =
|
|
create_dwp_v2_or_v5_section (per_objfile,
|
|
&dwp_file->sections.macro,
|
|
sections.macro_offset,
|
|
sections.macro_size);
|
|
dwo_file->sections.loclists =
|
|
create_dwp_v2_or_v5_section (per_objfile,
|
|
&dwp_file->sections.loclists,
|
|
sections.loclists_offset,
|
|
sections.loclists_size);
|
|
dwo_file->sections.rnglists =
|
|
create_dwp_v2_or_v5_section (per_objfile,
|
|
&dwp_file->sections.rnglists,
|
|
sections.rnglists_offset,
|
|
sections.rnglists_size);
|
|
dwo_file->sections.str_offsets =
|
|
create_dwp_v2_or_v5_section (per_objfile,
|
|
&dwp_file->sections.str_offsets,
|
|
sections.str_offsets_offset,
|
|
sections.str_offsets_size);
|
|
/* The "str" section is global to the entire DWP file. */
|
|
dwo_file->sections.str = dwp_file->sections.str;
|
|
/* The info or types section is assigned below to dwo_unit,
|
|
there's no need to record it in dwo_file.
|
|
Also, we can't simply record type sections in dwo_file because
|
|
we record a pointer into the vector in dwo_unit. As we collect more
|
|
types we'll grow the vector and eventually have to reallocate space
|
|
for it, invalidating all copies of pointers into the previous
|
|
contents. */
|
|
*dwo_file_slot = dwo_file;
|
|
}
|
|
else
|
|
{
|
|
dwarf_read_debug_printf ("Using existing virtual DWO: %s",
|
|
virtual_dwo_name.c_str ());
|
|
|
|
dwo_file = (struct dwo_file *) *dwo_file_slot;
|
|
}
|
|
|
|
dwo_unit = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, struct dwo_unit);
|
|
dwo_unit->dwo_file = dwo_file;
|
|
dwo_unit->signature = signature;
|
|
dwo_unit->section
|
|
= XOBNEW (&per_objfile->per_bfd->obstack, struct dwarf2_section_info);
|
|
*dwo_unit->section = create_dwp_v2_or_v5_section (per_objfile,
|
|
&dwp_file->sections.info,
|
|
sections.info_or_types_offset,
|
|
sections.info_or_types_size);
|
|
/* dwo_unit->{offset,length,type_offset_in_tu} are set later. */
|
|
|
|
return dwo_unit;
|
|
}
|
|
|
|
/* Lookup the DWO unit with SIGNATURE in DWP_FILE.
|
|
Returns NULL if the signature isn't found. */
|
|
|
|
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)
|
|
{
|
|
const struct dwp_hash_table *dwp_htab =
|
|
is_debug_types ? dwp_file->tus : dwp_file->cus;
|
|
bfd *dbfd = dwp_file->dbfd.get ();
|
|
uint32_t mask = dwp_htab->nr_slots - 1;
|
|
uint32_t hash = signature & mask;
|
|
uint32_t hash2 = ((signature >> 32) & mask) | 1;
|
|
unsigned int i;
|
|
void **slot;
|
|
struct dwo_unit find_dwo_cu;
|
|
|
|
memset (&find_dwo_cu, 0, sizeof (find_dwo_cu));
|
|
find_dwo_cu.signature = signature;
|
|
slot = htab_find_slot (is_debug_types
|
|
? dwp_file->loaded_tus.get ()
|
|
: dwp_file->loaded_cus.get (),
|
|
&find_dwo_cu, INSERT);
|
|
|
|
if (*slot != NULL)
|
|
return (struct dwo_unit *) *slot;
|
|
|
|
/* Use a for loop so that we don't loop forever on bad debug info. */
|
|
for (i = 0; i < dwp_htab->nr_slots; ++i)
|
|
{
|
|
ULONGEST signature_in_table;
|
|
|
|
signature_in_table =
|
|
read_8_bytes (dbfd, dwp_htab->hash_table + hash * sizeof (uint64_t));
|
|
if (signature_in_table == signature)
|
|
{
|
|
uint32_t unit_index =
|
|
read_4_bytes (dbfd,
|
|
dwp_htab->unit_table + hash * sizeof (uint32_t));
|
|
|
|
if (dwp_file->version == 1)
|
|
{
|
|
*slot = create_dwo_unit_in_dwp_v1 (per_objfile, dwp_file,
|
|
unit_index, comp_dir,
|
|
signature, is_debug_types);
|
|
}
|
|
else if (dwp_file->version == 2)
|
|
{
|
|
*slot = create_dwo_unit_in_dwp_v2 (per_objfile, dwp_file,
|
|
unit_index, comp_dir,
|
|
signature, is_debug_types);
|
|
}
|
|
else /* version == 5 */
|
|
{
|
|
*slot = create_dwo_unit_in_dwp_v5 (per_objfile, dwp_file,
|
|
unit_index, comp_dir,
|
|
signature, is_debug_types);
|
|
}
|
|
return (struct dwo_unit *) *slot;
|
|
}
|
|
if (signature_in_table == 0)
|
|
return NULL;
|
|
hash = (hash + hash2) & mask;
|
|
}
|
|
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"bad DWP hash table, lookup didn't terminate [in module %s]"),
|
|
dwp_file->name);
|
|
}
|
|
|
|
/* Subroutine of open_dwo_file,open_dwp_file to simplify them.
|
|
Open the file specified by FILE_NAME and hand it off to BFD for
|
|
preliminary analysis. Return a newly initialized bfd *, which
|
|
includes a canonicalized copy of FILE_NAME.
|
|
If IS_DWP is TRUE, we're opening a DWP file, otherwise a DWO file.
|
|
SEARCH_CWD is true if the current directory is to be searched.
|
|
It will be searched before debug-file-directory.
|
|
If successful, the file is added to the bfd include table of the
|
|
objfile's bfd (see gdb_bfd_record_inclusion).
|
|
If unable to find/open the file, return NULL.
|
|
NOTE: This function is derived from symfile_bfd_open. */
|
|
|
|
static gdb_bfd_ref_ptr
|
|
try_open_dwop_file (dwarf2_per_objfile *per_objfile,
|
|
const char *file_name, int is_dwp, int search_cwd)
|
|
{
|
|
int desc;
|
|
/* Blech. OPF_TRY_CWD_FIRST also disables searching the path list if
|
|
FILE_NAME contains a '/'. So we can't use it. Instead prepend "."
|
|
to debug_file_directory. */
|
|
const char *search_path;
|
|
static const char dirname_separator_string[] = { DIRNAME_SEPARATOR, '\0' };
|
|
|
|
gdb::unique_xmalloc_ptr<char> search_path_holder;
|
|
if (search_cwd)
|
|
{
|
|
const std::string &debug_dir = per_objfile->per_bfd->captured_debug_dir;
|
|
|
|
if (!debug_dir.empty ())
|
|
{
|
|
search_path_holder.reset (concat (".", dirname_separator_string,
|
|
debug_dir.c_str (),
|
|
(char *) NULL));
|
|
search_path = search_path_holder.get ();
|
|
}
|
|
else
|
|
search_path = ".";
|
|
}
|
|
else
|
|
search_path = per_objfile->per_bfd->captured_debug_dir.c_str ();
|
|
|
|
/* Add the path for the executable binary to the list of search paths. */
|
|
std::string objfile_dir = ldirname (objfile_name (per_objfile->objfile));
|
|
search_path_holder.reset (concat (objfile_dir.c_str (),
|
|
dirname_separator_string,
|
|
search_path, nullptr));
|
|
search_path = search_path_holder.get ();
|
|
|
|
openp_flags flags = OPF_RETURN_REALPATH;
|
|
if (is_dwp)
|
|
flags |= OPF_SEARCH_IN_PATH;
|
|
|
|
gdb::unique_xmalloc_ptr<char> absolute_name;
|
|
desc = openp (search_path, flags, file_name,
|
|
O_RDONLY | O_BINARY, &absolute_name,
|
|
per_objfile->per_bfd->captured_cwd.c_str ());
|
|
if (desc < 0)
|
|
return NULL;
|
|
|
|
gdb_bfd_ref_ptr sym_bfd (gdb_bfd_open (absolute_name.get (),
|
|
gnutarget, desc));
|
|
if (sym_bfd == NULL)
|
|
return NULL;
|
|
|
|
if (!bfd_check_format (sym_bfd.get (), bfd_object))
|
|
return NULL;
|
|
|
|
/* Success. Record the bfd as having been included by the objfile's bfd.
|
|
This is important because things like demangled_names_hash lives in the
|
|
objfile's per_bfd space and may have references to things like symbol
|
|
names that live in the DWO/DWP file's per_bfd space. PR 16426. */
|
|
gdb_bfd_record_inclusion (per_objfile->objfile->obfd.get (), sym_bfd.get ());
|
|
|
|
return sym_bfd;
|
|
}
|
|
|
|
/* Try to open DWO file FILE_NAME.
|
|
COMP_DIR is the DW_AT_comp_dir attribute.
|
|
The result is the bfd handle of the file.
|
|
If there is a problem finding or opening the file, return NULL.
|
|
Upon success, the canonicalized path of the file is stored in the bfd,
|
|
same as symfile_bfd_open. */
|
|
|
|
static gdb_bfd_ref_ptr
|
|
open_dwo_file (dwarf2_per_objfile *per_objfile,
|
|
const char *file_name, const char *comp_dir)
|
|
{
|
|
if (IS_ABSOLUTE_PATH (file_name))
|
|
return try_open_dwop_file (per_objfile, file_name,
|
|
0 /*is_dwp*/, 0 /*search_cwd*/);
|
|
|
|
/* Before trying the search path, try DWO_NAME in COMP_DIR. */
|
|
|
|
if (comp_dir != NULL)
|
|
{
|
|
std::string path_to_try = path_join (comp_dir, file_name);
|
|
|
|
/* NOTE: If comp_dir is a relative path, this will also try the
|
|
search path, which seems useful. */
|
|
gdb_bfd_ref_ptr abfd (try_open_dwop_file
|
|
(per_objfile, path_to_try.c_str (), 0 /*is_dwp*/, 1 /*search_cwd*/));
|
|
|
|
if (abfd != NULL)
|
|
return abfd;
|
|
}
|
|
|
|
/* That didn't work, try debug-file-directory, which, despite its name,
|
|
is a list of paths. */
|
|
|
|
if (per_objfile->per_bfd->captured_debug_dir.empty ())
|
|
return NULL;
|
|
|
|
return try_open_dwop_file (per_objfile, file_name,
|
|
0 /*is_dwp*/, 1 /*search_cwd*/);
|
|
}
|
|
|
|
/* This function is mapped across the sections and remembers the offset and
|
|
size of each of the DWO debugging sections we are interested in. */
|
|
|
|
static void
|
|
dwarf2_locate_dwo_sections (objfile *objfile, dwo_file &dwo_file)
|
|
{
|
|
const struct dwop_section_names *names = &dwop_section_names;
|
|
dwo_sections &dwo_sections = dwo_file.sections;
|
|
bool complained_about_macro_already = false;
|
|
|
|
for (asection *sec : gdb_bfd_sections (dwo_file.dbfd))
|
|
{
|
|
struct dwarf2_section_info *dw_sect = nullptr;
|
|
|
|
if (names->abbrev_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.abbrev;
|
|
else if (names->info_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.infos.emplace_back (dwarf2_section_info {});
|
|
else if (names->line_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.line;
|
|
else if (names->loc_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.loc;
|
|
else if (names->loclists_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.loclists;
|
|
else if (names->macinfo_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.macinfo;
|
|
else if (names->macro_dwo.matches (sec->name))
|
|
{
|
|
/* gcc versions <= 13 generate multiple .debug_macro.dwo sections with
|
|
some unresolved links between them. It's not usable, so do as if
|
|
there were not there. */
|
|
if (!complained_about_macro_already)
|
|
{
|
|
if (dwo_sections.macro.s.section == nullptr)
|
|
dw_sect = &dwo_sections.macro;
|
|
else
|
|
{
|
|
warning (_("Multiple .debug_macro.dwo sections found in "
|
|
"%s, ignoring them."), dwo_file.dbfd->filename);
|
|
|
|
dwo_sections.macro = dwarf2_section_info {};
|
|
complained_about_macro_already = true;
|
|
}
|
|
}
|
|
}
|
|
else if (names->rnglists_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.rnglists;
|
|
else if (names->str_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.str;
|
|
else if (names->str_offsets_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.str_offsets;
|
|
else if (names->types_dwo.matches (sec->name))
|
|
dw_sect = &dwo_sections.types.emplace_back (dwarf2_section_info {});
|
|
|
|
if (dw_sect != nullptr)
|
|
{
|
|
/* Make sure we don't overwrite a section info that has been filled in
|
|
already. */
|
|
gdb_assert (!dw_sect->readin);
|
|
|
|
dw_sect->s.section = sec;
|
|
dw_sect->size = bfd_section_size (sec);
|
|
dw_sect->read (objfile);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Initialize the use of the DWO file specified by DWO_NAME and referenced
|
|
by PER_CU. This is for the non-DWP case.
|
|
The result is NULL if DWO_NAME can't be found. */
|
|
|
|
static struct dwo_file *
|
|
open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name,
|
|
const char *comp_dir)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
gdb_bfd_ref_ptr dbfd = open_dwo_file (per_objfile, dwo_name, comp_dir);
|
|
if (dbfd == NULL)
|
|
{
|
|
dwarf_read_debug_printf ("DWO file not found: %s", dwo_name);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
dwo_file_up dwo_file (new struct dwo_file);
|
|
dwo_file->dwo_name = dwo_name;
|
|
dwo_file->comp_dir = comp_dir;
|
|
dwo_file->dbfd = std::move (dbfd);
|
|
|
|
dwarf2_locate_dwo_sections (per_objfile->objfile, *dwo_file);
|
|
|
|
for (dwarf2_section_info §ion : dwo_file->sections.infos)
|
|
create_cus_hash_table (cu, *dwo_file, section);
|
|
|
|
if (cu->header.version < 5)
|
|
create_debug_types_hash_table (per_objfile, dwo_file.get (),
|
|
dwo_file->sections.types);
|
|
else
|
|
for (dwarf2_section_info §ion : dwo_file->sections.infos)
|
|
create_debug_type_hash_table (per_objfile, dwo_file.get (),
|
|
§ion,
|
|
rcuh_kind::COMPILE);
|
|
|
|
dwarf_read_debug_printf ("DWO file found: %s", dwo_name);
|
|
|
|
bfd_cache_close (dwo_file->dbfd.get ());
|
|
|
|
return dwo_file.release ();
|
|
}
|
|
|
|
/* This function is mapped across the sections and remembers the offset and
|
|
size of each of the DWP debugging sections common to version 1 and 2 that
|
|
we are interested in. */
|
|
|
|
static void
|
|
dwarf2_locate_common_dwp_sections (struct objfile *objfile, bfd *abfd,
|
|
asection *sectp, dwp_file *dwp_file)
|
|
{
|
|
const struct dwop_section_names *names = &dwop_section_names;
|
|
unsigned int elf_section_nr = elf_section_data (sectp)->this_idx;
|
|
|
|
/* Record the ELF section number for later lookup: this is what the
|
|
.debug_cu_index,.debug_tu_index tables use in DWP V1. */
|
|
gdb_assert (elf_section_nr < dwp_file->num_sections);
|
|
dwp_file->elf_sections[elf_section_nr] = sectp;
|
|
|
|
/* Look for specific sections that we need. */
|
|
struct dwarf2_section_info *dw_sect = nullptr;
|
|
if (names->str_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.str;
|
|
else if (names->cu_index.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.cu_index;
|
|
else if (names->tu_index.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.tu_index;
|
|
|
|
if (dw_sect != nullptr)
|
|
{
|
|
/* Make sure we don't overwrite a section info that has been filled in
|
|
already. */
|
|
gdb_assert (!dw_sect->readin);
|
|
|
|
dw_sect->s.section = sectp;
|
|
dw_sect->size = bfd_section_size (sectp);
|
|
dw_sect->read (objfile);
|
|
}
|
|
}
|
|
|
|
/* This function is mapped across the sections and remembers the offset and
|
|
size of each of the DWP version 2 debugging sections that we are interested
|
|
in. This is split into a separate function because we don't know if we
|
|
have version 1 or 2 or 5 until we parse the cu_index/tu_index sections. */
|
|
|
|
static void
|
|
dwarf2_locate_v2_dwp_sections (struct objfile *objfile, bfd *abfd,
|
|
asection *sectp, void *dwp_file_ptr)
|
|
{
|
|
struct dwp_file *dwp_file = (struct dwp_file *) dwp_file_ptr;
|
|
const struct dwop_section_names *names = &dwop_section_names;
|
|
unsigned int elf_section_nr = elf_section_data (sectp)->this_idx;
|
|
|
|
/* Record the ELF section number for later lookup: this is what the
|
|
.debug_cu_index,.debug_tu_index tables use in DWP V1. */
|
|
gdb_assert (elf_section_nr < dwp_file->num_sections);
|
|
dwp_file->elf_sections[elf_section_nr] = sectp;
|
|
|
|
/* Look for specific sections that we need. */
|
|
struct dwarf2_section_info *dw_sect = nullptr;
|
|
if (names->abbrev_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.abbrev;
|
|
else if (names->info_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.info;
|
|
else if (names->line_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.line;
|
|
else if (names->loc_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.loc;
|
|
else if (names->macinfo_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.macinfo;
|
|
else if (names->macro_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.macro;
|
|
else if (names->str_offsets_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.str_offsets;
|
|
else if (names->types_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.types;
|
|
|
|
if (dw_sect != nullptr)
|
|
{
|
|
/* Make sure we don't overwrite a section info that has been filled in
|
|
already. */
|
|
gdb_assert (!dw_sect->readin);
|
|
|
|
dw_sect->s.section = sectp;
|
|
dw_sect->size = bfd_section_size (sectp);
|
|
dw_sect->read (objfile);
|
|
}
|
|
}
|
|
|
|
/* This function is mapped across the sections and remembers the offset and
|
|
size of each of the DWP version 5 debugging sections that we are interested
|
|
in. This is split into a separate function because we don't know if we
|
|
have version 1 or 2 or 5 until we parse the cu_index/tu_index sections. */
|
|
|
|
static void
|
|
dwarf2_locate_v5_dwp_sections (struct objfile *objfile, bfd *abfd,
|
|
asection *sectp, void *dwp_file_ptr)
|
|
{
|
|
struct dwp_file *dwp_file = (struct dwp_file *) dwp_file_ptr;
|
|
const struct dwop_section_names *names = &dwop_section_names;
|
|
unsigned int elf_section_nr = elf_section_data (sectp)->this_idx;
|
|
|
|
/* Record the ELF section number for later lookup: this is what the
|
|
.debug_cu_index,.debug_tu_index tables use in DWP V1. */
|
|
gdb_assert (elf_section_nr < dwp_file->num_sections);
|
|
dwp_file->elf_sections[elf_section_nr] = sectp;
|
|
|
|
/* Look for specific sections that we need. */
|
|
struct dwarf2_section_info *dw_sect = nullptr;
|
|
if (names->abbrev_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.abbrev;
|
|
else if (names->info_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.info;
|
|
else if (names->line_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.line;
|
|
else if (names->loclists_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.loclists;
|
|
else if (names->macro_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.macro;
|
|
else if (names->rnglists_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.rnglists;
|
|
else if (names->str_offsets_dwo.matches (sectp->name))
|
|
dw_sect = &dwp_file->sections.str_offsets;
|
|
|
|
if (dw_sect != nullptr)
|
|
{
|
|
/* Make sure we don't overwrite a section info that has been filled in
|
|
already. */
|
|
gdb_assert (!dw_sect->readin);
|
|
|
|
dw_sect->s.section = sectp;
|
|
dw_sect->size = bfd_section_size (sectp);
|
|
dw_sect->read (objfile);
|
|
}
|
|
}
|
|
|
|
/* Hash function for dwp_file loaded CUs/TUs. */
|
|
|
|
static hashval_t
|
|
hash_dwp_loaded_cutus (const void *item)
|
|
{
|
|
const struct dwo_unit *dwo_unit = (const struct dwo_unit *) item;
|
|
|
|
/* This drops the top 32 bits of the signature, but is ok for a hash. */
|
|
return dwo_unit->signature;
|
|
}
|
|
|
|
/* Equality function for dwp_file loaded CUs/TUs. */
|
|
|
|
static int
|
|
eq_dwp_loaded_cutus (const void *a, const void *b)
|
|
{
|
|
const struct dwo_unit *dua = (const struct dwo_unit *) a;
|
|
const struct dwo_unit *dub = (const struct dwo_unit *) b;
|
|
|
|
return dua->signature == dub->signature;
|
|
}
|
|
|
|
/* Allocate a hash table for dwp_file loaded CUs/TUs. */
|
|
|
|
static htab_up
|
|
allocate_dwp_loaded_cutus_table ()
|
|
{
|
|
return htab_up (htab_create_alloc (3,
|
|
hash_dwp_loaded_cutus,
|
|
eq_dwp_loaded_cutus,
|
|
NULL, xcalloc, xfree));
|
|
}
|
|
|
|
/* Try to open DWP file FILE_NAME.
|
|
The result is the bfd handle of the file.
|
|
If there is a problem finding or opening the file, return NULL.
|
|
Upon success, the canonicalized path of the file is stored in the bfd,
|
|
same as symfile_bfd_open. */
|
|
|
|
static gdb_bfd_ref_ptr
|
|
open_dwp_file (dwarf2_per_objfile *per_objfile, const char *file_name)
|
|
{
|
|
gdb_bfd_ref_ptr abfd (try_open_dwop_file (per_objfile, file_name,
|
|
1 /*is_dwp*/,
|
|
1 /*search_cwd*/));
|
|
if (abfd != NULL)
|
|
return abfd;
|
|
|
|
/* Work around upstream bug 15652.
|
|
http://sourceware.org/bugzilla/show_bug.cgi?id=15652
|
|
[Whether that's a "bug" is debatable, but it is getting in our way.]
|
|
We have no real idea where the dwp file is, because gdb's realpath-ing
|
|
of the executable's path may have discarded the needed info.
|
|
[IWBN if the dwp file name was recorded in the executable, akin to
|
|
.gnu_debuglink, but that doesn't exist yet.]
|
|
Strip the directory from FILE_NAME and search again. */
|
|
if (!per_objfile->per_bfd->captured_debug_dir.empty ())
|
|
{
|
|
/* Don't implicitly search the current directory here.
|
|
If the user wants to search "." to handle this case,
|
|
it must be added to debug-file-directory. */
|
|
return try_open_dwop_file (per_objfile, lbasename (file_name),
|
|
1 /*is_dwp*/,
|
|
0 /*search_cwd*/);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Initialize the use of the DWP file for the current objfile.
|
|
By convention the name of the DWP file is ${objfile}.dwp.
|
|
The result is NULL if it can't be found. */
|
|
|
|
static std::unique_ptr<struct dwp_file>
|
|
open_and_init_dwp_file (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
|
|
/* Try to find first .dwp for the binary file before any symbolic links
|
|
resolving. */
|
|
|
|
/* If the objfile is a debug file, find the name of the real binary
|
|
file and get the name of dwp file from there. */
|
|
std::string dwp_name;
|
|
if (objfile->separate_debug_objfile_backlink != NULL)
|
|
{
|
|
struct objfile *backlink = objfile->separate_debug_objfile_backlink;
|
|
const char *backlink_basename = lbasename (backlink->original_name);
|
|
|
|
dwp_name = ldirname (objfile->original_name) + SLASH_STRING + backlink_basename;
|
|
}
|
|
else
|
|
dwp_name = objfile->original_name;
|
|
|
|
dwp_name += ".dwp";
|
|
|
|
gdb_bfd_ref_ptr dbfd (open_dwp_file (per_objfile, dwp_name.c_str ()));
|
|
if (dbfd == NULL
|
|
&& strcmp (objfile->original_name, objfile_name (objfile)) != 0)
|
|
{
|
|
/* Try to find .dwp for the binary file after gdb_realpath resolving. */
|
|
dwp_name = objfile_name (objfile);
|
|
dwp_name += ".dwp";
|
|
dbfd = open_dwp_file (per_objfile, dwp_name.c_str ());
|
|
}
|
|
|
|
if (dbfd == NULL)
|
|
{
|
|
dwarf_read_debug_printf ("DWP file not found: %s", dwp_name.c_str ());
|
|
|
|
return std::unique_ptr<dwp_file> ();
|
|
}
|
|
|
|
const char *name = bfd_get_filename (dbfd.get ());
|
|
std::unique_ptr<struct dwp_file> dwp_file
|
|
(new struct dwp_file (name, std::move (dbfd)));
|
|
|
|
dwp_file->num_sections = elf_numsections (dwp_file->dbfd);
|
|
dwp_file->elf_sections =
|
|
OBSTACK_CALLOC (&per_objfile->per_bfd->obstack,
|
|
dwp_file->num_sections, asection *);
|
|
|
|
for (asection *sec : gdb_bfd_sections (dwp_file->dbfd))
|
|
dwarf2_locate_common_dwp_sections (objfile, dwp_file->dbfd.get (), sec,
|
|
dwp_file.get ());
|
|
|
|
dwp_file->cus = create_dwp_hash_table (per_objfile, dwp_file.get (), 0);
|
|
|
|
dwp_file->tus = create_dwp_hash_table (per_objfile, dwp_file.get (), 1);
|
|
|
|
/* The DWP file version is stored in the hash table. Oh well. */
|
|
if (dwp_file->cus && dwp_file->tus
|
|
&& dwp_file->cus->version != dwp_file->tus->version)
|
|
{
|
|
/* Technically speaking, we should try to limp along, but this is
|
|
pretty bizarre. We use pulongest here because that's the established
|
|
portability solution (e.g, we cannot use %u for uint32_t). */
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"DWP file CU version %s doesn't match TU version %s"
|
|
" [in DWP file %s]"),
|
|
pulongest (dwp_file->cus->version),
|
|
pulongest (dwp_file->tus->version), dwp_name.c_str ());
|
|
}
|
|
|
|
if (dwp_file->cus)
|
|
dwp_file->version = dwp_file->cus->version;
|
|
else if (dwp_file->tus)
|
|
dwp_file->version = dwp_file->tus->version;
|
|
else
|
|
dwp_file->version = 2;
|
|
|
|
for (asection *sec : gdb_bfd_sections (dwp_file->dbfd))
|
|
{
|
|
if (dwp_file->version == 2)
|
|
dwarf2_locate_v2_dwp_sections (objfile, dwp_file->dbfd.get (), sec,
|
|
dwp_file.get ());
|
|
else
|
|
dwarf2_locate_v5_dwp_sections (objfile, dwp_file->dbfd.get (), sec,
|
|
dwp_file.get ());
|
|
}
|
|
|
|
dwp_file->loaded_cus = allocate_dwp_loaded_cutus_table ();
|
|
dwp_file->loaded_tus = allocate_dwp_loaded_cutus_table ();
|
|
|
|
dwarf_read_debug_printf ("DWP file found: %s", dwp_file->name);
|
|
dwarf_read_debug_printf (" %s CUs, %s TUs",
|
|
pulongest (dwp_file->cus ? dwp_file->cus->nr_units : 0),
|
|
pulongest (dwp_file->tus ? dwp_file->tus->nr_units : 0));
|
|
|
|
bfd_cache_close (dwp_file->dbfd.get ());
|
|
|
|
return dwp_file;
|
|
}
|
|
|
|
/* Wrapper around open_and_init_dwp_file, only open it once. */
|
|
|
|
static struct dwp_file *
|
|
get_dwp_file (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
if (!per_objfile->per_bfd->dwp_checked)
|
|
{
|
|
per_objfile->per_bfd->dwp_file = open_and_init_dwp_file (per_objfile);
|
|
per_objfile->per_bfd->dwp_checked = 1;
|
|
}
|
|
return per_objfile->per_bfd->dwp_file.get ();
|
|
}
|
|
|
|
/* Subroutine of lookup_dwo_comp_unit, lookup_dwo_type_unit.
|
|
Look up the CU/TU with signature SIGNATURE, either in DWO file DWO_NAME
|
|
or in the DWP file for the objfile, referenced by THIS_UNIT.
|
|
If non-NULL, comp_dir is the DW_AT_comp_dir attribute.
|
|
IS_DEBUG_TYPES is non-zero if reading a TU, otherwise read a CU.
|
|
|
|
This is called, for example, when wanting to read a variable with a
|
|
complex location. Therefore we don't want to do file i/o for every call.
|
|
Therefore we don't want to look for a DWO file on every call.
|
|
Therefore we first see if we've already seen SIGNATURE in a DWP file,
|
|
then we check if we've already seen DWO_NAME, and only THEN do we check
|
|
for a DWO file.
|
|
|
|
The result is a pointer to the dwo_unit object or NULL if we didn't find it
|
|
(dwo_id mismatch or couldn't find the DWO/DWP file). */
|
|
|
|
static struct dwo_unit *
|
|
lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir,
|
|
ULONGEST signature, int is_debug_types)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
const char *kind = is_debug_types ? "TU" : "CU";
|
|
void **dwo_file_slot;
|
|
struct dwo_file *dwo_file;
|
|
struct dwp_file *dwp_file;
|
|
|
|
/* First see if there's a DWP file.
|
|
If we have a DWP file but didn't find the DWO inside it, don't
|
|
look for the original DWO file. It makes gdb behave differently
|
|
depending on whether one is debugging in the build tree. */
|
|
|
|
dwp_file = get_dwp_file (per_objfile);
|
|
if (dwp_file != NULL)
|
|
{
|
|
const struct dwp_hash_table *dwp_htab =
|
|
is_debug_types ? dwp_file->tus : dwp_file->cus;
|
|
|
|
if (dwp_htab != NULL)
|
|
{
|
|
struct dwo_unit *dwo_cutu =
|
|
lookup_dwo_unit_in_dwp (per_objfile, dwp_file, comp_dir, signature,
|
|
is_debug_types);
|
|
|
|
if (dwo_cutu != NULL)
|
|
{
|
|
dwarf_read_debug_printf ("Virtual DWO %s %s found: @%s",
|
|
kind, hex_string (signature),
|
|
host_address_to_string (dwo_cutu));
|
|
|
|
return dwo_cutu;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No DWP file, look for the DWO file. */
|
|
|
|
dwo_file_slot = lookup_dwo_file_slot (per_objfile, dwo_name, comp_dir);
|
|
if (*dwo_file_slot == NULL)
|
|
{
|
|
/* Read in the file and build a table of the CUs/TUs it contains. */
|
|
*dwo_file_slot = open_and_init_dwo_file (cu, dwo_name, comp_dir);
|
|
}
|
|
/* NOTE: This will be NULL if unable to open the file. */
|
|
dwo_file = (struct dwo_file *) *dwo_file_slot;
|
|
|
|
if (dwo_file != NULL)
|
|
{
|
|
struct dwo_unit *dwo_cutu = NULL;
|
|
|
|
if (is_debug_types && dwo_file->tus)
|
|
{
|
|
struct dwo_unit find_dwo_cutu;
|
|
|
|
memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu));
|
|
find_dwo_cutu.signature = signature;
|
|
dwo_cutu
|
|
= (struct dwo_unit *) htab_find (dwo_file->tus.get (),
|
|
&find_dwo_cutu);
|
|
}
|
|
else if (!is_debug_types && dwo_file->cus)
|
|
{
|
|
struct dwo_unit find_dwo_cutu;
|
|
|
|
memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu));
|
|
find_dwo_cutu.signature = signature;
|
|
dwo_cutu = (struct dwo_unit *)htab_find (dwo_file->cus.get (),
|
|
&find_dwo_cutu);
|
|
}
|
|
|
|
if (dwo_cutu != NULL)
|
|
{
|
|
dwarf_read_debug_printf ("DWO %s %s(%s) found: @%s",
|
|
kind, dwo_name, hex_string (signature),
|
|
host_address_to_string (dwo_cutu));
|
|
|
|
return dwo_cutu;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We didn't find it. This could mean a dwo_id mismatch, or
|
|
someone deleted the DWO/DWP file, or the search path isn't set up
|
|
correctly to find the file. */
|
|
|
|
dwarf_read_debug_printf ("DWO %s %s(%s) not found",
|
|
kind, dwo_name, hex_string (signature));
|
|
|
|
/* This is a warning and not a complaint because it can be caused by
|
|
pilot error (e.g., user accidentally deleting the DWO). */
|
|
{
|
|
/* Print the name of the DWP file if we looked there, helps the user
|
|
better diagnose the problem. */
|
|
std::string dwp_text;
|
|
|
|
if (dwp_file != NULL)
|
|
dwp_text = string_printf (" [in DWP file %s]",
|
|
lbasename (dwp_file->name));
|
|
|
|
warning (_("Could not find DWO %s %s(%s)%s referenced by %s at offset %s"
|
|
" [in module %s]"),
|
|
kind, dwo_name, hex_string (signature), dwp_text.c_str (), kind,
|
|
sect_offset_str (cu->per_cu->sect_off), objfile_name (objfile));
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Lookup the DWO CU DWO_NAME/SIGNATURE referenced from THIS_CU.
|
|
See lookup_dwo_cutu_unit for details. */
|
|
|
|
static struct dwo_unit *
|
|
lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir,
|
|
ULONGEST signature)
|
|
{
|
|
gdb_assert (!cu->per_cu->is_debug_types);
|
|
|
|
return lookup_dwo_cutu (cu, dwo_name, comp_dir, signature, 0);
|
|
}
|
|
|
|
/* Lookup the DWO TU DWO_NAME/SIGNATURE referenced from THIS_TU.
|
|
See lookup_dwo_cutu_unit for details. */
|
|
|
|
static struct dwo_unit *
|
|
lookup_dwo_type_unit (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir)
|
|
{
|
|
gdb_assert (cu->per_cu->is_debug_types);
|
|
|
|
signatured_type *sig_type = (signatured_type *) cu->per_cu;
|
|
|
|
return lookup_dwo_cutu (cu, dwo_name, comp_dir, sig_type->signature, 1);
|
|
}
|
|
|
|
/* Traversal function for queue_and_load_all_dwo_tus. */
|
|
|
|
static int
|
|
queue_and_load_dwo_tu (void **slot, void *info)
|
|
{
|
|
struct dwo_unit *dwo_unit = (struct dwo_unit *) *slot;
|
|
dwarf2_cu *cu = (dwarf2_cu *) info;
|
|
ULONGEST signature = dwo_unit->signature;
|
|
signatured_type *sig_type = lookup_dwo_signatured_type (cu, signature);
|
|
|
|
if (sig_type != NULL)
|
|
{
|
|
/* We pass NULL for DEPENDENT_CU because we don't yet know if there's
|
|
a real dependency of PER_CU on SIG_TYPE. That is detected later
|
|
while processing PER_CU. */
|
|
if (maybe_queue_comp_unit (NULL, sig_type, cu->per_objfile,
|
|
cu->lang ()))
|
|
load_full_type_unit (sig_type, cu->per_objfile);
|
|
cu->per_cu->imported_symtabs.push_back (sig_type);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Queue all TUs contained in the DWO of CU to be read in.
|
|
The DWO may have the only definition of the type, though it may not be
|
|
referenced anywhere in PER_CU. Thus we have to load *all* its TUs.
|
|
http://sourceware.org/bugzilla/show_bug.cgi?id=15021 */
|
|
|
|
static void
|
|
queue_and_load_all_dwo_tus (dwarf2_cu *cu)
|
|
{
|
|
struct dwo_unit *dwo_unit;
|
|
struct dwo_file *dwo_file;
|
|
|
|
gdb_assert (cu != nullptr);
|
|
gdb_assert (!cu->per_cu->is_debug_types);
|
|
gdb_assert (get_dwp_file (cu->per_objfile) == nullptr);
|
|
|
|
dwo_unit = cu->dwo_unit;
|
|
gdb_assert (dwo_unit != NULL);
|
|
|
|
dwo_file = dwo_unit->dwo_file;
|
|
if (dwo_file->tus != NULL)
|
|
htab_traverse_noresize (dwo_file->tus.get (), queue_and_load_dwo_tu, cu);
|
|
}
|
|
|
|
/* Read in various DIEs. */
|
|
|
|
/* DW_AT_abstract_origin inherits whole DIEs (not just their attributes).
|
|
Inherit only the children of the DW_AT_abstract_origin DIE not being
|
|
already referenced by DW_AT_abstract_origin from the children of the
|
|
current DIE. */
|
|
|
|
static void
|
|
inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
attribute *attr = dwarf2_attr (die, DW_AT_abstract_origin, cu);
|
|
if (attr == nullptr)
|
|
return;
|
|
|
|
/* Note that following die references may follow to a die in a
|
|
different CU. */
|
|
dwarf2_cu *origin_cu = cu;
|
|
|
|
/* Parent of DIE - referenced by DW_AT_abstract_origin. */
|
|
die_info *origin_die = follow_die_ref (die, attr, &origin_cu);
|
|
|
|
/* We're inheriting ORIGIN's children into the scope we'd put DIE's
|
|
symbols in. */
|
|
struct pending **origin_previous_list_in_scope = origin_cu->list_in_scope;
|
|
origin_cu->list_in_scope = cu->list_in_scope;
|
|
|
|
if (die->tag != origin_die->tag
|
|
&& !(die->tag == DW_TAG_inlined_subroutine
|
|
&& origin_die->tag == DW_TAG_subprogram))
|
|
complaint (_("DIE %s and its abstract origin %s have different tags"),
|
|
sect_offset_str (die->sect_off),
|
|
sect_offset_str (origin_die->sect_off));
|
|
|
|
/* Find if the concrete and abstract trees are structurally the
|
|
same. This is a shallow traversal and it is not bullet-proof;
|
|
the compiler can trick the debugger into believing that the trees
|
|
are isomorphic, whereas they actually are not. However, the
|
|
likelihood of this happening is pretty low, and a full-fledged
|
|
check would be an overkill. */
|
|
bool are_isomorphic = true;
|
|
die_info *concrete_child = die->child;
|
|
die_info *abstract_child = origin_die->child;
|
|
while (concrete_child != nullptr || abstract_child != nullptr)
|
|
{
|
|
if (concrete_child == nullptr
|
|
|| abstract_child == nullptr
|
|
|| concrete_child->tag != abstract_child->tag)
|
|
{
|
|
are_isomorphic = false;
|
|
break;
|
|
}
|
|
|
|
concrete_child = concrete_child->sibling;
|
|
abstract_child = abstract_child->sibling;
|
|
}
|
|
|
|
/* Walk the origin's children in parallel to the concrete children.
|
|
This helps match an origin child in case the debug info misses
|
|
DW_AT_abstract_origin attributes. Keep in mind that the abstract
|
|
origin tree may not have the same tree structure as the concrete
|
|
DIE, though. */
|
|
die_info *corresponding_abstract_child
|
|
= are_isomorphic ? origin_die->child : nullptr;
|
|
|
|
std::vector<sect_offset> offsets;
|
|
|
|
for (die_info *child_die = die->child;
|
|
child_die && child_die->tag;
|
|
child_die = child_die->sibling)
|
|
{
|
|
/* We are trying to process concrete instance entries:
|
|
DW_TAG_call_site DIEs indeed have a DW_AT_abstract_origin tag, but
|
|
it's not relevant to our analysis here. i.e. detecting DIEs that are
|
|
present in the abstract instance but not referenced in the concrete
|
|
one. */
|
|
if (child_die->tag == DW_TAG_call_site
|
|
|| child_die->tag == DW_TAG_GNU_call_site)
|
|
{
|
|
if (are_isomorphic)
|
|
corresponding_abstract_child
|
|
= corresponding_abstract_child->sibling;
|
|
continue;
|
|
}
|
|
|
|
/* For each CHILD_DIE, find the corresponding child of
|
|
ORIGIN_DIE. If there is more than one layer of
|
|
DW_AT_abstract_origin, follow them all; there shouldn't be,
|
|
but GCC versions at least through 4.4 generate this (GCC PR
|
|
40573). */
|
|
die_info *child_origin_die = child_die;
|
|
dwarf2_cu *child_origin_cu = cu;
|
|
while (true)
|
|
{
|
|
attr = dwarf2_attr (child_origin_die, DW_AT_abstract_origin,
|
|
child_origin_cu);
|
|
if (attr == nullptr)
|
|
break;
|
|
|
|
die_info *prev_child_origin_die = child_origin_die;
|
|
child_origin_die = follow_die_ref (child_origin_die, attr,
|
|
&child_origin_cu);
|
|
|
|
if (prev_child_origin_die == child_origin_die)
|
|
{
|
|
/* Handle DIE with self-reference. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If missing DW_AT_abstract_origin, try the corresponding child
|
|
of the origin. Clang emits such lexical scopes. */
|
|
if (child_origin_die == child_die
|
|
&& dwarf2_attr (child_die, DW_AT_abstract_origin, cu) == nullptr
|
|
&& are_isomorphic
|
|
&& child_die->tag == DW_TAG_lexical_block)
|
|
child_origin_die = corresponding_abstract_child;
|
|
|
|
/* According to DWARF3 3.3.8.2 #3 new entries without their abstract
|
|
counterpart may exist. */
|
|
if (child_origin_die != child_die)
|
|
{
|
|
if (child_die->tag != child_origin_die->tag
|
|
&& !(child_die->tag == DW_TAG_inlined_subroutine
|
|
&& child_origin_die->tag == DW_TAG_subprogram))
|
|
complaint (_("Child DIE %s and its abstract origin %s have "
|
|
"different tags"),
|
|
sect_offset_str (child_die->sect_off),
|
|
sect_offset_str (child_origin_die->sect_off));
|
|
if (child_origin_die->parent != origin_die)
|
|
complaint (_("Child DIE %s and its abstract origin %s have "
|
|
"different parents"),
|
|
sect_offset_str (child_die->sect_off),
|
|
sect_offset_str (child_origin_die->sect_off));
|
|
else
|
|
offsets.push_back (child_origin_die->sect_off);
|
|
}
|
|
|
|
if (are_isomorphic)
|
|
corresponding_abstract_child = corresponding_abstract_child->sibling;
|
|
}
|
|
|
|
if (!offsets.empty ())
|
|
{
|
|
std::sort (offsets.begin (), offsets.end ());
|
|
|
|
for (auto offsets_it = offsets.begin () + 1;
|
|
offsets_it < offsets.end ();
|
|
++offsets_it)
|
|
if (*(offsets_it - 1) == *offsets_it)
|
|
complaint (_("Multiple children of DIE %s refer "
|
|
"to DIE %s as their abstract origin"),
|
|
sect_offset_str (die->sect_off),
|
|
sect_offset_str (*offsets_it));
|
|
}
|
|
|
|
auto offsets_it = offsets.begin ();
|
|
die_info *origin_child_die = origin_die->child;
|
|
while (origin_child_die != nullptr && origin_child_die->tag != 0)
|
|
{
|
|
/* Is ORIGIN_CHILD_DIE referenced by any of the DIE children? */
|
|
while (offsets_it < offsets.end ()
|
|
&& *offsets_it < origin_child_die->sect_off)
|
|
++offsets_it;
|
|
|
|
if (offsets_it == offsets.end ()
|
|
|| *offsets_it > origin_child_die->sect_off)
|
|
{
|
|
/* Found that ORIGIN_CHILD_DIE is really not referenced.
|
|
Check whether we're already processing ORIGIN_CHILD_DIE.
|
|
This can happen with mutually referenced abstract_origins.
|
|
PR 16581. */
|
|
if (!origin_child_die->in_process)
|
|
process_die (origin_child_die, origin_cu);
|
|
}
|
|
|
|
origin_child_die = origin_child_die->sibling;
|
|
}
|
|
|
|
origin_cu->list_in_scope = origin_previous_list_in_scope;
|
|
|
|
if (cu != origin_cu)
|
|
compute_delayed_physnames (origin_cu);
|
|
}
|
|
|
|
/* Return TRUE if the given DIE is the program's "main". DWARF 4 has
|
|
defined a dedicated DW_AT_main_subprogram attribute to indicate the
|
|
starting function of the program, however with older versions the
|
|
DW_CC_program value of the DW_AT_calling_convention attribute was
|
|
used instead as the only means available. We handle both variants. */
|
|
|
|
static bool
|
|
dwarf2_func_is_main_p (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
if (dwarf2_flag_true_p (die, DW_AT_main_subprogram, cu))
|
|
return true;
|
|
struct attribute *attr = dwarf2_attr (die, DW_AT_calling_convention, cu);
|
|
return (attr != nullptr
|
|
&& attr->constant_value (DW_CC_normal) == DW_CC_program);
|
|
}
|
|
|
|
/* A helper to handle Ada's "Pragma Import" feature when it is applied
|
|
to a function. */
|
|
|
|
static bool
|
|
check_ada_pragma_import (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
/* A Pragma Import will have both a name and a linkage name. */
|
|
const char *name = dwarf2_name (die, cu);
|
|
if (name == nullptr)
|
|
return false;
|
|
|
|
const char *linkage_name = dw2_linkage_name (die, cu);
|
|
/* Disallow the special Ada symbols. */
|
|
if (!is_ada_import_or_export (cu, name, linkage_name))
|
|
return false;
|
|
|
|
/* A Pragma Import will be a declaration, while a Pragma Export will
|
|
not be. */
|
|
if (!die_is_declaration (die, cu))
|
|
return false;
|
|
|
|
new_symbol (die, read_type_die (die, cu), cu);
|
|
return true;
|
|
}
|
|
|
|
/* Apply fixups to LOW_PC and HIGH_PC due to an incorrect DIE in CU. */
|
|
|
|
static void
|
|
fixup_low_high_pc (struct dwarf2_cu *cu, struct die_info *die, CORE_ADDR *low_pc,
|
|
CORE_ADDR *high_pc)
|
|
{
|
|
if (die->tag != DW_TAG_subprogram)
|
|
return;
|
|
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
|
|
if (gdbarch_bfd_arch_info (gdbarch)->arch == bfd_arch_arm
|
|
&& producer_is_gas_ge_2_39 (cu))
|
|
{
|
|
/* Gas version 2.39 produces DWARF for a Thumb subprogram with a low_pc
|
|
attribute with the thumb bit set (PR gas/31115). Work around this. */
|
|
*low_pc = gdbarch_addr_bits_remove (gdbarch, *low_pc);
|
|
if (high_pc != nullptr)
|
|
*high_pc = gdbarch_addr_bits_remove (gdbarch, *high_pc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
struct context_stack *newobj;
|
|
CORE_ADDR lowpc;
|
|
CORE_ADDR highpc;
|
|
struct die_info *child_die;
|
|
struct attribute *attr, *call_line, *call_file;
|
|
const char *name;
|
|
struct block *block;
|
|
int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
|
|
std::vector<struct symbol *> template_args;
|
|
struct template_symbol *templ_func = NULL;
|
|
|
|
if (inlined_func)
|
|
{
|
|
/* If we do not have call site information, we can't show the
|
|
caller of this inlined function. That's too confusing, so
|
|
only use the scope for local variables. */
|
|
call_line = dwarf2_attr (die, DW_AT_call_line, cu);
|
|
call_file = dwarf2_attr (die, DW_AT_call_file, cu);
|
|
if (call_line == NULL || call_file == NULL)
|
|
{
|
|
read_lexical_block_scope (die, cu);
|
|
return;
|
|
}
|
|
}
|
|
|
|
name = dwarf2_name (die, cu);
|
|
if (name == nullptr)
|
|
name = dw2_linkage_name (die, cu);
|
|
|
|
/* Ignore functions with missing or empty names. These are actually
|
|
illegal according to the DWARF standard. */
|
|
if (name == NULL)
|
|
{
|
|
complaint (_("missing name for subprogram DIE at %s"),
|
|
sect_offset_str (die->sect_off));
|
|
return;
|
|
}
|
|
|
|
if (check_ada_pragma_import (die, cu))
|
|
{
|
|
/* We already made the symbol for the Pragma Import, and because
|
|
it is a declaration, we know it won't have any other
|
|
important information, so we can simply return. */
|
|
return;
|
|
}
|
|
|
|
/* Ignore functions with missing or invalid low and high pc attributes. */
|
|
unrelocated_addr unrel_low, unrel_high;
|
|
if (dwarf2_get_pc_bounds (die, &unrel_low, &unrel_high, cu, nullptr, nullptr)
|
|
<= PC_BOUNDS_INVALID)
|
|
{
|
|
if (have_complaint ())
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_external, cu);
|
|
bool external_p = attr != nullptr && attr->as_boolean ();
|
|
attr = dwarf2_attr (die, DW_AT_inline, cu);
|
|
bool inlined_p
|
|
= (attr != nullptr
|
|
&& attr->is_nonnegative ()
|
|
&& (attr->as_nonnegative () == DW_INL_inlined
|
|
|| attr->as_nonnegative () == DW_INL_declared_inlined));
|
|
attr = dwarf2_attr (die, DW_AT_declaration, cu);
|
|
bool decl_p = attr != nullptr && attr->as_boolean ();
|
|
if (!external_p && !inlined_p && !decl_p)
|
|
complaint (_("cannot get low and high bounds "
|
|
"for subprogram DIE at %s"),
|
|
sect_offset_str (die->sect_off));
|
|
}
|
|
return;
|
|
}
|
|
|
|
lowpc = per_objfile->relocate (unrel_low);
|
|
highpc = per_objfile->relocate (unrel_high);
|
|
fixup_low_high_pc (cu, die, &lowpc, &highpc);
|
|
|
|
/* If we have any template arguments, then we must allocate a
|
|
different sort of symbol. */
|
|
for (child_die = die->child; child_die; child_die = child_die->sibling)
|
|
{
|
|
if (child_die->tag == DW_TAG_template_type_param
|
|
|| child_die->tag == DW_TAG_template_value_param)
|
|
{
|
|
templ_func = new (&objfile->objfile_obstack) template_symbol;
|
|
templ_func->subclass = SYMBOL_TEMPLATE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
gdb_assert (cu->get_builder () != nullptr);
|
|
newobj = cu->get_builder ()->push_context (0, lowpc);
|
|
newobj->name = new_symbol (die, read_type_die (die, cu), cu, templ_func);
|
|
|
|
if (dwarf2_func_is_main_p (die, cu))
|
|
set_objfile_main_name (objfile, newobj->name->linkage_name (),
|
|
cu->lang ());
|
|
|
|
/* If there is a location expression for DW_AT_frame_base, record
|
|
it. */
|
|
attr = dwarf2_attr (die, DW_AT_frame_base, cu);
|
|
if (attr != nullptr)
|
|
dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
|
|
|
|
/* If there is a location for the static link, record it. */
|
|
newobj->static_link = NULL;
|
|
attr = dwarf2_attr (die, DW_AT_static_link, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
newobj->static_link
|
|
= XOBNEW (&objfile->objfile_obstack, struct dynamic_prop);
|
|
attr_to_dynamic_prop (attr, die, cu, newobj->static_link,
|
|
cu->addr_type ());
|
|
}
|
|
|
|
cu->list_in_scope = cu->get_builder ()->get_local_symbols ();
|
|
|
|
if (die->child != NULL)
|
|
{
|
|
child_die = die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
if (child_die->tag == DW_TAG_template_type_param
|
|
|| child_die->tag == DW_TAG_template_value_param)
|
|
{
|
|
struct symbol *arg = new_symbol (child_die, NULL, cu);
|
|
|
|
if (arg != NULL)
|
|
template_args.push_back (arg);
|
|
}
|
|
else
|
|
process_die (child_die, cu);
|
|
child_die = child_die->sibling;
|
|
}
|
|
}
|
|
|
|
inherit_abstract_dies (die, cu);
|
|
|
|
/* If we have a DW_AT_specification, we might need to import using
|
|
directives from the context of the specification DIE. See the
|
|
comment in determine_prefix. */
|
|
if (is_cplus_dialect (cu->lang ())
|
|
&& dwarf2_attr (die, DW_AT_specification, cu))
|
|
{
|
|
struct dwarf2_cu *spec_cu = cu;
|
|
struct die_info *spec_die = die_specification (die, &spec_cu);
|
|
|
|
while (spec_die)
|
|
{
|
|
child_die = spec_die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
if (child_die->tag == DW_TAG_imported_module)
|
|
process_die (child_die, spec_cu);
|
|
child_die = child_die->sibling;
|
|
}
|
|
|
|
/* In some cases, GCC generates specification DIEs that
|
|
themselves contain DW_AT_specification attributes. */
|
|
spec_die = die_specification (spec_die, &spec_cu);
|
|
}
|
|
}
|
|
|
|
struct context_stack cstk = cu->get_builder ()->pop_context ();
|
|
/* Make a block for the local symbols within. */
|
|
block = cu->get_builder ()->finish_block (cstk.name, cstk.old_blocks,
|
|
cstk.static_link, lowpc, highpc);
|
|
|
|
/* For C++, set the block's scope. */
|
|
if ((is_cplus_dialect (cu->lang ())
|
|
|| cu->lang () == language_fortran
|
|
|| cu->lang () == language_d
|
|
|| cu->lang () == language_rust)
|
|
&& cu->processing_has_namespace_info)
|
|
block->set_scope (determine_prefix (die, cu),
|
|
&objfile->objfile_obstack);
|
|
|
|
/* If we have address ranges, record them. */
|
|
dwarf2_record_block_ranges (die, block, cu);
|
|
|
|
gdbarch_make_symbol_special (gdbarch, cstk.name, objfile);
|
|
|
|
/* Attach template arguments to function. */
|
|
if (!template_args.empty ())
|
|
{
|
|
gdb_assert (templ_func != NULL);
|
|
|
|
templ_func->n_template_arguments = template_args.size ();
|
|
templ_func->template_arguments
|
|
= XOBNEWVEC (&objfile->objfile_obstack, struct symbol *,
|
|
templ_func->n_template_arguments);
|
|
memcpy (templ_func->template_arguments,
|
|
template_args.data (),
|
|
(templ_func->n_template_arguments * sizeof (struct symbol *)));
|
|
|
|
/* Make sure that the symtab is set on the new symbols. Even
|
|
though they don't appear in this symtab directly, other parts
|
|
of gdb assume that symbols do, and this is reasonably
|
|
true. */
|
|
for (symbol *sym : template_args)
|
|
sym->set_symtab (templ_func->symtab ());
|
|
}
|
|
|
|
/* In C++, we can have functions nested inside functions (e.g., when
|
|
a function declares a class that has methods). This means that
|
|
when we finish processing a function scope, we may need to go
|
|
back to building a containing block's symbol lists. */
|
|
*cu->get_builder ()->get_local_symbols () = cstk.locals;
|
|
cu->get_builder ()->set_local_using_directives (cstk.local_using_directives);
|
|
|
|
/* If we've finished processing a top-level function, subsequent
|
|
symbols go in the file symbol list. */
|
|
if (cu->get_builder ()->outermost_context_p ())
|
|
cu->list_in_scope = cu->get_builder ()->get_file_symbols ();
|
|
}
|
|
|
|
/* Process all the DIES contained within a lexical block scope. Start
|
|
a new scope, process the dies, and then close the scope. */
|
|
|
|
static void
|
|
read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
CORE_ADDR lowpc, highpc;
|
|
struct die_info *child_die;
|
|
|
|
/* Ignore blocks with missing or invalid low and high pc attributes. */
|
|
/* ??? Perhaps consider discontiguous blocks defined by DW_AT_ranges
|
|
as multiple lexical blocks? Handling children in a sane way would
|
|
be nasty. Might be easier to properly extend generic blocks to
|
|
describe ranges. */
|
|
unrelocated_addr unrel_low, unrel_high;
|
|
switch (dwarf2_get_pc_bounds (die, &unrel_low, &unrel_high, cu,
|
|
nullptr, nullptr))
|
|
{
|
|
case PC_BOUNDS_NOT_PRESENT:
|
|
/* DW_TAG_lexical_block has no attributes, process its children as if
|
|
there was no wrapping by that DW_TAG_lexical_block.
|
|
GCC does no longer produces such DWARF since GCC r224161. */
|
|
for (child_die = die->child;
|
|
child_die != NULL && child_die->tag;
|
|
child_die = child_die->sibling)
|
|
{
|
|
/* We might already be processing this DIE. This can happen
|
|
in an unusual circumstance -- where a subroutine A
|
|
appears lexically in another subroutine B, but A actually
|
|
inlines B. The recursion is broken here, rather than in
|
|
inherit_abstract_dies, because it seems better to simply
|
|
drop concrete children here. */
|
|
if (!child_die->in_process)
|
|
process_die (child_die, cu);
|
|
}
|
|
return;
|
|
case PC_BOUNDS_INVALID:
|
|
return;
|
|
}
|
|
lowpc = per_objfile->relocate (unrel_low);
|
|
highpc = per_objfile->relocate (unrel_high);
|
|
|
|
cu->get_builder ()->push_context (0, lowpc);
|
|
if (die->child != NULL)
|
|
{
|
|
child_die = die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
process_die (child_die, cu);
|
|
child_die = child_die->sibling;
|
|
}
|
|
}
|
|
inherit_abstract_dies (die, cu);
|
|
struct context_stack cstk = cu->get_builder ()->pop_context ();
|
|
|
|
if (*cu->get_builder ()->get_local_symbols () != NULL
|
|
|| (*cu->get_builder ()->get_local_using_directives ()) != NULL)
|
|
{
|
|
struct block *block
|
|
= cu->get_builder ()->finish_block (0, cstk.old_blocks, NULL,
|
|
cstk.start_addr, highpc);
|
|
|
|
/* Note that recording ranges after traversing children, as we
|
|
do here, means that recording a parent's ranges entails
|
|
walking across all its children's ranges as they appear in
|
|
the address map, which is quadratic behavior.
|
|
|
|
It would be nicer to record the parent's ranges before
|
|
traversing its children, simply overriding whatever you find
|
|
there. But since we don't even decide whether to create a
|
|
block until after we've traversed its children, that's hard
|
|
to do. */
|
|
dwarf2_record_block_ranges (die, block, cu);
|
|
}
|
|
*cu->get_builder ()->get_local_symbols () = cstk.locals;
|
|
cu->get_builder ()->set_local_using_directives (cstk.local_using_directives);
|
|
}
|
|
|
|
static void dwarf2_ranges_read_low_addrs
|
|
(unsigned offset,
|
|
struct dwarf2_cu *cu,
|
|
dwarf_tag tag,
|
|
std::vector<unrelocated_addr> &result);
|
|
|
|
/* Read in DW_TAG_call_site and insert it to CU->call_site_htab. */
|
|
|
|
static void
|
|
read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
struct attribute *attr;
|
|
int nparams;
|
|
struct die_info *child_die;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_call_return_pc, cu);
|
|
if (attr == NULL)
|
|
{
|
|
/* This was a pre-DWARF-5 GNU extension alias
|
|
for DW_AT_call_return_pc. */
|
|
attr = dwarf2_attr (die, DW_AT_low_pc, cu);
|
|
}
|
|
if (!attr)
|
|
{
|
|
complaint (_("missing DW_AT_call_return_pc for DW_TAG_call_site "
|
|
"DIE %s [in module %s]"),
|
|
sect_offset_str (die->sect_off), objfile_name (objfile));
|
|
return;
|
|
}
|
|
unrelocated_addr pc = attr->as_address ();
|
|
|
|
/* Count parameters at the caller. */
|
|
|
|
nparams = 0;
|
|
for (child_die = die->child; child_die && child_die->tag;
|
|
child_die = child_die->sibling)
|
|
{
|
|
if (child_die->tag != DW_TAG_call_site_parameter
|
|
&& child_die->tag != DW_TAG_GNU_call_site_parameter)
|
|
{
|
|
complaint (_("Tag %d is not DW_TAG_call_site_parameter in "
|
|
"DW_TAG_call_site child DIE %s [in module %s]"),
|
|
child_die->tag, sect_offset_str (child_die->sect_off),
|
|
objfile_name (objfile));
|
|
continue;
|
|
}
|
|
|
|
nparams++;
|
|
}
|
|
|
|
struct call_site *call_site
|
|
= new (XOBNEWVAR (&objfile->objfile_obstack,
|
|
struct call_site,
|
|
sizeof (*call_site) + sizeof (call_site->parameter[0]) * nparams))
|
|
struct call_site (pc, cu->per_cu, per_objfile);
|
|
|
|
if (!cu->call_site_htab.emplace (call_site).second)
|
|
{
|
|
complaint (_("Duplicate PC %s for DW_TAG_call_site "
|
|
"DIE %s [in module %s]"),
|
|
paddress (gdbarch, (CORE_ADDR) pc), sect_offset_str (die->sect_off),
|
|
objfile_name (objfile));
|
|
return;
|
|
}
|
|
|
|
/* We never call the destructor of call_site, so we must ensure it is
|
|
trivially destructible. */
|
|
static_assert(std::is_trivially_destructible<struct call_site>::value);
|
|
|
|
if (dwarf2_flag_true_p (die, DW_AT_call_tail_call, cu)
|
|
|| dwarf2_flag_true_p (die, DW_AT_GNU_tail_call, cu))
|
|
{
|
|
struct die_info *func_die;
|
|
|
|
/* Skip also over DW_TAG_inlined_subroutine. */
|
|
for (func_die = die->parent;
|
|
func_die && func_die->tag != DW_TAG_subprogram
|
|
&& func_die->tag != DW_TAG_subroutine_type;
|
|
func_die = func_die->parent);
|
|
|
|
/* DW_AT_call_all_calls is a superset
|
|
of DW_AT_call_all_tail_calls. */
|
|
if (func_die
|
|
&& !dwarf2_flag_true_p (func_die, DW_AT_call_all_calls, cu)
|
|
&& !dwarf2_flag_true_p (func_die, DW_AT_GNU_all_call_sites, cu)
|
|
&& !dwarf2_flag_true_p (func_die, DW_AT_call_all_tail_calls, cu)
|
|
&& !dwarf2_flag_true_p (func_die, DW_AT_GNU_all_tail_call_sites, cu))
|
|
{
|
|
/* TYPE_TAIL_CALL_LIST is not interesting in functions where it is
|
|
not complete. But keep CALL_SITE for look ups via call_site_htab,
|
|
both the initial caller containing the real return address PC and
|
|
the final callee containing the current PC of a chain of tail
|
|
calls do not need to have the tail call list complete. But any
|
|
function candidate for a virtual tail call frame searched via
|
|
TYPE_TAIL_CALL_LIST must have the tail call list complete to be
|
|
determined unambiguously. */
|
|
}
|
|
else
|
|
{
|
|
struct type *func_type = NULL;
|
|
|
|
if (func_die)
|
|
func_type = get_die_type (func_die, cu);
|
|
if (func_type != NULL)
|
|
{
|
|
gdb_assert (func_type->code () == TYPE_CODE_FUNC);
|
|
|
|
/* Enlist this call site to the function. */
|
|
call_site->tail_call_next = TYPE_TAIL_CALL_LIST (func_type);
|
|
TYPE_TAIL_CALL_LIST (func_type) = call_site;
|
|
}
|
|
else
|
|
complaint (_("Cannot find function owning DW_TAG_call_site "
|
|
"DIE %s [in module %s]"),
|
|
sect_offset_str (die->sect_off), objfile_name (objfile));
|
|
}
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_call_target, cu);
|
|
if (attr == NULL)
|
|
attr = dwarf2_attr (die, DW_AT_GNU_call_site_target, cu);
|
|
if (attr == NULL)
|
|
attr = dwarf2_attr (die, DW_AT_call_origin, cu);
|
|
if (attr == NULL)
|
|
{
|
|
/* This was a pre-DWARF-5 GNU extension alias for DW_AT_call_origin. */
|
|
attr = dwarf2_attr (die, DW_AT_abstract_origin, cu);
|
|
}
|
|
|
|
call_site->target.set_loc_dwarf_block (nullptr);
|
|
if (!attr || (attr->form_is_block () && attr->as_block ()->size == 0))
|
|
/* Keep NULL DWARF_BLOCK. */;
|
|
else if (attr->form_is_block ())
|
|
{
|
|
struct dwarf2_locexpr_baton *dlbaton;
|
|
struct dwarf_block *block = attr->as_block ();
|
|
|
|
dlbaton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton);
|
|
dlbaton->data = block->data;
|
|
dlbaton->size = block->size;
|
|
dlbaton->per_objfile = per_objfile;
|
|
dlbaton->per_cu = cu->per_cu;
|
|
|
|
call_site->target.set_loc_dwarf_block (dlbaton);
|
|
}
|
|
else if (attr->form_is_ref ())
|
|
{
|
|
struct dwarf2_cu *target_cu = cu;
|
|
struct die_info *target_die;
|
|
|
|
target_die = follow_die_ref (die, attr, &target_cu);
|
|
gdb_assert (target_cu->per_objfile->objfile == objfile);
|
|
|
|
struct attribute *ranges_attr
|
|
= dwarf2_attr (target_die, DW_AT_ranges, target_cu);
|
|
|
|
if (die_is_declaration (target_die, target_cu))
|
|
{
|
|
const char *target_physname;
|
|
|
|
/* Prefer the mangled name; otherwise compute the demangled one. */
|
|
target_physname = dw2_linkage_name (target_die, target_cu);
|
|
if (target_physname == NULL)
|
|
target_physname = dwarf2_physname (NULL, target_die, target_cu);
|
|
if (target_physname == NULL)
|
|
complaint (_("DW_AT_call_target target DIE has invalid "
|
|
"physname, for referencing DIE %s [in module %s]"),
|
|
sect_offset_str (die->sect_off), objfile_name (objfile));
|
|
else
|
|
call_site->target.set_loc_physname (target_physname);
|
|
}
|
|
else if (ranges_attr != nullptr && ranges_attr->form_is_unsigned ())
|
|
{
|
|
ULONGEST ranges_offset = (ranges_attr->as_unsigned ()
|
|
+ target_cu->gnu_ranges_base);
|
|
std::vector<unrelocated_addr> addresses;
|
|
dwarf2_ranges_read_low_addrs (ranges_offset, target_cu,
|
|
target_die->tag, addresses);
|
|
unrelocated_addr *saved = XOBNEWVEC (&objfile->objfile_obstack,
|
|
unrelocated_addr,
|
|
addresses.size ());
|
|
std::copy (addresses.begin (), addresses.end (), saved);
|
|
call_site->target.set_loc_array (addresses.size (), saved);
|
|
}
|
|
else
|
|
{
|
|
unrelocated_addr lowpc;
|
|
|
|
/* DW_AT_entry_pc should be preferred. */
|
|
if (dwarf2_get_pc_bounds (target_die, &lowpc, NULL, target_cu,
|
|
nullptr, nullptr)
|
|
<= PC_BOUNDS_INVALID)
|
|
complaint (_("DW_AT_call_target target DIE has invalid "
|
|
"low pc, for referencing DIE %s [in module %s]"),
|
|
sect_offset_str (die->sect_off), objfile_name (objfile));
|
|
else
|
|
call_site->target.set_loc_physaddr (lowpc);
|
|
}
|
|
}
|
|
else
|
|
complaint (_("DW_TAG_call_site DW_AT_call_target is neither "
|
|
"block nor reference, for DIE %s [in module %s]"),
|
|
sect_offset_str (die->sect_off), objfile_name (objfile));
|
|
|
|
for (child_die = die->child;
|
|
child_die && child_die->tag;
|
|
child_die = child_die->sibling)
|
|
{
|
|
struct call_site_parameter *parameter;
|
|
struct attribute *loc, *origin;
|
|
|
|
if (child_die->tag != DW_TAG_call_site_parameter
|
|
&& child_die->tag != DW_TAG_GNU_call_site_parameter)
|
|
{
|
|
/* Already printed the complaint above. */
|
|
continue;
|
|
}
|
|
|
|
gdb_assert (call_site->parameter_count < nparams);
|
|
parameter = &call_site->parameter[call_site->parameter_count];
|
|
|
|
/* DW_AT_location specifies the register number or DW_AT_abstract_origin
|
|
specifies DW_TAG_formal_parameter. Value of the data assumed for the
|
|
register is contained in DW_AT_call_value. */
|
|
|
|
loc = dwarf2_attr (child_die, DW_AT_location, cu);
|
|
origin = dwarf2_attr (child_die, DW_AT_call_parameter, cu);
|
|
if (origin == NULL)
|
|
{
|
|
/* This was a pre-DWARF-5 GNU extension alias
|
|
for DW_AT_call_parameter. */
|
|
origin = dwarf2_attr (child_die, DW_AT_abstract_origin, cu);
|
|
}
|
|
if (loc == NULL && origin != NULL && origin->form_is_ref ())
|
|
{
|
|
parameter->kind = CALL_SITE_PARAMETER_PARAM_OFFSET;
|
|
|
|
sect_offset sect_off = origin->get_ref_die_offset ();
|
|
if (!cu->header.offset_in_cu_p (sect_off))
|
|
{
|
|
/* As DW_OP_GNU_parameter_ref uses CU-relative offset this
|
|
binding can be done only inside one CU. Such referenced DIE
|
|
therefore cannot be even moved to DW_TAG_partial_unit. */
|
|
complaint (_("DW_AT_call_parameter offset is not in CU for "
|
|
"DW_TAG_call_site child DIE %s [in module %s]"),
|
|
sect_offset_str (child_die->sect_off),
|
|
objfile_name (objfile));
|
|
continue;
|
|
}
|
|
parameter->u.param_cu_off
|
|
= (cu_offset) (sect_off - cu->header.sect_off);
|
|
}
|
|
else if (loc == NULL || origin != NULL || !loc->form_is_block ())
|
|
{
|
|
complaint (_("No DW_FORM_block* DW_AT_location for "
|
|
"DW_TAG_call_site child DIE %s [in module %s]"),
|
|
sect_offset_str (child_die->sect_off), objfile_name (objfile));
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
struct dwarf_block *block = loc->as_block ();
|
|
|
|
parameter->u.dwarf_reg = dwarf_block_to_dwarf_reg
|
|
(block->data, &block->data[block->size]);
|
|
if (parameter->u.dwarf_reg != -1)
|
|
parameter->kind = CALL_SITE_PARAMETER_DWARF_REG;
|
|
else if (dwarf_block_to_sp_offset (gdbarch, block->data,
|
|
&block->data[block->size],
|
|
¶meter->u.fb_offset))
|
|
parameter->kind = CALL_SITE_PARAMETER_FB_OFFSET;
|
|
else
|
|
{
|
|
complaint (_("Only single DW_OP_reg or DW_OP_fbreg is supported "
|
|
"for DW_FORM_block* DW_AT_location is supported for "
|
|
"DW_TAG_call_site child DIE %s "
|
|
"[in module %s]"),
|
|
sect_offset_str (child_die->sect_off),
|
|
objfile_name (objfile));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
attr = dwarf2_attr (child_die, DW_AT_call_value, cu);
|
|
if (attr == NULL)
|
|
attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_value, cu);
|
|
if (attr == NULL || !attr->form_is_block ())
|
|
{
|
|
complaint (_("No DW_FORM_block* DW_AT_call_value for "
|
|
"DW_TAG_call_site child DIE %s [in module %s]"),
|
|
sect_offset_str (child_die->sect_off),
|
|
objfile_name (objfile));
|
|
continue;
|
|
}
|
|
|
|
struct dwarf_block *block = attr->as_block ();
|
|
parameter->value = block->data;
|
|
parameter->value_size = block->size;
|
|
|
|
/* Parameters are not pre-cleared by memset above. */
|
|
parameter->data_value = NULL;
|
|
parameter->data_value_size = 0;
|
|
call_site->parameter_count++;
|
|
|
|
attr = dwarf2_attr (child_die, DW_AT_call_data_value, cu);
|
|
if (attr == NULL)
|
|
attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_data_value, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
if (!attr->form_is_block ())
|
|
complaint (_("No DW_FORM_block* DW_AT_call_data_value for "
|
|
"DW_TAG_call_site child DIE %s [in module %s]"),
|
|
sect_offset_str (child_die->sect_off),
|
|
objfile_name (objfile));
|
|
else
|
|
{
|
|
block = attr->as_block ();
|
|
parameter->data_value = block->data;
|
|
parameter->data_value_size = block->size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Helper function for read_variable. If DIE represents a virtual
|
|
table, then return the type of the concrete object that is
|
|
associated with the virtual table. Otherwise, return NULL. */
|
|
|
|
static struct type *
|
|
rust_containing_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr = dwarf2_attr (die, DW_AT_type, cu);
|
|
if (attr == NULL)
|
|
return NULL;
|
|
|
|
/* Find the type DIE. */
|
|
struct die_info *type_die = NULL;
|
|
struct dwarf2_cu *type_cu = cu;
|
|
|
|
if (attr->form_is_ref ())
|
|
type_die = follow_die_ref (die, attr, &type_cu);
|
|
if (type_die == NULL)
|
|
return NULL;
|
|
|
|
if (dwarf2_attr (type_die, DW_AT_containing_type, type_cu) == NULL)
|
|
return NULL;
|
|
return die_containing_type (type_die, type_cu);
|
|
}
|
|
|
|
/* Read a variable (DW_TAG_variable) DIE and create a new symbol. */
|
|
|
|
static void
|
|
read_variable (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct rust_vtable_symbol *storage = NULL;
|
|
|
|
if (cu->lang () == language_rust)
|
|
{
|
|
struct type *containing_type = rust_containing_type (die, cu);
|
|
|
|
if (containing_type != NULL)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
|
|
storage = new (&objfile->objfile_obstack) rust_vtable_symbol;
|
|
storage->concrete_type = containing_type;
|
|
storage->subclass = SYMBOL_RUST_VTABLE;
|
|
}
|
|
}
|
|
|
|
struct symbol *res = new_symbol (die, NULL, cu, storage);
|
|
struct attribute *abstract_origin
|
|
= dwarf2_attr (die, DW_AT_abstract_origin, cu);
|
|
struct attribute *loc = dwarf2_attr (die, DW_AT_location, cu);
|
|
if (res == NULL && loc && abstract_origin)
|
|
{
|
|
/* We have a variable without a name, but with a location and an abstract
|
|
origin. This may be a concrete instance of an abstract variable
|
|
referenced from an DW_OP_GNU_variable_value, so save it to find it back
|
|
later. */
|
|
struct dwarf2_cu *origin_cu = cu;
|
|
struct die_info *origin_die
|
|
= follow_die_ref (die, abstract_origin, &origin_cu);
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
per_objfile->per_bfd->abstract_to_concrete
|
|
[origin_die->sect_off].push_back (die->sect_off);
|
|
}
|
|
}
|
|
|
|
/* Call CALLBACK from DW_AT_ranges attribute value OFFSET
|
|
reading .debug_rnglists.
|
|
Callback's type should be:
|
|
void (CORE_ADDR range_beginning, CORE_ADDR range_end)
|
|
Return true if the attributes are present and valid, otherwise,
|
|
return false. */
|
|
|
|
template <typename Callback>
|
|
static bool
|
|
dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
|
|
dwarf_tag tag, Callback &&callback)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
bfd *obfd = objfile->obfd.get ();
|
|
/* Base address selection entry. */
|
|
std::optional<unrelocated_addr> base;
|
|
const gdb_byte *buffer;
|
|
bool overflow = false;
|
|
ULONGEST addr_index;
|
|
struct dwarf2_section_info *rnglists_section;
|
|
|
|
base = cu->base_address;
|
|
rnglists_section = cu_debug_rnglists_section (cu, tag);
|
|
rnglists_section->read (objfile);
|
|
|
|
if (offset >= rnglists_section->size)
|
|
{
|
|
complaint (_("Offset %d out of bounds for DW_AT_ranges attribute"),
|
|
offset);
|
|
return false;
|
|
}
|
|
buffer = rnglists_section->buffer + offset;
|
|
|
|
while (1)
|
|
{
|
|
/* Initialize it due to a false compiler warning. */
|
|
unrelocated_addr range_beginning = {}, range_end = {};
|
|
const gdb_byte *buf_end = (rnglists_section->buffer
|
|
+ rnglists_section->size);
|
|
unsigned int bytes_read;
|
|
|
|
if (buffer == buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
const auto rlet = static_cast<enum dwarf_range_list_entry>(*buffer++);
|
|
switch (rlet)
|
|
{
|
|
case DW_RLE_end_of_list:
|
|
break;
|
|
case DW_RLE_base_address:
|
|
if (buffer + cu->header.addr_size > buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
base = cu->header.read_address (obfd, buffer, &bytes_read);
|
|
buffer += bytes_read;
|
|
break;
|
|
case DW_RLE_base_addressx:
|
|
addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
|
|
buffer += bytes_read;
|
|
base = read_addr_index (cu, addr_index);
|
|
break;
|
|
case DW_RLE_start_length:
|
|
if (buffer + cu->header.addr_size > buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
range_beginning = cu->header.read_address (obfd, buffer,
|
|
&bytes_read);
|
|
buffer += bytes_read;
|
|
range_end
|
|
= (unrelocated_addr) ((CORE_ADDR) range_beginning
|
|
+ read_unsigned_leb128 (obfd, buffer,
|
|
&bytes_read));
|
|
buffer += bytes_read;
|
|
if (buffer > buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
break;
|
|
case DW_RLE_startx_length:
|
|
addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
|
|
buffer += bytes_read;
|
|
range_beginning = read_addr_index (cu, addr_index);
|
|
if (buffer > buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
range_end
|
|
= (unrelocated_addr) ((CORE_ADDR) range_beginning
|
|
+ read_unsigned_leb128 (obfd, buffer,
|
|
&bytes_read));
|
|
buffer += bytes_read;
|
|
break;
|
|
case DW_RLE_offset_pair:
|
|
range_beginning = (unrelocated_addr) read_unsigned_leb128 (obfd, buffer,
|
|
&bytes_read);
|
|
buffer += bytes_read;
|
|
if (buffer > buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
range_end = (unrelocated_addr) read_unsigned_leb128 (obfd, buffer,
|
|
&bytes_read);
|
|
buffer += bytes_read;
|
|
if (buffer > buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
break;
|
|
case DW_RLE_start_end:
|
|
if (buffer + 2 * cu->header.addr_size > buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
range_beginning = cu->header.read_address (obfd, buffer,
|
|
&bytes_read);
|
|
buffer += bytes_read;
|
|
range_end = cu->header.read_address (obfd, buffer, &bytes_read);
|
|
buffer += bytes_read;
|
|
break;
|
|
case DW_RLE_startx_endx:
|
|
addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
|
|
buffer += bytes_read;
|
|
range_beginning = read_addr_index (cu, addr_index);
|
|
if (buffer > buf_end)
|
|
{
|
|
overflow = true;
|
|
break;
|
|
}
|
|
addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
|
|
buffer += bytes_read;
|
|
range_end = read_addr_index (cu, addr_index);
|
|
break;
|
|
default:
|
|
complaint (_("Invalid .debug_rnglists data (no base address)"));
|
|
return false;
|
|
}
|
|
if (rlet == DW_RLE_end_of_list || overflow)
|
|
break;
|
|
if (rlet == DW_RLE_base_address)
|
|
continue;
|
|
|
|
if (range_beginning > range_end)
|
|
{
|
|
/* Inverted range entries are invalid. */
|
|
complaint (_("Invalid .debug_rnglists data (inverted range)"));
|
|
return false;
|
|
}
|
|
|
|
/* Empty range entries have no effect. */
|
|
if (range_beginning == range_end)
|
|
continue;
|
|
|
|
/* Only DW_RLE_offset_pair needs the base address added. */
|
|
if (rlet == DW_RLE_offset_pair)
|
|
{
|
|
if (!base.has_value ())
|
|
{
|
|
/* We have no valid base address for the DW_RLE_offset_pair. */
|
|
complaint (_("Invalid .debug_rnglists data (no base address for "
|
|
"DW_RLE_offset_pair)"));
|
|
return false;
|
|
}
|
|
|
|
range_beginning = (unrelocated_addr) ((CORE_ADDR) range_beginning
|
|
+ (CORE_ADDR) *base);
|
|
range_end = (unrelocated_addr) ((CORE_ADDR) range_end
|
|
+ (CORE_ADDR) *base);
|
|
}
|
|
|
|
/* A not-uncommon case of bad debug info.
|
|
Don't pollute the addrmap with bad data. */
|
|
if (range_beginning == (unrelocated_addr) 0
|
|
&& !per_objfile->per_bfd->has_section_at_zero)
|
|
{
|
|
complaint (_(".debug_rnglists entry has start address of zero"
|
|
" [in module %s]"), objfile_name (objfile));
|
|
continue;
|
|
}
|
|
|
|
callback (range_beginning, range_end);
|
|
}
|
|
|
|
if (overflow)
|
|
{
|
|
complaint (_("Offset %d is not terminated "
|
|
"for DW_AT_ranges attribute"),
|
|
offset);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Call CALLBACK from DW_AT_ranges attribute value OFFSET reading .debug_ranges.
|
|
Callback's type should be:
|
|
void (unrelocated_addr range_beginning, unrelocated_addr range_end)
|
|
Return 1 if the attributes are present and valid, otherwise, return 0. */
|
|
|
|
template <typename Callback>
|
|
static int
|
|
dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu, dwarf_tag tag,
|
|
Callback &&callback)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct comp_unit_head *cu_header = &cu->header;
|
|
bfd *obfd = objfile->obfd.get ();
|
|
unsigned int addr_size = cu_header->addr_size;
|
|
CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
|
|
/* Base address selection entry. */
|
|
std::optional<unrelocated_addr> base;
|
|
unsigned int dummy;
|
|
const gdb_byte *buffer;
|
|
|
|
if (cu_header->version >= 5)
|
|
return dwarf2_rnglists_process (offset, cu, tag, callback);
|
|
|
|
base = cu->base_address;
|
|
|
|
per_objfile->per_bfd->ranges.read (objfile);
|
|
if (offset >= per_objfile->per_bfd->ranges.size)
|
|
{
|
|
complaint (_("Offset %d out of bounds for DW_AT_ranges attribute"),
|
|
offset);
|
|
return 0;
|
|
}
|
|
buffer = per_objfile->per_bfd->ranges.buffer + offset;
|
|
|
|
while (1)
|
|
{
|
|
unrelocated_addr range_beginning, range_end;
|
|
|
|
range_beginning = cu->header.read_address (obfd, buffer, &dummy);
|
|
buffer += addr_size;
|
|
range_end = cu->header.read_address (obfd, buffer, &dummy);
|
|
buffer += addr_size;
|
|
offset += 2 * addr_size;
|
|
|
|
/* An end of list marker is a pair of zero addresses. */
|
|
if (range_beginning == (unrelocated_addr) 0
|
|
&& range_end == (unrelocated_addr) 0)
|
|
/* Found the end of list entry. */
|
|
break;
|
|
|
|
/* Each base address selection entry is a pair of 2 values.
|
|
The first is the largest possible address, the second is
|
|
the base address. Check for a base address here. */
|
|
if (((CORE_ADDR) range_beginning & mask) == mask)
|
|
{
|
|
/* If we found the largest possible address, then we already
|
|
have the base address in range_end. */
|
|
base = range_end;
|
|
continue;
|
|
}
|
|
|
|
if (!base.has_value ())
|
|
{
|
|
/* We have no valid base address for the ranges
|
|
data. */
|
|
complaint (_("Invalid .debug_ranges data (no base address)"));
|
|
return 0;
|
|
}
|
|
|
|
if (range_beginning > range_end)
|
|
{
|
|
/* Inverted range entries are invalid. */
|
|
complaint (_("Invalid .debug_ranges data (inverted range)"));
|
|
return 0;
|
|
}
|
|
|
|
/* Empty range entries have no effect. */
|
|
if (range_beginning == range_end)
|
|
continue;
|
|
|
|
range_beginning = (unrelocated_addr) ((CORE_ADDR) range_beginning
|
|
+ (CORE_ADDR) *base);
|
|
range_end = (unrelocated_addr) ((CORE_ADDR) range_end
|
|
+ (CORE_ADDR) *base);
|
|
|
|
/* A not-uncommon case of bad debug info.
|
|
Don't pollute the addrmap with bad data. */
|
|
if (range_beginning == (unrelocated_addr) 0
|
|
&& !per_objfile->per_bfd->has_section_at_zero)
|
|
{
|
|
complaint (_(".debug_ranges entry has start address of zero"
|
|
" [in module %s]"), objfile_name (objfile));
|
|
continue;
|
|
}
|
|
|
|
callback (range_beginning, range_end);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Get low and high pc attributes from DW_AT_ranges attribute value OFFSET.
|
|
Return 1 if the attributes are present and valid, otherwise, return 0.
|
|
TAG is passed to dwarf2_ranges_process. If MAP is not NULL, then
|
|
ranges in MAP are set, using DATUM as the value. */
|
|
|
|
static int
|
|
dwarf2_ranges_read (unsigned offset, unrelocated_addr *low_return,
|
|
unrelocated_addr *high_return, struct dwarf2_cu *cu,
|
|
addrmap_mutable *map, void *datum, dwarf_tag tag)
|
|
{
|
|
int low_set = 0;
|
|
unrelocated_addr low = {};
|
|
unrelocated_addr high = {};
|
|
int retval;
|
|
|
|
retval = dwarf2_ranges_process (offset, cu, tag,
|
|
[&] (unrelocated_addr range_beginning, unrelocated_addr range_end)
|
|
{
|
|
if (map != nullptr)
|
|
{
|
|
/* addrmap only accepts CORE_ADDR, so we must cast here. */
|
|
map->set_empty ((CORE_ADDR) range_beginning,
|
|
(CORE_ADDR) range_end - 1,
|
|
datum);
|
|
}
|
|
|
|
/* FIXME: This is recording everything as a low-high
|
|
segment of consecutive addresses. We should have a
|
|
data structure for discontiguous block ranges
|
|
instead. */
|
|
if (! low_set)
|
|
{
|
|
low = range_beginning;
|
|
high = range_end;
|
|
low_set = 1;
|
|
}
|
|
else
|
|
{
|
|
if (range_beginning < low)
|
|
low = range_beginning;
|
|
if (range_end > high)
|
|
high = range_end;
|
|
}
|
|
});
|
|
if (!retval)
|
|
return 0;
|
|
|
|
if (! low_set)
|
|
/* If the first entry is an end-of-list marker, the range
|
|
describes an empty scope, i.e. no instructions. */
|
|
return 0;
|
|
|
|
if (low_return)
|
|
*low_return = low;
|
|
if (high_return)
|
|
*high_return = high;
|
|
return 1;
|
|
}
|
|
|
|
/* Process ranges and fill in a vector of the low PC values only. */
|
|
|
|
static void
|
|
dwarf2_ranges_read_low_addrs (unsigned offset, struct dwarf2_cu *cu,
|
|
dwarf_tag tag,
|
|
std::vector<unrelocated_addr> &result)
|
|
{
|
|
dwarf2_ranges_process (offset, cu, tag,
|
|
[&] (unrelocated_addr start, unrelocated_addr end)
|
|
{
|
|
result.push_back (start);
|
|
});
|
|
}
|
|
|
|
/* Determine the low and high pc of a DW_TAG_entry_point. */
|
|
|
|
static pc_bounds_kind
|
|
dwarf2_get_pc_bounds_entry_point (die_info *die, unrelocated_addr *low,
|
|
unrelocated_addr *high, dwarf2_cu *cu)
|
|
{
|
|
gdb_assert (low != nullptr);
|
|
gdb_assert (high != nullptr);
|
|
|
|
if (die->parent->tag != DW_TAG_subprogram)
|
|
{
|
|
complaint (_("DW_TAG_entry_point not embedded in DW_TAG_subprogram"));
|
|
return PC_BOUNDS_INVALID;
|
|
}
|
|
|
|
/* A DW_TAG_entry_point is embedded in an subprogram. Therefore, we can use
|
|
the highpc from its enveloping subprogram and get the lowpc from
|
|
DWARF. */
|
|
const enum pc_bounds_kind bounds_kind = dwarf2_get_pc_bounds (die->parent,
|
|
low, high,
|
|
cu, nullptr,
|
|
nullptr);
|
|
if (bounds_kind == PC_BOUNDS_INVALID || bounds_kind == PC_BOUNDS_NOT_PRESENT)
|
|
return bounds_kind;
|
|
|
|
attribute *attr_low = dwarf2_attr (die, DW_AT_low_pc, cu);
|
|
if (!attr_low)
|
|
{
|
|
complaint (_("DW_TAG_entry_point is missing DW_AT_low_pc"));
|
|
return PC_BOUNDS_INVALID;
|
|
}
|
|
*low = attr_low->as_address ();
|
|
return bounds_kind;
|
|
}
|
|
|
|
/* Determine the low and high pc using the DW_AT_low_pc and DW_AT_high_pc or
|
|
DW_AT_ranges attributes of a DIE. */
|
|
|
|
static pc_bounds_kind
|
|
dwarf_get_pc_bounds_ranges_or_highlow_pc (die_info *die, unrelocated_addr *low,
|
|
unrelocated_addr *high, dwarf2_cu *cu,
|
|
addrmap_mutable *map, void *datum)
|
|
{
|
|
gdb_assert (low != nullptr);
|
|
gdb_assert (high != nullptr);
|
|
|
|
struct attribute *attr;
|
|
struct attribute *attr_high;
|
|
enum pc_bounds_kind ret;
|
|
|
|
attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);
|
|
if (attr_high)
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_low_pc, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
*low = attr->as_address ();
|
|
*high = attr_high->as_address ();
|
|
if (cu->header.version >= 4 && attr_high->form_is_constant ())
|
|
*high = (unrelocated_addr) ((ULONGEST) *high + (ULONGEST) *low);
|
|
|
|
/* Found consecutive range of addresses. */
|
|
ret = PC_BOUNDS_HIGH_LOW;
|
|
}
|
|
else
|
|
{
|
|
/* Found high w/o low attribute. */
|
|
ret = PC_BOUNDS_INVALID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_ranges, cu);
|
|
if (attr != nullptr && attr->form_is_unsigned ())
|
|
{
|
|
/* Offset in the .debug_ranges or .debug_rnglist section (depending
|
|
on DWARF version). */
|
|
ULONGEST ranges_offset = attr->as_unsigned ();
|
|
|
|
/* See dwarf2_cu::gnu_ranges_base's doc for why we might want to add
|
|
this value. */
|
|
if (die->tag != DW_TAG_compile_unit)
|
|
ranges_offset += cu->gnu_ranges_base;
|
|
|
|
/* Value of the DW_AT_ranges attribute is the offset in the
|
|
.debug_ranges section. */
|
|
if (!dwarf2_ranges_read (ranges_offset, low, high, cu,
|
|
map, datum, die->tag))
|
|
return PC_BOUNDS_INVALID;
|
|
/* Found discontinuous range of addresses. */
|
|
ret = PC_BOUNDS_RANGES;
|
|
}
|
|
else
|
|
{
|
|
/* Could not find high_pc or ranges attributed and thus no bounds
|
|
pair. */
|
|
ret = PC_BOUNDS_NOT_PRESENT;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Get low and high pc attributes from a die. See enum pc_bounds_kind
|
|
definition for the return value. *LOWPC and *HIGHPC are set iff
|
|
neither PC_BOUNDS_NOT_PRESENT nor PC_BOUNDS_INVALID are returned. */
|
|
|
|
static enum pc_bounds_kind
|
|
dwarf2_get_pc_bounds (struct die_info *die, unrelocated_addr *lowpc,
|
|
unrelocated_addr *highpc, struct dwarf2_cu *cu,
|
|
addrmap_mutable *map, void *datum)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
unrelocated_addr low = {};
|
|
unrelocated_addr high = {};
|
|
enum pc_bounds_kind ret;
|
|
|
|
if (die->tag == DW_TAG_entry_point)
|
|
ret = dwarf2_get_pc_bounds_entry_point (die, &low, &high, cu);
|
|
else
|
|
ret = dwarf_get_pc_bounds_ranges_or_highlow_pc (die, &low, &high, cu, map,
|
|
datum);
|
|
|
|
if (ret == PC_BOUNDS_NOT_PRESENT || ret == PC_BOUNDS_INVALID)
|
|
return ret;
|
|
|
|
/* partial_die_info::read has also the strict LOW < HIGH requirement. */
|
|
if (high <= low)
|
|
return PC_BOUNDS_INVALID;
|
|
|
|
/* When using the GNU linker, .gnu.linkonce. sections are used to
|
|
eliminate duplicate copies of functions and vtables and such.
|
|
The linker will arbitrarily choose one and discard the others.
|
|
The AT_*_pc values for such functions refer to local labels in
|
|
these sections. If the section from that file was discarded, the
|
|
labels are not in the output, so the relocs get a value of 0.
|
|
If this is a discarded function, mark the pc bounds as invalid,
|
|
so that GDB will ignore it. */
|
|
if (low == (unrelocated_addr) 0
|
|
&& !per_objfile->per_bfd->has_section_at_zero)
|
|
return PC_BOUNDS_INVALID;
|
|
|
|
gdb_assert (lowpc != nullptr);
|
|
*lowpc = low;
|
|
if (highpc != nullptr)
|
|
*highpc = high;
|
|
return ret;
|
|
}
|
|
|
|
/* Assuming that DIE represents a subprogram DIE or a lexical block, get
|
|
its low and high PC addresses. Do nothing if these addresses could not
|
|
be determined. Otherwise, set LOWPC to the low address if it is smaller,
|
|
and HIGHPC to the high address if greater than HIGHPC. */
|
|
|
|
static void
|
|
dwarf2_get_subprogram_pc_bounds (struct die_info *die,
|
|
unrelocated_addr *lowpc,
|
|
unrelocated_addr *highpc,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
unrelocated_addr low, high;
|
|
struct die_info *child = die->child;
|
|
|
|
if (dwarf2_get_pc_bounds (die, &low, &high, cu, nullptr, nullptr)
|
|
>= PC_BOUNDS_RANGES)
|
|
{
|
|
*lowpc = std::min (*lowpc, low);
|
|
*highpc = std::max (*highpc, high);
|
|
}
|
|
|
|
/* If the language does not allow nested subprograms (either inside
|
|
subprograms or lexical blocks), we're done. */
|
|
if (cu->lang () != language_ada)
|
|
return;
|
|
|
|
/* Check all the children of the given DIE. If it contains nested
|
|
subprograms, then check their pc bounds. Likewise, we need to
|
|
check lexical blocks as well, as they may also contain subprogram
|
|
definitions. */
|
|
while (child && child->tag)
|
|
{
|
|
if (child->tag == DW_TAG_subprogram
|
|
|| child->tag == DW_TAG_lexical_block)
|
|
dwarf2_get_subprogram_pc_bounds (child, lowpc, highpc, cu);
|
|
child = child->sibling;
|
|
}
|
|
}
|
|
|
|
/* Get the low and high pc's represented by the scope DIE, and store
|
|
them in *LOWPC and *HIGHPC. If the correct values can't be
|
|
determined, set *LOWPC to -1 and *HIGHPC to 0. */
|
|
|
|
static void
|
|
get_scope_pc_bounds (struct die_info *die,
|
|
unrelocated_addr *lowpc, unrelocated_addr *highpc,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
unrelocated_addr best_low = (unrelocated_addr) -1;
|
|
unrelocated_addr best_high = {};
|
|
unrelocated_addr current_low, current_high;
|
|
|
|
if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_high, cu,
|
|
nullptr, nullptr)
|
|
>= PC_BOUNDS_RANGES)
|
|
{
|
|
best_low = current_low;
|
|
best_high = current_high;
|
|
}
|
|
else
|
|
{
|
|
struct die_info *child = die->child;
|
|
|
|
while (child && child->tag)
|
|
{
|
|
switch (child->tag) {
|
|
case DW_TAG_subprogram:
|
|
dwarf2_get_subprogram_pc_bounds (child, &best_low, &best_high, cu);
|
|
break;
|
|
case DW_TAG_namespace:
|
|
case DW_TAG_module:
|
|
/* FIXME: carlton/2004-01-16: Should we do this for
|
|
DW_TAG_class_type/DW_TAG_structure_type, too? I think
|
|
that current GCC's always emit the DIEs corresponding
|
|
to definitions of methods of classes as children of a
|
|
DW_TAG_compile_unit or DW_TAG_namespace (as opposed to
|
|
the DIEs giving the declarations, which could be
|
|
anywhere). But I don't see any reason why the
|
|
standards says that they have to be there. */
|
|
get_scope_pc_bounds (child, ¤t_low, ¤t_high, cu);
|
|
|
|
if (current_low != ((unrelocated_addr) -1))
|
|
{
|
|
best_low = std::min (best_low, current_low);
|
|
best_high = std::max (best_high, current_high);
|
|
}
|
|
break;
|
|
default:
|
|
/* Ignore. */
|
|
break;
|
|
}
|
|
|
|
child = child->sibling;
|
|
}
|
|
}
|
|
|
|
*lowpc = best_low;
|
|
*highpc = best_high;
|
|
}
|
|
|
|
/* Return the base address for DIE (which is represented by BLOCK) within
|
|
CU. The base address is the DW_AT_low_pc, or if that is not present,
|
|
the first address in the first range defined by DW_AT_ranges.
|
|
|
|
The DWARF standard actually says that if DIE has neither DW_AT_low_pc or
|
|
DW_AT_ranges then we should search in the parent of DIE for those
|
|
properties, and so on up the hierarchy, until we find a die with one of
|
|
those attributes, and use that as the base address. We don't implement
|
|
that yet simply because we've never encountered a need for it. */
|
|
|
|
static std::optional<CORE_ADDR>
|
|
dwarf2_die_base_address (struct die_info *die, struct block *block,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
struct attribute *attr = dwarf2_attr (die, DW_AT_low_pc, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
CORE_ADDR res = per_objfile->relocate (attr->as_address ());
|
|
fixup_low_high_pc (cu, die, &res, nullptr);
|
|
return res;
|
|
}
|
|
else if (block->ranges ().size () > 0)
|
|
return block->ranges ()[0].start ();
|
|
|
|
return {};
|
|
}
|
|
|
|
/* Return true if ADDR is within any of the ranges covered by BLOCK. If
|
|
there are no sub-ranges then just check against the block's start and
|
|
end addresses, otherwise, check each sub-range covered by the block. */
|
|
|
|
static bool
|
|
dwarf2_addr_in_block_ranges (CORE_ADDR addr, struct block *block)
|
|
{
|
|
if (block->ranges ().size () == 0)
|
|
return addr >= block->start () && addr < block->end ();
|
|
|
|
/* Check if ADDR is within any of the block's sub-ranges. */
|
|
for (const blockrange &br : block->ranges ())
|
|
{
|
|
if (addr >= br.start () && addr < br.end ())
|
|
return true;
|
|
}
|
|
|
|
/* ADDR is not within any of the block's sub-ranges. */
|
|
return false;
|
|
}
|
|
|
|
|
|
/* Set the entry PC for BLOCK which represents DIE from CU. Relies on the
|
|
range information (if present) already having been read from DIE and
|
|
stored into BLOCK. */
|
|
|
|
static void
|
|
dwarf2_record_block_entry_pc (struct die_info *die, struct block *block,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
/* Filled with the entry-pc if we can find it. */
|
|
std::optional<CORE_ADDR> entry;
|
|
|
|
/* Set the block's entry PC where possible. */
|
|
struct attribute *attr = dwarf2_attr (die, DW_AT_entry_pc, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
/* DWARF-5 allows for the DW_AT_entry_pc to be an unsigned constant
|
|
offset from the containing DIE's base address. We don't limit the
|
|
constant handling to DWARF-5 though. If a broken compiler emits
|
|
this for DWARF-4 then we handle it just as we would for DWARF-5. */
|
|
if (attr->form_is_constant ())
|
|
{
|
|
if (attr->form_is_unsigned ())
|
|
{
|
|
CORE_ADDR offset = attr->as_unsigned ();
|
|
|
|
std::optional<CORE_ADDR> base
|
|
= dwarf2_die_base_address (die, block, cu);
|
|
|
|
if (base.has_value ())
|
|
entry.emplace (base.value () + offset);
|
|
}
|
|
else
|
|
{
|
|
/* We could possibly handle signed constants, but this is out
|
|
of spec, so for now, just complain and ignore it. */
|
|
complaint (_("Unhandled constant for DW_AT_entry_pc, value (%s)"),
|
|
plongest (attr->as_nonnegative ()));
|
|
}
|
|
}
|
|
else
|
|
entry.emplace (per_objfile->relocate (attr->as_address ()));
|
|
}
|
|
else
|
|
entry = dwarf2_die_base_address (die, block, cu);
|
|
|
|
if (entry.has_value ())
|
|
{
|
|
CORE_ADDR entry_pc = entry.value ();
|
|
|
|
/* Some compilers (e.g. GCC) will have the DW_AT_entry_pc point at an
|
|
empty sub-range, which by a strict reading of the DWARF means that
|
|
the entry-pc is outside the blocks code range. If we continue
|
|
using this address then GDB will confuse itself, breakpoints will
|
|
be placed at the entry-pc, but once stopped there, GDB will not
|
|
recognise that it is inside this block.
|
|
|
|
To avoid this, ignore entry-pc values that are outside the block's
|
|
range, GDB will then select a suitable default entry-pc. */
|
|
if (dwarf2_addr_in_block_ranges (entry_pc, block))
|
|
block->set_entry_pc (entry_pc);
|
|
else
|
|
complaint (_("in %s, DIE %s, DW_AT_entry_pc (%s) outside "
|
|
"block range (%s -> %s)"),
|
|
objfile_name (per_objfile->objfile),
|
|
sect_offset_str (die->sect_off),
|
|
paddress (per_objfile->objfile->arch (), entry_pc),
|
|
paddress (per_objfile->objfile->arch (), block->start ()),
|
|
paddress (per_objfile->objfile->arch (), block->end ()));
|
|
}
|
|
}
|
|
|
|
/* Record the address ranges for BLOCK, offset by BASEADDR, as given
|
|
in DIE. Also set the entry PC for BLOCK. */
|
|
|
|
static void
|
|
dwarf2_record_block_ranges (struct die_info *die, struct block *block,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct attribute *attr;
|
|
struct attribute *attr_high;
|
|
|
|
/* Like dwarf_get_pc_bounds_ranges_or_highlow_pc, we read either the
|
|
low/high pc attributes, OR the ranges attribute, but not both. If we
|
|
parse both here then we open up the possibility that, due to invalid
|
|
DWARF, a block's start() and end() might not contain all of the ranges.
|
|
|
|
We have seen this in the wild with older (pre v9) versions of GCC. In
|
|
this case a GCC bug meant that a DIE was linked via DW_AT_abstract_origin
|
|
to the wrong DIE. Instead of pointing at the abstract DIE, GCC was
|
|
linking one instance DIE to an earlier instance DIE. The first instance
|
|
DIE had low/high pc attributes, while the second instance DIE had a
|
|
ranges attribute. When processing the incorrectly linked instance GDB
|
|
would see a DIE with both a low/high pc and some ranges data. However,
|
|
the ranges data was all outside the low/high range, which would trigger
|
|
asserts when setting the entry-pc. */
|
|
|
|
attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);
|
|
if (attr_high)
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_low_pc, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
unrelocated_addr unrel_low = attr->as_address ();
|
|
unrelocated_addr unrel_high = attr_high->as_address ();
|
|
|
|
if (cu->header.version >= 4 && attr_high->form_is_constant ())
|
|
unrel_high = (unrelocated_addr) ((ULONGEST) unrel_high
|
|
+ (ULONGEST) unrel_low);
|
|
|
|
CORE_ADDR low = per_objfile->relocate (unrel_low);
|
|
CORE_ADDR high = per_objfile->relocate (unrel_high);
|
|
fixup_low_high_pc (cu, die, &low, &high);
|
|
cu->get_builder ()->record_block_range (block, low, high - 1);
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_ranges, cu);
|
|
if (attr != nullptr && attr->form_is_unsigned ())
|
|
complaint (_("in %s, DIE %s, DW_AT_ranges ignored due to DW_AT_low_pc"),
|
|
objfile_name (per_objfile->objfile),
|
|
sect_offset_str (die->sect_off));
|
|
}
|
|
else
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_ranges, cu);
|
|
if (attr != nullptr && attr->form_is_unsigned ())
|
|
{
|
|
/* Offset in the .debug_ranges or .debug_rnglist section (depending
|
|
on DWARF version). */
|
|
ULONGEST ranges_offset = attr->as_unsigned ();
|
|
|
|
/* See dwarf2_cu::gnu_ranges_base's doc for why we might want to add
|
|
this value. */
|
|
if (die->tag != DW_TAG_compile_unit)
|
|
ranges_offset += cu->gnu_ranges_base;
|
|
|
|
std::vector<blockrange> blockvec;
|
|
dwarf2_ranges_process (ranges_offset, cu, die->tag,
|
|
[&] (unrelocated_addr start,
|
|
unrelocated_addr end)
|
|
{
|
|
CORE_ADDR abs_start = per_objfile->relocate (start);
|
|
CORE_ADDR abs_end = per_objfile->relocate (end);
|
|
cu->get_builder ()->record_block_range (block, abs_start,
|
|
abs_end - 1);
|
|
blockvec.emplace_back (abs_start, abs_end);
|
|
});
|
|
|
|
block->set_ranges (make_blockranges (objfile, blockvec));
|
|
}
|
|
}
|
|
|
|
dwarf2_record_block_entry_pc (die, block, cu);
|
|
}
|
|
|
|
/* Check whether the producer field indicates either of GCC < 4.6, or the
|
|
Intel C/C++ compiler, and cache the result in CU. */
|
|
|
|
static void
|
|
check_producer (struct dwarf2_cu *cu)
|
|
{
|
|
int major, minor;
|
|
|
|
if (cu->producer == NULL)
|
|
{
|
|
/* For unknown compilers expect their behavior is DWARF version
|
|
compliant.
|
|
|
|
GCC started to support .debug_types sections by -gdwarf-4 since
|
|
gcc-4.5.x. As the .debug_types sections are missing DW_AT_producer
|
|
for their space efficiency GDB cannot workaround gcc-4.5.x -gdwarf-4
|
|
combination. gcc-4.5.x -gdwarf-4 binaries have DW_AT_accessibility
|
|
interpreted incorrectly by GDB now - GCC PR debug/48229. */
|
|
}
|
|
else if (producer_is_gcc (cu->producer, &major, &minor))
|
|
{
|
|
cu->producer_is_gxx_lt_4_6 = major < 4 || (major == 4 && minor < 6);
|
|
cu->producer_is_gcc_lt_4_3 = major < 4 || (major == 4 && minor < 3);
|
|
cu->producer_is_gcc_11 = major == 11;
|
|
}
|
|
else if (producer_is_icc (cu->producer, &major, &minor))
|
|
{
|
|
cu->producer_is_icc = true;
|
|
cu->producer_is_icc_lt_14 = major < 14;
|
|
}
|
|
else if (startswith (cu->producer, "CodeWarrior S12/L-ISA"))
|
|
cu->producer_is_codewarrior = true;
|
|
else if (producer_is_clang (cu->producer, &major, &minor))
|
|
cu->producer_is_clang = true;
|
|
else if (producer_is_gas (cu->producer, &major, &minor))
|
|
{
|
|
cu->producer_is_gas_lt_2_38 = major < 2 || (major == 2 && minor < 38);
|
|
cu->producer_is_gas_2_39 = major == 2 && minor == 39;
|
|
cu->producer_is_gas_ge_2_40 = major > 2 || (major == 2 && minor >= 40);
|
|
}
|
|
else
|
|
{
|
|
/* For other non-GCC compilers, expect their behavior is DWARF version
|
|
compliant. */
|
|
}
|
|
|
|
cu->checked_producer = true;
|
|
}
|
|
|
|
/* Check for GCC PR debug/45124 fix which is not present in any G++ version up
|
|
to 4.5.any while it is present already in G++ 4.6.0 - the PR has been fixed
|
|
during 4.6.0 experimental. */
|
|
|
|
static bool
|
|
producer_is_gxx_lt_4_6 (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_gxx_lt_4_6;
|
|
}
|
|
|
|
|
|
/* Codewarrior (at least as of version 5.0.40) generates dwarf line information
|
|
with incorrect is_stmt attributes. */
|
|
|
|
static bool
|
|
producer_is_codewarrior (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_codewarrior;
|
|
}
|
|
|
|
static bool
|
|
producer_is_gas_lt_2_38 (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_gas_lt_2_38;
|
|
}
|
|
|
|
static bool
|
|
producer_is_gas_2_39 (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_gas_2_39;
|
|
}
|
|
|
|
/* Return true if CU is produced by GAS 2.39 or later. */
|
|
|
|
static bool
|
|
producer_is_gas_ge_2_39 (struct dwarf2_cu *cu)
|
|
{
|
|
if (!cu->checked_producer)
|
|
check_producer (cu);
|
|
|
|
return cu->producer_is_gas_2_39 || cu->producer_is_gas_ge_2_40;
|
|
}
|
|
|
|
/* Return the accessibility of DIE, as given by DW_AT_accessibility.
|
|
If that attribute is not available, return the appropriate
|
|
default. */
|
|
|
|
static enum dwarf_access_attribute
|
|
dwarf2_access_attribute (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
attribute *attr = dwarf2_attr (die, DW_AT_accessibility, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
LONGEST value = attr->constant_value (-1);
|
|
if (value == DW_ACCESS_public
|
|
|| value == DW_ACCESS_protected
|
|
|| value == DW_ACCESS_private)
|
|
return (dwarf_access_attribute) value;
|
|
complaint (_("Unhandled DW_AT_accessibility value (%s)"),
|
|
plongest (value));
|
|
}
|
|
|
|
if (cu->header.version < 3 || producer_is_gxx_lt_4_6 (cu))
|
|
{
|
|
/* The default DWARF 2 accessibility for members is public, the default
|
|
accessibility for inheritance is private. */
|
|
|
|
if (die->tag != DW_TAG_inheritance)
|
|
return DW_ACCESS_public;
|
|
else
|
|
return DW_ACCESS_private;
|
|
}
|
|
else
|
|
{
|
|
/* DWARF 3+ defines the default accessibility a different way. The same
|
|
rules apply now for DW_TAG_inheritance as for the members and it only
|
|
depends on the container kind. */
|
|
|
|
if (die->parent->tag == DW_TAG_class_type)
|
|
return DW_ACCESS_private;
|
|
else
|
|
return DW_ACCESS_public;
|
|
}
|
|
}
|
|
|
|
/* Look for DW_AT_data_member_location or DW_AT_data_bit_offset. Set
|
|
*OFFSET to the byte offset. If the attribute was not found return
|
|
0, otherwise return 1. If it was found but could not properly be
|
|
handled, set *OFFSET to 0. */
|
|
|
|
static int
|
|
handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
|
|
LONGEST *offset)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_data_member_location, cu);
|
|
if (attr != NULL)
|
|
{
|
|
*offset = 0;
|
|
CORE_ADDR temp;
|
|
|
|
/* Note that we do not check for a section offset first here.
|
|
This is because DW_AT_data_member_location is new in DWARF 4,
|
|
so if we see it, we can assume that a constant form is really
|
|
a constant and not a section offset. */
|
|
if (attr->form_is_constant ())
|
|
*offset = attr->constant_value (0);
|
|
else if (attr->form_is_section_offset ())
|
|
dwarf2_complex_location_expr_complaint ();
|
|
else if (attr->form_is_block ()
|
|
&& decode_locdesc (attr->as_block (), cu, &temp))
|
|
{
|
|
*offset = temp;
|
|
}
|
|
else
|
|
dwarf2_complex_location_expr_complaint ();
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
*offset = attr->constant_value (0);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Look for DW_AT_data_member_location or DW_AT_data_bit_offset and
|
|
store the results in FIELD. */
|
|
|
|
static void
|
|
handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
|
|
struct field *field)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_data_member_location, cu);
|
|
if (attr != NULL)
|
|
{
|
|
if (attr->form_is_constant ())
|
|
{
|
|
LONGEST offset = attr->constant_value (0);
|
|
|
|
/* Work around this GCC 11 bug, where it would erroneously use -1
|
|
data member locations, instead of 0:
|
|
|
|
Negative DW_AT_data_member_location
|
|
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101378
|
|
*/
|
|
if (offset == -1 && cu->producer_is_gcc_11)
|
|
{
|
|
complaint (_("DW_AT_data_member_location value of -1, assuming 0"));
|
|
offset = 0;
|
|
}
|
|
|
|
field->set_loc_bitpos (offset * bits_per_byte);
|
|
}
|
|
else if (attr->form_is_section_offset ())
|
|
dwarf2_complex_location_expr_complaint ();
|
|
else if (attr->form_is_block ())
|
|
{
|
|
CORE_ADDR offset;
|
|
if (decode_locdesc (attr->as_block (), cu, &offset))
|
|
field->set_loc_bitpos (offset * bits_per_byte);
|
|
else
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct dwarf2_locexpr_baton *dlbaton
|
|
= XOBNEW (&objfile->objfile_obstack,
|
|
struct dwarf2_locexpr_baton);
|
|
dlbaton->data = attr->as_block ()->data;
|
|
dlbaton->size = attr->as_block ()->size;
|
|
/* When using this baton, we want to compute the address
|
|
of the field, not the value. This is why
|
|
is_reference is set to false here. */
|
|
dlbaton->is_reference = false;
|
|
dlbaton->per_objfile = per_objfile;
|
|
dlbaton->per_cu = cu->per_cu;
|
|
|
|
field->set_loc_dwarf_block (dlbaton);
|
|
}
|
|
}
|
|
else
|
|
dwarf2_complex_location_expr_complaint ();
|
|
}
|
|
else
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu);
|
|
if (attr != nullptr)
|
|
field->set_loc_bitpos (attr->constant_value (0));
|
|
}
|
|
}
|
|
|
|
/* Add an aggregate field to the field list. */
|
|
|
|
static void
|
|
dwarf2_add_field (struct field_info *fip, struct die_info *die,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
struct nextfield *new_field;
|
|
struct attribute *attr;
|
|
struct field *fp;
|
|
const char *fieldname = "";
|
|
|
|
if (die->tag == DW_TAG_inheritance)
|
|
new_field = &fip->baseclasses.emplace_back ();
|
|
else
|
|
new_field = &fip->fields.emplace_back ();
|
|
|
|
new_field->offset = die->sect_off;
|
|
|
|
switch (dwarf2_access_attribute (die, cu))
|
|
{
|
|
case DW_ACCESS_public:
|
|
break;
|
|
case DW_ACCESS_private:
|
|
new_field->field.set_accessibility (accessibility::PRIVATE);
|
|
break;
|
|
case DW_ACCESS_protected:
|
|
new_field->field.set_accessibility (accessibility::PROTECTED);
|
|
break;
|
|
default:
|
|
gdb_assert_not_reached ("invalid accessibility");
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_virtuality, cu);
|
|
if (attr != nullptr && attr->as_virtuality ())
|
|
new_field->field.set_virtual ();
|
|
|
|
fp = &new_field->field;
|
|
|
|
if ((die->tag == DW_TAG_member || die->tag == DW_TAG_namelist_item)
|
|
&& !die_is_declaration (die, cu))
|
|
{
|
|
if (die->tag == DW_TAG_namelist_item)
|
|
{
|
|
/* Typically, DW_TAG_namelist_item are references to namelist items.
|
|
If so, follow that reference. */
|
|
struct attribute *attr1 = dwarf2_attr (die, DW_AT_namelist_item, cu);
|
|
struct die_info *item_die = nullptr;
|
|
struct dwarf2_cu *item_cu = cu;
|
|
if (attr1->form_is_ref ())
|
|
item_die = follow_die_ref (die, attr1, &item_cu);
|
|
if (item_die != nullptr)
|
|
die = item_die;
|
|
}
|
|
/* Data member other than a C++ static data member. */
|
|
|
|
/* Get type of field. */
|
|
fp->set_type (die_type (die, cu));
|
|
|
|
fp->set_loc_bitpos (0);
|
|
|
|
/* Get bit size of field (zero if none). */
|
|
attr = dwarf2_attr (die, DW_AT_bit_size, cu);
|
|
if (attr != nullptr)
|
|
fp->set_bitsize (attr->constant_value (0));
|
|
else
|
|
fp->set_bitsize (0);
|
|
|
|
/* Get bit offset of field. */
|
|
handle_member_location (die, cu, fp);
|
|
attr = dwarf2_attr (die, DW_AT_bit_offset, cu);
|
|
if (attr != nullptr && attr->form_is_constant ())
|
|
{
|
|
if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
|
|
{
|
|
/* For big endian bits, the DW_AT_bit_offset gives the
|
|
additional bit offset from the MSB of the containing
|
|
anonymous object to the MSB of the field. We don't
|
|
have to do anything special since we don't need to
|
|
know the size of the anonymous object. */
|
|
fp->set_loc_bitpos (fp->loc_bitpos () + attr->constant_value (0));
|
|
}
|
|
else
|
|
{
|
|
/* For little endian bits, compute the bit offset to the
|
|
MSB of the anonymous object, subtract off the number of
|
|
bits from the MSB of the field to the MSB of the
|
|
object, and then subtract off the number of bits of
|
|
the field itself. The result is the bit offset of
|
|
the LSB of the field. */
|
|
int anonymous_size;
|
|
int bit_offset = attr->constant_value (0);
|
|
|
|
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr != nullptr && attr->form_is_constant ())
|
|
{
|
|
/* The size of the anonymous object containing
|
|
the bit field is explicit, so use the
|
|
indicated size (in bytes). */
|
|
anonymous_size = attr->constant_value (0);
|
|
}
|
|
else
|
|
{
|
|
/* The size of the anonymous object containing
|
|
the bit field must be inferred from the type
|
|
attribute of the data member containing the
|
|
bit field. */
|
|
anonymous_size = fp->type ()->length ();
|
|
}
|
|
fp->set_loc_bitpos (fp->loc_bitpos ()
|
|
+ anonymous_size * bits_per_byte
|
|
- bit_offset - fp->bitsize ());
|
|
}
|
|
}
|
|
|
|
/* Get name of field. */
|
|
fieldname = dwarf2_name (die, cu);
|
|
if (fieldname == NULL)
|
|
fieldname = "";
|
|
|
|
/* The name is already allocated along with this objfile, so we don't
|
|
need to duplicate it for the type. */
|
|
fp->set_name (fieldname);
|
|
|
|
/* Change accessibility for artificial fields (e.g. virtual table
|
|
pointer or virtual base class pointer) to private. */
|
|
if (dwarf2_attr (die, DW_AT_artificial, cu))
|
|
{
|
|
fp->set_is_artificial (true);
|
|
fp->set_accessibility (accessibility::PRIVATE);
|
|
}
|
|
}
|
|
else if (die->tag == DW_TAG_member || die->tag == DW_TAG_variable)
|
|
{
|
|
/* C++ static member. */
|
|
|
|
/* NOTE: carlton/2002-11-05: It should be a DW_TAG_member that
|
|
is a declaration, but all versions of G++ as of this writing
|
|
(so through at least 3.2.1) incorrectly generate
|
|
DW_TAG_variable tags. */
|
|
|
|
const char *physname;
|
|
|
|
/* Get name of field. */
|
|
fieldname = dwarf2_name (die, cu);
|
|
if (fieldname == NULL)
|
|
return;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_const_value, cu);
|
|
if (attr
|
|
/* Only create a symbol if this is an external value.
|
|
new_symbol checks this and puts the value in the global symbol
|
|
table, which we want. If it is not external, new_symbol
|
|
will try to put the value in cu->list_in_scope which is wrong. */
|
|
&& dwarf2_flag_true_p (die, DW_AT_external, cu))
|
|
{
|
|
/* A static const member, not much different than an enum as far as
|
|
we're concerned, except that we can support more types. */
|
|
new_symbol (die, NULL, cu);
|
|
}
|
|
|
|
/* Get physical name. */
|
|
physname = dwarf2_physname (fieldname, die, cu);
|
|
|
|
/* The name is already allocated along with this objfile, so we don't
|
|
need to duplicate it for the type. */
|
|
fp->set_loc_physname (physname ? physname : "");
|
|
fp->set_type (die_type (die, cu));
|
|
fp->set_name (fieldname);
|
|
}
|
|
else if (die->tag == DW_TAG_inheritance)
|
|
{
|
|
/* C++ base class field. */
|
|
handle_member_location (die, cu, fp);
|
|
fp->set_bitsize (0);
|
|
fp->set_type (die_type (die, cu));
|
|
fp->set_name (fp->type ()->name ());
|
|
}
|
|
else
|
|
gdb_assert_not_reached ("missing case in dwarf2_add_field");
|
|
}
|
|
|
|
/* Can the type given by DIE define another type? */
|
|
|
|
static bool
|
|
type_can_define_types (const struct die_info *die)
|
|
{
|
|
switch (die->tag)
|
|
{
|
|
case DW_TAG_typedef:
|
|
case DW_TAG_class_type:
|
|
case DW_TAG_structure_type:
|
|
case DW_TAG_union_type:
|
|
case DW_TAG_enumeration_type:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Add a type definition defined in the scope of the FIP's class. */
|
|
|
|
static void
|
|
dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct decl_field fp;
|
|
memset (&fp, 0, sizeof (fp));
|
|
|
|
gdb_assert (type_can_define_types (die));
|
|
|
|
/* Get name of field. NULL is okay here, meaning an anonymous type. */
|
|
fp.name = dwarf2_name (die, cu);
|
|
fp.type = read_type_die (die, cu);
|
|
|
|
/* Save accessibility. */
|
|
dwarf_access_attribute accessibility = dwarf2_access_attribute (die, cu);
|
|
switch (accessibility)
|
|
{
|
|
case DW_ACCESS_public:
|
|
/* The assumed value if neither private nor protected. */
|
|
break;
|
|
case DW_ACCESS_private:
|
|
fp.accessibility = accessibility::PRIVATE;
|
|
break;
|
|
case DW_ACCESS_protected:
|
|
fp.accessibility = accessibility::PROTECTED;
|
|
break;
|
|
}
|
|
|
|
if (die->tag == DW_TAG_typedef)
|
|
fip->typedef_field_list.push_back (fp);
|
|
else
|
|
fip->nested_types_list.push_back (fp);
|
|
}
|
|
|
|
/* A convenience typedef that's used when finding the discriminant
|
|
field for a variant part. */
|
|
typedef std::unordered_map<sect_offset, int> offset_map_type;
|
|
|
|
/* Compute the discriminant range for a given variant. OBSTACK is
|
|
where the results will be stored. VARIANT is the variant to
|
|
process. IS_UNSIGNED indicates whether the discriminant is signed
|
|
or unsigned. */
|
|
|
|
static const gdb::array_view<discriminant_range>
|
|
convert_variant_range (struct obstack *obstack, const variant_field &variant,
|
|
bool is_unsigned)
|
|
{
|
|
std::vector<discriminant_range> ranges;
|
|
|
|
if (variant.default_branch)
|
|
return {};
|
|
|
|
if (variant.discr_list_data == nullptr)
|
|
{
|
|
discriminant_range r
|
|
= {variant.discriminant_value, variant.discriminant_value};
|
|
ranges.push_back (r);
|
|
}
|
|
else
|
|
{
|
|
gdb::array_view<const gdb_byte> data (variant.discr_list_data->data,
|
|
variant.discr_list_data->size);
|
|
while (!data.empty ())
|
|
{
|
|
if (data[0] != DW_DSC_range && data[0] != DW_DSC_label)
|
|
{
|
|
complaint (_("invalid discriminant marker: %d"), data[0]);
|
|
break;
|
|
}
|
|
bool is_range = data[0] == DW_DSC_range;
|
|
data = data.slice (1);
|
|
|
|
ULONGEST low, high;
|
|
unsigned int bytes_read;
|
|
|
|
if (data.empty ())
|
|
{
|
|
complaint (_("DW_AT_discr_list missing low value"));
|
|
break;
|
|
}
|
|
if (is_unsigned)
|
|
low = read_unsigned_leb128 (nullptr, data.data (), &bytes_read);
|
|
else
|
|
low = (ULONGEST) read_signed_leb128 (nullptr, data.data (),
|
|
&bytes_read);
|
|
data = data.slice (bytes_read);
|
|
|
|
if (is_range)
|
|
{
|
|
if (data.empty ())
|
|
{
|
|
complaint (_("DW_AT_discr_list missing high value"));
|
|
break;
|
|
}
|
|
if (is_unsigned)
|
|
high = read_unsigned_leb128 (nullptr, data.data (),
|
|
&bytes_read);
|
|
else
|
|
high = (LONGEST) read_signed_leb128 (nullptr, data.data (),
|
|
&bytes_read);
|
|
data = data.slice (bytes_read);
|
|
}
|
|
else
|
|
high = low;
|
|
|
|
ranges.push_back ({ low, high });
|
|
}
|
|
}
|
|
|
|
discriminant_range *result = XOBNEWVEC (obstack, discriminant_range,
|
|
ranges.size ());
|
|
std::copy (ranges.begin (), ranges.end (), result);
|
|
return gdb::array_view<discriminant_range> (result, ranges.size ());
|
|
}
|
|
|
|
static const gdb::array_view<variant_part> create_variant_parts
|
|
(struct obstack *obstack,
|
|
const offset_map_type &offset_map,
|
|
struct field_info *fi,
|
|
const std::vector<variant_part_builder> &variant_parts);
|
|
|
|
/* Fill in a "struct variant" for a given variant field. RESULT is
|
|
the variant to fill in. OBSTACK is where any needed allocations
|
|
will be done. OFFSET_MAP holds the mapping from section offsets to
|
|
fields for the type. FI describes the fields of the type we're
|
|
processing. FIELD is the variant field we're converting. */
|
|
|
|
static void
|
|
create_one_variant (variant &result, struct obstack *obstack,
|
|
const offset_map_type &offset_map,
|
|
struct field_info *fi, const variant_field &field)
|
|
{
|
|
result.discriminants = convert_variant_range (obstack, field, false);
|
|
result.first_field = field.first_field + fi->baseclasses.size ();
|
|
result.last_field = field.last_field + fi->baseclasses.size ();
|
|
result.parts = create_variant_parts (obstack, offset_map, fi,
|
|
field.variant_parts);
|
|
}
|
|
|
|
/* Fill in a "struct variant_part" for a given variant part. RESULT
|
|
is the variant part to fill in. OBSTACK is where any needed
|
|
allocations will be done. OFFSET_MAP holds the mapping from
|
|
section offsets to fields for the type. FI describes the fields of
|
|
the type we're processing. BUILDER is the variant part to be
|
|
converted. */
|
|
|
|
static void
|
|
create_one_variant_part (variant_part &result,
|
|
struct obstack *obstack,
|
|
const offset_map_type &offset_map,
|
|
struct field_info *fi,
|
|
const variant_part_builder &builder)
|
|
{
|
|
auto iter = offset_map.find (builder.discriminant_offset);
|
|
if (iter == offset_map.end ())
|
|
{
|
|
result.discriminant_index = -1;
|
|
/* Doesn't matter. */
|
|
result.is_unsigned = false;
|
|
}
|
|
else
|
|
{
|
|
result.discriminant_index = iter->second;
|
|
result.is_unsigned
|
|
= fi->fields[result.discriminant_index].field.type ()->is_unsigned ();
|
|
}
|
|
|
|
size_t n = builder.variants.size ();
|
|
variant *output = new (obstack) variant[n];
|
|
for (size_t i = 0; i < n; ++i)
|
|
create_one_variant (output[i], obstack, offset_map, fi,
|
|
builder.variants[i]);
|
|
|
|
result.variants = gdb::array_view<variant> (output, n);
|
|
}
|
|
|
|
/* Create a vector of variant parts that can be attached to a type.
|
|
OBSTACK is where any needed allocations will be done. OFFSET_MAP
|
|
holds the mapping from section offsets to fields for the type. FI
|
|
describes the fields of the type we're processing. VARIANT_PARTS
|
|
is the vector to convert. */
|
|
|
|
static const gdb::array_view<variant_part>
|
|
create_variant_parts (struct obstack *obstack,
|
|
const offset_map_type &offset_map,
|
|
struct field_info *fi,
|
|
const std::vector<variant_part_builder> &variant_parts)
|
|
{
|
|
if (variant_parts.empty ())
|
|
return {};
|
|
|
|
size_t n = variant_parts.size ();
|
|
variant_part *result = new (obstack) variant_part[n];
|
|
for (size_t i = 0; i < n; ++i)
|
|
create_one_variant_part (result[i], obstack, offset_map, fi,
|
|
variant_parts[i]);
|
|
|
|
return gdb::array_view<variant_part> (result, n);
|
|
}
|
|
|
|
/* Compute the variant part vector for FIP, attaching it to TYPE when
|
|
done. */
|
|
|
|
static void
|
|
add_variant_property (struct field_info *fip, struct type *type,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
/* Map section offsets of fields to their field index. Note the
|
|
field index here does not take the number of baseclasses into
|
|
account. */
|
|
offset_map_type offset_map;
|
|
for (int i = 0; i < fip->fields.size (); ++i)
|
|
offset_map[fip->fields[i].offset] = i;
|
|
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
gdb::array_view<const variant_part> parts
|
|
= create_variant_parts (&objfile->objfile_obstack, offset_map, fip,
|
|
fip->variant_parts);
|
|
|
|
struct dynamic_prop prop;
|
|
prop.set_variant_parts ((gdb::array_view<variant_part> *)
|
|
obstack_copy (&objfile->objfile_obstack, &parts,
|
|
sizeof (parts)));
|
|
|
|
type->add_dyn_prop (DYN_PROP_VARIANT_PARTS, prop);
|
|
}
|
|
|
|
/* Create the vector of fields, and attach it to the type. */
|
|
|
|
static void
|
|
dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
int nfields = fip->nfields ();
|
|
|
|
/* Record the field count, allocate space for the array of fields,
|
|
and create blank accessibility bitfields if necessary. */
|
|
type->alloc_fields (nfields);
|
|
|
|
if (!fip->baseclasses.empty () && cu->lang () != language_ada)
|
|
{
|
|
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
|
TYPE_N_BASECLASSES (type) = fip->baseclasses.size ();
|
|
}
|
|
|
|
if (!fip->variant_parts.empty ())
|
|
add_variant_property (fip, type, cu);
|
|
|
|
/* Copy the saved-up fields into the field vector. */
|
|
for (int i = 0; i < nfields; ++i)
|
|
{
|
|
struct nextfield &field
|
|
= ((i < fip->baseclasses.size ()) ? fip->baseclasses[i]
|
|
: fip->fields[i - fip->baseclasses.size ()]);
|
|
|
|
type->field (i) = field.field;
|
|
}
|
|
}
|
|
|
|
/* Return true if this member function is a constructor, false
|
|
otherwise. */
|
|
|
|
static int
|
|
dwarf2_is_constructor (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
const char *fieldname;
|
|
const char *type_name;
|
|
int len;
|
|
|
|
if (die->parent == NULL)
|
|
return 0;
|
|
|
|
if (die->parent->tag != DW_TAG_structure_type
|
|
&& die->parent->tag != DW_TAG_union_type
|
|
&& die->parent->tag != DW_TAG_class_type)
|
|
return 0;
|
|
|
|
fieldname = dwarf2_name (die, cu);
|
|
type_name = dwarf2_name (die->parent, cu);
|
|
if (fieldname == NULL || type_name == NULL)
|
|
return 0;
|
|
|
|
len = strlen (fieldname);
|
|
return (strncmp (fieldname, type_name, len) == 0
|
|
&& (type_name[len] == '\0' || type_name[len] == '<'));
|
|
}
|
|
|
|
/* Add a member function to the proper fieldlist. */
|
|
|
|
static void
|
|
dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
|
|
struct type *type, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct attribute *attr;
|
|
int i;
|
|
struct fnfieldlist *flp = nullptr;
|
|
struct fn_field *fnp;
|
|
const char *fieldname;
|
|
struct type *this_type;
|
|
|
|
if (cu->lang () == language_ada)
|
|
error (_("unexpected member function in Ada type"));
|
|
|
|
/* Get name of member function. */
|
|
fieldname = dwarf2_name (die, cu);
|
|
if (fieldname == NULL)
|
|
return;
|
|
|
|
/* Look up member function name in fieldlist. */
|
|
for (i = 0; i < fip->fnfieldlists.size (); i++)
|
|
{
|
|
if (strcmp (fip->fnfieldlists[i].name, fieldname) == 0)
|
|
{
|
|
flp = &fip->fnfieldlists[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Create a new fnfieldlist if necessary. */
|
|
if (flp == nullptr)
|
|
{
|
|
flp = &fip->fnfieldlists.emplace_back ();
|
|
flp->name = fieldname;
|
|
i = fip->fnfieldlists.size () - 1;
|
|
}
|
|
|
|
/* Create a new member function field and add it to the vector of
|
|
fnfieldlists. */
|
|
fnp = &flp->fnfields.emplace_back ();
|
|
|
|
/* Delay processing of the physname until later. */
|
|
if (is_cplus_dialect (cu->lang ()))
|
|
add_to_method_list (type, i, flp->fnfields.size () - 1, fieldname,
|
|
die, cu);
|
|
else
|
|
{
|
|
const char *physname = dwarf2_physname (fieldname, die, cu);
|
|
fnp->physname = physname ? physname : "";
|
|
}
|
|
|
|
fnp->type = type_allocator (objfile, cu->lang ()).new_type ();
|
|
this_type = read_type_die (die, cu);
|
|
if (this_type && this_type->code () == TYPE_CODE_FUNC)
|
|
{
|
|
int nparams = this_type->num_fields ();
|
|
|
|
/* TYPE is the domain of this method, and THIS_TYPE is the type
|
|
of the method itself (TYPE_CODE_METHOD). */
|
|
smash_to_method_type (fnp->type, type,
|
|
this_type->target_type (),
|
|
this_type->fields (),
|
|
this_type->num_fields (),
|
|
this_type->has_varargs ());
|
|
|
|
/* Handle static member functions.
|
|
Dwarf2 has no clean way to discern C++ static and non-static
|
|
member functions. G++ helps GDB by marking the first
|
|
parameter for non-static member functions (which is the this
|
|
pointer) as artificial. We obtain this information from
|
|
read_subroutine_type via TYPE_FIELD_ARTIFICIAL. */
|
|
if (nparams == 0 || this_type->field (0).is_artificial () == 0)
|
|
fnp->voffset = VOFFSET_STATIC;
|
|
}
|
|
else
|
|
complaint (_("member function type missing for '%s'"),
|
|
dwarf2_full_name (fieldname, die, cu));
|
|
|
|
/* Get fcontext from DW_AT_containing_type if present. */
|
|
if (dwarf2_attr (die, DW_AT_containing_type, cu) != NULL)
|
|
fnp->fcontext = die_containing_type (die, cu);
|
|
|
|
/* dwarf2 doesn't have stubbed physical names, so the setting of is_const and
|
|
is_volatile is irrelevant, as it is needed by gdb_mangle_name only. */
|
|
|
|
/* Get accessibility. */
|
|
dwarf_access_attribute accessibility = dwarf2_access_attribute (die, cu);
|
|
switch (accessibility)
|
|
{
|
|
case DW_ACCESS_private:
|
|
fnp->accessibility = accessibility::PRIVATE;
|
|
break;
|
|
case DW_ACCESS_protected:
|
|
fnp->accessibility = accessibility::PROTECTED;
|
|
break;
|
|
}
|
|
|
|
/* Check for artificial methods. */
|
|
attr = dwarf2_attr (die, DW_AT_artificial, cu);
|
|
if (attr && attr->as_boolean ())
|
|
fnp->is_artificial = 1;
|
|
|
|
/* Check for defaulted methods. */
|
|
attr = dwarf2_attr (die, DW_AT_defaulted, cu);
|
|
if (attr != nullptr)
|
|
fnp->defaulted = attr->defaulted ();
|
|
|
|
/* Check for deleted methods. */
|
|
attr = dwarf2_attr (die, DW_AT_deleted, cu);
|
|
if (attr != nullptr && attr->as_boolean ())
|
|
fnp->is_deleted = 1;
|
|
|
|
fnp->is_constructor = dwarf2_is_constructor (die, cu);
|
|
|
|
/* Get index in virtual function table if it is a virtual member
|
|
function. For older versions of GCC, this is an offset in the
|
|
appropriate virtual table, as specified by DW_AT_containing_type.
|
|
For everyone else, it is an expression to be evaluated relative
|
|
to the object address. */
|
|
|
|
attr = dwarf2_attr (die, DW_AT_vtable_elem_location, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
if (attr->form_is_block () && attr->as_block ()->size > 0)
|
|
{
|
|
struct dwarf_block *block = attr->as_block ();
|
|
CORE_ADDR offset;
|
|
|
|
if (block->data[0] == DW_OP_constu
|
|
&& decode_locdesc (block, cu, &offset))
|
|
{
|
|
/* "Old"-style GCC. See
|
|
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44126
|
|
for discussion. This was known and a patch available
|
|
in 2010, but as of 2023, both GCC and clang still
|
|
emit this. */
|
|
fnp->voffset = offset + 2;
|
|
}
|
|
else if ((block->data[0] == DW_OP_deref
|
|
|| (block->size > 1
|
|
&& block->data[0] == DW_OP_deref_size
|
|
&& block->data[1] == cu->header.addr_size))
|
|
&& decode_locdesc (block, cu, &offset))
|
|
{
|
|
fnp->voffset = offset;
|
|
if ((fnp->voffset % cu->header.addr_size) != 0)
|
|
dwarf2_complex_location_expr_complaint ();
|
|
else
|
|
fnp->voffset /= cu->header.addr_size;
|
|
fnp->voffset += 2;
|
|
}
|
|
else
|
|
dwarf2_complex_location_expr_complaint ();
|
|
|
|
if (!fnp->fcontext)
|
|
{
|
|
/* If there is no `this' field and no DW_AT_containing_type,
|
|
we cannot actually find a base class context for the
|
|
vtable! */
|
|
if (this_type->num_fields () == 0
|
|
|| !this_type->field (0).is_artificial ())
|
|
{
|
|
complaint (_("cannot determine context for virtual member "
|
|
"function \"%s\" (offset %s)"),
|
|
fieldname, sect_offset_str (die->sect_off));
|
|
}
|
|
else
|
|
{
|
|
fnp->fcontext = this_type->field (0).type ()->target_type ();
|
|
}
|
|
}
|
|
}
|
|
else if (attr->form_is_section_offset ())
|
|
{
|
|
dwarf2_complex_location_expr_complaint ();
|
|
}
|
|
else
|
|
{
|
|
dwarf2_invalid_attrib_class_complaint ("DW_AT_vtable_elem_location",
|
|
fieldname);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_virtuality, cu);
|
|
if (attr != nullptr && attr->as_virtuality () != DW_VIRTUALITY_none)
|
|
{
|
|
/* GCC does this, as of 2008-08-25; PR debug/37237. */
|
|
complaint (_("Member function \"%s\" (offset %s) is virtual "
|
|
"but the vtable offset is not specified"),
|
|
fieldname, sect_offset_str (die->sect_off));
|
|
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
|
TYPE_CPLUS_DYNAMIC (type) = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Create the vector of member function fields, and attach it to the type. */
|
|
|
|
static void
|
|
dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
if (cu->lang () == language_ada)
|
|
error (_("unexpected member functions in Ada type"));
|
|
|
|
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
|
TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
|
|
TYPE_ZALLOC (type,
|
|
sizeof (struct fn_fieldlist) * fip->fnfieldlists.size ());
|
|
|
|
for (int i = 0; i < fip->fnfieldlists.size (); i++)
|
|
{
|
|
struct fnfieldlist &nf = fip->fnfieldlists[i];
|
|
struct fn_fieldlist *fn_flp = &TYPE_FN_FIELDLIST (type, i);
|
|
|
|
TYPE_FN_FIELDLIST_NAME (type, i) = nf.name;
|
|
TYPE_FN_FIELDLIST_LENGTH (type, i) = nf.fnfields.size ();
|
|
/* No need to zero-initialize, initialization is done by the copy in
|
|
the loop below. */
|
|
fn_flp->fn_fields = (struct fn_field *)
|
|
TYPE_ALLOC (type, sizeof (struct fn_field) * nf.fnfields.size ());
|
|
|
|
for (int k = 0; k < nf.fnfields.size (); ++k)
|
|
fn_flp->fn_fields[k] = nf.fnfields[k];
|
|
}
|
|
|
|
TYPE_NFN_FIELDS (type) = fip->fnfieldlists.size ();
|
|
}
|
|
|
|
/* Returns non-zero if NAME is the name of a vtable member in CU's
|
|
language, zero otherwise. */
|
|
static int
|
|
is_vtable_name (const char *name, struct dwarf2_cu *cu)
|
|
{
|
|
static const char vptr[] = "_vptr";
|
|
|
|
/* Look for the C++ form of the vtable. */
|
|
if (startswith (name, vptr) && is_cplus_marker (name[sizeof (vptr) - 1]))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* GCC outputs unnamed structures that are really pointers to member
|
|
functions, with the ABI-specified layout. If TYPE describes
|
|
such a structure, smash it into a member function type.
|
|
|
|
GCC shouldn't do this; it should just output pointer to member DIEs.
|
|
This is GCC PR debug/28767. */
|
|
|
|
static void
|
|
quirk_gcc_member_function_pointer (struct type *type, struct objfile *objfile)
|
|
{
|
|
struct type *pfn_type, *self_type, *new_type;
|
|
|
|
/* Check for a structure with no name and two children. */
|
|
if (type->code () != TYPE_CODE_STRUCT || type->num_fields () != 2)
|
|
return;
|
|
|
|
/* Check for __pfn and __delta members. */
|
|
if (type->field (0).name () == NULL
|
|
|| strcmp (type->field (0).name (), "__pfn") != 0
|
|
|| type->field (1).name () == NULL
|
|
|| strcmp (type->field (1).name (), "__delta") != 0)
|
|
return;
|
|
|
|
/* Find the type of the method. */
|
|
pfn_type = type->field (0).type ();
|
|
if (pfn_type == NULL
|
|
|| pfn_type->code () != TYPE_CODE_PTR
|
|
|| pfn_type->target_type ()->code () != TYPE_CODE_FUNC)
|
|
return;
|
|
|
|
/* Look for the "this" argument. */
|
|
pfn_type = pfn_type->target_type ();
|
|
if (pfn_type->num_fields () == 0
|
|
/* || pfn_type->field (0).type () == NULL */
|
|
|| pfn_type->field (0).type ()->code () != TYPE_CODE_PTR)
|
|
return;
|
|
|
|
self_type = pfn_type->field (0).type ()->target_type ();
|
|
new_type = type_allocator (type).new_type ();
|
|
smash_to_method_type (new_type, self_type, pfn_type->target_type (),
|
|
pfn_type->fields (), pfn_type->num_fields (),
|
|
pfn_type->has_varargs ());
|
|
smash_to_methodptr_type (type, new_type);
|
|
}
|
|
|
|
/* Helper for quirk_ada_thick_pointer. If TYPE is an array type that
|
|
requires rewriting, then copy it and return the updated copy.
|
|
Otherwise return nullptr. */
|
|
|
|
static struct type *
|
|
rewrite_array_type (struct type *type)
|
|
{
|
|
if (type->code () != TYPE_CODE_ARRAY)
|
|
return nullptr;
|
|
|
|
struct type *index_type = type->index_type ();
|
|
range_bounds *current_bounds = index_type->bounds ();
|
|
|
|
/* Handle multi-dimensional arrays. */
|
|
struct type *new_target = rewrite_array_type (type->target_type ());
|
|
if (new_target == nullptr)
|
|
{
|
|
/* Maybe we don't need to rewrite this array. */
|
|
if (current_bounds->low.is_constant ()
|
|
&& current_bounds->high.is_constant ())
|
|
return nullptr;
|
|
}
|
|
|
|
/* Either the target type was rewritten, or the bounds have to be
|
|
updated. Either way we want to copy the type and update
|
|
everything. */
|
|
struct type *copy = copy_type (type);
|
|
copy->copy_fields (type);
|
|
if (new_target != nullptr)
|
|
copy->set_target_type (new_target);
|
|
|
|
struct type *index_copy = copy_type (index_type);
|
|
range_bounds *bounds
|
|
= (struct range_bounds *) TYPE_ZALLOC (index_copy,
|
|
sizeof (range_bounds));
|
|
*bounds = *current_bounds;
|
|
bounds->low.set_const_val (1);
|
|
bounds->high.set_const_val (0);
|
|
index_copy->set_bounds (bounds);
|
|
copy->set_index_type (index_copy);
|
|
|
|
return copy;
|
|
}
|
|
|
|
/* While some versions of GCC will generate complicated DWARF for an
|
|
array (see quirk_ada_thick_pointer), more recent versions were
|
|
modified to emit an explicit thick pointer structure. However, in
|
|
this case, the array still has DWARF expressions for its ranges,
|
|
and these must be ignored. */
|
|
|
|
static void
|
|
quirk_ada_thick_pointer_struct (struct die_info *die, struct dwarf2_cu *cu,
|
|
struct type *type)
|
|
{
|
|
gdb_assert (cu->lang () == language_ada);
|
|
|
|
/* Check for a structure with two children. */
|
|
if (type->code () != TYPE_CODE_STRUCT || type->num_fields () != 2)
|
|
return;
|
|
|
|
/* Check for P_ARRAY and P_BOUNDS members. */
|
|
if (type->field (0).name () == NULL
|
|
|| strcmp (type->field (0).name (), "P_ARRAY") != 0
|
|
|| type->field (1).name () == NULL
|
|
|| strcmp (type->field (1).name (), "P_BOUNDS") != 0)
|
|
return;
|
|
|
|
/* Make sure we're looking at a pointer to an array. */
|
|
if (type->field (0).type ()->code () != TYPE_CODE_PTR)
|
|
return;
|
|
|
|
/* The Ada code already knows how to handle these types, so all that
|
|
we need to do is turn the bounds into static bounds. However, we
|
|
don't want to rewrite existing array or index types in-place,
|
|
because those may be referenced in other contexts where this
|
|
rewriting is undesirable. */
|
|
struct type *new_ary_type
|
|
= rewrite_array_type (type->field (0).type ()->target_type ());
|
|
if (new_ary_type != nullptr)
|
|
type->field (0).set_type (lookup_pointer_type (new_ary_type));
|
|
}
|
|
|
|
/* If the DIE has a DW_AT_alignment attribute, return its value, doing
|
|
appropriate error checking and issuing complaints if there is a
|
|
problem. */
|
|
|
|
static ULONGEST
|
|
get_alignment (struct dwarf2_cu *cu, struct die_info *die)
|
|
{
|
|
struct attribute *attr = dwarf2_attr (die, DW_AT_alignment, cu);
|
|
|
|
if (attr == nullptr)
|
|
return 0;
|
|
|
|
if (!attr->form_is_constant ())
|
|
{
|
|
complaint (_("DW_AT_alignment must have constant form"
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
return 0;
|
|
}
|
|
|
|
LONGEST val = attr->constant_value (0);
|
|
if (val < 0)
|
|
{
|
|
complaint (_("DW_AT_alignment value must not be negative"
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
return 0;
|
|
}
|
|
ULONGEST align = val;
|
|
|
|
if (align == 0)
|
|
{
|
|
complaint (_("DW_AT_alignment value must not be zero"
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
return 0;
|
|
}
|
|
if ((align & (align - 1)) != 0)
|
|
{
|
|
complaint (_("DW_AT_alignment value must be a power of 2"
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
return 0;
|
|
}
|
|
|
|
return align;
|
|
}
|
|
|
|
/* If the DIE has a DW_AT_alignment attribute, use its value to set
|
|
the alignment for TYPE. */
|
|
|
|
static void
|
|
maybe_set_alignment (struct dwarf2_cu *cu, struct die_info *die,
|
|
struct type *type)
|
|
{
|
|
if (!set_type_align (type, get_alignment (cu, die)))
|
|
complaint (_("DW_AT_alignment value too large"
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
}
|
|
|
|
/* Check if the given VALUE is a valid enum dwarf_calling_convention
|
|
constant for a type, according to DWARF5 spec, Table 5.5. */
|
|
|
|
static bool
|
|
is_valid_DW_AT_calling_convention_for_type (ULONGEST value)
|
|
{
|
|
switch (value)
|
|
{
|
|
case DW_CC_normal:
|
|
case DW_CC_pass_by_reference:
|
|
case DW_CC_pass_by_value:
|
|
return true;
|
|
|
|
default:
|
|
complaint (_("unrecognized DW_AT_calling_convention value "
|
|
"(%s) for a type"), pulongest (value));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Check if the given VALUE is a valid enum dwarf_calling_convention
|
|
constant for a subroutine, according to DWARF5 spec, Table 3.3, and
|
|
also according to GNU-specific values (see include/dwarf2.h). */
|
|
|
|
static bool
|
|
is_valid_DW_AT_calling_convention_for_subroutine (ULONGEST value)
|
|
{
|
|
switch (value)
|
|
{
|
|
case DW_CC_normal:
|
|
case DW_CC_program:
|
|
case DW_CC_nocall:
|
|
return true;
|
|
|
|
case DW_CC_GNU_renesas_sh:
|
|
case DW_CC_GNU_borland_fastcall_i386:
|
|
case DW_CC_GDB_IBM_OpenCL:
|
|
return true;
|
|
|
|
default:
|
|
complaint (_("unrecognized DW_AT_calling_convention value "
|
|
"(%s) for a subroutine"), pulongest (value));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Called when we find the DIE that starts a structure or union scope
|
|
(definition) to create a type for the structure or union. Fill in
|
|
the type's name and general properties; the members will not be
|
|
processed until process_structure_scope. A symbol table entry for
|
|
the type will also not be done until process_structure_scope (assuming
|
|
the type has a name).
|
|
|
|
NOTE: we need to call these functions regardless of whether or not the
|
|
DIE has a DW_AT_name attribute, since it might be an anonymous
|
|
structure or union. This gets the type entered into our set of
|
|
user defined types. */
|
|
|
|
static struct type *
|
|
read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct type *type;
|
|
struct attribute *attr;
|
|
const char *name;
|
|
|
|
/* If the definition of this type lives in .debug_types, read that type.
|
|
Don't follow DW_AT_specification though, that will take us back up
|
|
the chain and we want to go down. */
|
|
attr = die->attr (DW_AT_signature);
|
|
if (attr != nullptr)
|
|
{
|
|
type = get_DW_AT_signature_type (die, attr, cu);
|
|
|
|
/* The type's CU may not be the same as CU.
|
|
Ensure TYPE is recorded with CU in die_type_hash. */
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
type = type_allocator (objfile, cu->lang ()).new_type ();
|
|
INIT_CPLUS_SPECIFIC (type);
|
|
|
|
name = dwarf2_name (die, cu);
|
|
if (name != NULL)
|
|
{
|
|
if (is_cplus_dialect (cu->lang ())
|
|
|| cu->lang () == language_d
|
|
|| cu->lang () == language_rust)
|
|
{
|
|
const char *full_name = dwarf2_full_name (name, die, cu);
|
|
|
|
/* dwarf2_full_name might have already finished building the DIE's
|
|
type. If so, there is no need to continue. */
|
|
if (get_die_type (die, cu) != NULL)
|
|
return get_die_type (die, cu);
|
|
|
|
type->set_name (full_name);
|
|
}
|
|
else
|
|
{
|
|
/* The name is already allocated along with this objfile, so
|
|
we don't need to duplicate it for the type. */
|
|
type->set_name (name);
|
|
}
|
|
}
|
|
|
|
if (die->tag == DW_TAG_structure_type)
|
|
{
|
|
type->set_code (TYPE_CODE_STRUCT);
|
|
}
|
|
else if (die->tag == DW_TAG_union_type)
|
|
{
|
|
type->set_code (TYPE_CODE_UNION);
|
|
}
|
|
else if (die->tag == DW_TAG_namelist)
|
|
{
|
|
type->set_code (TYPE_CODE_NAMELIST);
|
|
}
|
|
else
|
|
{
|
|
type->set_code (TYPE_CODE_STRUCT);
|
|
}
|
|
|
|
if (is_cplus_dialect (cu->lang ()) && die->tag == DW_TAG_class_type)
|
|
type->set_is_declared_class (true);
|
|
|
|
/* Store the calling convention in the type if it's available in
|
|
the die. Otherwise the calling convention remains set to
|
|
the default value DW_CC_normal. */
|
|
attr = dwarf2_attr (die, DW_AT_calling_convention, cu);
|
|
if (attr != nullptr
|
|
&& is_valid_DW_AT_calling_convention_for_type (attr->constant_value (0)))
|
|
{
|
|
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
|
TYPE_CPLUS_CALLING_CONVENTION (type)
|
|
= (enum dwarf_calling_convention) (attr->constant_value (0));
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
if (attr->form_is_constant ())
|
|
type->set_length (attr->constant_value (0));
|
|
else
|
|
{
|
|
struct dynamic_prop prop;
|
|
if (attr_to_dynamic_prop (attr, die, cu, &prop, cu->addr_type ()))
|
|
type->add_dyn_prop (DYN_PROP_BYTE_SIZE, prop);
|
|
|
|
type->set_length (0);
|
|
}
|
|
}
|
|
else
|
|
type->set_length (0);
|
|
|
|
maybe_set_alignment (cu, die, type);
|
|
|
|
if (producer_is_icc_lt_14 (cu) && (type->length () == 0))
|
|
{
|
|
/* ICC<14 does not output the required DW_AT_declaration on
|
|
incomplete types, but gives them a size of zero. */
|
|
type->set_is_stub (true);
|
|
}
|
|
else
|
|
type->set_stub_is_supported (true);
|
|
|
|
if (die_is_declaration (die, cu))
|
|
type->set_is_stub (true);
|
|
else if (attr == NULL && die->child == NULL
|
|
&& producer_is_realview (cu->producer))
|
|
/* RealView does not output the required DW_AT_declaration
|
|
on incomplete types. */
|
|
type->set_is_stub (true);
|
|
|
|
/* We need to add the type field to the die immediately so we don't
|
|
infinitely recurse when dealing with pointers to the structure
|
|
type within the structure itself. */
|
|
set_die_type (die, type, cu);
|
|
|
|
/* set_die_type should be already done. */
|
|
set_descriptive_type (type, die, cu);
|
|
|
|
return type;
|
|
}
|
|
|
|
static void handle_struct_member_die
|
|
(struct die_info *child_die,
|
|
struct type *type,
|
|
struct field_info *fi,
|
|
std::vector<struct symbol *> *template_args,
|
|
struct dwarf2_cu *cu);
|
|
|
|
/* A helper for handle_struct_member_die that handles
|
|
DW_TAG_variant_part. */
|
|
|
|
static void
|
|
handle_variant_part (struct die_info *die, struct type *type,
|
|
struct field_info *fi,
|
|
std::vector<struct symbol *> *template_args,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
variant_part_builder *new_part;
|
|
if (fi->current_variant_part == nullptr)
|
|
new_part = &fi->variant_parts.emplace_back ();
|
|
else if (!fi->current_variant_part->processing_variant)
|
|
{
|
|
complaint (_("nested DW_TAG_variant_part seen "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
variant_field ¤t = fi->current_variant_part->variants.back ();
|
|
new_part = ¤t.variant_parts.emplace_back ();
|
|
}
|
|
|
|
/* When we recurse, we want callees to add to this new variant
|
|
part. */
|
|
scoped_restore save_current_variant_part
|
|
= make_scoped_restore (&fi->current_variant_part, new_part);
|
|
|
|
struct attribute *discr = dwarf2_attr (die, DW_AT_discr, cu);
|
|
if (discr == NULL)
|
|
{
|
|
/* It's a univariant form, an extension we support. */
|
|
}
|
|
else if (discr->form_is_ref ())
|
|
{
|
|
struct dwarf2_cu *target_cu = cu;
|
|
struct die_info *target_die = follow_die_ref (die, discr, &target_cu);
|
|
|
|
new_part->discriminant_offset = target_die->sect_off;
|
|
}
|
|
else
|
|
{
|
|
complaint (_("DW_AT_discr does not have DIE reference form"
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
}
|
|
|
|
for (die_info *child_die = die->child;
|
|
child_die != NULL;
|
|
child_die = child_die->sibling)
|
|
handle_struct_member_die (child_die, type, fi, template_args, cu);
|
|
}
|
|
|
|
/* A helper for handle_struct_member_die that handles
|
|
DW_TAG_variant. */
|
|
|
|
static void
|
|
handle_variant (struct die_info *die, struct type *type,
|
|
struct field_info *fi,
|
|
std::vector<struct symbol *> *template_args,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
if (fi->current_variant_part == nullptr)
|
|
{
|
|
complaint (_("saw DW_TAG_variant outside DW_TAG_variant_part "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
return;
|
|
}
|
|
if (fi->current_variant_part->processing_variant)
|
|
{
|
|
complaint (_("nested DW_TAG_variant seen "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
return;
|
|
}
|
|
|
|
scoped_restore save_processing_variant
|
|
= make_scoped_restore (&fi->current_variant_part->processing_variant,
|
|
true);
|
|
|
|
variant_field &variant = fi->current_variant_part->variants.emplace_back ();
|
|
variant.first_field = fi->fields.size ();
|
|
|
|
/* In a variant we want to get the discriminant and also add a
|
|
field for our sole member child. */
|
|
struct attribute *discr = dwarf2_attr (die, DW_AT_discr_value, cu);
|
|
if (discr == nullptr || !discr->form_is_constant ())
|
|
{
|
|
discr = dwarf2_attr (die, DW_AT_discr_list, cu);
|
|
if (discr == nullptr || discr->as_block ()->size == 0)
|
|
variant.default_branch = true;
|
|
else
|
|
variant.discr_list_data = discr->as_block ();
|
|
}
|
|
else
|
|
variant.discriminant_value = discr->constant_value (0);
|
|
|
|
for (die_info *variant_child = die->child;
|
|
variant_child != NULL;
|
|
variant_child = variant_child->sibling)
|
|
handle_struct_member_die (variant_child, type, fi, template_args, cu);
|
|
|
|
variant.last_field = fi->fields.size ();
|
|
}
|
|
|
|
/* A helper for process_structure_scope that handles a single member
|
|
DIE. */
|
|
|
|
static void
|
|
handle_struct_member_die (struct die_info *child_die, struct type *type,
|
|
struct field_info *fi,
|
|
std::vector<struct symbol *> *template_args,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
if (child_die->tag == DW_TAG_member
|
|
|| child_die->tag == DW_TAG_variable
|
|
|| child_die->tag == DW_TAG_namelist_item)
|
|
{
|
|
/* NOTE: carlton/2002-11-05: A C++ static data member
|
|
should be a DW_TAG_member that is a declaration, but
|
|
all versions of G++ as of this writing (so through at
|
|
least 3.2.1) incorrectly generate DW_TAG_variable
|
|
tags for them instead. */
|
|
dwarf2_add_field (fi, child_die, cu);
|
|
}
|
|
else if (child_die->tag == DW_TAG_subprogram)
|
|
{
|
|
/* Rust doesn't have member functions in the C++ sense.
|
|
However, it does emit ordinary functions as children
|
|
of a struct DIE. */
|
|
if (cu->lang () == language_rust)
|
|
read_func_scope (child_die, cu);
|
|
else
|
|
{
|
|
/* C++ member function. */
|
|
dwarf2_add_member_fn (fi, child_die, type, cu);
|
|
}
|
|
}
|
|
else if (child_die->tag == DW_TAG_inheritance)
|
|
{
|
|
/* C++ base class field. */
|
|
dwarf2_add_field (fi, child_die, cu);
|
|
}
|
|
else if (type_can_define_types (child_die))
|
|
dwarf2_add_type_defn (fi, child_die, cu);
|
|
else if (child_die->tag == DW_TAG_template_type_param
|
|
|| child_die->tag == DW_TAG_template_value_param)
|
|
{
|
|
struct symbol *arg = new_symbol (child_die, NULL, cu);
|
|
|
|
if (arg != NULL)
|
|
template_args->push_back (arg);
|
|
}
|
|
else if (child_die->tag == DW_TAG_variant_part)
|
|
handle_variant_part (child_die, type, fi, template_args, cu);
|
|
else if (child_die->tag == DW_TAG_variant)
|
|
handle_variant (child_die, type, fi, template_args, cu);
|
|
}
|
|
|
|
/* Finish creating a structure or union type, including filling in its
|
|
members and creating a symbol for it. This function also handles Fortran
|
|
namelist variables, their items or members and creating a symbol for
|
|
them. */
|
|
|
|
static void
|
|
process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct die_info *child_die;
|
|
struct type *type;
|
|
|
|
type = get_die_type (die, cu);
|
|
if (type == NULL)
|
|
type = read_structure_type (die, cu);
|
|
|
|
bool has_template_parameters = false;
|
|
if (die->child != NULL && ! die_is_declaration (die, cu))
|
|
{
|
|
struct field_info fi;
|
|
std::vector<struct symbol *> template_args;
|
|
|
|
child_die = die->child;
|
|
|
|
while (child_die && child_die->tag)
|
|
{
|
|
handle_struct_member_die (child_die, type, &fi, &template_args, cu);
|
|
child_die = child_die->sibling;
|
|
}
|
|
|
|
/* Attach template arguments to type. */
|
|
if (!template_args.empty ())
|
|
{
|
|
has_template_parameters = true;
|
|
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
|
TYPE_N_TEMPLATE_ARGUMENTS (type) = template_args.size ();
|
|
TYPE_TEMPLATE_ARGUMENTS (type)
|
|
= XOBNEWVEC (&objfile->objfile_obstack,
|
|
struct symbol *,
|
|
TYPE_N_TEMPLATE_ARGUMENTS (type));
|
|
memcpy (TYPE_TEMPLATE_ARGUMENTS (type),
|
|
template_args.data (),
|
|
(TYPE_N_TEMPLATE_ARGUMENTS (type)
|
|
* sizeof (struct symbol *)));
|
|
}
|
|
|
|
/* Attach fields and member functions to the type. */
|
|
if (fi.nfields () > 0)
|
|
dwarf2_attach_fields_to_type (&fi, type, cu);
|
|
if (!fi.fnfieldlists.empty ())
|
|
{
|
|
dwarf2_attach_fn_fields_to_type (&fi, type, cu);
|
|
|
|
/* Get the type which refers to the base class (possibly this
|
|
class itself) which contains the vtable pointer for the current
|
|
class from the DW_AT_containing_type attribute. This use of
|
|
DW_AT_containing_type is a GNU extension. */
|
|
|
|
if (dwarf2_attr (die, DW_AT_containing_type, cu) != NULL)
|
|
{
|
|
struct type *t = die_containing_type (die, cu);
|
|
|
|
set_type_vptr_basetype (type, t);
|
|
if (type == t)
|
|
{
|
|
int i;
|
|
|
|
/* Our own class provides vtbl ptr. */
|
|
for (i = t->num_fields () - 1;
|
|
i >= TYPE_N_BASECLASSES (t);
|
|
--i)
|
|
{
|
|
const char *fieldname = t->field (i).name ();
|
|
|
|
if (is_vtable_name (fieldname, cu))
|
|
{
|
|
set_type_vptr_fieldno (type, i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Complain if virtual function table field not found. */
|
|
if (i < TYPE_N_BASECLASSES (t))
|
|
complaint (_("virtual function table pointer "
|
|
"not found when defining class '%s'"),
|
|
type->name () ? type->name () : "");
|
|
}
|
|
else
|
|
{
|
|
set_type_vptr_fieldno (type, TYPE_VPTR_FIELDNO (t));
|
|
}
|
|
}
|
|
else if (cu->producer
|
|
&& startswith (cu->producer, "IBM(R) XL C/C++ Advanced Edition"))
|
|
{
|
|
/* The IBM XLC compiler does not provide direct indication
|
|
of the containing type, but the vtable pointer is
|
|
always named __vfp. */
|
|
|
|
int i;
|
|
|
|
for (i = type->num_fields () - 1;
|
|
i >= TYPE_N_BASECLASSES (type);
|
|
--i)
|
|
{
|
|
if (strcmp (type->field (i).name (), "__vfp") == 0)
|
|
{
|
|
set_type_vptr_fieldno (type, i);
|
|
set_type_vptr_basetype (type, type);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Copy fi.typedef_field_list linked list elements content into the
|
|
allocated array TYPE_TYPEDEF_FIELD_ARRAY (type). */
|
|
if (!fi.typedef_field_list.empty ())
|
|
{
|
|
int count = fi.typedef_field_list.size ();
|
|
|
|
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
|
/* No zero-initialization is needed, the elements are initialized by
|
|
the copy in the loop below. */
|
|
TYPE_TYPEDEF_FIELD_ARRAY (type)
|
|
= ((struct decl_field *)
|
|
TYPE_ALLOC (type,
|
|
sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * count));
|
|
TYPE_TYPEDEF_FIELD_COUNT (type) = count;
|
|
|
|
for (int i = 0; i < fi.typedef_field_list.size (); ++i)
|
|
TYPE_TYPEDEF_FIELD (type, i) = fi.typedef_field_list[i];
|
|
}
|
|
|
|
/* Copy fi.nested_types_list linked list elements content into the
|
|
allocated array TYPE_NESTED_TYPES_ARRAY (type). */
|
|
if (!fi.nested_types_list.empty ()
|
|
&& cu->lang () != language_ada)
|
|
{
|
|
int count = fi.nested_types_list.size ();
|
|
|
|
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
|
/* No zero-initialization is needed, the elements are initialized by
|
|
the copy in the loop below. */
|
|
TYPE_NESTED_TYPES_ARRAY (type)
|
|
= ((struct decl_field *)
|
|
TYPE_ALLOC (type, sizeof (struct decl_field) * count));
|
|
TYPE_NESTED_TYPES_COUNT (type) = count;
|
|
|
|
for (int i = 0; i < fi.nested_types_list.size (); ++i)
|
|
TYPE_NESTED_TYPES_FIELD (type, i) = fi.nested_types_list[i];
|
|
}
|
|
}
|
|
|
|
quirk_gcc_member_function_pointer (type, objfile);
|
|
if (cu->lang () == language_rust && die->tag == DW_TAG_union_type)
|
|
cu->rust_unions.push_back (type);
|
|
else if (cu->lang () == language_ada)
|
|
quirk_ada_thick_pointer_struct (die, cu, type);
|
|
|
|
/* NOTE: carlton/2004-03-16: GCC 3.4 (or at least one of its
|
|
snapshots) has been known to create a die giving a declaration
|
|
for a class that has, as a child, a die giving a definition for a
|
|
nested class. So we have to process our children even if the
|
|
current die is a declaration. Normally, of course, a declaration
|
|
won't have any children at all. */
|
|
|
|
child_die = die->child;
|
|
|
|
while (child_die != NULL && child_die->tag)
|
|
{
|
|
if (child_die->tag == DW_TAG_member
|
|
|| child_die->tag == DW_TAG_variable
|
|
|| child_die->tag == DW_TAG_inheritance
|
|
|| child_die->tag == DW_TAG_template_value_param
|
|
|| child_die->tag == DW_TAG_template_type_param)
|
|
{
|
|
/* Do nothing. */
|
|
}
|
|
else
|
|
process_die (child_die, cu);
|
|
|
|
child_die = child_die->sibling;
|
|
}
|
|
|
|
/* Do not consider external references. According to the DWARF standard,
|
|
these DIEs are identified by the fact that they have no byte_size
|
|
attribute, and a declaration attribute. */
|
|
if (dwarf2_attr (die, DW_AT_byte_size, cu) != NULL
|
|
|| !die_is_declaration (die, cu)
|
|
|| dwarf2_attr (die, DW_AT_signature, cu) != NULL)
|
|
{
|
|
struct symbol *sym = new_symbol (die, type, cu);
|
|
|
|
if (has_template_parameters)
|
|
{
|
|
struct symtab *symtab;
|
|
if (sym != nullptr)
|
|
symtab = sym->symtab ();
|
|
else if (cu->line_header != nullptr)
|
|
{
|
|
/* Any related symtab will do. */
|
|
symtab
|
|
= cu->line_header->file_names ()[0].symtab;
|
|
}
|
|
else
|
|
{
|
|
symtab = nullptr;
|
|
complaint (_("could not find suitable "
|
|
"symtab for template parameter"
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (objfile));
|
|
}
|
|
|
|
if (symtab != nullptr)
|
|
{
|
|
/* Make sure that the symtab is set on the new symbols.
|
|
Even though they don't appear in this symtab directly,
|
|
other parts of gdb assume that symbols do, and this is
|
|
reasonably true. */
|
|
for (int i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (type); ++i)
|
|
TYPE_TEMPLATE_ARGUMENT (type, i)->set_symtab (symtab);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Read DW_AT_endianity from DIE and compute the byte order that
|
|
should be used. The CU's arch is used as the default. The result
|
|
is true if the returned arch differs from the default, and false if
|
|
they are the same. If provided, the out parameter BYTE_ORDER is
|
|
also set. */
|
|
|
|
static bool
|
|
die_byte_order (die_info *die, dwarf2_cu *cu, enum bfd_endian *byte_order)
|
|
{
|
|
gdbarch *arch = cu->per_objfile->objfile->arch ();
|
|
enum bfd_endian arch_order = gdbarch_byte_order (arch);
|
|
enum bfd_endian new_order = arch_order;
|
|
|
|
attribute *attr = dwarf2_attr (die, DW_AT_endianity, cu);
|
|
if (attr != nullptr && attr->form_is_constant ())
|
|
{
|
|
int endianity = attr->constant_value (0);
|
|
|
|
switch (endianity)
|
|
{
|
|
case DW_END_big:
|
|
new_order = BFD_ENDIAN_BIG;
|
|
break;
|
|
case DW_END_little:
|
|
new_order = BFD_ENDIAN_LITTLE;
|
|
break;
|
|
default:
|
|
complaint (_("DW_AT_endianity has unrecognized value %d"), endianity);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (byte_order != nullptr)
|
|
*byte_order = new_order;
|
|
|
|
return new_order != arch_order;
|
|
}
|
|
|
|
/* Assuming DIE is an enumeration type, and TYPE is its associated
|
|
type, update TYPE using some information only available in DIE's
|
|
children. In particular, the fields are computed. */
|
|
|
|
static void
|
|
update_enumeration_type_from_children (struct die_info *die,
|
|
struct type *type,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct die_info *child_die;
|
|
int unsigned_enum = 1;
|
|
int flag_enum = 1;
|
|
|
|
auto_obstack obstack;
|
|
std::vector<struct field> fields;
|
|
|
|
for (child_die = die->child;
|
|
child_die != NULL && child_die->tag;
|
|
child_die = child_die->sibling)
|
|
{
|
|
struct attribute *attr;
|
|
LONGEST value;
|
|
const gdb_byte *bytes;
|
|
struct dwarf2_locexpr_baton *baton;
|
|
const char *name;
|
|
|
|
if (child_die->tag != DW_TAG_enumerator)
|
|
continue;
|
|
|
|
attr = dwarf2_attr (child_die, DW_AT_const_value, cu);
|
|
if (attr == NULL)
|
|
continue;
|
|
|
|
name = dwarf2_name (child_die, cu);
|
|
if (name == NULL)
|
|
name = "<anonymous enumerator>";
|
|
|
|
dwarf2_const_value_attr (attr, type, name, &obstack, cu,
|
|
&value, &bytes, &baton);
|
|
if (value < 0)
|
|
{
|
|
unsigned_enum = 0;
|
|
flag_enum = 0;
|
|
}
|
|
else
|
|
{
|
|
if (count_one_bits_ll (value) >= 2)
|
|
flag_enum = 0;
|
|
}
|
|
|
|
struct field &field = fields.emplace_back ();
|
|
field.set_name (dwarf2_physname (name, child_die, cu));
|
|
field.set_loc_enumval (value);
|
|
}
|
|
|
|
if (!fields.empty ())
|
|
type->copy_fields (fields);
|
|
else
|
|
flag_enum = 0;
|
|
|
|
if (unsigned_enum)
|
|
type->set_is_unsigned (true);
|
|
|
|
if (flag_enum)
|
|
type->set_is_flag_enum (true);
|
|
}
|
|
|
|
/* Given a DW_AT_enumeration_type die, set its type. We do not
|
|
complete the type's fields yet, or create any symbols. */
|
|
|
|
static struct type *
|
|
read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct type *type;
|
|
struct attribute *attr;
|
|
const char *name;
|
|
|
|
/* If the definition of this type lives in .debug_types, read that type.
|
|
Don't follow DW_AT_specification though, that will take us back up
|
|
the chain and we want to go down. */
|
|
attr = die->attr (DW_AT_signature);
|
|
if (attr != nullptr)
|
|
{
|
|
type = get_DW_AT_signature_type (die, attr, cu);
|
|
|
|
/* The type's CU may not be the same as CU.
|
|
Ensure TYPE is recorded with CU in die_type_hash. */
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
type = type_allocator (objfile, cu->lang ()).new_type ();
|
|
|
|
type->set_code (TYPE_CODE_ENUM);
|
|
name = dwarf2_full_name (NULL, die, cu);
|
|
if (name != NULL)
|
|
type->set_name (name);
|
|
|
|
attr = dwarf2_attr (die, DW_AT_type, cu);
|
|
if (attr != NULL)
|
|
{
|
|
struct type *underlying_type = die_type (die, cu);
|
|
|
|
type->set_target_type (underlying_type);
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr != nullptr)
|
|
type->set_length (attr->constant_value (0));
|
|
else
|
|
type->set_length (0);
|
|
|
|
maybe_set_alignment (cu, die, type);
|
|
|
|
/* The enumeration DIE can be incomplete. In Ada, any type can be
|
|
declared as private in the package spec, and then defined only
|
|
inside the package body. Such types are known as Taft Amendment
|
|
Types. When another package uses such a type, an incomplete DIE
|
|
may be generated by the compiler. */
|
|
if (die_is_declaration (die, cu))
|
|
type->set_is_stub (true);
|
|
|
|
/* If this type has an underlying type that is not a stub, then we
|
|
may use its attributes. We always use the "unsigned" attribute
|
|
in this situation, because ordinarily we guess whether the type
|
|
is unsigned -- but the guess can be wrong and the underlying type
|
|
can tell us the reality. However, we defer to a local size
|
|
attribute if one exists, because this lets the compiler override
|
|
the underlying type if needed. */
|
|
if (type->target_type () != NULL && !type->target_type ()->is_stub ())
|
|
{
|
|
struct type *underlying_type = type->target_type ();
|
|
underlying_type = check_typedef (underlying_type);
|
|
|
|
type->set_is_unsigned (underlying_type->is_unsigned ());
|
|
|
|
if (type->length () == 0)
|
|
type->set_length (underlying_type->length ());
|
|
|
|
if (TYPE_RAW_ALIGN (type) == 0
|
|
&& TYPE_RAW_ALIGN (underlying_type) != 0)
|
|
set_type_align (type, TYPE_RAW_ALIGN (underlying_type));
|
|
}
|
|
|
|
type->set_is_declared_class (dwarf2_flag_true_p (die, DW_AT_enum_class, cu));
|
|
|
|
type->set_endianity_is_not_default (die_byte_order (die, cu, nullptr));
|
|
|
|
set_die_type (die, type, cu);
|
|
|
|
/* Finish the creation of this type by using the enum's children.
|
|
Note that, as usual, this must come after set_die_type to avoid
|
|
infinite recursion when trying to compute the names of the
|
|
enumerators. */
|
|
update_enumeration_type_from_children (die, type, cu);
|
|
|
|
return type;
|
|
}
|
|
|
|
/* Given a pointer to a die which begins an enumeration, process all
|
|
the dies that define the members of the enumeration, and create the
|
|
symbol for the enumeration type.
|
|
|
|
NOTE: We reverse the order of the element list. */
|
|
|
|
static void
|
|
process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *this_type;
|
|
|
|
this_type = get_die_type (die, cu);
|
|
if (this_type == NULL)
|
|
this_type = read_enumeration_type (die, cu);
|
|
|
|
if (die->child != NULL)
|
|
{
|
|
struct die_info *child_die;
|
|
|
|
child_die = die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
if (child_die->tag != DW_TAG_enumerator)
|
|
{
|
|
process_die (child_die, cu);
|
|
}
|
|
else
|
|
new_symbol (child_die, this_type, cu);
|
|
|
|
child_die = child_die->sibling;
|
|
}
|
|
}
|
|
|
|
/* If we are reading an enum from a .debug_types unit, and the enum
|
|
is a declaration, and the enum is not the signatured type in the
|
|
unit, then we do not want to add a symbol for it. Adding a
|
|
symbol would in some cases obscure the true definition of the
|
|
enum, giving users an incomplete type when the definition is
|
|
actually available. Note that we do not want to do this for all
|
|
enums which are just declarations, because C++0x allows forward
|
|
enum declarations. */
|
|
if (cu->per_cu->is_debug_types
|
|
&& die_is_declaration (die, cu))
|
|
{
|
|
struct signatured_type *sig_type;
|
|
|
|
sig_type = (struct signatured_type *) cu->per_cu;
|
|
gdb_assert (to_underlying (sig_type->type_offset_in_section) != 0);
|
|
if (sig_type->type_offset_in_section != die->sect_off)
|
|
return;
|
|
}
|
|
|
|
new_symbol (die, this_type, cu);
|
|
}
|
|
|
|
/* Helper function for quirk_ada_thick_pointer that examines a bounds
|
|
expression for an index type and finds the corresponding field
|
|
offset in the hidden "P_BOUNDS" structure. Returns true on success
|
|
and updates *FIELD, false if it fails to recognize an
|
|
expression. */
|
|
|
|
static bool
|
|
recognize_bound_expression (struct die_info *die, enum dwarf_attribute name,
|
|
int *bounds_offset, struct field *field,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr = dwarf2_attr (die, name, cu);
|
|
if (attr == nullptr || !attr->form_is_block ())
|
|
return false;
|
|
|
|
const struct dwarf_block *block = attr->as_block ();
|
|
const gdb_byte *start = block->data;
|
|
const gdb_byte *end = block->data + block->size;
|
|
|
|
/* The expression to recognize generally looks like:
|
|
|
|
(DW_OP_push_object_address; DW_OP_plus_uconst: 8; DW_OP_deref;
|
|
DW_OP_plus_uconst: 4; DW_OP_deref_size: 4)
|
|
|
|
However, the second "plus_uconst" may be missing:
|
|
|
|
(DW_OP_push_object_address; DW_OP_plus_uconst: 8; DW_OP_deref;
|
|
DW_OP_deref_size: 4)
|
|
|
|
This happens when the field is at the start of the structure.
|
|
|
|
Also, the final deref may not be sized:
|
|
|
|
(DW_OP_push_object_address; DW_OP_plus_uconst: 4; DW_OP_deref;
|
|
DW_OP_deref)
|
|
|
|
This happens when the size of the index type happens to be the
|
|
same as the architecture's word size. This can occur with or
|
|
without the second plus_uconst. */
|
|
|
|
if (end - start < 2)
|
|
return false;
|
|
if (*start++ != DW_OP_push_object_address)
|
|
return false;
|
|
if (*start++ != DW_OP_plus_uconst)
|
|
return false;
|
|
|
|
uint64_t this_bound_off;
|
|
start = gdb_read_uleb128 (start, end, &this_bound_off);
|
|
if (start == nullptr || (int) this_bound_off != this_bound_off)
|
|
return false;
|
|
/* Update *BOUNDS_OFFSET if needed, or alternatively verify that it
|
|
is consistent among all bounds. */
|
|
if (*bounds_offset == -1)
|
|
*bounds_offset = this_bound_off;
|
|
else if (*bounds_offset != this_bound_off)
|
|
return false;
|
|
|
|
if (start == end || *start++ != DW_OP_deref)
|
|
return false;
|
|
|
|
int offset = 0;
|
|
if (start ==end)
|
|
return false;
|
|
else if (*start == DW_OP_deref_size || *start == DW_OP_deref)
|
|
{
|
|
/* This means an offset of 0. */
|
|
}
|
|
else if (*start++ != DW_OP_plus_uconst)
|
|
return false;
|
|
else
|
|
{
|
|
/* The size is the parameter to DW_OP_plus_uconst. */
|
|
uint64_t val;
|
|
start = gdb_read_uleb128 (start, end, &val);
|
|
if (start == nullptr)
|
|
return false;
|
|
if ((int) val != val)
|
|
return false;
|
|
offset = val;
|
|
}
|
|
|
|
if (start == end)
|
|
return false;
|
|
|
|
uint64_t size;
|
|
if (*start == DW_OP_deref_size)
|
|
{
|
|
start = gdb_read_uleb128 (start + 1, end, &size);
|
|
if (start == nullptr)
|
|
return false;
|
|
}
|
|
else if (*start == DW_OP_deref)
|
|
{
|
|
size = cu->header.addr_size;
|
|
++start;
|
|
}
|
|
else
|
|
return false;
|
|
|
|
field->set_loc_bitpos (8 * offset);
|
|
if (size != field->type ()->length ())
|
|
field->set_bitsize (8 * size);
|
|
|
|
return true;
|
|
}
|
|
|
|
/* With -fgnat-encodings=minimal, gcc will emit some unusual DWARF for
|
|
some kinds of Ada arrays:
|
|
|
|
<1><11db>: Abbrev Number: 7 (DW_TAG_array_type)
|
|
<11dc> DW_AT_name : (indirect string, offset: 0x1bb8): string
|
|
<11e0> DW_AT_data_location: 2 byte block: 97 6
|
|
(DW_OP_push_object_address; DW_OP_deref)
|
|
<11e3> DW_AT_type : <0x1173>
|
|
<11e7> DW_AT_sibling : <0x1201>
|
|
<2><11eb>: Abbrev Number: 8 (DW_TAG_subrange_type)
|
|
<11ec> DW_AT_type : <0x1206>
|
|
<11f0> DW_AT_lower_bound : 6 byte block: 97 23 8 6 94 4
|
|
(DW_OP_push_object_address; DW_OP_plus_uconst: 8; DW_OP_deref;
|
|
DW_OP_deref_size: 4)
|
|
<11f7> DW_AT_upper_bound : 8 byte block: 97 23 8 6 23 4 94 4
|
|
(DW_OP_push_object_address; DW_OP_plus_uconst: 8; DW_OP_deref;
|
|
DW_OP_plus_uconst: 4; DW_OP_deref_size: 4)
|
|
|
|
This actually represents a "thick pointer", which is a structure
|
|
with two elements: one that is a pointer to the array data, and one
|
|
that is a pointer to another structure; this second structure holds
|
|
the array bounds.
|
|
|
|
This returns a new type on success, or nullptr if this didn't
|
|
recognize the type. */
|
|
|
|
static struct type *
|
|
quirk_ada_thick_pointer (struct die_info *die, struct dwarf2_cu *cu,
|
|
struct type *type)
|
|
{
|
|
struct attribute *attr = dwarf2_attr (die, DW_AT_data_location, cu);
|
|
/* So far we've only seen this with block form. */
|
|
if (attr == nullptr || !attr->form_is_block ())
|
|
return nullptr;
|
|
|
|
/* Note that this will fail if the structure layout is changed by
|
|
the compiler. However, we have no good way to recognize some
|
|
other layout, because we don't know what expression the compiler
|
|
might choose to emit should this happen. */
|
|
struct dwarf_block *blk = attr->as_block ();
|
|
if (blk->size != 2
|
|
|| blk->data[0] != DW_OP_push_object_address
|
|
|| blk->data[1] != DW_OP_deref)
|
|
return nullptr;
|
|
|
|
int bounds_offset = -1;
|
|
int max_align = -1;
|
|
std::vector<struct field> range_fields;
|
|
for (struct die_info *child_die = die->child;
|
|
child_die;
|
|
child_die = child_die->sibling)
|
|
{
|
|
if (child_die->tag == DW_TAG_subrange_type)
|
|
{
|
|
struct type *underlying = read_subrange_index_type (child_die, cu);
|
|
|
|
int this_align = type_align (underlying);
|
|
if (this_align > max_align)
|
|
max_align = this_align;
|
|
|
|
range_fields.emplace_back ();
|
|
range_fields.emplace_back ();
|
|
|
|
struct field &lower = range_fields[range_fields.size () - 2];
|
|
struct field &upper = range_fields[range_fields.size () - 1];
|
|
|
|
lower.set_type (underlying);
|
|
lower.set_is_artificial (true);
|
|
|
|
upper.set_type (underlying);
|
|
upper.set_is_artificial (true);
|
|
|
|
if (!recognize_bound_expression (child_die, DW_AT_lower_bound,
|
|
&bounds_offset, &lower, cu)
|
|
|| !recognize_bound_expression (child_die, DW_AT_upper_bound,
|
|
&bounds_offset, &upper, cu))
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
/* This shouldn't really happen, but double-check that we found
|
|
where the bounds are stored. */
|
|
if (bounds_offset == -1)
|
|
return nullptr;
|
|
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
for (int i = 0; i < range_fields.size (); i += 2)
|
|
{
|
|
char name[20];
|
|
|
|
/* Set the name of each field in the bounds. */
|
|
xsnprintf (name, sizeof (name), "LB%d", i / 2);
|
|
range_fields[i].set_name (objfile->intern (name));
|
|
xsnprintf (name, sizeof (name), "UB%d", i / 2);
|
|
range_fields[i + 1].set_name (objfile->intern (name));
|
|
}
|
|
|
|
type_allocator alloc (objfile, cu->lang ());
|
|
struct type *bounds = alloc.new_type ();
|
|
bounds->set_code (TYPE_CODE_STRUCT);
|
|
|
|
bounds->copy_fields (range_fields);
|
|
|
|
int last_fieldno = range_fields.size () - 1;
|
|
int bounds_size = (bounds->field (last_fieldno).loc_bitpos () / 8
|
|
+ bounds->field (last_fieldno).type ()->length ());
|
|
bounds->set_length (align_up (bounds_size, max_align));
|
|
|
|
/* Rewrite the existing array type in place. Specifically, we
|
|
remove any dynamic properties we might have read, and we replace
|
|
the index types. */
|
|
struct type *iter = type;
|
|
for (int i = 0; i < range_fields.size (); i += 2)
|
|
{
|
|
gdb_assert (iter->code () == TYPE_CODE_ARRAY);
|
|
iter->main_type->dyn_prop_list = nullptr;
|
|
iter->set_index_type
|
|
(create_static_range_type (alloc, bounds->field (i).type (), 1, 0));
|
|
iter = iter->target_type ();
|
|
}
|
|
|
|
struct type *result = type_allocator (objfile, cu->lang ()).new_type ();
|
|
result->set_code (TYPE_CODE_STRUCT);
|
|
|
|
result->alloc_fields (2);
|
|
|
|
/* The names are chosen to coincide with what the compiler does with
|
|
-fgnat-encodings=all, which the Ada code in gdb already
|
|
understands. */
|
|
result->field (0).set_name ("P_ARRAY");
|
|
result->field (0).set_type (lookup_pointer_type (type));
|
|
|
|
result->field (1).set_name ("P_BOUNDS");
|
|
result->field (1).set_type (lookup_pointer_type (bounds));
|
|
result->field (1).set_loc_bitpos (8 * bounds_offset);
|
|
|
|
result->set_name (type->name ());
|
|
result->set_length (result->field (0).type ()->length ()
|
|
+ result->field (1).type ()->length ());
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Extract all information from a DW_TAG_array_type DIE and put it in
|
|
the DIE's type field. For now, this only handles one dimensional
|
|
arrays. */
|
|
|
|
static struct type *
|
|
read_array_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct die_info *child_die;
|
|
struct type *type;
|
|
struct type *element_type, *range_type, *index_type;
|
|
struct attribute *attr;
|
|
const char *name;
|
|
struct dynamic_prop *byte_stride_prop = NULL;
|
|
unsigned int bit_stride = 0;
|
|
|
|
element_type = die_type (die, cu);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
type = get_die_type (die, cu);
|
|
if (type)
|
|
return type;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_byte_stride, cu);
|
|
if (attr != NULL)
|
|
{
|
|
int stride_ok;
|
|
struct type *prop_type = cu->addr_sized_int_type (false);
|
|
|
|
byte_stride_prop
|
|
= (struct dynamic_prop *) alloca (sizeof (struct dynamic_prop));
|
|
stride_ok = attr_to_dynamic_prop (attr, die, cu, byte_stride_prop,
|
|
prop_type);
|
|
if (!stride_ok)
|
|
{
|
|
complaint (_("unable to read array DW_AT_byte_stride "
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
/* Ignore this attribute. We will likely not be able to print
|
|
arrays of this type correctly, but there is little we can do
|
|
to help if we cannot read the attribute's value. */
|
|
byte_stride_prop = NULL;
|
|
}
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_bit_stride, cu);
|
|
if (attr != NULL)
|
|
bit_stride = attr->constant_value (0);
|
|
|
|
/* Irix 6.2 native cc creates array types without children for
|
|
arrays with unspecified length. */
|
|
if (die->child == NULL)
|
|
{
|
|
index_type = builtin_type (objfile)->builtin_int;
|
|
type_allocator alloc (objfile, cu->lang ());
|
|
range_type = create_static_range_type (alloc, index_type, 0, -1);
|
|
type = create_array_type_with_stride (alloc, element_type, range_type,
|
|
byte_stride_prop, bit_stride);
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
std::vector<struct type *> range_types;
|
|
child_die = die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
if (child_die->tag == DW_TAG_subrange_type
|
|
|| child_die->tag == DW_TAG_generic_subrange)
|
|
{
|
|
struct type *child_type = read_type_die (child_die, cu);
|
|
|
|
if (child_type != NULL)
|
|
{
|
|
/* The range type was successfully read. Save it for the
|
|
array type creation. */
|
|
range_types.push_back (child_type);
|
|
}
|
|
}
|
|
child_die = child_die->sibling;
|
|
}
|
|
|
|
if (range_types.empty ())
|
|
{
|
|
complaint (_("unable to find array range - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
return NULL;
|
|
}
|
|
|
|
/* Dwarf2 dimensions are output from left to right, create the
|
|
necessary array types in backwards order. */
|
|
|
|
type = element_type;
|
|
|
|
type_allocator alloc (cu->per_objfile->objfile, cu->lang ());
|
|
if (read_array_order (die, cu) == DW_ORD_col_major)
|
|
{
|
|
int i = 0;
|
|
|
|
while (i < range_types.size ())
|
|
{
|
|
type = create_array_type_with_stride (alloc, type, range_types[i++],
|
|
byte_stride_prop, bit_stride);
|
|
type->set_is_multi_dimensional (true);
|
|
bit_stride = 0;
|
|
byte_stride_prop = nullptr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size_t ndim = range_types.size ();
|
|
while (ndim-- > 0)
|
|
{
|
|
type = create_array_type_with_stride (alloc, type, range_types[ndim],
|
|
byte_stride_prop, bit_stride);
|
|
type->set_is_multi_dimensional (true);
|
|
bit_stride = 0;
|
|
byte_stride_prop = nullptr;
|
|
}
|
|
}
|
|
|
|
/* Clear the flag on the outermost array type. */
|
|
type->set_is_multi_dimensional (false);
|
|
gdb_assert (type != element_type);
|
|
|
|
/* Understand Dwarf2 support for vector types (like they occur on
|
|
the PowerPC w/ AltiVec). Gcc just adds another attribute to the
|
|
array type. This is not part of the Dwarf2/3 standard yet, but a
|
|
custom vendor extension. The main difference between a regular
|
|
array and the vector variant is that vectors are passed by value
|
|
to functions. */
|
|
attr = dwarf2_attr (die, DW_AT_GNU_vector, cu);
|
|
if (attr != nullptr)
|
|
make_vector_type (type);
|
|
|
|
/* The DIE may have DW_AT_byte_size set. For example an OpenCL
|
|
implementation may choose to implement triple vectors using this
|
|
attribute. */
|
|
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr != nullptr && attr->form_is_unsigned ())
|
|
{
|
|
if (attr->as_unsigned () >= type->length ())
|
|
type->set_length (attr->as_unsigned ());
|
|
else
|
|
complaint (_("DW_AT_byte_size for array type smaller "
|
|
"than the total size of elements"));
|
|
}
|
|
|
|
name = dwarf2_name (die, cu);
|
|
if (name)
|
|
type->set_name (name);
|
|
|
|
maybe_set_alignment (cu, die, type);
|
|
|
|
struct type *replacement_type = nullptr;
|
|
if (cu->lang () == language_ada)
|
|
{
|
|
replacement_type = quirk_ada_thick_pointer (die, cu, type);
|
|
if (replacement_type != nullptr)
|
|
type = replacement_type;
|
|
}
|
|
|
|
/* Install the type in the die. */
|
|
set_die_type (die, type, cu, replacement_type != nullptr);
|
|
|
|
/* set_die_type should be already done. */
|
|
set_descriptive_type (type, die, cu);
|
|
|
|
return type;
|
|
}
|
|
|
|
static enum dwarf_array_dim_ordering
|
|
read_array_order (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_ordering, cu);
|
|
|
|
if (attr != nullptr)
|
|
{
|
|
LONGEST val = attr->constant_value (-1);
|
|
if (val == DW_ORD_row_major || val == DW_ORD_col_major)
|
|
return (enum dwarf_array_dim_ordering) val;
|
|
}
|
|
|
|
/* GNU F77 is a special case, as at 08/2004 array type info is the
|
|
opposite order to the dwarf2 specification, but data is still
|
|
laid out as per normal fortran.
|
|
|
|
FIXME: dsl/2004-8-20: If G77 is ever fixed, this will also need
|
|
version checking. */
|
|
|
|
if (cu->lang () == language_fortran
|
|
&& cu->producer && strstr (cu->producer, "GNU F77"))
|
|
{
|
|
return DW_ORD_row_major;
|
|
}
|
|
|
|
switch (cu->language_defn->array_ordering ())
|
|
{
|
|
case array_column_major:
|
|
return DW_ORD_col_major;
|
|
case array_row_major:
|
|
default:
|
|
return DW_ORD_row_major;
|
|
};
|
|
}
|
|
|
|
/* Extract all information from a DW_TAG_set_type DIE and put it in
|
|
the DIE's type field. */
|
|
|
|
static struct type *
|
|
read_set_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *domain_type, *set_type;
|
|
struct attribute *attr;
|
|
|
|
domain_type = die_type (die, cu);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
set_type = get_die_type (die, cu);
|
|
if (set_type)
|
|
return set_type;
|
|
|
|
type_allocator alloc (cu->per_objfile->objfile, cu->lang ());
|
|
set_type = create_set_type (alloc, domain_type);
|
|
|
|
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr != nullptr && attr->form_is_unsigned ())
|
|
set_type->set_length (attr->as_unsigned ());
|
|
|
|
maybe_set_alignment (cu, die, set_type);
|
|
|
|
return set_die_type (die, set_type, cu);
|
|
}
|
|
|
|
/* A helper for read_common_block that creates a locexpr baton.
|
|
SYM is the symbol which we are marking as computed.
|
|
COMMON_DIE is the DIE for the common block.
|
|
COMMON_LOC is the location expression attribute for the common
|
|
block itself.
|
|
MEMBER_LOC is the location expression attribute for the particular
|
|
member of the common block that we are processing.
|
|
CU is the CU from which the above come. */
|
|
|
|
static void
|
|
mark_common_block_symbol_computed (struct symbol *sym,
|
|
struct die_info *common_die,
|
|
struct attribute *common_loc,
|
|
struct attribute *member_loc,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct dwarf2_locexpr_baton *baton;
|
|
gdb_byte *ptr;
|
|
unsigned int cu_off;
|
|
enum bfd_endian byte_order = gdbarch_byte_order (objfile->arch ());
|
|
LONGEST offset = 0;
|
|
|
|
gdb_assert (common_loc && member_loc);
|
|
gdb_assert (common_loc->form_is_block ());
|
|
gdb_assert (member_loc->form_is_block ()
|
|
|| member_loc->form_is_constant ());
|
|
|
|
baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton);
|
|
baton->per_objfile = per_objfile;
|
|
baton->per_cu = cu->per_cu;
|
|
gdb_assert (baton->per_cu);
|
|
|
|
baton->size = 5 /* DW_OP_call4 */ + 1 /* DW_OP_plus */;
|
|
|
|
if (member_loc->form_is_constant ())
|
|
{
|
|
offset = member_loc->constant_value (0);
|
|
baton->size += 1 /* DW_OP_addr */ + cu->header.addr_size;
|
|
}
|
|
else
|
|
baton->size += member_loc->as_block ()->size;
|
|
|
|
ptr = (gdb_byte *) obstack_alloc (&objfile->objfile_obstack, baton->size);
|
|
baton->data = ptr;
|
|
|
|
*ptr++ = DW_OP_call4;
|
|
cu_off = common_die->sect_off - cu->per_cu->sect_off;
|
|
store_unsigned_integer (ptr, 4, byte_order, cu_off);
|
|
ptr += 4;
|
|
|
|
if (member_loc->form_is_constant ())
|
|
{
|
|
*ptr++ = DW_OP_addr;
|
|
store_unsigned_integer (ptr, cu->header.addr_size, byte_order, offset);
|
|
ptr += cu->header.addr_size;
|
|
}
|
|
else
|
|
{
|
|
/* We have to copy the data here, because DW_OP_call4 will only
|
|
use a DW_AT_location attribute. */
|
|
struct dwarf_block *block = member_loc->as_block ();
|
|
memcpy (ptr, block->data, block->size);
|
|
ptr += block->size;
|
|
}
|
|
|
|
*ptr++ = DW_OP_plus;
|
|
gdb_assert (ptr - baton->data == baton->size);
|
|
|
|
SYMBOL_LOCATION_BATON (sym) = baton;
|
|
sym->set_aclass_index (dwarf2_locexpr_index);
|
|
}
|
|
|
|
/* Create appropriate locally-scoped variables for all the
|
|
DW_TAG_common_block entries. Also create a struct common_block
|
|
listing all such variables for `info common'. COMMON_BLOCK_DOMAIN
|
|
is used to separate the common blocks name namespace from regular
|
|
variable names. */
|
|
|
|
static void
|
|
read_common_block (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_location, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
/* Support the .debug_loc offsets. */
|
|
if (attr->form_is_block ())
|
|
{
|
|
/* Ok. */
|
|
}
|
|
else if (attr->form_is_section_offset ())
|
|
{
|
|
dwarf2_complex_location_expr_complaint ();
|
|
attr = NULL;
|
|
}
|
|
else
|
|
{
|
|
dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
|
|
"common block member");
|
|
attr = NULL;
|
|
}
|
|
}
|
|
|
|
if (die->child != NULL)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct die_info *child_die;
|
|
size_t n_entries = 0, size;
|
|
struct common_block *common_block;
|
|
struct symbol *sym;
|
|
|
|
for (child_die = die->child;
|
|
child_die && child_die->tag;
|
|
child_die = child_die->sibling)
|
|
++n_entries;
|
|
|
|
size = (sizeof (struct common_block)
|
|
+ (n_entries - 1) * sizeof (struct symbol *));
|
|
common_block
|
|
= (struct common_block *) obstack_alloc (&objfile->objfile_obstack,
|
|
size);
|
|
memset (common_block->contents, 0, n_entries * sizeof (struct symbol *));
|
|
common_block->n_entries = 0;
|
|
|
|
for (child_die = die->child;
|
|
child_die && child_die->tag;
|
|
child_die = child_die->sibling)
|
|
{
|
|
/* Create the symbol in the DW_TAG_common_block block in the current
|
|
symbol scope. */
|
|
sym = new_symbol (child_die, NULL, cu);
|
|
if (sym != NULL)
|
|
{
|
|
struct attribute *member_loc;
|
|
|
|
common_block->contents[common_block->n_entries++] = sym;
|
|
|
|
member_loc = dwarf2_attr (child_die, DW_AT_data_member_location,
|
|
cu);
|
|
if (member_loc)
|
|
{
|
|
/* GDB has handled this for a long time, but it is
|
|
not specified by DWARF. It seems to have been
|
|
emitted by gfortran at least as recently as:
|
|
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23057. */
|
|
complaint (_("Variable in common block has "
|
|
"DW_AT_data_member_location "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (child_die->sect_off),
|
|
objfile_name (objfile));
|
|
|
|
if (member_loc->form_is_section_offset ())
|
|
dwarf2_complex_location_expr_complaint ();
|
|
else if (member_loc->form_is_constant ()
|
|
|| member_loc->form_is_block ())
|
|
{
|
|
if (attr != nullptr)
|
|
mark_common_block_symbol_computed (sym, die, attr,
|
|
member_loc, cu);
|
|
}
|
|
else
|
|
dwarf2_complex_location_expr_complaint ();
|
|
}
|
|
}
|
|
}
|
|
|
|
sym = new_symbol (die, builtin_type (objfile)->builtin_void, cu);
|
|
sym->set_value_common_block (common_block);
|
|
}
|
|
}
|
|
|
|
/* Create a type for a C++ namespace. */
|
|
|
|
static struct type *
|
|
read_namespace_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
const char *previous_prefix, *name;
|
|
int is_anonymous;
|
|
struct type *type;
|
|
|
|
/* For extensions, reuse the type of the original namespace. */
|
|
if (dwarf2_attr (die, DW_AT_extension, cu) != NULL)
|
|
{
|
|
struct die_info *ext_die;
|
|
struct dwarf2_cu *ext_cu = cu;
|
|
|
|
ext_die = dwarf2_extension (die, &ext_cu);
|
|
type = read_type_die (ext_die, ext_cu);
|
|
|
|
/* EXT_CU may not be the same as CU.
|
|
Ensure TYPE is recorded with CU in die_type_hash. */
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
name = namespace_name (die, &is_anonymous, cu);
|
|
|
|
/* Now build the name of the current namespace. */
|
|
|
|
previous_prefix = determine_prefix (die, cu);
|
|
gdb::unique_xmalloc_ptr<char> name_storage;
|
|
if (previous_prefix[0] != '\0')
|
|
{
|
|
name_storage = typename_concat (previous_prefix, name, 0, cu);
|
|
name = name_storage.get ();
|
|
}
|
|
|
|
/* Create the type. */
|
|
type = type_allocator (objfile, cu->lang ()).new_type (TYPE_CODE_NAMESPACE,
|
|
0, name);
|
|
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
/* Read a namespace scope. */
|
|
|
|
static void
|
|
read_namespace (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
int is_anonymous;
|
|
|
|
/* Add a symbol associated to this if we haven't seen the namespace
|
|
before. Also, add a using directive if it's an anonymous
|
|
namespace. */
|
|
|
|
if (dwarf2_attr (die, DW_AT_extension, cu) == NULL)
|
|
{
|
|
struct type *type;
|
|
|
|
type = read_type_die (die, cu);
|
|
new_symbol (die, type, cu);
|
|
|
|
namespace_name (die, &is_anonymous, cu);
|
|
if (is_anonymous)
|
|
{
|
|
const char *previous_prefix = determine_prefix (die, cu);
|
|
|
|
std::vector<const char *> excludes;
|
|
add_using_directive (using_directives (cu),
|
|
previous_prefix, type->name (), NULL,
|
|
NULL, excludes,
|
|
read_decl_line (die, cu),
|
|
&objfile->objfile_obstack);
|
|
}
|
|
}
|
|
|
|
if (die->child != NULL)
|
|
{
|
|
struct die_info *child_die = die->child;
|
|
|
|
while (child_die && child_die->tag)
|
|
{
|
|
process_die (child_die, cu);
|
|
child_die = child_die->sibling;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Read a Fortran module as type. This DIE can be only a declaration used for
|
|
imported module. Still we need that type as local Fortran "use ... only"
|
|
declaration imports depend on the created type in determine_prefix. */
|
|
|
|
static struct type *
|
|
read_module_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
const char *module_name;
|
|
struct type *type;
|
|
|
|
module_name = dwarf2_name (die, cu);
|
|
type = type_allocator (objfile, cu->lang ()).new_type (TYPE_CODE_MODULE,
|
|
0, module_name);
|
|
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
/* Read a Fortran module. */
|
|
|
|
static void
|
|
read_module (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct die_info *child_die = die->child;
|
|
struct type *type;
|
|
|
|
type = read_type_die (die, cu);
|
|
new_symbol (die, type, cu);
|
|
|
|
while (child_die && child_die->tag)
|
|
{
|
|
process_die (child_die, cu);
|
|
child_die = child_die->sibling;
|
|
}
|
|
}
|
|
|
|
/* Return the name of the namespace represented by DIE. Set
|
|
*IS_ANONYMOUS to tell whether or not the namespace is an anonymous
|
|
namespace. */
|
|
|
|
static const char *
|
|
namespace_name (struct die_info *die, int *is_anonymous, struct dwarf2_cu *cu)
|
|
{
|
|
struct die_info *current_die;
|
|
const char *name = NULL;
|
|
|
|
/* Loop through the extensions until we find a name. */
|
|
|
|
for (current_die = die;
|
|
current_die != NULL;
|
|
current_die = dwarf2_extension (die, &cu))
|
|
{
|
|
/* We don't use dwarf2_name here so that we can detect the absence
|
|
of a name -> anonymous namespace. */
|
|
name = dwarf2_string_attr (die, DW_AT_name, cu);
|
|
|
|
if (name != NULL)
|
|
break;
|
|
}
|
|
|
|
/* Is it an anonymous namespace? */
|
|
|
|
*is_anonymous = (name == NULL);
|
|
if (*is_anonymous)
|
|
name = CP_ANONYMOUS_NAMESPACE_STR;
|
|
|
|
return name;
|
|
}
|
|
|
|
/* Extract all information from a DW_TAG_pointer_type DIE and add to
|
|
the user defined type vector. */
|
|
|
|
static struct type *
|
|
read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct gdbarch *gdbarch = cu->per_objfile->objfile->arch ();
|
|
struct comp_unit_head *cu_header = &cu->header;
|
|
struct type *type;
|
|
struct attribute *attr_byte_size;
|
|
struct attribute *attr_address_class;
|
|
int byte_size, addr_class;
|
|
struct type *target_type;
|
|
|
|
target_type = die_type (die, cu);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
type = get_die_type (die, cu);
|
|
if (type)
|
|
return type;
|
|
|
|
type = lookup_pointer_type (target_type);
|
|
|
|
attr_byte_size = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr_byte_size)
|
|
byte_size = attr_byte_size->constant_value (cu_header->addr_size);
|
|
else
|
|
byte_size = cu_header->addr_size;
|
|
|
|
attr_address_class = dwarf2_attr (die, DW_AT_address_class, cu);
|
|
if (attr_address_class)
|
|
addr_class = attr_address_class->constant_value (DW_ADDR_none);
|
|
else
|
|
addr_class = DW_ADDR_none;
|
|
|
|
ULONGEST alignment = get_alignment (cu, die);
|
|
|
|
/* If the pointer size, alignment, or address class is different
|
|
than the default, create a type variant marked as such and set
|
|
the length accordingly. */
|
|
if (type->length () != byte_size
|
|
|| (alignment != 0 && TYPE_RAW_ALIGN (type) != 0
|
|
&& alignment != TYPE_RAW_ALIGN (type))
|
|
|| addr_class != DW_ADDR_none)
|
|
{
|
|
if (gdbarch_address_class_type_flags_p (gdbarch))
|
|
{
|
|
type_instance_flags type_flags
|
|
= gdbarch_address_class_type_flags (gdbarch, byte_size,
|
|
addr_class);
|
|
gdb_assert ((type_flags & ~TYPE_INSTANCE_FLAG_ADDRESS_CLASS_ALL)
|
|
== 0);
|
|
type = make_type_with_address_space (type, type_flags);
|
|
}
|
|
else if (type->length () != byte_size)
|
|
{
|
|
complaint (_("invalid pointer size %d"), byte_size);
|
|
}
|
|
else if (TYPE_RAW_ALIGN (type) != alignment)
|
|
{
|
|
complaint (_("Invalid DW_AT_alignment"
|
|
" - DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
}
|
|
else
|
|
{
|
|
/* Should we also complain about unhandled address classes? */
|
|
}
|
|
}
|
|
|
|
type->set_length (byte_size);
|
|
set_type_align (type, alignment);
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
/* Extract all information from a DW_TAG_ptr_to_member_type DIE and add to
|
|
the user defined type vector. */
|
|
|
|
static struct type *
|
|
read_tag_ptr_to_member_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *type;
|
|
struct type *to_type;
|
|
struct type *domain;
|
|
|
|
to_type = die_type (die, cu);
|
|
domain = die_containing_type (die, cu);
|
|
|
|
/* The calls above may have already set the type for this DIE. */
|
|
type = get_die_type (die, cu);
|
|
if (type)
|
|
return type;
|
|
|
|
if (check_typedef (to_type)->code () == TYPE_CODE_METHOD)
|
|
type = lookup_methodptr_type (to_type);
|
|
else if (check_typedef (to_type)->code () == TYPE_CODE_FUNC)
|
|
{
|
|
struct type *new_type
|
|
= type_allocator (cu->per_objfile->objfile, cu->lang ()).new_type ();
|
|
|
|
smash_to_method_type (new_type, domain, to_type->target_type (),
|
|
to_type->fields (), to_type->num_fields (),
|
|
to_type->has_varargs ());
|
|
type = lookup_methodptr_type (new_type);
|
|
}
|
|
else
|
|
type = lookup_memberptr_type (to_type, domain);
|
|
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
/* Extract all information from a DW_TAG_{rvalue_,}reference_type DIE and add to
|
|
the user defined type vector. */
|
|
|
|
static struct type *
|
|
read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu,
|
|
enum type_code refcode)
|
|
{
|
|
struct comp_unit_head *cu_header = &cu->header;
|
|
struct type *type, *target_type;
|
|
struct attribute *attr;
|
|
|
|
gdb_assert (refcode == TYPE_CODE_REF || refcode == TYPE_CODE_RVALUE_REF);
|
|
|
|
target_type = die_type (die, cu);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
type = get_die_type (die, cu);
|
|
if (type)
|
|
return type;
|
|
|
|
type = lookup_reference_type (target_type, refcode);
|
|
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr != nullptr)
|
|
type->set_length (attr->constant_value (cu_header->addr_size));
|
|
else
|
|
type->set_length (cu_header->addr_size);
|
|
|
|
maybe_set_alignment (cu, die, type);
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
/* Add the given cv-qualifiers to the element type of the array. GCC
|
|
outputs DWARF type qualifiers that apply to an array, not the
|
|
element type. But GDB relies on the array element type to carry
|
|
the cv-qualifiers. This mimics section 6.7.3 of the C99
|
|
specification. */
|
|
|
|
static struct type *
|
|
add_array_cv_type (struct die_info *die, struct dwarf2_cu *cu,
|
|
struct type *base_type, int cnst, int voltl)
|
|
{
|
|
struct type *el_type, *inner_array;
|
|
|
|
base_type = copy_type (base_type);
|
|
inner_array = base_type;
|
|
|
|
while (inner_array->target_type ()->code () == TYPE_CODE_ARRAY)
|
|
{
|
|
inner_array->set_target_type (copy_type (inner_array->target_type ()));
|
|
inner_array = inner_array->target_type ();
|
|
}
|
|
|
|
el_type = inner_array->target_type ();
|
|
cnst |= TYPE_CONST (el_type);
|
|
voltl |= TYPE_VOLATILE (el_type);
|
|
inner_array->set_target_type (make_cv_type (cnst, voltl, el_type, NULL));
|
|
|
|
return set_die_type (die, base_type, cu);
|
|
}
|
|
|
|
static struct type *
|
|
read_tag_const_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *base_type, *cv_type;
|
|
|
|
base_type = die_type (die, cu);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
cv_type = get_die_type (die, cu);
|
|
if (cv_type)
|
|
return cv_type;
|
|
|
|
/* In case the const qualifier is applied to an array type, the element type
|
|
is so qualified, not the array type (section 6.7.3 of C99). */
|
|
if (base_type->code () == TYPE_CODE_ARRAY)
|
|
return add_array_cv_type (die, cu, base_type, 1, 0);
|
|
|
|
cv_type = make_cv_type (1, TYPE_VOLATILE (base_type), base_type, 0);
|
|
return set_die_type (die, cv_type, cu);
|
|
}
|
|
|
|
static struct type *
|
|
read_tag_volatile_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *base_type, *cv_type;
|
|
|
|
base_type = die_type (die, cu);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
cv_type = get_die_type (die, cu);
|
|
if (cv_type)
|
|
return cv_type;
|
|
|
|
/* In case the volatile qualifier is applied to an array type, the
|
|
element type is so qualified, not the array type (section 6.7.3
|
|
of C99). */
|
|
if (base_type->code () == TYPE_CODE_ARRAY)
|
|
return add_array_cv_type (die, cu, base_type, 0, 1);
|
|
|
|
cv_type = make_cv_type (TYPE_CONST (base_type), 1, base_type, 0);
|
|
return set_die_type (die, cv_type, cu);
|
|
}
|
|
|
|
/* Handle DW_TAG_restrict_type. */
|
|
|
|
static struct type *
|
|
read_tag_restrict_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *base_type, *cv_type;
|
|
|
|
base_type = die_type (die, cu);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
cv_type = get_die_type (die, cu);
|
|
if (cv_type)
|
|
return cv_type;
|
|
|
|
cv_type = make_restrict_type (base_type);
|
|
return set_die_type (die, cv_type, cu);
|
|
}
|
|
|
|
/* Handle DW_TAG_atomic_type. */
|
|
|
|
static struct type *
|
|
read_tag_atomic_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *base_type, *cv_type;
|
|
|
|
base_type = die_type (die, cu);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
cv_type = get_die_type (die, cu);
|
|
if (cv_type)
|
|
return cv_type;
|
|
|
|
cv_type = make_atomic_type (base_type);
|
|
return set_die_type (die, cv_type, cu);
|
|
}
|
|
|
|
/* Extract all information from a DW_TAG_string_type DIE and add to
|
|
the user defined type vector. It isn't really a user defined type,
|
|
but it behaves like one, with other DIE's using an AT_user_def_type
|
|
attribute to reference it. */
|
|
|
|
static struct type *
|
|
read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
struct type *type, *range_type, *index_type, *char_type;
|
|
struct attribute *attr;
|
|
struct dynamic_prop prop;
|
|
bool length_is_constant = true;
|
|
LONGEST length;
|
|
|
|
/* There are a couple of places where bit sizes might be made use of
|
|
when parsing a DW_TAG_string_type, however, no producer that we know
|
|
of make use of these. Handling bit sizes that are a multiple of the
|
|
byte size is easy enough, but what about other bit sizes? Lets deal
|
|
with that problem when we have to. Warn about these attributes being
|
|
unsupported, then parse the type and ignore them like we always
|
|
have. */
|
|
if (dwarf2_attr (die, DW_AT_bit_size, cu) != nullptr
|
|
|| dwarf2_attr (die, DW_AT_string_length_bit_size, cu) != nullptr)
|
|
{
|
|
static bool warning_printed = false;
|
|
if (!warning_printed)
|
|
{
|
|
warning (_("DW_AT_bit_size and DW_AT_string_length_bit_size not "
|
|
"currently supported on DW_TAG_string_type."));
|
|
warning_printed = true;
|
|
}
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_string_length, cu);
|
|
if (attr != nullptr && !attr->form_is_constant ())
|
|
{
|
|
/* The string length describes the location at which the length of
|
|
the string can be found. The size of the length field can be
|
|
specified with one of the attributes below. */
|
|
struct type *prop_type;
|
|
struct attribute *len
|
|
= dwarf2_attr (die, DW_AT_string_length_byte_size, cu);
|
|
if (len == nullptr)
|
|
len = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (len != nullptr && len->form_is_constant ())
|
|
{
|
|
/* Pass 0 as the default as we know this attribute is constant
|
|
and the default value will not be returned. */
|
|
LONGEST sz = len->constant_value (0);
|
|
prop_type = objfile_int_type (objfile, sz, true);
|
|
}
|
|
else
|
|
{
|
|
/* If the size is not specified then we assume it is the size of
|
|
an address on this target. */
|
|
prop_type = cu->addr_sized_int_type (true);
|
|
}
|
|
|
|
/* Convert the attribute into a dynamic property. */
|
|
if (!attr_to_dynamic_prop (attr, die, cu, &prop, prop_type))
|
|
length = 1;
|
|
else
|
|
length_is_constant = false;
|
|
}
|
|
else if (attr != nullptr)
|
|
{
|
|
/* This DW_AT_string_length just contains the length with no
|
|
indirection. There's no need to create a dynamic property in this
|
|
case. Pass 0 for the default value as we know it will not be
|
|
returned in this case. */
|
|
length = attr->constant_value (0);
|
|
}
|
|
else if ((attr = dwarf2_attr (die, DW_AT_byte_size, cu)) != nullptr)
|
|
{
|
|
/* We don't currently support non-constant byte sizes for strings. */
|
|
length = attr->constant_value (1);
|
|
}
|
|
else
|
|
{
|
|
/* Use 1 as a fallback length if we have nothing else. */
|
|
length = 1;
|
|
}
|
|
|
|
index_type = builtin_type (objfile)->builtin_int;
|
|
type_allocator alloc (objfile, cu->lang ());
|
|
if (length_is_constant)
|
|
range_type = create_static_range_type (alloc, index_type, 1, length);
|
|
else
|
|
{
|
|
struct dynamic_prop low_bound;
|
|
|
|
low_bound.set_const_val (1);
|
|
range_type = create_range_type (alloc, index_type, &low_bound, &prop, 0);
|
|
}
|
|
char_type = language_string_char_type (cu->language_defn, gdbarch);
|
|
type = create_string_type (alloc, char_type, range_type);
|
|
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
/* Assuming that DIE corresponds to a function, returns nonzero
|
|
if the function is prototyped. */
|
|
|
|
static int
|
|
prototyped_function_p (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_prototyped, cu);
|
|
if (attr && attr->as_boolean ())
|
|
return 1;
|
|
|
|
/* The DWARF standard implies that the DW_AT_prototyped attribute
|
|
is only meaningful for C, but the concept also extends to other
|
|
languages that allow unprototyped functions (Eg: Objective C).
|
|
For all other languages, assume that functions are always
|
|
prototyped. */
|
|
if (cu->lang () != language_c
|
|
&& cu->lang () != language_objc
|
|
&& cu->lang () != language_opencl)
|
|
return 1;
|
|
|
|
/* RealView does not emit DW_AT_prototyped. We can not distinguish
|
|
prototyped and unprototyped functions; default to prototyped,
|
|
since that is more common in modern code (and RealView warns
|
|
about unprototyped functions). */
|
|
if (producer_is_realview (cu->producer))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Handle DIES due to C code like:
|
|
|
|
struct foo
|
|
{
|
|
int (*funcp)(int a, long l);
|
|
int b;
|
|
};
|
|
|
|
('funcp' generates a DW_TAG_subroutine_type DIE). */
|
|
|
|
static struct type *
|
|
read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct type *type; /* Type that this function returns. */
|
|
struct type *ftype; /* Function that returns above type. */
|
|
struct attribute *attr;
|
|
|
|
type = die_type (die, cu);
|
|
|
|
/* PR gas/29517 occurs in 2.39, and is fixed in 2.40, but it's only fixed
|
|
for dwarf version >= 3 which supports DW_TAG_unspecified_type. */
|
|
if (type->code () == TYPE_CODE_VOID
|
|
&& !type->is_stub ()
|
|
&& die->child == nullptr
|
|
&& (cu->header.version == 2 || producer_is_gas_2_39 (cu)))
|
|
{
|
|
/* Work around PR gas/29517, pretend we have an DW_TAG_unspecified_type
|
|
return type. */
|
|
type = (type_allocator (cu->per_objfile->objfile, cu->lang ())
|
|
.new_type (TYPE_CODE_VOID, 0, nullptr));
|
|
type->set_is_stub (true);
|
|
}
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
ftype = get_die_type (die, cu);
|
|
if (ftype)
|
|
return ftype;
|
|
|
|
ftype = lookup_function_type (type);
|
|
|
|
if (prototyped_function_p (die, cu))
|
|
ftype->set_is_prototyped (true);
|
|
|
|
/* Store the calling convention in the type if it's available in
|
|
the subroutine die. Otherwise set the calling convention to
|
|
the default value DW_CC_normal. */
|
|
attr = dwarf2_attr (die, DW_AT_calling_convention, cu);
|
|
if (attr != nullptr
|
|
&& is_valid_DW_AT_calling_convention_for_subroutine (attr->constant_value (0)))
|
|
TYPE_CALLING_CONVENTION (ftype)
|
|
= (enum dwarf_calling_convention) attr->constant_value (0);
|
|
else if (cu->producer && strstr (cu->producer, "IBM XL C for OpenCL"))
|
|
TYPE_CALLING_CONVENTION (ftype) = DW_CC_GDB_IBM_OpenCL;
|
|
else
|
|
TYPE_CALLING_CONVENTION (ftype) = DW_CC_normal;
|
|
|
|
/* Record whether the function returns normally to its caller or not
|
|
if the DWARF producer set that information. */
|
|
attr = dwarf2_attr (die, DW_AT_noreturn, cu);
|
|
if (attr && attr->as_boolean ())
|
|
TYPE_NO_RETURN (ftype) = 1;
|
|
|
|
/* We need to add the subroutine type to the die immediately so
|
|
we don't infinitely recurse when dealing with parameters
|
|
declared as the same subroutine type. */
|
|
set_die_type (die, ftype, cu);
|
|
|
|
if (die->child != NULL)
|
|
{
|
|
struct type *void_type = builtin_type (objfile)->builtin_void;
|
|
struct die_info *child_die;
|
|
int nparams, iparams;
|
|
|
|
/* Count the number of parameters.
|
|
FIXME: GDB currently ignores vararg functions, but knows about
|
|
vararg member functions. */
|
|
nparams = 0;
|
|
child_die = die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
if (child_die->tag == DW_TAG_formal_parameter)
|
|
nparams++;
|
|
else if (child_die->tag == DW_TAG_unspecified_parameters)
|
|
ftype->set_has_varargs (true);
|
|
|
|
child_die = child_die->sibling;
|
|
}
|
|
|
|
/* Allocate storage for parameters and fill them in. */
|
|
ftype->alloc_fields (nparams);
|
|
|
|
/* TYPE_FIELD_TYPE must never be NULL. Pre-fill the array to ensure it
|
|
even if we error out during the parameters reading below. */
|
|
for (iparams = 0; iparams < nparams; iparams++)
|
|
ftype->field (iparams).set_type (void_type);
|
|
|
|
iparams = 0;
|
|
child_die = die->child;
|
|
while (child_die && child_die->tag)
|
|
{
|
|
if (child_die->tag == DW_TAG_formal_parameter)
|
|
{
|
|
struct type *arg_type;
|
|
|
|
/* DWARF version 2 has no clean way to discern C++
|
|
static and non-static member functions. G++ helps
|
|
GDB by marking the first parameter for non-static
|
|
member functions (which is the this pointer) as
|
|
artificial. We pass this information to
|
|
dwarf2_add_member_fn via TYPE_FIELD_ARTIFICIAL.
|
|
|
|
DWARF version 3 added DW_AT_object_pointer, which GCC
|
|
4.5 does not yet generate. */
|
|
attr = dwarf2_attr (child_die, DW_AT_artificial, cu);
|
|
if (attr != nullptr)
|
|
ftype->field (iparams).set_is_artificial (attr->as_boolean ());
|
|
else
|
|
ftype->field (iparams).set_is_artificial (false);
|
|
arg_type = die_type (child_die, cu);
|
|
|
|
/* RealView does not mark THIS as const, which the testsuite
|
|
expects. GCC marks THIS as const in method definitions,
|
|
but not in the class specifications (GCC PR 43053). */
|
|
if (is_cplus_dialect (cu->lang ())
|
|
&& !TYPE_CONST (arg_type)
|
|
&& ftype->field (iparams).is_artificial ())
|
|
{
|
|
int is_this = 0;
|
|
struct dwarf2_cu *arg_cu = cu;
|
|
const char *name = dwarf2_name (child_die, cu);
|
|
|
|
attr = dwarf2_attr (die, DW_AT_object_pointer, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
/* If the compiler emits this, use it. */
|
|
if (follow_die_ref (die, attr, &arg_cu) == child_die)
|
|
is_this = 1;
|
|
}
|
|
else if (name && strcmp (name, "this") == 0)
|
|
/* Function definitions will have the argument names. */
|
|
is_this = 1;
|
|
else if (name == NULL && iparams == 0)
|
|
/* Declarations may not have the names, so like
|
|
elsewhere in GDB, assume an artificial first
|
|
argument is "this". */
|
|
is_this = 1;
|
|
|
|
if (is_this)
|
|
arg_type = make_cv_type (1, TYPE_VOLATILE (arg_type),
|
|
arg_type, 0);
|
|
}
|
|
|
|
ftype->field (iparams).set_type (arg_type);
|
|
iparams++;
|
|
}
|
|
child_die = child_die->sibling;
|
|
}
|
|
}
|
|
|
|
return ftype;
|
|
}
|
|
|
|
static struct type *
|
|
read_typedef (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
const char *name = dwarf2_full_name (NULL, die, cu);
|
|
struct type *this_type;
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
struct type *target_type = die_type (die, cu);
|
|
|
|
if (gdbarch_dwarf2_omit_typedef_p (gdbarch, target_type, cu->producer, name))
|
|
{
|
|
/* The long double is defined as a base type in C. GCC creates a long
|
|
double typedef with target-type _Float128 for the long double to
|
|
identify it as the IEEE Float128 value. This is a GCC hack since the
|
|
DWARF doesn't distinguish between the IBM long double and IEEE
|
|
128-bit float. Replace the GCC workaround for the long double
|
|
typedef with the actual type information copied from the target-type
|
|
with the correct long double base type name. */
|
|
this_type = copy_type (target_type);
|
|
this_type->set_name (name);
|
|
set_die_type (die, this_type, cu);
|
|
return this_type;
|
|
}
|
|
|
|
type_allocator alloc (objfile, cu->lang ());
|
|
this_type = alloc.new_type (TYPE_CODE_TYPEDEF, 0, name);
|
|
this_type->set_target_is_stub (true);
|
|
set_die_type (die, this_type, cu);
|
|
if (target_type != this_type)
|
|
this_type->set_target_type (target_type);
|
|
else
|
|
{
|
|
/* Self-referential typedefs are, it seems, not allowed by the DWARF
|
|
spec and cause infinite loops in GDB. */
|
|
complaint (_("Self-referential DW_TAG_typedef "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off), objfile_name (objfile));
|
|
this_type->set_target_type (nullptr);
|
|
}
|
|
if (name == NULL)
|
|
{
|
|
/* Gcc-7 and before supports -feliminate-dwarf2-dups, which generates
|
|
anonymous typedefs, which is, strictly speaking, invalid DWARF.
|
|
Handle these by just returning the target type, rather than
|
|
constructing an anonymous typedef type and trying to handle this
|
|
elsewhere. */
|
|
set_die_type (die, target_type, cu);
|
|
return target_type;
|
|
}
|
|
return this_type;
|
|
}
|
|
|
|
/* Helper for get_dwarf2_rational_constant that computes the value of
|
|
a given gmp_mpz given an attribute. */
|
|
|
|
static void
|
|
get_mpz (struct dwarf2_cu *cu, gdb_mpz *value, struct attribute *attr)
|
|
{
|
|
/* GCC will sometimes emit a 16-byte constant value as a DWARF
|
|
location expression that pushes an implicit value. */
|
|
if (attr->form == DW_FORM_exprloc)
|
|
{
|
|
dwarf_block *blk = attr->as_block ();
|
|
if (blk->size > 0 && blk->data[0] == DW_OP_implicit_value)
|
|
{
|
|
uint64_t len;
|
|
const gdb_byte *ptr = safe_read_uleb128 (blk->data + 1,
|
|
blk->data + blk->size,
|
|
&len);
|
|
if (ptr - blk->data + len <= blk->size)
|
|
{
|
|
value->read (gdb::make_array_view (ptr, len),
|
|
bfd_big_endian (cu->per_objfile->objfile->obfd.get ())
|
|
? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE,
|
|
true);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* On failure set it to 1. */
|
|
*value = gdb_mpz (1);
|
|
}
|
|
else if (attr->form_is_block ())
|
|
{
|
|
dwarf_block *blk = attr->as_block ();
|
|
value->read (gdb::make_array_view (blk->data, blk->size),
|
|
bfd_big_endian (cu->per_objfile->objfile->obfd.get ())
|
|
? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE,
|
|
true);
|
|
}
|
|
else if (attr->form_is_unsigned ())
|
|
*value = gdb_mpz (attr->as_unsigned ());
|
|
else
|
|
*value = gdb_mpz (attr->constant_value (1));
|
|
}
|
|
|
|
/* Assuming DIE is a rational DW_TAG_constant, read the DIE's
|
|
numerator and denominator into NUMERATOR and DENOMINATOR (resp).
|
|
|
|
If the numerator and/or numerator attribute is missing,
|
|
a complaint is filed, and NUMERATOR and DENOMINATOR are left
|
|
untouched. */
|
|
|
|
static void
|
|
get_dwarf2_rational_constant (struct die_info *die, struct dwarf2_cu *cu,
|
|
gdb_mpz *numerator, gdb_mpz *denominator)
|
|
{
|
|
struct attribute *num_attr, *denom_attr;
|
|
|
|
num_attr = dwarf2_attr (die, DW_AT_GNU_numerator, cu);
|
|
if (num_attr == nullptr)
|
|
complaint (_("DW_AT_GNU_numerator missing in %s DIE at %s"),
|
|
dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
|
|
|
|
denom_attr = dwarf2_attr (die, DW_AT_GNU_denominator, cu);
|
|
if (denom_attr == nullptr)
|
|
complaint (_("DW_AT_GNU_denominator missing in %s DIE at %s"),
|
|
dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
|
|
|
|
if (num_attr == nullptr || denom_attr == nullptr)
|
|
return;
|
|
|
|
get_mpz (cu, numerator, num_attr);
|
|
get_mpz (cu, denominator, denom_attr);
|
|
}
|
|
|
|
/* Same as get_dwarf2_rational_constant, but extracting an unsigned
|
|
rational constant, rather than a signed one.
|
|
|
|
If the rational constant has a negative value, a complaint
|
|
is filed, and NUMERATOR and DENOMINATOR are left untouched. */
|
|
|
|
static void
|
|
get_dwarf2_unsigned_rational_constant (struct die_info *die,
|
|
struct dwarf2_cu *cu,
|
|
gdb_mpz *numerator,
|
|
gdb_mpz *denominator)
|
|
{
|
|
gdb_mpz num (1);
|
|
gdb_mpz denom (1);
|
|
|
|
get_dwarf2_rational_constant (die, cu, &num, &denom);
|
|
if (num < 0 && denom < 0)
|
|
{
|
|
num.negate ();
|
|
denom.negate ();
|
|
}
|
|
else if (num < 0)
|
|
{
|
|
complaint (_("unexpected negative value for DW_AT_GNU_numerator"
|
|
" in DIE at %s"),
|
|
sect_offset_str (die->sect_off));
|
|
return;
|
|
}
|
|
else if (denom < 0)
|
|
{
|
|
complaint (_("unexpected negative value for DW_AT_GNU_denominator"
|
|
" in DIE at %s"),
|
|
sect_offset_str (die->sect_off));
|
|
return;
|
|
}
|
|
|
|
*numerator = std::move (num);
|
|
*denominator = std::move (denom);
|
|
}
|
|
|
|
/* Assuming that ENCODING is a string whose contents starting at the
|
|
K'th character is "_nn" where "nn" is a decimal number, scan that
|
|
number and set RESULT to the value. K is updated to point to the
|
|
character immediately following the number.
|
|
|
|
If the string does not conform to the format described above, false
|
|
is returned, and K may or may not be changed. */
|
|
|
|
static bool
|
|
ada_get_gnat_encoded_number (const char *encoding, int &k, gdb_mpz *result)
|
|
{
|
|
/* The next character should be an underscore ('_') followed
|
|
by a digit. */
|
|
if (encoding[k] != '_' || !isdigit (encoding[k + 1]))
|
|
return false;
|
|
|
|
/* Skip the underscore. */
|
|
k++;
|
|
int start = k;
|
|
|
|
/* Determine the number of digits for our number. */
|
|
while (isdigit (encoding[k]))
|
|
k++;
|
|
if (k == start)
|
|
return false;
|
|
|
|
std::string copy (&encoding[start], k - start);
|
|
return result->set (copy.c_str (), 10);
|
|
}
|
|
|
|
/* Scan two numbers from ENCODING at OFFSET, assuming the string is of
|
|
the form _NN_DD, where NN and DD are decimal numbers. Set NUM and
|
|
DENOM, update OFFSET, and return true on success. Return false on
|
|
failure. */
|
|
|
|
static bool
|
|
ada_get_gnat_encoded_ratio (const char *encoding, int &offset,
|
|
gdb_mpz *num, gdb_mpz *denom)
|
|
{
|
|
if (!ada_get_gnat_encoded_number (encoding, offset, num))
|
|
return false;
|
|
return ada_get_gnat_encoded_number (encoding, offset, denom);
|
|
}
|
|
|
|
/* Assuming DIE corresponds to a fixed point type, finish the creation
|
|
of the corresponding TYPE by setting its type-specific data. CU is
|
|
the DIE's CU. SUFFIX is the "XF" type name suffix coming from GNAT
|
|
encodings. It is nullptr if the GNAT encoding should be
|
|
ignored. */
|
|
|
|
static void
|
|
finish_fixed_point_type (struct type *type, const char *suffix,
|
|
struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
gdb_assert (type->code () == TYPE_CODE_FIXED_POINT
|
|
&& TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_FIXED_POINT);
|
|
|
|
/* If GNAT encodings are preferred, don't examine the
|
|
attributes. */
|
|
struct attribute *attr = nullptr;
|
|
if (suffix == nullptr)
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_binary_scale, cu);
|
|
if (attr == nullptr)
|
|
attr = dwarf2_attr (die, DW_AT_decimal_scale, cu);
|
|
if (attr == nullptr)
|
|
attr = dwarf2_attr (die, DW_AT_small, cu);
|
|
}
|
|
|
|
/* Numerator and denominator of our fixed-point type's scaling factor.
|
|
The default is a scaling factor of 1, which we use as a fallback
|
|
when we are not able to decode it (problem with the debugging info,
|
|
unsupported forms, bug in GDB, etc...). Using that as the default
|
|
allows us to at least print the unscaled value, which might still
|
|
be useful to a user. */
|
|
gdb_mpz scale_num (1);
|
|
gdb_mpz scale_denom (1);
|
|
|
|
if (attr == nullptr)
|
|
{
|
|
int offset = 0;
|
|
if (suffix != nullptr
|
|
&& ada_get_gnat_encoded_ratio (suffix, offset, &scale_num,
|
|
&scale_denom)
|
|
/* The number might be encoded as _nn_dd_nn_dd, where the
|
|
second ratio is the 'small value. In this situation, we
|
|
want the second value. */
|
|
&& (suffix[offset] != '_'
|
|
|| ada_get_gnat_encoded_ratio (suffix, offset, &scale_num,
|
|
&scale_denom)))
|
|
{
|
|
/* Found it. */
|
|
}
|
|
else
|
|
{
|
|
/* Scaling factor not found. Assume a scaling factor of 1,
|
|
and hope for the best. At least the user will be able to
|
|
see the encoded value. */
|
|
scale_num = 1;
|
|
scale_denom = 1;
|
|
complaint (_("no scale found for fixed-point type (DIE at %s)"),
|
|
sect_offset_str (die->sect_off));
|
|
}
|
|
}
|
|
else if (attr->name == DW_AT_binary_scale)
|
|
{
|
|
LONGEST scale_exp = attr->constant_value (0);
|
|
gdb_mpz &num_or_denom = scale_exp > 0 ? scale_num : scale_denom;
|
|
|
|
num_or_denom <<= std::abs (scale_exp);
|
|
}
|
|
else if (attr->name == DW_AT_decimal_scale)
|
|
{
|
|
LONGEST scale_exp = attr->constant_value (0);
|
|
gdb_mpz &num_or_denom = scale_exp > 0 ? scale_num : scale_denom;
|
|
|
|
num_or_denom = gdb_mpz::pow (10, std::abs (scale_exp));
|
|
}
|
|
else if (attr->name == DW_AT_small)
|
|
{
|
|
struct die_info *scale_die;
|
|
struct dwarf2_cu *scale_cu = cu;
|
|
|
|
scale_die = follow_die_ref (die, attr, &scale_cu);
|
|
if (scale_die->tag == DW_TAG_constant)
|
|
get_dwarf2_unsigned_rational_constant (scale_die, scale_cu,
|
|
&scale_num, &scale_denom);
|
|
else
|
|
complaint (_("%s DIE not supported as target of DW_AT_small attribute"
|
|
" (DIE at %s)"),
|
|
dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
|
|
}
|
|
else
|
|
{
|
|
complaint (_("unsupported scale attribute %s for fixed-point type"
|
|
" (DIE at %s)"),
|
|
dwarf_attr_name (attr->name),
|
|
sect_offset_str (die->sect_off));
|
|
}
|
|
|
|
type->fixed_point_info ().scaling_factor = gdb_mpq (scale_num, scale_denom);
|
|
}
|
|
|
|
/* The gnat-encoding suffix for fixed point. */
|
|
|
|
#define GNAT_FIXED_POINT_SUFFIX "___XF_"
|
|
|
|
/* If NAME encodes an Ada fixed-point type, return a pointer to the
|
|
"XF" suffix of the name. The text after this is what encodes the
|
|
'small and 'delta information. Otherwise, return nullptr. */
|
|
|
|
static const char *
|
|
gnat_encoded_fixed_point_type_info (const char *name)
|
|
{
|
|
return strstr (name, GNAT_FIXED_POINT_SUFFIX);
|
|
}
|
|
|
|
/* Allocate a floating-point type of size BITS and name NAME. Pass NAME_HINT
|
|
(which may be different from NAME) to the architecture back-end to allow
|
|
it to guess the correct format if necessary. */
|
|
|
|
static struct type *
|
|
dwarf2_init_float_type (struct dwarf2_cu *cu, int bits, const char *name,
|
|
const char *name_hint, enum bfd_endian byte_order)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
const struct floatformat **format;
|
|
struct type *type;
|
|
|
|
type_allocator alloc (objfile, cu->lang ());
|
|
format = gdbarch_floatformat_for_type (gdbarch, name_hint, bits);
|
|
if (format)
|
|
type = init_float_type (alloc, bits, name, format, byte_order);
|
|
else
|
|
type = alloc.new_type (TYPE_CODE_ERROR, bits, name);
|
|
|
|
return type;
|
|
}
|
|
|
|
/* Allocate an integer type of size BITS and name NAME. */
|
|
|
|
static struct type *
|
|
dwarf2_init_integer_type (struct dwarf2_cu *cu, int bits, int unsigned_p,
|
|
const char *name)
|
|
{
|
|
struct type *type;
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
|
|
/* Versions of Intel's C Compiler generate an integer type called "void"
|
|
instead of using DW_TAG_unspecified_type. This has been seen on
|
|
at least versions 14, 17, and 18. */
|
|
if (bits == 0 && producer_is_icc (cu) && name != nullptr
|
|
&& strcmp (name, "void") == 0)
|
|
type = builtin_type (objfile)->builtin_void;
|
|
else
|
|
{
|
|
type_allocator alloc (objfile, cu->lang ());
|
|
type = init_integer_type (alloc, bits, unsigned_p, name);
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
/* Return true if DIE has a DW_AT_small attribute whose value is
|
|
a constant rational, where both the numerator and denominator
|
|
are equal to zero.
|
|
|
|
CU is the DIE's Compilation Unit. */
|
|
|
|
static bool
|
|
has_zero_over_zero_small_attribute (struct die_info *die,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr = dwarf2_attr (die, DW_AT_small, cu);
|
|
if (attr == nullptr)
|
|
return false;
|
|
|
|
struct dwarf2_cu *scale_cu = cu;
|
|
struct die_info *scale_die
|
|
= follow_die_ref (die, attr, &scale_cu);
|
|
|
|
if (scale_die->tag != DW_TAG_constant)
|
|
return false;
|
|
|
|
gdb_mpz num (1), denom (1);
|
|
get_dwarf2_rational_constant (scale_die, cu, &num, &denom);
|
|
return num == 0 && denom == 0;
|
|
}
|
|
|
|
/* Initialise and return a floating point type of size BITS suitable for
|
|
use as a component of a complex number. The NAME_HINT is passed through
|
|
when initialising the floating point type and is the name of the complex
|
|
type.
|
|
|
|
As DWARF doesn't currently provide an explicit name for the components
|
|
of a complex number, but it can be helpful to have these components
|
|
named, we try to select a suitable name based on the size of the
|
|
component. */
|
|
static struct type *
|
|
dwarf2_init_complex_target_type (struct dwarf2_cu *cu,
|
|
int bits, const char *name_hint,
|
|
enum bfd_endian byte_order)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
gdbarch *gdbarch = objfile->arch ();
|
|
struct type *tt = nullptr;
|
|
|
|
/* Try to find a suitable floating point builtin type of size BITS.
|
|
We're going to use the name of this type as the name for the complex
|
|
target type that we are about to create. */
|
|
switch (strip_cplus_dialect (cu->lang ()))
|
|
{
|
|
case language_fortran:
|
|
switch (bits)
|
|
{
|
|
case 32:
|
|
tt = builtin_f_type (gdbarch)->builtin_real;
|
|
break;
|
|
case 64:
|
|
tt = builtin_f_type (gdbarch)->builtin_real_s8;
|
|
break;
|
|
case 96: /* The x86-32 ABI specifies 96-bit long double. */
|
|
case 128:
|
|
tt = builtin_f_type (gdbarch)->builtin_real_s16;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch (bits)
|
|
{
|
|
case 32:
|
|
tt = builtin_type (gdbarch)->builtin_float;
|
|
break;
|
|
case 64:
|
|
if (builtin_type (gdbarch)->builtin_long_double->length () == 8
|
|
&& name_hint != nullptr
|
|
&& strstr (name_hint, "long") != nullptr)
|
|
{
|
|
/* Use "long double" for "complex long double". */
|
|
tt = builtin_type (gdbarch)->builtin_long_double;
|
|
}
|
|
else
|
|
tt = builtin_type (gdbarch)->builtin_double;
|
|
break;
|
|
case 96: /* The x86-32 ABI specifies 96-bit long double. */
|
|
case 128:
|
|
tt = builtin_type (gdbarch)->builtin_long_double;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* If the type we found doesn't match the size we were looking for, then
|
|
pretend we didn't find a type at all, the complex target type we
|
|
create will then be nameless. */
|
|
if (tt != nullptr && tt->length () * TARGET_CHAR_BIT != bits)
|
|
tt = nullptr;
|
|
|
|
const char *name = (tt == nullptr) ? nullptr : tt->name ();
|
|
return dwarf2_init_float_type (cu, bits, name, name_hint, byte_order);
|
|
}
|
|
|
|
/* Find a representation of a given base type and install
|
|
it in the TYPE field of the die. */
|
|
|
|
static struct type *
|
|
read_base_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct type *type;
|
|
struct attribute *attr;
|
|
int encoding = 0, bits = 0;
|
|
const char *name;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_encoding, cu);
|
|
if (attr != nullptr && attr->form_is_constant ())
|
|
encoding = attr->constant_value (0);
|
|
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr != nullptr)
|
|
bits = attr->constant_value (0) * TARGET_CHAR_BIT;
|
|
name = dwarf2_name (die, cu);
|
|
if (!name)
|
|
complaint (_("DW_AT_name missing from DW_TAG_base_type"));
|
|
|
|
enum bfd_endian byte_order;
|
|
bool not_default = die_byte_order (die, cu, &byte_order);
|
|
|
|
if ((encoding == DW_ATE_signed_fixed || encoding == DW_ATE_unsigned_fixed)
|
|
&& cu->lang () == language_ada
|
|
&& has_zero_over_zero_small_attribute (die, cu))
|
|
{
|
|
/* brobecker/2018-02-24: This is a fixed point type for which
|
|
the scaling factor is represented as fraction whose value
|
|
does not make sense (zero divided by zero), so we should
|
|
normally never see these. However, there is a small category
|
|
of fixed point types for which GNAT is unable to provide
|
|
the scaling factor via the standard DWARF mechanisms, and
|
|
for which the info is provided via the GNAT encodings instead.
|
|
This is likely what this DIE is about. */
|
|
encoding = (encoding == DW_ATE_signed_fixed
|
|
? DW_ATE_signed
|
|
: DW_ATE_unsigned);
|
|
}
|
|
|
|
/* With GNAT encodings, fixed-point information will be encoded in
|
|
the type name. Note that this can also occur with the above
|
|
zero-over-zero case, which is why this is a separate "if" rather
|
|
than an "else if". */
|
|
const char *gnat_encoding_suffix = nullptr;
|
|
if ((encoding == DW_ATE_signed || encoding == DW_ATE_unsigned)
|
|
&& cu->lang () == language_ada
|
|
&& name != nullptr)
|
|
{
|
|
gnat_encoding_suffix = gnat_encoded_fixed_point_type_info (name);
|
|
if (gnat_encoding_suffix != nullptr)
|
|
{
|
|
gdb_assert (startswith (gnat_encoding_suffix,
|
|
GNAT_FIXED_POINT_SUFFIX));
|
|
name = obstack_strndup (&cu->per_objfile->objfile->objfile_obstack,
|
|
name, gnat_encoding_suffix - name);
|
|
/* Use -1 here so that SUFFIX points at the "_" after the
|
|
"XF". */
|
|
gnat_encoding_suffix += strlen (GNAT_FIXED_POINT_SUFFIX) - 1;
|
|
|
|
encoding = (encoding == DW_ATE_signed
|
|
? DW_ATE_signed_fixed
|
|
: DW_ATE_unsigned_fixed);
|
|
}
|
|
}
|
|
|
|
type_allocator alloc (objfile, cu->lang ());
|
|
switch (encoding)
|
|
{
|
|
case DW_ATE_address:
|
|
/* Turn DW_ATE_address into a void * pointer. */
|
|
type = alloc.new_type (TYPE_CODE_VOID, TARGET_CHAR_BIT, NULL);
|
|
type = init_pointer_type (alloc, bits, name, type);
|
|
break;
|
|
case DW_ATE_boolean:
|
|
type = init_boolean_type (alloc, bits, 1, name);
|
|
break;
|
|
case DW_ATE_complex_float:
|
|
type = dwarf2_init_complex_target_type (cu, bits / 2, name,
|
|
byte_order);
|
|
if (type->code () == TYPE_CODE_ERROR)
|
|
{
|
|
if (name == nullptr)
|
|
{
|
|
struct obstack *obstack
|
|
= &cu->per_objfile->objfile->objfile_obstack;
|
|
name = obconcat (obstack, "_Complex ", type->name (),
|
|
nullptr);
|
|
}
|
|
type = alloc.new_type (TYPE_CODE_ERROR, bits, name);
|
|
}
|
|
else
|
|
type = init_complex_type (name, type);
|
|
break;
|
|
case DW_ATE_decimal_float:
|
|
type = init_decfloat_type (alloc, bits, name);
|
|
break;
|
|
case DW_ATE_float:
|
|
type = dwarf2_init_float_type (cu, bits, name, name, byte_order);
|
|
break;
|
|
case DW_ATE_signed:
|
|
type = dwarf2_init_integer_type (cu, bits, 0, name);
|
|
break;
|
|
case DW_ATE_unsigned:
|
|
if (cu->lang () == language_fortran
|
|
&& name
|
|
&& startswith (name, "character("))
|
|
type = init_character_type (alloc, bits, 1, name);
|
|
else
|
|
type = dwarf2_init_integer_type (cu, bits, 1, name);
|
|
break;
|
|
case DW_ATE_signed_char:
|
|
if (cu->lang () == language_ada
|
|
|| cu->lang () == language_m2
|
|
|| cu->lang () == language_pascal
|
|
|| cu->lang () == language_fortran)
|
|
type = init_character_type (alloc, bits, 0, name);
|
|
else
|
|
type = dwarf2_init_integer_type (cu, bits, 0, name);
|
|
break;
|
|
case DW_ATE_unsigned_char:
|
|
if (cu->lang () == language_ada
|
|
|| cu->lang () == language_m2
|
|
|| cu->lang () == language_pascal
|
|
|| cu->lang () == language_fortran
|
|
|| cu->lang () == language_rust)
|
|
type = init_character_type (alloc, bits, 1, name);
|
|
else
|
|
type = dwarf2_init_integer_type (cu, bits, 1, name);
|
|
break;
|
|
case DW_ATE_UTF:
|
|
{
|
|
type = init_character_type (alloc, bits, 1, name);
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
break;
|
|
case DW_ATE_signed_fixed:
|
|
type = init_fixed_point_type (alloc, bits, 0, name);
|
|
finish_fixed_point_type (type, gnat_encoding_suffix, die, cu);
|
|
break;
|
|
case DW_ATE_unsigned_fixed:
|
|
type = init_fixed_point_type (alloc, bits, 1, name);
|
|
finish_fixed_point_type (type, gnat_encoding_suffix, die, cu);
|
|
break;
|
|
|
|
default:
|
|
complaint (_("unsupported DW_AT_encoding: '%s'"),
|
|
dwarf_type_encoding_name (encoding));
|
|
type = alloc.new_type (TYPE_CODE_ERROR, bits, name);
|
|
break;
|
|
}
|
|
|
|
if (type->code () == TYPE_CODE_INT
|
|
&& name != nullptr
|
|
&& strcmp (name, "char") == 0)
|
|
type->set_has_no_signedness (true);
|
|
|
|
maybe_set_alignment (cu, die, type);
|
|
|
|
type->set_endianity_is_not_default (not_default);
|
|
|
|
if (TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_INT)
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_bit_size, cu);
|
|
if (attr != nullptr && attr->form_is_constant ())
|
|
{
|
|
unsigned real_bit_size = attr->constant_value (0);
|
|
if (real_bit_size >= 0 && real_bit_size <= 8 * type->length ())
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu);
|
|
/* Only use the attributes if they make sense together. */
|
|
if (attr == nullptr
|
|
|| (attr->form_is_constant ()
|
|
&& attr->constant_value (0) >= 0
|
|
&& (attr->constant_value (0) + real_bit_size
|
|
<= 8 * type->length ())))
|
|
{
|
|
TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_size
|
|
= real_bit_size;
|
|
if (attr != nullptr)
|
|
TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_offset
|
|
= attr->constant_value (0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
/* A helper function that returns the name of DIE, if it refers to a
|
|
variable declaration. */
|
|
|
|
static const char *
|
|
var_decl_name (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
if (die->tag != DW_TAG_variable)
|
|
return nullptr;
|
|
|
|
attribute *attr = dwarf2_attr (die, DW_AT_declaration, cu);
|
|
if (attr == nullptr || !attr->as_boolean ())
|
|
return nullptr;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_name, cu);
|
|
if (attr == nullptr)
|
|
return nullptr;
|
|
return attr->as_string ();
|
|
}
|
|
|
|
/* Parse dwarf attribute if it's a block, reference or constant and put the
|
|
resulting value of the attribute into struct bound_prop.
|
|
Returns 1 if ATTR could be resolved into PROP, 0 otherwise. */
|
|
|
|
static int
|
|
attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
|
|
struct dwarf2_cu *cu, struct dynamic_prop *prop,
|
|
struct type *default_type)
|
|
{
|
|
struct dwarf2_property_baton *baton;
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct obstack *obstack = &objfile->objfile_obstack;
|
|
|
|
gdb_assert (default_type != NULL);
|
|
|
|
if (attr == NULL || prop == NULL)
|
|
return 0;
|
|
|
|
if (attr->form_is_block ())
|
|
{
|
|
baton = XOBNEW (obstack, struct dwarf2_property_baton);
|
|
baton->property_type = default_type;
|
|
baton->locexpr.per_cu = cu->per_cu;
|
|
baton->locexpr.per_objfile = per_objfile;
|
|
|
|
struct dwarf_block block;
|
|
if (attr->form == DW_FORM_data16)
|
|
{
|
|
size_t data_size = 16;
|
|
block.size = (data_size
|
|
+ 2 /* Extra bytes for DW_OP and arg. */);
|
|
gdb_byte *data = XOBNEWVEC (obstack, gdb_byte, block.size);
|
|
data[0] = DW_OP_implicit_value;
|
|
data[1] = data_size;
|
|
memcpy (&data[2], attr->as_block ()->data, data_size);
|
|
block.data = data;
|
|
}
|
|
else
|
|
block = *attr->as_block ();
|
|
|
|
baton->locexpr.size = block.size;
|
|
baton->locexpr.data = block.data;
|
|
switch (attr->name)
|
|
{
|
|
case DW_AT_string_length:
|
|
baton->locexpr.is_reference = true;
|
|
break;
|
|
default:
|
|
baton->locexpr.is_reference = false;
|
|
break;
|
|
}
|
|
|
|
prop->set_locexpr (baton);
|
|
gdb_assert (prop->baton () != NULL);
|
|
}
|
|
else if (attr->form_is_ref ())
|
|
{
|
|
struct dwarf2_cu *target_cu = cu;
|
|
struct die_info *target_die;
|
|
struct attribute *target_attr;
|
|
|
|
target_die = follow_die_ref (die, attr, &target_cu);
|
|
target_attr = dwarf2_attr (target_die, DW_AT_location, target_cu);
|
|
if (target_attr == NULL)
|
|
target_attr = dwarf2_attr (target_die, DW_AT_data_member_location,
|
|
target_cu);
|
|
if (target_attr == nullptr)
|
|
target_attr = dwarf2_attr (target_die, DW_AT_data_bit_offset,
|
|
target_cu);
|
|
if (target_attr == NULL)
|
|
{
|
|
const char *name = var_decl_name (target_die, target_cu);
|
|
if (name != nullptr)
|
|
{
|
|
prop->set_variable_name (name);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
switch (target_attr->name)
|
|
{
|
|
case DW_AT_location:
|
|
if (target_attr->form_is_section_offset ())
|
|
{
|
|
baton = XOBNEW (obstack, struct dwarf2_property_baton);
|
|
baton->property_type = die_type (target_die, target_cu);
|
|
fill_in_loclist_baton (cu, &baton->loclist, target_attr);
|
|
prop->set_loclist (baton);
|
|
gdb_assert (prop->baton () != NULL);
|
|
}
|
|
else if (target_attr->form_is_block ())
|
|
{
|
|
baton = XOBNEW (obstack, struct dwarf2_property_baton);
|
|
baton->property_type = die_type (target_die, target_cu);
|
|
baton->locexpr.per_cu = cu->per_cu;
|
|
baton->locexpr.per_objfile = per_objfile;
|
|
struct dwarf_block *block = target_attr->as_block ();
|
|
baton->locexpr.size = block->size;
|
|
baton->locexpr.data = block->data;
|
|
baton->locexpr.is_reference = true;
|
|
prop->set_locexpr (baton);
|
|
gdb_assert (prop->baton () != NULL);
|
|
}
|
|
else
|
|
{
|
|
dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
|
|
"dynamic property");
|
|
return 0;
|
|
}
|
|
break;
|
|
case DW_AT_data_member_location:
|
|
case DW_AT_data_bit_offset:
|
|
{
|
|
LONGEST offset;
|
|
|
|
if (!handle_member_location (target_die, target_cu, &offset))
|
|
return 0;
|
|
|
|
baton = XOBNEW (obstack, struct dwarf2_property_baton);
|
|
baton->property_type = read_type_die (target_die->parent,
|
|
target_cu);
|
|
baton->offset_info.offset = offset;
|
|
baton->offset_info.type = die_type (target_die, target_cu);
|
|
prop->set_addr_offset (baton);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (attr->form_is_constant ())
|
|
prop->set_const_val (attr->constant_value (0));
|
|
else if (attr->form_is_section_offset ())
|
|
{
|
|
switch (attr->name)
|
|
{
|
|
case DW_AT_string_length:
|
|
baton = XOBNEW (obstack, struct dwarf2_property_baton);
|
|
baton->property_type = default_type;
|
|
fill_in_loclist_baton (cu, &baton->loclist, attr);
|
|
prop->set_loclist (baton);
|
|
gdb_assert (prop->baton () != NULL);
|
|
break;
|
|
default:
|
|
goto invalid;
|
|
}
|
|
}
|
|
else
|
|
goto invalid;
|
|
|
|
return 1;
|
|
|
|
invalid:
|
|
dwarf2_invalid_attrib_class_complaint (dwarf_form_name (attr->form),
|
|
dwarf2_name (die, cu));
|
|
return 0;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
/* Read the DW_AT_type attribute for a sub-range. If this attribute is not
|
|
present (which is valid) then compute the default type based on the
|
|
compilation units address size. */
|
|
|
|
static struct type *
|
|
read_subrange_index_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *index_type = die_type (die, cu);
|
|
|
|
/* Dwarf-2 specifications explicitly allows to create subrange types
|
|
without specifying a base type.
|
|
In that case, the base type must be set to the type of
|
|
the lower bound, upper bound or count, in that order, if any of these
|
|
three attributes references an object that has a type.
|
|
If no base type is found, the Dwarf-2 specifications say that
|
|
a signed integer type of size equal to the size of an address should
|
|
be used.
|
|
For the following C code: `extern char gdb_int [];'
|
|
GCC produces an empty range DIE.
|
|
FIXME: muller/2010-05-28: Possible references to object for low bound,
|
|
high bound or count are not yet handled by this code. */
|
|
if (index_type->code () == TYPE_CODE_VOID)
|
|
index_type = cu->addr_sized_int_type (false);
|
|
|
|
return index_type;
|
|
}
|
|
|
|
/* Read the given DW_AT_subrange DIE. */
|
|
|
|
static struct type *
|
|
read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *base_type, *orig_base_type;
|
|
struct type *range_type;
|
|
struct attribute *attr;
|
|
struct dynamic_prop low, high;
|
|
int low_default_is_valid;
|
|
int high_bound_is_count = 0;
|
|
const char *name;
|
|
|
|
orig_base_type = read_subrange_index_type (die, cu);
|
|
|
|
/* If ORIG_BASE_TYPE is a typedef, it will not be TYPE_UNSIGNED,
|
|
whereas the real type might be. So, we use ORIG_BASE_TYPE when
|
|
creating the range type, but we use the result of check_typedef
|
|
when examining properties of the type. */
|
|
base_type = check_typedef (orig_base_type);
|
|
|
|
/* The die_type call above may have already set the type for this DIE. */
|
|
range_type = get_die_type (die, cu);
|
|
if (range_type)
|
|
return range_type;
|
|
|
|
high.set_const_val (0);
|
|
|
|
/* Set LOW_DEFAULT_IS_VALID if current language and DWARF version allow
|
|
omitting DW_AT_lower_bound. */
|
|
switch (strip_cplus_dialect (cu->lang ()))
|
|
{
|
|
case language_c:
|
|
case language_cplus:
|
|
low.set_const_val (0);
|
|
low_default_is_valid = 1;
|
|
break;
|
|
case language_fortran:
|
|
low.set_const_val (1);
|
|
low_default_is_valid = 1;
|
|
break;
|
|
case language_d:
|
|
case language_objc:
|
|
case language_rust:
|
|
low.set_const_val (0);
|
|
low_default_is_valid = (cu->header.version >= 4);
|
|
break;
|
|
case language_ada:
|
|
case language_m2:
|
|
case language_pascal:
|
|
low.set_const_val (1);
|
|
low_default_is_valid = (cu->header.version >= 4);
|
|
break;
|
|
default:
|
|
low.set_const_val (0);
|
|
low_default_is_valid = 0;
|
|
break;
|
|
}
|
|
|
|
attr = dwarf2_attr (die, DW_AT_lower_bound, cu);
|
|
if (attr != nullptr)
|
|
attr_to_dynamic_prop (attr, die, cu, &low, base_type);
|
|
else if (!low_default_is_valid)
|
|
complaint (_("Missing DW_AT_lower_bound "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
|
|
struct attribute *attr_ub, *attr_count;
|
|
attr = attr_ub = dwarf2_attr (die, DW_AT_upper_bound, cu);
|
|
if (!attr_to_dynamic_prop (attr, die, cu, &high, base_type))
|
|
{
|
|
attr = attr_count = dwarf2_attr (die, DW_AT_count, cu);
|
|
if (attr_to_dynamic_prop (attr, die, cu, &high, base_type))
|
|
{
|
|
/* If bounds are constant do the final calculation here. */
|
|
if (low.is_constant () && high.is_constant ())
|
|
high.set_const_val (low.const_val () + high.const_val () - 1);
|
|
else
|
|
high_bound_is_count = 1;
|
|
}
|
|
else
|
|
{
|
|
if (attr_ub != NULL)
|
|
complaint (_("Unresolved DW_AT_upper_bound "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
if (attr_count != NULL)
|
|
complaint (_("Unresolved DW_AT_count "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
}
|
|
}
|
|
|
|
LONGEST bias = 0;
|
|
struct attribute *bias_attr = dwarf2_attr (die, DW_AT_GNU_bias, cu);
|
|
if (bias_attr != nullptr && bias_attr->form_is_constant ())
|
|
bias = bias_attr->constant_value (0);
|
|
|
|
/* Normally, the DWARF producers are expected to use a signed
|
|
constant form (Eg. DW_FORM_sdata) to express negative bounds.
|
|
But this is unfortunately not always the case, as witnessed
|
|
with GCC, for instance, where the ambiguous DW_FORM_dataN form
|
|
is used instead. To work around that ambiguity, we treat
|
|
the bounds as signed, and thus sign-extend their values, when
|
|
the base type is signed.
|
|
|
|
Skip it if the base type's length is larger than ULONGEST, to avoid
|
|
the undefined behavior of a too large left shift. We don't really handle
|
|
constants larger than 8 bytes anyway, at the moment. */
|
|
|
|
if (base_type->length () <= sizeof (ULONGEST))
|
|
{
|
|
ULONGEST negative_mask
|
|
= -((ULONGEST) 1 << (base_type->length () * TARGET_CHAR_BIT - 1));
|
|
|
|
if (low.is_constant ()
|
|
&& !base_type->is_unsigned () && (low.const_val () & negative_mask))
|
|
low.set_const_val (low.const_val () | negative_mask);
|
|
|
|
if (high.is_constant ()
|
|
&& !base_type->is_unsigned () && (high.const_val () & negative_mask))
|
|
high.set_const_val (high.const_val () | negative_mask);
|
|
}
|
|
|
|
/* Check for bit and byte strides. */
|
|
struct dynamic_prop byte_stride_prop;
|
|
attribute *attr_byte_stride = dwarf2_attr (die, DW_AT_byte_stride, cu);
|
|
if (attr_byte_stride != nullptr)
|
|
{
|
|
struct type *prop_type = cu->addr_sized_int_type (false);
|
|
attr_to_dynamic_prop (attr_byte_stride, die, cu, &byte_stride_prop,
|
|
prop_type);
|
|
}
|
|
|
|
struct dynamic_prop bit_stride_prop;
|
|
attribute *attr_bit_stride = dwarf2_attr (die, DW_AT_bit_stride, cu);
|
|
if (attr_bit_stride != nullptr)
|
|
{
|
|
/* It only makes sense to have either a bit or byte stride. */
|
|
if (attr_byte_stride != nullptr)
|
|
{
|
|
complaint (_("Found DW_AT_bit_stride and DW_AT_byte_stride "
|
|
"- DIE at %s [in module %s]"),
|
|
sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
attr_bit_stride = nullptr;
|
|
}
|
|
else
|
|
{
|
|
struct type *prop_type = cu->addr_sized_int_type (false);
|
|
attr_to_dynamic_prop (attr_bit_stride, die, cu, &bit_stride_prop,
|
|
prop_type);
|
|
}
|
|
}
|
|
|
|
type_allocator alloc (cu->per_objfile->objfile, cu->lang ());
|
|
if (attr_byte_stride != nullptr
|
|
|| attr_bit_stride != nullptr)
|
|
{
|
|
bool byte_stride_p = (attr_byte_stride != nullptr);
|
|
struct dynamic_prop *stride
|
|
= byte_stride_p ? &byte_stride_prop : &bit_stride_prop;
|
|
|
|
range_type
|
|
= create_range_type_with_stride (alloc, orig_base_type, &low,
|
|
&high, bias, stride, byte_stride_p);
|
|
}
|
|
else
|
|
range_type = create_range_type (alloc, orig_base_type, &low, &high, bias);
|
|
|
|
if (high_bound_is_count)
|
|
range_type->bounds ()->flag_upper_bound_is_count = 1;
|
|
|
|
/* Ada expects an empty array on no boundary attributes. */
|
|
if (attr == NULL && cu->lang () != language_ada)
|
|
range_type->bounds ()->high.set_undefined ();
|
|
|
|
name = dwarf2_name (die, cu);
|
|
if (name)
|
|
range_type->set_name (name);
|
|
|
|
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
|
|
if (attr != nullptr)
|
|
range_type->set_length (attr->constant_value (0));
|
|
|
|
maybe_set_alignment (cu, die, range_type);
|
|
|
|
set_die_type (die, range_type, cu);
|
|
|
|
/* set_die_type should be already done. */
|
|
set_descriptive_type (range_type, die, cu);
|
|
|
|
return range_type;
|
|
}
|
|
|
|
static struct type *
|
|
read_unspecified_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *type;
|
|
|
|
type = (type_allocator (cu->per_objfile->objfile, cu->lang ())
|
|
.new_type (TYPE_CODE_VOID, 0, nullptr));
|
|
type->set_name (dwarf2_name (die, cu));
|
|
|
|
/* In Ada, an unspecified type is typically used when the description
|
|
of the type is deferred to a different unit. When encountering
|
|
such a type, we treat it as a stub, and try to resolve it later on,
|
|
when needed.
|
|
Mark this as a stub type for all languages though. */
|
|
type->set_is_stub (true);
|
|
|
|
return set_die_type (die, type, cu);
|
|
}
|
|
|
|
/* Read a single die and all its descendents. Set the die's sibling
|
|
field to NULL; set other fields in the die correctly, and set all
|
|
of the descendents' fields correctly. Set *NEW_INFO_PTR to the
|
|
location of the info_ptr after reading all of those dies. PARENT
|
|
is the parent of the die in question. */
|
|
|
|
static struct die_info *
|
|
read_die_and_children (const struct die_reader_specs *reader,
|
|
const gdb_byte *info_ptr,
|
|
const gdb_byte **new_info_ptr,
|
|
struct die_info *parent)
|
|
{
|
|
struct die_info *die;
|
|
const gdb_byte *cur_ptr;
|
|
|
|
cur_ptr = read_full_die_1 (reader, &die, info_ptr, 0, true);
|
|
if (die == NULL)
|
|
{
|
|
*new_info_ptr = cur_ptr;
|
|
return NULL;
|
|
}
|
|
|
|
bool inserted = reader->cu->die_hash.emplace (die).second;
|
|
gdb_assert (inserted);
|
|
|
|
if (die->has_children)
|
|
die->child = read_die_and_siblings_1 (reader, cur_ptr, new_info_ptr, die);
|
|
else
|
|
{
|
|
die->child = NULL;
|
|
*new_info_ptr = cur_ptr;
|
|
}
|
|
|
|
die->sibling = NULL;
|
|
die->parent = parent;
|
|
return die;
|
|
}
|
|
|
|
/* Read a die, all of its descendents, and all of its siblings; set
|
|
all of the fields of all of the dies correctly. Arguments are as
|
|
in read_die_and_children. */
|
|
|
|
static struct die_info *
|
|
read_die_and_siblings_1 (const struct die_reader_specs *reader,
|
|
const gdb_byte *info_ptr,
|
|
const gdb_byte **new_info_ptr,
|
|
struct die_info *parent)
|
|
{
|
|
struct die_info *first_die, *last_sibling;
|
|
const gdb_byte *cur_ptr;
|
|
|
|
cur_ptr = info_ptr;
|
|
first_die = last_sibling = NULL;
|
|
|
|
while (1)
|
|
{
|
|
struct die_info *die
|
|
= read_die_and_children (reader, cur_ptr, &cur_ptr, parent);
|
|
|
|
if (die == NULL)
|
|
{
|
|
*new_info_ptr = cur_ptr;
|
|
return first_die;
|
|
}
|
|
|
|
if (!first_die)
|
|
first_die = die;
|
|
else
|
|
last_sibling->sibling = die;
|
|
|
|
last_sibling = die;
|
|
}
|
|
}
|
|
|
|
/* Read a die, all of its descendents, and all of its siblings; set
|
|
all of the fields of all of the dies correctly. Arguments are as
|
|
in read_die_and_children.
|
|
This the main entry point for reading a DIE and all its children. */
|
|
|
|
static struct die_info *
|
|
read_die_and_siblings (const struct die_reader_specs *reader,
|
|
const gdb_byte *info_ptr,
|
|
const gdb_byte **new_info_ptr,
|
|
struct die_info *parent)
|
|
{
|
|
struct die_info *die = read_die_and_siblings_1 (reader, info_ptr,
|
|
new_info_ptr, parent);
|
|
|
|
if (dwarf_die_debug)
|
|
{
|
|
gdb_printf (gdb_stdlog,
|
|
"Read die from %s@0x%x of %s:\n",
|
|
reader->die_section->get_name (),
|
|
(unsigned) (info_ptr - reader->die_section->buffer),
|
|
bfd_get_filename (reader->abfd));
|
|
die->dump (dwarf_die_debug);
|
|
}
|
|
|
|
return die;
|
|
}
|
|
|
|
/* Read a die and all its attributes, leave space for NUM_EXTRA_ATTRS
|
|
attributes.
|
|
The caller is responsible for filling in the extra attributes
|
|
and updating (*DIEP)->num_attrs.
|
|
Set DIEP to point to a newly allocated die with its information,
|
|
except for its child, sibling, and parent fields. */
|
|
|
|
static const gdb_byte *
|
|
read_full_die_1 (const struct die_reader_specs *reader,
|
|
struct die_info **diep, const gdb_byte *info_ptr,
|
|
int num_extra_attrs, bool allow_reprocess)
|
|
{
|
|
unsigned int abbrev_number, bytes_read, i;
|
|
const struct abbrev_info *abbrev;
|
|
struct die_info *die;
|
|
struct dwarf2_cu *cu = reader->cu;
|
|
bfd *abfd = reader->abfd;
|
|
|
|
sect_offset sect_off = (sect_offset) (info_ptr - reader->buffer);
|
|
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
if (!abbrev_number)
|
|
{
|
|
*diep = NULL;
|
|
return info_ptr;
|
|
}
|
|
|
|
abbrev = reader->abbrev_table->lookup_abbrev (abbrev_number);
|
|
if (!abbrev)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"could not find abbrev number %d [in module %s]"),
|
|
abbrev_number,
|
|
bfd_get_filename (abfd));
|
|
|
|
die = die_info::allocate (&cu->comp_unit_obstack,
|
|
abbrev->num_attrs + num_extra_attrs);
|
|
die->sect_off = sect_off;
|
|
die->tag = abbrev->tag;
|
|
die->abbrev = abbrev_number;
|
|
die->has_children = abbrev->has_children;
|
|
|
|
/* Make the result usable.
|
|
The caller needs to update num_attrs after adding the extra
|
|
attributes. */
|
|
die->num_attrs = abbrev->num_attrs;
|
|
|
|
for (i = 0; i < abbrev->num_attrs; ++i)
|
|
info_ptr = read_attribute (reader, &die->attrs[i], &abbrev->attrs[i],
|
|
info_ptr, allow_reprocess);
|
|
|
|
*diep = die;
|
|
return info_ptr;
|
|
}
|
|
|
|
/* Read a die and all its attributes.
|
|
Set DIEP to point to a newly allocated die with its information,
|
|
except for its child, sibling, and parent fields. */
|
|
|
|
static const gdb_byte *
|
|
read_toplevel_die (const struct die_reader_specs *reader,
|
|
struct die_info **diep, const gdb_byte *info_ptr,
|
|
gdb::array_view<attribute *> extra_attrs)
|
|
{
|
|
const gdb_byte *result;
|
|
struct dwarf2_cu *cu = reader->cu;
|
|
|
|
result = read_full_die_1 (reader, diep, info_ptr, extra_attrs.size (),
|
|
false);
|
|
|
|
/* Copy in the extra attributes, if any. */
|
|
attribute *next = &(*diep)->attrs[(*diep)->num_attrs];
|
|
for (attribute *extra : extra_attrs)
|
|
*next++ = *extra;
|
|
|
|
struct attribute *attr = (*diep)->attr (DW_AT_str_offsets_base);
|
|
if (attr != nullptr && attr->form_is_unsigned ())
|
|
cu->str_offsets_base = attr->as_unsigned ();
|
|
|
|
attr = (*diep)->attr (DW_AT_loclists_base);
|
|
if (attr != nullptr)
|
|
cu->loclist_base = attr->as_unsigned ();
|
|
|
|
auto maybe_addr_base = (*diep)->addr_base ();
|
|
if (maybe_addr_base.has_value ())
|
|
cu->addr_base = *maybe_addr_base;
|
|
|
|
attr = (*diep)->attr (DW_AT_rnglists_base);
|
|
if (attr != nullptr)
|
|
cu->rnglists_base = attr->as_unsigned ();
|
|
|
|
for (int i = 0; i < (*diep)->num_attrs; ++i)
|
|
{
|
|
if ((*diep)->attrs[i].form_requires_reprocessing ())
|
|
read_attribute_reprocess (reader, &(*diep)->attrs[i], (*diep)->tag);
|
|
}
|
|
|
|
(*diep)->num_attrs += extra_attrs.size ();
|
|
|
|
if (dwarf_die_debug)
|
|
{
|
|
gdb_printf (gdb_stdlog,
|
|
"Read die from %s@0x%x of %s:\n",
|
|
reader->die_section->get_name (),
|
|
(unsigned) (info_ptr - reader->die_section->buffer),
|
|
bfd_get_filename (reader->abfd));
|
|
(*diep)->dump (dwarf_die_debug);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
void
|
|
cooked_indexer::check_bounds (cutu_reader *reader)
|
|
{
|
|
if (reader->cu->per_cu->addresses_seen)
|
|
return;
|
|
|
|
dwarf2_cu *cu = reader->cu;
|
|
|
|
unrelocated_addr best_lowpc = {}, best_highpc = {};
|
|
/* Possibly set the default values of LOWPC and HIGHPC from
|
|
`DW_AT_ranges'. */
|
|
dwarf2_find_base_address (reader->comp_unit_die, cu);
|
|
enum pc_bounds_kind cu_bounds_kind
|
|
= dwarf2_get_pc_bounds (reader->comp_unit_die, &best_lowpc, &best_highpc,
|
|
cu, m_index_storage->get_addrmap (), cu->per_cu);
|
|
if (cu_bounds_kind == PC_BOUNDS_HIGH_LOW && best_lowpc < best_highpc)
|
|
{
|
|
/* Store the contiguous range if it is not empty; it can be
|
|
empty for CUs with no code. addrmap requires CORE_ADDR, so
|
|
we cast here. */
|
|
m_index_storage->get_addrmap ()->set_empty ((CORE_ADDR) best_lowpc,
|
|
(CORE_ADDR) best_highpc - 1,
|
|
cu->per_cu);
|
|
|
|
cu->per_cu->addresses_seen = true;
|
|
}
|
|
}
|
|
|
|
/* Helper function that returns true if TAG can have a linkage
|
|
name. */
|
|
|
|
static bool
|
|
tag_can_have_linkage_name (enum dwarf_tag tag)
|
|
{
|
|
switch (tag)
|
|
{
|
|
case DW_TAG_variable:
|
|
case DW_TAG_subprogram:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
cutu_reader *
|
|
cooked_indexer::ensure_cu_exists (cutu_reader *reader,
|
|
dwarf2_per_objfile *per_objfile,
|
|
sect_offset sect_off, bool is_dwz,
|
|
bool for_scanning)
|
|
{
|
|
/* Lookups for type unit references are always in the CU, and
|
|
cross-CU references will crash. */
|
|
if (reader->cu->per_cu->is_dwz == is_dwz
|
|
&& reader->cu->header.offset_in_cu_p (sect_off))
|
|
return reader;
|
|
|
|
dwarf2_per_cu_data *per_cu
|
|
= dwarf2_find_containing_comp_unit (sect_off, is_dwz,
|
|
per_objfile->per_bfd);
|
|
|
|
/* When scanning, we only want to visit a given CU a single time.
|
|
Doing this check here avoids self-imports as well. */
|
|
if (for_scanning)
|
|
{
|
|
bool nope = false;
|
|
if (!per_cu->scanned.compare_exchange_strong (nope, true))
|
|
return nullptr;
|
|
}
|
|
|
|
cutu_reader *result = m_index_storage->get_reader (per_cu);
|
|
if (result == nullptr)
|
|
{
|
|
cutu_reader new_reader (per_cu, per_objfile, nullptr, nullptr, false,
|
|
&m_index_storage->get_abbrev_table_cache ());
|
|
|
|
if (new_reader.dummy_p || new_reader.comp_unit_die == nullptr
|
|
|| !new_reader.comp_unit_die->has_children)
|
|
return nullptr;
|
|
|
|
prepare_one_comp_unit (new_reader.cu, new_reader.comp_unit_die,
|
|
language_minimal);
|
|
std::unique_ptr<cutu_reader> copy
|
|
(new cutu_reader (std::move (new_reader)));
|
|
result = m_index_storage->preserve (std::move (copy));
|
|
}
|
|
|
|
if (result->dummy_p || result->comp_unit_die == nullptr
|
|
|| !result->comp_unit_die->has_children)
|
|
return nullptr;
|
|
|
|
if (for_scanning)
|
|
check_bounds (result);
|
|
|
|
return result;
|
|
}
|
|
|
|
const gdb_byte *
|
|
cooked_indexer::scan_attributes (dwarf2_per_cu_data *scanning_per_cu,
|
|
cutu_reader *reader,
|
|
const gdb_byte *watermark_ptr,
|
|
const gdb_byte *info_ptr,
|
|
const abbrev_info *abbrev,
|
|
const char **name,
|
|
const char **linkage_name,
|
|
cooked_index_flag *flags,
|
|
sect_offset *sibling_offset,
|
|
const cooked_index_entry **parent_entry,
|
|
parent_map::addr_type *maybe_defer,
|
|
bool *is_enum_class,
|
|
bool for_specification)
|
|
{
|
|
bool origin_is_dwz = false;
|
|
bool is_declaration = false;
|
|
sect_offset origin_offset {};
|
|
|
|
std::optional<unrelocated_addr> low_pc;
|
|
std::optional<unrelocated_addr> high_pc;
|
|
bool high_pc_relative = false;
|
|
|
|
for (int i = 0; i < abbrev->num_attrs; ++i)
|
|
{
|
|
attribute attr;
|
|
info_ptr = read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr);
|
|
|
|
/* Store the data if it is of an attribute we want to keep in a
|
|
partial symbol table. */
|
|
switch (attr.name)
|
|
{
|
|
case DW_AT_name:
|
|
switch (abbrev->tag)
|
|
{
|
|
case DW_TAG_compile_unit:
|
|
case DW_TAG_partial_unit:
|
|
case DW_TAG_type_unit:
|
|
/* Compilation units have a DW_AT_name that is a filename, not
|
|
a source language identifier. */
|
|
break;
|
|
|
|
default:
|
|
if (*name == nullptr)
|
|
*name = attr.as_string ();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DW_AT_linkage_name:
|
|
case DW_AT_MIPS_linkage_name:
|
|
/* Note that both forms of linkage name might appear. We
|
|
assume they will be the same, and we only store the last
|
|
one we see. */
|
|
if (*linkage_name == nullptr)
|
|
{
|
|
*linkage_name = attr.as_string ();
|
|
|
|
if (*linkage_name != nullptr)
|
|
{
|
|
*linkage_name
|
|
= (gdb_hip_test_mode_frob_names
|
|
(reader->cu->per_objfile->objfile,
|
|
*linkage_name));
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* DWARF 4 has defined a dedicated DW_AT_main_subprogram
|
|
attribute to indicate the starting function of the program... */
|
|
case DW_AT_main_subprogram:
|
|
if (attr.as_boolean ())
|
|
*flags |= IS_MAIN;
|
|
break;
|
|
|
|
/* ... however with older versions the DW_CC_program value of
|
|
the DW_AT_calling_convention attribute was used instead as
|
|
the only means available. We handle both variants then. */
|
|
case DW_AT_calling_convention:
|
|
if (attr.constant_value (DW_CC_normal) == DW_CC_program)
|
|
*flags |= IS_MAIN;
|
|
break;
|
|
|
|
case DW_AT_declaration:
|
|
is_declaration = attr.as_boolean ();
|
|
break;
|
|
|
|
case DW_AT_sibling:
|
|
if (sibling_offset != nullptr)
|
|
*sibling_offset = attr.get_ref_die_offset ();
|
|
break;
|
|
|
|
case DW_AT_specification:
|
|
case DW_AT_abstract_origin:
|
|
case DW_AT_extension:
|
|
origin_offset = attr.get_ref_die_offset ();
|
|
origin_is_dwz = attr.form == DW_FORM_GNU_ref_alt;
|
|
break;
|
|
|
|
case DW_AT_external:
|
|
if (attr.as_boolean ())
|
|
*flags &= ~IS_STATIC;
|
|
break;
|
|
|
|
case DW_AT_enum_class:
|
|
if (attr.as_boolean ())
|
|
*is_enum_class = true;
|
|
break;
|
|
|
|
case DW_AT_low_pc:
|
|
low_pc = attr.as_address ();
|
|
break;
|
|
|
|
case DW_AT_high_pc:
|
|
high_pc = attr.as_address ();
|
|
if (reader->cu->header.version >= 4 && attr.form_is_constant ())
|
|
high_pc_relative = true;
|
|
break;
|
|
|
|
case DW_AT_location:
|
|
if (!scanning_per_cu->addresses_seen && attr.form_is_block ())
|
|
{
|
|
struct dwarf_block *locdesc = attr.as_block ();
|
|
CORE_ADDR addr;
|
|
if (decode_locdesc (locdesc, reader->cu, &addr)
|
|
&& (addr != 0
|
|
|| reader->cu->per_objfile->per_bfd->has_section_at_zero))
|
|
{
|
|
low_pc = (unrelocated_addr) addr;
|
|
/* For variables, we don't want to try decoding the
|
|
type just to find the size -- for gdb's purposes
|
|
we only need the address of a variable. */
|
|
high_pc = (unrelocated_addr) (addr + 1);
|
|
high_pc_relative = false;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DW_AT_ranges:
|
|
if (!scanning_per_cu->addresses_seen)
|
|
{
|
|
/* Offset in the .debug_ranges or .debug_rnglist section
|
|
(depending on DWARF version). */
|
|
ULONGEST ranges_offset = attr.as_unsigned ();
|
|
|
|
/* See dwarf2_cu::gnu_ranges_base's doc for why we might
|
|
want to add this value. */
|
|
ranges_offset += reader->cu->gnu_ranges_base;
|
|
|
|
unrelocated_addr lowpc, highpc;
|
|
dwarf2_ranges_read (ranges_offset, &lowpc, &highpc, reader->cu,
|
|
m_index_storage->get_addrmap (),
|
|
scanning_per_cu, abbrev->tag);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We don't want to examine declarations, but if we found a
|
|
declaration when handling DW_AT_specification or the like, then
|
|
that is ok. Similarly, we allow an external variable without a
|
|
location; those are resolved via minimal symbols. */
|
|
if (is_declaration && !for_specification
|
|
&& !(abbrev->tag == DW_TAG_variable && (*flags & IS_STATIC) == 0))
|
|
{
|
|
/* We always want to recurse into some types, but we may not
|
|
want to treat them as definitions. */
|
|
if ((abbrev->tag == DW_TAG_class_type
|
|
|| abbrev->tag == DW_TAG_structure_type
|
|
|| abbrev->tag == DW_TAG_union_type
|
|
|| abbrev->tag == DW_TAG_namespace)
|
|
&& abbrev->has_children)
|
|
*flags |= IS_TYPE_DECLARATION;
|
|
else
|
|
{
|
|
*linkage_name = nullptr;
|
|
*name = nullptr;
|
|
}
|
|
}
|
|
else if ((*name == nullptr
|
|
|| (*linkage_name == nullptr
|
|
&& tag_can_have_linkage_name (abbrev->tag))
|
|
|| (*parent_entry == nullptr && m_language != language_c))
|
|
&& origin_offset != sect_offset (0))
|
|
{
|
|
cutu_reader *new_reader
|
|
= ensure_cu_exists (reader, reader->cu->per_objfile, origin_offset,
|
|
origin_is_dwz, false);
|
|
if (new_reader == nullptr)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"cannot follow reference to DIE at %s"
|
|
" [in module %s]"),
|
|
sect_offset_str (origin_offset),
|
|
bfd_get_filename (reader->abfd));
|
|
|
|
const gdb_byte *new_info_ptr = (new_reader->buffer
|
|
+ to_underlying (origin_offset));
|
|
|
|
if (*parent_entry == nullptr)
|
|
{
|
|
/* We only perform immediate lookups of parents for DIEs
|
|
from earlier in this CU. This avoids any problem
|
|
with a NULL result when when we see a reference to a
|
|
DIE in another CU that we may or may not have
|
|
imported locally. */
|
|
parent_map::addr_type addr = parent_map::form_addr (new_info_ptr);
|
|
if (new_reader->cu != reader->cu || new_info_ptr > watermark_ptr)
|
|
*maybe_defer = addr;
|
|
else
|
|
*parent_entry = m_die_range_map->find (addr);
|
|
}
|
|
|
|
unsigned int bytes_read;
|
|
const abbrev_info *new_abbrev = peek_die_abbrev (*new_reader,
|
|
new_info_ptr,
|
|
&bytes_read);
|
|
|
|
if (new_abbrev == nullptr)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Unexpected null DIE at offset %s [in module %s]"),
|
|
sect_offset_str (origin_offset),
|
|
bfd_get_filename (new_reader->abfd));
|
|
|
|
new_info_ptr += bytes_read;
|
|
|
|
if (new_reader->cu == reader->cu && new_info_ptr == watermark_ptr)
|
|
{
|
|
/* Self-reference, we're done. */
|
|
}
|
|
else
|
|
scan_attributes (scanning_per_cu, new_reader, new_info_ptr,
|
|
new_info_ptr, new_abbrev, name, linkage_name,
|
|
flags, nullptr, parent_entry, maybe_defer,
|
|
is_enum_class, true);
|
|
}
|
|
|
|
if (!for_specification)
|
|
{
|
|
if (m_language == language_ada
|
|
&& *linkage_name == nullptr)
|
|
*linkage_name = *name;
|
|
|
|
if (!scanning_per_cu->addresses_seen
|
|
&& low_pc.has_value ()
|
|
&& (reader->cu->per_objfile->per_bfd->has_section_at_zero
|
|
|| *low_pc != (unrelocated_addr) 0)
|
|
&& high_pc.has_value ())
|
|
{
|
|
if (high_pc_relative)
|
|
high_pc = (unrelocated_addr) ((ULONGEST) *high_pc
|
|
+ (ULONGEST) *low_pc);
|
|
|
|
if (*high_pc > *low_pc)
|
|
{
|
|
/* Need CORE_ADDR casts for addrmap. */
|
|
m_index_storage->get_addrmap ()->set_empty
|
|
((CORE_ADDR) *low_pc, (CORE_ADDR) *high_pc - 1,
|
|
scanning_per_cu);
|
|
}
|
|
}
|
|
|
|
if (abbrev->tag == DW_TAG_module || abbrev->tag == DW_TAG_namespace)
|
|
*flags &= ~IS_STATIC;
|
|
|
|
if (abbrev->tag == DW_TAG_namespace && *name == nullptr)
|
|
*name = "(anonymous namespace)";
|
|
|
|
if (is_cplus_dialect (m_language)
|
|
&& (abbrev->tag == DW_TAG_class_type
|
|
|| abbrev->tag == DW_TAG_interface_type
|
|
|| abbrev->tag == DW_TAG_structure_type
|
|
|| abbrev->tag == DW_TAG_union_type
|
|
|| abbrev->tag == DW_TAG_enumeration_type
|
|
|| abbrev->tag == DW_TAG_enumerator))
|
|
*flags &= ~IS_STATIC;
|
|
|
|
/* Keep in sync with new_symbol. */
|
|
if (abbrev->tag == DW_TAG_subprogram
|
|
&& (m_language == language_ada
|
|
|| m_language == language_fortran))
|
|
*flags &= ~IS_STATIC;
|
|
}
|
|
|
|
return info_ptr;
|
|
}
|
|
|
|
const gdb_byte *
|
|
cooked_indexer::index_imported_unit (cutu_reader *reader,
|
|
const gdb_byte *info_ptr,
|
|
const abbrev_info *abbrev)
|
|
{
|
|
sect_offset sect_off {};
|
|
bool is_dwz = false;
|
|
|
|
for (int i = 0; i < abbrev->num_attrs; ++i)
|
|
{
|
|
/* Note that we never need to reprocess attributes here. */
|
|
attribute attr;
|
|
info_ptr = read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr);
|
|
|
|
if (attr.name == DW_AT_import)
|
|
{
|
|
sect_off = attr.get_ref_die_offset ();
|
|
is_dwz = (attr.form == DW_FORM_GNU_ref_alt
|
|
|| reader->cu->per_cu->is_dwz);
|
|
}
|
|
}
|
|
|
|
/* Did not find DW_AT_import. */
|
|
if (sect_off == sect_offset (0))
|
|
return info_ptr;
|
|
|
|
dwarf2_per_objfile *per_objfile = reader->cu->per_objfile;
|
|
cutu_reader *new_reader = ensure_cu_exists (reader, per_objfile, sect_off,
|
|
is_dwz, true);
|
|
if (new_reader != nullptr)
|
|
{
|
|
index_dies (new_reader, new_reader->info_ptr, nullptr, false);
|
|
|
|
reader->cu->add_dependence (new_reader->cu->per_cu);
|
|
}
|
|
|
|
return info_ptr;
|
|
}
|
|
|
|
const gdb_byte *
|
|
cooked_indexer::recurse (cutu_reader *reader,
|
|
const gdb_byte *info_ptr,
|
|
std::variant<const cooked_index_entry *,
|
|
parent_map::addr_type> parent,
|
|
bool fully)
|
|
{
|
|
info_ptr = index_dies (reader, info_ptr, parent, fully);
|
|
|
|
if (!std::holds_alternative<const cooked_index_entry *> (parent))
|
|
return info_ptr;
|
|
const cooked_index_entry *parent_entry
|
|
= std::get<const cooked_index_entry *> (parent);
|
|
|
|
if (parent_entry != nullptr)
|
|
{
|
|
/* Both start and end are inclusive, so use both "+ 1" and "- 1" to
|
|
limit the range to the children of parent_entry. */
|
|
parent_map::addr_type start
|
|
= parent_map::form_addr (reader->buffer
|
|
+ to_underlying (parent_entry->die_offset)
|
|
+ 1);
|
|
parent_map::addr_type end = parent_map::form_addr (info_ptr - 1);
|
|
m_die_range_map->add_entry (start, end, parent_entry);
|
|
}
|
|
|
|
return info_ptr;
|
|
}
|
|
|
|
const gdb_byte *
|
|
cooked_indexer::index_dies (cutu_reader *reader,
|
|
const gdb_byte *info_ptr,
|
|
std::variant<const cooked_index_entry *,
|
|
parent_map::addr_type> parent,
|
|
bool fully)
|
|
{
|
|
const gdb_byte *end_ptr = (reader->buffer
|
|
+ to_underlying (reader->cu->header.sect_off)
|
|
+ reader->cu->header.get_length_with_initial ());
|
|
|
|
while (info_ptr < end_ptr)
|
|
{
|
|
sect_offset this_die = (sect_offset) (info_ptr - reader->buffer);
|
|
unsigned int bytes_read;
|
|
const abbrev_info *abbrev = peek_die_abbrev (*reader, info_ptr,
|
|
&bytes_read);
|
|
info_ptr += bytes_read;
|
|
if (abbrev == nullptr)
|
|
break;
|
|
|
|
if (abbrev->tag == DW_TAG_imported_unit)
|
|
{
|
|
info_ptr = index_imported_unit (reader, info_ptr, abbrev);
|
|
continue;
|
|
}
|
|
|
|
parent_map::addr_type defer {};
|
|
if (std::holds_alternative<parent_map::addr_type> (parent))
|
|
defer = std::get<parent_map::addr_type> (parent);
|
|
const cooked_index_entry *parent_entry = nullptr;
|
|
if (std::holds_alternative<const cooked_index_entry *> (parent))
|
|
parent_entry = std::get<const cooked_index_entry *> (parent);
|
|
|
|
/* If a DIE parent is a DW_TAG_subprogram, then the DIE is only
|
|
interesting if it's a DW_TAG_subprogram or a DW_TAG_entry_point. */
|
|
bool die_interesting
|
|
= (abbrev->interesting
|
|
&& (parent_entry == nullptr
|
|
|| parent_entry->tag != DW_TAG_subprogram
|
|
|| abbrev->tag == DW_TAG_subprogram
|
|
|| abbrev->tag == DW_TAG_entry_point));
|
|
|
|
if (!die_interesting)
|
|
{
|
|
info_ptr = skip_one_die (reader, info_ptr, abbrev, !fully);
|
|
if (fully && abbrev->has_children)
|
|
info_ptr = index_dies (reader, info_ptr, parent, fully);
|
|
continue;
|
|
}
|
|
|
|
const char *name = nullptr;
|
|
const char *linkage_name = nullptr;
|
|
cooked_index_flag flags = IS_STATIC;
|
|
sect_offset sibling {};
|
|
const cooked_index_entry *this_parent_entry = parent_entry;
|
|
bool is_enum_class = false;
|
|
|
|
/* The scope of a DW_TAG_entry_point cooked_index_entry is the one of
|
|
its surrounding subroutine. */
|
|
if (abbrev->tag == DW_TAG_entry_point)
|
|
this_parent_entry = parent_entry->get_parent ();
|
|
info_ptr = scan_attributes (reader->cu->per_cu, reader, info_ptr,
|
|
info_ptr, abbrev, &name, &linkage_name,
|
|
&flags, &sibling, &this_parent_entry,
|
|
&defer, &is_enum_class, false);
|
|
/* A DW_TAG_entry_point inherits its static/extern property from
|
|
the enclosing subroutine. */
|
|
if (abbrev->tag == DW_TAG_entry_point)
|
|
{
|
|
flags &= ~IS_STATIC;
|
|
flags |= parent_entry->flags & IS_STATIC;
|
|
}
|
|
|
|
if (abbrev->tag == DW_TAG_namespace
|
|
&& is_cplus_dialect (m_language)
|
|
&& strcmp (name, "::") == 0)
|
|
{
|
|
/* GCC 4.0 and 4.1 had a bug (PR c++/28460) where they
|
|
generated bogus DW_TAG_namespace DIEs with a name of "::"
|
|
for the global namespace. Work around this problem
|
|
here. */
|
|
name = nullptr;
|
|
}
|
|
|
|
cooked_index_entry *this_entry = nullptr;
|
|
if (name != nullptr)
|
|
{
|
|
if (defer != 0)
|
|
this_entry
|
|
= m_index_storage->add (this_die, abbrev->tag,
|
|
flags | IS_PARENT_DEFERRED, name,
|
|
defer, m_per_cu);
|
|
else
|
|
this_entry
|
|
= m_index_storage->add (this_die, abbrev->tag, flags, name,
|
|
this_parent_entry, m_per_cu);
|
|
}
|
|
|
|
if (linkage_name != nullptr)
|
|
{
|
|
/* We only want this to be "main" if it has a linkage name
|
|
but not an ordinary name. */
|
|
if (name != nullptr)
|
|
flags = flags & ~IS_MAIN;
|
|
/* Set the IS_LINKAGE on for everything except when functions
|
|
have linkage name present but name is absent. */
|
|
if (name != nullptr
|
|
|| (abbrev->tag != DW_TAG_subprogram
|
|
&& abbrev->tag != DW_TAG_inlined_subroutine
|
|
&& abbrev->tag != DW_TAG_entry_point))
|
|
flags = flags | IS_LINKAGE;
|
|
m_index_storage->add (this_die, abbrev->tag, flags,
|
|
linkage_name, nullptr, m_per_cu);
|
|
}
|
|
|
|
if (abbrev->has_children)
|
|
{
|
|
switch (abbrev->tag)
|
|
{
|
|
case DW_TAG_class_type:
|
|
case DW_TAG_interface_type:
|
|
case DW_TAG_structure_type:
|
|
case DW_TAG_union_type:
|
|
if (m_language != language_c && this_entry != nullptr)
|
|
{
|
|
info_ptr = recurse (reader, info_ptr, this_entry, fully);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case DW_TAG_enumeration_type:
|
|
/* Some versions of gdc could emit an "enum class"
|
|
without a name, which is nonsensical. These are
|
|
skipped. */
|
|
if (is_enum_class && this_entry == nullptr)
|
|
continue;
|
|
|
|
/* We need to recurse even for an anonymous enumeration.
|
|
Which scope we record as the parent scope depends on
|
|
whether we're reading an "enum class". If so, we use
|
|
the enum itself as the parent, yielding names like
|
|
"enum_class::enumerator"; otherwise we inject the
|
|
names into our own parent scope. */
|
|
{
|
|
std::variant<const cooked_index_entry *,
|
|
parent_map::addr_type> recurse_parent;
|
|
if (is_enum_class)
|
|
{
|
|
gdb_assert (this_entry != nullptr);
|
|
recurse_parent = this_entry;
|
|
}
|
|
else if (defer != 0)
|
|
recurse_parent = defer;
|
|
else
|
|
recurse_parent = this_parent_entry;
|
|
|
|
info_ptr = recurse (reader, info_ptr, recurse_parent, fully);
|
|
}
|
|
continue;
|
|
|
|
case DW_TAG_module:
|
|
if (this_entry == nullptr)
|
|
break;
|
|
[[fallthrough]];
|
|
case DW_TAG_namespace:
|
|
/* We don't check THIS_ENTRY for a namespace, to handle
|
|
the ancient G++ workaround pointed out above. */
|
|
info_ptr = recurse (reader, info_ptr, this_entry, fully);
|
|
continue;
|
|
|
|
case DW_TAG_subprogram:
|
|
if ((m_language == language_fortran
|
|
|| m_language == language_ada)
|
|
&& this_entry != nullptr)
|
|
{
|
|
info_ptr = recurse (reader, info_ptr, this_entry, true);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (sibling != sect_offset (0))
|
|
{
|
|
const gdb_byte *sibling_ptr
|
|
= reader->buffer + to_underlying (sibling);
|
|
|
|
if (sibling_ptr < info_ptr)
|
|
complaint (_("DW_AT_sibling points backwards"));
|
|
else if (sibling_ptr > reader->buffer_end)
|
|
reader->die_section->overflow_complaint ();
|
|
else
|
|
info_ptr = sibling_ptr;
|
|
}
|
|
else
|
|
info_ptr = skip_children (reader, info_ptr);
|
|
}
|
|
}
|
|
|
|
return info_ptr;
|
|
}
|
|
|
|
void
|
|
cooked_indexer::make_index (cutu_reader *reader)
|
|
{
|
|
check_bounds (reader);
|
|
find_file_and_directory (reader->comp_unit_die, reader->cu);
|
|
if (!reader->comp_unit_die->has_children)
|
|
return;
|
|
index_dies (reader, reader->info_ptr, nullptr, false);
|
|
}
|
|
|
|
struct compunit_symtab *
|
|
cooked_index_functions::find_compunit_symtab_by_address
|
|
(struct objfile *objfile, CORE_ADDR address)
|
|
{
|
|
if (objfile->sect_index_data == -1)
|
|
return nullptr;
|
|
|
|
dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
|
|
cooked_index *table = wait (objfile, true);
|
|
|
|
CORE_ADDR baseaddr = objfile->data_section_offset ();
|
|
dwarf2_per_cu_data *per_cu
|
|
= table->lookup ((unrelocated_addr) (address - baseaddr));
|
|
if (per_cu == nullptr)
|
|
return nullptr;
|
|
|
|
return dw2_instantiate_symtab (per_cu, per_objfile, false);
|
|
}
|
|
|
|
bool
|
|
cooked_index_functions::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,
|
|
gdb::function_view<expand_symtabs_lang_matcher_ftype> lang_matcher)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
|
|
|
|
cooked_index *table = wait (objfile, true);
|
|
|
|
dw_expand_symtabs_matching_file_matcher (per_objfile, file_matcher);
|
|
|
|
/* This invariant is documented in quick-functions.h. */
|
|
gdb_assert (lookup_name != nullptr || symbol_matcher == nullptr);
|
|
if (lookup_name == nullptr)
|
|
{
|
|
for (dwarf2_per_cu_data *per_cu
|
|
: all_units_range (per_objfile->per_bfd))
|
|
{
|
|
QUIT;
|
|
|
|
if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile,
|
|
file_matcher,
|
|
expansion_notify,
|
|
lang_matcher))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
lookup_name_info lookup_name_without_params
|
|
= lookup_name->make_ignore_params ();
|
|
bool completing = lookup_name->completion_mode ();
|
|
|
|
/* Unique styles of language splitting. */
|
|
static const enum language unique_styles[] =
|
|
{
|
|
/* No splitting is also a style. */
|
|
language_c,
|
|
/* This includes Rust. */
|
|
language_cplus,
|
|
/* This includes Go. */
|
|
language_d,
|
|
language_ada
|
|
};
|
|
|
|
symbol_name_match_type match_type
|
|
= lookup_name_without_params.match_type ();
|
|
|
|
std::bitset<nr_languages> unique_styles_used;
|
|
if (lang_matcher != nullptr)
|
|
for (unsigned iter = 0; iter < nr_languages; ++iter)
|
|
{
|
|
enum language lang = (enum language) iter;
|
|
if (!lang_matcher (lang))
|
|
continue;
|
|
|
|
switch (strip_cplus_dialect (lang))
|
|
{
|
|
case language_cplus:
|
|
case language_rust:
|
|
unique_styles_used[language_cplus] = true;
|
|
break;
|
|
case language_d:
|
|
case language_go:
|
|
unique_styles_used[language_d] = true;
|
|
break;
|
|
case language_ada:
|
|
unique_styles_used[language_ada] = true;
|
|
break;
|
|
default:
|
|
unique_styles_used[language_c] = true;
|
|
}
|
|
|
|
if (unique_styles_used.count ()
|
|
== sizeof (unique_styles) / sizeof (unique_styles[0]))
|
|
break;
|
|
}
|
|
|
|
for (enum language lang : unique_styles)
|
|
{
|
|
if (lang_matcher != nullptr
|
|
&& !unique_styles_used.test (lang))
|
|
continue;
|
|
|
|
std::vector<std::string_view> name_vec
|
|
= lookup_name_without_params.split_name (lang);
|
|
std::vector<std::string> name_str_vec (name_vec.begin (), name_vec.end ());
|
|
std::vector<lookup_name_info> segment_lookup_names;
|
|
segment_lookup_names.reserve (name_vec.size ());
|
|
for (auto &segment_name : name_str_vec)
|
|
{
|
|
segment_lookup_names.emplace_back (segment_name,
|
|
symbol_name_match_type::FULL, completing, true);
|
|
}
|
|
|
|
for (const cooked_index_entry *entry : table->find (name_str_vec.back (),
|
|
completing))
|
|
{
|
|
QUIT;
|
|
|
|
/* No need to consider symbols from expanded CUs. */
|
|
if (per_objfile->symtab_set_p (entry->per_cu))
|
|
continue;
|
|
|
|
/* If file-matching was done, we don't need to consider
|
|
symbols from unmarked CUs. */
|
|
if (file_matcher != nullptr && !entry->per_cu->mark)
|
|
continue;
|
|
|
|
/* See if the symbol matches the type filter. */
|
|
if (!entry->matches (search_flags)
|
|
|| !entry->matches (domain))
|
|
continue;
|
|
|
|
if (lang_matcher != nullptr)
|
|
{
|
|
/* Try to skip CUs with non-matching language. */
|
|
entry->per_cu->ensure_lang (per_objfile);
|
|
if (!entry->per_cu->maybe_multi_language ()
|
|
&& !lang_matcher (entry->per_cu->lang ()))
|
|
continue;
|
|
}
|
|
|
|
/* We've found the base name of the symbol; now walk its
|
|
parentage chain, ensuring that each component
|
|
matches. */
|
|
bool found = true;
|
|
|
|
const cooked_index_entry *parent = entry->get_parent ();
|
|
for (int i = name_vec.size () - 1; i > 0; --i)
|
|
{
|
|
/* If we ran out of entries, or if this segment doesn't
|
|
match, this did not match. */
|
|
if (parent == nullptr)
|
|
{
|
|
found = false;
|
|
break;
|
|
}
|
|
if (parent->lang != language_unknown)
|
|
{
|
|
const language_defn *lang_def = language_def (parent->lang);
|
|
symbol_name_matcher_ftype *name_matcher
|
|
= lang_def->get_symbol_name_matcher
|
|
(segment_lookup_names[i-1]);
|
|
if (!name_matcher (parent->canonical,
|
|
segment_lookup_names[i-1], nullptr))
|
|
{
|
|
found = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
parent = parent->get_parent ();
|
|
}
|
|
|
|
if (!found)
|
|
continue;
|
|
|
|
/* Might have been looking for "a::b" and found
|
|
"x::a::b". */
|
|
if (symbol_matcher == nullptr)
|
|
{
|
|
if ((match_type == symbol_name_match_type::FULL
|
|
|| (lang != language_ada
|
|
&& match_type == symbol_name_match_type::EXPRESSION)))
|
|
{
|
|
if (parent != nullptr)
|
|
continue;
|
|
|
|
if (entry->lang != language_unknown)
|
|
{
|
|
const language_defn *lang_def = language_def (entry->lang);
|
|
symbol_name_matcher_ftype *name_matcher
|
|
= lang_def->get_symbol_name_matcher
|
|
(segment_lookup_names.back ());
|
|
if (!name_matcher (entry->canonical,
|
|
segment_lookup_names.back (), nullptr))
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto_obstack temp_storage;
|
|
const char *full_name = entry->full_name (&temp_storage);
|
|
if (!symbol_matcher (full_name))
|
|
continue;
|
|
}
|
|
|
|
if (!dw2_expand_symtabs_matching_one (entry->per_cu, per_objfile,
|
|
file_matcher,
|
|
expansion_notify, nullptr))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Start reading .debug_info using the indexer. */
|
|
|
|
static void
|
|
start_debug_info_reader (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
/* Set the index table early so that sharing works even while
|
|
scanning; and then start the scanning. */
|
|
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
|
|
std::unique_ptr<cooked_index_worker> worker
|
|
(new cooked_index_debug_info (per_objfile));
|
|
cooked_index *idx = new cooked_index (per_objfile, std::move (worker));
|
|
per_bfd->index_table.reset (idx);
|
|
/* Don't start reading until after 'index_table' is set. This
|
|
avoids races. */
|
|
idx->start_reading ();
|
|
}
|
|
|
|
|
|
|
|
/* Read the .debug_loclists or .debug_rnglists header (they are the same format)
|
|
contents from the given SECTION in the HEADER.
|
|
|
|
HEADER_OFFSET is the offset of the header in the section. */
|
|
static void
|
|
read_loclists_rnglists_header (struct loclists_rnglists_header *header,
|
|
struct dwarf2_section_info *section,
|
|
sect_offset header_offset)
|
|
{
|
|
unsigned int bytes_read;
|
|
bfd *abfd = section->get_bfd_owner ();
|
|
const gdb_byte *info_ptr = section->buffer + to_underlying (header_offset);
|
|
|
|
header->length = read_initial_length (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
|
|
header->version = read_2_bytes (abfd, info_ptr);
|
|
info_ptr += 2;
|
|
|
|
header->addr_size = read_1_byte (abfd, info_ptr);
|
|
info_ptr += 1;
|
|
|
|
header->segment_collector_size = read_1_byte (abfd, info_ptr);
|
|
info_ptr += 1;
|
|
|
|
header->offset_entry_count = read_4_bytes (abfd, info_ptr);
|
|
}
|
|
|
|
/* Return the DW_AT_loclists_base value for the CU. */
|
|
static ULONGEST
|
|
lookup_loclist_base (struct dwarf2_cu *cu)
|
|
{
|
|
/* For the .dwo unit, the loclist_base points to the first offset following
|
|
the header. The header consists of the following entities-
|
|
1. Unit Length (4 bytes for 32 bit DWARF format, and 12 bytes for the 64
|
|
bit format)
|
|
2. version (2 bytes)
|
|
3. address size (1 byte)
|
|
4. segment selector size (1 byte)
|
|
5. offset entry count (4 bytes)
|
|
These sizes are derived as per the DWARFv5 standard. */
|
|
if (cu->dwo_unit != nullptr)
|
|
{
|
|
if (cu->header.initial_length_size == 4)
|
|
return LOCLIST_HEADER_SIZE32;
|
|
return LOCLIST_HEADER_SIZE64;
|
|
}
|
|
return cu->loclist_base;
|
|
}
|
|
|
|
/* Given a DW_FORM_loclistx value LOCLIST_INDEX, fetch the offset from the
|
|
array of offsets in the .debug_loclists section. */
|
|
|
|
static sect_offset
|
|
read_loclist_index (struct dwarf2_cu *cu, ULONGEST loclist_index)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
bfd *abfd = objfile->obfd.get ();
|
|
ULONGEST loclist_header_size =
|
|
(cu->header.initial_length_size == 4 ? LOCLIST_HEADER_SIZE32
|
|
: LOCLIST_HEADER_SIZE64);
|
|
ULONGEST loclist_base = lookup_loclist_base (cu);
|
|
|
|
/* Offset in .debug_loclists of the offset for LOCLIST_INDEX. */
|
|
ULONGEST start_offset =
|
|
loclist_base + loclist_index * cu->header.offset_size;
|
|
|
|
/* Get loclists section. */
|
|
struct dwarf2_section_info *section = cu_debug_loc_section (cu);
|
|
|
|
/* Read the loclists section content. */
|
|
section->read (objfile);
|
|
if (section->buffer == NULL)
|
|
error (_("DW_FORM_loclistx used without .debug_loclists "
|
|
"section [in module %s]"), objfile_name (objfile));
|
|
|
|
/* DW_AT_loclists_base points after the .debug_loclists contribution header,
|
|
so if loclist_base is smaller than the header size, we have a problem. */
|
|
if (loclist_base < loclist_header_size)
|
|
error (_("DW_AT_loclists_base is smaller than header size [in module %s]"),
|
|
objfile_name (objfile));
|
|
|
|
/* Read the header of the loclists contribution. */
|
|
struct loclists_rnglists_header header;
|
|
read_loclists_rnglists_header (&header, section,
|
|
(sect_offset) (loclist_base - loclist_header_size));
|
|
|
|
/* Verify the loclist index is valid. */
|
|
if (loclist_index >= header.offset_entry_count)
|
|
error (_("DW_FORM_loclistx pointing outside of "
|
|
".debug_loclists offset array [in module %s]"),
|
|
objfile_name (objfile));
|
|
|
|
/* Validate that reading won't go beyond the end of the section. */
|
|
if (start_offset + cu->header.offset_size > section->size)
|
|
error (_("Reading DW_FORM_loclistx index beyond end of"
|
|
".debug_loclists section [in module %s]"),
|
|
objfile_name (objfile));
|
|
|
|
const gdb_byte *info_ptr = section->buffer + start_offset;
|
|
|
|
if (cu->header.offset_size == 4)
|
|
return (sect_offset) (bfd_get_32 (abfd, info_ptr) + loclist_base);
|
|
else
|
|
return (sect_offset) (bfd_get_64 (abfd, info_ptr) + loclist_base);
|
|
}
|
|
|
|
/* Given a DW_FORM_rnglistx value RNGLIST_INDEX, fetch the offset from the
|
|
array of offsets in the .debug_rnglists section. */
|
|
|
|
static sect_offset
|
|
read_rnglist_index (struct dwarf2_cu *cu, ULONGEST rnglist_index,
|
|
dwarf_tag tag)
|
|
{
|
|
struct dwarf2_per_objfile *dwarf2_per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = dwarf2_per_objfile->objfile;
|
|
bfd *abfd = objfile->obfd.get ();
|
|
ULONGEST rnglist_header_size =
|
|
(cu->header.initial_length_size == 4 ? RNGLIST_HEADER_SIZE32
|
|
: RNGLIST_HEADER_SIZE64);
|
|
|
|
/* When reading a DW_FORM_rnglistx from a DWO, we read from the DWO's
|
|
.debug_rnglists.dwo section. The rnglists base given in the skeleton
|
|
doesn't apply. */
|
|
ULONGEST rnglist_base =
|
|
(cu->dwo_unit != nullptr) ? rnglist_header_size : cu->rnglists_base;
|
|
|
|
/* Offset in .debug_rnglists of the offset for RNGLIST_INDEX. */
|
|
ULONGEST start_offset =
|
|
rnglist_base + rnglist_index * cu->header.offset_size;
|
|
|
|
/* Get rnglists section. */
|
|
struct dwarf2_section_info *section = cu_debug_rnglists_section (cu, tag);
|
|
|
|
/* Read the rnglists section content. */
|
|
section->read (objfile);
|
|
if (section->buffer == nullptr)
|
|
error (_("DW_FORM_rnglistx used without .debug_rnglists section "
|
|
"[in module %s]"),
|
|
objfile_name (objfile));
|
|
|
|
/* DW_AT_rnglists_base points after the .debug_rnglists contribution header,
|
|
so if rnglist_base is smaller than the header size, we have a problem. */
|
|
if (rnglist_base < rnglist_header_size)
|
|
error (_("DW_AT_rnglists_base is smaller than header size [in module %s]"),
|
|
objfile_name (objfile));
|
|
|
|
/* Read the header of the rnglists contribution. */
|
|
struct loclists_rnglists_header header;
|
|
read_loclists_rnglists_header (&header, section,
|
|
(sect_offset) (rnglist_base - rnglist_header_size));
|
|
|
|
/* Verify the rnglist index is valid. */
|
|
if (rnglist_index >= header.offset_entry_count)
|
|
error (_("DW_FORM_rnglistx index pointing outside of "
|
|
".debug_rnglists offset array [in module %s]"),
|
|
objfile_name (objfile));
|
|
|
|
/* Validate that reading won't go beyond the end of the section. */
|
|
if (start_offset + cu->header.offset_size > section->size)
|
|
error (_("Reading DW_FORM_rnglistx index beyond end of"
|
|
".debug_rnglists section [in module %s]"),
|
|
objfile_name (objfile));
|
|
|
|
const gdb_byte *info_ptr = section->buffer + start_offset;
|
|
|
|
if (cu->header.offset_size == 4)
|
|
return (sect_offset) (read_4_bytes (abfd, info_ptr) + rnglist_base);
|
|
else
|
|
return (sect_offset) (read_8_bytes (abfd, info_ptr) + rnglist_base);
|
|
}
|
|
|
|
/* Process the attributes that had to be skipped in the first round. These
|
|
attributes are the ones that need str_offsets_base or addr_base attributes.
|
|
They could not have been processed in the first round, because at the time
|
|
the values of str_offsets_base or addr_base may not have been known. */
|
|
static void
|
|
read_attribute_reprocess (const struct die_reader_specs *reader,
|
|
struct attribute *attr, dwarf_tag tag)
|
|
{
|
|
struct dwarf2_cu *cu = reader->cu;
|
|
switch (attr->form)
|
|
{
|
|
case DW_FORM_addrx:
|
|
case DW_FORM_GNU_addr_index:
|
|
attr->set_address (read_addr_index (cu,
|
|
attr->as_unsigned_reprocess ()));
|
|
break;
|
|
case DW_FORM_loclistx:
|
|
{
|
|
sect_offset loclists_sect_off
|
|
= read_loclist_index (cu, attr->as_unsigned_reprocess ());
|
|
|
|
attr->set_unsigned (to_underlying (loclists_sect_off));
|
|
}
|
|
break;
|
|
case DW_FORM_rnglistx:
|
|
{
|
|
sect_offset rnglists_sect_off
|
|
= read_rnglist_index (cu, attr->as_unsigned_reprocess (), tag);
|
|
|
|
attr->set_unsigned (to_underlying (rnglists_sect_off));
|
|
}
|
|
break;
|
|
case DW_FORM_strx:
|
|
case DW_FORM_strx1:
|
|
case DW_FORM_strx2:
|
|
case DW_FORM_strx3:
|
|
case DW_FORM_strx4:
|
|
case DW_FORM_GNU_str_index:
|
|
{
|
|
unsigned int str_index = attr->as_unsigned_reprocess ();
|
|
gdb_assert (!attr->canonical_string_p ());
|
|
if (reader->dwo_file != NULL)
|
|
attr->set_string_noncanonical (read_dwo_str_index (reader,
|
|
str_index));
|
|
else
|
|
attr->set_string_noncanonical (read_stub_str_index (cu,
|
|
str_index));
|
|
break;
|
|
}
|
|
default:
|
|
gdb_assert_not_reached ("Unexpected DWARF form.");
|
|
}
|
|
}
|
|
|
|
/* Read an attribute value described by an attribute form. */
|
|
|
|
static const gdb_byte *
|
|
read_attribute_value (const struct die_reader_specs *reader,
|
|
struct attribute *attr, unsigned form,
|
|
LONGEST implicit_const, const gdb_byte *info_ptr,
|
|
bool allow_reprocess)
|
|
{
|
|
struct dwarf2_cu *cu = reader->cu;
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
bfd *abfd = reader->abfd;
|
|
struct comp_unit_head *cu_header = &cu->header;
|
|
unsigned int bytes_read;
|
|
struct dwarf_block *blk;
|
|
|
|
attr->form = (enum dwarf_form) form;
|
|
switch (form)
|
|
{
|
|
case DW_FORM_ref_addr:
|
|
if (cu_header->version == 2)
|
|
attr->set_unsigned ((ULONGEST) cu_header->read_address (abfd, info_ptr,
|
|
&bytes_read));
|
|
else
|
|
attr->set_unsigned (cu_header->read_offset (abfd, info_ptr,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_GNU_ref_alt:
|
|
attr->set_unsigned (cu_header->read_offset (abfd, info_ptr,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_addr:
|
|
{
|
|
unrelocated_addr addr = cu_header->read_address (abfd, info_ptr,
|
|
&bytes_read);
|
|
attr->set_address (addr);
|
|
info_ptr += bytes_read;
|
|
}
|
|
break;
|
|
case DW_FORM_block2:
|
|
blk = dwarf_alloc_block (cu);
|
|
blk->size = read_2_bytes (abfd, info_ptr);
|
|
info_ptr += 2;
|
|
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
|
|
info_ptr += blk->size;
|
|
attr->set_block (blk);
|
|
break;
|
|
case DW_FORM_block4:
|
|
blk = dwarf_alloc_block (cu);
|
|
blk->size = read_4_bytes (abfd, info_ptr);
|
|
info_ptr += 4;
|
|
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
|
|
info_ptr += blk->size;
|
|
attr->set_block (blk);
|
|
break;
|
|
case DW_FORM_data2:
|
|
attr->set_unsigned (read_2_bytes (abfd, info_ptr));
|
|
info_ptr += 2;
|
|
break;
|
|
case DW_FORM_data4:
|
|
attr->set_unsigned (read_4_bytes (abfd, info_ptr));
|
|
info_ptr += 4;
|
|
break;
|
|
case DW_FORM_data8:
|
|
attr->set_unsigned (read_8_bytes (abfd, info_ptr));
|
|
info_ptr += 8;
|
|
break;
|
|
case DW_FORM_data16:
|
|
blk = dwarf_alloc_block (cu);
|
|
blk->size = 16;
|
|
blk->data = read_n_bytes (abfd, info_ptr, 16);
|
|
info_ptr += 16;
|
|
attr->set_block (blk);
|
|
break;
|
|
case DW_FORM_sec_offset:
|
|
attr->set_unsigned (cu_header->read_offset (abfd, info_ptr,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_loclistx:
|
|
{
|
|
attr->set_unsigned_reprocess (read_unsigned_leb128 (abfd, info_ptr,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
if (allow_reprocess)
|
|
read_attribute_reprocess (reader, attr);
|
|
}
|
|
break;
|
|
case DW_FORM_string:
|
|
attr->set_string_noncanonical (read_direct_string (abfd, info_ptr,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_strp:
|
|
if (!cu->per_cu->is_dwz)
|
|
{
|
|
attr->set_string_noncanonical
|
|
(read_indirect_string (per_objfile,
|
|
abfd, info_ptr, cu_header,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
}
|
|
[[fallthrough]];
|
|
case DW_FORM_line_strp:
|
|
if (!cu->per_cu->is_dwz)
|
|
{
|
|
attr->set_string_noncanonical
|
|
(per_objfile->read_line_string (info_ptr, cu_header,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
}
|
|
[[fallthrough]];
|
|
case DW_FORM_GNU_strp_alt:
|
|
{
|
|
dwz_file *dwz = dwarf2_get_dwz_file (per_objfile->per_bfd, true);
|
|
LONGEST str_offset = cu_header->read_offset (abfd, info_ptr,
|
|
&bytes_read);
|
|
|
|
attr->set_string_noncanonical
|
|
(dwz->read_string (objfile, str_offset));
|
|
info_ptr += bytes_read;
|
|
}
|
|
break;
|
|
case DW_FORM_exprloc:
|
|
case DW_FORM_block:
|
|
blk = dwarf_alloc_block (cu);
|
|
blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
|
|
info_ptr += blk->size;
|
|
attr->set_block (blk);
|
|
break;
|
|
case DW_FORM_block1:
|
|
blk = dwarf_alloc_block (cu);
|
|
blk->size = read_1_byte (abfd, info_ptr);
|
|
info_ptr += 1;
|
|
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
|
|
info_ptr += blk->size;
|
|
attr->set_block (blk);
|
|
break;
|
|
case DW_FORM_data1:
|
|
case DW_FORM_flag:
|
|
attr->set_unsigned (read_1_byte (abfd, info_ptr));
|
|
info_ptr += 1;
|
|
break;
|
|
case DW_FORM_flag_present:
|
|
attr->set_unsigned (1);
|
|
break;
|
|
case DW_FORM_sdata:
|
|
attr->set_signed (read_signed_leb128 (abfd, info_ptr, &bytes_read));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_rnglistx:
|
|
{
|
|
attr->set_unsigned_reprocess (read_unsigned_leb128 (abfd, info_ptr,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
if (allow_reprocess)
|
|
read_attribute_reprocess (reader, attr);
|
|
}
|
|
break;
|
|
case DW_FORM_udata:
|
|
attr->set_unsigned (read_unsigned_leb128 (abfd, info_ptr, &bytes_read));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_ref1:
|
|
attr->set_unsigned ((to_underlying (cu_header->sect_off)
|
|
+ read_1_byte (abfd, info_ptr)));
|
|
info_ptr += 1;
|
|
break;
|
|
case DW_FORM_ref2:
|
|
attr->set_unsigned ((to_underlying (cu_header->sect_off)
|
|
+ read_2_bytes (abfd, info_ptr)));
|
|
info_ptr += 2;
|
|
break;
|
|
case DW_FORM_ref4:
|
|
attr->set_unsigned ((to_underlying (cu_header->sect_off)
|
|
+ read_4_bytes (abfd, info_ptr)));
|
|
info_ptr += 4;
|
|
break;
|
|
case DW_FORM_ref8:
|
|
attr->set_unsigned ((to_underlying (cu_header->sect_off)
|
|
+ read_8_bytes (abfd, info_ptr)));
|
|
info_ptr += 8;
|
|
break;
|
|
case DW_FORM_ref_sig8:
|
|
attr->set_signature (read_8_bytes (abfd, info_ptr));
|
|
info_ptr += 8;
|
|
break;
|
|
case DW_FORM_ref_udata:
|
|
attr->set_unsigned ((to_underlying (cu_header->sect_off)
|
|
+ read_unsigned_leb128 (abfd, info_ptr,
|
|
&bytes_read)));
|
|
info_ptr += bytes_read;
|
|
break;
|
|
case DW_FORM_indirect:
|
|
form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
if (form == DW_FORM_implicit_const)
|
|
{
|
|
implicit_const = read_signed_leb128 (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
}
|
|
info_ptr = read_attribute_value (reader, attr, form, implicit_const,
|
|
info_ptr, allow_reprocess);
|
|
break;
|
|
case DW_FORM_implicit_const:
|
|
attr->set_signed (implicit_const);
|
|
break;
|
|
case DW_FORM_addrx:
|
|
case DW_FORM_GNU_addr_index:
|
|
attr->set_unsigned_reprocess (read_unsigned_leb128 (abfd, info_ptr,
|
|
&bytes_read));
|
|
info_ptr += bytes_read;
|
|
if (allow_reprocess)
|
|
read_attribute_reprocess (reader, attr);
|
|
break;
|
|
case DW_FORM_strx:
|
|
case DW_FORM_strx1:
|
|
case DW_FORM_strx2:
|
|
case DW_FORM_strx3:
|
|
case DW_FORM_strx4:
|
|
case DW_FORM_GNU_str_index:
|
|
{
|
|
ULONGEST str_index;
|
|
if (form == DW_FORM_strx1)
|
|
{
|
|
str_index = read_1_byte (abfd, info_ptr);
|
|
info_ptr += 1;
|
|
}
|
|
else if (form == DW_FORM_strx2)
|
|
{
|
|
str_index = read_2_bytes (abfd, info_ptr);
|
|
info_ptr += 2;
|
|
}
|
|
else if (form == DW_FORM_strx3)
|
|
{
|
|
str_index = read_3_bytes (abfd, info_ptr);
|
|
info_ptr += 3;
|
|
}
|
|
else if (form == DW_FORM_strx4)
|
|
{
|
|
str_index = read_4_bytes (abfd, info_ptr);
|
|
info_ptr += 4;
|
|
}
|
|
else
|
|
{
|
|
str_index = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
|
|
info_ptr += bytes_read;
|
|
}
|
|
attr->set_unsigned_reprocess (str_index);
|
|
if (allow_reprocess)
|
|
read_attribute_reprocess (reader, attr);
|
|
}
|
|
break;
|
|
default:
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Cannot handle %s in DWARF reader [in module %s]"),
|
|
dwarf_form_name (form),
|
|
bfd_get_filename (abfd));
|
|
}
|
|
|
|
/* Super hack. */
|
|
if (cu->per_cu->is_dwz && attr->form_is_ref ())
|
|
attr->form = DW_FORM_GNU_ref_alt;
|
|
|
|
/* We have seen instances where the compiler tried to emit a byte
|
|
size attribute of -1 which ended up being encoded as an unsigned
|
|
0xffffffff. Although 0xffffffff is technically a valid size value,
|
|
an object of this size seems pretty unlikely so we can relatively
|
|
safely treat these cases as if the size attribute was invalid and
|
|
treat them as zero by default. */
|
|
if (attr->name == DW_AT_byte_size
|
|
&& form == DW_FORM_data4
|
|
&& attr->as_unsigned () >= 0xffffffff)
|
|
{
|
|
complaint
|
|
(_("Suspicious DW_AT_byte_size value treated as zero instead of %s"),
|
|
hex_string (attr->as_unsigned ()));
|
|
attr->set_unsigned (0);
|
|
}
|
|
|
|
return info_ptr;
|
|
}
|
|
|
|
/* Read an attribute described by an abbreviated attribute. */
|
|
|
|
static const gdb_byte *
|
|
read_attribute (const struct die_reader_specs *reader,
|
|
struct attribute *attr, const struct attr_abbrev *abbrev,
|
|
const gdb_byte *info_ptr,
|
|
bool allow_reprocess)
|
|
{
|
|
attr->name = abbrev->name;
|
|
attr->string_is_canonical = 0;
|
|
return read_attribute_value (reader, attr, abbrev->form,
|
|
abbrev->implicit_const, info_ptr,
|
|
allow_reprocess);
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
const char *
|
|
read_indirect_string_at_offset (dwarf2_per_objfile *per_objfile,
|
|
LONGEST str_offset)
|
|
{
|
|
return per_objfile->per_bfd->str.read_string (per_objfile->objfile,
|
|
str_offset, "DW_FORM_strp");
|
|
}
|
|
|
|
/* Return pointer to string at .debug_str offset as read from BUF.
|
|
BUF is assumed to be in a compilation unit described by CU_HEADER.
|
|
Return *BYTES_READ_PTR count of bytes read from BUF. */
|
|
|
|
static const char *
|
|
read_indirect_string (dwarf2_per_objfile *per_objfile, bfd *abfd,
|
|
const gdb_byte *buf,
|
|
const struct comp_unit_head *cu_header,
|
|
unsigned int *bytes_read_ptr)
|
|
{
|
|
LONGEST str_offset = cu_header->read_offset (abfd, buf, bytes_read_ptr);
|
|
|
|
return read_indirect_string_at_offset (per_objfile, str_offset);
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
const char *
|
|
dwarf2_per_objfile::read_line_string (const gdb_byte *buf,
|
|
unsigned int offset_size)
|
|
{
|
|
bfd *abfd = objfile->obfd.get ();
|
|
ULONGEST str_offset = read_offset (abfd, buf, offset_size);
|
|
|
|
return per_bfd->line_str.read_string (objfile, str_offset, "DW_FORM_line_strp");
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
const char *
|
|
dwarf2_per_objfile::read_line_string (const gdb_byte *buf,
|
|
const struct comp_unit_head *cu_header,
|
|
unsigned int *bytes_read_ptr)
|
|
{
|
|
bfd *abfd = objfile->obfd.get ();
|
|
LONGEST str_offset = cu_header->read_offset (abfd, buf, bytes_read_ptr);
|
|
|
|
return per_bfd->line_str.read_string (objfile, str_offset, "DW_FORM_line_strp");
|
|
}
|
|
|
|
/* Given index ADDR_INDEX in .debug_addr, fetch the value.
|
|
ADDR_BASE is the DW_AT_addr_base (DW_AT_GNU_addr_base) attribute or zero.
|
|
ADDR_SIZE is the size of addresses from the CU header. */
|
|
|
|
static unrelocated_addr
|
|
read_addr_index_1 (dwarf2_per_objfile *per_objfile, unsigned int addr_index,
|
|
std::optional<ULONGEST> addr_base, int addr_size)
|
|
{
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
bfd *abfd = objfile->obfd.get ();
|
|
const gdb_byte *info_ptr;
|
|
ULONGEST addr_base_or_zero = addr_base.has_value () ? *addr_base : 0;
|
|
|
|
per_objfile->per_bfd->addr.read (objfile);
|
|
if (per_objfile->per_bfd->addr.buffer == NULL)
|
|
error (_("DW_FORM_addr_index used without .debug_addr section [in module %s]"),
|
|
objfile_name (objfile));
|
|
if (addr_base_or_zero + addr_index * addr_size
|
|
>= per_objfile->per_bfd->addr.size)
|
|
error (_("DW_FORM_addr_index pointing outside of "
|
|
".debug_addr section [in module %s]"),
|
|
objfile_name (objfile));
|
|
info_ptr = (per_objfile->per_bfd->addr.buffer + addr_base_or_zero
|
|
+ addr_index * addr_size);
|
|
if (addr_size == 4)
|
|
return (unrelocated_addr) bfd_get_32 (abfd, info_ptr);
|
|
else
|
|
return (unrelocated_addr) bfd_get_64 (abfd, info_ptr);
|
|
}
|
|
|
|
/* Given index ADDR_INDEX in .debug_addr, fetch the value. */
|
|
|
|
static unrelocated_addr
|
|
read_addr_index (struct dwarf2_cu *cu, unsigned int addr_index)
|
|
{
|
|
return read_addr_index_1 (cu->per_objfile, addr_index,
|
|
cu->addr_base, cu->header.addr_size);
|
|
}
|
|
|
|
/* Given a pointer to an leb128 value, fetch the value from .debug_addr. */
|
|
|
|
static unrelocated_addr
|
|
read_addr_index_from_leb128 (struct dwarf2_cu *cu, const gdb_byte *info_ptr,
|
|
unsigned int *bytes_read)
|
|
{
|
|
bfd *abfd = cu->per_objfile->objfile->obfd.get ();
|
|
unsigned int addr_index = read_unsigned_leb128 (abfd, info_ptr, bytes_read);
|
|
|
|
return read_addr_index (cu, addr_index);
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
unrelocated_addr
|
|
dwarf2_read_addr_index (dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
unsigned int addr_index)
|
|
{
|
|
struct dwarf2_cu *cu = per_objfile->get_cu (per_cu);
|
|
std::optional<ULONGEST> addr_base;
|
|
int addr_size;
|
|
|
|
/* We need addr_base and addr_size.
|
|
If we don't have PER_CU->cu, we have to get it.
|
|
Nasty, but the alternative is storing the needed info in PER_CU,
|
|
which at this point doesn't seem justified: it's not clear how frequently
|
|
it would get used and it would increase the size of every PER_CU.
|
|
Entry points like dwarf2_per_cu_addr_size do a similar thing
|
|
so we're not in uncharted territory here.
|
|
Alas we need to be a bit more complicated as addr_base is contained
|
|
in the DIE.
|
|
|
|
We don't need to read the entire CU(/TU).
|
|
We just need the header and top level die.
|
|
|
|
IWBN to use the aging mechanism to let us lazily later discard the CU.
|
|
For now we skip this optimization. */
|
|
|
|
if (cu != NULL)
|
|
{
|
|
addr_base = cu->addr_base;
|
|
addr_size = cu->header.addr_size;
|
|
}
|
|
else
|
|
{
|
|
cutu_reader reader (per_cu, per_objfile, nullptr, nullptr, false);
|
|
addr_base = reader.cu->addr_base;
|
|
addr_size = reader.cu->header.addr_size;
|
|
}
|
|
|
|
return read_addr_index_1 (per_objfile, addr_index, addr_base, addr_size);
|
|
}
|
|
|
|
/* Given a DW_FORM_GNU_str_index value STR_INDEX, fetch the string.
|
|
STR_SECTION, STR_OFFSETS_SECTION can be from a Fission stub or a
|
|
DWO file. */
|
|
|
|
static const char *
|
|
read_str_index (struct dwarf2_cu *cu,
|
|
struct dwarf2_section_info *str_section,
|
|
struct dwarf2_section_info *str_offsets_section,
|
|
ULONGEST str_offsets_base, ULONGEST str_index,
|
|
unsigned offset_size)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
const char *objf_name = objfile_name (objfile);
|
|
bfd *abfd = objfile->obfd.get ();
|
|
const gdb_byte *info_ptr;
|
|
ULONGEST str_offset;
|
|
static const char form_name[] = "DW_FORM_GNU_str_index or DW_FORM_strx";
|
|
|
|
str_section->read (objfile);
|
|
str_offsets_section->read (objfile);
|
|
if (str_section->buffer == NULL)
|
|
error (_("%s used without %s section"
|
|
" in CU at offset %s [in module %s]"),
|
|
form_name, str_section->get_name (),
|
|
sect_offset_str (cu->header.sect_off), objf_name);
|
|
if (str_offsets_section->buffer == NULL)
|
|
error (_("%s used without %s section"
|
|
" in CU at offset %s [in module %s]"),
|
|
form_name, str_section->get_name (),
|
|
sect_offset_str (cu->header.sect_off), objf_name);
|
|
info_ptr = (str_offsets_section->buffer
|
|
+ str_offsets_base
|
|
+ str_index * offset_size);
|
|
if (offset_size == 4)
|
|
str_offset = bfd_get_32 (abfd, info_ptr);
|
|
else
|
|
str_offset = bfd_get_64 (abfd, info_ptr);
|
|
if (str_offset >= str_section->size)
|
|
error (_("Offset from %s pointing outside of"
|
|
" %s section in CU at offset %s [in module %s]"),
|
|
form_name, str_section->get_name (),
|
|
sect_offset_str (cu->header.sect_off), objf_name);
|
|
return (const char *) (str_section->buffer + str_offset);
|
|
}
|
|
|
|
/* Given a DW_FORM_GNU_str_index from a DWO file, fetch the string. */
|
|
|
|
static const char *
|
|
read_dwo_str_index (const struct die_reader_specs *reader, ULONGEST str_index)
|
|
{
|
|
unsigned offset_size;
|
|
ULONGEST str_offsets_base;
|
|
if (reader->cu->header.version >= 5)
|
|
{
|
|
/* We have a DWARF5 CU with a reference to a .debug_str_offsets section,
|
|
so assume the .debug_str_offsets section is DWARF5 as well, and
|
|
parse the header. FIXME: Parse the header only once. */
|
|
unsigned int bytes_read = 0;
|
|
bfd *abfd = reader->dwo_file->sections.str_offsets.get_bfd_owner ();
|
|
const gdb_byte *p = reader->dwo_file->sections.str_offsets.buffer;
|
|
|
|
/* Header: Initial length. */
|
|
read_initial_length (abfd, p + bytes_read, &bytes_read);
|
|
|
|
/* Determine offset_size based on the .debug_str_offsets header. */
|
|
const bool dwarf5_is_dwarf64 = bytes_read != 4;
|
|
offset_size = dwarf5_is_dwarf64 ? 8 : 4;
|
|
|
|
/* Header: Version. */
|
|
unsigned version = read_2_bytes (abfd, p + bytes_read);
|
|
bytes_read += 2;
|
|
|
|
if (version <= 4)
|
|
{
|
|
/* We'd like one warning here about ignoring the section, but
|
|
because we parse the header more than once (see FIXME above)
|
|
we'd have many warnings, so use a complaint instead, which at
|
|
least has a limit. */
|
|
complaint (_("Section .debug_str_offsets in %s has unsupported"
|
|
" version %d, use empty string."),
|
|
reader->dwo_file->dwo_name.c_str (), version);
|
|
return "";
|
|
}
|
|
|
|
/* Header: Padding. */
|
|
bytes_read += 2;
|
|
|
|
str_offsets_base = bytes_read;
|
|
}
|
|
else
|
|
{
|
|
/* We have a pre-DWARF5 CU with a reference to a .debug_str_offsets
|
|
section, assume the .debug_str_offsets section is pre-DWARF5 as
|
|
well, which doesn't have a header. */
|
|
str_offsets_base = 0;
|
|
|
|
/* Determine offset_size based on the .debug_info header. */
|
|
offset_size = reader->cu->header.offset_size;
|
|
}
|
|
|
|
return read_str_index (reader->cu,
|
|
&reader->dwo_file->sections.str,
|
|
&reader->dwo_file->sections.str_offsets,
|
|
str_offsets_base, str_index, offset_size);
|
|
}
|
|
|
|
/* Given a DW_FORM_GNU_str_index from a Fission stub, fetch the string. */
|
|
|
|
static const char *
|
|
read_stub_str_index (struct dwarf2_cu *cu, ULONGEST str_index)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
const char *objf_name = objfile_name (objfile);
|
|
static const char form_name[] = "DW_FORM_GNU_str_index";
|
|
static const char str_offsets_attr_name[] = "DW_AT_str_offsets";
|
|
|
|
if (!cu->str_offsets_base.has_value ())
|
|
error (_("%s used in Fission stub without %s"
|
|
" in CU at offset 0x%lx [in module %s]"),
|
|
form_name, str_offsets_attr_name,
|
|
(long) cu->header.offset_size, objf_name);
|
|
|
|
return read_str_index (cu,
|
|
&cu->per_objfile->per_bfd->str,
|
|
&cu->per_objfile->per_bfd->str_offsets,
|
|
*cu->str_offsets_base, str_index,
|
|
cu->header.offset_size);
|
|
}
|
|
|
|
/* Return the length of an LEB128 number in BUF. */
|
|
|
|
static int
|
|
leb128_size (const gdb_byte *buf)
|
|
{
|
|
const gdb_byte *begin = buf;
|
|
gdb_byte byte;
|
|
|
|
while (1)
|
|
{
|
|
byte = *buf++;
|
|
if ((byte & 128) == 0)
|
|
return buf - begin;
|
|
}
|
|
}
|
|
|
|
/* Converts DWARF language names to GDB language names. */
|
|
|
|
enum language
|
|
dwarf_lang_to_enum_language (unsigned int lang)
|
|
{
|
|
enum language language;
|
|
|
|
switch (lang)
|
|
{
|
|
case DW_LANG_C89:
|
|
case DW_LANG_C99:
|
|
case DW_LANG_C11:
|
|
case DW_LANG_C17:
|
|
case DW_LANG_C23:
|
|
case DW_LANG_C:
|
|
case DW_LANG_UPC:
|
|
language = language_c;
|
|
break;
|
|
case DW_LANG_Java:
|
|
case DW_LANG_C_plus_plus:
|
|
case DW_LANG_C_plus_plus_11:
|
|
case DW_LANG_C_plus_plus_14:
|
|
case DW_LANG_C_plus_plus_17:
|
|
case DW_LANG_C_plus_plus_20:
|
|
case DW_LANG_C_plus_plus_23:
|
|
language = language_cplus;
|
|
break;
|
|
case DW_LANG_D:
|
|
language = language_d;
|
|
break;
|
|
case DW_LANG_Fortran77:
|
|
case DW_LANG_Fortran90:
|
|
case DW_LANG_Fortran95:
|
|
case DW_LANG_Fortran03:
|
|
case DW_LANG_Fortran08:
|
|
case DW_LANG_Fortran18:
|
|
case DW_LANG_Fortran23:
|
|
language = language_fortran;
|
|
break;
|
|
case DW_LANG_Go:
|
|
language = language_go;
|
|
break;
|
|
case DW_LANG_Assembly:
|
|
case DW_LANG_Mips_Assembler:
|
|
language = language_asm;
|
|
break;
|
|
case DW_LANG_Ada83:
|
|
case DW_LANG_Ada95:
|
|
case DW_LANG_Ada2005:
|
|
case DW_LANG_Ada2012:
|
|
language = language_ada;
|
|
break;
|
|
case DW_LANG_Modula2:
|
|
language = language_m2;
|
|
break;
|
|
case DW_LANG_Pascal83:
|
|
language = language_pascal;
|
|
break;
|
|
case DW_LANG_ObjC:
|
|
language = language_objc;
|
|
break;
|
|
case DW_LANG_Rust:
|
|
case DW_LANG_Rust_old:
|
|
language = language_rust;
|
|
break;
|
|
case DW_LANG_OpenCL:
|
|
language = language_opencl;
|
|
break;
|
|
case DW_LANG_HIP:
|
|
language = language_hip;
|
|
break;
|
|
case DW_LANG_Cobol74:
|
|
case DW_LANG_Cobol85:
|
|
default:
|
|
language = language_minimal;
|
|
break;
|
|
}
|
|
|
|
return language;
|
|
}
|
|
|
|
/* Return the NAME attribute of DIE in *CU, or return NULL if not there. Also
|
|
return in *CU the cu in which the attribute was actually found. */
|
|
|
|
static struct attribute *
|
|
dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu **cu)
|
|
{
|
|
for (;;)
|
|
{
|
|
unsigned int i;
|
|
struct attribute *spec = NULL;
|
|
|
|
for (i = 0; i < die->num_attrs; ++i)
|
|
{
|
|
if (die->attrs[i].name == name)
|
|
return &die->attrs[i];
|
|
if (die->attrs[i].name == DW_AT_specification
|
|
|| die->attrs[i].name == DW_AT_abstract_origin)
|
|
spec = &die->attrs[i];
|
|
}
|
|
|
|
if (!spec)
|
|
break;
|
|
|
|
struct die_info *prev_die = die;
|
|
die = follow_die_ref (die, spec, cu);
|
|
if (die == prev_die)
|
|
/* Self-reference, we're done. */
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Return the NAME attribute of DIE in CU, or return NULL if not there. */
|
|
|
|
static struct attribute *
|
|
dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu)
|
|
{
|
|
return dwarf2_attr (die, name, &cu);
|
|
}
|
|
|
|
/* Return the string associated with a string-typed attribute, or NULL if it
|
|
is either not found or is of an incorrect type. */
|
|
|
|
static const char *
|
|
dwarf2_string_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
const char *str = NULL;
|
|
|
|
attr = dwarf2_attr (die, name, cu);
|
|
|
|
if (attr != NULL)
|
|
{
|
|
str = attr->as_string ();
|
|
if (str == nullptr)
|
|
complaint (_("string type expected for attribute %s for "
|
|
"DIE at %s [in module %s]"),
|
|
dwarf_attr_name (name), sect_offset_str (die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
/* Return the dwo name or NULL if not present. If present, it is in either
|
|
DW_AT_GNU_dwo_name or DW_AT_dwo_name attribute. */
|
|
static const char *
|
|
dwarf2_dwo_name (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
const char *dwo_name = dwarf2_string_attr (die, DW_AT_GNU_dwo_name, cu);
|
|
if (dwo_name == nullptr)
|
|
dwo_name = dwarf2_string_attr (die, DW_AT_dwo_name, cu);
|
|
return dwo_name;
|
|
}
|
|
|
|
/* Return non-zero iff the attribute NAME is defined for the given DIE,
|
|
and holds a non-zero value. This function should only be used for
|
|
DW_FORM_flag or DW_FORM_flag_present attributes. */
|
|
|
|
static int
|
|
dwarf2_flag_true_p (struct die_info *die, unsigned name, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr = dwarf2_attr (die, name, cu);
|
|
|
|
return attr != nullptr && attr->as_boolean ();
|
|
}
|
|
|
|
static int
|
|
die_is_declaration (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
/* A DIE is a declaration if it has a DW_AT_declaration attribute
|
|
which value is non-zero. However, we have to be careful with
|
|
DIEs having a DW_AT_specification attribute, because dwarf2_attr()
|
|
(via dwarf2_flag_true_p) follows this attribute. So we may
|
|
end up accidentally finding a declaration attribute that belongs
|
|
to a different DIE referenced by the specification attribute,
|
|
even though the given DIE does not have a declaration attribute. */
|
|
return (dwarf2_flag_true_p (die, DW_AT_declaration, cu)
|
|
&& dwarf2_attr (die, DW_AT_specification, cu) == NULL);
|
|
}
|
|
|
|
/* Return the die giving the specification for DIE, if there is
|
|
one. *SPEC_CU is the CU containing DIE on input, and the CU
|
|
containing the return value on output. If there is no
|
|
specification, but there is an abstract origin, that is
|
|
returned. */
|
|
|
|
static struct die_info *
|
|
die_specification (struct die_info *die, struct dwarf2_cu **spec_cu)
|
|
{
|
|
struct attribute *spec_attr = dwarf2_attr (die, DW_AT_specification,
|
|
*spec_cu);
|
|
|
|
if (spec_attr == NULL)
|
|
spec_attr = dwarf2_attr (die, DW_AT_abstract_origin, *spec_cu);
|
|
|
|
if (spec_attr == NULL)
|
|
return NULL;
|
|
else
|
|
return follow_die_ref (die, spec_attr, spec_cu);
|
|
}
|
|
|
|
/* A convenience function to find the proper .debug_line section for a CU. */
|
|
|
|
static struct dwarf2_section_info *
|
|
get_debug_line_section (struct dwarf2_cu *cu)
|
|
{
|
|
struct dwarf2_section_info *section;
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
/* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the
|
|
DWO file. */
|
|
if (cu->dwo_unit && cu->per_cu->is_debug_types)
|
|
section = &cu->dwo_unit->dwo_file->sections.line;
|
|
else if (cu->per_cu->is_dwz)
|
|
{
|
|
dwz_file *dwz = dwarf2_get_dwz_file (per_objfile->per_bfd, true);
|
|
|
|
section = &dwz->line;
|
|
}
|
|
else
|
|
section = &per_objfile->per_bfd->line;
|
|
|
|
return section;
|
|
}
|
|
|
|
/* Read the statement program header starting at OFFSET in
|
|
.debug_line, or .debug_line.dwo. Return a pointer
|
|
to a struct line_header, allocated using xmalloc.
|
|
Returns NULL if there is a problem reading the header, e.g., if it
|
|
has a version we don't understand.
|
|
|
|
NOTE: the strings in the include directory and file name tables of
|
|
the returned object point into the dwarf line section buffer,
|
|
and must not be freed. */
|
|
|
|
static line_header_up
|
|
dwarf_decode_line_header (sect_offset sect_off, struct dwarf2_cu *cu,
|
|
const char *comp_dir)
|
|
{
|
|
struct dwarf2_section_info *section;
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
section = get_debug_line_section (cu);
|
|
section->read (per_objfile->objfile);
|
|
if (section->buffer == NULL)
|
|
{
|
|
if (cu->dwo_unit && cu->per_cu->is_debug_types)
|
|
complaint (_("missing .debug_line.dwo section"));
|
|
else
|
|
complaint (_("missing .debug_line section"));
|
|
return 0;
|
|
}
|
|
|
|
return dwarf_decode_line_header (sect_off, cu->per_cu->is_dwz,
|
|
per_objfile, section, &cu->header,
|
|
comp_dir);
|
|
}
|
|
|
|
/* Subroutine of dwarf_decode_lines to simplify it.
|
|
Return the file name for the given file_entry.
|
|
CU_INFO describes the CU's DW_AT_name and DW_AT_comp_dir.
|
|
If space for the result is malloc'd, *NAME_HOLDER will be set.
|
|
Returns NULL if FILE_INDEX should be ignored, i.e., it is
|
|
equivalent to CU_INFO. */
|
|
|
|
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)
|
|
{
|
|
const char *include_name = fe.name;
|
|
const char *include_name_to_compare = include_name;
|
|
|
|
const char *dir_name = fe.include_dir (lh);
|
|
|
|
std::string hold_compare;
|
|
if (!IS_ABSOLUTE_PATH (include_name)
|
|
&& (dir_name != nullptr || cu_info.get_comp_dir () != nullptr))
|
|
{
|
|
/* Avoid creating a duplicate name for CU_INFO.
|
|
We do this by comparing INCLUDE_NAME and CU_INFO.
|
|
Before we do the comparison, however, we need to account
|
|
for DIR_NAME and COMP_DIR.
|
|
First prepend dir_name (if non-NULL). If we still don't
|
|
have an absolute path prepend comp_dir (if non-NULL).
|
|
However, the directory we record in the include-file's
|
|
psymtab does not contain COMP_DIR (to match the
|
|
corresponding symtab(s)).
|
|
|
|
Example:
|
|
|
|
bash$ cd /tmp
|
|
bash$ gcc -g ./hello.c
|
|
include_name = "hello.c"
|
|
dir_name = "."
|
|
DW_AT_comp_dir = comp_dir = "/tmp"
|
|
DW_AT_name = "./hello.c"
|
|
|
|
*/
|
|
|
|
if (dir_name != NULL)
|
|
{
|
|
name_holder = path_join (dir_name, include_name);
|
|
include_name = name_holder.c_str ();
|
|
include_name_to_compare = include_name;
|
|
}
|
|
if (!IS_ABSOLUTE_PATH (include_name)
|
|
&& cu_info.get_comp_dir () != nullptr)
|
|
{
|
|
hold_compare = path_join (cu_info.get_comp_dir (), include_name);
|
|
include_name_to_compare = hold_compare.c_str ();
|
|
}
|
|
}
|
|
|
|
std::string copied_name;
|
|
const char *cu_filename = cu_info.get_name ();
|
|
if (!IS_ABSOLUTE_PATH (cu_filename) && cu_info.get_comp_dir () != nullptr)
|
|
{
|
|
copied_name = path_join (cu_info.get_comp_dir (), cu_filename);
|
|
cu_filename = copied_name.c_str ();
|
|
}
|
|
|
|
if (FILENAME_CMP (include_name_to_compare, cu_filename) == 0)
|
|
return nullptr;
|
|
return include_name;
|
|
}
|
|
|
|
/* State machine to track the state of the line number program. */
|
|
|
|
class lnp_state_machine
|
|
{
|
|
public:
|
|
/* Initialize a machine state for the start of a line number
|
|
program. */
|
|
lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, line_header *lh);
|
|
|
|
file_entry *current_file ()
|
|
{
|
|
/* lh->file_names is 0-based, but the file name numbers in the
|
|
statement program are 1-based. */
|
|
return m_line_header->file_name_at (m_file);
|
|
}
|
|
|
|
/* Record the line in the state machine. END_SEQUENCE is true if
|
|
we're processing the end of a sequence. */
|
|
void record_line (bool end_sequence);
|
|
|
|
/* Check ADDRESS is -1, -2, or zero and less than UNRELOCATED_LOWPC, and if
|
|
true nop-out rest of the lines in this sequence. */
|
|
void check_line_address (struct dwarf2_cu *cu,
|
|
const gdb_byte *line_ptr,
|
|
unrelocated_addr unrelocated_lowpc,
|
|
unrelocated_addr address);
|
|
|
|
void handle_set_discriminator (unsigned int discriminator)
|
|
{
|
|
m_discriminator = discriminator;
|
|
m_line_has_non_zero_discriminator |= discriminator != 0;
|
|
}
|
|
|
|
/* Handle DW_LNE_set_address. */
|
|
void handle_set_address (unrelocated_addr address)
|
|
{
|
|
m_op_index = 0;
|
|
m_address
|
|
= (unrelocated_addr) gdbarch_adjust_dwarf2_line (m_gdbarch,
|
|
(CORE_ADDR) address,
|
|
false);
|
|
}
|
|
|
|
/* Handle DW_LNS_advance_pc. */
|
|
void handle_advance_pc (CORE_ADDR adjust);
|
|
|
|
/* Handle a special opcode. */
|
|
void handle_special_opcode (unsigned char op_code);
|
|
|
|
/* Handle DW_LNS_advance_line. */
|
|
void handle_advance_line (int line_delta)
|
|
{
|
|
advance_line (line_delta);
|
|
}
|
|
|
|
/* Handle DW_LNS_set_file. */
|
|
void handle_set_file (file_name_index file);
|
|
|
|
/* Handle DW_LNS_negate_stmt. */
|
|
void handle_negate_stmt ()
|
|
{
|
|
m_flags ^= LEF_IS_STMT;
|
|
}
|
|
|
|
/* Handle DW_LNS_const_add_pc. */
|
|
void handle_const_add_pc ();
|
|
|
|
/* Handle DW_LNS_fixed_advance_pc. */
|
|
void handle_fixed_advance_pc (CORE_ADDR addr_adj)
|
|
{
|
|
addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true);
|
|
m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj);
|
|
m_op_index = 0;
|
|
}
|
|
|
|
/* Handle DW_LNS_copy. */
|
|
void handle_copy ()
|
|
{
|
|
record_line (false);
|
|
m_discriminator = 0;
|
|
m_flags &= ~LEF_PROLOGUE_END;
|
|
m_flags &= ~LEF_EPILOGUE_BEGIN;
|
|
}
|
|
|
|
/* Handle DW_LNE_end_sequence. */
|
|
void handle_end_sequence ()
|
|
{
|
|
m_currently_recording_lines = true;
|
|
}
|
|
|
|
/* Handle DW_LNS_set_prologue_end. */
|
|
void handle_set_prologue_end ()
|
|
{
|
|
m_flags |= LEF_PROLOGUE_END;
|
|
}
|
|
|
|
void handle_set_epilogue_begin ()
|
|
{
|
|
m_flags |= LEF_EPILOGUE_BEGIN;
|
|
}
|
|
|
|
private:
|
|
/* Advance the line by LINE_DELTA. */
|
|
void advance_line (int line_delta)
|
|
{
|
|
m_line += line_delta;
|
|
|
|
if (line_delta != 0)
|
|
m_line_has_non_zero_discriminator = m_discriminator != 0;
|
|
}
|
|
|
|
struct dwarf2_cu *m_cu;
|
|
|
|
gdbarch *m_gdbarch;
|
|
|
|
/* The line number header. */
|
|
line_header *m_line_header;
|
|
|
|
/* These are part of the standard DWARF line number state machine,
|
|
and initialized according to the DWARF spec. */
|
|
|
|
unsigned char m_op_index = 0;
|
|
/* The line table index of the current file. */
|
|
file_name_index m_file = 1;
|
|
unsigned int m_line = 1;
|
|
|
|
/* These are initialized in the constructor. */
|
|
|
|
unrelocated_addr m_address;
|
|
linetable_entry_flags m_flags;
|
|
unsigned int m_discriminator = 0;
|
|
|
|
/* Additional bits of state we need to track. */
|
|
|
|
/* The last file that we called dwarf2_start_subfile for.
|
|
This is only used for TLLs. */
|
|
unsigned int m_last_file = 0;
|
|
/* The last file a line number was recorded for. */
|
|
struct subfile *m_last_subfile = NULL;
|
|
|
|
/* The address of the last line entry. */
|
|
unrelocated_addr m_last_address;
|
|
|
|
/* Set to true when a previous line at the same address (using
|
|
m_last_address) had LEF_IS_STMT set in m_flags. This is reset to false
|
|
when a line entry at a new address (m_address different to
|
|
m_last_address) is processed. */
|
|
bool m_stmt_at_address = false;
|
|
|
|
/* When true, record the lines we decode. */
|
|
bool m_currently_recording_lines = true;
|
|
|
|
/* The last line number that was recorded, used to coalesce
|
|
consecutive entries for the same line. This can happen, for
|
|
example, when discriminators are present. PR 17276. */
|
|
unsigned int m_last_line = 0;
|
|
bool m_line_has_non_zero_discriminator = false;
|
|
};
|
|
|
|
void
|
|
lnp_state_machine::handle_advance_pc (CORE_ADDR adjust)
|
|
{
|
|
CORE_ADDR addr_adj = (((m_op_index + adjust)
|
|
/ m_line_header->maximum_ops_per_instruction)
|
|
* m_line_header->minimum_instruction_length);
|
|
addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true);
|
|
m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj);
|
|
m_op_index = ((m_op_index + adjust)
|
|
% m_line_header->maximum_ops_per_instruction);
|
|
}
|
|
|
|
void
|
|
lnp_state_machine::handle_special_opcode (unsigned char op_code)
|
|
{
|
|
unsigned char adj_opcode = op_code - m_line_header->opcode_base;
|
|
unsigned char adj_opcode_d = adj_opcode / m_line_header->line_range;
|
|
unsigned char adj_opcode_r = adj_opcode % m_line_header->line_range;
|
|
CORE_ADDR addr_adj = (((m_op_index + adj_opcode_d)
|
|
/ m_line_header->maximum_ops_per_instruction)
|
|
* m_line_header->minimum_instruction_length);
|
|
addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true);
|
|
m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj);
|
|
m_op_index = ((m_op_index + adj_opcode_d)
|
|
% m_line_header->maximum_ops_per_instruction);
|
|
|
|
int line_delta = m_line_header->line_base + adj_opcode_r;
|
|
advance_line (line_delta);
|
|
record_line (false);
|
|
m_discriminator = 0;
|
|
m_flags &= ~LEF_PROLOGUE_END;
|
|
m_flags &= ~LEF_EPILOGUE_BEGIN;
|
|
}
|
|
|
|
void
|
|
lnp_state_machine::handle_set_file (file_name_index file)
|
|
{
|
|
m_file = file;
|
|
|
|
const file_entry *fe = current_file ();
|
|
if (fe == NULL)
|
|
dwarf2_debug_line_missing_file_complaint ();
|
|
else
|
|
{
|
|
m_last_subfile = m_cu->get_builder ()->get_current_subfile ();
|
|
m_line_has_non_zero_discriminator = m_discriminator != 0;
|
|
dwarf2_start_subfile (m_cu, *fe, *m_line_header);
|
|
}
|
|
}
|
|
|
|
void
|
|
lnp_state_machine::handle_const_add_pc ()
|
|
{
|
|
CORE_ADDR adjust
|
|
= (255 - m_line_header->opcode_base) / m_line_header->line_range;
|
|
|
|
CORE_ADDR addr_adj
|
|
= (((m_op_index + adjust)
|
|
/ m_line_header->maximum_ops_per_instruction)
|
|
* m_line_header->minimum_instruction_length);
|
|
|
|
addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true);
|
|
m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj);
|
|
m_op_index = ((m_op_index + adjust)
|
|
% m_line_header->maximum_ops_per_instruction);
|
|
}
|
|
|
|
/* Return non-zero if we should add LINE to the line number table.
|
|
LINE is the line to add, LAST_LINE is the last line that was added,
|
|
LAST_SUBFILE is the subfile for LAST_LINE.
|
|
LINE_HAS_NON_ZERO_DISCRIMINATOR is non-zero if LINE has ever
|
|
had a non-zero discriminator.
|
|
|
|
We have to be careful in the presence of discriminators.
|
|
E.g., for this line:
|
|
|
|
for (i = 0; i < 100000; i++);
|
|
|
|
clang can emit four line number entries for that one line,
|
|
each with a different discriminator.
|
|
See gdb.dwarf2/dw2-single-line-discriminators.exp for an example.
|
|
|
|
However, we want gdb to coalesce all four entries into one.
|
|
Otherwise the user could stepi into the middle of the line and
|
|
gdb would get confused about whether the pc really was in the
|
|
middle of the line.
|
|
|
|
Things are further complicated by the fact that two consecutive
|
|
line number entries for the same line is a heuristic used by gcc
|
|
to denote the end of the prologue. So we can't just discard duplicate
|
|
entries, we have to be selective about it. The heuristic we use is
|
|
that we only collapse consecutive entries for the same line if at least
|
|
one of those entries has a non-zero discriminator. PR 17276.
|
|
|
|
Note: Addresses in the line number state machine can never go backwards
|
|
within one sequence, thus this coalescing is ok. */
|
|
|
|
static int
|
|
dwarf_record_line_p (struct dwarf2_cu *cu,
|
|
unsigned int line, unsigned int last_line,
|
|
int line_has_non_zero_discriminator,
|
|
struct subfile *last_subfile)
|
|
{
|
|
if (cu->get_builder ()->get_current_subfile () != last_subfile)
|
|
return 1;
|
|
if (line != last_line)
|
|
return 1;
|
|
/* Same line for the same file that we've seen already.
|
|
As a last check, for pr 17276, only record the line if the line
|
|
has never had a non-zero discriminator. */
|
|
if (!line_has_non_zero_discriminator)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/* Use the CU's builder to record line number LINE beginning at
|
|
address ADDRESS in the line table of subfile SUBFILE. */
|
|
|
|
static void
|
|
dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
|
|
unsigned int line, unrelocated_addr address,
|
|
linetable_entry_flags flags,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
unrelocated_addr addr
|
|
= unrelocated_addr (gdbarch_addr_bits_remove (gdbarch,
|
|
(CORE_ADDR) address));
|
|
|
|
if (dwarf_line_debug)
|
|
{
|
|
gdb_printf (gdb_stdlog,
|
|
"Recording line %u, file %s, address %s\n",
|
|
line, lbasename (subfile->name.c_str ()),
|
|
paddress (gdbarch, (CORE_ADDR) address));
|
|
}
|
|
|
|
if (cu != nullptr)
|
|
cu->get_builder ()->record_line (subfile, line, addr, flags);
|
|
}
|
|
|
|
/* Subroutine of dwarf_decode_lines_1 to simplify it.
|
|
Mark the end of a set of line number records.
|
|
The arguments are the same as for dwarf_record_line_1.
|
|
If SUBFILE is NULL the request is ignored. */
|
|
|
|
static void
|
|
dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
|
|
unrelocated_addr address, struct dwarf2_cu *cu)
|
|
{
|
|
if (subfile == NULL)
|
|
return;
|
|
|
|
if (dwarf_line_debug)
|
|
{
|
|
gdb_printf (gdb_stdlog,
|
|
"Finishing current line, file %s, address %s\n",
|
|
lbasename (subfile->name.c_str ()),
|
|
paddress (gdbarch, (CORE_ADDR) address));
|
|
}
|
|
|
|
dwarf_record_line_1 (gdbarch, subfile, 0, address, LEF_IS_STMT, cu);
|
|
}
|
|
|
|
void
|
|
lnp_state_machine::record_line (bool end_sequence)
|
|
{
|
|
if (dwarf_line_debug)
|
|
{
|
|
gdb_printf (gdb_stdlog,
|
|
"Processing actual line %u: file %u,"
|
|
" address %s, is_stmt %u, prologue_end %u,"
|
|
" epilogue_begin %u, discrim %u%s\n",
|
|
m_line, m_file,
|
|
paddress (m_gdbarch, (CORE_ADDR) m_address),
|
|
(m_flags & LEF_IS_STMT) != 0,
|
|
(m_flags & LEF_PROLOGUE_END) != 0,
|
|
(m_flags & LEF_EPILOGUE_BEGIN) != 0,
|
|
m_discriminator,
|
|
(end_sequence ? "\t(end sequence)" : ""));
|
|
}
|
|
|
|
file_entry *fe = current_file ();
|
|
|
|
if (fe == NULL)
|
|
dwarf2_debug_line_missing_file_complaint ();
|
|
/* For now we ignore lines not starting on an instruction boundary.
|
|
But not when processing end_sequence for compatibility with the
|
|
previous version of the code. */
|
|
else if (m_op_index == 0 || end_sequence)
|
|
{
|
|
/* When we switch files we insert an end maker in the first file,
|
|
switch to the second file and add a new line entry. The
|
|
problem is that the end marker inserted in the first file will
|
|
discard any previous line entries at the same address. If the
|
|
line entries in the first file are marked as is-stmt, while
|
|
the new line in the second file is non-stmt, then this means
|
|
the end marker will discard is-stmt lines so we can have a
|
|
non-stmt line. This means that there are less addresses at
|
|
which the user can insert a breakpoint.
|
|
|
|
To improve this we track the last address in m_last_address,
|
|
and whether we have seen an is-stmt at this address. Then
|
|
when switching files, if we have seen a stmt at the current
|
|
address, and we are switching to create a non-stmt line, then
|
|
discard the new line. */
|
|
bool file_changed
|
|
= m_last_subfile != m_cu->get_builder ()->get_current_subfile ();
|
|
bool ignore_this_line
|
|
= ((file_changed && !end_sequence && m_last_address == m_address
|
|
&& ((m_flags & LEF_IS_STMT) == 0)
|
|
&& m_stmt_at_address)
|
|
|| (!end_sequence && m_line == 0));
|
|
|
|
if ((file_changed && !ignore_this_line) || end_sequence)
|
|
{
|
|
dwarf_finish_line (m_gdbarch, m_last_subfile, m_address,
|
|
m_currently_recording_lines ? m_cu : nullptr);
|
|
}
|
|
|
|
if (!end_sequence && !ignore_this_line)
|
|
{
|
|
linetable_entry_flags lte_flags = m_flags;
|
|
if (producer_is_codewarrior (m_cu))
|
|
lte_flags |= LEF_IS_STMT;
|
|
|
|
if (dwarf_record_line_p (m_cu, m_line, m_last_line,
|
|
m_line_has_non_zero_discriminator,
|
|
m_last_subfile))
|
|
{
|
|
buildsym_compunit *builder = m_cu->get_builder ();
|
|
dwarf_record_line_1 (m_gdbarch,
|
|
builder->get_current_subfile (),
|
|
m_line, m_address, lte_flags,
|
|
m_currently_recording_lines ? m_cu : nullptr);
|
|
}
|
|
m_last_subfile = m_cu->get_builder ()->get_current_subfile ();
|
|
m_last_line = m_line;
|
|
}
|
|
}
|
|
|
|
/* Track whether we have seen any IS_STMT true at m_address in case we
|
|
have multiple line table entries all at m_address. */
|
|
if (m_last_address != m_address)
|
|
{
|
|
m_stmt_at_address = false;
|
|
m_last_address = m_address;
|
|
}
|
|
m_stmt_at_address |= (m_flags & LEF_IS_STMT) != 0;
|
|
}
|
|
|
|
lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
|
|
line_header *lh)
|
|
: m_cu (cu),
|
|
m_gdbarch (arch),
|
|
m_line_header (lh),
|
|
/* Call `gdbarch_adjust_dwarf2_line' on the initial 0 address as
|
|
if there was a line entry for it so that the backend has a
|
|
chance to adjust it and also record it in case it needs it.
|
|
This is currently used by MIPS code,
|
|
cf. `mips_adjust_dwarf2_line'. */
|
|
m_address ((unrelocated_addr) gdbarch_adjust_dwarf2_line (arch, 0, 0)),
|
|
m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0),
|
|
m_last_address (m_address)
|
|
{
|
|
}
|
|
|
|
void
|
|
lnp_state_machine::check_line_address (struct dwarf2_cu *cu,
|
|
const gdb_byte *line_ptr,
|
|
unrelocated_addr unrelocated_lowpc,
|
|
unrelocated_addr address)
|
|
{
|
|
/* Linkers resolve a symbolic relocation referencing a GC'd function to 0,
|
|
-1 or -2 (-2 is used by certain lld versions, see
|
|
https://github.com/llvm/llvm-project/commit/e618ccbf431f6730edb6d1467a127c3a52fd57f7).
|
|
If ADDRESS is 0, ignoring the opcode will err if the text section is
|
|
located at 0x0. In this case, additionally check that if
|
|
ADDRESS < UNRELOCATED_LOWPC. */
|
|
|
|
if ((address == (unrelocated_addr) 0 && address < unrelocated_lowpc)
|
|
|| address == (unrelocated_addr) -1
|
|
|| address == (unrelocated_addr) -2)
|
|
{
|
|
/* This line table is for a function which has been
|
|
GCd by the linker. Ignore it. PR gdb/12528 */
|
|
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
long line_offset = line_ptr - get_debug_line_section (cu)->buffer;
|
|
|
|
complaint (_(".debug_line address at offset 0x%lx is 0 [in module %s]"),
|
|
line_offset, objfile_name (objfile));
|
|
m_currently_recording_lines = false;
|
|
/* Note: m_currently_recording_lines is left as false until we see
|
|
DW_LNE_end_sequence. */
|
|
}
|
|
}
|
|
|
|
/* Subroutine of dwarf_decode_lines to simplify it.
|
|
Process the line number information in LH. */
|
|
|
|
static void
|
|
dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
|
|
unrelocated_addr lowpc)
|
|
{
|
|
const gdb_byte *line_ptr, *extended_end;
|
|
const gdb_byte *line_end;
|
|
unsigned int bytes_read, extended_len;
|
|
unsigned char op_code, extended_op;
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
bfd *abfd = objfile->obfd.get ();
|
|
struct gdbarch *gdbarch = objfile->arch ();
|
|
|
|
line_ptr = lh->statement_program_start;
|
|
line_end = lh->statement_program_end;
|
|
|
|
/* Read the statement sequences until there's nothing left. */
|
|
while (line_ptr < line_end)
|
|
{
|
|
/* The DWARF line number program state machine. Reset the state
|
|
machine at the start of each sequence. */
|
|
lnp_state_machine state_machine (cu, gdbarch, lh);
|
|
bool end_sequence = false;
|
|
|
|
/* Start a subfile for the current file of the state
|
|
machine. */
|
|
const file_entry *fe = state_machine.current_file ();
|
|
|
|
if (fe != NULL)
|
|
dwarf2_start_subfile (cu, *fe, *lh);
|
|
|
|
/* Decode the table. */
|
|
while (line_ptr < line_end && !end_sequence)
|
|
{
|
|
op_code = read_1_byte (abfd, line_ptr);
|
|
line_ptr += 1;
|
|
|
|
if (op_code >= lh->opcode_base)
|
|
{
|
|
/* Special opcode. */
|
|
state_machine.handle_special_opcode (op_code);
|
|
}
|
|
else switch (op_code)
|
|
{
|
|
case DW_LNS_extended_op:
|
|
extended_len = read_unsigned_leb128 (abfd, line_ptr,
|
|
&bytes_read);
|
|
line_ptr += bytes_read;
|
|
extended_end = line_ptr + extended_len;
|
|
extended_op = read_1_byte (abfd, line_ptr);
|
|
line_ptr += 1;
|
|
if (DW_LNE_lo_user <= extended_op
|
|
&& extended_op <= DW_LNE_hi_user)
|
|
{
|
|
/* Vendor extension, ignore. */
|
|
line_ptr = extended_end;
|
|
break;
|
|
}
|
|
switch (extended_op)
|
|
{
|
|
case DW_LNE_end_sequence:
|
|
state_machine.handle_end_sequence ();
|
|
end_sequence = true;
|
|
break;
|
|
case DW_LNE_set_address:
|
|
{
|
|
unrelocated_addr address
|
|
= cu->header.read_address (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
|
|
state_machine.check_line_address (cu, line_ptr, lowpc,
|
|
address);
|
|
state_machine.handle_set_address (address);
|
|
}
|
|
break;
|
|
case DW_LNE_define_file:
|
|
{
|
|
const char *cur_file;
|
|
unsigned int mod_time, length;
|
|
dir_index dindex;
|
|
|
|
cur_file = read_direct_string (abfd, line_ptr,
|
|
&bytes_read);
|
|
line_ptr += bytes_read;
|
|
dindex = (dir_index)
|
|
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
mod_time =
|
|
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
length =
|
|
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
lh->add_file_name (cur_file, dindex, mod_time, length);
|
|
}
|
|
break;
|
|
case DW_LNE_set_discriminator:
|
|
{
|
|
/* The discriminator is not interesting to the
|
|
debugger; just ignore it. We still need to
|
|
check its value though:
|
|
if there are consecutive entries for the same
|
|
(non-prologue) line we want to coalesce them.
|
|
PR 17276. */
|
|
unsigned int discr
|
|
= read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
|
|
state_machine.handle_set_discriminator (discr);
|
|
}
|
|
break;
|
|
default:
|
|
complaint (_("mangled .debug_line section"));
|
|
return;
|
|
}
|
|
/* Make sure that we parsed the extended op correctly. If e.g.
|
|
we expected a different address size than the producer used,
|
|
we may have read the wrong number of bytes. */
|
|
if (line_ptr != extended_end)
|
|
{
|
|
complaint (_("mangled .debug_line section"));
|
|
return;
|
|
}
|
|
break;
|
|
case DW_LNS_copy:
|
|
state_machine.handle_copy ();
|
|
break;
|
|
case DW_LNS_advance_pc:
|
|
{
|
|
CORE_ADDR adjust
|
|
= read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
|
|
state_machine.handle_advance_pc (adjust);
|
|
}
|
|
break;
|
|
case DW_LNS_advance_line:
|
|
{
|
|
int line_delta
|
|
= read_signed_leb128 (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
|
|
state_machine.handle_advance_line (line_delta);
|
|
}
|
|
break;
|
|
case DW_LNS_set_file:
|
|
{
|
|
file_name_index file
|
|
= (file_name_index) read_unsigned_leb128 (abfd, line_ptr,
|
|
&bytes_read);
|
|
line_ptr += bytes_read;
|
|
|
|
state_machine.handle_set_file (file);
|
|
}
|
|
break;
|
|
case DW_LNS_set_column:
|
|
(void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
break;
|
|
case DW_LNS_negate_stmt:
|
|
state_machine.handle_negate_stmt ();
|
|
break;
|
|
case DW_LNS_set_basic_block:
|
|
break;
|
|
/* Add to the address register of the state machine the
|
|
address increment value corresponding to special opcode
|
|
255. I.e., this value is scaled by the minimum
|
|
instruction length since special opcode 255 would have
|
|
scaled the increment. */
|
|
case DW_LNS_const_add_pc:
|
|
state_machine.handle_const_add_pc ();
|
|
break;
|
|
case DW_LNS_fixed_advance_pc:
|
|
{
|
|
CORE_ADDR addr_adj = read_2_bytes (abfd, line_ptr);
|
|
line_ptr += 2;
|
|
|
|
state_machine.handle_fixed_advance_pc (addr_adj);
|
|
}
|
|
break;
|
|
case DW_LNS_set_prologue_end:
|
|
state_machine.handle_set_prologue_end ();
|
|
break;
|
|
case DW_LNS_set_epilogue_begin:
|
|
state_machine.handle_set_epilogue_begin ();
|
|
break;
|
|
default:
|
|
{
|
|
/* Unknown standard opcode, ignore it. */
|
|
int i;
|
|
|
|
for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++)
|
|
{
|
|
(void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
|
|
line_ptr += bytes_read;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!end_sequence)
|
|
dwarf2_debug_line_missing_end_sequence_complaint ();
|
|
|
|
/* We got a DW_LNE_end_sequence (or we ran off the end of the buffer,
|
|
in which case we still finish recording the last line). */
|
|
state_machine.record_line (true);
|
|
}
|
|
}
|
|
|
|
/* Decode the Line Number Program (LNP) for the given line_header
|
|
structure and CU. The actual information extracted and the type
|
|
of structures created from the LNP depends on the value of PST.
|
|
|
|
FND holds the CU file name and directory, if known.
|
|
It is used for relative paths in the line table.
|
|
|
|
NOTE: It is important that psymtabs have the same file name (via
|
|
strcmp) as the corresponding symtab. Since the directory is not
|
|
used in the name of the symtab we don't use it in the name of the
|
|
psymtabs we create. E.g. expand_line_sal requires this when
|
|
finding psymtabs to expand. A good testcase for this is
|
|
mb-inline.exp.
|
|
|
|
LOWPC is the lowest address in CU (or 0 if not known).
|
|
|
|
Boolean DECODE_MAPPING specifies we need to fully decode .debug_line
|
|
for its PC<->lines mapping information. Otherwise only the filename
|
|
table is read in. */
|
|
|
|
static void
|
|
dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu,
|
|
unrelocated_addr lowpc, int decode_mapping)
|
|
{
|
|
if (decode_mapping)
|
|
dwarf_decode_lines_1 (lh, cu, lowpc);
|
|
|
|
/* Make sure a symtab is created for every file, even files
|
|
which contain only variables (i.e. no code with associated
|
|
line numbers). */
|
|
buildsym_compunit *builder = cu->get_builder ();
|
|
struct compunit_symtab *cust = builder->get_compunit_symtab ();
|
|
|
|
for (auto &fe : lh->file_names ())
|
|
{
|
|
dwarf2_start_subfile (cu, fe, *lh);
|
|
subfile *sf = builder->get_current_subfile ();
|
|
|
|
if (sf->symtab == nullptr)
|
|
sf->symtab = allocate_symtab (cust, sf->name.c_str (),
|
|
sf->name_for_id.c_str ());
|
|
|
|
fe.symtab = sf->symtab;
|
|
}
|
|
}
|
|
|
|
/* Start a subfile for DWARF. FILENAME is the name of the file and
|
|
DIRNAME the name of the source directory which contains FILENAME
|
|
or NULL if not known.
|
|
This routine tries to keep line numbers from identical absolute and
|
|
relative file names in a common subfile.
|
|
|
|
Using the `list' example from the GDB testsuite, which resides in
|
|
/srcdir and compiling it with Irix6.2 cc in /compdir using a filename
|
|
of /srcdir/list0.c yields the following debugging information for list0.c:
|
|
|
|
DW_AT_name: /srcdir/list0.c
|
|
DW_AT_comp_dir: /compdir
|
|
files.files[0].name: list0.h
|
|
files.files[0].dir: /srcdir
|
|
files.files[1].name: list0.c
|
|
files.files[1].dir: /srcdir
|
|
|
|
The line number information for list0.c has to end up in a single
|
|
subfile, so that `break /srcdir/list0.c:1' works as expected.
|
|
start_subfile will ensure that this happens provided that we pass the
|
|
concatenation of files.files[1].dir and files.files[1].name as the
|
|
subfile's name. */
|
|
|
|
static void
|
|
dwarf2_start_subfile (dwarf2_cu *cu, const file_entry &fe,
|
|
const line_header &lh)
|
|
{
|
|
std::string filename_holder;
|
|
const char *filename = fe.name;
|
|
const char *dirname = lh.include_dir_at (fe.d_index);
|
|
|
|
/* In order not to lose the line information directory,
|
|
we concatenate it to the filename when it makes sense.
|
|
Note that the Dwarf3 standard says (speaking of filenames in line
|
|
information): ``The directory index is ignored for file names
|
|
that represent full path names''. Thus ignoring dirname in the
|
|
`else' branch below isn't an issue. */
|
|
|
|
if (!IS_ABSOLUTE_PATH (filename) && dirname != NULL)
|
|
{
|
|
filename_holder = path_join (dirname, filename);
|
|
filename = filename_holder.c_str ();
|
|
}
|
|
|
|
std::string filename_for_id = lh.file_file_name (fe);
|
|
cu->get_builder ()->start_subfile (filename, filename_for_id.c_str ());
|
|
}
|
|
|
|
static void
|
|
var_decode_location (struct attribute *attr, struct symbol *sym,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
struct comp_unit_head *cu_header = &cu->header;
|
|
|
|
/* NOTE drow/2003-01-30: There used to be a comment and some special
|
|
code here to turn a symbol with DW_AT_external and a
|
|
SYMBOL_VALUE_ADDRESS of 0 into a LOC_UNRESOLVED symbol. This was
|
|
necessary for platforms (maybe Alpha, certainly PowerPC GNU/Linux
|
|
with some versions of binutils) where shared libraries could have
|
|
relocations against symbols in their debug information - the
|
|
minimal symbol would have the right address, but the debug info
|
|
would not. It's no longer necessary, because we will explicitly
|
|
apply relocations when we read in the debug information now. */
|
|
|
|
/* A DW_AT_location attribute with no contents indicates that a
|
|
variable has been optimized away. */
|
|
if (attr->form_is_block () && attr->as_block ()->size == 0)
|
|
{
|
|
sym->set_aclass_index (LOC_OPTIMIZED_OUT);
|
|
return;
|
|
}
|
|
|
|
/* Handle one degenerate form of location expression specially, to
|
|
preserve GDB's previous behavior when section offsets are
|
|
specified. If this is just a DW_OP_addr, DW_OP_addrx, or
|
|
DW_OP_GNU_addr_index then mark this symbol as LOC_STATIC. */
|
|
|
|
if (attr->form_is_block ())
|
|
{
|
|
struct dwarf_block *block = attr->as_block ();
|
|
|
|
if ((block->data[0] == DW_OP_addr
|
|
&& block->size == 1 + cu_header->addr_size)
|
|
|| ((block->data[0] == DW_OP_GNU_addr_index
|
|
|| block->data[0] == DW_OP_addrx)
|
|
&& (block->size
|
|
== 1 + leb128_size (&block->data[1]))))
|
|
{
|
|
unsigned int dummy;
|
|
|
|
unrelocated_addr tem;
|
|
if (block->data[0] == DW_OP_addr)
|
|
tem = cu->header.read_address (objfile->obfd.get (),
|
|
block->data + 1,
|
|
&dummy);
|
|
else
|
|
tem = read_addr_index_from_leb128 (cu, block->data + 1, &dummy);
|
|
sym->set_value_address ((CORE_ADDR) tem);
|
|
sym->set_aclass_index (LOC_STATIC);
|
|
fixup_symbol_section (sym, objfile);
|
|
sym->set_value_address
|
|
(sym->value_address ()
|
|
+ objfile->section_offsets[sym->section_index ()]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* NOTE drow/2002-01-30: It might be worthwhile to have a static
|
|
expression evaluator, and use LOC_COMPUTED only when necessary
|
|
(i.e. when the value of a register or memory location is
|
|
referenced, or a thread-local block, etc.). Then again, it might
|
|
not be worthwhile. I'm assuming that it isn't unless performance
|
|
or memory numbers show me otherwise. */
|
|
|
|
dwarf2_symbol_mark_computed (attr, sym, cu, 0);
|
|
|
|
if (sym->computed_ops ()->location_has_loclist)
|
|
cu->has_loclist = true;
|
|
}
|
|
|
|
/* A helper function to add an "export" symbol. The new symbol starts
|
|
as a clone of ORIG, but is modified to defer to the symbol named
|
|
ORIG_NAME. The original symbol uses the name given in the source
|
|
code, and the symbol that is created here uses the linkage name as
|
|
its name. See ada-imported.c. */
|
|
|
|
static void
|
|
add_ada_export_symbol (struct symbol *orig, const char *new_name,
|
|
const char *orig_name, struct dwarf2_cu *cu,
|
|
struct pending **list_to_add)
|
|
{
|
|
struct symbol *copy
|
|
= new (&cu->per_objfile->objfile->objfile_obstack) symbol (*orig);
|
|
copy->set_linkage_name (new_name);
|
|
SYMBOL_LOCATION_BATON (copy) = (void *) orig_name;
|
|
copy->set_aclass_index (copy->aclass () == LOC_BLOCK
|
|
? ada_block_index
|
|
: ada_imported_index);
|
|
add_symbol_to_list (copy, list_to_add);
|
|
}
|
|
|
|
/* A helper function that decides if a given symbol is an Ada Pragma
|
|
Import or Pragma Export. */
|
|
|
|
static bool
|
|
is_ada_import_or_export (dwarf2_cu *cu, const char *name,
|
|
const char *linkagename)
|
|
{
|
|
return (cu->lang () == language_ada
|
|
&& linkagename != nullptr
|
|
&& !streq (name, linkagename)
|
|
/* The following exclusions are necessary because symbols
|
|
with names or linkage names that match here will meet the
|
|
other criteria but are not in fact caused by Pragma
|
|
Import or Pragma Export, and applying the import/export
|
|
treatment to them will introduce problems. Some of these
|
|
checks only apply to functions, but it is simpler and
|
|
harmless to always do them all. */
|
|
&& !startswith (name, "__builtin")
|
|
&& !startswith (linkagename, "___ghost_")
|
|
&& !startswith (linkagename, "__gnat")
|
|
&& !startswith (linkagename, "_ada_")
|
|
&& !streq (linkagename, "adainit"));
|
|
}
|
|
|
|
/* Given a pointer to a DWARF information entry, figure out if we need
|
|
to make a symbol table entry for it, and if so, create a new entry
|
|
and return a pointer to it.
|
|
If TYPE is NULL, determine symbol type from the die, otherwise
|
|
used the passed type.
|
|
If SPACE is not NULL, use it to hold the new symbol. If it is
|
|
NULL, allocate a new symbol on the objfile's obstack. */
|
|
|
|
static struct symbol *
|
|
new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
|
|
struct symbol *space)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct symbol *sym = NULL;
|
|
const char *name;
|
|
struct attribute *attr = NULL;
|
|
struct attribute *attr2 = NULL;
|
|
struct pending **list_to_add = NULL;
|
|
|
|
int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
|
|
|
|
name = dwarf2_name (die, cu);
|
|
if (name == nullptr && (die->tag == DW_TAG_subprogram
|
|
|| die->tag == DW_TAG_inlined_subroutine
|
|
|| die->tag == DW_TAG_entry_point))
|
|
name = dw2_linkage_name (die, cu);
|
|
|
|
if (name)
|
|
{
|
|
int suppress_add = 0;
|
|
|
|
if (space)
|
|
sym = space;
|
|
else
|
|
sym = new (&objfile->objfile_obstack) symbol;
|
|
OBJSTAT (objfile, n_syms++);
|
|
|
|
/* Cache this symbol's name and the name's demangled form (if any). */
|
|
sym->set_language (cu->lang (), &objfile->objfile_obstack);
|
|
/* Fortran does not have mangling standard and the mangling does differ
|
|
between gfortran, iFort etc. */
|
|
const char *physname
|
|
= (cu->lang () == language_fortran
|
|
? dwarf2_full_name (name, die, cu)
|
|
: dwarf2_physname (name, die, cu));
|
|
const char *linkagename = dw2_linkage_name (die, cu);
|
|
|
|
if (linkagename == nullptr || cu->lang () == language_ada)
|
|
sym->set_linkage_name (physname);
|
|
else
|
|
{
|
|
if (physname == linkagename)
|
|
sym->set_demangled_name (name, &objfile->objfile_obstack);
|
|
else
|
|
sym->set_demangled_name (physname, &objfile->objfile_obstack);
|
|
|
|
sym->set_linkage_name (linkagename);
|
|
}
|
|
|
|
/* Handle DW_AT_artificial. */
|
|
attr = dwarf2_attr (die, DW_AT_artificial, cu);
|
|
if (attr != nullptr)
|
|
sym->set_is_artificial (attr->as_boolean ());
|
|
|
|
/* Default assumptions.
|
|
Use the passed type or decode it from the die. */
|
|
sym->set_domain (UNDEF_DOMAIN);
|
|
sym->set_aclass_index (LOC_OPTIMIZED_OUT);
|
|
if (type != NULL)
|
|
sym->set_type (type);
|
|
else
|
|
sym->set_type (die_type (die, cu));
|
|
attr = dwarf2_attr (die,
|
|
inlined_func ? DW_AT_call_line : DW_AT_decl_line,
|
|
cu);
|
|
if (attr != nullptr)
|
|
sym->set_line (attr->constant_value (0));
|
|
|
|
struct dwarf2_cu *file_cu = cu;
|
|
attr = dwarf2_attr (die,
|
|
inlined_func ? DW_AT_call_file : DW_AT_decl_file,
|
|
&file_cu);
|
|
if (attr != nullptr && attr->is_nonnegative ())
|
|
{
|
|
file_name_index file_index
|
|
= (file_name_index) attr->as_nonnegative ();
|
|
struct file_entry *fe;
|
|
|
|
if (file_cu->line_header == nullptr)
|
|
{
|
|
file_and_directory fnd (nullptr, nullptr);
|
|
handle_DW_AT_stmt_list (file_cu->dies, file_cu, fnd, {}, false);
|
|
}
|
|
|
|
if (file_cu->line_header != nullptr)
|
|
fe = file_cu->line_header->file_name_at (file_index);
|
|
else
|
|
fe = NULL;
|
|
|
|
if (fe == NULL)
|
|
complaint (_("file index out of range"));
|
|
else
|
|
sym->set_symtab (fe->symtab);
|
|
}
|
|
|
|
switch (die->tag)
|
|
{
|
|
case DW_TAG_label:
|
|
attr = dwarf2_attr (die, DW_AT_low_pc, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
CORE_ADDR addr = per_objfile->relocate (attr->as_address ());
|
|
sym->set_section_index (SECT_OFF_TEXT (objfile));
|
|
sym->set_value_address (addr);
|
|
sym->set_aclass_index (LOC_LABEL);
|
|
}
|
|
else
|
|
sym->set_aclass_index (LOC_OPTIMIZED_OUT);
|
|
sym->set_type (builtin_type (objfile)->builtin_core_addr);
|
|
sym->set_domain (LABEL_DOMAIN);
|
|
list_to_add = cu->list_in_scope;
|
|
break;
|
|
case DW_TAG_entry_point:
|
|
/* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
|
|
finish_block. */
|
|
sym->set_domain (FUNCTION_DOMAIN);
|
|
sym->set_aclass_index (LOC_BLOCK);
|
|
/* DW_TAG_entry_point provides an additional entry_point to an
|
|
existing sub_program. Therefore, we inherit the "external"
|
|
attribute from the sub_program to which the entry_point
|
|
belongs to. */
|
|
attr2 = dwarf2_attr (die->parent, DW_AT_external, cu);
|
|
if (attr2 != nullptr && attr2->as_boolean ())
|
|
list_to_add = cu->get_builder ()->get_global_symbols ();
|
|
else
|
|
list_to_add = cu->list_in_scope;
|
|
break;
|
|
case DW_TAG_subprogram:
|
|
/* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
|
|
finish_block. */
|
|
sym->set_domain (FUNCTION_DOMAIN);
|
|
sym->set_aclass_index (LOC_BLOCK);
|
|
attr2 = dwarf2_attr (die, DW_AT_external, cu);
|
|
if ((attr2 != nullptr && attr2->as_boolean ())
|
|
|| cu->lang () == language_ada
|
|
|| cu->lang () == language_fortran)
|
|
{
|
|
/* Subprograms marked external are stored as a global symbol.
|
|
Ada and Fortran subprograms, whether marked external or
|
|
not, are always stored as a global symbol, because we want
|
|
to be able to access them globally. For instance, we want
|
|
to be able to break on a nested subprogram without having
|
|
to specify the context. */
|
|
list_to_add = cu->get_builder ()->get_global_symbols ();
|
|
}
|
|
else
|
|
{
|
|
list_to_add = cu->list_in_scope;
|
|
}
|
|
|
|
if (is_ada_import_or_export (cu, name, linkagename))
|
|
{
|
|
/* This is either a Pragma Import or Export. They can
|
|
be distinguished by the declaration flag. */
|
|
sym->set_linkage_name (name);
|
|
if (die_is_declaration (die, cu))
|
|
{
|
|
/* For Import, create a symbol using the source
|
|
name, and have it refer to the linkage name. */
|
|
SYMBOL_LOCATION_BATON (sym) = (void *) linkagename;
|
|
sym->set_aclass_index (ada_block_index);
|
|
}
|
|
else
|
|
{
|
|
/* For Export, create a symbol using the source
|
|
name, then create a second symbol that refers
|
|
back to it. */
|
|
add_ada_export_symbol (sym, linkagename, name, cu,
|
|
list_to_add);
|
|
}
|
|
}
|
|
break;
|
|
case DW_TAG_inlined_subroutine:
|
|
/* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
|
|
finish_block. */
|
|
sym->set_domain (FUNCTION_DOMAIN);
|
|
sym->set_aclass_index (LOC_BLOCK);
|
|
sym->set_is_inlined (1);
|
|
list_to_add = cu->list_in_scope;
|
|
break;
|
|
case DW_TAG_template_value_param:
|
|
suppress_add = 1;
|
|
[[fallthrough]];
|
|
case DW_TAG_constant:
|
|
case DW_TAG_variable:
|
|
case DW_TAG_member:
|
|
sym->set_domain (VAR_DOMAIN);
|
|
/* Compilation with minimal debug info may result in
|
|
variables with missing type entries. Change the
|
|
misleading `void' type to something sensible. */
|
|
if (sym->type ()->code () == TYPE_CODE_VOID)
|
|
sym->set_type (builtin_type (objfile)->builtin_int);
|
|
|
|
attr = dwarf2_attr (die, DW_AT_const_value, cu);
|
|
/* In the case of DW_TAG_member, we should only be called for
|
|
static const members. */
|
|
if (die->tag == DW_TAG_member)
|
|
{
|
|
/* dwarf2_add_field uses die_is_declaration,
|
|
so we do the same. */
|
|
gdb_assert (die_is_declaration (die, cu));
|
|
gdb_assert (attr);
|
|
}
|
|
if (attr != nullptr)
|
|
{
|
|
dwarf2_const_value (attr, sym, cu);
|
|
attr2 = dwarf2_attr (die, DW_AT_external, cu);
|
|
if (!suppress_add)
|
|
{
|
|
if (attr2 != nullptr && attr2->as_boolean ())
|
|
list_to_add = cu->get_builder ()->get_global_symbols ();
|
|
else
|
|
list_to_add = cu->list_in_scope;
|
|
}
|
|
break;
|
|
}
|
|
attr = dwarf2_attr (die, DW_AT_location, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
var_decode_location (attr, sym, cu);
|
|
attr2 = dwarf2_attr (die, DW_AT_external, cu);
|
|
|
|
/* Fortran explicitly imports any global symbols to the local
|
|
scope by DW_TAG_common_block. */
|
|
if (cu->lang () == language_fortran && die->parent
|
|
&& die->parent->tag == DW_TAG_common_block)
|
|
attr2 = NULL;
|
|
|
|
if (sym->aclass () == LOC_STATIC
|
|
&& sym->value_address () == 0
|
|
&& !per_objfile->per_bfd->has_section_at_zero)
|
|
{
|
|
/* When a static variable is eliminated by the linker,
|
|
the corresponding debug information is not stripped
|
|
out, but the variable address is set to null;
|
|
do not add such variables into symbol table. */
|
|
}
|
|
else if (attr2 != nullptr && attr2->as_boolean ())
|
|
{
|
|
if (sym->aclass () == LOC_STATIC
|
|
&& (objfile->flags & OBJF_MAINLINE) == 0
|
|
&& per_objfile->per_bfd->can_copy)
|
|
{
|
|
/* A global static variable might be subject to
|
|
copy relocation. We first check for a local
|
|
minsym, though, because maybe the symbol was
|
|
marked hidden, in which case this would not
|
|
apply. */
|
|
bound_minimal_symbol found
|
|
= (lookup_minimal_symbol_linkage
|
|
(sym->linkage_name (), objfile, false));
|
|
if (found.minsym != nullptr)
|
|
sym->maybe_copied = 1;
|
|
}
|
|
|
|
/* A variable with DW_AT_external is never static,
|
|
but it may be block-scoped. */
|
|
list_to_add
|
|
= ((cu->list_in_scope
|
|
== cu->get_builder ()->get_file_symbols ())
|
|
? cu->get_builder ()->get_global_symbols ()
|
|
: cu->list_in_scope);
|
|
}
|
|
else
|
|
list_to_add = cu->list_in_scope;
|
|
|
|
if (list_to_add != nullptr
|
|
&& is_ada_import_or_export (cu, name, linkagename))
|
|
{
|
|
/* This is a Pragma Export. A Pragma Import won't
|
|
be seen here, because it will not have a location
|
|
and so will be handled below. */
|
|
add_ada_export_symbol (sym, name, linkagename, cu,
|
|
list_to_add);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* We do not know the address of this symbol.
|
|
If it is an external symbol and we have type information
|
|
for it, enter the symbol as a LOC_UNRESOLVED symbol.
|
|
The address of the variable will then be determined from
|
|
the minimal symbol table whenever the variable is
|
|
referenced. */
|
|
attr2 = dwarf2_attr (die, DW_AT_external, cu);
|
|
|
|
/* Fortran explicitly imports any global symbols to the local
|
|
scope by DW_TAG_common_block. */
|
|
if (cu->lang () == language_fortran && die->parent
|
|
&& die->parent->tag == DW_TAG_common_block)
|
|
{
|
|
/* SYMBOL_CLASS doesn't matter here because
|
|
read_common_block is going to reset it. */
|
|
if (!suppress_add)
|
|
list_to_add = cu->list_in_scope;
|
|
}
|
|
else if (is_ada_import_or_export (cu, name, linkagename))
|
|
{
|
|
/* This is a Pragma Import. A Pragma Export won't
|
|
be seen here, because it will have a location and
|
|
so will be handled above. */
|
|
sym->set_linkage_name (name);
|
|
list_to_add = cu->list_in_scope;
|
|
SYMBOL_LOCATION_BATON (sym) = (void *) linkagename;
|
|
sym->set_aclass_index (ada_imported_index);
|
|
}
|
|
else if (attr2 != nullptr && attr2->as_boolean ()
|
|
&& dwarf2_attr (die, DW_AT_type, cu) != NULL)
|
|
{
|
|
/* A variable with DW_AT_external is never static, but it
|
|
may be block-scoped. */
|
|
list_to_add
|
|
= ((cu->list_in_scope
|
|
== cu->get_builder ()->get_file_symbols ())
|
|
? cu->get_builder ()->get_global_symbols ()
|
|
: cu->list_in_scope);
|
|
|
|
sym->set_aclass_index (LOC_UNRESOLVED);
|
|
}
|
|
else if (!die_is_declaration (die, cu))
|
|
{
|
|
/* Use the default LOC_OPTIMIZED_OUT class. */
|
|
gdb_assert (sym->aclass () == LOC_OPTIMIZED_OUT);
|
|
if (!suppress_add)
|
|
list_to_add = cu->list_in_scope;
|
|
}
|
|
}
|
|
break;
|
|
case DW_TAG_formal_parameter:
|
|
{
|
|
/* If we are inside a function, mark this as an argument. If
|
|
not, we might be looking at an argument to an inlined function
|
|
when we do not have enough information to show inlined frames;
|
|
pretend it's a local variable in that case so that the user can
|
|
still see it. */
|
|
sym->set_domain (VAR_DOMAIN);
|
|
struct context_stack *curr
|
|
= cu->get_builder ()->get_current_context_stack ();
|
|
if (curr != nullptr && curr->name != nullptr)
|
|
sym->set_is_argument (1);
|
|
attr = dwarf2_attr (die, DW_AT_location, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
var_decode_location (attr, sym, cu);
|
|
}
|
|
attr = dwarf2_attr (die, DW_AT_const_value, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
dwarf2_const_value (attr, sym, cu);
|
|
}
|
|
|
|
list_to_add = cu->list_in_scope;
|
|
}
|
|
break;
|
|
case DW_TAG_unspecified_parameters:
|
|
/* From varargs functions; gdb doesn't seem to have any
|
|
interest in this information, so just ignore it for now.
|
|
(FIXME?) */
|
|
break;
|
|
case DW_TAG_template_type_param:
|
|
suppress_add = 1;
|
|
[[fallthrough]];
|
|
case DW_TAG_class_type:
|
|
case DW_TAG_interface_type:
|
|
case DW_TAG_structure_type:
|
|
case DW_TAG_union_type:
|
|
case DW_TAG_set_type:
|
|
case DW_TAG_enumeration_type:
|
|
case DW_TAG_namelist:
|
|
if (die->tag == DW_TAG_namelist)
|
|
{
|
|
sym->set_aclass_index (LOC_STATIC);
|
|
sym->set_domain (VAR_DOMAIN);
|
|
}
|
|
else if (cu->lang () == language_c
|
|
|| is_cplus_dialect (cu->lang ())
|
|
|| cu->lang () == language_objc
|
|
|| cu->lang () == language_opencl
|
|
|| cu->lang () == language_minimal)
|
|
{
|
|
/* These languages have a tag namespace. Note that
|
|
there's a special hack for C++ in the matching code,
|
|
so we don't need to enter a separate typedef for the
|
|
tag. */
|
|
sym->set_aclass_index (LOC_TYPEDEF);
|
|
sym->set_domain (STRUCT_DOMAIN);
|
|
}
|
|
else
|
|
{
|
|
/* Other languages don't have a tag namespace. */
|
|
sym->set_aclass_index (LOC_TYPEDEF);
|
|
sym->set_domain (TYPE_DOMAIN);
|
|
}
|
|
|
|
/* NOTE: carlton/2003-11-10: C++ class symbols shouldn't
|
|
really ever be static objects: otherwise, if you try
|
|
to, say, break of a class's method and you're in a file
|
|
which doesn't mention that class, it won't work unless
|
|
the check for all static symbols in lookup_symbol_aux
|
|
saves you. See the OtherFileClass tests in
|
|
gdb.c++/namespace.exp. */
|
|
|
|
if (!suppress_add)
|
|
{
|
|
buildsym_compunit *builder = cu->get_builder ();
|
|
list_to_add
|
|
= (cu->list_in_scope == builder->get_file_symbols ()
|
|
&& is_cplus_dialect (cu->lang ())
|
|
? builder->get_global_symbols ()
|
|
: cu->list_in_scope);
|
|
|
|
/* The semantics of C++ state that "struct foo {
|
|
... }" also defines a typedef for "foo". */
|
|
if (is_cplus_dialect (cu->lang ())
|
|
|| cu->lang () == language_ada
|
|
|| cu->lang () == language_d
|
|
|| cu->lang () == language_rust)
|
|
{
|
|
/* The symbol's name is already allocated along
|
|
with this objfile, so we don't need to
|
|
duplicate it for the type. */
|
|
if (sym->type ()->name () == 0)
|
|
sym->type ()->set_name (sym->search_name ());
|
|
}
|
|
}
|
|
break;
|
|
case DW_TAG_unspecified_type:
|
|
if (cu->lang () == language_ada)
|
|
break;
|
|
[[fallthrough]];
|
|
case DW_TAG_typedef:
|
|
case DW_TAG_array_type:
|
|
case DW_TAG_base_type:
|
|
case DW_TAG_subrange_type:
|
|
case DW_TAG_generic_subrange:
|
|
sym->set_aclass_index (LOC_TYPEDEF);
|
|
sym->set_domain (TYPE_DOMAIN);
|
|
list_to_add = cu->list_in_scope;
|
|
break;
|
|
case DW_TAG_enumerator:
|
|
sym->set_domain (VAR_DOMAIN);
|
|
attr = dwarf2_attr (die, DW_AT_const_value, cu);
|
|
if (attr != nullptr)
|
|
{
|
|
dwarf2_const_value (attr, sym, cu);
|
|
}
|
|
|
|
/* NOTE: carlton/2003-11-10: See comment above in the
|
|
DW_TAG_class_type, etc. block. */
|
|
|
|
list_to_add
|
|
= (cu->list_in_scope == cu->get_builder ()->get_file_symbols ()
|
|
&& is_cplus_dialect (cu->lang ())
|
|
? cu->get_builder ()->get_global_symbols ()
|
|
: cu->list_in_scope);
|
|
break;
|
|
case DW_TAG_imported_declaration:
|
|
case DW_TAG_namespace:
|
|
sym->set_domain (TYPE_DOMAIN);
|
|
sym->set_aclass_index (LOC_TYPEDEF);
|
|
list_to_add = cu->get_builder ()->get_global_symbols ();
|
|
break;
|
|
case DW_TAG_module:
|
|
sym->set_aclass_index (LOC_TYPEDEF);
|
|
sym->set_domain (MODULE_DOMAIN);
|
|
list_to_add = cu->get_builder ()->get_global_symbols ();
|
|
break;
|
|
case DW_TAG_common_block:
|
|
sym->set_aclass_index (LOC_COMMON_BLOCK);
|
|
sym->set_domain (COMMON_BLOCK_DOMAIN);
|
|
list_to_add = cu->list_in_scope;
|
|
break;
|
|
default:
|
|
/* Not a tag we recognize. Hopefully we aren't processing
|
|
trash data, but since we must specifically ignore things
|
|
we don't recognize, there is nothing else we should do at
|
|
this point. */
|
|
complaint (_("unsupported tag: '%s'"),
|
|
dwarf_tag_name (die->tag));
|
|
break;
|
|
}
|
|
|
|
if (suppress_add)
|
|
{
|
|
sym->hash_next = objfile->template_symbols;
|
|
objfile->template_symbols = sym;
|
|
list_to_add = NULL;
|
|
}
|
|
|
|
if (list_to_add != NULL)
|
|
add_symbol_to_list (sym, list_to_add);
|
|
|
|
/* For the benefit of old versions of GCC, check for anonymous
|
|
namespaces based on the demangled name. */
|
|
if (!cu->processing_has_namespace_info
|
|
&& is_cplus_dialect (cu->lang ()))
|
|
cp_scan_for_anonymous_namespaces (cu->get_builder (), sym, objfile);
|
|
}
|
|
return (sym);
|
|
}
|
|
|
|
/* Given an attr with a DW_FORM_dataN value in host byte order,
|
|
zero-extend it as appropriate for the symbol's type. The DWARF
|
|
standard (v4) is not entirely clear about the meaning of using
|
|
DW_FORM_dataN for a constant with a signed type, where the type is
|
|
wider than the data. The conclusion of a discussion on the DWARF
|
|
list was that this is unspecified. We choose to always zero-extend
|
|
because that is the interpretation long in use by GCC. */
|
|
|
|
static gdb_byte *
|
|
dwarf2_const_value_data (const struct attribute *attr, struct obstack *obstack,
|
|
struct dwarf2_cu *cu, LONGEST *value, int bits)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
enum bfd_endian byte_order = bfd_big_endian (objfile->obfd.get ()) ?
|
|
BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
|
|
LONGEST l = attr->constant_value (0);
|
|
|
|
if (bits < sizeof (*value) * 8)
|
|
{
|
|
l &= ((LONGEST) 1 << bits) - 1;
|
|
*value = l;
|
|
}
|
|
else if (bits == sizeof (*value) * 8)
|
|
*value = l;
|
|
else
|
|
{
|
|
gdb_byte *bytes = (gdb_byte *) obstack_alloc (obstack, bits / 8);
|
|
store_unsigned_integer (bytes, bits / 8, byte_order, l);
|
|
return bytes;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Read a constant value from an attribute. Either set *VALUE, or if
|
|
the value does not fit in *VALUE, set *BYTES - either already
|
|
allocated on the objfile obstack, or newly allocated on OBSTACK,
|
|
or, set *BATON, if we translated the constant to a location
|
|
expression. */
|
|
|
|
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)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct comp_unit_head *cu_header = &cu->header;
|
|
struct dwarf_block *blk;
|
|
enum bfd_endian byte_order = (bfd_big_endian (objfile->obfd.get ()) ?
|
|
BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE);
|
|
|
|
*value = 0;
|
|
*bytes = NULL;
|
|
*baton = NULL;
|
|
|
|
switch (attr->form)
|
|
{
|
|
case DW_FORM_addr:
|
|
case DW_FORM_addrx:
|
|
case DW_FORM_GNU_addr_index:
|
|
{
|
|
gdb_byte *data;
|
|
|
|
if (type->length () != cu_header->addr_size)
|
|
dwarf2_const_value_length_mismatch_complaint (name,
|
|
cu_header->addr_size,
|
|
type->length ());
|
|
/* Symbols of this form are reasonably rare, so we just
|
|
piggyback on the existing location code rather than writing
|
|
a new implementation of symbol_computed_ops. */
|
|
*baton = XOBNEW (obstack, struct dwarf2_locexpr_baton);
|
|
(*baton)->per_objfile = per_objfile;
|
|
(*baton)->per_cu = cu->per_cu;
|
|
gdb_assert ((*baton)->per_cu);
|
|
|
|
(*baton)->size = 2 + cu_header->addr_size;
|
|
data = (gdb_byte *) obstack_alloc (obstack, (*baton)->size);
|
|
(*baton)->data = data;
|
|
|
|
data[0] = DW_OP_addr;
|
|
store_unsigned_integer (&data[1], cu_header->addr_size,
|
|
byte_order, (ULONGEST) attr->as_address ());
|
|
data[cu_header->addr_size + 1] = DW_OP_stack_value;
|
|
}
|
|
break;
|
|
case DW_FORM_string:
|
|
case DW_FORM_strp:
|
|
case DW_FORM_strx:
|
|
case DW_FORM_GNU_str_index:
|
|
case DW_FORM_GNU_strp_alt:
|
|
/* The string is already allocated on the objfile obstack, point
|
|
directly to it. */
|
|
*bytes = (const gdb_byte *) attr->as_string ();
|
|
break;
|
|
case DW_FORM_block1:
|
|
case DW_FORM_block2:
|
|
case DW_FORM_block4:
|
|
case DW_FORM_block:
|
|
case DW_FORM_exprloc:
|
|
case DW_FORM_data16:
|
|
blk = attr->as_block ();
|
|
if (type->length () != blk->size)
|
|
dwarf2_const_value_length_mismatch_complaint (name, blk->size,
|
|
type->length ());
|
|
*bytes = blk->data;
|
|
break;
|
|
|
|
/* The DW_AT_const_value attributes are supposed to carry the
|
|
symbol's value "represented as it would be on the target
|
|
architecture." By the time we get here, it's already been
|
|
converted to host endianness, so we just need to sign- or
|
|
zero-extend it as appropriate. */
|
|
case DW_FORM_data1:
|
|
*bytes = dwarf2_const_value_data (attr, obstack, cu, value, 8);
|
|
break;
|
|
case DW_FORM_data2:
|
|
*bytes = dwarf2_const_value_data (attr, obstack, cu, value, 16);
|
|
break;
|
|
case DW_FORM_data4:
|
|
*bytes = dwarf2_const_value_data (attr, obstack, cu, value, 32);
|
|
break;
|
|
case DW_FORM_data8:
|
|
*bytes = dwarf2_const_value_data (attr, obstack, cu, value, 64);
|
|
break;
|
|
|
|
case DW_FORM_sdata:
|
|
case DW_FORM_implicit_const:
|
|
*value = attr->as_signed ();
|
|
break;
|
|
|
|
case DW_FORM_udata:
|
|
*value = attr->as_unsigned ();
|
|
break;
|
|
|
|
default:
|
|
complaint (_("unsupported const value attribute form: '%s'"),
|
|
dwarf_form_name (attr->form));
|
|
*value = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* Copy constant value from an attribute to a symbol. */
|
|
|
|
static void
|
|
dwarf2_const_value (const struct attribute *attr, struct symbol *sym,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
LONGEST value;
|
|
const gdb_byte *bytes;
|
|
struct dwarf2_locexpr_baton *baton;
|
|
|
|
dwarf2_const_value_attr (attr, sym->type (),
|
|
sym->print_name (),
|
|
&objfile->objfile_obstack, cu,
|
|
&value, &bytes, &baton);
|
|
|
|
if (baton != NULL)
|
|
{
|
|
SYMBOL_LOCATION_BATON (sym) = baton;
|
|
sym->set_aclass_index (dwarf2_locexpr_index);
|
|
}
|
|
else if (bytes != NULL)
|
|
{
|
|
sym->set_value_bytes (bytes);
|
|
sym->set_aclass_index (LOC_CONST_BYTES);
|
|
}
|
|
else
|
|
{
|
|
sym->set_value_longest (value);
|
|
sym->set_aclass_index (LOC_CONST);
|
|
}
|
|
}
|
|
|
|
/* Return the type of the die in question using its DW_AT_type attribute. */
|
|
|
|
static struct type *
|
|
die_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *type_attr;
|
|
|
|
type_attr = dwarf2_attr (die, DW_AT_type, cu);
|
|
if (!type_attr)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
/* A missing DW_AT_type represents a void type. */
|
|
return builtin_type (objfile)->builtin_void;
|
|
}
|
|
|
|
return lookup_die_type (die, type_attr, cu);
|
|
}
|
|
|
|
/* True iff CU's producer generates GNAT Ada auxiliary information
|
|
that allows to find parallel types through that information instead
|
|
of having to do expensive parallel lookups by type name. */
|
|
|
|
static int
|
|
need_gnat_info (struct dwarf2_cu *cu)
|
|
{
|
|
/* Assume that the Ada compiler was GNAT, which always produces
|
|
the auxiliary information. */
|
|
return (cu->lang () == language_ada);
|
|
}
|
|
|
|
/* Return the auxiliary type of the die in question using its
|
|
DW_AT_GNAT_descriptive_type attribute. Returns NULL if the
|
|
attribute is not present. */
|
|
|
|
static struct type *
|
|
die_descriptive_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *type_attr;
|
|
|
|
type_attr = dwarf2_attr (die, DW_AT_GNAT_descriptive_type, cu);
|
|
if (!type_attr)
|
|
return NULL;
|
|
|
|
return lookup_die_type (die, type_attr, cu);
|
|
}
|
|
|
|
/* If DIE has a descriptive_type attribute, then set the TYPE's
|
|
descriptive type accordingly. */
|
|
|
|
static void
|
|
set_descriptive_type (struct type *type, struct die_info *die,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
struct type *descriptive_type = die_descriptive_type (die, cu);
|
|
|
|
if (descriptive_type)
|
|
{
|
|
ALLOCATE_GNAT_AUX_TYPE (type);
|
|
TYPE_DESCRIPTIVE_TYPE (type) = descriptive_type;
|
|
}
|
|
}
|
|
|
|
/* Return the containing type of the die in question using its
|
|
DW_AT_containing_type attribute. */
|
|
|
|
static struct type *
|
|
die_containing_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *type_attr;
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
|
|
type_attr = dwarf2_attr (die, DW_AT_containing_type, cu);
|
|
if (!type_attr)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Problem turning containing type into gdb type "
|
|
"[in module %s]"),
|
|
objfile_name (objfile));
|
|
|
|
return lookup_die_type (die, type_attr, cu);
|
|
}
|
|
|
|
/* Return an error marker type to use for the ill formed type in DIE/CU. */
|
|
|
|
static struct type *
|
|
build_error_marker_type (struct dwarf2_cu *cu, struct die_info *die)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
char *saved;
|
|
|
|
std::string message
|
|
= string_printf (_("<unknown type in %s, CU %s, DIE %s>"),
|
|
objfile_name (objfile),
|
|
sect_offset_str (cu->header.sect_off),
|
|
sect_offset_str (die->sect_off));
|
|
saved = obstack_strdup (&objfile->objfile_obstack, message);
|
|
|
|
return type_allocator (objfile, cu->lang ()).new_type (TYPE_CODE_ERROR,
|
|
0, saved);
|
|
}
|
|
|
|
/* Look up the type of DIE in CU using its type attribute ATTR.
|
|
ATTR must be one of: DW_AT_type, DW_AT_GNAT_descriptive_type,
|
|
DW_AT_containing_type.
|
|
If there is no type substitute an error marker. */
|
|
|
|
static struct type *
|
|
lookup_die_type (struct die_info *die, const struct attribute *attr,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct type *this_type;
|
|
|
|
gdb_assert (attr->name == DW_AT_type
|
|
|| attr->name == DW_AT_GNAT_descriptive_type
|
|
|| attr->name == DW_AT_containing_type);
|
|
|
|
/* First see if we have it cached. */
|
|
|
|
if (attr->form == DW_FORM_GNU_ref_alt)
|
|
{
|
|
struct dwarf2_per_cu_data *per_cu;
|
|
sect_offset sect_off = attr->get_ref_die_offset ();
|
|
|
|
per_cu = dwarf2_find_containing_comp_unit (sect_off, 1,
|
|
per_objfile->per_bfd);
|
|
this_type = get_die_type_at_offset (sect_off, per_cu, per_objfile);
|
|
}
|
|
else if (attr->form_is_ref ())
|
|
{
|
|
sect_offset sect_off = attr->get_ref_die_offset ();
|
|
|
|
this_type = get_die_type_at_offset (sect_off, cu->per_cu, per_objfile);
|
|
}
|
|
else if (attr->form == DW_FORM_ref_sig8)
|
|
{
|
|
ULONGEST signature = attr->as_signature ();
|
|
|
|
return get_signatured_type (die, signature, cu);
|
|
}
|
|
else
|
|
{
|
|
complaint (_(DWARF_ERROR_PREFIX
|
|
"Bad type attribute %s in DIE at %s [in module %s]"),
|
|
dwarf_attr_name (attr->name), sect_offset_str (die->sect_off),
|
|
objfile_name (objfile));
|
|
return build_error_marker_type (cu, die);
|
|
}
|
|
|
|
/* If not cached we need to read it in. */
|
|
|
|
if (this_type == NULL)
|
|
{
|
|
struct die_info *type_die = NULL;
|
|
struct dwarf2_cu *type_cu = cu;
|
|
|
|
if (attr->form_is_ref ())
|
|
type_die = follow_die_ref (die, attr, &type_cu);
|
|
if (type_die == NULL)
|
|
return build_error_marker_type (cu, die);
|
|
/* If we find the type now, it's probably because the type came
|
|
from an inter-CU reference and the type's CU got expanded before
|
|
ours. */
|
|
this_type = read_type_die (type_die, type_cu);
|
|
}
|
|
|
|
/* If we still don't have a type use an error marker. */
|
|
|
|
if (this_type == NULL)
|
|
return build_error_marker_type (cu, die);
|
|
|
|
return this_type;
|
|
}
|
|
|
|
/* Return the type in DIE, CU.
|
|
Returns NULL for invalid types.
|
|
|
|
This first does a lookup in die_type_hash,
|
|
and only reads the die in if necessary.
|
|
|
|
NOTE: This can be called when reading in partial or full symbols. */
|
|
|
|
static struct type *
|
|
read_type_die (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *this_type;
|
|
|
|
this_type = get_die_type (die, cu);
|
|
if (this_type)
|
|
return this_type;
|
|
|
|
return read_type_die_1 (die, cu);
|
|
}
|
|
|
|
/* Read the type in DIE, CU.
|
|
Returns NULL for invalid types. */
|
|
|
|
static struct type *
|
|
read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct type *this_type = NULL;
|
|
|
|
switch (die->tag)
|
|
{
|
|
case DW_TAG_class_type:
|
|
case DW_TAG_interface_type:
|
|
case DW_TAG_structure_type:
|
|
case DW_TAG_union_type:
|
|
this_type = read_structure_type (die, cu);
|
|
break;
|
|
case DW_TAG_enumeration_type:
|
|
this_type = read_enumeration_type (die, cu);
|
|
break;
|
|
case DW_TAG_entry_point:
|
|
case DW_TAG_subprogram:
|
|
case DW_TAG_subroutine_type:
|
|
case DW_TAG_inlined_subroutine:
|
|
this_type = read_subroutine_type (die, cu);
|
|
break;
|
|
case DW_TAG_array_type:
|
|
this_type = read_array_type (die, cu);
|
|
break;
|
|
case DW_TAG_set_type:
|
|
this_type = read_set_type (die, cu);
|
|
break;
|
|
case DW_TAG_pointer_type:
|
|
this_type = read_tag_pointer_type (die, cu);
|
|
break;
|
|
case DW_TAG_ptr_to_member_type:
|
|
this_type = read_tag_ptr_to_member_type (die, cu);
|
|
break;
|
|
case DW_TAG_reference_type:
|
|
this_type = read_tag_reference_type (die, cu, TYPE_CODE_REF);
|
|
break;
|
|
case DW_TAG_rvalue_reference_type:
|
|
this_type = read_tag_reference_type (die, cu, TYPE_CODE_RVALUE_REF);
|
|
break;
|
|
case DW_TAG_const_type:
|
|
this_type = read_tag_const_type (die, cu);
|
|
break;
|
|
case DW_TAG_volatile_type:
|
|
this_type = read_tag_volatile_type (die, cu);
|
|
break;
|
|
case DW_TAG_restrict_type:
|
|
this_type = read_tag_restrict_type (die, cu);
|
|
break;
|
|
case DW_TAG_string_type:
|
|
this_type = read_tag_string_type (die, cu);
|
|
break;
|
|
case DW_TAG_typedef:
|
|
this_type = read_typedef (die, cu);
|
|
break;
|
|
case DW_TAG_generic_subrange:
|
|
case DW_TAG_subrange_type:
|
|
this_type = read_subrange_type (die, cu);
|
|
break;
|
|
case DW_TAG_base_type:
|
|
this_type = read_base_type (die, cu);
|
|
break;
|
|
case DW_TAG_unspecified_type:
|
|
this_type = read_unspecified_type (die, cu);
|
|
break;
|
|
case DW_TAG_namespace:
|
|
this_type = read_namespace_type (die, cu);
|
|
break;
|
|
case DW_TAG_module:
|
|
this_type = read_module_type (die, cu);
|
|
break;
|
|
case DW_TAG_atomic_type:
|
|
this_type = read_tag_atomic_type (die, cu);
|
|
break;
|
|
default:
|
|
complaint (_("unexpected tag in read_type_die: '%s'"),
|
|
dwarf_tag_name (die->tag));
|
|
break;
|
|
}
|
|
|
|
return this_type;
|
|
}
|
|
|
|
/* See if we can figure out if the class lives in a namespace. We do
|
|
this by looking for a member function; its demangled name will
|
|
contain namespace info, if there is any.
|
|
Return the computed name or NULL.
|
|
Space for the result is allocated on the objfile's obstack.
|
|
This is the full-die version of guess_partial_die_structure_name.
|
|
In this case we know DIE has no useful parent. */
|
|
|
|
static const char *
|
|
guess_full_die_structure_name (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct die_info *spec_die;
|
|
struct dwarf2_cu *spec_cu;
|
|
struct die_info *child;
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
|
|
spec_cu = cu;
|
|
spec_die = die_specification (die, &spec_cu);
|
|
if (spec_die != NULL)
|
|
{
|
|
die = spec_die;
|
|
cu = spec_cu;
|
|
}
|
|
|
|
for (child = die->child;
|
|
child != NULL;
|
|
child = child->sibling)
|
|
{
|
|
if (child->tag == DW_TAG_subprogram)
|
|
{
|
|
const char *linkage_name = dw2_linkage_name (child, cu);
|
|
|
|
if (linkage_name != NULL)
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> actual_name
|
|
(cu->language_defn->class_name_from_physname (linkage_name));
|
|
const char *name = NULL;
|
|
|
|
if (actual_name != NULL)
|
|
{
|
|
const char *die_name = dwarf2_name (die, cu);
|
|
|
|
if (die_name != NULL
|
|
&& strcmp (die_name, actual_name.get ()) != 0)
|
|
{
|
|
/* Strip off the class name from the full name.
|
|
We want the prefix. */
|
|
int die_name_len = strlen (die_name);
|
|
int actual_name_len = strlen (actual_name.get ());
|
|
const char *ptr = actual_name.get ();
|
|
|
|
/* Test for '::' as a sanity check. */
|
|
if (actual_name_len > die_name_len + 2
|
|
&& ptr[actual_name_len - die_name_len - 1] == ':')
|
|
name = obstack_strndup (
|
|
&objfile->per_bfd->storage_obstack,
|
|
ptr, actual_name_len - die_name_len - 2);
|
|
}
|
|
}
|
|
return name;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* GCC might emit a nameless typedef that has a linkage name. Determine the
|
|
prefix part in such case. See
|
|
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47510. */
|
|
|
|
static const char *
|
|
anonymous_struct_prefix (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
const char *base;
|
|
|
|
if (die->tag != DW_TAG_class_type && die->tag != DW_TAG_interface_type
|
|
&& die->tag != DW_TAG_structure_type && die->tag != DW_TAG_union_type)
|
|
return NULL;
|
|
|
|
if (dwarf2_string_attr (die, DW_AT_name, cu) != NULL)
|
|
return NULL;
|
|
|
|
attr = dw2_linkage_name_attr (die, cu);
|
|
const char *attr_name = attr->as_string ();
|
|
if (attr == NULL || attr_name == NULL)
|
|
return NULL;
|
|
|
|
/* dwarf2_name had to be already called. */
|
|
gdb_assert (attr->canonical_string_p ());
|
|
|
|
/* Strip the base name, keep any leading namespaces/classes. */
|
|
base = strrchr (attr_name, ':');
|
|
if (base == NULL || base == attr_name || base[-1] != ':')
|
|
return "";
|
|
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
return obstack_strndup (&objfile->per_bfd->storage_obstack,
|
|
attr_name,
|
|
&base[-1] - attr_name);
|
|
}
|
|
|
|
/* Return the name of the namespace/class that DIE is defined within,
|
|
or "" if we can't tell. The caller should not xfree the result.
|
|
|
|
For example, if we're within the method foo() in the following
|
|
code:
|
|
|
|
namespace N {
|
|
class C {
|
|
void foo () {
|
|
}
|
|
};
|
|
}
|
|
|
|
then determine_prefix on foo's die will return "N::C". */
|
|
|
|
static const char *
|
|
determine_prefix (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct die_info *parent, *spec_die;
|
|
struct dwarf2_cu *spec_cu;
|
|
struct type *parent_type;
|
|
const char *retval;
|
|
|
|
if (!is_cplus_dialect (cu->lang ())
|
|
&& cu->lang () != language_fortran
|
|
&& cu->lang () != language_d
|
|
&& cu->lang () != language_rust)
|
|
return "";
|
|
|
|
retval = anonymous_struct_prefix (die, cu);
|
|
if (retval)
|
|
return retval;
|
|
|
|
/* We have to be careful in the presence of DW_AT_specification.
|
|
For example, with GCC 3.4, given the code
|
|
|
|
namespace N {
|
|
void foo() {
|
|
// Definition of N::foo.
|
|
}
|
|
}
|
|
|
|
then we'll have a tree of DIEs like this:
|
|
|
|
1: DW_TAG_compile_unit
|
|
2: DW_TAG_namespace // N
|
|
3: DW_TAG_subprogram // declaration of N::foo
|
|
4: DW_TAG_subprogram // definition of N::foo
|
|
DW_AT_specification // refers to die #3
|
|
|
|
Thus, when processing die #4, we have to pretend that we're in
|
|
the context of its DW_AT_specification, namely the context of die
|
|
#3. */
|
|
spec_cu = cu;
|
|
spec_die = die_specification (die, &spec_cu);
|
|
if (spec_die == NULL)
|
|
parent = die->parent;
|
|
else
|
|
{
|
|
parent = spec_die->parent;
|
|
cu = spec_cu;
|
|
}
|
|
|
|
if (parent == NULL)
|
|
return "";
|
|
else if (parent->building_fullname)
|
|
{
|
|
const char *name;
|
|
const char *parent_name;
|
|
|
|
/* It has been seen on RealView 2.2 built binaries,
|
|
DW_TAG_template_type_param types actually _defined_ as
|
|
children of the parent class:
|
|
|
|
enum E {};
|
|
template class <class Enum> Class{};
|
|
Class<enum E> class_e;
|
|
|
|
1: DW_TAG_class_type (Class)
|
|
2: DW_TAG_enumeration_type (E)
|
|
3: DW_TAG_enumerator (enum1:0)
|
|
3: DW_TAG_enumerator (enum2:1)
|
|
...
|
|
2: DW_TAG_template_type_param
|
|
DW_AT_type DW_FORM_ref_udata (E)
|
|
|
|
Besides being broken debug info, it can put GDB into an
|
|
infinite loop. Consider:
|
|
|
|
When we're building the full name for Class<E>, we'll start
|
|
at Class, and go look over its template type parameters,
|
|
finding E. We'll then try to build the full name of E, and
|
|
reach here. We're now trying to build the full name of E,
|
|
and look over the parent DIE for containing scope. In the
|
|
broken case, if we followed the parent DIE of E, we'd again
|
|
find Class, and once again go look at its template type
|
|
arguments, etc., etc. Simply don't consider such parent die
|
|
as source-level parent of this die (it can't be, the language
|
|
doesn't allow it), and break the loop here. */
|
|
name = dwarf2_name (die, cu);
|
|
parent_name = dwarf2_name (parent, cu);
|
|
complaint (_("template param type '%s' defined within parent '%s'"),
|
|
name ? name : "<unknown>",
|
|
parent_name ? parent_name : "<unknown>");
|
|
return "";
|
|
}
|
|
else
|
|
switch (parent->tag)
|
|
{
|
|
case DW_TAG_namespace:
|
|
parent_type = read_type_die (parent, cu);
|
|
/* GCC 4.0 and 4.1 had a bug (PR c++/28460) where they generated bogus
|
|
DW_TAG_namespace DIEs with a name of "::" for the global namespace.
|
|
Work around this problem here. */
|
|
if (is_cplus_dialect (cu->lang ())
|
|
&& strcmp (parent_type->name (), "::") == 0)
|
|
return "";
|
|
/* We give a name to even anonymous namespaces. */
|
|
return parent_type->name ();
|
|
case DW_TAG_class_type:
|
|
case DW_TAG_interface_type:
|
|
case DW_TAG_structure_type:
|
|
case DW_TAG_union_type:
|
|
case DW_TAG_module:
|
|
parent_type = read_type_die (parent, cu);
|
|
if (parent_type->name () != NULL)
|
|
return parent_type->name ();
|
|
else
|
|
/* An anonymous structure is only allowed non-static data
|
|
members; no typedefs, no member functions, et cetera.
|
|
So it does not need a prefix. */
|
|
return "";
|
|
case DW_TAG_compile_unit:
|
|
case DW_TAG_partial_unit:
|
|
/* gcc-4.5 -gdwarf-4 can drop the enclosing namespace. Cope. */
|
|
if (is_cplus_dialect (cu->lang ())
|
|
&& !per_objfile->per_bfd->types.empty ()
|
|
&& die->child != NULL
|
|
&& (die->tag == DW_TAG_class_type
|
|
|| die->tag == DW_TAG_structure_type
|
|
|| die->tag == DW_TAG_union_type))
|
|
{
|
|
const char *name = guess_full_die_structure_name (die, cu);
|
|
if (name != NULL)
|
|
return name;
|
|
}
|
|
return "";
|
|
case DW_TAG_subprogram:
|
|
/* Nested subroutines in Fortran get a prefix with the name
|
|
of the parent's subroutine. Entry points are prefixed by the
|
|
parent's namespace. */
|
|
if (cu->lang () == language_fortran)
|
|
{
|
|
if ((die->tag == DW_TAG_subprogram)
|
|
&& (dwarf2_name (parent, cu) != NULL))
|
|
return dwarf2_name (parent, cu);
|
|
else if (die->tag == DW_TAG_entry_point)
|
|
return determine_prefix (parent, cu);
|
|
}
|
|
return "";
|
|
case DW_TAG_enumeration_type:
|
|
parent_type = read_type_die (parent, cu);
|
|
if (parent_type->is_declared_class ())
|
|
{
|
|
if (parent_type->name () != NULL)
|
|
return parent_type->name ();
|
|
return "";
|
|
}
|
|
[[fallthrough]];
|
|
default:
|
|
return determine_prefix (parent, cu);
|
|
}
|
|
}
|
|
|
|
/* Return a newly-allocated string formed by concatenating PREFIX and
|
|
SUFFIX with appropriate separator. If PREFIX or SUFFIX is NULL or
|
|
empty, then simply copy the SUFFIX or PREFIX, respectively. The CU
|
|
argument is used to determine the language and hence, the
|
|
appropriate separator. */
|
|
|
|
static gdb::unique_xmalloc_ptr<char>
|
|
typename_concat (const char *prefix, const char *suffix, int physname,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
const char *lead = "";
|
|
const char *sep;
|
|
|
|
if (suffix == NULL || suffix[0] == '\0'
|
|
|| prefix == NULL || prefix[0] == '\0')
|
|
sep = "";
|
|
else if (cu->lang () == language_d)
|
|
{
|
|
/* For D, the 'main' function could be defined in any module, but it
|
|
should never be prefixed. */
|
|
if (strcmp (suffix, "D main") == 0)
|
|
{
|
|
prefix = "";
|
|
sep = "";
|
|
}
|
|
else
|
|
sep = ".";
|
|
}
|
|
else if (cu->lang () == language_fortran && physname)
|
|
{
|
|
/* This is gfortran specific mangling. Normally DW_AT_linkage_name or
|
|
DW_AT_MIPS_linkage_name is preferred and used instead. */
|
|
|
|
lead = "__";
|
|
sep = "_MOD_";
|
|
}
|
|
else
|
|
sep = "::";
|
|
|
|
if (prefix == NULL)
|
|
prefix = "";
|
|
if (suffix == NULL)
|
|
suffix = "";
|
|
|
|
return gdb::unique_xmalloc_ptr<char> (concat (lead, prefix, sep, suffix,
|
|
nullptr));
|
|
}
|
|
|
|
/* Return a generic name for a DW_TAG_template_type_param or
|
|
DW_TAG_template_value_param tag, missing a DW_AT_name attribute. We do this
|
|
per parent, so each function/class/struct template will have their own set
|
|
of template parameters named <unnnamed0>, <unnamed1>, ... where the
|
|
enumeration starts at 0 and represents the position of the template tag in
|
|
the list of unnamed template tags for this parent, counting both, type and
|
|
value tags. */
|
|
|
|
static const char *
|
|
unnamed_template_tag_name (die_info *die, dwarf2_cu *cu)
|
|
{
|
|
if (die->parent == nullptr)
|
|
return nullptr;
|
|
|
|
/* Count the parent types unnamed template type and value children until, we
|
|
arrive at our entry. */
|
|
size_t nth_unnamed = 0;
|
|
|
|
die_info *child = die->parent->child;
|
|
while (child != die)
|
|
{
|
|
gdb_assert (child != nullptr);
|
|
if (child->tag == DW_TAG_template_type_param
|
|
|| child->tag == DW_TAG_template_value_param)
|
|
{
|
|
if (dwarf2_attr (child, DW_AT_name, cu) == nullptr)
|
|
++nth_unnamed;
|
|
}
|
|
child = child->sibling;
|
|
}
|
|
|
|
const std::string name_str = "<unnamed" + std::to_string (nth_unnamed) + ">";
|
|
return cu->per_objfile->objfile->intern (name_str.c_str ());
|
|
}
|
|
|
|
/* Get name of a die, return NULL if not found. */
|
|
|
|
static const char *
|
|
dwarf2_canonicalize_name (const char *name, struct dwarf2_cu *cu,
|
|
struct objfile *objfile)
|
|
{
|
|
if (name == nullptr)
|
|
return name;
|
|
|
|
if (is_cplus_dialect (cu->lang ()))
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> canon_name
|
|
= cp_canonicalize_string (name);
|
|
|
|
if (canon_name != nullptr)
|
|
name = objfile->intern (canon_name.get ());
|
|
}
|
|
else if (cu->lang () == language_c)
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> canon_name
|
|
= c_canonicalize_name (name);
|
|
|
|
if (canon_name != nullptr)
|
|
name = objfile->intern (canon_name.get ());
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
/* Get name of a die, return NULL if not found.
|
|
Anonymous namespaces are converted to their magic string. */
|
|
|
|
static const char *
|
|
dwarf2_name (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
struct attribute *attr;
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_name, cu);
|
|
const char *attr_name = attr == nullptr ? nullptr : attr->as_string ();
|
|
if (attr_name == nullptr
|
|
&& die->tag != DW_TAG_namespace
|
|
&& die->tag != DW_TAG_class_type
|
|
&& die->tag != DW_TAG_interface_type
|
|
&& die->tag != DW_TAG_structure_type
|
|
&& die->tag != DW_TAG_namelist
|
|
&& die->tag != DW_TAG_union_type
|
|
&& die->tag != DW_TAG_template_type_param
|
|
&& die->tag != DW_TAG_template_value_param)
|
|
return NULL;
|
|
|
|
switch (die->tag)
|
|
{
|
|
/* A member's name should not be canonicalized. This is a bit
|
|
of a hack, in that normally it should not be possible to run
|
|
into this situation; however, the dw2-unusual-field-names.exp
|
|
test creates custom DWARF that does. */
|
|
case DW_TAG_member:
|
|
case DW_TAG_compile_unit:
|
|
case DW_TAG_partial_unit:
|
|
/* Compilation units have a DW_AT_name that is a filename, not
|
|
a source language identifier. */
|
|
case DW_TAG_enumeration_type:
|
|
case DW_TAG_enumerator:
|
|
/* These tags always have simple identifiers already; no need
|
|
to canonicalize them. */
|
|
return attr_name;
|
|
|
|
case DW_TAG_namespace:
|
|
if (attr_name != nullptr)
|
|
return attr_name;
|
|
return CP_ANONYMOUS_NAMESPACE_STR;
|
|
|
|
/* DWARF does not actually require template tags to have a name. */
|
|
case DW_TAG_template_type_param:
|
|
case DW_TAG_template_value_param:
|
|
if (attr_name == nullptr)
|
|
return unnamed_template_tag_name (die, cu);
|
|
[[fallthrough]];
|
|
case DW_TAG_class_type:
|
|
case DW_TAG_interface_type:
|
|
case DW_TAG_structure_type:
|
|
case DW_TAG_union_type:
|
|
case DW_TAG_namelist:
|
|
/* Some GCC versions emit spurious DW_AT_name attributes for unnamed
|
|
structures or unions. These were of the form "._%d" in GCC 4.1,
|
|
or simply "<anonymous struct>" or "<anonymous union>" in GCC 4.3
|
|
and GCC 4.4. We work around this problem by ignoring these. */
|
|
if (attr_name != nullptr
|
|
&& (startswith (attr_name, "._")
|
|
|| startswith (attr_name, "<anonymous")))
|
|
return NULL;
|
|
|
|
/* GCC might emit a nameless typedef that has a linkage name. See
|
|
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47510. */
|
|
if (!attr || attr_name == NULL)
|
|
{
|
|
attr = dw2_linkage_name_attr (die, cu);
|
|
attr_name = attr == nullptr ? nullptr : attr->as_string ();
|
|
if (attr == NULL || attr_name == NULL)
|
|
return NULL;
|
|
|
|
/* Avoid demangling attr_name the second time on a second
|
|
call for the same DIE. */
|
|
if (!attr->canonical_string_p ())
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> demangled
|
|
(gdb_demangle (attr_name, DMGL_TYPES));
|
|
if (demangled == nullptr)
|
|
return nullptr;
|
|
|
|
attr->set_string_canonical (objfile->intern (demangled.get ()));
|
|
attr_name = attr->as_string ();
|
|
}
|
|
|
|
/* Strip any leading namespaces/classes, keep only the
|
|
base name. DW_AT_name for named DIEs does not
|
|
contain the prefixes. */
|
|
const char *base = strrchr (attr_name, ':');
|
|
if (base && base > attr_name && base[-1] == ':')
|
|
return &base[1];
|
|
else
|
|
return attr_name;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!attr->canonical_string_p ())
|
|
{
|
|
attr_name = gdb_hip_test_mode_frob_names (cu->per_objfile->objfile,
|
|
attr_name);
|
|
attr->set_string_canonical (dwarf2_canonicalize_name (attr_name, cu,
|
|
objfile));
|
|
}
|
|
return attr->as_string ();
|
|
}
|
|
|
|
/* Return the die that this die in an extension of, or NULL if there
|
|
is none. *EXT_CU is the CU containing DIE on input, and the CU
|
|
containing the return value on output. */
|
|
|
|
static struct die_info *
|
|
dwarf2_extension (struct die_info *die, struct dwarf2_cu **ext_cu)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
attr = dwarf2_attr (die, DW_AT_extension, *ext_cu);
|
|
if (attr == NULL)
|
|
return NULL;
|
|
|
|
return follow_die_ref (die, attr, ext_cu);
|
|
}
|
|
|
|
/* Follow reference or signature attribute ATTR of SRC_DIE.
|
|
On entry *REF_CU is the CU of SRC_DIE.
|
|
On exit *REF_CU is the CU of the result. */
|
|
|
|
static struct die_info *
|
|
follow_die_ref_or_sig (struct die_info *src_die, const struct attribute *attr,
|
|
struct dwarf2_cu **ref_cu)
|
|
{
|
|
struct die_info *die;
|
|
|
|
if (attr->form_is_ref ())
|
|
die = follow_die_ref (src_die, attr, ref_cu);
|
|
else if (attr->form == DW_FORM_ref_sig8)
|
|
die = follow_die_sig (src_die, attr, ref_cu);
|
|
else
|
|
{
|
|
src_die->error_dump ();
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Expected reference attribute [in module %s]"),
|
|
objfile_name ((*ref_cu)->per_objfile->objfile));
|
|
}
|
|
|
|
return die;
|
|
}
|
|
|
|
/* Follow reference OFFSET.
|
|
On entry *REF_CU is the CU of the source die referencing OFFSET.
|
|
On exit *REF_CU is the CU of the result.
|
|
Returns NULL if OFFSET is invalid. */
|
|
|
|
static struct die_info *
|
|
follow_die_offset (sect_offset sect_off, int offset_in_dwz,
|
|
struct dwarf2_cu **ref_cu)
|
|
{
|
|
struct dwarf2_cu *target_cu, *cu = *ref_cu;
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
gdb_assert (cu->per_cu != NULL);
|
|
|
|
target_cu = cu;
|
|
|
|
dwarf_read_debug_printf_v ("source CU offset: %s, target offset: %s, "
|
|
"source CU contains target offset: %d",
|
|
sect_offset_str (cu->per_cu->sect_off),
|
|
sect_offset_str (sect_off),
|
|
cu->header.offset_in_cu_p (sect_off));
|
|
|
|
if (cu->per_cu->is_debug_types)
|
|
{
|
|
/* .debug_types CUs cannot reference anything outside their CU.
|
|
If they need to, they have to reference a signatured type via
|
|
DW_FORM_ref_sig8. */
|
|
if (!cu->header.offset_in_cu_p (sect_off))
|
|
return NULL;
|
|
}
|
|
else if (offset_in_dwz != cu->per_cu->is_dwz
|
|
|| !cu->header.offset_in_cu_p (sect_off))
|
|
{
|
|
struct dwarf2_per_cu_data *per_cu;
|
|
|
|
per_cu = dwarf2_find_containing_comp_unit (sect_off, offset_in_dwz,
|
|
per_objfile->per_bfd);
|
|
|
|
dwarf_read_debug_printf_v ("target CU offset: %s, "
|
|
"target CU DIEs loaded: %d",
|
|
sect_offset_str (per_cu->sect_off),
|
|
per_objfile->get_cu (per_cu) != nullptr);
|
|
|
|
/* If necessary, add it to the queue and load its DIEs.
|
|
|
|
Even if maybe_queue_comp_unit doesn't require us to load the CU's DIEs,
|
|
it doesn't mean they are currently loaded. Since we require them
|
|
to be loaded, we must check for ourselves. */
|
|
if (maybe_queue_comp_unit (cu, per_cu, per_objfile, cu->lang ())
|
|
|| per_objfile->get_cu (per_cu) == nullptr)
|
|
load_full_comp_unit (per_cu, per_objfile, per_objfile->get_cu (per_cu),
|
|
false, cu->lang ());
|
|
|
|
target_cu = per_objfile->get_cu (per_cu);
|
|
if (target_cu == nullptr)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"cannot follow reference to DIE at %s"
|
|
" [in module %s]"),
|
|
sect_offset_str (sect_off),
|
|
objfile_name (per_objfile->objfile));
|
|
}
|
|
else if (cu->dies == NULL)
|
|
{
|
|
/* We're loading full DIEs during partial symbol reading. */
|
|
load_full_comp_unit (cu->per_cu, per_objfile, cu, false,
|
|
language_minimal);
|
|
}
|
|
|
|
*ref_cu = target_cu;
|
|
|
|
auto it = target_cu->die_hash.find (sect_off);
|
|
return it != target_cu->die_hash.end () ? *it : nullptr;
|
|
}
|
|
|
|
/* Follow reference attribute ATTR of SRC_DIE.
|
|
On entry *REF_CU is the CU of SRC_DIE.
|
|
On exit *REF_CU is the CU of the result. */
|
|
|
|
static struct die_info *
|
|
follow_die_ref (struct die_info *src_die, const struct attribute *attr,
|
|
struct dwarf2_cu **ref_cu)
|
|
{
|
|
sect_offset sect_off = attr->get_ref_die_offset ();
|
|
struct dwarf2_cu *cu = *ref_cu;
|
|
struct die_info *die;
|
|
|
|
if (attr->form != DW_FORM_GNU_ref_alt && src_die->sect_off == sect_off)
|
|
{
|
|
/* Self-reference, we're done. */
|
|
return src_die;
|
|
}
|
|
|
|
die = follow_die_offset (sect_off,
|
|
(attr->form == DW_FORM_GNU_ref_alt
|
|
|| cu->per_cu->is_dwz),
|
|
ref_cu);
|
|
if (!die)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Cannot find DIE at %s referenced from DIE at %s [in module %s]"),
|
|
sect_offset_str (sect_off), sect_offset_str (src_die->sect_off),
|
|
objfile_name (cu->per_objfile->objfile));
|
|
|
|
return die;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
struct dwarf2_locexpr_baton
|
|
dwarf2_fetch_die_loc_sect_off (sect_offset sect_off,
|
|
dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
gdb::function_view<CORE_ADDR ()> get_frame_pc,
|
|
bool resolve_abstract_p)
|
|
{
|
|
struct die_info *die;
|
|
struct attribute *attr;
|
|
struct dwarf2_locexpr_baton retval;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
|
|
dwarf2_cu *cu = per_objfile->get_cu (per_cu);
|
|
if (cu == nullptr)
|
|
cu = load_cu (per_cu, per_objfile, false);
|
|
|
|
if (cu == nullptr)
|
|
{
|
|
/* We shouldn't get here for a dummy CU, but don't crash on the user.
|
|
Instead just throw an error, not much else we can do. */
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Dummy CU at %s referenced [in module %s]"),
|
|
sect_offset_str (sect_off), objfile_name (objfile));
|
|
}
|
|
|
|
die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
|
|
if (!die)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Cannot find DIE at %s referenced [in module %s]"),
|
|
sect_offset_str (sect_off), objfile_name (objfile));
|
|
|
|
attr = dwarf2_attr (die, DW_AT_location, cu);
|
|
if (!attr && resolve_abstract_p
|
|
&& (per_objfile->per_bfd->abstract_to_concrete.find (die->sect_off)
|
|
!= per_objfile->per_bfd->abstract_to_concrete.end ()))
|
|
{
|
|
CORE_ADDR pc = get_frame_pc ();
|
|
|
|
for (const auto &cand_off
|
|
: per_objfile->per_bfd->abstract_to_concrete[die->sect_off])
|
|
{
|
|
struct dwarf2_cu *cand_cu = cu;
|
|
struct die_info *cand
|
|
= follow_die_offset (cand_off, per_cu->is_dwz, &cand_cu);
|
|
if (!cand
|
|
|| !cand->parent
|
|
|| cand->parent->tag != DW_TAG_subprogram)
|
|
continue;
|
|
|
|
unrelocated_addr unrel_low, unrel_high;
|
|
get_scope_pc_bounds (cand->parent, &unrel_low, &unrel_high, cu);
|
|
if (unrel_low == ((unrelocated_addr) -1))
|
|
continue;
|
|
CORE_ADDR pc_low = per_objfile->relocate (unrel_low);
|
|
CORE_ADDR pc_high = per_objfile->relocate (unrel_high);
|
|
if (!(pc_low <= pc && pc < pc_high))
|
|
continue;
|
|
|
|
die = cand;
|
|
attr = dwarf2_attr (die, DW_AT_location, cu);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!attr)
|
|
{
|
|
/* DWARF: "If there is no such attribute, then there is no effect.".
|
|
DATA is ignored if SIZE is 0. */
|
|
|
|
retval.data = NULL;
|
|
retval.size = 0;
|
|
}
|
|
else if (attr->form_is_section_offset ())
|
|
{
|
|
struct dwarf2_loclist_baton loclist_baton;
|
|
CORE_ADDR pc = get_frame_pc ();
|
|
size_t size;
|
|
|
|
fill_in_loclist_baton (cu, &loclist_baton, attr);
|
|
|
|
retval.data = dwarf2_find_location_expression (&loclist_baton,
|
|
&size, pc);
|
|
retval.size = size;
|
|
}
|
|
else
|
|
{
|
|
if (!attr->form_is_block ())
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"DIE at %s is neither DW_FORM_block* nor DW_FORM_exprloc"
|
|
" [in module %s]"),
|
|
sect_offset_str (sect_off), objfile_name (objfile));
|
|
|
|
struct dwarf_block *block = attr->as_block ();
|
|
retval.data = block->data;
|
|
retval.size = block->size;
|
|
}
|
|
retval.per_objfile = per_objfile;
|
|
retval.per_cu = cu->per_cu;
|
|
|
|
per_objfile->age_comp_units ();
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
struct dwarf2_locexpr_baton
|
|
dwarf2_fetch_die_loc_cu_off (cu_offset offset_in_cu,
|
|
dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
gdb::function_view<CORE_ADDR ()> get_frame_pc)
|
|
{
|
|
sect_offset sect_off = per_cu->sect_off + to_underlying (offset_in_cu);
|
|
|
|
return dwarf2_fetch_die_loc_sect_off (sect_off, per_cu, per_objfile,
|
|
get_frame_pc);
|
|
}
|
|
|
|
/* Write a constant of a given type as target-ordered bytes into
|
|
OBSTACK. */
|
|
|
|
static const gdb_byte *
|
|
write_constant_as_bytes (struct obstack *obstack,
|
|
enum bfd_endian byte_order,
|
|
struct type *type,
|
|
ULONGEST value,
|
|
LONGEST *len)
|
|
{
|
|
gdb_byte *result;
|
|
|
|
*len = type->length ();
|
|
result = (gdb_byte *) obstack_alloc (obstack, *len);
|
|
store_unsigned_integer (result, *len, byte_order, value);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
const gdb_byte *
|
|
dwarf2_fetch_constant_bytes (sect_offset sect_off,
|
|
dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
obstack *obstack,
|
|
LONGEST *len)
|
|
{
|
|
struct die_info *die;
|
|
struct attribute *attr;
|
|
const gdb_byte *result = NULL;
|
|
struct type *type;
|
|
LONGEST value;
|
|
enum bfd_endian byte_order;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
|
|
dwarf2_cu *cu = per_objfile->get_cu (per_cu);
|
|
if (cu == nullptr)
|
|
cu = load_cu (per_cu, per_objfile, false);
|
|
|
|
if (cu == nullptr)
|
|
{
|
|
/* We shouldn't get here for a dummy CU, but don't crash on the user.
|
|
Instead just throw an error, not much else we can do. */
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Dummy CU at %s referenced [in module %s]"),
|
|
sect_offset_str (sect_off), objfile_name (objfile));
|
|
}
|
|
|
|
die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
|
|
if (!die)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Cannot find DIE at %s referenced [in module %s]"),
|
|
sect_offset_str (sect_off), objfile_name (objfile));
|
|
|
|
attr = dwarf2_attr (die, DW_AT_const_value, cu);
|
|
if (attr == NULL)
|
|
return NULL;
|
|
|
|
byte_order = (bfd_big_endian (objfile->obfd.get ())
|
|
? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE);
|
|
|
|
switch (attr->form)
|
|
{
|
|
case DW_FORM_addr:
|
|
case DW_FORM_addrx:
|
|
case DW_FORM_GNU_addr_index:
|
|
{
|
|
gdb_byte *tem;
|
|
|
|
*len = cu->header.addr_size;
|
|
tem = (gdb_byte *) obstack_alloc (obstack, *len);
|
|
store_unsigned_integer (tem, *len, byte_order,
|
|
(ULONGEST) attr->as_address ());
|
|
result = tem;
|
|
}
|
|
break;
|
|
case DW_FORM_string:
|
|
case DW_FORM_strp:
|
|
case DW_FORM_strx:
|
|
case DW_FORM_GNU_str_index:
|
|
case DW_FORM_GNU_strp_alt:
|
|
/* The string is already allocated on the objfile obstack, point
|
|
directly to it. */
|
|
{
|
|
const char *attr_name = attr->as_string ();
|
|
result = (const gdb_byte *) attr_name;
|
|
*len = strlen (attr_name);
|
|
}
|
|
break;
|
|
case DW_FORM_block1:
|
|
case DW_FORM_block2:
|
|
case DW_FORM_block4:
|
|
case DW_FORM_block:
|
|
case DW_FORM_exprloc:
|
|
case DW_FORM_data16:
|
|
{
|
|
struct dwarf_block *block = attr->as_block ();
|
|
result = block->data;
|
|
*len = block->size;
|
|
}
|
|
break;
|
|
|
|
/* The DW_AT_const_value attributes are supposed to carry the
|
|
symbol's value "represented as it would be on the target
|
|
architecture." By the time we get here, it's already been
|
|
converted to host endianness, so we just need to sign- or
|
|
zero-extend it as appropriate. */
|
|
case DW_FORM_data1:
|
|
type = die_type (die, cu);
|
|
result = dwarf2_const_value_data (attr, obstack, cu, &value, 8);
|
|
if (result == NULL)
|
|
result = write_constant_as_bytes (obstack, byte_order,
|
|
type, value, len);
|
|
break;
|
|
case DW_FORM_data2:
|
|
type = die_type (die, cu);
|
|
result = dwarf2_const_value_data (attr, obstack, cu, &value, 16);
|
|
if (result == NULL)
|
|
result = write_constant_as_bytes (obstack, byte_order,
|
|
type, value, len);
|
|
break;
|
|
case DW_FORM_data4:
|
|
type = die_type (die, cu);
|
|
result = dwarf2_const_value_data (attr, obstack, cu, &value, 32);
|
|
if (result == NULL)
|
|
result = write_constant_as_bytes (obstack, byte_order,
|
|
type, value, len);
|
|
break;
|
|
case DW_FORM_data8:
|
|
type = die_type (die, cu);
|
|
result = dwarf2_const_value_data (attr, obstack, cu, &value, 64);
|
|
if (result == NULL)
|
|
result = write_constant_as_bytes (obstack, byte_order,
|
|
type, value, len);
|
|
break;
|
|
|
|
case DW_FORM_sdata:
|
|
case DW_FORM_implicit_const:
|
|
type = die_type (die, cu);
|
|
result = write_constant_as_bytes (obstack, byte_order,
|
|
type, attr->as_signed (), len);
|
|
break;
|
|
|
|
case DW_FORM_udata:
|
|
type = die_type (die, cu);
|
|
result = write_constant_as_bytes (obstack, byte_order,
|
|
type, attr->as_unsigned (), len);
|
|
break;
|
|
|
|
default:
|
|
complaint (_("unsupported const value attribute form: '%s'"),
|
|
dwarf_form_name (attr->form));
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
struct type *
|
|
dwarf2_fetch_die_type_sect_off (sect_offset sect_off,
|
|
dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile,
|
|
const char **var_name)
|
|
{
|
|
struct die_info *die;
|
|
|
|
dwarf2_cu *cu = per_objfile->get_cu (per_cu);
|
|
if (cu == nullptr)
|
|
cu = load_cu (per_cu, per_objfile, false);
|
|
|
|
if (cu == nullptr)
|
|
return nullptr;
|
|
|
|
die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
|
|
if (!die)
|
|
return NULL;
|
|
|
|
if (var_name != nullptr)
|
|
*var_name = var_decl_name (die, cu);
|
|
return die_type (die, cu);
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
struct type *
|
|
dwarf2_get_die_type (cu_offset die_offset,
|
|
dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile)
|
|
{
|
|
sect_offset die_offset_sect = per_cu->sect_off + to_underlying (die_offset);
|
|
return get_die_type_at_offset (die_offset_sect, per_cu, per_objfile);
|
|
}
|
|
|
|
/* Follow type unit SIG_TYPE referenced by SRC_DIE.
|
|
On entry *REF_CU is the CU of SRC_DIE.
|
|
On exit *REF_CU is the CU of the result.
|
|
Returns NULL if the referenced DIE isn't found. */
|
|
|
|
static struct die_info *
|
|
follow_die_sig_1 (struct die_info *src_die, struct signatured_type *sig_type,
|
|
struct dwarf2_cu **ref_cu)
|
|
{
|
|
struct dwarf2_cu *sig_cu;
|
|
dwarf2_per_objfile *per_objfile = (*ref_cu)->per_objfile;
|
|
|
|
|
|
/* While it might be nice to assert sig_type->type == NULL here,
|
|
we can get here for DW_AT_imported_declaration where we need
|
|
the DIE not the type. */
|
|
|
|
/* If necessary, add it to the queue and load its DIEs.
|
|
|
|
Even if maybe_queue_comp_unit doesn't require us to load the CU's DIEs,
|
|
it doesn't mean they are currently loaded. Since we require them
|
|
to be loaded, we must check for ourselves. */
|
|
if (maybe_queue_comp_unit (*ref_cu, sig_type, per_objfile,
|
|
language_minimal)
|
|
|| per_objfile->get_cu (sig_type) == nullptr)
|
|
read_signatured_type (sig_type, per_objfile);
|
|
|
|
sig_cu = per_objfile->get_cu (sig_type);
|
|
gdb_assert (sig_cu != NULL);
|
|
gdb_assert (to_underlying (sig_type->type_offset_in_section) != 0);
|
|
|
|
if (auto die_it = sig_cu->die_hash.find (sig_type->type_offset_in_section);
|
|
die_it != sig_cu->die_hash.end ())
|
|
{
|
|
/* For .gdb_index version 7 keep track of included TUs.
|
|
http://sourceware.org/bugzilla/show_bug.cgi?id=15021. */
|
|
if (per_objfile->per_bfd->index_table != NULL
|
|
&& !per_objfile->per_bfd->index_table->version_check ())
|
|
(*ref_cu)->per_cu->imported_symtabs.push_back (sig_cu->per_cu);
|
|
|
|
*ref_cu = sig_cu;
|
|
return *die_it;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Follow signatured type referenced by ATTR in SRC_DIE.
|
|
On entry *REF_CU is the CU of SRC_DIE.
|
|
On exit *REF_CU is the CU of the result.
|
|
The result is the DIE of the type.
|
|
If the referenced type cannot be found an error is thrown. */
|
|
|
|
static struct die_info *
|
|
follow_die_sig (struct die_info *src_die, const struct attribute *attr,
|
|
struct dwarf2_cu **ref_cu)
|
|
{
|
|
ULONGEST signature = attr->as_signature ();
|
|
struct signatured_type *sig_type;
|
|
struct die_info *die;
|
|
|
|
gdb_assert (attr->form == DW_FORM_ref_sig8);
|
|
|
|
sig_type = lookup_signatured_type (*ref_cu, signature);
|
|
/* sig_type will be NULL if the signatured type is missing from
|
|
the debug info. */
|
|
if (sig_type == NULL)
|
|
{
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Cannot find signatured DIE %s referenced from DIE at %s"
|
|
" [in module %s]"),
|
|
hex_string (signature), sect_offset_str (src_die->sect_off),
|
|
objfile_name ((*ref_cu)->per_objfile->objfile));
|
|
}
|
|
|
|
die = follow_die_sig_1 (src_die, sig_type, ref_cu);
|
|
if (die == NULL)
|
|
{
|
|
src_die->error_dump ();
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"Problem reading signatured DIE %s referenced from DIE at %s"
|
|
" [in module %s]"),
|
|
hex_string (signature), sect_offset_str (src_die->sect_off),
|
|
objfile_name ((*ref_cu)->per_objfile->objfile));
|
|
}
|
|
|
|
return die;
|
|
}
|
|
|
|
/* Get the type specified by SIGNATURE referenced in DIE/CU,
|
|
reading in and processing the type unit if necessary. */
|
|
|
|
static struct type *
|
|
get_signatured_type (struct die_info *die, ULONGEST signature,
|
|
struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct signatured_type *sig_type;
|
|
struct dwarf2_cu *type_cu;
|
|
struct die_info *type_die;
|
|
struct type *type;
|
|
|
|
sig_type = lookup_signatured_type (cu, signature);
|
|
/* sig_type will be NULL if the signatured type is missing from
|
|
the debug info. */
|
|
if (sig_type == NULL)
|
|
{
|
|
complaint (_(DWARF_ERROR_PREFIX
|
|
"Cannot find signatured DIE %s referenced from DIE at %s"
|
|
" [in module %s]"),
|
|
hex_string (signature), sect_offset_str (die->sect_off),
|
|
objfile_name (per_objfile->objfile));
|
|
return build_error_marker_type (cu, die);
|
|
}
|
|
|
|
/* If we already know the type we're done. */
|
|
type = per_objfile->get_type_for_signatured_type (sig_type);
|
|
if (type != nullptr)
|
|
return type;
|
|
|
|
type_cu = cu;
|
|
type_die = follow_die_sig_1 (die, sig_type, &type_cu);
|
|
if (type_die != NULL)
|
|
{
|
|
/* N.B. We need to call get_die_type to ensure only one type for this DIE
|
|
is created. This is important, for example, because for c++ classes
|
|
we need TYPE_NAME set which is only done by new_symbol. Blech. */
|
|
type = read_type_die (type_die, type_cu);
|
|
if (type == NULL)
|
|
{
|
|
complaint (_(DWARF_ERROR_PREFIX
|
|
"Cannot build signatured type %s"
|
|
" referenced from DIE at %s [in module %s]"),
|
|
hex_string (signature), sect_offset_str (die->sect_off),
|
|
objfile_name (per_objfile->objfile));
|
|
type = build_error_marker_type (cu, die);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
complaint (_(DWARF_ERROR_PREFIX
|
|
"Problem reading signatured DIE %s referenced"
|
|
" from DIE at %s [in module %s]"),
|
|
hex_string (signature), sect_offset_str (die->sect_off),
|
|
objfile_name (per_objfile->objfile));
|
|
type = build_error_marker_type (cu, die);
|
|
}
|
|
|
|
per_objfile->set_type_for_signatured_type (sig_type, type);
|
|
|
|
return type;
|
|
}
|
|
|
|
/* Get the type specified by the DW_AT_signature ATTR in DIE/CU,
|
|
reading in and processing the type unit if necessary. */
|
|
|
|
static struct type *
|
|
get_DW_AT_signature_type (struct die_info *die, const struct attribute *attr,
|
|
struct dwarf2_cu *cu) /* ARI: editCase function */
|
|
{
|
|
/* Yes, DW_AT_signature can use a non-ref_sig8 reference. */
|
|
if (attr->form_is_ref ())
|
|
{
|
|
struct dwarf2_cu *type_cu = cu;
|
|
struct die_info *type_die = follow_die_ref (die, attr, &type_cu);
|
|
|
|
return read_type_die (type_die, type_cu);
|
|
}
|
|
else if (attr->form == DW_FORM_ref_sig8)
|
|
{
|
|
return get_signatured_type (die, attr->as_signature (), cu);
|
|
}
|
|
else
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
complaint (_(DWARF_ERROR_PREFIX
|
|
"DW_AT_signature has bad form %s in DIE at %s"
|
|
" [in module %s]"),
|
|
dwarf_form_name (attr->form), sect_offset_str (die->sect_off),
|
|
objfile_name (per_objfile->objfile));
|
|
return build_error_marker_type (cu, die);
|
|
}
|
|
}
|
|
|
|
/* Load the DIEs associated with type unit PER_CU into memory. */
|
|
|
|
static void
|
|
load_full_type_unit (dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile)
|
|
{
|
|
struct signatured_type *sig_type;
|
|
|
|
/* We have the per_cu, but we need the signatured_type.
|
|
Fortunately this is an easy translation. */
|
|
gdb_assert (per_cu->is_debug_types);
|
|
sig_type = (struct signatured_type *) per_cu;
|
|
|
|
gdb_assert (per_objfile->get_cu (per_cu) == nullptr);
|
|
|
|
read_signatured_type (sig_type, per_objfile);
|
|
|
|
gdb_assert (per_objfile->get_cu (per_cu) != nullptr);
|
|
}
|
|
|
|
/* Read in a signatured type and build its CU and DIEs.
|
|
If the type is a stub for the real type in a DWO file,
|
|
read in the real type from the DWO file as well. */
|
|
|
|
static void
|
|
read_signatured_type (signatured_type *sig_type,
|
|
dwarf2_per_objfile *per_objfile)
|
|
{
|
|
gdb_assert (sig_type->is_debug_types);
|
|
gdb_assert (per_objfile->get_cu (sig_type) == nullptr);
|
|
|
|
cutu_reader reader (sig_type, per_objfile, nullptr, nullptr, false);
|
|
|
|
if (!reader.dummy_p)
|
|
{
|
|
struct dwarf2_cu *cu = reader.cu;
|
|
const gdb_byte *info_ptr = reader.info_ptr;
|
|
|
|
gdb_assert (cu->die_hash.empty ());
|
|
cu->die_hash.reserve (cu->header.get_length_without_initial () / 12);
|
|
|
|
if (reader.comp_unit_die->has_children)
|
|
reader.comp_unit_die->child
|
|
= read_die_and_siblings (&reader, info_ptr, &info_ptr,
|
|
reader.comp_unit_die);
|
|
cu->dies = reader.comp_unit_die;
|
|
/* comp_unit_die is not stored in die_hash, no need. */
|
|
|
|
/* We try not to read any attributes in this function, because
|
|
not all CUs needed for references have been loaded yet, and
|
|
symbol table processing isn't initialized. But we have to
|
|
set the CU language, or we won't be able to build types
|
|
correctly. Similarly, if we do not read the producer, we can
|
|
not apply producer-specific interpretation. */
|
|
prepare_one_comp_unit (cu, cu->dies, language_minimal);
|
|
|
|
reader.keep ();
|
|
}
|
|
|
|
sig_type->tu_read = 1;
|
|
}
|
|
|
|
/* Decode simple location descriptions.
|
|
|
|
Given a pointer to a DWARF block that defines a location, compute
|
|
the location. Returns true if the expression was computable by
|
|
this function, false otherwise. On a true return, *RESULT is set.
|
|
|
|
Note that this function does not implement a full DWARF expression
|
|
evaluator. Instead, it is used for a few limited purposes:
|
|
|
|
- Getting the address of a symbol that has a constant address. For
|
|
example, if a symbol has a location like "DW_OP_addr", the address
|
|
can be extracted.
|
|
|
|
- Getting the offset of a virtual function in its vtable. There
|
|
are two forms of this, one of which involves DW_OP_deref -- so this
|
|
function handles derefs in a peculiar way to make this 'work'.
|
|
(Probably this area should be rewritten.)
|
|
|
|
- Getting the offset of a field, when it is constant.
|
|
|
|
Opcodes that cannot be part of a constant expression, for example
|
|
those involving registers, simply result in a return of
|
|
'false'.
|
|
|
|
This function may emit a complaint. */
|
|
|
|
static bool
|
|
decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu,
|
|
CORE_ADDR *result)
|
|
{
|
|
struct objfile *objfile = cu->per_objfile->objfile;
|
|
size_t i;
|
|
size_t size = blk->size;
|
|
const gdb_byte *data = blk->data;
|
|
CORE_ADDR stack[64];
|
|
int stacki;
|
|
unsigned int bytes_read;
|
|
gdb_byte op;
|
|
|
|
*result = 0;
|
|
i = 0;
|
|
stacki = 0;
|
|
stack[stacki] = 0;
|
|
stack[++stacki] = 0;
|
|
|
|
while (i < size)
|
|
{
|
|
op = data[i++];
|
|
switch (op)
|
|
{
|
|
case DW_OP_lit0:
|
|
case DW_OP_lit1:
|
|
case DW_OP_lit2:
|
|
case DW_OP_lit3:
|
|
case DW_OP_lit4:
|
|
case DW_OP_lit5:
|
|
case DW_OP_lit6:
|
|
case DW_OP_lit7:
|
|
case DW_OP_lit8:
|
|
case DW_OP_lit9:
|
|
case DW_OP_lit10:
|
|
case DW_OP_lit11:
|
|
case DW_OP_lit12:
|
|
case DW_OP_lit13:
|
|
case DW_OP_lit14:
|
|
case DW_OP_lit15:
|
|
case DW_OP_lit16:
|
|
case DW_OP_lit17:
|
|
case DW_OP_lit18:
|
|
case DW_OP_lit19:
|
|
case DW_OP_lit20:
|
|
case DW_OP_lit21:
|
|
case DW_OP_lit22:
|
|
case DW_OP_lit23:
|
|
case DW_OP_lit24:
|
|
case DW_OP_lit25:
|
|
case DW_OP_lit26:
|
|
case DW_OP_lit27:
|
|
case DW_OP_lit28:
|
|
case DW_OP_lit29:
|
|
case DW_OP_lit30:
|
|
case DW_OP_lit31:
|
|
stack[++stacki] = op - DW_OP_lit0;
|
|
break;
|
|
|
|
case DW_OP_addr:
|
|
stack[++stacki]
|
|
= (CORE_ADDR) cu->header.read_address (objfile->obfd.get (),
|
|
&data[i],
|
|
&bytes_read);
|
|
i += bytes_read;
|
|
break;
|
|
|
|
case DW_OP_const1u:
|
|
stack[++stacki] = read_1_byte (objfile->obfd.get (), &data[i]);
|
|
i += 1;
|
|
break;
|
|
|
|
case DW_OP_const1s:
|
|
stack[++stacki] = read_1_signed_byte (objfile->obfd.get (), &data[i]);
|
|
i += 1;
|
|
break;
|
|
|
|
case DW_OP_const2u:
|
|
stack[++stacki] = read_2_bytes (objfile->obfd.get (), &data[i]);
|
|
i += 2;
|
|
break;
|
|
|
|
case DW_OP_const2s:
|
|
stack[++stacki] = read_2_signed_bytes (objfile->obfd.get (), &data[i]);
|
|
i += 2;
|
|
break;
|
|
|
|
case DW_OP_const4u:
|
|
stack[++stacki] = read_4_bytes (objfile->obfd.get (), &data[i]);
|
|
i += 4;
|
|
break;
|
|
|
|
case DW_OP_const4s:
|
|
stack[++stacki] = read_4_signed_bytes (objfile->obfd.get (), &data[i]);
|
|
i += 4;
|
|
break;
|
|
|
|
case DW_OP_const8u:
|
|
stack[++stacki] = read_8_bytes (objfile->obfd.get (), &data[i]);
|
|
i += 8;
|
|
break;
|
|
|
|
case DW_OP_constu:
|
|
stack[++stacki] = read_unsigned_leb128 (NULL, (data + i),
|
|
&bytes_read);
|
|
i += bytes_read;
|
|
break;
|
|
|
|
case DW_OP_consts:
|
|
stack[++stacki] = read_signed_leb128 (NULL, (data + i), &bytes_read);
|
|
i += bytes_read;
|
|
break;
|
|
|
|
case DW_OP_dup:
|
|
stack[stacki + 1] = stack[stacki];
|
|
stacki++;
|
|
break;
|
|
|
|
case DW_OP_plus:
|
|
stack[stacki - 1] += stack[stacki];
|
|
stacki--;
|
|
break;
|
|
|
|
case DW_OP_plus_uconst:
|
|
stack[stacki] += read_unsigned_leb128 (NULL, (data + i),
|
|
&bytes_read);
|
|
i += bytes_read;
|
|
break;
|
|
|
|
case DW_OP_minus:
|
|
stack[stacki - 1] -= stack[stacki];
|
|
stacki--;
|
|
break;
|
|
|
|
case DW_OP_deref:
|
|
/* If we're not the last op, then we definitely can't encode
|
|
this using GDB's address_class enum. This is valid for partial
|
|
global symbols, although the variable's address will be bogus
|
|
in the psymtab. */
|
|
if (i < size)
|
|
return false;
|
|
break;
|
|
|
|
case DW_OP_addrx:
|
|
case DW_OP_GNU_addr_index:
|
|
case DW_OP_constx:
|
|
case DW_OP_GNU_const_index:
|
|
stack[++stacki]
|
|
= (CORE_ADDR) read_addr_index_from_leb128 (cu, &data[i],
|
|
&bytes_read);
|
|
i += bytes_read;
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
/* Enforce maximum stack depth of SIZE-1 to avoid writing
|
|
outside of the allocated space. Also enforce minimum>0. */
|
|
if (stacki >= ARRAY_SIZE (stack) - 1)
|
|
{
|
|
complaint (_("location description stack overflow"));
|
|
return false;
|
|
}
|
|
|
|
if (stacki <= 0)
|
|
{
|
|
complaint (_("location description stack underflow"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
*result = stack[stacki];
|
|
return true;
|
|
}
|
|
|
|
/* memory allocation interface */
|
|
|
|
static struct dwarf_block *
|
|
dwarf_alloc_block (struct dwarf2_cu *cu)
|
|
{
|
|
return XOBNEW (&cu->comp_unit_obstack, struct dwarf_block);
|
|
}
|
|
|
|
|
|
|
|
/* Macro support. */
|
|
|
|
/* An overload of dwarf_decode_macros that finds the correct section
|
|
and ensures it is read in before calling the other overload. */
|
|
|
|
static void
|
|
dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset,
|
|
int section_is_gnu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
const struct line_header *lh = cu->line_header;
|
|
unsigned int offset_size = cu->header.offset_size;
|
|
struct dwarf2_section_info *section;
|
|
const char *section_name;
|
|
|
|
if (cu->dwo_unit != nullptr)
|
|
{
|
|
if (section_is_gnu)
|
|
{
|
|
section = &cu->dwo_unit->dwo_file->sections.macro;
|
|
section_name = ".debug_macro.dwo";
|
|
}
|
|
else
|
|
{
|
|
section = &cu->dwo_unit->dwo_file->sections.macinfo;
|
|
section_name = ".debug_macinfo.dwo";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (section_is_gnu)
|
|
{
|
|
section = &per_objfile->per_bfd->macro;
|
|
section_name = ".debug_macro";
|
|
}
|
|
else
|
|
{
|
|
section = &per_objfile->per_bfd->macinfo;
|
|
section_name = ".debug_macinfo";
|
|
}
|
|
}
|
|
|
|
section->read (objfile);
|
|
if (section->buffer == nullptr)
|
|
{
|
|
complaint (_("missing %s section"), section_name);
|
|
return;
|
|
}
|
|
|
|
buildsym_compunit *builder = cu->get_builder ();
|
|
|
|
struct dwarf2_section_info *str_offsets_section;
|
|
struct dwarf2_section_info *str_section;
|
|
std::optional<ULONGEST> str_offsets_base;
|
|
|
|
if (cu->dwo_unit != nullptr)
|
|
{
|
|
str_offsets_section = &cu->dwo_unit->dwo_file
|
|
->sections.str_offsets;
|
|
str_section = &cu->dwo_unit->dwo_file->sections.str;
|
|
str_offsets_base = cu->header.addr_size;
|
|
}
|
|
else
|
|
{
|
|
str_offsets_section = &per_objfile->per_bfd->str_offsets;
|
|
str_section = &per_objfile->per_bfd->str;
|
|
str_offsets_base = cu->str_offsets_base;
|
|
}
|
|
|
|
dwarf_decode_macros (per_objfile, builder, section, lh,
|
|
offset_size, offset, str_section, str_offsets_section,
|
|
str_offsets_base, section_is_gnu, cu);
|
|
}
|
|
|
|
/* Return the .debug_loc section to use for CU.
|
|
For DWO files use .debug_loc.dwo. */
|
|
|
|
static struct dwarf2_section_info *
|
|
cu_debug_loc_section (struct dwarf2_cu *cu)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
|
|
if (cu->dwo_unit)
|
|
{
|
|
struct dwo_sections *sections = &cu->dwo_unit->dwo_file->sections;
|
|
|
|
return cu->header.version >= 5 ? §ions->loclists : §ions->loc;
|
|
}
|
|
return (cu->header.version >= 5 ? &per_objfile->per_bfd->loclists
|
|
: &per_objfile->per_bfd->loc);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
if (cu->header.version < 5)
|
|
error (_(".debug_rnglists section cannot be used in DWARF %d"),
|
|
cu->header.version);
|
|
struct dwarf2_per_objfile *dwarf2_per_objfile = cu->per_objfile;
|
|
|
|
/* Make sure we read the .debug_rnglists section from the file that
|
|
contains the DW_AT_ranges attribute we are reading. Normally that
|
|
would be the .dwo file, if there is one. However for DW_TAG_compile_unit
|
|
or DW_TAG_skeleton unit, we always want to read from objfile/linked
|
|
program. */
|
|
if (cu->dwo_unit != nullptr
|
|
&& tag != DW_TAG_compile_unit
|
|
&& tag != DW_TAG_skeleton_unit)
|
|
{
|
|
struct dwo_sections *sections = &cu->dwo_unit->dwo_file->sections;
|
|
|
|
if (sections->rnglists.size > 0)
|
|
return §ions->rnglists;
|
|
else
|
|
error (_(".debug_rnglists section is missing from .dwo file."));
|
|
}
|
|
return &dwarf2_per_objfile->per_bfd->rnglists;
|
|
}
|
|
|
|
/* A helper function that fills in a dwarf2_loclist_baton. */
|
|
|
|
static void
|
|
fill_in_loclist_baton (struct dwarf2_cu *cu,
|
|
struct dwarf2_loclist_baton *baton,
|
|
const struct attribute *attr)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct dwarf2_section_info *section = cu_debug_loc_section (cu);
|
|
|
|
section->read (per_objfile->objfile);
|
|
|
|
baton->per_objfile = per_objfile;
|
|
baton->per_cu = cu->per_cu;
|
|
gdb_assert (baton->per_cu);
|
|
/* We don't know how long the location list is, but make sure we
|
|
don't run off the edge of the section. */
|
|
baton->size = section->size - attr->as_unsigned ();
|
|
baton->data = section->buffer + attr->as_unsigned ();
|
|
if (cu->base_address.has_value ())
|
|
baton->base_address = *cu->base_address;
|
|
else
|
|
baton->base_address = {};
|
|
baton->from_dwo = cu->dwo_unit != NULL;
|
|
baton->dwarf_version = cu->header.version;
|
|
}
|
|
|
|
static void
|
|
dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym,
|
|
struct dwarf2_cu *cu, int is_block)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct objfile *objfile = per_objfile->objfile;
|
|
struct dwarf2_section_info *section = cu_debug_loc_section (cu);
|
|
|
|
if (attr->form_is_section_offset ()
|
|
/* .debug_loc{,.dwo} may not exist at all, or the offset may be outside
|
|
the section. If so, fall through to the complaint in the
|
|
other branch. */
|
|
&& attr->as_unsigned () < section->get_size (objfile))
|
|
{
|
|
struct dwarf2_loclist_baton *baton;
|
|
|
|
baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_loclist_baton);
|
|
|
|
fill_in_loclist_baton (cu, baton, attr);
|
|
|
|
if (!cu->base_address.has_value ())
|
|
complaint (_("Location list used without "
|
|
"specifying the CU base address."));
|
|
|
|
sym->set_aclass_index ((is_block
|
|
? dwarf2_loclist_block_index
|
|
: dwarf2_loclist_index));
|
|
SYMBOL_LOCATION_BATON (sym) = baton;
|
|
}
|
|
else
|
|
{
|
|
struct dwarf2_locexpr_baton *baton;
|
|
|
|
baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton);
|
|
baton->per_objfile = per_objfile;
|
|
baton->per_cu = cu->per_cu;
|
|
gdb_assert (baton->per_cu);
|
|
|
|
if (attr->form_is_block ())
|
|
{
|
|
/* Note that we're just copying the block's data pointer
|
|
here, not the actual data. We're still pointing into the
|
|
info_buffer for SYM's objfile; right now we never release
|
|
that buffer, but when we do clean up properly this may
|
|
need to change. */
|
|
struct dwarf_block *block = attr->as_block ();
|
|
baton->size = block->size;
|
|
baton->data = block->data;
|
|
}
|
|
else
|
|
{
|
|
dwarf2_invalid_attrib_class_complaint ("location description",
|
|
sym->natural_name ());
|
|
baton->size = 0;
|
|
}
|
|
|
|
sym->set_aclass_index ((is_block
|
|
? dwarf2_locexpr_block_index
|
|
: dwarf2_locexpr_index));
|
|
SYMBOL_LOCATION_BATON (sym) = baton;
|
|
}
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
const comp_unit_head *
|
|
dwarf2_per_cu_data::get_header () const
|
|
{
|
|
if (!m_header_read_in)
|
|
{
|
|
const gdb_byte *info_ptr
|
|
= this->section->buffer + to_underlying (this->sect_off);
|
|
|
|
read_comp_unit_head (&m_header, info_ptr, this->section,
|
|
rcuh_kind::COMPILE);
|
|
|
|
m_header_read_in = true;
|
|
}
|
|
|
|
return &m_header;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
int
|
|
dwarf2_per_cu_data::addr_size () const
|
|
{
|
|
return this->get_header ()->addr_size;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
int
|
|
dwarf2_per_cu_data::offset_size () const
|
|
{
|
|
return this->get_header ()->offset_size;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
int
|
|
dwarf2_per_cu_data::ref_addr_size () const
|
|
{
|
|
const comp_unit_head *header = this->get_header ();
|
|
|
|
if (header->version == 2)
|
|
return header->addr_size;
|
|
else
|
|
return header->offset_size;
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
void
|
|
dwarf2_per_cu_data::set_lang (enum language lang,
|
|
dwarf_source_language dw_lang)
|
|
{
|
|
if (unit_type () == DW_UT_partial)
|
|
return;
|
|
|
|
/* Set if not set already. */
|
|
packed<language, LANGUAGE_BYTES> new_value = lang;
|
|
packed<language, LANGUAGE_BYTES> old_value = m_lang.exchange (new_value);
|
|
/* If already set, verify that it's the same value. */
|
|
gdb_assert (old_value == language_unknown || old_value == lang);
|
|
|
|
packed<dwarf_source_language, 2> new_dw = dw_lang;
|
|
packed<dwarf_source_language, 2> old_dw = m_dw_lang.exchange (new_dw);
|
|
gdb_assert (old_dw == 0 || old_dw == dw_lang);
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
void
|
|
dwarf2_per_cu_data::ensure_lang (dwarf2_per_objfile *per_objfile)
|
|
{
|
|
if (lang (false) != language_unknown)
|
|
return;
|
|
|
|
cutu_reader reader (this, per_objfile);
|
|
if (reader.dummy_p)
|
|
{
|
|
set_lang (language_minimal, (dwarf_source_language)0);
|
|
return;
|
|
}
|
|
|
|
prepare_one_comp_unit (reader.cu, reader.comp_unit_die, language_minimal);
|
|
}
|
|
|
|
/* A helper function for dwarf2_find_containing_comp_unit that returns
|
|
the index of the result, and that searches a vector. It will
|
|
return a result even if the offset in question does not actually
|
|
occur in any CU. This is separate so that it can be unit
|
|
tested. */
|
|
|
|
static int
|
|
dwarf2_find_containing_comp_unit
|
|
(sect_offset sect_off,
|
|
unsigned int offset_in_dwz,
|
|
const std::vector<dwarf2_per_cu_data_up> &all_units)
|
|
{
|
|
int low, high;
|
|
|
|
low = 0;
|
|
high = all_units.size () - 1;
|
|
while (high > low)
|
|
{
|
|
struct dwarf2_per_cu_data *mid_cu;
|
|
int mid = low + (high - low) / 2;
|
|
|
|
mid_cu = all_units[mid].get ();
|
|
if (mid_cu->is_dwz > offset_in_dwz
|
|
|| (mid_cu->is_dwz == offset_in_dwz
|
|
&& mid_cu->sect_off + mid_cu->length () > sect_off))
|
|
high = mid;
|
|
else
|
|
low = mid + 1;
|
|
}
|
|
gdb_assert (low == high);
|
|
return low;
|
|
}
|
|
|
|
/* Locate the .debug_info compilation unit from CU's objfile which contains
|
|
the DIE at OFFSET. Raises an error on failure. */
|
|
|
|
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)
|
|
{
|
|
int low = dwarf2_find_containing_comp_unit
|
|
(sect_off, offset_in_dwz, per_bfd->all_units);
|
|
dwarf2_per_cu_data *this_cu = per_bfd->all_units[low].get ();
|
|
|
|
if (this_cu->is_dwz != offset_in_dwz || this_cu->sect_off > sect_off)
|
|
{
|
|
if (low == 0 || this_cu->is_dwz != offset_in_dwz)
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"could not find CU containing offset %s [in module %s]"),
|
|
sect_offset_str (sect_off),
|
|
bfd_get_filename (per_bfd->obfd));
|
|
|
|
gdb_assert (per_bfd->all_units[low-1]->sect_off
|
|
<= sect_off);
|
|
return per_bfd->all_units[low - 1].get ();
|
|
}
|
|
else
|
|
{
|
|
if (low == per_bfd->all_units.size () - 1
|
|
&& sect_off >= this_cu->sect_off + this_cu->length ())
|
|
error (_("invalid dwarf2 offset %s"), sect_offset_str (sect_off));
|
|
gdb_assert (sect_off < this_cu->sect_off + this_cu->length ());
|
|
return this_cu;
|
|
}
|
|
}
|
|
|
|
#if GDB_SELF_TEST
|
|
|
|
namespace selftests {
|
|
namespace find_containing_comp_unit {
|
|
|
|
static void
|
|
run_test ()
|
|
{
|
|
dwarf2_per_cu_data_up one (new dwarf2_per_cu_data);
|
|
dwarf2_per_cu_data *one_ptr = one.get ();
|
|
dwarf2_per_cu_data_up two (new dwarf2_per_cu_data);
|
|
dwarf2_per_cu_data *two_ptr = two.get ();
|
|
dwarf2_per_cu_data_up three (new dwarf2_per_cu_data);
|
|
dwarf2_per_cu_data *three_ptr = three.get ();
|
|
dwarf2_per_cu_data_up four (new dwarf2_per_cu_data);
|
|
dwarf2_per_cu_data *four_ptr = four.get ();
|
|
|
|
one->set_length (5);
|
|
two->sect_off = sect_offset (one->length ());
|
|
two->set_length (7);
|
|
|
|
three->set_length (5);
|
|
three->is_dwz = 1;
|
|
four->sect_off = sect_offset (three->length ());
|
|
four->set_length (7);
|
|
four->is_dwz = 1;
|
|
|
|
std::vector<dwarf2_per_cu_data_up> units;
|
|
units.push_back (std::move (one));
|
|
units.push_back (std::move (two));
|
|
units.push_back (std::move (three));
|
|
units.push_back (std::move (four));
|
|
|
|
int result;
|
|
|
|
result = dwarf2_find_containing_comp_unit (sect_offset (0), 0, units);
|
|
SELF_CHECK (units[result].get () == one_ptr);
|
|
result = dwarf2_find_containing_comp_unit (sect_offset (3), 0, units);
|
|
SELF_CHECK (units[result].get () == one_ptr);
|
|
result = dwarf2_find_containing_comp_unit (sect_offset (5), 0, units);
|
|
SELF_CHECK (units[result].get () == two_ptr);
|
|
|
|
result = dwarf2_find_containing_comp_unit (sect_offset (0), 1, units);
|
|
SELF_CHECK (units[result].get () == three_ptr);
|
|
result = dwarf2_find_containing_comp_unit (sect_offset (3), 1, units);
|
|
SELF_CHECK (units[result].get () == three_ptr);
|
|
result = dwarf2_find_containing_comp_unit (sect_offset (5), 1, units);
|
|
SELF_CHECK (units[result].get () == four_ptr);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif /* GDB_SELF_TEST */
|
|
|
|
/* Initialize basic fields of dwarf_cu CU according to DIE COMP_UNIT_DIE. */
|
|
|
|
static void
|
|
prepare_one_comp_unit (struct dwarf2_cu *cu, struct die_info *comp_unit_die,
|
|
enum language pretend_language)
|
|
{
|
|
struct attribute *attr;
|
|
|
|
cu->producer = dwarf2_string_attr (comp_unit_die, DW_AT_producer, cu);
|
|
|
|
/* Set the language we're debugging. */
|
|
attr = dwarf2_attr (comp_unit_die, DW_AT_language, cu);
|
|
enum language lang;
|
|
dwarf_source_language dw_lang = (dwarf_source_language) 0;
|
|
if (cu->producer != nullptr
|
|
&& strstr (cu->producer, "IBM XL C for OpenCL") != NULL)
|
|
{
|
|
/* The XLCL doesn't generate DW_LANG_OpenCL because this
|
|
attribute is not standardised yet. As a workaround for the
|
|
language detection we fall back to the DW_AT_producer
|
|
string. */
|
|
lang = language_opencl;
|
|
dw_lang = DW_LANG_OpenCL;
|
|
}
|
|
else if (cu->producer != nullptr
|
|
&& strstr (cu->producer, "GNU Go ") != NULL)
|
|
{
|
|
/* Similar hack for Go. */
|
|
lang = language_go;
|
|
dw_lang = DW_LANG_Go;
|
|
}
|
|
else if (attr != nullptr)
|
|
{
|
|
lang = dwarf_lang_to_enum_language (attr->constant_value (0));
|
|
dw_lang = (dwarf_source_language) attr->constant_value (0);
|
|
|
|
/* The HIP compiler instead of setting DW_AT_language to DW_LANG_HIP
|
|
sets it to DW_LANG_C_plus_plus_14. As a workaround for the
|
|
language detection, we fall back to checking the target
|
|
architecture when the language is C++. There are still 2 caveats:
|
|
|
|
1) Erroneously labeling device codes written purely in C++ as HIP
|
|
2) Not detecting the host HIP codes as HIP, but the emitted C++14
|
|
|
|
Point (1) is quite unlikely. Point (2) can be remedied for now
|
|
with a "set language hip" command in GDB itself. Still, this
|
|
workaround works better than checking the "producer", since
|
|
various providers tend to name them slightly differently. */
|
|
if (lang == language_cplus
|
|
&& (cu->per_objfile->per_bfd->obfd->arch_info->arch
|
|
== bfd_arch_amdgcn))
|
|
{
|
|
lang = language_hip;
|
|
dw_lang = DW_LANG_HIP;
|
|
}
|
|
}
|
|
else
|
|
lang = pretend_language;
|
|
|
|
cu->language_defn = language_def (lang);
|
|
|
|
/* Initialize the lto_artificial field. */
|
|
attr = dwarf2_attr (comp_unit_die, DW_AT_name, cu);
|
|
if (attr != nullptr
|
|
&& cu->producer != nullptr
|
|
&& attr->as_string () != nullptr
|
|
&& strcmp (attr->as_string (), "<artificial>") == 0
|
|
&& producer_is_gcc (cu->producer, nullptr, nullptr))
|
|
cu->per_cu->lto_artificial = true;
|
|
|
|
switch (comp_unit_die->tag)
|
|
{
|
|
case DW_TAG_compile_unit:
|
|
cu->per_cu->set_unit_type (DW_UT_compile);
|
|
break;
|
|
case DW_TAG_partial_unit:
|
|
cu->per_cu->set_unit_type (DW_UT_partial);
|
|
break;
|
|
case DW_TAG_type_unit:
|
|
cu->per_cu->set_unit_type (DW_UT_type);
|
|
break;
|
|
default:
|
|
error (_(DWARF_ERROR_PREFIX
|
|
"unexpected tag '%s' at offset %s"),
|
|
dwarf_tag_name (comp_unit_die->tag),
|
|
sect_offset_str (cu->per_cu->sect_off));
|
|
}
|
|
|
|
cu->per_cu->set_lang (lang, dw_lang);
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
dwarf2_cu *
|
|
dwarf2_per_objfile::get_cu (dwarf2_per_cu_data *per_cu)
|
|
{
|
|
auto it = m_dwarf2_cus.find (per_cu);
|
|
if (it == m_dwarf2_cus.end ())
|
|
return nullptr;
|
|
|
|
return it->second.get ();
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
void
|
|
dwarf2_per_objfile::set_cu (dwarf2_per_cu_data *per_cu,
|
|
std::unique_ptr<dwarf2_cu> cu)
|
|
{
|
|
gdb_assert (this->get_cu (per_cu) == nullptr);
|
|
|
|
m_dwarf2_cus[per_cu] = std::move (cu);
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
void
|
|
dwarf2_per_objfile::age_comp_units ()
|
|
{
|
|
dwarf_read_debug_printf_v ("running");
|
|
|
|
/* This is not expected to be called in the middle of CU expansion. There is
|
|
an invariant that if a CU is in the CUs-to-expand queue, its DIEs are
|
|
loaded in memory. Calling age_comp_units while the queue is in use could
|
|
make us free the DIEs for a CU that is in the queue and therefore break
|
|
that invariant. */
|
|
gdb_assert (!queue.has_value ());
|
|
|
|
/* Start by clearing all marks. */
|
|
for (const auto &pair : m_dwarf2_cus)
|
|
pair.second->clear_mark ();
|
|
|
|
/* Traverse all CUs, mark them and their dependencies if used recently
|
|
enough. */
|
|
for (const auto &pair : m_dwarf2_cus)
|
|
{
|
|
dwarf2_cu *cu = pair.second.get ();
|
|
|
|
cu->last_used++;
|
|
if (cu->last_used <= dwarf_max_cache_age)
|
|
cu->mark ();
|
|
}
|
|
|
|
/* Delete all CUs still not marked. */
|
|
for (auto it = m_dwarf2_cus.begin (); it != m_dwarf2_cus.end ();)
|
|
{
|
|
dwarf2_cu *cu = it->second.get ();
|
|
|
|
if (!cu->is_marked ())
|
|
{
|
|
dwarf_read_debug_printf_v ("deleting old CU %s",
|
|
sect_offset_str (cu->per_cu->sect_off));
|
|
it = m_dwarf2_cus.erase (it);
|
|
}
|
|
else
|
|
it++;
|
|
}
|
|
}
|
|
|
|
/* See read.h. */
|
|
|
|
void
|
|
dwarf2_per_objfile::remove_cu (dwarf2_per_cu_data *per_cu)
|
|
{
|
|
auto it = m_dwarf2_cus.find (per_cu);
|
|
if (it == m_dwarf2_cus.end ())
|
|
return;
|
|
|
|
m_dwarf2_cus.erase (it);
|
|
}
|
|
|
|
dwarf2_per_objfile::~dwarf2_per_objfile ()
|
|
{
|
|
remove_all_cus ();
|
|
}
|
|
|
|
/* Set the type associated with DIE to TYPE. Save it in CU's hash
|
|
table if necessary. For convenience, return TYPE.
|
|
|
|
The DIEs reading must have careful ordering to:
|
|
* Not cause infinite loops trying to read in DIEs as a prerequisite for
|
|
reading current DIE.
|
|
* Not trying to dereference contents of still incompletely read in types
|
|
while reading in other DIEs.
|
|
* Enable referencing still incompletely read in types just by a pointer to
|
|
the type without accessing its fields.
|
|
|
|
Therefore caller should follow these rules:
|
|
* Try to fetch any prerequisite types we may need to build this DIE type
|
|
before building the type and calling set_die_type.
|
|
* After building type call set_die_type for current DIE as soon as
|
|
possible before fetching more types to complete the current type.
|
|
* Make the type as complete as possible before fetching more types. */
|
|
|
|
static struct type *
|
|
set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
|
|
bool skip_data_location)
|
|
{
|
|
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
|
struct attribute *attr;
|
|
struct dynamic_prop prop;
|
|
|
|
/* For Ada types, make sure that the gnat-specific data is always
|
|
initialized (if not already set). There are a few types where
|
|
we should not be doing so, because the type-specific area is
|
|
already used to hold some other piece of info (eg: TYPE_CODE_FLT
|
|
where the type-specific area is used to store the floatformat).
|
|
But this is not a problem, because the gnat-specific information
|
|
is actually not needed for these types. */
|
|
if (need_gnat_info (cu)
|
|
&& type->code () != TYPE_CODE_FUNC
|
|
&& type->code () != TYPE_CODE_FLT
|
|
&& type->code () != TYPE_CODE_METHODPTR
|
|
&& type->code () != TYPE_CODE_MEMBERPTR
|
|
&& type->code () != TYPE_CODE_METHOD
|
|
&& type->code () != TYPE_CODE_FIXED_POINT
|
|
&& !HAVE_GNAT_AUX_INFO (type))
|
|
INIT_GNAT_SPECIFIC (type);
|
|
|
|
/* Read DW_AT_allocated and set in type. */
|
|
attr = dwarf2_attr (die, DW_AT_allocated, cu);
|
|
if (attr != NULL)
|
|
{
|
|
struct type *prop_type = cu->addr_sized_int_type (false);
|
|
if (attr_to_dynamic_prop (attr, die, cu, &prop, prop_type))
|
|
type->add_dyn_prop (DYN_PROP_ALLOCATED, prop);
|
|
}
|
|
|
|
/* Read DW_AT_associated and set in type. */
|
|
attr = dwarf2_attr (die, DW_AT_associated, cu);
|
|
if (attr != NULL)
|
|
{
|
|
struct type *prop_type = cu->addr_sized_int_type (false);
|
|
if (attr_to_dynamic_prop (attr, die, cu, &prop, prop_type))
|
|
type->add_dyn_prop (DYN_PROP_ASSOCIATED, prop);
|
|
}
|
|
|
|
/* Read DW_AT_rank and set in type. */
|
|
attr = dwarf2_attr (die, DW_AT_rank, cu);
|
|
if (attr != NULL)
|
|
{
|
|
struct type *prop_type = cu->addr_sized_int_type (false);
|
|
if (attr_to_dynamic_prop (attr, die, cu, &prop, prop_type))
|
|
type->add_dyn_prop (DYN_PROP_RANK, prop);
|
|
}
|
|
|
|
/* Read DW_AT_data_location and set in type. */
|
|
if (!skip_data_location)
|
|
{
|
|
attr = dwarf2_attr (die, DW_AT_data_location, cu);
|
|
if (attr_to_dynamic_prop (attr, die, cu, &prop, cu->addr_type ()))
|
|
type->add_dyn_prop (DYN_PROP_DATA_LOCATION, prop);
|
|
}
|
|
|
|
bool inserted
|
|
= per_objfile->die_type_hash.emplace
|
|
(per_cu_and_offset {cu->per_cu, die->sect_off}, type).second;
|
|
if (!inserted)
|
|
complaint (_("A problem internal to GDB: DIE %s has type already set"),
|
|
sect_offset_str (die->sect_off));
|
|
|
|
return type;
|
|
}
|
|
|
|
/* Look up the type for the die at SECT_OFF in PER_CU in die_type_hash,
|
|
or return NULL if the die does not have a saved type. */
|
|
|
|
static struct type *
|
|
get_die_type_at_offset (sect_offset sect_off,
|
|
dwarf2_per_cu_data *per_cu,
|
|
dwarf2_per_objfile *per_objfile)
|
|
{
|
|
auto it = per_objfile->die_type_hash.find ({per_cu, sect_off});
|
|
|
|
return it != per_objfile->die_type_hash.end () ? it->second : nullptr;
|
|
}
|
|
|
|
/* Look up the type for DIE in CU in die_type_hash,
|
|
or return NULL if DIE does not have a saved type. */
|
|
|
|
static struct type *
|
|
get_die_type (struct die_info *die, struct dwarf2_cu *cu)
|
|
{
|
|
return get_die_type_at_offset (die->sect_off, cu->per_cu, cu->per_objfile);
|
|
}
|
|
|
|
struct cmd_list_element *set_dwarf_cmdlist;
|
|
struct cmd_list_element *show_dwarf_cmdlist;
|
|
|
|
static void
|
|
show_check_physname (struct ui_file *file, int from_tty,
|
|
struct cmd_list_element *c, const char *value)
|
|
{
|
|
gdb_printf (file,
|
|
_("Whether to check \"physname\" is %s.\n"),
|
|
value);
|
|
}
|
|
|
|
void _initialize_dwarf2_read ();
|
|
void
|
|
_initialize_dwarf2_read ()
|
|
{
|
|
add_setshow_prefix_cmd ("dwarf", class_maintenance,
|
|
_("\
|
|
Set DWARF specific variables.\n\
|
|
Configure DWARF variables such as the cache size."),
|
|
_("\
|
|
Show DWARF specific variables.\n\
|
|
Show DWARF variables such as the cache size."),
|
|
&set_dwarf_cmdlist, &show_dwarf_cmdlist,
|
|
&maintenance_set_cmdlist, &maintenance_show_cmdlist);
|
|
|
|
add_setshow_zinteger_cmd ("max-cache-age", class_obscure,
|
|
&dwarf_max_cache_age, _("\
|
|
Set the upper bound on the age of cached DWARF compilation units."), _("\
|
|
Show the upper bound on the age of cached DWARF compilation units."), _("\
|
|
A higher limit means that cached compilation units will be stored\n\
|
|
in memory longer, and more total memory will be used. Zero disables\n\
|
|
caching, which can slow down startup."),
|
|
NULL,
|
|
show_dwarf_max_cache_age,
|
|
&set_dwarf_cmdlist,
|
|
&show_dwarf_cmdlist);
|
|
|
|
add_setshow_boolean_cmd ("synchronous", class_obscure,
|
|
&dwarf_synchronous, _("\
|
|
Set whether DWARF is read synchronously."), _("\
|
|
Show whether DWARF is read synchronously."), _("\
|
|
By default, DWARF information is read in worker threads,\n\
|
|
and gdb will not generally wait for the reading to complete\n\
|
|
before continuing with other work, for example presenting a\n\
|
|
prompt to the user.\n\
|
|
Enabling this setting will cause the DWARF reader to always wait\n\
|
|
for debug info processing to be finished before gdb can proceed."),
|
|
nullptr,
|
|
show_dwarf_synchronous,
|
|
&set_dwarf_cmdlist,
|
|
&show_dwarf_cmdlist);
|
|
|
|
add_setshow_zuinteger_cmd ("dwarf-read", no_class, &dwarf_read_debug, _("\
|
|
Set debugging of the DWARF reader."), _("\
|
|
Show debugging of the DWARF reader."), _("\
|
|
When enabled (non-zero), debugging messages are printed during DWARF\n\
|
|
reading and symtab expansion. A value of 1 (one) provides basic\n\
|
|
information. A value greater than 1 provides more verbose information."),
|
|
NULL,
|
|
NULL,
|
|
&setdebuglist, &showdebuglist);
|
|
|
|
add_setshow_zuinteger_cmd ("dwarf-die", no_class, &dwarf_die_debug, _("\
|
|
Set debugging of the DWARF DIE reader."), _("\
|
|
Show debugging of the DWARF DIE reader."), _("\
|
|
When enabled (non-zero), DIEs are dumped after they are read in.\n\
|
|
The value is the maximum depth to print."),
|
|
NULL,
|
|
NULL,
|
|
&setdebuglist, &showdebuglist);
|
|
|
|
add_setshow_zuinteger_cmd ("dwarf-line", no_class, &dwarf_line_debug, _("\
|
|
Set debugging of the dwarf line reader."), _("\
|
|
Show debugging of the dwarf line reader."), _("\
|
|
When enabled (non-zero), line number entries are dumped as they are read in.\n\
|
|
A value of 1 (one) provides basic information.\n\
|
|
A value greater than 1 provides more verbose information."),
|
|
NULL,
|
|
NULL,
|
|
&setdebuglist, &showdebuglist);
|
|
|
|
add_setshow_boolean_cmd ("check-physname", no_class, &check_physname, _("\
|
|
Set cross-checking of \"physname\" code against demangler."), _("\
|
|
Show cross-checking of \"physname\" code against demangler."), _("\
|
|
When enabled, GDB's internal \"physname\" code is checked against\n\
|
|
the demangler."),
|
|
NULL, show_check_physname,
|
|
&setdebuglist, &showdebuglist);
|
|
|
|
dwarf2_locexpr_index = register_symbol_computed_impl (LOC_COMPUTED,
|
|
&dwarf2_locexpr_funcs);
|
|
dwarf2_loclist_index = register_symbol_computed_impl (LOC_COMPUTED,
|
|
&dwarf2_loclist_funcs);
|
|
ada_imported_index = register_symbol_computed_impl (LOC_COMPUTED,
|
|
&ada_imported_funcs);
|
|
|
|
dwarf2_locexpr_block_index = register_symbol_block_impl (LOC_BLOCK,
|
|
&dwarf2_block_frame_base_locexpr_funcs);
|
|
dwarf2_loclist_block_index = register_symbol_block_impl (LOC_BLOCK,
|
|
&dwarf2_block_frame_base_loclist_funcs);
|
|
ada_block_index = register_symbol_block_impl (LOC_BLOCK,
|
|
&ada_function_alias_funcs);
|
|
|
|
#if GDB_SELF_TEST
|
|
selftests::register_test ("dw2_expand_symtabs_matching",
|
|
selftests::dw2_expand_symtabs_matching::run_test);
|
|
selftests::register_test ("dwarf2_find_containing_comp_unit",
|
|
selftests::find_containing_comp_unit::run_test);
|
|
#endif
|
|
}
|