https://github.com/UltimateForce21 created 
https://github.com/llvm/llvm-project/pull/147460

This PR builds upon the functionality introduced in [PR 
#144238](https://github.com/llvm/llvm-project/pull/144238), which adds support 
for annotating disassembly output with DWARF variable locations.

This patch includes:

Additional test coverage for various DWARF location cases (e.g., stack 
variables, control flow edges, partial decoding).

A refined implementation that uses the new DWARFExpressionEntry API.

Logic to gracefully skip <decoding error> fragments while preserving valid 
annotations.

⚠️ Note: This PR depends on #144238 and should be rebased once it lands.

### Summary
This patch adds a first‐pass prototype of “rich disassembly” annotations into 
Instruction::Dump(). For each instruction, it will:

1. Query our new `GetExpressionEntryAtAddress()` API for any in‐scope variable 
live‐ranges covering this PC.

If a variable’s live‐range begins exactly at the current PC that is being 
iterated in the disassembly, call `expr->DumpLocation(...)` to render its DWARF 
expression (e.g. “`DW_OP_reg5 RDI`”, “`DW_OP_reg3 RBX`”, or constant) and 
append it as a `; var = …` comment after the instruction.

Currently this only handles simple cases:

Variables whose location expression is a single register (e.g. `DW_OP_reg14 
R14`)

Variables whose location expression is a constant (e.g. `DW_OP_consts +0`)

### Example test program
```
// test.cpp
#include <iostream>

void testFunction(int value);

int main(int argc, char** argv) {
    int total = 0;
    for (int my_special_variable = 0; my_special_variable < 5; 
++my_special_variable){
        puts(argv[my_special_variable]);
        int new_variable = my_special_variable + 1;
        testFunction(new_variable); 
        total += my_special_variable;
    }
    return total;
}


void testFunction(int value) {
    std::cout << "Local variable value: " << value << std::endl;
}
```


### Disassembly output with annotations

```
(lldb) target create "/home/ultimateforce21/lldb_test/test"
Current executable set to '/home/ultimateforce21/lldb_test/test' (x86_64).
(lldb) b main
Breakpoint 1: where = test`main + 16 at test.cpp:10:14, address = 
0x0000000000001200
(lldb) r
Process 26674 launched: '/home/ultimateforce21/lldb_test/test' (x86_64)
Process 26674 stopped
* thread #1, name = 'test', stop reason = breakpoint 1.1
    frame #0: 0x0000555555555200 test`main(argc=<unavailable>, 
argv=0x00007fffffffdc68) at test.cpp:10:14
   7    int main(int argc, char** argv) {
   8        int total = 0;
   9        for (int my_special_variable = 0; my_special_variable < 5; 
++my_special_variable){
-> 10           puts(argv[my_special_variable]);
   11           int new_variable = my_special_variable + 1;
   12           testFunction(new_variable); 
   13           total += my_special_variable;
(lldb) dis
test`main:
    0x5555555551f0 <+0>:  pushq  %r14           ; argc = DW_OP_reg5 RDI ; argv 
= DW_OP_reg4 RSI ; std::__ioinit = DW_OP_addrx 0x0
    0x5555555551f2 <+2>:  pushq  %rbx
    0x5555555551f3 <+3>:  pushq  %rax
    0x5555555551f4 <+4>:  movq   %rsi, %r14
    0x5555555551f7 <+7>:  xorl   %ebx, %ebx ; total = DW_OP_consts +0, 
DW_OP_stack_value
    0x5555555551f9 <+9>:  nopl   (%rax) ; my_special_variable = DW_OP_reg3 RBX 
; argc = DW_OP_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value ; argv = 
DW_OP_reg14 R14
->  0x555555555200 <+16>: movq   (%r14,%rbx,8), %rdi
    0x555555555204 <+20>: callq  0x5555555550a0 ; symbol stub for: puts
    0x555555555209 <+25>: addq   $0x1, %rbx
    0x55555555520d <+29>: movl   %ebx, %edi ; new_variable = DW_OP_reg3 RBX
    0x55555555520f <+31>: callq  0x555555555230 ; testFunction at test.cpp:19
    0x555555555214 <+36>: cmpq   $0x5, %rbx ; my_special_variable = DW_OP_reg3 
RBX
    0x555555555218 <+40>: jne    0x555555555200 ; <+16> at test.cpp:10:14
    0x55555555521a <+42>: movl   $0xa, %eax
    0x55555555521f <+47>: addq   $0x8, %rsp
    0x555555555223 <+51>: popq   %rbx
    0x555555555224 <+52>: popq   %r14
    0x555555555226 <+54>: retq                             ; argv = 
DW_OP_entry_value(DW_OP_reg4 RSI), DW_OP_stack_value
```




### Next steps
**Cleanup & style (DONE)**
- Tidy up any styling according to LLDB’s conventions, and handle any 
off‐by‐one column issues.

**Test coverage (DONE)**
- Add a lldb-test cases exercising single-register variables at known 
instructions.



>From 8ed8c540e7600d720a63bc2882a81a2c65c11d41 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Wed, 11 Jun 2025 00:11:09 -0400
Subject: [PATCH 01/19] [lldb] Add DWARFExpressionEntry and
 GetExpressionEntryAtAddress() to DWARFExpressionList

This introduces a new API for retrieving DWARF expression metadata associated 
with variable location entries at a given PC address. It provides the base, 
end, and expression pointer for downstream consumers such as disassembler 
annotations.

Intended for use in richer instruction annotations in Instruction::Dump().
---
 .../lldb/Expression/DWARFExpressionList.h     | 12 +++++++++++
 .../source/Expression/DWARFExpressionList.cpp | 21 +++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h 
b/lldb/include/lldb/Expression/DWARFExpressionList.h
index d8f8ec247ed56..a329b37393018 100644
--- a/lldb/include/lldb/Expression/DWARFExpressionList.h
+++ b/lldb/include/lldb/Expression/DWARFExpressionList.h
@@ -59,6 +59,18 @@ class DWARFExpressionList {
 
   lldb::addr_t GetFuncFileAddress() { return m_func_file_addr; }
 
+  /// Represents an entry in the DWARFExpressionList with all needed metadata
+  struct DWARFExpressionEntry {
+    lldb::addr_t base;
+    lldb::addr_t end;
+    const DWARFExpression *expr;
+  };
+
+  /// Returns the entry (base, end, data) for a given PC address
+  llvm::Expected<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..b55bc7120c4af 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -53,6 +53,27 @@ bool DWARFExpressionList::ContainsAddress(lldb::addr_t 
func_load_addr,
   return GetExpressionAtAddress(func_load_addr, addr) != nullptr;
 }
 
+llvm::Expected<DWARFExpressionList::DWARFExpressionEntry>
+DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
+                                                 lldb::addr_t load_addr) const 
{
+  if (const DWARFExpression *expr = GetAlwaysValidExpr()) {
+    return DWARFExpressionEntry{0, LLDB_INVALID_ADDRESS, expr};
+  }
+
+  if (func_load_addr == LLDB_INVALID_ADDRESS)
+    func_load_addr = m_func_file_addr;
+
+  addr_t addr = load_addr - func_load_addr + m_func_file_addr;
+  uint32_t index = m_exprs.FindEntryIndexThatContains(addr);
+  if (index == UINT32_MAX) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "No DWARF expression found for address 
0x%llx", addr);
+  }
+
+  const Entry &entry = *m_exprs.GetEntryAtIndex(index);
+  return DWARFExpressionEntry{entry.base, entry.GetRangeEnd(), &entry.data};
+}
+
 const DWARFExpression *
 DWARFExpressionList::GetExpressionAtAddress(lldb::addr_t func_load_addr,
                                             lldb::addr_t load_addr) const {

>From 1db5002a69dba4f88aaac56d61520b7b4b214b01 Mon Sep 17 00:00:00 2001
From: Abdullah Mohammad Amin
 <67847674+ultimateforc...@users.noreply.github.com>
Date: Thu, 19 Jun 2025 11:55:35 -0400
Subject: [PATCH 02/19] Update
 lldb/include/lldb/Expression/DWARFExpressionList.h

Co-authored-by: Jonas Devlieghere <jo...@devlieghere.com>
---
 lldb/include/lldb/Expression/DWARFExpressionList.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h 
b/lldb/include/lldb/Expression/DWARFExpressionList.h
index a329b37393018..89e55ffc07659 100644
--- a/lldb/include/lldb/Expression/DWARFExpressionList.h
+++ b/lldb/include/lldb/Expression/DWARFExpressionList.h
@@ -59,7 +59,7 @@ class DWARFExpressionList {
 
   lldb::addr_t GetFuncFileAddress() { return m_func_file_addr; }
 
-  /// Represents an entry in the DWARFExpressionList with all needed metadata
+  /// Represents an entry in the DWARFExpressionList with all needed metadata.
   struct DWARFExpressionEntry {
     lldb::addr_t base;
     lldb::addr_t end;

>From a26010b06e5067b8b3b223cbd76e8848ecb9a289 Mon Sep 17 00:00:00 2001
From: Abdullah Mohammad Amin
 <67847674+ultimateforc...@users.noreply.github.com>
Date: Thu, 19 Jun 2025 11:58:28 -0400
Subject: [PATCH 03/19] Update
 lldb/include/lldb/Expression/DWARFExpressionList.h

Updated comment for GetExpressionEntryAtAddress to directly refer to struct 
DWARFExpressionEntry

Co-authored-by: Jonas Devlieghere <jo...@devlieghere.com>
---
 lldb/include/lldb/Expression/DWARFExpressionList.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h 
b/lldb/include/lldb/Expression/DWARFExpressionList.h
index 89e55ffc07659..f6a269809decc 100644
--- a/lldb/include/lldb/Expression/DWARFExpressionList.h
+++ b/lldb/include/lldb/Expression/DWARFExpressionList.h
@@ -66,7 +66,7 @@ class DWARFExpressionList {
     const DWARFExpression *expr;
   };
 
-  /// Returns the entry (base, end, data) for a given PC address
+  /// Returns the DWARFExpressionEntry for a given PC address.
   llvm::Expected<DWARFExpressionEntry>
   GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
                               lldb::addr_t load_addr) const;

>From 72237b75a12daa94f887f7492b2dfc141519b8a8 Mon Sep 17 00:00:00 2001
From: Abdullah Mohammad Amin
 <67847674+ultimateforc...@users.noreply.github.com>
Date: Thu, 19 Jun 2025 11:59:35 -0400
Subject: [PATCH 04/19] Update lldb/source/Expression/DWARFExpressionList.cpp

updating code style for function GetExpressionEntryAtAddress

Co-authored-by: Jonas Devlieghere <jo...@devlieghere.com>
---
 lldb/source/Expression/DWARFExpressionList.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lldb/source/Expression/DWARFExpressionList.cpp 
b/lldb/source/Expression/DWARFExpressionList.cpp
index b55bc7120c4af..ebf57dd457769 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -56,9 +56,8 @@ bool DWARFExpressionList::ContainsAddress(lldb::addr_t 
func_load_addr,
 llvm::Expected<DWARFExpressionList::DWARFExpressionEntry>
 DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
                                                  lldb::addr_t load_addr) const 
{
-  if (const DWARFExpression *expr = GetAlwaysValidExpr()) {
+  if (const DWARFExpression *expr = GetAlwaysValidExpr())
     return DWARFExpressionEntry{0, LLDB_INVALID_ADDRESS, expr};
-  }
 
   if (func_load_addr == LLDB_INVALID_ADDRESS)
     func_load_addr = m_func_file_addr;

>From 94e4951ac8eb39f078b783c2d3a7006c395ae4b2 Mon Sep 17 00:00:00 2001
From: Abdullah Mohammad Amin
 <67847674+ultimateforc...@users.noreply.github.com>
Date: Tue, 24 Jun 2025 16:28:14 -0400
Subject: [PATCH 05/19] Update DWARFExpressionList.h

Replace raw base/end with `AddressRange` in `DWARFExpressionEntry` and cleans 
up helper comments to follow Doxygen convention.

Using `AddressRange` makes the intent clearer, avoids duplication of basic 
`AddressRange` logic usage
---
 lldb/include/lldb/Expression/DWARFExpressionList.h | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h 
b/lldb/include/lldb/Expression/DWARFExpressionList.h
index f6a269809decc..4af6f99b9c23a 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"
@@ -58,15 +59,16 @@ class DWARFExpressionList {
   }
 
   lldb::addr_t GetFuncFileAddress() { return m_func_file_addr; }
-
+  
   /// Represents an entry in the DWARFExpressionList with all needed metadata.
   struct DWARFExpressionEntry {
-    lldb::addr_t base;
-    lldb::addr_t end;
+    AddressRange file_range; /// Represents a DWARF location range in the 
DWARF unit’s file‐address space
     const DWARFExpression *expr;
   };
 
-  /// Returns the DWARFExpressionEntry for a given PC address.
+  /// 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.
   llvm::Expected<DWARFExpressionEntry>
   GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
                               lldb::addr_t load_addr) const;

>From e8142dab5a1c90f05deb659a57059313c055b99d Mon Sep 17 00:00:00 2001
From: Abdullah Mohammad Amin
 <67847674+ultimateforc...@users.noreply.github.com>
Date: Tue, 24 Jun 2025 16:36:41 -0400
Subject: [PATCH 06/19] Update DWARFExpressionList.cpp

Converts `GetExpressionEntryAtAddress` to return 
`llvm::Expected<DWARFExpressionEntry>` using the updated 
`DWARFExpressionEntry`. Updates the implementation to compute a single 
`AddressRange file_range` for each DWARF location interval.
---
 .../source/Expression/DWARFExpressionList.cpp | 26 +++++++++++--------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/lldb/source/Expression/DWARFExpressionList.cpp 
b/lldb/source/Expression/DWARFExpressionList.cpp
index ebf57dd457769..8b8378eb895d3 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -6,6 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include "lldb/Core/AddressRange.h"
 #include "lldb/Expression/DWARFExpressionList.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Target/RegisterContext.h"
@@ -55,22 +56,25 @@ bool DWARFExpressionList::ContainsAddress(lldb::addr_t 
func_load_addr,
 
 llvm::Expected<DWARFExpressionList::DWARFExpressionEntry>
 DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
-                                                 lldb::addr_t load_addr) const 
{
-  if (const DWARFExpression *expr = GetAlwaysValidExpr())
-    return DWARFExpressionEntry{0, LLDB_INVALID_ADDRESS, expr};
+                                                lldb::addr_t load_addr) const {
+  if (const DWARFExpression *always = GetAlwaysValidExpr()) {
+    AddressRange full_range(m_func_file_addr, /*size=*/LLDB_INVALID_ADDRESS);
+    return DWARFExpressionEntry{full_range, always};
+  }
 
   if (func_load_addr == LLDB_INVALID_ADDRESS)
     func_load_addr = m_func_file_addr;
+  lldb::addr_t file_pc = load_addr - func_load_addr + m_func_file_addr;
 
-  addr_t addr = load_addr - func_load_addr + m_func_file_addr;
-  uint32_t index = m_exprs.FindEntryIndexThatContains(addr);
-  if (index == UINT32_MAX) {
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "No DWARF expression found for address 
0x%llx", addr);
-  }
+  uint32_t idx = m_exprs.FindEntryIndexThatContains(file_pc);
+  if (idx == UINT32_MAX)
+    return llvm::createStringError(
+        llvm::inconvertibleErrorCode(),
+        "no DWARF location list entry for PC 0x%" PRIx64, load_addr);
 
-  const Entry &entry = *m_exprs.GetEntryAtIndex(index);
-  return DWARFExpressionEntry{entry.base, entry.GetRangeEnd(), &entry.data};
+  const auto &entry = *m_exprs.GetEntryAtIndex(idx);
+  AddressRange range_in_file(entry.base, entry.GetRangeEnd() - entry.base);
+  return DWARFExpressionEntry{range_in_file, &entry.data};
 }
 
 const DWARFExpression *

>From 7e8741edfefa6989d06b4e50e11dfd4a47d57d28 Mon Sep 17 00:00:00 2001
From: Abdullah Mohammad Amin
 <67847674+ultimateforc...@users.noreply.github.com>
Date: Sat, 28 Jun 2025 12:59:08 -0400
Subject: [PATCH 07/19] Update DWARFExpressionList.h

Updated commenting style for struct DWARFExpressionEntry
---
 lldb/include/lldb/Expression/DWARFExpressionList.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h 
b/lldb/include/lldb/Expression/DWARFExpressionList.h
index 4af6f99b9c23a..31b852eb1ec80 100644
--- a/lldb/include/lldb/Expression/DWARFExpressionList.h
+++ b/lldb/include/lldb/Expression/DWARFExpressionList.h
@@ -62,7 +62,8 @@ class DWARFExpressionList {
   
   /// Represents an entry in the DWARFExpressionList with all needed metadata.
   struct DWARFExpressionEntry {
-    AddressRange file_range; /// Represents a DWARF location range in the 
DWARF unit’s file‐address space
+    /// Represents a DWARF location range in the DWARF unit’s file‐address 
space
+    AddressRange file_range;
     const DWARFExpression *expr;
   };
 

>From c4cd77fa3605b3f1653b3987ed0a65b4c264f655 Mon Sep 17 00:00:00 2001
From: Abdullah Mohammad Amin
 <67847674+ultimateforc...@users.noreply.github.com>
Date: Sat, 28 Jun 2025 13:24:57 -0400
Subject: [PATCH 08/19] Update DWARFExpressionList.cpp

Updated function `llvm::Expected<DWARFExpressionList::DWARFExpressionEntry>
DWARFExpressionList::GetExpressionEntryAtAddress` to use 
`FindEntryThatContains` instead of `FindEntryIndexThatContains`
---
 lldb/source/Expression/DWARFExpressionList.cpp | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/lldb/source/Expression/DWARFExpressionList.cpp 
b/lldb/source/Expression/DWARFExpressionList.cpp
index 8b8378eb895d3..9a6cccf445028 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -64,17 +64,19 @@ 
DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
 
   if (func_load_addr == LLDB_INVALID_ADDRESS)
     func_load_addr = m_func_file_addr;
+  
+  // translate to file-relative PC
   lldb::addr_t file_pc = load_addr - func_load_addr + m_func_file_addr;
 
-  uint32_t idx = m_exprs.FindEntryIndexThatContains(file_pc);
-  if (idx == UINT32_MAX)
-    return llvm::createStringError(
-        llvm::inconvertibleErrorCode(),
-        "no DWARF location list entry for PC 0x%" PRIx64, load_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};
+  }
 
-  const auto &entry = *m_exprs.GetEntryAtIndex(idx);
-  AddressRange range_in_file(entry.base, entry.GetRangeEnd() - entry.base);
-  return DWARFExpressionEntry{range_in_file, &entry.data};
+  return llvm::createStringError(
+      llvm::inconvertibleErrorCode(),
+      "no DWARF location list entry for PC 0x%" PRIx64, load_addr);
 }
 
 const DWARFExpression *

>From 62c02a9f1afd2018e0bd11541bf001047e4f7917 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Sat, 28 Jun 2025 21:46:46 -0400
Subject: [PATCH 09/19] Change GetExpressionEntryAtAddress to return
 std::optional instead of llvm::Expected

---
 lldb/include/lldb/Expression/DWARFExpressionList.h | 2 +-
 lldb/source/Expression/DWARFExpressionList.cpp     | 7 +++----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h 
b/lldb/include/lldb/Expression/DWARFExpressionList.h
index 31b852eb1ec80..b21b694694ddc 100644
--- a/lldb/include/lldb/Expression/DWARFExpressionList.h
+++ b/lldb/include/lldb/Expression/DWARFExpressionList.h
@@ -70,7 +70,7 @@ class DWARFExpressionList {
   /// 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.
-  llvm::Expected<DWARFExpressionEntry>
+  std::optional<DWARFExpressionEntry>
   GetExpressionEntryAtAddress(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 9a6cccf445028..763dcb568d2ec 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -54,7 +54,7 @@ bool DWARFExpressionList::ContainsAddress(lldb::addr_t 
func_load_addr,
   return GetExpressionAtAddress(func_load_addr, addr) != nullptr;
 }
 
-llvm::Expected<DWARFExpressionList::DWARFExpressionEntry>
+std::optional<DWARFExpressionList::DWARFExpressionEntry>
 DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
                                                 lldb::addr_t load_addr) const {
   if (const DWARFExpression *always = GetAlwaysValidExpr()) {
@@ -74,9 +74,8 @@ DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t 
func_load_addr,
     return DWARFExpressionEntry{range_in_file, &entry->data};
   }
 
-  return llvm::createStringError(
-      llvm::inconvertibleErrorCode(),
-      "no DWARF location list entry for PC 0x%" PRIx64, load_addr);
+  // No entry covers this PC:
+  return std::nullopt;
 }
 
 const DWARFExpression *

>From d015971a280d41a68e17530b00258c193ea46a82 Mon Sep 17 00:00:00 2001
From: Abdullah Mohammad Amin
 <67847674+ultimateforc...@users.noreply.github.com>
Date: Wed, 2 Jul 2025 11:45:48 -0400
Subject: [PATCH 10/19] Update DWARFExpressionList.cpp

Co-authored-by: Adrian Prantl <adrian.pra...@gmail.com>
---
 lldb/source/Expression/DWARFExpressionList.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Expression/DWARFExpressionList.cpp 
b/lldb/source/Expression/DWARFExpressionList.cpp
index 763dcb568d2ec..2f0f034b613db 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -65,7 +65,7 @@ DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t 
func_load_addr,
   if (func_load_addr == LLDB_INVALID_ADDRESS)
     func_load_addr = m_func_file_addr;
   
-  // translate to file-relative PC
+  // Translate to file-relative PC.
   lldb::addr_t file_pc = load_addr - func_load_addr + m_func_file_addr;
 
   if (const auto *entry = m_exprs.FindEntryThatContains(file_pc)) {

>From 60898ea58bf178a2aa87f86b44ddfe7fd8b5d6da Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Thu, 3 Jul 2025 00:05:26 -0400
Subject: [PATCH 11/19] Add underflow/overflow checks to
 GetExpressionEntryAtAddressi This patch adds explicit checks:   - ensure
 `load_addr >= func_load_addr` to avoid underflow,   - compute and verify a
 temporary delta variable, then verify `delta + m_func_file_addr` does     not
 exceed `addr_t` max to avoid overflow.

---
 lldb/source/Expression/DWARFExpressionList.cpp | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/lldb/source/Expression/DWARFExpressionList.cpp 
b/lldb/source/Expression/DWARFExpressionList.cpp
index 2f0f034b613db..772c23fd96d0f 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -64,10 +64,18 @@ 
DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
 
   if (func_load_addr == LLDB_INVALID_ADDRESS)
     func_load_addr = m_func_file_addr;
-  
-  // Translate to file-relative PC.
-  lldb::addr_t file_pc = load_addr - 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());

>From 3462165da7811d190d1896ed41372af25548abd5 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Mon, 7 Jul 2025 22:39:45 -0400
Subject: [PATCH 12/19] Make file_range optional in DWARFExpressionEntry for
 always-valid expr

---
 lldb/include/lldb/Expression/DWARFExpressionList.h | 2 +-
 lldb/source/Expression/DWARFExpressionList.cpp     | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h 
b/lldb/include/lldb/Expression/DWARFExpressionList.h
index b21b694694ddc..1bd762a9836e8 100644
--- a/lldb/include/lldb/Expression/DWARFExpressionList.h
+++ b/lldb/include/lldb/Expression/DWARFExpressionList.h
@@ -63,7 +63,7 @@ class DWARFExpressionList {
   /// 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
-    AddressRange file_range;
+    std::optional<AddressRange> file_range; ///< None = always-valid single 
expr
     const DWARFExpression *expr;
   };
 
diff --git a/lldb/source/Expression/DWARFExpressionList.cpp 
b/lldb/source/Expression/DWARFExpressionList.cpp
index 772c23fd96d0f..b51317a98365c 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -58,8 +58,7 @@ std::optional<DWARFExpressionList::DWARFExpressionEntry>
 DWARFExpressionList::GetExpressionEntryAtAddress(lldb::addr_t func_load_addr,
                                                 lldb::addr_t load_addr) const {
   if (const DWARFExpression *always = GetAlwaysValidExpr()) {
-    AddressRange full_range(m_func_file_addr, /*size=*/LLDB_INVALID_ADDRESS);
-    return DWARFExpressionEntry{full_range, always};
+    return DWARFExpressionEntry{std::nullopt, always};
   }
 
   if (func_load_addr == LLDB_INVALID_ADDRESS)

>From 2ed84430163412eec217f8cabc653191f5be4766 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Thu, 3 Jul 2025 19:54:27 -0400
Subject: [PATCH 13/19] Annotate Instruction::Dump() with DWARF variable
 locations

---
 lldb/source/Core/Disassembler.cpp | 49 +++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/lldb/source/Core/Disassembler.cpp 
b/lldb/source/Core/Disassembler.cpp
index dce3d59457c0e..f818eb20bdad5 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -26,7 +26,10 @@
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/Symbol.h"
 #include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Target/Target.h"
@@ -702,6 +705,52 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t 
max_opcode_byte_size,
   ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
   ss.PutCString(mnemonics);
 
+  if (exe_ctx && exe_ctx->GetFramePtr()) {
+    StackFrame *frame = exe_ctx->GetFramePtr();
+    TargetSP target_sp = exe_ctx->GetTargetSP();
+    if (frame && target_sp) {
+      addr_t current_pc = m_address.GetLoadAddress(target_sp.get());
+      addr_t original_pc = 
frame->GetFrameCodeAddress().GetLoadAddress(target_sp.get());
+      if (frame->ChangePC(current_pc)) {
+        VariableListSP var_list_sp = frame->GetInScopeVariableList(true);
+        SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction);
+        addr_t func_load_addr = LLDB_INVALID_ADDRESS;
+        if (sc.function)
+          func_load_addr = 
sc.function->GetAddress().GetLoadAddress(target_sp.get());
+
+        if (var_list_sp) {
+          for (size_t i = 0; i < var_list_sp->GetSize(); ++i) {
+            VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
+            if (!var_sp)
+              continue;
+
+            const char *name = var_sp->GetName().AsCString();
+            auto &expr_list = var_sp->LocationExpressionList();
+
+            // Handle std::optional<DWARFExpressionEntry>.
+            if (auto entryOrErr = 
expr_list.GetExpressionEntryAtAddress(func_load_addr, current_pc)) {
+              auto entry = *entryOrErr;
+
+              // Translate file-range to load-space start.
+              addr_t file_base = 
entry.file_range.GetBaseAddress().GetFileAddress();
+              addr_t start_load_addr = file_base + (func_load_addr - 
expr_list.GetFuncFileAddress());
+
+              if (current_pc == start_load_addr) {
+                StreamString loc_str;
+                ABI *abi = exe_ctx->GetProcessPtr()->GetABI().get();
+                entry.expr->DumpLocation(&loc_str, eDescriptionLevelBrief, 
abi);
+                ss.FillLastLineToColumn(opcode_pos + opcode_column_width + 
operand_column_width, ' ');
+                ss.Printf(" ; %s = %s", name, 
loc_str.GetString().str().c_str());
+              }
+            }
+          }
+        }
+
+        frame->ChangePC(original_pc);
+      }
+    }
+  }
+
   if (!m_comment.empty()) {
     ss.FillLastLineToColumn(
         opcode_pos + opcode_column_width + operand_column_width, ' ');

>From 8c6b22dab6ef744742ae46e948f204d6b27f8145 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Sat, 5 Jul 2025 01:22:33 -0400
Subject: [PATCH 14/19] Added Initial Basic API test for rich variable
 annotation in disassembly output. Right now just checks if DW annotations
 show up for a basic program and that a variable location is annotated (i.e 'a
 = DW_OP_reg...').

---
 .../rich-disassembler/Makefile                |   4 ++
 .../rich-disassembler/TestRichDisassembler.py |  38 ++++++++++++++++++
 .../rich-disassembler/main.cpp                |  15 +++++++
 .../rich-disassembler/unoptimized_output      | Bin 0 -> 17184 bytes
 4 files changed, 57 insertions(+)
 create mode 100644 lldb/test/API/functionalities/rich-disassembler/Makefile
 create mode 100644 
lldb/test/API/functionalities/rich-disassembler/TestRichDisassembler.py
 create mode 100644 lldb/test/API/functionalities/rich-disassembler/main.cpp
 create mode 100755 
lldb/test/API/functionalities/rich-disassembler/unoptimized_output

diff --git a/lldb/test/API/functionalities/rich-disassembler/Makefile 
b/lldb/test/API/functionalities/rich-disassembler/Makefile
new file mode 100644
index 0000000000000..5fcbc722e7559
--- /dev/null
+++ b/lldb/test/API/functionalities/rich-disassembler/Makefile
@@ -0,0 +1,4 @@
+CXX := clang++
+CXX_SOURCES := main.cpp
+CXXFLAGS_EXTRAS := -g -O0 -fno-inline
+include Makefile.rules
diff --git 
a/lldb/test/API/functionalities/rich-disassembler/TestRichDisassembler.py 
b/lldb/test/API/functionalities/rich-disassembler/TestRichDisassembler.py
new file mode 100644
index 0000000000000..2a8b7df1947c1
--- /dev/null
+++ b/lldb/test/API/functionalities/rich-disassembler/TestRichDisassembler.py
@@ -0,0 +1,38 @@
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+
+class TestRichDisassembler(TestBase):
+    """
+    Tests that the disassembler includes DWARF variable annotations in output.
+    Specifically checks that variables like 'a' and 'temp' are shown with 
DW_OP locations.
+    """
+    def test_variable_annotation(self):
+        print("Building with:", self.getCompiler())
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        src_file = lldb.SBFileSpec("main.cpp")
+        breakpoint = target.BreakpointCreateByName("test")
+        print("Breakpoint locations:", breakpoint.GetNumLocations())
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        print("Process state:", process.GetState())
+        print("Exit status:", process.GetExitStatus())
+        print("Exit description:", process.GetExitDescription())
+
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped, "Process did 
not stop")
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        # Check that at least one DWARF annotation is shown.
+        self.assertIn("DW_OP_", disasm)
+
+        # Check that at least one variable name is annotated.
+        self.assertRegex(disasm, r'[a-zA-Z_]\w*\s*=\s*DW_OP_')
+
diff --git a/lldb/test/API/functionalities/rich-disassembler/main.cpp 
b/lldb/test/API/functionalities/rich-disassembler/main.cpp
new file mode 100644
index 0000000000000..4fa182b9fa0de
--- /dev/null
+++ b/lldb/test/API/functionalities/rich-disassembler/main.cpp
@@ -0,0 +1,15 @@
+// main.cpp
+
+
+__attribute__((noinline))
+void test(int a) {
+  for (int i = 0; i < 3; ++i) {       // i should be in a register
+    int temp = i + 1;                 // temp also likely register
+  }
+}
+
+int main() {
+  test(5);
+  return 0;
+}
+
diff --git a/lldb/test/API/functionalities/rich-disassembler/unoptimized_output 
b/lldb/test/API/functionalities/rich-disassembler/unoptimized_output
new file mode 100755
index 
0000000000000000000000000000000000000000..3ead1df962fa45b59eb04f5957d72195cfbe1332
GIT binary patch
literal 17184
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
T;$5w_KD*J8s|laLXR3b!>b;%1

literal 0
HcmV?d00001


>From 842a9e51bd89282277e067a66cd6f1651fa61a74 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Sun, 6 Jul 2025 01:09:36 -0400
Subject: [PATCH 15/19] Improved DWARF variable annotation printing and
 alignment

- Fixed an issue where variable location annotations were not shown if the 
current instruction address did not exactly match the DWARF base address. Now, 
annotations are shown as long as the PC is within the valid range.
- Improved alignment of annotation comments in Instruction::Dump(). While 
`FillLastLineToColumn` can sometimes overcompensate due to internal formatting 
or byte-width mismatches, the overall alignment is now significantly more 
consistent and readable.
---
 lldb/source/Core/Disassembler.cpp | 64 ++++++++++++++++++++-----------
 1 file changed, 41 insertions(+), 23 deletions(-)

diff --git a/lldb/source/Core/Disassembler.cpp 
b/lldb/source/Core/Disassembler.cpp
index f818eb20bdad5..a3f8efe3487ef 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -705,6 +705,8 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t 
max_opcode_byte_size,
   ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
   ss.PutCString(mnemonics);
 
+  const size_t annotation_column = 150;
+
   if (exe_ctx && exe_ctx->GetFramePtr()) {
     StackFrame *frame = exe_ctx->GetFramePtr();
     TargetSP target_sp = exe_ctx->GetTargetSP();
@@ -718,29 +720,45 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t 
max_opcode_byte_size,
         if (sc.function)
           func_load_addr = 
sc.function->GetAddress().GetLoadAddress(target_sp.get());
 
-        if (var_list_sp) {
-          for (size_t i = 0; i < var_list_sp->GetSize(); ++i) {
-            VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
-            if (!var_sp)
-              continue;
-
-            const char *name = var_sp->GetName().AsCString();
-            auto &expr_list = var_sp->LocationExpressionList();
-
-            // Handle std::optional<DWARFExpressionEntry>.
-            if (auto entryOrErr = 
expr_list.GetExpressionEntryAtAddress(func_load_addr, current_pc)) {
-              auto entry = *entryOrErr;
-
-              // Translate file-range to load-space start.
-              addr_t file_base = 
entry.file_range.GetBaseAddress().GetFileAddress();
-              addr_t start_load_addr = file_base + (func_load_addr - 
expr_list.GetFuncFileAddress());
-
-              if (current_pc == start_load_addr) {
-                StreamString loc_str;
-                ABI *abi = exe_ctx->GetProcessPtr()->GetABI().get();
-                entry.expr->DumpLocation(&loc_str, eDescriptionLevelBrief, 
abi);
-                ss.FillLastLineToColumn(opcode_pos + opcode_column_width + 
operand_column_width, ' ');
-                ss.Printf(" ; %s = %s", name, 
loc_str.GetString().str().c_str());
+        
+        if(ss.GetSizeOfLastLine() < annotation_column) {
+
+          std::vector<std::string> annotations;
+
+          if (var_list_sp) {
+            for (size_t i = 0; i < var_list_sp->GetSize(); ++i) {
+              VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
+              if (!var_sp)
+                continue;
+
+              const char *name = var_sp->GetName().AsCString();
+              auto &expr_list = var_sp->LocationExpressionList();
+              if (!expr_list.IsValid())
+                continue;
+              // Handle std::optional<DWARFExpressionEntry>.
+              if (auto entryOrErr = 
expr_list.GetExpressionEntryAtAddress(func_load_addr, current_pc)) {
+                auto entry = *entryOrErr;
+
+                // Translate file-range to load-space start.
+                addr_t file_base = 
entry.file_range.GetBaseAddress().GetFileAddress();
+                addr_t start_load_addr = file_base + (func_load_addr - 
expr_list.GetFuncFileAddress());
+
+                if (current_pc >= start_load_addr) {
+                  StreamString loc_str;
+                  ABI *abi = exe_ctx->GetProcessPtr()->GetABI().get();
+                  entry.expr->DumpLocation(&loc_str, eDescriptionLevelBrief, 
abi);
+                  annotations.push_back(llvm::formatv("{0} = {1}", name, 
loc_str.GetString()));
+                }
+              }
+            }
+
+            if (!annotations.empty()) {
+              ss.FillLastLineToColumn(annotation_column, ' ');
+              ss.PutCString(" ; ");
+              for (size_t i = 0; i < annotations.size(); ++i) {
+                if (i > 0)
+                  ss.PutCString(", ");
+                ss.PutCString(annotations[i]);
               }
             }
           }

>From 2fa6d243b24927510af426cfbd57c112c7289b0e Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Sun, 6 Jul 2025 11:10:46 -0400
Subject: [PATCH 16/19] Filter out partial DWARF decoding errors from
 disassembly annotations

Previously, when a DWARF expression contained any decoding error,
the entire variable location annotation was printed with the error,
e.g. `c = DW_OP_addr 0x0, <decoding error> 00 00 00`. This was
misleading and cluttered the disassembly view.

This patch improves the formatting by stripping out the
`<decoding error ...>` fragments while preserving the valid portions
of the expression, so that partial information like
`c = DW_OP_addr 0x0` can still be shown.

This allows the rich disassembler to give more meaningful variable
annotations, especially in optimized (-O1/-O2) builds where partial
DWARF corruption or unsupported expressions may occur.
---
 lldb/source/Core/Disassembler.cpp | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Core/Disassembler.cpp 
b/lldb/source/Core/Disassembler.cpp
index a3f8efe3487ef..0982c98fd80c0 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -49,6 +49,7 @@
 
 #include <cstdint>
 #include <cstring>
+#include <regex>
 #include <utility>
 
 #include <cassert>
@@ -747,7 +748,19 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t 
max_opcode_byte_size,
                   StreamString loc_str;
                   ABI *abi = exe_ctx->GetProcessPtr()->GetABI().get();
                   entry.expr->DumpLocation(&loc_str, eDescriptionLevelBrief, 
abi);
-                  annotations.push_back(llvm::formatv("{0} = {1}", name, 
loc_str.GetString()));
+                  
+                  std::string loc_output = loc_str.GetString().str();
+
+                  // Remove ", <decoding error> ..." segments.
+                  std::regex decoding_err_re(", <decoding error>[^,]*");
+                  loc_output = std::regex_replace(loc_output, decoding_err_re, 
"");
+
+                  llvm::StringRef cleaned_output = 
llvm::StringRef(loc_output).trim();
+
+                  // Only keep this annotation if there is still something 
useful left.
+                  if (!cleaned_output.empty()) {
+                    annotations.push_back(llvm::formatv("{0} = {1}", name, 
cleaned_output));
+                  }
                 }
               }
             }

>From 6bbc8aaa45e8df045ccb5be4db52ab23fa169aa2 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Sun, 6 Jul 2025 11:45:19 -0400
Subject: [PATCH 17/19] Ignore annotations with only decoding errors

Handled edge case where the entire DWARF expression is a `<decoding error>`, 
ensuring no misleading or empty annotations are printed for such variables.
---
 lldb/source/Core/Disassembler.cpp | 35 +++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Core/Disassembler.cpp 
b/lldb/source/Core/Disassembler.cpp
index 0982c98fd80c0..710856404b67a 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -751,15 +751,38 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t 
max_opcode_byte_size,
                   
                   std::string loc_output = loc_str.GetString().str();
 
-                  // Remove ", <decoding error> ..." segments.
-                  std::regex decoding_err_re(", <decoding error>[^,]*");
-                  loc_output = std::regex_replace(loc_output, decoding_err_re, 
"");
+                  // // Remove ", <decoding error> ..." segments.
+                  // std::regex decoding_err_re(", <decoding error>[^,]*");
+                  // loc_output = std::regex_replace(loc_output, 
decoding_err_re, "");
 
-                  llvm::StringRef cleaned_output = 
llvm::StringRef(loc_output).trim();
+                  // llvm::StringRef cleaned_output = 
llvm::StringRef(loc_output).trim();
+
+                  // // Only keep this annotation if there is still something 
useful left.
+                  // if (!cleaned_output.empty()) {
+                  //   annotations.push_back(llvm::formatv("{0} = {1}", name, 
cleaned_output));
+                  // }
+
+                  llvm::SmallVector<llvm::StringRef, 4> parts;
+                  llvm::StringRef(loc_str.GetString()).split(parts, ", ");
+
+                  // Reconstruct the string without the decoding error chunks
+                  std::string cleaned_output;
+                  bool first = true;
+
+                  for (const auto &part : parts) {
+                    if (part.contains("<decoding error>"))
+                      continue;
+
+                    if (!first)
+                      cleaned_output += ", ";
+                    cleaned_output += part.str();
+                    first = false;
+                  }
 
                   // Only keep this annotation if there is still something 
useful left.
-                  if (!cleaned_output.empty()) {
-                    annotations.push_back(llvm::formatv("{0} = {1}", name, 
cleaned_output));
+                  llvm::StringRef cleaned_ref = 
llvm::StringRef(cleaned_output).trim();
+                  if (!cleaned_ref.empty()) {
+                    annotations.push_back(llvm::formatv("{0} = {1}", name, 
cleaned_ref));
                   }
                 }
               }

>From cbbc9241e0b620f7cc8e925fd83fe36dd94536a4 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Sun, 6 Jul 2025 14:19:12 -0400
Subject: [PATCH 18/19] Add tests for disassembly variable annotations and
 decoding edge cases

This patch adds API tests to verify that DWARF variable location
annotations are correctly displayed in the disassembly output.

The tests cover:
- Local variables in loops and functions
- Multiple stack variables
- Control flow edge cases
- Different optimization levels (-O0, -O1, -O2)
- Ensuring decoding errors are excluded from output
---
 .../rich-disassembler/Makefile                |   8 +-
 .../rich-disassembler/TestRichDisassembler.py | 295 +++++++++++++++++-
 .../a_loop_with_local_variable.c              |   8 +
 .../b_multiple_stack_variables.c              |   9 +
 .../c_variable_passed_to_another_function.c   |  11 +
 .../rich-disassembler/d_original_example.c    |   7 +
 .../rich-disassembler/e_control_flow_edge.c   |  10 +
 .../rich-disassembler/main.cpp                |  15 -
 .../rich-disassembler/unoptimized_output      | Bin 17184 -> 0 bytes
 9 files changed, 328 insertions(+), 35 deletions(-)
 create mode 100644 
lldb/test/API/functionalities/rich-disassembler/a_loop_with_local_variable.c
 create mode 100644 
lldb/test/API/functionalities/rich-disassembler/b_multiple_stack_variables.c
 create mode 100644 
lldb/test/API/functionalities/rich-disassembler/c_variable_passed_to_another_function.c
 create mode 100644 
lldb/test/API/functionalities/rich-disassembler/d_original_example.c
 create mode 100644 
lldb/test/API/functionalities/rich-disassembler/e_control_flow_edge.c
 delete mode 100644 lldb/test/API/functionalities/rich-disassembler/main.cpp
 delete mode 100755 
lldb/test/API/functionalities/rich-disassembler/unoptimized_output

diff --git a/lldb/test/API/functionalities/rich-disassembler/Makefile 
b/lldb/test/API/functionalities/rich-disassembler/Makefile
index 5fcbc722e7559..ae3330e632a0e 100644
--- a/lldb/test/API/functionalities/rich-disassembler/Makefile
+++ b/lldb/test/API/functionalities/rich-disassembler/Makefile
@@ -1,4 +1,6 @@
-CXX := clang++
-CXX_SOURCES := main.cpp
-CXXFLAGS_EXTRAS := -g -O0 -fno-inline
+
+# CXX_SOURCES := a_loop_with_local_variable.c  b_multiple_stack_variables.c  
c_variable_passed_to_another_function.c  d_original_example.c  
e_control_flow_edge.c
+C_SOURCES := a_loop_with_local_variable.c b_multiple_stack_variables.c 
c_variable_passed_to_another_function.c d_original_example.c 
e_control_flow_edge.c
+
+
 include Makefile.rules
diff --git 
a/lldb/test/API/functionalities/rich-disassembler/TestRichDisassembler.py 
b/lldb/test/API/functionalities/rich-disassembler/TestRichDisassembler.py
index 2a8b7df1947c1..d85e6488575b7 100644
--- a/lldb/test/API/functionalities/rich-disassembler/TestRichDisassembler.py
+++ b/lldb/test/API/functionalities/rich-disassembler/TestRichDisassembler.py
@@ -2,37 +2,298 @@
 from lldbsuite.test.decorators import *
 
 class TestRichDisassembler(TestBase):
-    """
-    Tests that the disassembler includes DWARF variable annotations in output.
-    Specifically checks that variables like 'a' and 'temp' are shown with 
DW_OP locations.
-    """
-    def test_variable_annotation(self):
-        print("Building with:", self.getCompiler())
-        self.build()
+
+    @no_debug_info_test
+    def test_a_loop_with_local_variable(self):
+        """
+        Tests that the disassembler includes basic DWARF variable annotation 
in output.
+        Specifically checks that local variables in a loop are shown with 
DW_OP locations.
+        Additionally, it verifies that the disassembly does not contain 
decoding errors.
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'a_loop_with_local_variable.c',
+            'CFLAGS_EXTRAS': '-g -O0'
+        })
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        # Set a breakpoint inside main's loop
+        src_file = lldb.SBFileSpec("test_loop_function_call.c")
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        # Check that we have DWARF annotations for variables
+        self.assertIn("i = ", disasm)
+        self.assertIn("DW_OP", disasm)
+        self.assertNotIn("<decoding error>", disasm)
+
+
+    @no_debug_info_test
+    def test_b_multiple_stack_variables_O0(self):
+        """
+        Tests disassembler output for b_multiple_stack_variables.c built with 
-O0.
+        This test checks that multiple local variables are annotated with DWARF
+        and that their locations are distinct. It also ensures that no 
decoding errors appear.
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'b_multiple_stack_variables.c',
+            'CFLAGS_EXTRAS': '-g -O0'
+        })
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        # Set a breakpoint inside main's loop
+        src_file = lldb.SBFileSpec("test_loop_function_call.c")
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        # Check that we have DWARF annotations for variables
+        self.assertIn("a = ", disasm)
+        self.assertIn("b = ", disasm)
+        self.assertIn("c = ", disasm)
+        self.assertIn("DW_OP", disasm)
+        self.assertNotIn("<decoding error>", disasm)
+
+
+    @no_debug_info_test
+    def test_b_multiple_stack_variables_O1(self):
+        """
+        Tests disassembler output for b_multiple_stack_variables.c built with 
-O1.
+        Due to optimizations, some variables may be optimized out.
+        We only check for 'c' and ensure no decoding errors appear.
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'b_multiple_stack_variables.c',
+            'CFLAGS_EXTRAS': '-g -O1'
+        })
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        self.assertIn("c = ", disasm)
+        self.assertIn("DW_OP", disasm)
+        self.assertNotIn("<decoding error>", disasm)
+
+
+    @no_debug_info_test
+    def test_c_variable_passed_to_another_function(self):
+        """
+        Tests disassembler output for c_variable_passed_to_another_function.c.
+        This test checks that a variable passed to another function is 
annotated
+        with DWARF and that its location is distinct. It also ensures that no 
decoding errors appear.        
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'c_variable_passed_to_another_function.c',
+            'CFLAGS_EXTRAS': '-g -O0'
+        })
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        self.assertIn("x = ", disasm)
+        self.assertIn("DW_OP", disasm)
+        self.assertNotIn("<decoding error>", disasm)
+
+
+    @no_debug_info_test
+    def test_c_variable_passed_to_another_function_O1(self):
+        """
+        Tests disassembler output for c_variable_passed_to_another_function.c 
built with -O1.
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'c_variable_passed_to_another_function.c',
+            'CFLAGS_EXTRAS': '-g -O1'
+        })
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        self.assertIn("x = ", disasm)
+        self.assertIn("arg = ", disasm)
+        self.assertIn("DW_OP", disasm)
+        self.assertNotIn("<decoding error>", disasm)
+
+    @no_debug_info_test
+    def test_d_original_example(self):
+        """
+        Tests disassembler output for d_original_example.c.
+        This test checks that the disassembly includes basic DWARF variable 
annotations
+        and that local variables in the main function are shown with DW_OP 
locations.
+        Additionally, it verifies that the disassembly does not contain 
decoding errors.
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'd_original_example.c',
+            'CFLAGS_EXTRAS': '-g -O0'
+        })
         exe = self.getBuildArtifact("a.out")
         target = self.dbg.CreateTarget(exe)
         self.assertTrue(target)
 
-        src_file = lldb.SBFileSpec("main.cpp")
-        breakpoint = target.BreakpointCreateByName("test")
-        print("Breakpoint locations:", breakpoint.GetNumLocations())
+        breakpoint = target.BreakpointCreateByName("main")
         self.assertGreater(breakpoint.GetNumLocations(), 0)
 
         process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
-        print("Process state:", process.GetState())
-        print("Exit status:", process.GetExitStatus())
-        print("Exit description:", process.GetExitDescription())
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        self.assertIn("argc = ", disasm)
+        self.assertIn("argv = ", disasm)
+        self.assertIn("i = ", disasm)
+        self.assertIn("DW_OP", disasm)
+        self.assertNotIn("<decoding error>", disasm)
+
+    @no_debug_info_test
+    def test_d_original_example_O1(self):
+        """
+        Tests disassembler output for d_original_example.c built with -O1.
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'd_original_example.c',
+            'CFLAGS_EXTRAS': '-g -O1'
+        })
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        self.assertIn("argc = ", disasm)
+        self.assertIn("argv = ", disasm)
+        self.assertIn("i = ", disasm)
+        self.assertIn("DW_OP_reg", disasm)
+        self.assertIn("DW_OP_stack_value", disasm)
+        self.assertNotIn("<decoding error>", disasm)
+
+
+    @no_debug_info_test
+    def test_e_control_flow_edge(self):
+        """
+        Tests disassembler output for e_control_flow_edge.c with a focus on 
control flow edges.
+        This test checks that the disassembly includes basic DWARF variable 
annotations
+        and that local variables in the main function are shown with DW_OP 
locations.
+        Additionally, it verifies that the disassembly does not contain 
decoding errors.
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'e_control_flow_edge.c',
+            'CFLAGS_EXTRAS': '-g -O0'
+        })
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
 
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
         self.assertTrue(process, "Failed to launch process")
-        self.assertEqual(process.GetState(), lldb.eStateStopped, "Process did 
not stop")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
 
         frame = process.GetSelectedThread().GetSelectedFrame()
         disasm = frame.Disassemble()
         print(disasm)
 
-        # Check that at least one DWARF annotation is shown.
+        self.assertIn("a = ", disasm)
+        self.assertIn("b = ", disasm)
         self.assertIn("DW_OP_", disasm)
+        self.assertNotIn("<decoding error>", disasm)
+
+    @no_debug_info_test
+    def test_e_control_flow_edge_O1(self):
+        """
+        Tests disassembler output for e_control_flow_edge.c built with -O1.
+        This test checks that the disassembly annotation does not contain 
decoding errors.
+        """
+        self.build(dictionary={
+            'C_SOURCES': 'e_control_flow_edge.c',
+            'CFLAGS_EXTRAS': '-g -O1'
+        })
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target)
+
+        breakpoint = target.BreakpointCreateByName("main")
+        self.assertGreater(breakpoint.GetNumLocations(), 0)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, "Failed to launch process")
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+
+        frame = process.GetSelectedThread().GetSelectedFrame()
+        disasm = frame.Disassemble()
+        print(disasm)
+
+        self.assertNotIn("<decoding error>", disasm)
+
+
+    
+
+
+
+
+
 
-        # Check that at least one variable name is annotated.
-        self.assertRegex(disasm, r'[a-zA-Z_]\w*\s*=\s*DW_OP_')
 
diff --git 
a/lldb/test/API/functionalities/rich-disassembler/a_loop_with_local_variable.c 
b/lldb/test/API/functionalities/rich-disassembler/a_loop_with_local_variable.c
new file mode 100644
index 0000000000000..6555f3822187f
--- /dev/null
+++ 
b/lldb/test/API/functionalities/rich-disassembler/a_loop_with_local_variable.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int main() {
+    for (int i = 0; i < 3; ++i) {
+        puts("Hi");
+    }
+    return 0;
+}
diff --git 
a/lldb/test/API/functionalities/rich-disassembler/b_multiple_stack_variables.c 
b/lldb/test/API/functionalities/rich-disassembler/b_multiple_stack_variables.c
new file mode 100644
index 0000000000000..d3cd447b43d65
--- /dev/null
+++ 
b/lldb/test/API/functionalities/rich-disassembler/b_multiple_stack_variables.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main() {
+    int a = 1;
+    int b = 2;
+    int c = a + b;
+    return c;
+}
+
diff --git 
a/lldb/test/API/functionalities/rich-disassembler/c_variable_passed_to_another_function.c
 
