Skip to content

Commit 7cb8439

Browse files
UltimateForce21JDevlieghereadrian-prantl
authored
[lldb] Add DWARFExpressionEntry and GetExpressionEntryAtAddress() to … (#144238)
This patch introduces a new struct and helper API in `DWARFExpressionList` to expose variable location metadata (base address, end address, and DWARFExpression pointer) for a given PC address. It will be used in later patches to annotate disassembly instructions with source-level variable locations. ## New struct ``` /// Represents one entry in a DWARFExpressionList, with its range and expr. struct DWARFExpressionEntry { lldb::addr_t base; // file‐address start of this location range lldb::addr_t end; // file‐address end of this range (exclusive) const DWARFExpression *expr; // the DWARF expression for this range }; ``` ## New API ``` /// Retrieve the DWARFExpressionEntry covering a particular instruction. /// /// \param func_load_addr /// The load address of the start of the function containing this location list; /// used to translate between file offsets and load addresses. If this is /// LLDB_INVALID_ADDRESS, the stored CU base (m_func_file_addr) is used. /// /// \param load_addr /// The load address of the *current* PC (i.e., the instruction for which /// we want its variable‐location entry). We first convert this back into /// the function’s file‐address space to find the correct DWARF range. /// /// \returns /// On success, an entry whose `[base,end)` covers this PC; else an Error. llvm::Expected<DWARFExpressionEntry> GetExpressionEntryAtAddress(lldb::addr_t func_load_addr, lldb::addr_t load_addr) const; ``` ## Rationale LLDB already provides: ``` const DWARFExpression * GetExpressionAtAddress(lldb::addr_t func_load_addr, lldb::addr_t load_addr) const; ``` However, this only returns the DWARF expression itself, without the file‐address start (base) and end (end) of the location range. Those bounds are crucial for: 1) Detecting range beginnings: render a var = <location> annotation exactly when a variable’s live‐range starts. 2) Detecting range continuation: optionally display a “|” on subsequent instructions in the same range. 3) Detecting state changes: know when a variable moves (e.g. from one register to another), becomes a constant, or goes out of scope. These primitives form the foundation for the Rich Disassembler feature proposed for GSoC 25. --------- Co-authored-by: Jonas Devlieghere <[email protected]> Co-authored-by: Adrian Prantl <[email protected]>
1 parent 647f02a commit 7cb8439

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

lldb/include/lldb/Expression/DWARFExpressionList.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H
1010
#define LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H
1111

12+
#include "lldb/Core/AddressRange.h"
1213
#include "lldb/Core/Value.h"
1314
#include "lldb/Expression/DWARFExpression.h"
1415
#include "lldb/Utility/RangeMap.h"
@@ -59,6 +60,21 @@ class DWARFExpressionList {
5960

6061
lldb::addr_t GetFuncFileAddress() { return m_func_file_addr; }
6162

63+
/// Represents an entry in the DWARFExpressionList with all needed metadata.
64+
struct DWARFExpressionEntry {
65+
/// Represents a DWARF location range in the DWARF unit’s file‐address space
66+
std::optional<AddressRange> file_range; ///< None = always-valid single expr
67+
const DWARFExpression *expr;
68+
};
69+
70+
/// Returns a DWARFExpressionEntry whose file_range contains the given
71+
/// load‐address. `func_load_addr` is the load‐address of the function
72+
/// start; `load_addr` is the full runtime PC. On success, `expr` is
73+
/// non-null.
74+
std::optional<DWARFExpressionEntry>
75+
GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
76+
lldb::addr_t load_addr) const;
77+
6278
const DWARFExpression *GetExpressionAtAddress(lldb::addr_t func_load_addr,
6379
lldb::addr_t load_addr) const;
6480

lldb/source/Expression/DWARFExpressionList.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "lldb/Expression/DWARFExpressionList.h"
10+
#include "lldb/Core/AddressRange.h"
1011
#include "lldb/Symbol/Function.h"
1112
#include "lldb/Target/RegisterContext.h"
1213
#include "lldb/Target/StackFrame.h"
@@ -20,7 +21,7 @@ bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {
2021
return GetAlwaysValidExpr() != nullptr;
2122
}
2223

23-
const DWARFExpression * DWARFExpressionList::GetAlwaysValidExpr() const {
24+
const DWARFExpression *DWARFExpressionList::GetAlwaysValidExpr() const {
2425
if (m_exprs.GetSize() != 1)
2526
return nullptr;
2627
const auto *expr = m_exprs.GetEntryAtIndex(0);
@@ -53,6 +54,38 @@ bool DWARFExpressionList::ContainsAddress(lldb::addr_t func_load_addr,
5354
return GetExpressionAtAddress(func_load_addr, addr) != nullptr;
5455
}
5556

57+
std::optional<DWARFExpressionList::DWARFExpressionEntry>
58+
DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
59+
lldb::addr_t load_addr) const {
60+
if (const DWARFExpression *always = GetAlwaysValidExpr()) {
61+
return DWARFExpressionEntry{std::nullopt, always};
62+
}
63+
64+
if (func_load_addr == LLDB_INVALID_ADDRESS)
65+
func_load_addr = m_func_file_addr;
66+
67+
// Guard against underflow when translating a load address back into file
68+
// space.
69+
if (load_addr < func_load_addr)
70+
return std::nullopt;
71+
72+
// Guard against overflow.
73+
lldb::addr_t delta = load_addr - func_load_addr;
74+
if (delta > std::numeric_limits<lldb::addr_t>::max() - m_func_file_addr)
75+
return std::nullopt;
76+
77+
lldb::addr_t file_pc = (load_addr - func_load_addr) + m_func_file_addr;
78+
79+
if (const auto *entry = m_exprs.FindEntryThatContains(file_pc)) {
80+
AddressRange range_in_file(entry->GetRangeBase(),
81+
entry->GetRangeEnd() - entry->GetRangeBase());
82+
return DWARFExpressionEntry{range_in_file, &entry->data};
83+
}
84+
85+
// No entry covers this PC:
86+
return std::nullopt;
87+
}
88+
5689
const DWARFExpression *
5790
DWARFExpressionList::GetExpressionAtAddress(lldb::addr_t func_load_addr,
5891
lldb::addr_t load_addr) const {

0 commit comments

Comments
 (0)