/* 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
/* Print a "dwarf-read" debug statement if dwarf_read_debug is >= 1. */
#define dwarf_read_debug_printf(fmt, ...) \
- do \
- { \
- if (dwarf_read_debug >= 1) \
- debug_prefixed_printf ("dwarf-read", __func__, fmt, ##__VA_ARGS__); \
- } \
- while (0)
+ 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, ...) \
- do \
- { \
- if (dwarf_read_debug >= 2) \
- debug_prefixed_printf ("dwarf-read", __func__, fmt, ##__VA_ARGS__); \
- } \
- while (0)
+ 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;
/* 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. */
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;
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).
static void
get_dwarf2_rational_constant (struct die_info *die, struct dwarf2_cu *cu,
- LONGEST *numerator, LONGEST *denominator)
+ gdb_mpz *numerator, gdb_mpz *denominator)
{
struct attribute *num_attr, *denom_attr;
if (num_attr == nullptr || denom_attr == nullptr)
return;
- *numerator = num_attr->constant_value (1);
- *denominator = denom_attr->constant_value (1);
+ get_mpz (cu, numerator, num_attr);
+ get_mpz (cu, denominator, denom_attr);
}
/* Same as get_dwarf2_rational_constant, but extracting an unsigned
static void
get_dwarf2_unsigned_rational_constant (struct die_info *die,
struct dwarf2_cu *cu,
- ULONGEST *numerator,
- ULONGEST *denominator)
+ gdb_mpz *numerator,
+ gdb_mpz *denominator)
{
- LONGEST num = 1, denom = 1;
+ gdb_mpz num (1);
+ gdb_mpz denom (1);
get_dwarf2_rational_constant (die, cu, &num, &denom);
- if (num < 0 && denom < 0)
+ if (mpz_sgn (num.val) == -1 && mpz_sgn (denom.val) == -1)
{
- num = -num;
- denom = -denom;
+ mpz_neg (num.val, num.val);
+ mpz_neg (denom.val, denom.val);
}
- else if (num < 0)
+ 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 (denom < 0)
+ else if (mpz_sgn (denom.val) == -1)
{
complaint (_("unexpected negative value for DW_AT_GNU_denominator"
" in DIE at %s"),
return;
}
- *numerator = num;
- *denominator = denom;
+ *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_FIXED_POINT_INFO.
+ of the corresponding TYPE by setting its type-specific data.
CU is the DIE's CU. */
static void
struct dwarf2_cu *cu)
{
struct attribute *attr;
- /* 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. */
- ULONGEST scale_num = 1;
- ULONGEST scale_denom = 1;
gdb_assert (type->code () == TYPE_CODE_FIXED_POINT
&& TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_FIXED_POINT);
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,
else if (attr->name == DW_AT_binary_scale)
{
LONGEST scale_exp = attr->constant_value (0);
- ULONGEST *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
+ gdb_mpz *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
- *num_or_denom = 1 << abs (scale_exp);
+ 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);
- ULONGEST *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
+ gdb_mpz *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
- *num_or_denom = uinteger_pow (10, abs (scale_exp));
+ mpz_ui_pow_ui (num_or_denom->val, 10, std::abs (scale_exp));
}
else if (attr->name == DW_AT_small)
{
sect_offset_str (die->sect_off));
}
- gdb_mpq &scaling_factor = TYPE_FIXED_POINT_INFO (type)->scaling_factor;
-
- gdb_mpz tmp_z (scale_num);
- mpz_set (mpq_numref (scaling_factor.val), tmp_z.val);
-
- tmp_z = scale_denom;
- mpz_set (mpq_denref (scaling_factor.val), tmp_z.val);
-
+ 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);
}
if (scale_die->tag != DW_TAG_constant)
return false;
- LONGEST num = 1, denom = 1;
+ gdb_mpz num (1), denom (1);
get_dwarf2_rational_constant (scale_die, cu, &num, &denom);
- return (num == 0 && denom == 0);
+ return mpz_sgn (num.val) == 0 && mpz_sgn (denom.val) == 0;
}
/* Initialise and return a floating point type of size BITS suitable for
/* 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));
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);
}