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 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 + 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::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::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 {