b/lldb/test/API/functionalities/rich-disassembler/c_variable_passed_to_another_function.c
new file mode 100644
index 0000000000000..9603bdc636043
--- /dev/null
+++ 
b/lldb/test/API/functionalities/rich-disassembler/c_variable_passed_to_another_function.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+void foo(int arg) {
+    printf("%d\n", arg);
+}
+
+int main() {
+    int x = 10;
+    foo(x);
+    return 0;
+}
diff --git 
a/lldb/test/API/functionalities/rich-disassembler/d_original_example.c 
b/lldb/test/API/functionalities/rich-disassembler/d_original_example.c
new file mode 100644
index 0000000000000..4f245f518a182
--- /dev/null
+++ b/lldb/test/API/functionalities/rich-disassembler/d_original_example.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+    for (int i = 1; i < argc; ++i)
+        puts(argv[i]);
+    return 0;
+}
diff --git 
a/lldb/test/API/functionalities/rich-disassembler/e_control_flow_edge.c 
b/lldb/test/API/functionalities/rich-disassembler/e_control_flow_edge.c
new file mode 100644
index 0000000000000..d8d69f501eb4f
--- /dev/null
+++ b/lldb/test/API/functionalities/rich-disassembler/e_control_flow_edge.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main() {
+    int a = 1;
+    if (a > 0) {
+        int b = 2;
+        return b;
+    }
+    return a;
+}
diff --git a/lldb/test/API/functionalities/rich-disassembler/main.cpp 
b/lldb/test/API/functionalities/rich-disassembler/main.cpp
deleted file mode 100644
index 4fa182b9fa0de..0000000000000
--- a/lldb/test/API/functionalities/rich-disassembler/main.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// main.cpp
-
-
-__attribute__((noinline))
-void test(int a) {
-  for (int i = 0; i < 3; ++i) {       // i should be in a register
-    int temp = i + 1;                 // temp also likely register
-  }
-}
-
-int main() {
-  test(5);
-  return 0;
-}
-
diff --git a/lldb/test/API/functionalities/rich-disassembler/unoptimized_output 
b/lldb/test/API/functionalities/rich-disassembler/unoptimized_output
deleted file mode 100755
index 
3ead1df962fa45b59eb04f5957d72195cfbe1332..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 17184
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
T;$5w_KD*J8s|laLXR3b!>b;%1


