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

Reply via email to