DavidSpickett updated this revision to Diff 382287. DavidSpickett added a comment.
Set ValidAtAllInstructions. Move building unwind plan into PlatformLinux and add a platform method to lookup unwind plans for signal handlers. I'm still checking architecture in PlatformLinux but it does move the code out of Symbol. The only per arch thing on lldb's side is Architecture plugins but they're not meant to know about operating system. So it seems like a reasonable compromise to put it in PlatformLinux. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D112069/new/ https://reviews.llvm.org/D112069 Files: lldb/include/lldb/Target/Platform.h lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp lldb/source/Plugins/Platform/Linux/PlatformLinux.h lldb/source/Target/RegisterContextUnwind.cpp lldb/test/API/functionalities/signal/handle-abrt/TestHandleAbort.py
Index: lldb/test/API/functionalities/signal/handle-abrt/TestHandleAbort.py =================================================================== --- lldb/test/API/functionalities/signal/handle-abrt/TestHandleAbort.py +++ lldb/test/API/functionalities/signal/handle-abrt/TestHandleAbort.py @@ -16,8 +16,6 @@ NO_DEBUG_INFO_TESTCASE = True @skipIfWindows # signals do not exist on Windows - # Fails on Ubuntu Focal - @skipIf(archs=["aarch64"], oslist=["linux"]) @expectedFailureNetBSD def test_inferior_handle_sigabrt(self): """Inferior calls abort() and handles the resultant SIGABRT. @@ -47,6 +45,9 @@ self.assertEqual(thread.GetStopReasonDataAtIndex(0), signo, "The stop signal should be SIGABRT") + # Save the backtrace frames to compare to the handler backtrace later. + signal_frames = thread.get_thread_frames() + # Continue to breakpoint in abort handler bkpt = target.FindBreakpointByID( lldbutil.run_break_set_by_source_regexp(self, "Set a breakpoint here")) @@ -58,13 +59,21 @@ frame = thread.GetFrameAtIndex(0) self.assertEqual(frame.GetDisplayFunctionName(), "handler", "Unexpected break?") + handler_frames = thread.get_thread_frames() + # Expect that unwinding should find 'abort_caller' - foundFoo = False - for frame in thread: + found_caller = False + for frame in handler_frames: if frame.GetDisplayFunctionName() == "abort_caller": - foundFoo = True + found_caller = True + break + + self.assertTrue(found_caller, "Unwinding did not find func that called abort") - self.assertTrue(foundFoo, "Unwinding did not find func that called abort") + # Check that frames present in both backtraces have the same addresses. + # The signal handler backtrace has extra frames at the start. + self.assertEqual(signal_frames, handler_frames[-len(signal_frames):], + "Common frames for signal and signal handler backtrace do not match") # Continue until we exit. process.Continue() Index: lldb/source/Target/RegisterContextUnwind.cpp =================================================================== --- lldb/source/Target/RegisterContextUnwind.cpp +++ lldb/source/Target/RegisterContextUnwind.cpp @@ -900,6 +900,17 @@ // unwind out of sigtramp. if (m_frame_type == eTrapHandlerFrame && process) { m_fast_unwind_plan_sp.reset(); + + if (m_sym_ctx_valid) { + lldb::PlatformSP platform = process->GetTarget().GetPlatform(); + unwind_plan_sp = platform->GetTrapHandlerUnwindPlan( + process->GetTarget().GetArchitecture().GetMachine(), + GetSymbolOrFunctionName(m_sym_ctx)); + + if (unwind_plan_sp) + return unwind_plan_sp; + } + unwind_plan_sp = func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget()); if (!unwind_plan_sp) Index: lldb/source/Plugins/Platform/Linux/PlatformLinux.h =================================================================== --- lldb/source/Plugins/Platform/Linux/PlatformLinux.h +++ lldb/source/Plugins/Platform/Linux/PlatformLinux.h @@ -50,6 +50,9 @@ void CalculateTrapHandlerSymbolNames() override; + lldb::UnwindPlanSP GetTrapHandlerUnwindPlan(llvm::Triple::ArchType machine, + ConstString name) override; + MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, lldb::addr_t length, unsigned prot, unsigned flags, lldb::addr_t fd, Index: lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp =================================================================== --- lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -14,9 +14,11 @@ #include <sys/utsname.h> #endif +#include "Utility/ARM64_DWARF_Registers.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/FileSpec.h" @@ -251,6 +253,61 @@ m_trap_handlers.push_back(ConstString("__restore_rt")); } +static lldb::UnwindPlanSP GetAArch64TrapHanlderUnwindPlan(ConstString name) { + UnwindPlanSP unwind_plan_sp; + if (name != "__kernel_rt_sigreturn") + return unwind_plan_sp; + + UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>(); + row->SetOffset(0); + + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext struct: + // - 8-byte long (uc_flags) + // - 8-byte pointer (uc_link) + // - 24-byte stack_t + // - 128-byte signal set + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - sigcontext/mcontext_t + // [1] + // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c + int32_t offset = 128 + 8 + 8 + 24 + 128 + 8; + // Then sigcontext[2] is: + // - 8 byte fault address + // - 31 8 byte registers + // - 8 byte sp + // - 8 byte pc + // [2] + // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h + offset += 8 + (31 * 8); + row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, offset); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::fp, 0, false); + row->SetRegisterLocationToAtCFAPlusOffset(arm64_dwarf::pc, 8, false); + + unwind_plan_sp = std::make_shared<UnwindPlan>(eRegisterKindGeneric); + unwind_plan_sp->AppendRow(row); + unwind_plan_sp->SetSourceName("AArch64 Linux sigcontext"); + unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes); + // Because sp is the same throughout the function + unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); + unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes); + unwind_plan_sp->SetRegisterKind(eRegisterKindDWARF); + + return unwind_plan_sp; +} + +lldb::UnwindPlanSP +PlatformLinux::GetTrapHandlerUnwindPlan(llvm::Triple::ArchType machine, + ConstString name) { + if ((machine == llvm::Triple::ArchType::aarch64 || + machine == llvm::Triple::ArchType::aarch64_be || + machine == llvm::Triple::ArchType::aarch64_32)) + return GetAArch64TrapHanlderUnwindPlan(name); + + return {}; +} + MmapArgList PlatformLinux::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, addr_t length, unsigned prot, unsigned flags, Index: lldb/include/lldb/Target/Platform.h =================================================================== --- lldb/include/lldb/Target/Platform.h +++ lldb/include/lldb/Target/Platform.h @@ -720,6 +720,24 @@ /// A list of symbol names. The list may be empty. virtual const std::vector<ConstString> &GetTrapHandlerSymbolNames(); + /// Try to get a specific unwind plan for a named trap handler. + /// The default is not to have specific unwind plans for trap handlers. + /// + /// \param[in] machine + /// The architecture of the current target. + /// + /// \param[in] name + /// Name of the trap handler function. + /// + /// \return + /// A specific unwind plan for that trap handler, or an empty + /// shared pointer. The latter means there is no specific plan, + /// unwind as normal. + virtual lldb::UnwindPlanSP + GetTrapHandlerUnwindPlan(llvm::Triple::ArchType machine, ConstString name) { + return {}; + } + /// Find a support executable that may not live within in the standard /// locations related to LLDB. ///
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits