[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
Tue Sep 29 05:50:28 PDT 2026
https://github.com/charles-zablit created https://github.com/llvm/llvm-project/pull/227298
When the current function has no symbol, the unwinder does not know where the function starts.
It then uses the Windows x64 unwind info for "after the prologue", even at the function's first instruction.
This gives a wrong frame address, so stepping over a call into static CRT code (e.g. [`puts`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/puts-putws?view=msvc-170)) stopped inside it.
This patch takes the function's start from [`.pdata`](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-pdata-section) instead. Only Windows x64 images are affected.
Adds a minidump regression test.
>From 798dd2af016fb64cb57aa4af9df978bc773436c0 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] [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 354bfddaa47ce..77790c5f25503 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 0000000000000..591998c483c9b
--- /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 0000000000000..27dc947d47bad
--- /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 0000000000000..33809de47b68b
--- /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`
More information about the lldb-commits
mailing list