[PATCH 6/6] Handle multiple addresses in call_site_target
Tom Tromey
tromey@adacore.com
Wed Dec 1 22:04:32 GMT 2021
A large customer program has a function that is partitioned into hot
and cold parts. A variable in a callee of this function is described
using DW_OP_GNU_entry_value, but gdb gets confused when trying to find
the caller. I tracked this down to dwarf2_get_pc_bounds interpreting
the function's changes so that the returned low PC is the "wrong"
function.
Intead, when processing DW_TAG_call_site, the low PC of each range in
DW_AT_ranges should be preserved in the call_site_target. This fixes
the variable lookup in the test case I have.
I didn't write a standalone test for this as it seemed excessively
complicated.
---
gdb/dwarf2/loc.c | 12 ++++++++++++
gdb/dwarf2/read.c | 35 +++++++++++++++++++++++++++++++++++
gdb/gdbtypes.h | 15 +++++++++++++++
3 files changed, 62 insertions(+)
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index e1001eb7adb..82508c78cc7 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -726,6 +726,18 @@ call_site_target::iterate_over_addresses
}
break;
+ case call_site_target::ADDRESSES:
+ {
+ dwarf2_per_objfile *per_objfile = call_site->per_objfile;
+ compunit_symtab *cust = per_objfile->get_symtab (call_site->per_cu);
+ int sect_idx = COMPUNIT_BLOCK_LINE_SECTION (cust);
+ CORE_ADDR delta = per_objfile->objfile->section_offsets[sect_idx];
+
+ for (unsigned i = 0; i < m_loc.addresses.length; ++i)
+ callback (m_loc.addresses.values[i] + delta);
+ }
+ break;
+
default:
internal_error (__FILE__, __LINE__, _("invalid call site target kind"));
}
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 57538fc0adf..f40606216d1 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -13335,6 +13335,11 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
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<CORE_ADDR> &result);
+
/* Read in DW_TAG_call_site and insert it to CU->call_site_htab. */
static void
@@ -13498,6 +13503,10 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
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;
@@ -13513,6 +13522,18 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
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<CORE_ADDR> addresses;
+ dwarf2_ranges_read_low_addrs (ranges_offset, target_cu,
+ target_die->tag, addresses);
+ CORE_ADDR *saved = XOBNEWVAR (&objfile->objfile_obstack, CORE_ADDR,
+ addresses.size ());
+ std::copy (addresses.begin (), addresses.end (), saved);
+ call_site->target.set_loc_array (addresses.size (), saved);
+ }
else
{
CORE_ADDR lowpc;
@@ -14086,6 +14107,20 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
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<CORE_ADDR> &result)
+{
+ dwarf2_ranges_process (offset, cu, tag,
+ [&] (CORE_ADDR start, CORE_ADDR end)
+ {
+ result.push_back (start);
+ });
+}
+
/* 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. */
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index eaa3cd0dcb7..c89521c4318 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1820,6 +1820,8 @@ struct call_site_target
PHYSNAME,
/* A DWARF block. */
DWARF_BLOCK,
+ /* An array of addresses. */
+ ADDRESSES,
};
void set_loc_physaddr (CORE_ADDR physaddr)
@@ -1840,6 +1842,13 @@ struct call_site_target
m_loc.dwarf_block = dwarf_block;
}
+ void set_loc_array (unsigned length, const CORE_ADDR *data)
+ {
+ m_loc_kind = ADDRESSES;
+ m_loc.addresses.length = length;
+ m_loc.addresses.values = data;
+ }
+
/* Callback type for iterate_over_addresses. */
using iterate_ftype = gdb::function_view<void (CORE_ADDR)>;
@@ -1863,6 +1872,12 @@ struct call_site_target
const char *physname;
/* DWARF block. */
struct dwarf2_locexpr_baton *dwarf_block;
+ /* Array of addresses. */
+ struct
+ {
+ unsigned length;
+ const CORE_ADDR *values;
+ } addresses;
} m_loc;
/* * Discriminant for union field_location. */
--
2.31.1
More information about the Gdb-patches
mailing list