diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 61f3400091b3..9e24f24f6e94 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -172,6 +172,21 @@ RegisterContextLLDB::InitializeZerothFrame() m_sym_ctx_valid = true; } + if (m_sym_ctx.symbol) + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'", + current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + } + else if (m_sym_ctx.function) + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'", + current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString()); + } + else + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", current_pc); + } + AddressRange addr_range; m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range); @@ -294,12 +309,12 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (log) { - UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc); + UnwindLogMsg ("pc = 0x%" PRIx64, pc); addr_t reg_val; if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) - UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val); + UnwindLogMsg ("fp = 0x%" PRIx64, reg_val); if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) - UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val); + UnwindLogMsg ("sp = 0x%" PRIx64, reg_val); } // A pc of 0x0 means it's the end of the stack crawl @@ -442,6 +457,21 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_sym_ctx_valid = true; } + if (m_sym_ctx.symbol) + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'", + pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + } + else if (m_sym_ctx.function) + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'", + pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString()); + } + else + { + UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", pc); + } + AddressRange addr_range; if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) { @@ -472,17 +502,21 @@ RegisterContextLLDB::InitializeNonZerothFrame() // to the ABI plugin and consult that. if (decr_pc_and_recompute_addr_range) { - Address temporary_pc(m_current_pc); - temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); - m_sym_ctx.Clear(false); + UnwindLogMsg ("Backing up the pc value of 0x%" PRIx64 " by 1 and re-doing symbol lookup; old symbol was %s", + pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + Address temporary_pc; + temporary_pc.SetLoadAddress (pc - 1, &process->GetTarget()); + m_sym_ctx.Clear (false); m_sym_ctx_valid = false; uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; - if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope) + ModuleSP temporary_module_sp = temporary_pc.GetModule(); + if (temporary_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope) { if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) m_sym_ctx_valid = true; } + UnwindLogMsg ("Symbol is now %s", m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); } // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function. @@ -490,13 +524,15 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (addr_range.GetBaseAddress().IsValid()) { m_start_pc = addr_range.GetBaseAddress(); - m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset(); + m_current_offset = pc - m_start_pc.GetLoadAddress (&process->GetTarget()); m_current_offset_backed_up_one = m_current_offset; if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0) { m_current_offset_backed_up_one--; if (m_sym_ctx_valid) - m_current_pc.SetOffset(m_current_pc.GetOffset() - 1); + { + m_current_pc.SetLoadAddress (pc - 1, &process->GetTarget()); + } } } else diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 760d3b2f1d6f..c46db4cfadf9 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -384,7 +384,31 @@ StackFrame::GetSymbolContext (uint32_t resolve_scope) { addr_t offset = lookup_addr.GetOffset(); if (offset > 0) + { lookup_addr.SetOffset(offset - 1); + + } + else + { + // lookup_addr is the start of a section. We need + // do the math on the actual load address and re-compute + // the section. We're working with a 'noreturn' function + // at the end of a section. + ThreadSP thread_sp (GetThread()); + if (thread_sp) + { + TargetSP target_sp (thread_sp->CalculateTarget()); + if (target_sp) + { + addr_t addr_minus_one = lookup_addr.GetLoadAddress(target_sp.get()) - 1; + lookup_addr.SetLoadAddress (addr_minus_one, target_sp.get()); + } + else + { + lookup_addr.SetOffset(offset - 1); + } + } + } } diff --git a/lldb/test/functionalities/unwind/noreturn/Makefile b/lldb/test/functionalities/unwind/noreturn/Makefile new file mode 100644 index 000000000000..ede25f029bcd --- /dev/null +++ b/lldb/test/functionalities/unwind/noreturn/Makefile @@ -0,0 +1,7 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +CFLAGS ?= -g -Os + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py b/lldb/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py new file mode 100644 index 000000000000..28012795ab2d --- /dev/null +++ b/lldb/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py @@ -0,0 +1,87 @@ +""" +Test that we can backtrace correctly with 'noreturn' functions on the stack +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil + +class NoreturnUnwind(TestBase): + mydir = TestBase.compute_mydir(__file__) + + @dsym_test + def test_with_dsym (self): + """Test that we can backtrace correctly with 'noreturn' functions on the stack""" + self.buildDsym() + self.setTearDownCleanup() + self.noreturn_unwind_tests() + + @dwarf_test + def test_with_dsym (self): + """Test that we can backtrace correctly with 'noreturn' functions on the stack""" + self.buildDsym() + self.setTearDownCleanup() + self.noreturn_unwind_tests() + + def noreturn_unwind_tests (self): + exe = os.path.join(os.getcwd(), "a.out") + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + process = target.LaunchSimple (None, None, self.get_process_working_directory()) + + if not process: + self.fail("SBTarget.Launch() failed") + + if process.GetState() != lldb.eStateStopped: + self.fail("Process should be in the 'stopped' state, " + "instead the actual state is: '%s'" % + lldbutil.state_type_to_str(process.GetState())) + + thread = process.GetThreadAtIndex(0) + abort_frame_number = 0 + for f in thread.frames: + if f.GetFunctionName() == "abort": + break + abort_frame_number = abort_frame_number + 1 + + if self.TraceOn(): + print "Backtrace once we're stopped:" + for f in thread.frames: + print " %d %s" % (f.GetFrameID(), f.GetFunctionName()) + + # I'm going to assume that abort() ends up calling/invoking another + # function before halting the process. In which case if abort_frame_number + # equals 0, we didn't find abort() in the backtrace. + if abort_frame_number == 0: + self.fail("Unable to find abort() in backtrace.") + + func_c_frame_number = abort_frame_number + 1 + if thread.GetFrameAtIndex (func_c_frame_number).GetFunctionName() != "func_c": + self.fail("Did not find func_c() above abort().") + + # This depends on whether we see the func_b inlined function in the backtrace + # or not. I'm not interested in testing that aspect of the backtrace here + # right now. + + if thread.GetFrameAtIndex (func_c_frame_number + 1).GetFunctionName() == "func_b": + func_a_frame_number = func_c_frame_number + 2 + else: + func_a_frame_number = func_c_frame_number + 1 + + if thread.GetFrameAtIndex (func_a_frame_number).GetFunctionName() != "func_a": + self.fail("Did not find func_a() above func_c().") + + main_frame_number = func_a_frame_number + 1 + + if thread.GetFrameAtIndex (main_frame_number).GetFunctionName() != "main": + self.fail("Did not find main() above func_a().") + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/unwind/noreturn/main.c b/lldb/test/functionalities/unwind/noreturn/main.c new file mode 100644 index 000000000000..7190e38f5d8c --- /dev/null +++ b/lldb/test/functionalities/unwind/noreturn/main.c @@ -0,0 +1,37 @@ +#include +#include +#include + +static void func_a (void) __attribute__((noinline)); +static void func_b (void) __attribute__((noreturn)); +static void func_c (void) __attribute__((noinline)); + +static void +func_c (void) +{ + abort (); +} + +static void +func_b (void) +{ + func_c (); + while (1) + ; +} + +static void +func_a (void) +{ + func_b (); +} + +int +main (int argc, char *argv[]) +{ + sleep (2); + + func_a (); + + return 0; +}