Skip to content
Permalink
Browse files

Support Linux signal return trampolines in frame initialization

Summary:
Add __kernel_rt_sigreturn to the list of trap handlers for Linux (it's
used as such on aarch64 at least), and __restore_rt as well (used on
x86_64).

Skip decrement-and-recompute for trap handlers in
InitializeNonZerothFrame, as signal dispatch may point the child frame's
return address to the start of the return trampoline.

Parse the 'S' flag for signal handlers from eh_frame augmentation, and
propagate it to the unwind plan.

Reviewers: labath, jankratochvil, compnerd, jfb, jasonmolenda

Reviewed By: jasonmolenda

Subscribers: clayborg, MaskRay, wuzish, nemanjai, kbarton, jrtc27, atanasyan, jsji, javed.absar, kristof.beyls, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D63667

llvm-svn: 366580
  • Loading branch information...
JosephTremoulet committed Jul 19, 2019
1 parent 9e6a42a commit 3fd917d8860e9bdcabc14c536da4377307906be0
Showing with 169 additions and 12 deletions.
  1. +14 −0 lldb/include/lldb/Symbol/UnwindPlan.h
  2. +5 −0 lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/Makefile
  3. +72 −0 lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/TestHandleAbort.py
  4. +25 −0 lldb/packages/Python/lldbsuite/test/functionalities/signal/handle-abrt/main.c
  5. +1 −0 lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
  6. +1 −0 lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
  7. +1 −0 lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
  8. +1 −0 lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp
  9. +2 −0 lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
  10. +1 −0 lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
  11. +1 −0 lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp
  12. +1 −0 lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp
  13. +1 −0 lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp
  14. +1 −0 lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
  15. +1 −0 lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
  16. +1 −0 lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
  17. +1 −0 lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
  18. +1 −0 lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
  19. +1 −0 lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
  20. +1 −0 lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
  21. +1 −0 lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
  22. +2 −0 lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
  23. +22 −12 lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
  24. +1 −0 lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
  25. +1 −0 lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
  26. +1 −0 lldb/source/Symbol/ArmUnwindInfo.cpp
  27. +4 −0 lldb/source/Symbol/CompactUnwindInfo.cpp
  28. +4 −0 lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -370,6 +370,7 @@ class UnwindPlan {
m_return_addr_register(LLDB_INVALID_REGNUM), m_source_name(),
m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
m_plan_is_for_signal_trap(eLazyBoolCalculate),
m_lsda_address(), m_personality_func_addr() {}

// Performs a deep copy of the plan, including all the rows (expensive).
@@ -463,6 +464,17 @@ class UnwindPlan {
m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
}

// Is this UnwindPlan for a signal trap frame? If so, then its saved pc
// may have been set manually by the signal dispatch code and therefore
// not follow a call to the child frame.
lldb_private::LazyBool GetUnwindPlanForSignalTrap() const {
return m_plan_is_for_signal_trap;
}

void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) {
m_plan_is_for_signal_trap = is_for_signal_trap;
}

int GetRowCount() const;

