From: Andrew Burgess Date: Thu, 20 Mar 2025 11:07:02 +0000 (+0000) Subject: gdb: record block end addresses while parsing DIEs X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a418b1a4700ffdaffab296dc2f2e89dd6fa0b36c;p=thirdparty%2Fbinutils-gdb.git gdb: record block end addresses while parsing DIEs Continuing to work towards the goal of improving GDB's ability to debug optimised code, this commit stores a map from the end address of a block (or a block's sub-range) to the block pointer. This information is collected while parsing the DIEs. This new map is required as a consequence of the previous commit. The optimised code fix ups require that we can map from an address back to a block, something that the address map was perfect for, but the previous commit deferred building the address map until later on. The problem is that the optimised code fixes in the next commit require the address to block map, but also adjust block ranges, which invalidates the address to block map. We could try to build the full address to block early on, and then update it as the optimised code fixes are performed, but this is expensive. The solution I propose is to build a light weight, partial map, that only holds the interesting (inline) blocks. This partial map is only needed between reading the DIE and applying the optimised code fixes, after which it is done with, and as a consequence we don't need to update this map as the optimised code fixes adjust block ranges, this makes the partial map cheaper. This commit is all about building the new partial map. Currently, nothing is done with this information; the information is recorded as the block ranges are parsed, and then discarded after the line table has been built. But in the next commit, this will be used to help adjust the ranges of some inline blocks, and this will improve GDB's ability to debug optimised code. There should be no user visible changes after this commit. Approved-By: Tom Tromey --- diff --git a/gdb/dwarf2/cu.h b/gdb/dwarf2/cu.h index 97c0b87121b..b3ade5a2e6e 100644 --- a/gdb/dwarf2/cu.h +++ b/gdb/dwarf2/cu.h @@ -281,6 +281,13 @@ struct dwarf2_cu return m_producer; } + /* The end addresses for some inline blocks. For blocks with multiple + sub-ranges, this is the end address of every sub-range within the + block. These are the inclusive end addresses, that is, these are the + last addresses inside the block's ranges. Only the first block that + ends at any given address will be recorded. */ + gdb::unordered_map inline_block_ends; + private: const char *m_producer = nullptr; diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index a7248c2627e..d3b316dc57b 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -6014,6 +6014,10 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu) && cu->line_header != nullptr) dwarf_decode_lines (cu, unrel_low); + /* We no longer need to track the inline block end addresses. Release + memory associated with this. */ + cu->inline_block_ends.clear (); + /* 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 @@ -9253,14 +9257,16 @@ dwarf2_record_block_entry_pc (struct die_info *die, struct block *block, } } -/* Nothing for now. A later patch changes this. */ +/* If BLOCK is an inline function, then record UNREL_HIGH as its end + address. */ static void -dwarf2_record_single_block_range (struct dwarf2_cu *cu, struct block *block, - CORE_ADDR low, CORE_ADDR high, - unrelocated_addr unrel_high) +dwarf2_maybe_record_inline_function (struct dwarf2_cu *cu, struct block *block, + unrelocated_addr unrel_high) { - /* Nothing for now, a later patch adds code here. */ + /* If this is the end of an inline block, then record its end address. */ + if (block->inlined_p () && block->function () != nullptr) + cu->inline_block_ends.insert ({unrel_high, block}); } /* Record the address ranges for BLOCK, offset by BASEADDR, as given @@ -9331,8 +9337,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block, in GDB's internal structures, it's just more to search through, and it will never match any address. */ if (high >= low) - dwarf2_record_single_block_range (cu, block, low, high, - unrel_high); + dwarf2_maybe_record_inline_function (cu, block, unrel_high); } attr = dwarf2_attr (die, DW_AT_ranges, cu); @@ -9362,8 +9367,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block, { CORE_ADDR abs_start = per_objfile->relocate (start); CORE_ADDR abs_end = per_objfile->relocate (end); - dwarf2_record_single_block_range (cu, block, abs_start, - abs_end - 1, end); + dwarf2_maybe_record_inline_function (cu, block, end); blockvec.emplace_back (abs_start, abs_end); });