[Lldb-commits] [lldb] [lldb] Handle non-zero offsets from CFA when computing initial SP value (PR #192752)

via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 17 16:08:33 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Sergei Barannikov (s-barannikov)

<details>
<summary>Changes</summary>

Some targets (for example, X86 and MSP430) push the return address on the stack when calling a function, and have CFA=SP+offset initial rule. This offset must be taken into account when building an unwind plan by analyzing instructions.

None of the in-tree targets that currently implement EmulateInstruction plugin interface experience this bug because all of them define the initial CFA value as zero offset from SP.

---
Full diff: https://github.com/llvm/llvm-project/pull/192752.diff


4 Files Affected:

- (modified) lldb/include/lldb/Symbol/UnwindPlan.h (+3-1) 
- (modified) lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (+10-2) 
- (modified) lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h (+1-1) 
- (modified) lldb/source/Symbol/UnwindPlan.cpp (+6) 


``````````diff
diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h b/lldb/include/lldb/Symbol/UnwindPlan.h
index fe8081f83c590..31483f97fe39d 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -486,7 +486,9 @@ class UnwindPlan {
 
   const UnwindPlan::Row *GetRowAtIndex(uint32_t idx) const;
 
-  const UnwindPlan::Row *GetLastRow() const;
+  const Row *GetFirstRow() const;
+
+  const Row *GetLastRow() const;
 
   lldb_private::ConstString GetSourceName() const;
 
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index 19ae1cf392efa..8b50b2c1042fa 100644
--- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -95,7 +95,13 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
 
   // CreateFunctionEntryUnwind should have created the first row. If it doesn't,
   // then we are done.
-  if (unwind_plan.GetRowCount() == 0)
+  const UnwindPlan::Row *initial_row = unwind_plan.GetFirstRow();
+  if (!initial_row)
+    return false;
+
+  // Only isRegisterPlusOffset rule is currently supported.
+  const UnwindPlan::Row::FAValue &initial_row_cfa = initial_row->GetCFAValue();
+  if (!initial_row_cfa.IsRegisterPlusOffset())
     return false;
 
   const bool prefer_file_cache = true;
@@ -119,7 +125,9 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
   m_pushed_regs.clear();
 
   RegisterValue cfa_reg_value;
-  cfa_reg_value.SetUInt(m_initial_cfa, m_state.cfa_reg_info.byte_size);
+  assert(initial_row_cfa.IsRegisterPlusOffset());
+  cfa_reg_value.SetUInt(m_initial_cfa - initial_row_cfa.GetOffset(),
+                        m_state.cfa_reg_info.byte_size);
   SetRegisterValue(m_state.cfa_reg_info, cfa_reg_value);
 
   InstructionList inst_list = disasm_sp->GetInstructionList();
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
index 43daf1c9f9fd6..ddce8c61ec413 100644
--- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
+++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -138,7 +138,7 @@ class UnwindAssemblyInstEmulation : public lldb_private::UnwindAssembly {
   lldb_private::AddressRange *m_range_ptr;
   lldb_private::UnwindPlan *m_unwind_plan_ptr;
   UnwindState m_state;
-  uint64_t m_initial_cfa;
+  lldb::addr_t m_initial_cfa;
   typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap;
   PushedRegisterToAddrMap m_pushed_regs;
 
diff --git a/lldb/source/Symbol/UnwindPlan.cpp b/lldb/source/Symbol/UnwindPlan.cpp
index 9245e52732061..008568d4aacb2 100644
--- a/lldb/source/Symbol/UnwindPlan.cpp
+++ b/lldb/source/Symbol/UnwindPlan.cpp
@@ -444,6 +444,12 @@ const UnwindPlan::Row *UnwindPlan::GetRowAtIndex(uint32_t idx) const {
   return nullptr;
 }
 
+const UnwindPlan::Row *UnwindPlan::GetFirstRow() const {
+  if (m_row_list.empty())
+    return nullptr;
+  return &m_row_list.front();
+}
+
 const UnwindPlan::Row *UnwindPlan::GetLastRow() const {
   if (m_row_list.empty()) {
     LLDB_LOG(GetLog(LLDBLog::Unwind),

``````````

</details>


https://github.com/llvm/llvm-project/pull/192752


More information about the lldb-commits mailing list