[Lldb-commits] [lldb] [lldb] Use the .pdata function start for a frame 0 that has no symbol (PR #227298)

Charles Zablit via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 16 07:53:49 PDT 2026


https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/227298

>From 00c9f4cf5fc97e129f88149fc69cad14898d4551 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 29 Sep 2026 13:44:12 +0100
Subject: [PATCH 1/2] [lldb] Use the .pdata function start for a frame 0 that
 has no symbol

---
 lldb/source/Target/RegisterContextUnwind.cpp  | 25 +++++++++-
 .../Inputs/symbolless-entry-unwind.dmp.yaml   | 27 +++++++++++
 .../Inputs/symbolless-entry-unwind.exe.yaml   | 47 +++++++++++++++++++
 .../Windows/symbolless-entry-unwind.test      | 12 +++++
 4 files changed, 109 insertions(+), 2 deletions(-)
 create mode 100644 lldb/test/Shell/Minidump/Windows/Inputs/symbolless-entry-unwind.dmp.yaml
 create mode 100644 lldb/test/Shell/Minidump/Windows/Inputs/symbolless-entry-unwind.exe.yaml
 create mode 100644 lldb/test/Shell/Minidump/Windows/symbolless-entry-unwind.test

diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 8d31c291f21686..b9d10f585bd528 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -75,6 +75,20 @@ static bool IsClangOutlinedFunction(const SymbolContext &sym_ctx) {
   return false;
 }
 
+/// Return the start of the function containing \p pc according to the object
+/// file's own unwind info (the .pdata RUNTIME_FUNCTION on PE/COFF x64), or an
+/// invalid address if there is none.
+static Address GetFunctionStartFromObjectFileUnwindInfo(const Address &pc) {
+  ModuleSP module_sp = pc.GetModule();
+  if (!module_sp)
+    return Address();
+  CallFrameInfo *cfi = module_sp->GetUnwindTable().GetObjectFileUnwindInfo();
+  AddressRange range;
+  if (!cfi || !cfi->GetAddressRange(pc, range))
+    return Address();
+  return range.GetBaseAddress();
+}
+
 #define UNWIND_LOG_IMPL(LOG_FN, log, ...)                                      \
   LOG_FN(log, "{0}th{1}/fr{2} {3}",                                            \
          llvm::indent(std::min(m_frame_number, 100U)), m_thread.GetIndexID(),  \
@@ -223,6 +237,13 @@ void RegisterContextUnwind::InitializeZerothFrame() {
           m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
     }
     m_current_offset_backed_up_one = m_current_offset;
+  } else if (Address start =
+                 GetFunctionStartFromObjectFileUnwindInfo(m_current_pc);
+             start.IsValid()) {
+    m_start_pc = start;
+    m_current_offset =
+        m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
+    m_current_offset_backed_up_one = m_current_offset;
   } else {
     m_start_pc = m_current_pc;
     m_current_offset = std::nullopt;
@@ -928,8 +949,8 @@ RegisterContextUnwind::GetFullUnwindPlanForFrame() {
     // track.
     if (DWARFCallFrameInfo *eh_frame =
             pc_module_sp->GetUnwindTable().GetEHFrameInfo()) {
-      if (std::unique_ptr<UnwindPlan> plan_up =
-              eh_frame->GetUnwindPlan(m_current_pc))
+      if (std::unique_ptr<UnwindPlan> plan_up = eh_frame->GetUnwindPlan(
+              {AddressRange(m_current_pc, 1)}, m_start_pc))
         return plan_up;
     }
 
diff --git a/lldb/test/Shell/Minidump/Windows/Inputs/symbolless-entry-unwind.dmp.yaml b/lldb/test/Shell/Minidump/Windows/Inputs/symbolless-entry-unwind.dmp.yaml
new file mode 100644
index 00000000000000..591998c483c9b5
--- /dev/null
+++ b/lldb/test/Shell/Minidump/Windows/Inputs/symbolless-entry-unwind.dmp.yaml
@@ -0,0 +1,27 @@
+--- !minidump
+Streams:
+  - Type:            ThreadList
+    Threads:
+      - Thread Id:       0x00001000
+        Context:         0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101000400100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+        Stack:
+          Start of Memory Range: 0x20000
+          Content:         0910004001000000DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD0000000000000000DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+  - Type:            MemoryList
+    Memory Ranges:
+      - Start of Memory Range: 0x20000
+        Content:         0910004001000000DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD0000000000000000DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+  - Type:            ModuleList
+    Modules:
+      - Base of Image:   0x140000000
+        Size of Image:   0x00004000
+        Module Name:     'symbolless-entry-unwind.exe'
+        CodeView Record: ''
+  - Type:            SystemInfo
+    Processor Arch:  AMD64
+    Platform ID:     Win32NT
+    CPU:
+      Vendor ID:       GenuineIntel
+      Version Info:    0x00000000
+      Feature Info:    0x00000000
+...
diff --git a/lldb/test/Shell/Minidump/Windows/Inputs/symbolless-entry-unwind.exe.yaml b/lldb/test/Shell/Minidump/Windows/Inputs/symbolless-entry-unwind.exe.yaml
new file mode 100644
index 00000000000000..27dc947d47bad0
--- /dev/null
+++ b/lldb/test/Shell/Minidump/Windows/Inputs/symbolless-entry-unwind.exe.yaml
@@ -0,0 +1,47 @@
+# An x86_64 PE image with no symbol table and no exports. Its two functions
+# are described only by .pdata/.xdata:
+#   0x140001000 caller: sub rsp, 0x28; call callee; add rsp, 0x28; ret
+#   0x140001010 callee: push rbp; push rbx; sub rsp, 0x48;
+#                       add rsp, 0x48; pop rbx; pop rbp; ret
+--- !COFF
+OptionalHeader:
+  AddressOfEntryPoint: 4096
+  ImageBase:       5368709120
+  SectionAlignment: 4096
+  FileAlignment:   512
+  MajorOperatingSystemVersion: 6
+  MinorOperatingSystemVersion: 0
+  MajorImageVersion: 0
+  MinorImageVersion: 0
+  MajorSubsystemVersion: 6
+  MinorSubsystemVersion: 0
+  Subsystem:       IMAGE_SUBSYSTEM_WINDOWS_CUI
+  DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]
+  SizeOfStackReserve: 1048576
+  SizeOfStackCommit: 4096
+  SizeOfHeapReserve: 1048576
+  SizeOfHeapCommit: 4096
+  ExceptionTable:
+    RelativeVirtualAddress: 12288
+    Size:            24
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  4096
+    VirtualSize:     29
+    SectionData:     4883EC28E8070000004883C428C3CCCC55534883EC484883C4485B5DC3
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  8192
+    VirtualSize:     20
+    SectionData:     0104010004420000010603000682023001500000
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  12288
+    VirtualSize:     24
+    SectionData:     001000000E10000000200000101000001D10000008200000
+symbols:         []
+...
diff --git a/lldb/test/Shell/Minidump/Windows/symbolless-entry-unwind.test b/lldb/test/Shell/Minidump/Windows/symbolless-entry-unwind.test
new file mode 100644
index 00000000000000..33809de47b68b7
--- /dev/null
+++ b/lldb/test/Shell/Minidump/Windows/symbolless-entry-unwind.test
@@ -0,0 +1,12 @@
+Test unwinding from the first instruction of a function that no symbol covers
+and that is described only by the PE .pdata/.xdata unwind info.
+
+RUN: mkdir -p %t.dir
+RUN: yaml2obj %S/Inputs/symbolless-entry-unwind.exe.yaml -o %t.dir/symbolless-entry-unwind.exe
+RUN: yaml2obj %S/Inputs/symbolless-entry-unwind.dmp.yaml -o %t.dir/symbolless-entry-unwind.dmp
+RUN: %lldb -O "settings set target.exec-search-paths %t.dir" \
+RUN:   -c %t.dir/symbolless-entry-unwind.dmp -o "thread backtrace" -o exit \
+RUN:   | FileCheck %s
+
+CHECK:      frame #0: 0x0000000140001010 symbolless-entry-unwind.exe`
+CHECK-NEXT: frame #1: 0x0000000140001009 symbolless-entry-unwind.exe`

>From 4714e76dbafb1b2fa8b8aef024f4f169c9a33e44 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Fri, 16 Oct 2026 13:57:28 +0100
Subject: [PATCH 2/2] Address review comments

---
 lldb/include/lldb/Symbol/UnwindTable.h        |  5 ++++
 lldb/source/Symbol/UnwindTable.cpp            | 11 ++++++++
 lldb/source/Target/RegisterContextUnwind.cpp  | 26 ++++++-------------
 .../lang/cpp/signed_types/TestSignedTypes.py  |  2 +-
 4 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/lldb/include/lldb/Symbol/UnwindTable.h b/lldb/include/lldb/Symbol/UnwindTable.h
index f2741cb46dbf9a..0ba86fa89dc897 100644
--- a/lldb/include/lldb/Symbol/UnwindTable.h
+++ b/lldb/include/lldb/Symbol/UnwindTable.h
@@ -43,6 +43,11 @@ class UnwindTable {
   GetFuncUnwindersContainingAddress(const Address &addr,
                                     const SymbolContext &sc);
 
+  /// Return the start of the function containing \p addr according to the
+  /// object file's own unwind info (the .pdata RUNTIME_FUNCTION on PE/COFF
+  /// x64), or an invalid address if there is none.
+  Address GetFunctionStartFromObjectFileUnwindInfo(const Address &addr);
+
   bool GetAllowAssemblyEmulationUnwindPlans();
 
   // Normally when we create a new FuncUnwinders object we track it in this
diff --git a/lldb/source/Symbol/UnwindTable.cpp b/lldb/source/Symbol/UnwindTable.cpp
index 3aca495696c844..b89409e8eb0d4f 100644
--- a/lldb/source/Symbol/UnwindTable.cpp
+++ b/lldb/source/Symbol/UnwindTable.cpp
@@ -174,6 +174,17 @@ FuncUnwindersSP UnwindTable::GetUncachedFuncUnwindersContainingAddress(
   return std::make_shared<FuncUnwinders>(*this, start_addr, std::move(ranges));
 }
 
+Address
+UnwindTable::GetFunctionStartFromObjectFileUnwindInfo(const Address &addr) {
+  Initialize();
+
+  AddressRange range;
+  if (!m_object_file_unwind_up ||
+      !m_object_file_unwind_up->GetAddressRange(addr, range))
+    return Address();
+  return range.GetBaseAddress();
+}
+
 void UnwindTable::Dump(Stream &s) {
   std::lock_guard<std::mutex> guard(m_mutex);
   s.Format("UnwindTable for '{0}':\n", m_module.GetFileSpec());
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index b9d10f585bd528..68c0730ec94c81 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -75,20 +75,6 @@ static bool IsClangOutlinedFunction(const SymbolContext &sym_ctx) {
   return false;
 }
 
-/// Return the start of the function containing \p pc according to the object
-/// file's own unwind info (the .pdata RUNTIME_FUNCTION on PE/COFF x64), or an
-/// invalid address if there is none.
-static Address GetFunctionStartFromObjectFileUnwindInfo(const Address &pc) {
-  ModuleSP module_sp = pc.GetModule();
-  if (!module_sp)
-    return Address();
-  CallFrameInfo *cfi = module_sp->GetUnwindTable().GetObjectFileUnwindInfo();
-  AddressRange range;
-  if (!cfi || !cfi->GetAddressRange(pc, range))
-    return Address();
-  return range.GetBaseAddress();
-}
-
 #define UNWIND_LOG_IMPL(LOG_FN, log, ...)                                      \
   LOG_FN(log, "{0}th{1}/fr{2} {3}",                                            \
          llvm::indent(std::min(m_frame_number, 100U)), m_thread.GetIndexID(),  \
@@ -238,7 +224,10 @@ void RegisterContextUnwind::InitializeZerothFrame() {
     }
     m_current_offset_backed_up_one = m_current_offset;
   } else if (Address start =
-                 GetFunctionStartFromObjectFileUnwindInfo(m_current_pc);
+                 pc_module_sp ? pc_module_sp->GetUnwindTable()
+                                    .GetFunctionStartFromObjectFileUnwindInfo(
+                                        m_current_pc)
+                              : Address();
              start.IsValid()) {
     m_start_pc = start;
     m_current_offset =
@@ -935,9 +924,10 @@ RegisterContextUnwind::GetFullUnwindPlanForFrame() {
 
   // No FuncUnwinders available for this pc (stripped function symbols, lldb
   // could not augment its function table with another source, like
-  // LC_FUNCTION_STARTS or eh_frame in ObjectFileMachO). See if eh_frame or the
-  // .ARM.exidx tables have unwind information for this address, else fall back
-  // to the architectural default unwind.
+  // LC_FUNCTION_STARTS or eh_frame in ObjectFileMachO). See if eh_frame, the
+  // .ARM.exidx tables or the object file's own unwind info (e.g. the PE EH info
+  // in .pdata) have unwind information for this address, else fall back to the
+  // architectural default unwind.
   if (!func_unwinders_sp) {
     m_frame_type = eNormalFrame;
 
diff --git a/lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py b/lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py
index de9bbeaa9f33fd..12c3412929c84b 100644
--- a/lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py
+++ b/lldb/test/API/lang/cpp/signed_types/TestSignedTypes.py
@@ -20,7 +20,7 @@ def setUp(self):
     @expectedFailureAll(
         oslist=["windows"],
         debug_info=no_match(["pdb"]),
-        archs=["i[3-6]86", "x86_64", "aarch64"],
+        archs=["i[3-6]86", "aarch64"],
         bugnumber="llvm.org/pr24489",
     )
     def test(self):



More information about the lldb-commits mailing list