void Clear() {
@@ -472,6 +484,7 @@ class UnwindPlan {
m_source_name.Clear();
m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
m_plan_is_for_signal_trap = eLazyBoolCalculate;
m_lsda_address.Clear();
m_personality_func_addr.Clear();
}
@@ -502,6 +515,7 @@ class UnwindPlan {
m_source_name; // for logging, where this UnwindPlan originated from
lldb_private::LazyBool m_plan_is_sourced_from_compiler;
lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
lldb_private::LazyBool m_plan_is_for_signal_trap;

Address m_lsda_address; // Where the language specific data area exists in the
// module - used
@@ -0,0 +1,5 @@
LEVEL = ../../../make

C_SOURCES := main.c

include $(LEVEL)/Makefile.rules
@@ -0,0 +1,72 @@
"""Test that we can unwind out of a SIGABRT handler"""

from __future__ import print_function


import os
import re

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class HandleAbortTestCase(TestBase):

mydir = TestBase.compute_mydir(__file__)

NO_DEBUG_INFO_TESTCASE = True

@skipIfWindows # signals do not exist on Windows
def test_inferior_handle_sigabrt(self):
"""Inferior calls abort() and handles the resultant SIGABRT.
Stopped at a breakpoint in the handler, verify that the backtrace
includes the function that called abort()."""
self.build()
exe = self.getBuildArtifact("a.out")

# Create a target by the debugger.
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)

# launch
process = target.LaunchSimple(
None, None, self.get_process_working_directory())
self.assertTrue(process, PROCESS_IS_VALID)
self.assertEqual(process.GetState(), lldb.eStateStopped)
signo = process.GetUnixSignals().GetSignalNumberFromName("SIGABRT")

thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
self.assertTrue(
thread and thread.IsValid(),
"Thread should be stopped due to a signal")
self.assertTrue(
thread.GetStopReasonDataCount() >= 1,
"There should be data in the event.")
self.assertEqual(thread.GetStopReasonDataAtIndex(0),
signo, "The stop signal should be SIGABRT")

# Continue to breakpoint in abort handler
bkpt = target.FindBreakpointByID(
lldbutil.run_break_set_by_source_regexp(self, "Set a breakpoint here"))
threads = lldbutil.continue_to_breakpoint(process, bkpt)
self.assertEqual(len(threads), 1, "Expected single thread")
thread = threads[0]

# Expect breakpoint in 'handler'
frame = thread.GetFrameAtIndex(0)
self.assertEqual(frame.GetDisplayFunctionName(), "handler", "Unexpected break?")

# Expect that unwinding should find 'abort_caller'
foundFoo = False
for frame in thread:
if frame.GetDisplayFunctionName() == "abort_caller":
foundFoo = True

self.assertTrue(foundFoo, "Unwinding did not find func that called abort")

# Continue until we exit.
process.Continue()
self.assertEqual(process.GetState(), lldb.eStateExited)
self.assertEqual(process.GetExitStatus(), 0)
@@ -0,0 +1,25 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

void handler(int sig)
{
printf("Set a breakpoint here.\n");
exit(0);
}

void abort_caller() {
abort();
}

int main()
{
if (signal(SIGABRT, handler) == SIG_ERR)
{
perror("signal");
return 1;
}

abort_caller();
return 2;
}
@@ -1846,6 +1846,7 @@ bool ABIMacOSX_arm::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("arm-apple-ios default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);

return true;
}
@@ -2011,6 +2011,7 @@ bool ABIMacOSX_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("arm64-apple-darwin default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}

@@ -1055,6 +1055,7 @@ bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("i386 default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}

@@ -1960,6 +1960,7 @@ bool ABISysV_arm::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("arm default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);

return true;
}
@@ -1958,6 +1958,7 @@ bool ABISysV_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("arm64 at-func-entry default");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);

return true;
}
@@ -1982,6 +1983,7 @@ bool ABISysV_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("arm64 default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);

return true;
}
@@ -1247,6 +1247,7 @@ bool ABISysV_hexagon::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("hexagon default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}

@@ -785,6 +785,7 @@ bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("i386 default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}

@@ -997,6 +997,7 @@ bool ABISysV_mips::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("mips default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}

@@ -1168,6 +1168,7 @@ bool ABISysV_mips64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("mips64 default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}

@@ -910,6 +910,7 @@ bool ABISysV_ppc::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("ppc default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(dwarf_lr);
return true;
}
@@ -1017,6 +1017,7 @@ bool ABISysV_ppc64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("ppc64 default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(pc_reg_num);
return true;
}
@@ -1034,6 +1034,7 @@ bool ABISysV_x86_64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("x86_64 default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}

@@ -14507,6 +14507,7 @@ bool EmulateInstructionARM::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) {
unwind_plan.SetSourceName("EmulateInstructionARM");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(dwarf_lr);
return true;
}
@@ -479,6 +479,7 @@ bool EmulateInstructionARM64::CreateFunctionEntryUnwind(
unwind_plan.SetSourceName("EmulateInstructionARM64");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(gpr_lr_arm64);
return true;
}
@@ -1150,6 +1150,7 @@ bool EmulateInstructionMIPS::CreateFunctionEntryUnwind(
unwind_plan.SetSourceName("EmulateInstructionMIPS");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(dwarf_ra_mips);

return true;
@@ -1042,6 +1042,7 @@ bool EmulateInstructionMIPS64::CreateFunctionEntryUnwind(
unwind_plan.SetSourceName("EmulateInstructionMIPS64");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(dwarf_ra_mips64);

return true;
@@ -135,6 +135,7 @@ bool EmulateInstructionPPC64::CreateFunctionEntryUnwind(
unwind_plan.SetSourceName("EmulateInstructionPPC64");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(gpr_lr_ppc64le);
return true;
}
@@ -396,6 +396,8 @@ PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,

void PlatformLinux::CalculateTrapHandlerSymbolNames() {
m_trap_handlers.push_back(ConstString("_sigtramp"));
m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn"));
m_trap_handlers.push_back(ConstString("__restore_rt"));
}

MmapArgList PlatformLinux::GetMmapArgumentList(const ArchSpec &arch,
@@ -472,20 +472,30 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
m_sym_ctx_valid = false;
}

bool decr_pc_and_recompute_addr_range = false;
bool decr_pc_and_recompute_addr_range;

// If the symbol lookup failed...
if (!m_sym_ctx_valid)
if (!m_sym_ctx_valid) {
// Always decrement and recompute if the symbol lookup failed
decr_pc_and_recompute_addr_range = true;

// Or if we're in the middle of the stack (and not "above" an asynchronous
// event like sigtramp), and our "current" pc is the start of a function...
if (GetNextFrame()->m_frame_type != eTrapHandlerFrame &&
GetNextFrame()->m_frame_type != eDebuggerFrame &&
(!m_sym_ctx_valid ||
(addr_range.GetBaseAddress().IsValid() &&
addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() &&
addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()))) {
} else if (GetNextFrame()->m_frame_type == eTrapHandlerFrame ||
GetNextFrame()->m_frame_type == eDebuggerFrame) {
// Don't decrement if we're "above" an asynchronous event like
// sigtramp.
decr_pc_and_recompute_addr_range = false;
} else if (!addr_range.GetBaseAddress().IsValid() ||
addr_range.GetBaseAddress().GetSection() != m_current_pc.GetSection() ||
addr_range.GetBaseAddress().GetOffset() != m_current_pc.GetOffset()) {
// If our "current" pc isn't the start of a function, no need
// to decrement and recompute.
decr_pc_and_recompute_addr_range = false;
} else if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
// Signal dispatch may set the return address of the handler it calls to
// point to the first byte of a return trampoline (like __kernel_rt_sigreturn),
// so do not decrement and recompute if the symbol we already found is a trap
// handler.
decr_pc_and_recompute_addr_range = false;
} else {
// Decrement to find the function containing the call.
decr_pc_and_recompute_addr_range = true;
}

@@ -495,6 +495,7 @@ SymbolFileBreakpad::GetUnwindPlan(const Address &address,
auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
plan_sp->SetSourceName("breakpad STACK CFI");
plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
plan_sp->SetPlanValidAddressRange(
AddressRange(base + init_record->Address, *init_record->Size,
@@ -1328,6 +1328,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
unwind_plan.SetSourceName("assembly insn profiling");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);

return true;
}
@@ -344,6 +344,7 @@ bool ArmUnwindInfo::GetUnwindPlan(Target &target, const Address &addr,
unwind_plan.SetSourceName("ARM.exidx unwind info");
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindDWARF);

return true;
@@ -737,6 +737,7 @@ bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
unwind_plan.SetSourceName("compact unwind info");
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindEHFrame);

unwind_plan.SetLSDAAddress(function_info.lsda_address);
@@ -1008,6 +1009,7 @@ bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
unwind_plan.SetSourceName("compact unwind info");
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindEHFrame);

unwind_plan.SetLSDAAddress(function_info.lsda_address);
@@ -1304,6 +1306,7 @@ bool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
unwind_plan.SetSourceName("compact unwind info");
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindEHFrame);

unwind_plan.SetLSDAAddress(function_info.lsda_address);
@@ -1437,6 +1440,7 @@ bool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
unwind_plan.SetSourceName("compact unwind info");
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindEHFrame);

unwind_plan.SetLSDAAddress(function_info.lsda_address);

0 comments on commit 3fd917d

Please sign in to comment.
You can’t perform that action at this time.