/* DWARF 2 debugging format support for GDB.
- Copyright (C) 1994-2020 Free Software Foundation, Inc.
+ Copyright (C) 1994-2021 Free Software Foundation, Inc.
Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology,
Inc. with support from Florida State University (under contract
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;
}
}
+/* Attempt to find a .dwz file (whose full path is represented by
+ FILENAME) in all of the specified debug file directories provided.
+
+ Return the equivalent gdb_bfd_ref_ptr of the .dwz file found, or
+ nullptr if it could not find anything. */
+
+static gdb_bfd_ref_ptr
+dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid,
+ size_t buildid_len)
+{
+ /* Let's assume that the path represented by FILENAME has the
+ "/.dwz/" subpath in it. This is what (most) GNU/Linux
+ distributions do, anyway. */
+ size_t dwz_pos = filename.find ("/.dwz/");
+
+ if (dwz_pos == std::string::npos)
+ return nullptr;
+
+ /* This is an obvious assertion, but it's here more to educate
+ future readers of this code that FILENAME at DWZ_POS *must*
+ contain a directory separator. */
+ gdb_assert (IS_DIR_SEPARATOR (filename[dwz_pos]));
+
+ gdb_bfd_ref_ptr dwz_bfd;
+ std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec
+ = dirnames_to_char_ptr_vec (debug_file_directory);
+
+ for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec)
+ {
+ /* The idea is to iterate over the
+ debug file directories provided by the user and
+ replace the hard-coded path in the "filename" by each
+ debug-file-directory.
+
+ For example, suppose that filename is:
+
+ /usr/lib/debug/.dwz/foo.dwz
+
+ And suppose that we have "$HOME/bar" as the
+ debug-file-directory. We would then adjust filename
+ to look like:
+
+ $HOME/bar/.dwz/foo.dwz
+
+ which would hopefully allow us to find the alt debug
+ file. */
+ std::string ddir = debugdir.get ();
+
+ if (ddir.empty ())
+ continue;
+
+ /* Make sure the current debug-file-directory ends with a
+ directory separator. This is needed because, if FILENAME
+ contains something like "/usr/lib/abcde/.dwz/foo.dwz" and
+ DDIR is "/usr/lib/abc", then could wrongfully skip it
+ below. */
+ if (!IS_DIR_SEPARATOR (ddir.back ()))
+ ddir += SLASH_STRING;
+
+ /* Check whether the beginning of FILENAME is DDIR. If it is,
+ then we are dealing with a file which we already attempted to
+ open before, so we just skip it and continue processing the
+ remaining debug file directories. */
+ if (filename.size () > ddir.size ()
+ && filename.compare (0, ddir.size (), ddir) == 0)
+ continue;
+
+ /* Replace FILENAME's default debug-file-directory with
+ DDIR. */
+ std::string new_filename = ddir + &filename[dwz_pos + 1];
+
+ dwz_bfd = gdb_bfd_open (new_filename.c_str (), gnutarget);
+
+ if (dwz_bfd == nullptr)
+ continue;
+
+ if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
+ {
+ dwz_bfd.reset (nullptr);
+ continue;
+ }
+
+ /* Found it. */
+ break;
+ }
+
+ return dwz_bfd;
+}
+
/* See dwarf2read.h. */
struct dwz_file *
dwarf2_get_dwz_file (dwarf2_per_bfd *per_bfd)
{
- const char *filename;
bfd_size_type buildid_len_arg;
size_t buildid_len;
bfd_byte *buildid;
buildid_len = (size_t) buildid_len_arg;
- filename = data.get ();
+ std::string filename = data.get ();
- std::string abs_storage;
- if (!IS_ABSOLUTE_PATH (filename))
+ if (!IS_ABSOLUTE_PATH (filename.c_str ()))
{
gdb::unique_xmalloc_ptr<char> abs
= gdb_realpath (bfd_get_filename (per_bfd->obfd));
- abs_storage = ldirname (abs.get ()) + SLASH_STRING + filename;
- filename = abs_storage.c_str ();
+ filename = ldirname (abs.get ()) + SLASH_STRING + filename;
}
/* First try the file name given in the section. If that doesn't
work, try to use the build-id instead. */
- gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename, gnutarget));
+ gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename.c_str (), gnutarget));
if (dwz_bfd != NULL)
{
if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
if (dwz_bfd == NULL)
dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid);
+ if (dwz_bfd == nullptr)
+ {
+ /* If the user has provided us with different
+ debug file directories, we can try them in order. */
+ dwz_bfd = dwz_search_other_debugdirs (filename, buildid, buildid_len);
+ }
+
if (dwz_bfd == nullptr)
{
gdb::unique_xmalloc_ptr<char> alt_filename;
return cu;
}
-/* Read in the symbols for PER_CU in the context of DWARF"_PER_OBJFILE. */
+/* 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,
/* 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 (dwarf2_per_objfile);
+ dwarf2_queue_guard q_guard (per_objfile);
if (!per_objfile->symtab_set_p (per_cu))
{
? &dwo_file->sections.abbrev
: &per_objfile->per_bfd->abbrev);
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
- section->get_name (),
- abbrev_section->get_file_name ());
+ dwarf_read_debug_printf ("Reading %s for %s:",
+ section->get_name (),
+ abbrev_section->get_file_name ());
section->read (objfile);
info_ptr = section->buffer;
}
*slot = dwo_file ? (void *) dwo_tu : (void *) sig_type;
- if (dwarf_read_debug > 1)
- fprintf_unfiltered (gdb_stdlog, " offset %s, signature %s\n",
- sect_offset_str (sect_off),
- hex_string (header.signature));
+ dwarf_read_debug_printf_v (" offset %s, signature %s",
+ sect_offset_str (sect_off),
+ hex_string (header.signature));
info_ptr += length;
}
dwo_unit->length = cu->header.get_length ();
}
+ dwo_abbrev_section->read (objfile);
*result_dwo_abbrev_table
- = abbrev_table::read (objfile, dwo_abbrev_section,
- cu->header.abbrev_sect_off);
+ = 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 ());
gdb_assert (cu->header.abbrev_sect_off == abbrev_table->sect_off);
else
{
+ abbrev_section->read (objfile);
m_abbrev_table_holder
- = abbrev_table::read (objfile, abbrev_section,
- cu->header.abbrev_sect_off);
+ = abbrev_table::read (abbrev_section, cu->header.abbrev_sect_off);
abbrev_table = m_abbrev_table_holder.get ();
}
return;
}
+ abbrev_section->read (objfile);
m_abbrev_table_holder
- = abbrev_table::read (objfile, abbrev_section,
- m_new_cu->header.abbrev_sect_off);
+ = 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 ());
and build a psymtab for each of them. */
dwarf2_build_include_psymtabs (cu, comp_unit_die, pst);
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Psymtab for %s unit @%s: %s - %s"
- ", %d global, %d static syms\n",
- per_cu->is_debug_types ? "type" : "comp",
- sect_offset_str (per_cu->sect_off),
- paddress (gdbarch, pst->text_low (objfile)),
- paddress (gdbarch, pst->text_high (objfile)),
- (int) pst->global_psymbols.size (),
- (int) pst->static_psymbols.size ());
+ dwarf_read_debug_printf ("Psymtab for %s unit @%s: %s - %s"
+ ", %d global, %d static syms",
+ per_cu->is_debug_types ? "type" : "comp",
+ sect_offset_str (per_cu->sect_off),
+ paddress (gdbarch, pst->text_low (objfile)),
+ paddress (gdbarch, pst->text_high (objfile)),
+ (int) pst->global_psymbols.size (),
+ (int) pst->static_psymbols.size ());
}
/* Subroutine of dwarf2_build_psymtabs_hard to simplify it.
[IWBN if DWO skeletons had DW_AT_stmt_list]
call FUNC */
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "Building type unit groups ...\n");
+ dwarf_read_debug_printf ("Building type unit groups ...");
/* Sort in a separate table to maintain the order of all_type_units
for .gdb_index: TU indices directly index all_type_units. */
|| 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->objfile,
- &per_objfile->per_bfd->abbrev, abbrev_offset);
+ abbrev_table::read (&per_objfile->per_bfd->abbrev, abbrev_offset);
++tu_stats->nr_uniq_abbrev_tables;
}
{
struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats;
- fprintf_unfiltered (gdb_stdlog, "Type unit statistics:\n");
- fprintf_unfiltered (gdb_stdlog, " %zu TUs\n",
- per_objfile->per_bfd->all_type_units.size ());
- fprintf_unfiltered (gdb_stdlog, " %d uniq abbrev tables\n",
- tu_stats->nr_uniq_abbrev_tables);
- fprintf_unfiltered (gdb_stdlog, " %d symtabs from stmt_list entries\n",
- tu_stats->nr_symtabs);
- fprintf_unfiltered (gdb_stdlog, " %d symtab sharers\n",
- tu_stats->nr_symtab_sharers);
- fprintf_unfiltered (gdb_stdlog, " %d type units without a stmt_list\n",
- tu_stats->nr_stmt_less_type_units);
- fprintf_unfiltered (gdb_stdlog, " %d all_type_units reallocs\n",
- tu_stats->nr_all_type_units_reallocs);
+ dwarf_read_debug_printf ("Type unit statistics:");
+ dwarf_read_debug_printf (" %zu TUs",
+ per_objfile->per_bfd->all_type_units.size ());
+ 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);
}
/* Traversal function for build_type_psymtabs. */
{
struct objfile *objfile = per_objfile->objfile;
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Building psymtabs of objfile %s ...\n",
- objfile_name (objfile));
- }
+ dwarf_read_debug_printf ("Building psymtabs of objfile %s ...",
+ objfile_name (objfile));
scoped_restore restore_reading_psyms
= make_scoped_restore (&per_objfile->per_bfd->reading_partial_symbols,
build_type_psymtab_dependencies, per_objfile);
}
- if (dwarf_read_debug)
+ if (dwarf_read_debug > 0)
print_tu_stats (per_objfile);
set_partial_user (per_objfile);
/* At this point we want to keep the address map. */
save_psymtabs_addrmap.release ();
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "Done building psymtabs of %s\n",
- objfile_name (objfile));
+ dwarf_read_debug_printf ("Done building psymtabs of %s",
+ objfile_name (objfile));
}
/* Load the partial DIEs for a secondary CU into memory.
const gdb_byte *info_ptr;
struct objfile *objfile = per_objfile->objfile;
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "Reading %s for %s\n",
- section->get_name (),
- section->get_file_name ());
+ dwarf_read_debug_printf ("Reading %s for %s",
+ section->get_name (),
+ section->get_file_name ());
section->read (objfile);
where = psymbol_placement::STATIC;
}
break;
+ case DW_TAG_array_type:
case DW_TAG_typedef:
case DW_TAG_base_type:
case DW_TAG_subrange_type:
/* If it's already on the queue, we have nothing to do. */
if (per_cu->queued)
- return 0;
+ {
+ /* Verify the invariant that if a CU is queued for expansion, its DIEs are
+ loaded. */
+ gdb_assert (per_objfile->get_cu (per_cu) != nullptr);
+ return 0;
+ }
/* If the compilation unit is already loaded, just mark it as
used. */
static void
process_queue (dwarf2_per_objfile *per_objfile)
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog,
- "Expanding one or more symtabs of objfile %s ...\n",
- objfile_name (per_objfile->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. */
}
if (dwarf_read_debug >= debug_print_threshold)
- fprintf_unfiltered (gdb_stdlog, "Expanding symtab of %s\n", buf);
+ dwarf_read_debug_printf ("Expanding symtab of %s", buf);
if (per_cu->is_debug_types)
process_full_type_unit (cu, item.pretend_language);
process_full_comp_unit (cu, item.pretend_language);
if (dwarf_read_debug >= debug_print_threshold)
- fprintf_unfiltered (gdb_stdlog, "Done expanding %s\n", buf);
+ dwarf_read_debug_printf ("Done expanding %s", buf);
}
}
per_objfile->per_bfd->queue.pop ();
}
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Done expanding symtabs of %s.\n",
- objfile_name (per_objfile->objfile));
- }
+ dwarf_read_debug_printf ("Done expanding symtabs of %s.",
+ objfile_name (per_objfile->objfile));
}
/* Read in full symbols for PST, and anything it depends on. */
read them on-demand through read_type_die. */
case DW_TAG_subroutine_type:
case DW_TAG_set_type:
- case DW_TAG_array_type:
case DW_TAG_pointer_type:
case DW_TAG_ptr_to_member_type:
case DW_TAG_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->language != language_ada)
+ break;
+ /* FALLTHROUGH */
case DW_TAG_base_type:
case DW_TAG_subrange_type:
case DW_TAG_typedef:
struct attribute *attr;
struct die_info *child;
int first = 1;
+ const language_defn *cplus_lang = language_def (cu->language);
die->building_fullname = 1;
if (child->tag == DW_TAG_template_type_param)
{
- c_print_type (type, "", &buf, -1, 0, cu->language,
- &type_print_raw_options);
+ cplus_lang->print_type (type, "", &buf, -1, 0,
+ &type_print_raw_options);
continue;
}
if (type->has_no_signedness ())
/* GDB prints characters as NUMBER 'CHAR'. If that's
changed, this can use value_print instead. */
- c_printchar (value, type, &buf);
+ cplus_lang->printchar (value, type, &buf);
else
{
struct value_print_options opts;
dwo_unit->sect_off = sect_off;
dwo_unit->length = cu->per_cu->length;
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, " offset %s, dwo_id %s\n",
- sect_offset_str (sect_off),
- hex_string (dwo_unit->signature));
+ 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.
if (info_ptr == NULL)
return;
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
- section.get_name (),
- section.get_file_name ());
- }
+ 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)
gdb_assert (dwp_file->version == 1);
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Reading %s %s/%s in DWP V1 file: %s\n",
- kind,
- pulongest (unit_index), hex_string (signature),
- dwp_file->name);
- }
+ 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
/* Create one if necessary. */
if (*dwo_file_slot == NULL)
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n",
- virtual_dwo_name.c_str ());
- }
+ dwarf_read_debug_printf ("Creating virtual DWO: %s",
+ virtual_dwo_name.c_str ());
+
dwo_file = new struct dwo_file;
dwo_file->dwo_name = per_objfile->objfile->intern (virtual_dwo_name);
dwo_file->comp_dir = comp_dir;
}
else
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n",
- virtual_dwo_name.c_str ());
- }
+ dwarf_read_debug_printf ("Using existing virtual DWO: %s",
+ virtual_dwo_name.c_str ());
+
dwo_file = (struct dwo_file *) *dwo_file_slot;
}
gdb_assert (dwp_file->version == 2);
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Reading %s %s/%s in DWP V2 file: %s\n",
- kind,
- pulongest (unit_index), hex_string (signature),
- dwp_file->name);
- }
+ 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. */
/* Create one if necessary. */
if (*dwo_file_slot == NULL)
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n",
- virtual_dwo_name.c_str ());
- }
+ dwarf_read_debug_printf ("Creating virtual DWO: %s",
+ virtual_dwo_name.c_str ());
+
dwo_file = new struct dwo_file;
dwo_file->dwo_name = per_objfile->objfile->intern (virtual_dwo_name);
dwo_file->comp_dir = comp_dir;
}
else
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n",
- virtual_dwo_name.c_str ());
- }
+ dwarf_read_debug_printf ("Using existing virtual DWO: %s",
+ virtual_dwo_name.c_str ());
+
dwo_file = (struct dwo_file *) *dwo_file_slot;
}
gdb_assert (dwp_file->version == 5);
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Reading %s %s/%s in DWP V5 file: %s\n",
- kind,
- pulongest (unit_index), hex_string (signature),
- dwp_file->name);
- }
+ 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. */
/* Create one if necessary. */
if (*dwo_file_slot == NULL)
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n",
- virtual_dwo_name.c_str ());
- }
+ dwarf_read_debug_printf ("Creating virtual DWO: %s",
+ virtual_dwo_name.c_str ());
+
dwo_file = new struct dwo_file;
dwo_file->dwo_name = per_objfile->objfile->intern (virtual_dwo_name);
dwo_file->comp_dir = comp_dir;
}
else
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n",
- virtual_dwo_name.c_str ());
- }
+ dwarf_read_debug_printf ("Using existing virtual DWO: %s",
+ virtual_dwo_name.c_str ());
+
dwo_file = (struct dwo_file *) *dwo_file_slot;
}
gdb_bfd_ref_ptr dbfd = open_dwo_file (per_objfile, dwo_name, comp_dir);
if (dbfd == NULL)
{
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "DWO file not found: %s\n", dwo_name);
+ dwarf_read_debug_printf ("DWO file not found: %s", dwo_name);
+
return NULL;
}
rcuh_kind::TYPE);
}
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "DWO file found: %s\n", dwo_name);
+ dwarf_read_debug_printf ("DWO file found: %s", dwo_name);
return dwo_file.release ();
}
if (dbfd == NULL)
{
- if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "DWP file not found: %s\n", dwp_name.c_str ());
+ dwarf_read_debug_printf ("DWP file not found: %s", dwp_name.c_str ());
+
return std::unique_ptr<dwp_file> ();
}
dwp_file->loaded_cus = allocate_dwp_loaded_cutus_table ();
dwp_file->loaded_tus = allocate_dwp_loaded_cutus_table ();
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "DWP file found: %s\n", dwp_file->name);
- fprintf_unfiltered (gdb_stdlog,
- " %s CUs, %s TUs\n",
- pulongest (dwp_file->cus ? dwp_file->cus->nr_units : 0),
- pulongest (dwp_file->tus ? dwp_file->tus->nr_units : 0));
- }
+ 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));
return dwp_file;
}
if (dwo_cutu != NULL)
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog,
- "Virtual DWO %s %s found: @%s\n",
- kind, hex_string (signature),
- host_address_to_string (dwo_cutu));
- }
+ dwarf_read_debug_printf ("Virtual DWO %s %s found: @%s",
+ kind, hex_string (signature),
+ host_address_to_string (dwo_cutu));
+
return dwo_cutu;
}
}
if (dwo_cutu != NULL)
{
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "DWO %s %s(%s) found: @%s\n",
- kind, dwo_name, hex_string (signature),
- host_address_to_string (dwo_cutu));
- }
+ 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;
}
}
someone deleted the DWO/DWP file, or the search path isn't set up
correctly to find the file. */
- if (dwarf_read_debug)
- {
- fprintf_unfiltered (gdb_stdlog, "DWO %s %s(%s) not found\n",
- kind, dwo_name, hex_string (signature));
- }
+ 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). */
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 (type));
+ if (new_target == nullptr)
+ {
+ /* Maybe we don't need to rewrite this array. */
+ if (current_bounds->low.kind () == PROP_CONST
+ && current_bounds->high.kind () == PROP_CONST)
+ 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);
+ int nfields = copy->num_fields ();
+ field *new_fields
+ = ((struct field *) TYPE_ZALLOC (copy,
+ nfields * sizeof (struct field)));
+ memcpy (new_fields, copy->fields (), nfields * sizeof (struct field));
+ copy->set_fields (new_fields);
+ if (new_target != nullptr)
+ TYPE_TARGET_TYPE (copy) = 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
/* Make sure we're looking at a pointer to an array. */
if (type->field (0).type ()->code () != TYPE_CODE_PTR)
return;
- struct type *ary_type = TYPE_TARGET_TYPE (type->field (0).type ());
- while (ary_type->code () == TYPE_CODE_ARRAY)
- {
- /* The Ada code already knows how to handle these types, so all
- that we need to do is turn the bounds into static bounds. */
- struct type *index_type = ary_type->index_type ();
-
- index_type->bounds ()->low.set_const_val (1);
- index_type->bounds ()->high.set_const_val (0);
-
- /* Handle multi-dimensional arrays. */
- ary_type = TYPE_TARGET_TYPE (ary_type);
- }
+ /* 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_TARGET_TYPE (type->field (0).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
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)
+ {
+ mpz_import (value->val, len,
+ bfd_big_endian (cu->per_objfile->objfile->obfd) ? 1 : -1,
+ 1, 0, 0, ptr);
+ return;
+ }
+ }
+
+ /* On failure set it to 1. */
+ *value = gdb_mpz (1);
+ }
+ else if (attr->form_is_block ())
+ {
+ dwarf_block *blk = attr->as_block ();
+ mpz_import (value->val, blk->size,
+ bfd_big_endian (cu->per_objfile->objfile->obfd) ? 1 : -1,
+ 1, 0, 0, blk->data);
+ }
+ 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 (mpz_sgn (num.val) == -1 && mpz_sgn (denom.val) == -1)
+ {
+ mpz_neg (num.val, num.val);
+ mpz_neg (denom.val, denom.val);
+ }
+ else if (mpz_sgn (num.val) == -1)
+ {
+ complaint (_("unexpected negative value for DW_AT_GNU_numerator"
+ " in DIE at %s"),
+ sect_offset_str (die->sect_off));
+ return;
+ }
+ else if (mpz_sgn (denom.val) == -1)
+ {
+ 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 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. */
+
+static void
+finish_fixed_point_type (struct type *type, struct die_info *die,
+ struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+
+ gdb_assert (type->code () == TYPE_CODE_FIXED_POINT
+ && TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_FIXED_POINT);
+
+ attr = dwarf2_attr (die, DW_AT_binary_scale, cu);
+ if (!attr)
+ attr = dwarf2_attr (die, DW_AT_decimal_scale, cu);
+ if (!attr)
+ 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)
+ {
+ /* 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. */
+ 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;
+
+ mpz_mul_2exp (num_or_denom->val, num_or_denom->val, 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;
+
+ mpz_ui_pow_ui (num_or_denom->val, 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));
+ }
+
+ gdb_mpq &scaling_factor = type->fixed_point_info ().scaling_factor;
+ mpz_set (mpq_numref (scaling_factor.val), scale_num.val);
+ mpz_set (mpq_denref (scaling_factor.val), scale_denom.val);
+ mpq_canonicalize (scaling_factor.val);
+}
+
/* 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. */
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 mpz_sgn (num.val) == 0 && mpz_sgn (denom.val) == 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
}
}
+ if ((encoding == DW_ATE_signed_fixed || encoding == DW_ATE_unsigned_fixed)
+ && cu->language == 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.
+
+ Ideally, GNAT should be declaring this type the same way
+ it declares other fixed point types when using the legacy
+ GNAT encoding, which is to use a simple signed or unsigned
+ base type. A report to the GNAT team has been created to
+ look into it. In the meantime, pretend this type is a simple
+ signed or unsigned integral, rather than a fixed point type,
+ to avoid any confusion later on as to how to process this type. */
+ encoding = (encoding == DW_ATE_signed_fixed
+ ? DW_ATE_signed
+ : DW_ATE_unsigned);
+ }
+
switch (encoding)
{
case DW_ATE_address:
return set_die_type (die, type, cu);
}
break;
+ case DW_ATE_signed_fixed:
+ type = init_fixed_point_type (objfile, bits, 0, name);
+ finish_fixed_point_type (type, die, cu);
+ break;
+ case DW_ATE_unsigned_fixed:
+ type = init_fixed_point_type (objfile, bits, 1, name);
+ finish_fixed_point_type (type, die, cu);
+ break;
default:
complaint (_("unsupported DW_AT_encoding: '%s'"),
symbol for. */
static int
-is_type_tag_for_partial (int tag)
+is_type_tag_for_partial (int tag, enum language lang)
{
switch (tag)
{
#if 0
/* Some types that would be reasonable to generate partial symbols for,
- that we don't at present. */
- case DW_TAG_array_type:
+ that we don't at present. Note that normally this does not
+ matter, mainly because C compilers don't give names to these
+ types, but instead emit DW_TAG_typedef. */
case DW_TAG_file_type:
case DW_TAG_ptr_to_member_type:
case DW_TAG_set_type:
case DW_TAG_string_type:
case DW_TAG_subroutine_type:
#endif
+
+ /* GNAT may emit an array with a name, but no typedef, so we
+ need to make a symbol in this case. */
+ case DW_TAG_array_type:
+ return lang == language_ada;
+
case DW_TAG_base_type:
case DW_TAG_class_type:
case DW_TAG_interface_type:
later variables referencing them via DW_AT_specification (for
static members). */
if (!load_all
- && !is_type_tag_for_partial (abbrev->tag)
+ && !is_type_tag_for_partial (abbrev->tag, cu->language)
&& abbrev->tag != DW_TAG_constant
&& abbrev->tag != DW_TAG_enumerator
&& abbrev->tag != DW_TAG_subprogram
&& pdi.is_declaration == 0
&& ((pdi.tag == DW_TAG_typedef && !pdi.has_children)
|| pdi.tag == DW_TAG_base_type
+ || pdi.tag == DW_TAG_array_type
|| pdi.tag == DW_TAG_subrange_type))
{
if (building_psymtab && pdi.raw_name != NULL)
/* It would be nice to reuse dwarf2_get_pc_bounds here,
but that requires a full DIE, so instead we just
reimplement it. */
- unsigned int ranges_offset = (attr.constant_value (0)
+ unsigned int ranges_offset = (attr.as_unsigned ()
+ (need_ranges_base
? cu->ranges_base
: 0));
SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
list_to_add = cu->list_in_scope;
break;
+ case DW_TAG_array_type:
case DW_TAG_base_type:
case DW_TAG_subrange_type:
SYMBOL_ACLASS_INDEX (sym) = LOC_TYPEDEF;
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.
per_cu = dwarf2_find_containing_comp_unit (sect_off, offset_in_dwz,
per_objfile);
+ 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. */
if (maybe_queue_comp_unit (cu, per_cu, per_objfile, cu->language))
load_full_comp_unit (per_cu, per_objfile, per_objfile->get_cu (per_cu),
void
dwarf2_per_objfile::age_comp_units ()
{
+ dwarf_read_debug_printf_v ("running");
+
/* Start by clearing all marks. */
for (auto pair : m_dwarf2_cus)
pair.second->mark = false;
if (!cu->mark)
{
+ dwarf_read_debug_printf_v ("deleting old CU %s",
+ sect_offset_str (cu->per_cu->sect_off));
delete cu;
it = m_dwarf2_cus.erase (it);
}
&& 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);