diff options
author | Tom Tromey <tromey@adacore.com> | 2021-11-19 10:12:44 -0700 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2022-03-28 13:31:22 -0600 |
commit | 48ac197b0c209ccf1f2de9704eb6cdf7c5c73a8e (patch) | |
tree | 9add73f002b76696ce8dc9eb1ea5eff3678c813d /gdb/dwarf2 | |
parent | a0e0ca7044f240c0b56a829ed762f5efd0854fc6 (diff) | |
download | gdb-48ac197b0c209ccf1f2de9704eb6cdf7c5c73a8e.zip gdb-48ac197b0c209ccf1f2de9704eb6cdf7c5c73a8e.tar.gz gdb-48ac197b0c209ccf1f2de9704eb6cdf7c5c73a8e.tar.bz2 |
Handle multiple addresses in call_site_target
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.
Diffstat (limited to 'gdb/dwarf2')
-rw-r--r-- | gdb/dwarf2/loc.c | 12 | ||||
-rw-r--r-- | gdb/dwarf2/read.c | 35 |
2 files changed, 47 insertions, 0 deletions
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index 37e5a16..5cfd5a2 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 = cust->block_line_section (); + 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 f9c942d..6c41ede 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -13311,6 +13311,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 @@ -13474,6 +13479,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; @@ -13489,6 +13498,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; @@ -14062,6 +14083,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. */ |