https://github.com/dsandersllvm updated 
https://github.com/llvm/llvm-project/pull/150732

>From bd27929645928939f319dc915da1a4636e4d317d Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sand...@apple.com>
Date: Wed, 28 Aug 2024 19:02:21 -0700
Subject: [PATCH 1/6] [lldb] Implement DW_CFA_val_offset and
 DW_CFA_val_offset_sf

The test for this is artificial as I'm not aware of any upstream targets
that use DW_CFA_val_offset

RegisterContextUnwind::ReadFrameAddress now reports how it's attempting to
obtain the CFA unless all success/failure cases emit logs that clearly
identify the method it was attempting. Previously several of the existing
failure paths emit no message or a message that's indistinguishable from
those on other paths.
---
 lldb/include/lldb/Symbol/UnwindPlan.h         |  20 +++
 lldb/include/lldb/Target/UnwindLLDB.h         |   8 ++
 lldb/source/Symbol/DWARFCallFrameInfo.cpp     |  28 +++-
 lldb/source/Symbol/UnwindPlan.cpp             |  17 +++
 lldb/source/Target/RegisterContextUnwind.cpp  |  54 +++++++-
 .../Symbol/TestDWARFCallFrameInfo.cpp         | 124 ++++++++++++++++++
 6 files changed, 248 insertions(+), 3 deletions(-)

diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h 
b/lldb/include/lldb/Symbol/UnwindPlan.h
index fe8081f83c590..9587f1312aa2e 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -67,6 +67,7 @@ class UnwindPlan {
         atAFAPlusOffset,   // reg = deref(AFA + offset)
         isAFAPlusOffset,   // reg = AFA + offset
         inOtherRegister,   // reg = other reg
+        isOtherRegisterPlusOffset, // reg = other reg + offset
         atDWARFExpression, // reg = deref(eval(dwarf_expr))
         isDWARFExpression, // reg = eval(dwarf_expr)
         isConstant         // reg = constant
@@ -102,6 +103,10 @@ class UnwindPlan {
 
       bool IsInOtherRegister() const { return m_type == inOtherRegister; }
 
+      bool IsOtherRegisterPlusOffset() const {
+        return m_type == isOtherRegisterPlusOffset;
+      }
+
       bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
 
       bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
@@ -140,9 +145,17 @@ class UnwindPlan {
         m_location.reg_num = reg_num;
       }
 
+      void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset = 0) {
+        m_type = isOtherRegisterPlusOffset;
+        m_location.reg_plus_offset.reg_num = reg_num;
+        m_location.reg_plus_offset.offset = offset;
+      }
+
       uint32_t GetRegisterNumber() const {
         if (m_type == inOtherRegister)
           return m_location.reg_num;
+        if (m_type == isOtherRegisterPlusOffset)
+          return m_location.reg_plus_offset.reg_num;
         return LLDB_INVALID_REGNUM;
       }
 
@@ -156,6 +169,8 @@ class UnwindPlan {
         case atAFAPlusOffset:
         case isAFAPlusOffset:
           return m_location.offset;
+        case inOtherRegister:
+          return m_location.reg_plus_offset.offset;
         default:
           return 0;
         }
@@ -204,6 +219,11 @@ class UnwindPlan {
         } expr;
         // For m_type == isConstant
         uint64_t constant_value;
+        // For m_type == inOtherRegisterPlusOffset
+        struct {
+          uint32_t reg_num;
+          int32_t offset;
+        } reg_plus_offset;
       } m_location;
     };
 
diff --git a/lldb/include/lldb/Target/UnwindLLDB.h 
b/lldb/include/lldb/Target/UnwindLLDB.h
index f2f65e67a7640..88180b37fd93a 100644
--- a/lldb/include/lldb/Target/UnwindLLDB.h
+++ b/lldb/include/lldb/Target/UnwindLLDB.h
@@ -49,6 +49,9 @@ class UnwindLLDB : public lldb_private::Unwind {
                                       // target mem (target_memory_location)
       eRegisterInRegister, // register is available in a (possible other)
                            // register (register_number)
+      eRegisterIsRegisterPlusOffset, // register is available in a (possible
+                                     // other) register (register_number) with
+                                     // an offset applied
       eRegisterSavedAtHostMemoryLocation, // register is saved at a word in
                                           // lldb's address space
       eRegisterValueInferred,        // register val was computed (and is in
@@ -64,6 +67,11 @@ class UnwindLLDB : public lldb_private::Unwind {
       void *host_memory_location;
       uint64_t inferred_value; // eRegisterValueInferred - e.g. stack pointer 
==
                                // cfa + offset
+      struct {
+        uint32_t
+            register_number; // in eRegisterKindLLDB register numbering system
+        uint64_t offset;
+      } reg_plus_offset;
     } location;
   };
 
diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp 
b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
index a2d748adad64a..2f8f9e9182fb2 100644
--- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -766,8 +766,32 @@ DWARFCallFrameInfo::ParseFDE(dw_offset_t dwarf_offset,
           break;
         }
 
-        case DW_CFA_val_offset:    // 0x14
-        case DW_CFA_val_offset_sf: // 0x15
+        case DW_CFA_val_offset: { // 0x14
+          // takes two unsigned LEB128 operands representing a register number
+          // and a factored offset. The required action is to change the rule
+          // for the register indicated by the register number to be a
+          // val_offset(N) rule where the value of N is factored_offset*
+          // data_alignment_factor
+          uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+          int32_t op_offset =
+              (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
+          reg_location.SetIsCFAPlusOffset(op_offset);
+          row.SetRegisterInfo(reg_num, reg_location);
+          break;
+        }
+        case DW_CFA_val_offset_sf: { // 0x15
+          // takes two operands: an unsigned LEB128 value representing a
+          // register number and a signed LEB128 factored offset. This
+          // instruction is identical to DW_CFA_val_offset except that the
+          // second operand is signed and factored. The resulting offset is
+          // factored_offset* data_alignment_factor.
+          uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+          int32_t op_offset =
+              (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
+          reg_location.SetIsCFAPlusOffset(op_offset);
+          row.SetRegisterInfo(reg_num, reg_location);
+          break;
+        }
         default:
           break;
         }
diff --git a/lldb/source/Symbol/UnwindPlan.cpp 
b/lldb/source/Symbol/UnwindPlan.cpp
index 9245e52732061..93587568a7e64 100644
--- a/lldb/source/Symbol/UnwindPlan.cpp
+++ b/lldb/source/Symbol/UnwindPlan.cpp
@@ -42,6 +42,12 @@ bool UnwindPlan::Row::AbstractRegisterLocation::operator==(
     case inOtherRegister:
       return m_location.reg_num == rhs.m_location.reg_num;
 
+    case isOtherRegisterPlusOffset:
+      return m_location.reg_plus_offset.reg_num ==
+                 rhs.m_location.reg_plus_offset.reg_num &&
+             m_location.reg_plus_offset.offset ==
+                 rhs.m_location.reg_plus_offset.offset;
+
     case atDWARFExpression:
     case isDWARFExpression:
       if (m_location.expr.length == rhs.m_location.expr.length)
@@ -145,6 +151,17 @@ void UnwindPlan::Row::AbstractRegisterLocation::Dump(
       s.Printf("=reg(%u)", m_location.reg_num);
   } break;
 
+  case isOtherRegisterPlusOffset: {
+    const RegisterInfo *other_reg_info = nullptr;
+    if (unwind_plan)
+      other_reg_info = unwind_plan->GetRegisterInfo(thread, 
m_location.reg_num);
+    if (other_reg_info)
+      s.Printf("=%s", other_reg_info->name);
+    else
+      s.Printf("=reg(%u)+%u", m_location.reg_plus_offset.reg_num,
+               m_location.reg_plus_offset.offset);
+  } break;
+
   case atDWARFExpression:
   case isDWARFExpression: {
     s.PutChar('=');
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp 
b/lldb/source/Target/RegisterContextUnwind.cpp
index 880300d0637fb..80345e6d3588c 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1118,6 +1118,27 @@ bool 
RegisterContextUnwind::ReadRegisterValueFromRegisterLocation(
       success = GetNextFrame()->ReadRegister(other_reg_info, value);
     }
   } break;
+  case UnwindLLDB::ConcreteRegisterLocation::eRegisterIsRegisterPlusOffset: {
+    auto regnum = regloc.location.reg_plus_offset.register_number;
+    const RegisterInfo *other_reg_info =
+        
GetRegisterInfoAtIndex(regloc.location.reg_plus_offset.register_number);
+
+    if (!other_reg_info)
+      return false;
+
+    if (IsFrameZero()) {
+      success =
+          m_thread.GetRegisterContext()->ReadRegister(other_reg_info, value);
+    } else {
+      success = GetNextFrame()->ReadRegister(other_reg_info, value);
+    }
+    if (success) {
+      UnwindLogMsg("read (%d)'s location", regnum);
+      value = value.GetAsUInt64(~0ull, &success) +
+              regloc.location.reg_plus_offset.offset;
+      UnwindLogMsg("success %s", success ? "yes" : "no");
+    }
+  } break;
   case UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred:
     success =
         value.SetUInt(regloc.location.inferred_value, reg_info->byte_size);
@@ -1164,6 +1185,7 @@ bool 
RegisterContextUnwind::WriteRegisterValueToRegisterLocation(
       success = GetNextFrame()->WriteRegister(other_reg_info, value);
     }
   } break;
+  case UnwindLLDB::ConcreteRegisterLocation::eRegisterIsRegisterPlusOffset:
   case UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred:
   case UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved:
     break;
@@ -1633,6 +1655,30 @@ RegisterContextUnwind::SavedLocationForRegister(
     return UnwindLLDB::RegisterSearchResult::eRegisterFound;
   }
 
+  if (abs_regloc->IsOtherRegisterPlusOffset()) {
+    uint32_t unwindplan_regnum = abs_regloc->GetRegisterNumber();
+    int unwindplan_offset = abs_regloc->GetOffset();
+    RegisterNumber row_regnum(m_thread, abs_regkind, unwindplan_regnum);
+    if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) {
+      UnwindLogMsg("could not supply caller's %s (%d) location - was saved in "
+                   "another reg+offset but couldn't convert that regnum",
+                   regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+      return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+    }
+    regloc.type =
+        UnwindLLDB::ConcreteRegisterLocation::eRegisterIsRegisterPlusOffset;
+    regloc.location.reg_plus_offset.register_number =
+        row_regnum.GetAsKind(eRegisterKindLLDB);
+    regloc.location.reg_plus_offset.offset = unwindplan_offset;
+    m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+    UnwindLogMsg("supplying caller's register %s (%d), "
+                 "from register %s (%d) plus offset %u",
+                 regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+                 row_regnum.GetName(), row_regnum.GetAsKind(eRegisterKindLLDB),
+                 unwindplan_offset);
+    return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+  }
+
   if (abs_regloc->IsDWARFExpression() || abs_regloc->IsAtDWARFExpression()) {
     DataExtractor dwarfdata(abs_regloc->GetDWARFExpressionBytes(),
                             abs_regloc->GetDWARFExpressionLength(),
@@ -1959,6 +2005,7 @@ bool RegisterContextUnwind::ReadFrameAddress(
 
   switch (fa.GetValueType()) {
   case UnwindPlan::Row::FAValue::isRegisterDereferenced: {
+    UnwindLogMsg("CFA value via dereferencing reg");
     RegisterNumber cfa_reg(m_thread, row_register_kind,
                            fa.GetRegisterNumber());
     if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
@@ -1991,6 +2038,7 @@ bool RegisterContextUnwind::ReadFrameAddress(
     break;
   }
   case UnwindPlan::Row::FAValue::isRegisterPlusOffset: {
+    UnwindLogMsg("CFA value via register plus offset");
     RegisterNumber cfa_reg(m_thread, row_register_kind,
                            fa.GetRegisterNumber());
     if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
@@ -2012,10 +2060,13 @@ bool RegisterContextUnwind::ReadFrameAddress(
           address, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
           cfa_reg_contents, fa.GetOffset());
       return true;
-    }
+    } else
+      UnwindLogMsg("unable to read CFA register %s (%d)", cfa_reg.GetName(),
+                   cfa_reg.GetAsKind(eRegisterKindLLDB));
     break;
   }
   case UnwindPlan::Row::FAValue::isDWARFExpression: {
+    UnwindLogMsg("CFA value via DWARF expression");
     ExecutionContext exe_ctx(m_thread.shared_from_this());
     Process *process = exe_ctx.GetProcessPtr();
     DataExtractor dwarfdata(fa.GetDWARFExpressionBytes(),
@@ -2042,6 +2093,7 @@ bool RegisterContextUnwind::ReadFrameAddress(
     break;
   }
   case UnwindPlan::Row::FAValue::isRaSearch: {
+    UnwindLogMsg("CFA value via heuristic search");
     Process &process = *m_thread.GetProcess();
     lldb::addr_t return_address_hint = GetReturnAddressHint(fa.GetOffset());
     if (return_address_hint == LLDB_INVALID_ADDRESS)
diff --git a/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp 
b/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
index c1dcab02227da..a75a4acd304b2 100644
--- a/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
+++ b/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
@@ -39,6 +39,7 @@ class DWARFCallFrameInfoTest : public testing::Test {
 
 protected:
   void TestBasic(DWARFCallFrameInfo::Type type, llvm::StringRef symbol);
+  void TestValOffset(DWARFCallFrameInfo::Type type, llvm::StringRef symbol);
 };
 
 namespace lldb_private {
@@ -256,3 +257,126 @@ TEST_F(DWARFCallFrameInfoTest, Basic_dwarf4) {
 TEST_F(DWARFCallFrameInfoTest, Basic_eh) {
   TestBasic(DWARFCallFrameInfo::EH, "eh_frame");
 }
+
+static UnwindPlan::Row GetValOffsetExpectedRow0() {
+  UnwindPlan::Row row;
+  row.SetOffset(0);
+  row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 16);
+  row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
+  row.SetRegisterLocationToIsCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
+  return row;
+}
+
+void DWARFCallFrameInfoTest::TestValOffset(DWARFCallFrameInfo::Type type,
+                                           llvm::StringRef symbol) {
+  // This test is artificial as X86 does not use DW_CFA_val_offset but this
+  // test verifies that we can successfully interpret them if they do occur.
+  // Note the distinction between RBP and RIP in this part of the DWARF dump:
+  // 0x0: CFA=RSP+16: RBP=CFA-16, RIP=[CFA-8]
+  // Whereas RIP is stored in the memory CFA-8 points at, RBP is reconstructed
+  // from the CFA without any memory access.
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x4
+    Content:         0F1F00
+  - Name:            .debug_frame
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x8
+#00000000 00000014 ffffffff CIE
+#  Format:                DWARF32
+#  Version:               4
+#  Augmentation:          ""
+#  Address size:          8
+#  Segment desc size:     0
+#  Code alignment factor: 1
+#  Data alignment factor: -8
+#  Return address column: 16
+#
+#  DW_CFA_def_cfa: RSP +8
+#  DW_CFA_offset: RIP -8
+#  DW_CFA_nop:
+#  DW_CFA_nop:
+#  DW_CFA_nop:
+#  DW_CFA_nop:
+#
+#  CFA=RSP+8: RIP=[CFA-8]
+#
+#00000018 0000001c 00000000 FDE cie=00000000 pc=00000000...00000003
+#  Format:       DWARF32
+#  DW_CFA_def_cfa_offset: +16
+#  DW_CFA_val_offset: RBP -16
+#  DW_CFA_nop:
+#  DW_CFA_nop:
+#  DW_CFA_nop:
+#
+#  0x0: CFA=RSP+16: RBP=CFA-16, RIP=[CFA-8]
+    Content:         
14000000FFFFFFFF040008000178100C07089001000000001C00000000000000000000000000000003000000000000000E10140602000000
+  - Name:            .rela.debug_frame
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x8
+    Info:            .debug_frame
+    Relocations:
+      - Offset:          0x1C
+        Symbol:          .debug_frame
+        Type:            R_X86_64_32
+      - Offset:          0x20
+        Symbol:          .text
+        Type:            R_X86_64_64
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            .text
+      - Name:            .debug_frame
+      - Name:            .rela.debug_frame
+      - Name:            .symtab
+Symbols:
+  - Name:            .text
+    Type:            STT_SECTION
+    Section:         .text
+  - Name:            debug_frame3
+    Section:         .text
+  - Name:            .debug_frame
+    Type:            STT_SECTION
+    Section:         .debug_frame
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+  SectionList *list = module_sp->GetSectionList();
+  ASSERT_NE(nullptr, list);
+
+  auto section_sp = list->FindSectionByType(type == DWARFCallFrameInfo::EH
+                                                ? eSectionTypeEHFrame
+                                                : eSectionTypeDWARFDebugFrame,
+                                            false);
+  ASSERT_NE(nullptr, section_sp);
+
+  DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp, type);
+
+  const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString(symbol), eSymbolTypeAny);
+  ASSERT_NE(nullptr, sym);
+
+  std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
+  ASSERT_TRUE(plan_up);
+  ASSERT_EQ(1, plan_up->GetRowCount());
+  EXPECT_THAT(plan_up->GetRowAtIndex(0), 
testing::Pointee(GetValOffsetExpectedRow0()));
+}
+
+TEST_F(DWARFCallFrameInfoTest, ValOffset_dwarf3) {
+  TestValOffset(DWARFCallFrameInfo::DWARF, "debug_frame3");
+}
+

>From c9e9bbfbfca5a2221bf5bb0be32789a705241a50 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sand...@apple.com>
Date: Mon, 28 Jul 2025 09:06:34 -0700
Subject: [PATCH 2/6] fixup: formatting

---
 lldb/include/lldb/Symbol/UnwindPlan.h         | 26 +++++++++----------
 .../Symbol/TestDWARFCallFrameInfo.cpp         |  4 +--
 2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h 
b/lldb/include/lldb/Symbol/UnwindPlan.h
index 9587f1312aa2e..7c562e6686023 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -57,20 +57,20 @@ class UnwindPlan {
     class AbstractRegisterLocation {
     public:
       enum RestoreType {
-        unspecified,       // not specified, we may be able to assume this
-                           // is the same register. gcc doesn't specify all
-                           // initial values so we really don't know...
-        undefined,         // reg is not available, e.g. volatile reg
-        same,              // reg is unchanged
-        atCFAPlusOffset,   // reg = deref(CFA + offset)
-        isCFAPlusOffset,   // reg = CFA + offset
-        atAFAPlusOffset,   // reg = deref(AFA + offset)
-        isAFAPlusOffset,   // reg = AFA + offset
-        inOtherRegister,   // reg = other reg
+        unspecified,     // not specified, we may be able to assume this
+                         // is the same register. gcc doesn't specify all
+                         // initial values so we really don't know...
+        undefined,       // reg is not available, e.g. volatile reg
+        same,            // reg is unchanged
+        atCFAPlusOffset, // reg = deref(CFA + offset)
+        isCFAPlusOffset, // reg = CFA + offset
+        atAFAPlusOffset, // reg = deref(AFA + offset)
+        isAFAPlusOffset, // reg = AFA + offset
+        inOtherRegister, // reg = other reg
         isOtherRegisterPlusOffset, // reg = other reg + offset
-        atDWARFExpression, // reg = deref(eval(dwarf_expr))
-        isDWARFExpression, // reg = eval(dwarf_expr)
-        isConstant         // reg = constant
+        atDWARFExpression,         // reg = deref(eval(dwarf_expr))
+        isDWARFExpression,         // reg = eval(dwarf_expr)
+        isConstant                 // reg = constant
       };
 
       AbstractRegisterLocation() : m_location() {}
diff --git a/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp 
b/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
index a75a4acd304b2..e113b8ca99341 100644
--- a/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
+++ b/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
@@ -373,10 +373,10 @@ void 
DWARFCallFrameInfoTest::TestValOffset(DWARFCallFrameInfo::Type type,
   std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
   ASSERT_TRUE(plan_up);
   ASSERT_EQ(1, plan_up->GetRowCount());
-  EXPECT_THAT(plan_up->GetRowAtIndex(0), 
testing::Pointee(GetValOffsetExpectedRow0()));
+  EXPECT_THAT(plan_up->GetRowAtIndex(0),
+              testing::Pointee(GetValOffsetExpectedRow0()));
 }
 
 TEST_F(DWARFCallFrameInfoTest, ValOffset_dwarf3) {
   TestValOffset(DWARFCallFrameInfo::DWARF, "debug_frame3");
 }
-

>From 7a0329fe6cc02f1ea057dccd09336b18968474b2 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sand...@apple.com>
Date: Mon, 28 Jul 2025 10:25:29 -0700
Subject: [PATCH 3/6] fixup: Remove unused code

---
 lldb/include/lldb/Symbol/UnwindPlan.h        | 20 ----------------
 lldb/source/Symbol/UnwindPlan.cpp            | 17 --------------
 lldb/source/Target/RegisterContextUnwind.cpp | 24 --------------------
 3 files changed, 61 deletions(-)

diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h 
b/lldb/include/lldb/Symbol/UnwindPlan.h
index 7c562e6686023..a38d36a69302d 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -67,7 +67,6 @@ class UnwindPlan {
         atAFAPlusOffset, // reg = deref(AFA + offset)
         isAFAPlusOffset, // reg = AFA + offset
         inOtherRegister, // reg = other reg
-        isOtherRegisterPlusOffset, // reg = other reg + offset
         atDWARFExpression,         // reg = deref(eval(dwarf_expr))
         isDWARFExpression,         // reg = eval(dwarf_expr)
         isConstant                 // reg = constant
@@ -103,10 +102,6 @@ class UnwindPlan {
 
       bool IsInOtherRegister() const { return m_type == inOtherRegister; }
 
-      bool IsOtherRegisterPlusOffset() const {
-        return m_type == isOtherRegisterPlusOffset;
-      }
-
       bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
 
       bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
@@ -145,17 +140,9 @@ class UnwindPlan {
         m_location.reg_num = reg_num;
       }
 
-      void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset = 0) {
-        m_type = isOtherRegisterPlusOffset;
-        m_location.reg_plus_offset.reg_num = reg_num;
-        m_location.reg_plus_offset.offset = offset;
-      }
-
       uint32_t GetRegisterNumber() const {
         if (m_type == inOtherRegister)
           return m_location.reg_num;
-        if (m_type == isOtherRegisterPlusOffset)
-          return m_location.reg_plus_offset.reg_num;
         return LLDB_INVALID_REGNUM;
       }
 
@@ -169,8 +156,6 @@ class UnwindPlan {
         case atAFAPlusOffset:
         case isAFAPlusOffset:
           return m_location.offset;
-        case inOtherRegister:
-          return m_location.reg_plus_offset.offset;
         default:
           return 0;
         }
@@ -219,11 +204,6 @@ class UnwindPlan {
         } expr;
         // For m_type == isConstant
         uint64_t constant_value;
-        // For m_type == inOtherRegisterPlusOffset
-        struct {
-          uint32_t reg_num;
-          int32_t offset;
-        } reg_plus_offset;
       } m_location;
     };
 
diff --git a/lldb/source/Symbol/UnwindPlan.cpp 
b/lldb/source/Symbol/UnwindPlan.cpp
index 93587568a7e64..9245e52732061 100644
--- a/lldb/source/Symbol/UnwindPlan.cpp
+++ b/lldb/source/Symbol/UnwindPlan.cpp
@@ -42,12 +42,6 @@ bool UnwindPlan::Row::AbstractRegisterLocation::operator==(
     case inOtherRegister:
       return m_location.reg_num == rhs.m_location.reg_num;
 
-    case isOtherRegisterPlusOffset:
-      return m_location.reg_plus_offset.reg_num ==
-                 rhs.m_location.reg_plus_offset.reg_num &&
-             m_location.reg_plus_offset.offset ==
-                 rhs.m_location.reg_plus_offset.offset;
-
     case atDWARFExpression:
     case isDWARFExpression:
       if (m_location.expr.length == rhs.m_location.expr.length)
@@ -151,17 +145,6 @@ void UnwindPlan::Row::AbstractRegisterLocation::Dump(
       s.Printf("=reg(%u)", m_location.reg_num);
   } break;
 
-  case isOtherRegisterPlusOffset: {
-    const RegisterInfo *other_reg_info = nullptr;
-    if (unwind_plan)
-      other_reg_info = unwind_plan->GetRegisterInfo(thread, 
m_location.reg_num);
-    if (other_reg_info)
-      s.Printf("=%s", other_reg_info->name);
-    else
-      s.Printf("=reg(%u)+%u", m_location.reg_plus_offset.reg_num,
-               m_location.reg_plus_offset.offset);
-  } break;
-
   case atDWARFExpression:
   case isDWARFExpression: {
     s.PutChar('=');
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp 
b/lldb/source/Target/RegisterContextUnwind.cpp
index 80345e6d3588c..9e9e2d86958f3 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1655,30 +1655,6 @@ RegisterContextUnwind::SavedLocationForRegister(
     return UnwindLLDB::RegisterSearchResult::eRegisterFound;
   }
 
-  if (abs_regloc->IsOtherRegisterPlusOffset()) {
-    uint32_t unwindplan_regnum = abs_regloc->GetRegisterNumber();
-    int unwindplan_offset = abs_regloc->GetOffset();
-    RegisterNumber row_regnum(m_thread, abs_regkind, unwindplan_regnum);
-    if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) {
-      UnwindLogMsg("could not supply caller's %s (%d) location - was saved in "
-                   "another reg+offset but couldn't convert that regnum",
-                   regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
-      return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
-    }
-    regloc.type =
-        UnwindLLDB::ConcreteRegisterLocation::eRegisterIsRegisterPlusOffset;
-    regloc.location.reg_plus_offset.register_number =
-        row_regnum.GetAsKind(eRegisterKindLLDB);
-    regloc.location.reg_plus_offset.offset = unwindplan_offset;
-    m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
-    UnwindLogMsg("supplying caller's register %s (%d), "
-                 "from register %s (%d) plus offset %u",
-                 regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
-                 row_regnum.GetName(), row_regnum.GetAsKind(eRegisterKindLLDB),
-                 unwindplan_offset);
-    return UnwindLLDB::RegisterSearchResult::eRegisterFound;
-  }
-
   if (abs_regloc->IsDWARFExpression() || abs_regloc->IsAtDWARFExpression()) {
     DataExtractor dwarfdata(abs_regloc->GetDWARFExpressionBytes(),
                             abs_regloc->GetDWARFExpressionLength(),

>From 321b51671a9a2d492cc40d5d146f6a4e13776886 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sand...@apple.com>
Date: Mon, 28 Jul 2025 12:58:48 -0700
Subject: [PATCH 4/6] fixup: formatting

---
 lldb/include/lldb/Symbol/UnwindPlan.h | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h 
b/lldb/include/lldb/Symbol/UnwindPlan.h
index a38d36a69302d..fe8081f83c590 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -57,19 +57,19 @@ class UnwindPlan {
     class AbstractRegisterLocation {
     public:
       enum RestoreType {
-        unspecified,     // not specified, we may be able to assume this
-                         // is the same register. gcc doesn't specify all
-                         // initial values so we really don't know...
-        undefined,       // reg is not available, e.g. volatile reg
-        same,            // reg is unchanged
-        atCFAPlusOffset, // reg = deref(CFA + offset)
-        isCFAPlusOffset, // reg = CFA + offset
-        atAFAPlusOffset, // reg = deref(AFA + offset)
-        isAFAPlusOffset, // reg = AFA + offset
-        inOtherRegister, // reg = other reg
-        atDWARFExpression,         // reg = deref(eval(dwarf_expr))
-        isDWARFExpression,         // reg = eval(dwarf_expr)
-        isConstant                 // reg = constant
+        unspecified,       // not specified, we may be able to assume this
+                           // is the same register. gcc doesn't specify all
+                           // initial values so we really don't know...
+        undefined,         // reg is not available, e.g. volatile reg
+        same,              // reg is unchanged
+        atCFAPlusOffset,   // reg = deref(CFA + offset)
+        isCFAPlusOffset,   // reg = CFA + offset
+        atAFAPlusOffset,   // reg = deref(AFA + offset)
+        isAFAPlusOffset,   // reg = AFA + offset
+        inOtherRegister,   // reg = other reg
+        atDWARFExpression, // reg = deref(eval(dwarf_expr))
+        isDWARFExpression, // reg = eval(dwarf_expr)
+        isConstant         // reg = constant
       };
 
       AbstractRegisterLocation() : m_location() {}

>From 2092e5660273141aa3abda9f297a1017d8d135f2 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sand...@apple.com>
Date: Wed, 30 Jul 2025 19:19:49 -0700
Subject: [PATCH 5/6] fixup: Additional test case

---
 .../Inputs/eh-frame-dwarf-unwind-val-offset.s | 46 +++++++++++++++
 .../eh-frame-dwarf-unwind-val-offset.test     | 58 +++++++++++++++++++
 2 files changed, 104 insertions(+)
 create mode 100644 
lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s
 create mode 100644 lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test

diff --git a/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s 
b/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s
new file mode 100644
index 0000000000000..b0ce2c29c9991
--- /dev/null
+++ b/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s
@@ -0,0 +1,46 @@
+        .text
+        .globl  bar
+bar:
+        .cfi_startproc
+        leal    (%edi, %edi), %eax
+        ret
+        .cfi_endproc
+
+        .globl  foo
+foo:
+        .cfi_startproc
+        .cfi_escape 0x16, 0x10, 0x06, 0x38, 0x1c, 0x06, 0x08, 0x47, 0x1c
+        # Clobber r12 and record that it's reconstructable from CFA
+        .cfi_val_offset %r12, 0
+        movq    $0x456, %r12
+        call    bar
+        addl    $1, %eax
+        # Reconstruct %r12
+        movq    %rsp, %r12
+        addq    %r12, 8
+        popq    %rdi
+        subq    $0x47, %rdi
+        jmp     *%rdi # Return
+        .cfi_endproc
+
+        .globl  asm_main
+asm_main:
+        .cfi_startproc
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset %rbp, -16
+        movq    %rsp, %rbp
+        movq    %rsp, %r12
+        .cfi_def_cfa_register %rbp
+        movl    $47, %edi
+
+        # Non-standard calling convention. The real return address must be
+        # decremented by 0x47.
+        leaq    0x47+1f(%rip), %rax
+        pushq   %rax
+        jmp     foo # call
+1:
+        popq    %rbp
+        .cfi_def_cfa %rsp, 8
+        ret
+        .cfi_endproc
diff --git a/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test 
b/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test
new file mode 100644
index 0000000000000..00b5fd31113b8
--- /dev/null
+++ b/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test
@@ -0,0 +1,58 @@
+# Test handing of the dwarf val_offset() rule which can be used to reconstruct
+# the value of a register that is neither in a live register or saved on the
+# stack but is computable with CFA + offset.
+
+# UNSUPPORTED: system-windows, ld_new-bug
+# REQUIRES: target-x86_64, native
+
+# RUN: %clang_host %p/Inputs/call-asm.c 
%p/Inputs/eh-frame-dwarf-unwind-val-offset.s -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+breakpoint set -n asm_main
+# CHECK: Breakpoint 1: where = {{.*}}`asm_main
+
+breakpoint set -n bar
+# CHECK: Breakpoint 2: where = {{.*}}`bar
+
+process launch
+# CHECK: stop reason = breakpoint 1.1
+
+stepi
+stepi
+stepi
+print/x $r12
+# CHECK: (unsigned long) 0x[[#%.16x,R12:]]{{$}}
+
+continue
+# CHECK: stop reason = breakpoint 2.1
+
+thread backtrace
+# CHECK: frame #0: {{.*}}`bar
+# CHECK: frame #1: {{.*}}`foo + 12
+# CHECK: frame #2: {{.*}}`asm_main + 25
+
+target modules show-unwind -n bar
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]:  0: CFA=rsp +8 => rip=[CFA-8]
+
+target modules show-unwind -n foo
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]: 0: CFA=rsp +8 => r12=CFA+0 rip=DW_OP_lit8, DW_OP_minus, 
DW_OP_deref, DW_OP_const1u 0x47, DW_OP_minus
+
+target modules show-unwind -n asm_main
+# CHECK: eh_frame UnwindPlan:
+# CHECK: row[0]:  0: CFA=rsp +8 => rip=[CFA-8]
+# CHECK: row[1]:  1: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[2]:  7: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[3]: 26: CFA=rsp +8 => rbp=[CFA-16] rip=[CFA-8]
+
+print/x $r12
+# CHECK: (unsigned long) 0x0000000000000456
+
+frame select 1
+print/x $r12
+# CHECK: (unsigned long) 0x0000000000000456
+
+frame select 2
+print/x $r12
+# CHECK: (unsigned long) 0x[[#R12]]

>From ed7dea3a7b9afcc11bdf4f6356f24205e1afaa81 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sand...@apple.com>
Date: Wed, 30 Jul 2025 19:31:24 -0700
Subject: [PATCH 6/6] fixup: Use a non-zero offset for the .cfi_val_offset

---
 .../Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s   |  3 ++-
 .../Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test | 10 +++++-----
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s 
b/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s
index b0ce2c29c9991..cd67114498bb8 100644
--- a/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s
+++ b/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-val-offset.s
@@ -11,7 +11,7 @@ foo:
         .cfi_startproc
         .cfi_escape 0x16, 0x10, 0x06, 0x38, 0x1c, 0x06, 0x08, 0x47, 0x1c
         # Clobber r12 and record that it's reconstructable from CFA
-        .cfi_val_offset %r12, 0
+        .cfi_val_offset %r12, 32
         movq    $0x456, %r12
         call    bar
         addl    $1, %eax
@@ -31,6 +31,7 @@ asm_main:
         .cfi_offset %rbp, -16
         movq    %rsp, %rbp
         movq    %rsp, %r12
+        addq    $32, %r12
         .cfi_def_cfa_register %rbp
         movl    $47, %edi
 
diff --git a/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test 
b/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test
index 00b5fd31113b8..64811e6196326 100644
--- a/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test
+++ b/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-val-offset.test
@@ -29,7 +29,7 @@ continue
 thread backtrace
 # CHECK: frame #0: {{.*}}`bar
 # CHECK: frame #1: {{.*}}`foo + 12
-# CHECK: frame #2: {{.*}}`asm_main + 25
+# CHECK: frame #2: {{.*}}`asm_main + 29
 
 target modules show-unwind -n bar
 # CHECK: eh_frame UnwindPlan:
@@ -37,14 +37,14 @@ target modules show-unwind -n bar
 
 target modules show-unwind -n foo
 # CHECK: eh_frame UnwindPlan:
-# CHECK: row[0]: 0: CFA=rsp +8 => r12=CFA+0 rip=DW_OP_lit8, DW_OP_minus, 
DW_OP_deref, DW_OP_const1u 0x47, DW_OP_minus
+# CHECK: row[0]: 0: CFA=rsp +8 => r12=CFA+32 rip=DW_OP_lit8, DW_OP_minus, 
DW_OP_deref, DW_OP_const1u 0x47, DW_OP_minus
 
 target modules show-unwind -n asm_main
 # CHECK: eh_frame UnwindPlan:
 # CHECK: row[0]:  0: CFA=rsp +8 => rip=[CFA-8]
 # CHECK: row[1]:  1: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8]
-# CHECK: row[2]:  7: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
-# CHECK: row[3]: 26: CFA=rsp +8 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[2]: 11: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8]
+# CHECK: row[3]: 30: CFA=rsp +8 => rbp=[CFA-16] rip=[CFA-8]
 
 print/x $r12
 # CHECK: (unsigned long) 0x0000000000000456
@@ -55,4 +55,4 @@ print/x $r12
 
 frame select 2
 print/x $r12
-# CHECK: (unsigned long) 0x[[#R12]]
+# CHECK: (unsigned long) 0x[[#R12 + 32]]

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

Reply via email to