>From b887db2cb51c170ec8c6b0159768344d919cab10 Mon Sep 17 00:00:00 2001
From: ultimateforce21 <abdullahmohammad...@gmail.com>
Date: Mon, 7 Jul 2025 23:52:24 -0400
Subject: [PATCH 19/19] Rebase disassembler annotations branch onto updated
 DWARFExpressionEntry API

This rebases the `add-disassembler-annotations` work onto the
latest `add-dwarfexprentry-api` branch so that the instruction
annotation patches sit cleanly atop the new DWARFExpressionEntry
struct and helper API. All conflicts have been resolved and the
annotation code now integrates with the updated 
std::optional<AddressRange>-based
GetExpressionEntryAtAddress signature.
---
 lldb/source/Core/Disassembler.cpp | 19 +++----------------
 1 file changed, 3 insertions(+), 16 deletions(-)

diff --git a/lldb/source/Core/Disassembler.cpp 
b/lldb/source/Core/Disassembler.cpp
index 710856404b67a..30a028d005dc1 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -49,7 +49,6 @@
 
 #include <cstdint>
 #include <cstring>
-#include <regex>
 #include <utility>
 
 #include <cassert>
@@ -740,28 +739,16 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t 
max_opcode_byte_size,
               if (auto entryOrErr = 
expr_list.GetExpressionEntryAtAddress(func_load_addr, current_pc)) {
                 auto entry = *entryOrErr;
 
-                // Translate file-range to load-space start.
-                addr_t file_base = 
entry.file_range.GetBaseAddress().GetFileAddress();
-                addr_t start_load_addr = file_base + (func_load_addr - 
expr_list.GetFuncFileAddress());
+                // Check if entry has a file_range, and filter on address if 
so.
+                if (!entry.file_range || entry.file_range->ContainsFileAddress(
+                        (current_pc - func_load_addr) + 
expr_list.GetFuncFileAddress())) {
 
-                if (current_pc >= start_load_addr) {
                   StreamString loc_str;
                   ABI *abi = exe_ctx->GetProcessPtr()->GetABI().get();
                   entry.expr->DumpLocation(&loc_str, eDescriptionLevelBrief, 
abi);
                   
                   std::string loc_output = loc_str.GetString().str();
 
-                  // // Remove ", <decoding error> ..." segments.
-                  // std::regex decoding_err_re(", <decoding error>[^,]*");
-                  // loc_output = std::regex_replace(loc_output, 
decoding_err_re, "");
-
-                  // llvm::StringRef cleaned_output = 
llvm::StringRef(loc_output).trim();
-
-                  // // Only keep this annotation if there is still something 
useful left.
-                  // if (!cleaned_output.empty()) {
-                  //   annotations.push_back(llvm::formatv("{0} = {1}", name, 
cleaned_output));
-                  // }
-
                   llvm::SmallVector<llvm::StringRef, 4> parts;
                   llvm::StringRef(loc_str.GetString()).split(parts, ", ");
 

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to