llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Pavel Labath (labath) <details> <summary>Changes</summary> A leaf function may not store the link register to stack, but we it can still end up being a non-zero frame if it gets interrupted by a signal. Currently, we were unable to unwind past this function because we could not read the link register value. To make this work, this patch: - changes the function-entry unwind plan to include the `fp|lr = <same>` rules. This in turn necessitated an adjustment in the generic instruction emulation logic to ensure that `lr=[sp-X]` can override the `<same>` rule. - allows the `<same>` rule for pc and lr in all `m_all_registers_available` frames (and not just frame zero). The test verifies that we can unwind in a situation like this, and that the backtrace matches the one we computed before getting a signal. --- Full diff: https://github.com/llvm/llvm-project/pull/91321.diff 6 Files Affected: - (modified) lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp (+2) - (modified) lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (+1-3) - (modified) lldb/source/Target/RegisterContextUnwind.cpp (+3-3) - (added) lldb/test/Shell/Unwind/Inputs/signal-in-leaf-function-aarch64.c (+15) - (added) lldb/test/Shell/Unwind/signal-in-leaf-function-aarch64.test (+24) - (modified) lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp (+20-4) ``````````diff diff --git a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp index 6ca4fb052457e..62ecac3e0831d 100644 --- a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp +++ b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -444,6 +444,8 @@ bool EmulateInstructionARM64::CreateFunctionEntryUnwind( // Our previous Call Frame Address is the stack pointer row->GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_arm64, 0); + row->SetRegisterLocationToSame(gpr_lr_arm64, /*must_replace=*/false); + row->SetRegisterLocationToSame(gpr_fp_arm64, /*must_replace=*/false); unwind_plan.AppendRow(row); unwind_plan.SetSourceName("EmulateInstructionARM64"); diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index c4a171ec7d01b..49edd40544e32 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -424,8 +424,6 @@ size_t UnwindAssemblyInstEmulation::WriteMemory( log->PutString(strm.GetString()); } - const bool cant_replace = false; - switch (context.type) { default: case EmulateInstruction::eContextInvalid: @@ -467,7 +465,7 @@ size_t UnwindAssemblyInstEmulation::WriteMemory( m_pushed_regs[reg_num] = addr; const int32_t offset = addr - m_initial_sp; m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset, - cant_replace); + /*can_replace=*/true); m_curr_row_modified = true; } } diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index 13e101413a477..e2d712cb72eae 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -1555,12 +1555,12 @@ RegisterContextUnwind::SavedLocationForRegister( } if (unwindplan_regloc.IsSame()) { - if (!IsFrameZero() && + if (!m_all_registers_available && (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC || regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) { UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or " - "return address reg on a non-zero frame -- treat as if we " - "have no information", + "return address reg on a frame which does not have all " + "registers available -- treat as if we have no information", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } else { diff --git a/lldb/test/Shell/Unwind/Inputs/signal-in-leaf-function-aarch64.c b/lldb/test/Shell/Unwind/Inputs/signal-in-leaf-function-aarch64.c new file mode 100644 index 0000000000000..9a751330623f4 --- /dev/null +++ b/lldb/test/Shell/Unwind/Inputs/signal-in-leaf-function-aarch64.c @@ -0,0 +1,15 @@ +#include <signal.h> +#include <unistd.h> + +int __attribute__((naked)) signal_generating_add(int a, int b) { + asm("add w0, w1, w0\n\t" + "udf #0xdead\n\t" + "ret"); +} + +void sigill_handler(int) { _exit(0); } + +int main() { + signal(SIGILL, sigill_handler); + return signal_generating_add(42, 47); +} diff --git a/lldb/test/Shell/Unwind/signal-in-leaf-function-aarch64.test b/lldb/test/Shell/Unwind/signal-in-leaf-function-aarch64.test new file mode 100644 index 0000000000000..0580d0cf734ae --- /dev/null +++ b/lldb/test/Shell/Unwind/signal-in-leaf-function-aarch64.test @@ -0,0 +1,24 @@ +# REQUIRES: target-aarch64 && native +# UNSUPPORTED: system-windows + +# RUN: %clang_host %S/Inputs/signal-in-leaf-function-aarch64.c -o %t +# RUN: %lldb -s %s -o exit %t | FileCheck %s + +breakpoint set -n sigill_handler +# CHECK: Breakpoint 1: where = {{.*}}`sigill_handler + +run +# CHECK: thread #1, {{.*}} stop reason = signal SIGILL + +thread backtrace +# CHECK: frame #0: [[ADD:0x[0-9a-fA-F]*]] {{.*}}`signal_generating_add +# CHECK: frame #1: [[MAIN:0x[0-9a-fA-F]*]] {{.*}}`main + +continue +# CHECK: thread #1, {{.*}} stop reason = breakpoint 1 + +thread backtrace +# CHECK: frame #0: {{.*}}`sigill_handler +# Unknown number of signal trampoline frames +# CHECK: frame #{{[0-9]+}}: [[ADD]] {{.*}}`signal_generating_add +# CHECK: frame #{{[0-9]+}}: [[MAIN]] {{.*}}`main diff --git a/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp b/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp index 80abeb8fae9e5..9303d6f5f3c6e 100644 --- a/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp +++ b/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp @@ -77,7 +77,7 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) { // UnwindPlan we expect: - // row[0]: 0: CFA=sp +0 => + // row[0]: 0: CFA=sp +0 => fp= <same> lr= <same> // row[1]: 4: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8] // row[2]: 8: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8] // row[2]: 16: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8] @@ -88,13 +88,19 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) { EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( sample_range, data, sizeof(data), unwind_plan)); - // CFA=sp +0 + // CFA=sp +0 => fp= <same> lr= <same> row_sp = unwind_plan.GetRowForFunctionOffset(0); EXPECT_EQ(0ull, row_sp->GetOffset()); EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); + EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); + EXPECT_TRUE(regloc.IsSame()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); + EXPECT_TRUE(regloc.IsSame()); + // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8] row_sp = unwind_plan.GetRowForFunctionOffset(4); EXPECT_EQ(4ull, row_sp->GetOffset()); @@ -146,6 +152,12 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) { EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); + EXPECT_TRUE(regloc.IsSame()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); + EXPECT_TRUE(regloc.IsSame()); } TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) { @@ -381,8 +393,12 @@ TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) { EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x26_arm64, regloc)); EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x27_arm64, regloc)); EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x28_arm64, regloc)); - EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); - EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); + + EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); + EXPECT_TRUE(regloc.IsSame()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); + EXPECT_TRUE(regloc.IsSame()); row_sp = unwind_plan.GetRowForFunctionOffset(36); EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); `````````` </details> https://github.com/llvm/llvm-project/pull/91321 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits