From 07b9e6ed0db206912b99c153a6bcfcb41f792cc5 Mon Sep 17 00:00:00 2001 From: Jaroslav Sevcik Date: Thu, 15 Jun 2023 18:10:25 +0200 Subject: [PATCH] [lldb] Fix handling of cfi_restore in the unwinder Currently, lldb's unwinder ignores cfi_restore opcodes for registers that are not set in the first row of the unwinding info. This prevents unwinding of failed assertion in Chrome/v8 (https://github.com/v8/v8). The attached test is an x64 copy of v8's function that failed to unwind correctly (V8_Fatal). This patch changes handling of cfi_restore to reset the location if the first unwind table row does not map the restored register. Differential Revision: https://reviews.llvm.org/D153043 --- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 5 +++++ .../Unwind/Inputs/eh-frame-dwarf-unwind-abort.s | 25 ++++++++++++++++++++++ .../Shell/Unwind/eh-frame-dwarf-unwind-abort.test | 21 ++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s create mode 100644 lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index be9f643..dc54d13 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -674,6 +674,11 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location)) row->SetRegisterInfo(reg_num, reg_location); + else { + // If the register was not set in the first row, remove the + // register info to keep the unmodified value from the caller. + row->RemoveRegisterInfo(reg_num); + } break; } } diff --git a/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s b/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s new file mode 100644 index 0000000..e03a69f --- /dev/null +++ b/lldb/test/Shell/Unwind/Inputs/eh-frame-dwarf-unwind-abort.s @@ -0,0 +1,25 @@ + .text + .globl asm_main +asm_main: + .cfi_startproc + cmpb $0x0, g_hard_abort(%rip) + jne .L + + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset 6, -16 + movq %rsp, %rbp + .cfi_def_cfa_register 6 + callq abort +.L: + .cfi_def_cfa 7, 8 + .cfi_restore 6 + int3 + ud2 + .cfi_endproc + + .data + .globl g_hard_abort +g_hard_abort: + .byte 1 + .size g_hard_abort, 1 \ No newline at end of file diff --git a/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test b/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test new file mode 100644 index 0000000..ccf973d --- /dev/null +++ b/lldb/test/Shell/Unwind/eh-frame-dwarf-unwind-abort.test @@ -0,0 +1,21 @@ +# Test restoring of register values. + +# UNSUPPORTED: system-windows +# REQUIRES: target-x86_64, native + +# RUN: %clang_host %p/Inputs/call-asm.c %p/Inputs/eh-frame-dwarf-unwind-abort.s -o %t +# RUN: %lldb %t -s %s -o exit | FileCheck %s + +process launch +# CHECK: stop reason = signal SIGTRAP + +thread backtrace +# CHECK: frame #0: {{.*}}`asm_main + 23 +# CHECK: frame #1: {{.*}}`main + {{.*}} + +target modules show-unwind -n asm_main +# CHECK: eh_frame UnwindPlan: +# CHECK: row[0]: 0: CFA=rsp +8 => rip=[CFA-8] +# CHECK: row[1]: 14: CFA=rsp+16 => rbp=[CFA-16] rip=[CFA-8] +# CHECK: row[2]: 17: CFA=rbp+16 => rbp=[CFA-16] rip=[CFA-8] +# CHECK: row[3]: 22: CFA=rsp +8 => rip=[CFA-8] -- 2.7.4