diff --git a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h --- a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h +++ b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h @@ -40,10 +40,15 @@ bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; - // In Windows_x86_64 ABI, stack will always be maintained 16-byte aligned + // In Windows_x86_64 ABI requires that the stack will be maintained 16-byte + // aligned. + // When ntdll invokes callbacks such as KiUserExceptionDispatcher or + // KiUserCallbackDispatcher, those functions won't have a properly 16-byte + // aligned stack - but tolerate unwinding through them by relaxing the + // requirement to 8 bytes. bool CallFrameAddressIsValid(lldb::addr_t cfa) override { - if (cfa & (16ull - 1ull)) - return false; // Not 16 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned if (cfa == 0) return false; // Zero is not a valid stack address return true; diff --git a/lldb/test/Shell/Unwind/Inputs/windows-unaligned-x86_64-asm.s b/lldb/test/Shell/Unwind/Inputs/windows-unaligned-x86_64-asm.s new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Unwind/Inputs/windows-unaligned-x86_64-asm.s @@ -0,0 +1,25 @@ + .globl call_func + .def call_func; .scl 2; .type 32; .endef + .seh_proc call_func +call_func: + subq $32, %rsp + .seh_stackalloc 32 + .seh_endprologue + call realign_stack + addq $32, %rsp + ret + .seh_endproc + + .globl realign_stack + .def realign_stack; .scl 2; .type 32; .endef + .seh_proc realign_stack +realign_stack: + subq $32, %rsp + .seh_stackalloc 32 + .seh_endprologue + movq %rcx, %rax + movl %edx, %ecx + call *%rax + addq $32, %rsp + ret + .seh_endproc diff --git a/lldb/test/Shell/Unwind/Inputs/windows-unaligned-x86_64.cpp b/lldb/test/Shell/Unwind/Inputs/windows-unaligned-x86_64.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Unwind/Inputs/windows-unaligned-x86_64.cpp @@ -0,0 +1,8 @@ +extern "C" void call_func(void (*ptr)(int a), int a); + +extern "C" void func(int arg) { } + +int main(int argc, char **argv) { + call_func(func, 42); + return 0; +} diff --git a/lldb/test/Shell/Unwind/windows-unaligned-x86_64.test b/lldb/test/Shell/Unwind/windows-unaligned-x86_64.test new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Unwind/windows-unaligned-x86_64.test @@ -0,0 +1,26 @@ +# Test unwinding through stack frames that aren't aligned to 16 bytes. +# (In real world code, this happens when unwinding through +# KiUserExceptionDispatcher and KiUserCallbackDispatcher in ntdll.dll.) + +# REQUIRES: target-x86_64, native, system-windows + +# RUN: %build %p/Inputs/windows-unaligned-x86_64.cpp %p/Inputs/windows-unaligned-x86_64-asm.s -o %t +# RUN: %lldb %t -s %s -o exit | FileCheck %s + +# Future TODO: If %build could compile the source file in C mode, the symbol +# name handling would be easier across msvc and mingw build configurations. +# (In mingw mode, the extern C symbol "func" is printed as "::func" while +# it's plain "func" in msvc mode. Without the extern C, it's "func(..." in +# mingw mode, but "void __cdecl func(..." in msvc mode.) + +breakpoint set -n func +# CHECK: Breakpoint 1: where = {{.*}}`{{(::)?}}func + +process launch +# CHECK: stop reason = breakpoint 1.1 + +thread backtrace +# CHECK: frame #0: {{.*}}`{{(::)?}}func +# CHECK: frame #1: {{.*}}`realign_stack +# CHECK: frame #2: {{.*}}`call_func +# CHECK: frame #3: {{.*}}`main