summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp54
-rw-r--r--lldb/source/Target/StackFrame.cpp24
-rw-r--r--lldb/test/functionalities/unwind/noreturn/Makefile7
-rw-r--r--lldb/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py87
-rw-r--r--lldb/test/functionalities/unwind/noreturn/main.c37
5 files changed, 200 insertions, 9 deletions
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index 61f3400091b..9e24f24f6e9 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 760d3b2f1d6..c46db4cfadf 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 00000000000..ede25f029bc
--- /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 00000000000..28012795ab2
--- /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 00000000000..7190e38f5d8
--- /dev/null
+++ b/lldb/test/functionalities/unwind/noreturn/main.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+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;
+}
OpenPOWER on IntegriCloud