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
This commit is contained in:
Joseph Tremoulet 2019-07-19 14:05:55 +00:00
parent 9e6a42a185
commit 3fd917d886
28 changed files with 169 additions and 12 deletions

View File

@ -370,6 +370,7 @@ public:
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 @@ public:
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 @@ public:
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 @@ private:
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

View File

@ -0,0 +1,5 @@
LEVEL = ../../../make
C_SOURCES := main.c
include $(LEVEL)/Makefile.rules

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -19,6 +19,7 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Timer.h"
#include <list>
#include <cstring>
using namespace lldb;
using namespace lldb_private;
@ -601,6 +602,9 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
}
offset += aug_data_len;
}
unwind_plan.SetUnwindPlanForSignalTrap(
strchr(cie->augmentation, 'S') ? eLazyBoolYes : eLazyBoolNo);
Address lsda_data;
Address personality_function_ptr;