Author: Abdullah Mohammad Amin Date: 2025-07-12T10:03:54-07:00 New Revision: 7cb84392fd4abb2190c09045d25abc98571a1396
URL: https://github.com/llvm/llvm-project/commit/7cb84392fd4abb2190c09045d25abc98571a1396 DIFF: https://github.com/llvm/llvm-project/commit/7cb84392fd4abb2190c09045d25abc98571a1396.diff LOG: [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 <jo...@devlieghere.com> Co-authored-by: Adrian Prantl <adrian.pra...@gmail.com> Added: Modified: lldb/include/lldb/Expression/DWARFExpressionList.h lldb/source/Expression/DWARFExpressionList.cpp Removed: ################################################################################ diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h b/lldb/include/lldb/Expression/DWARFExpressionList.h index d8f8ec247ed56..d303ad834b354 100644 --- a/lldb/include/lldb/Expression/DWARFExpressionList.h +++ b/lldb/include/lldb/Expression/DWARFExpressionList.h @@ -9,6 +9,7 @@ #ifndef LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H #define LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H +#include "lldb/Core/AddressRange.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Utility/RangeMap.h" @@ -59,6 +60,21 @@ class DWARFExpressionList { lldb::addr_t GetFuncFileAddress() { return m_func_file_addr; } + /// Represents an entry in the DWARFExpressionList with all needed metadata. + struct DWARFExpressionEntry { + /// Represents a DWARF location range in the DWARF unit’s file‐address space + std::optional<AddressRange> file_range; ///< None = always-valid single expr + const DWARFExpression *expr; + }; + + /// Returns a DWARFExpressionEntry whose file_range contains the given + /// load‐address. `func_load_addr` is the load‐address of the function + /// start; `load_addr` is the full runtime PC. On success, `expr` is + /// non-null. + std::optional<DWARFExpressionEntry> + GetExpressionEntryAtAddress(lldb::addr_t func_load_addr, + lldb::addr_t load_addr) const; + const DWARFExpression *GetExpressionAtAddress(lldb::addr_t func_load_addr, lldb::addr_t load_addr) const; diff --git a/lldb/source/Expression/DWARFExpressionList.cpp b/lldb/source/Expression/DWARFExpressionList.cpp index 04592a1eb7ff4..ef7333518f008 100644 --- a/lldb/source/Expression/DWARFExpressionList.cpp +++ b/lldb/source/Expression/DWARFExpressionList.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Expression/DWARFExpressionList.h" +#include "lldb/Core/AddressRange.h" #include "lldb/Symbol/Function.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" @@ -20,7 +21,7 @@ bool DWARFExpressionList::IsAlwaysValidSingleExpr() const { return GetAlwaysValidExpr() != nullptr; } -const DWARFExpression * DWARFExpressionList::GetAlwaysValidExpr() const { +const DWARFExpression *DWARFExpressionList::GetAlwaysValidExpr() const { if (m_exprs.GetSize() != 1) return nullptr; const auto *expr = m_exprs.GetEntryAtIndex(0); @@ -53,6 +54,38 @@ bool DWARFExpressionList::ContainsAddress(lldb::addr_t func_load_addr, return GetExpressionAtAddress(func_load_addr, addr) != nullptr; } +std::optional<DWARFExpressionList::DWARFExpressionEntry> +DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr, + lldb::addr_t load_addr) const { + if (const DWARFExpression *always = GetAlwaysValidExpr()) { + return DWARFExpressionEntry{std::nullopt, always}; + } + + if (func_load_addr == LLDB_INVALID_ADDRESS) + func_load_addr = m_func_file_addr; + + // Guard against underflow when translating a load address back into file + // space. + if (load_addr < func_load_addr) + return std::nullopt; + + // Guard against overflow. + lldb::addr_t delta = load_addr - func_load_addr; + if (delta > std::numeric_limits<lldb::addr_t>::max() - m_func_file_addr) + return std::nullopt; + + lldb::addr_t file_pc = (load_addr - func_load_addr) + m_func_file_addr; + + if (const auto *entry = m_exprs.FindEntryThatContains(file_pc)) { + AddressRange range_in_file(entry->GetRangeBase(), + entry->GetRangeEnd() - entry->GetRangeBase()); + return DWARFExpressionEntry{range_in_file, &entry->data}; + } + + // No entry covers this PC: + return std::nullopt; +} + const DWARFExpression * DWARFExpressionList::GetExpressionAtAddress(lldb::addr_t func_load_addr, lldb::addr_t load_addr) const { _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits