summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2015-01-10 04:01:03 +0000
committerJason Molenda <jmolenda@apple.com>2015-01-10 04:01:03 +0000
commitb0401736fcfdaaf719b19eea861a30333a2173a6 (patch)
tree77766b8b60211b2dc2502f9746223c7e1d52ae8c
parentb9ea4231615ec1b1849cea54de62113315af169d (diff)
Hoist the RegisterNumber class out of RegisterContextLLDB and make
it more generally available. Add checks to UnwindAssembly_x86::AugmentUnwindPlanFromCallSite() so that it won't try to augment an UnwindPlan that already describes the function epilogue. Add a test case for backtracing out of _sigtramp on Darwin systems. This could probably be adapted to test the same thing on linux/bsd but the function names of sigtramp and kill are probably platform specific and I'm not sure what they should be. git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@225578 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lldb.xcodeproj/project.pbxproj4
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.h160
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp71
-rw-r--r--source/Utility/RegisterNumber.cpp151
-rw-r--r--test/functionalities/unwind/sigtramp/Makefile5
-rw-r--r--test/functionalities/unwind/sigtramp/TestSigtrampUnwind.py94
-rw-r--r--test/functionalities/unwind/sigtramp/main.c27
7 files changed, 350 insertions, 162 deletions
diff --git a/lldb.xcodeproj/project.pbxproj b/lldb.xcodeproj/project.pbxproj
index 3f851ba3d..e637d5025 100644
--- a/lldb.xcodeproj/project.pbxproj
+++ b/lldb.xcodeproj/project.pbxproj
@@ -745,6 +745,7 @@
AF1729D7182C907200E0AB97 /* HistoryUnwind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF1729D5182C907200E0AB97 /* HistoryUnwind.cpp */; };
AF1F7B07189C904B0087DB9C /* AppleGetPendingItemsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF1F7B05189C904B0087DB9C /* AppleGetPendingItemsHandler.cpp */; };
AF1F7B08189C904B0087DB9C /* AppleGetPendingItemsHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1F7B06189C904B0087DB9C /* AppleGetPendingItemsHandler.h */; };
+ AF1FA88A1A60A69500272AFC /* RegisterNumber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF1FA8891A60A69500272AFC /* RegisterNumber.cpp */; };
AF23B4DB19009C66003E2A58 /* FreeBSDSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF23B4D919009C66003E2A58 /* FreeBSDSignals.cpp */; };
AF254E31170CCC33007AE5C9 /* PlatformDarwinKernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF254E2F170CCC33007AE5C9 /* PlatformDarwinKernel.cpp */; };
AF254E32170CCC33007AE5C9 /* PlatformDarwinKernel.h in Headers */ = {isa = PBXBuildFile; fileRef = AF254E30170CCC33007AE5C9 /* PlatformDarwinKernel.h */; };
@@ -2200,6 +2201,7 @@
AF1729D5182C907200E0AB97 /* HistoryUnwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HistoryUnwind.cpp; path = Utility/HistoryUnwind.cpp; sourceTree = "<group>"; };
AF1F7B05189C904B0087DB9C /* AppleGetPendingItemsHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleGetPendingItemsHandler.cpp; sourceTree = "<group>"; };
AF1F7B06189C904B0087DB9C /* AppleGetPendingItemsHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleGetPendingItemsHandler.h; sourceTree = "<group>"; };
+ AF1FA8891A60A69500272AFC /* RegisterNumber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterNumber.cpp; path = source/Utility/RegisterNumber.cpp; sourceTree = "<group>"; };
AF23B4D919009C66003E2A58 /* FreeBSDSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FreeBSDSignals.cpp; path = Utility/FreeBSDSignals.cpp; sourceTree = "<group>"; };
AF23B4DA19009C66003E2A58 /* FreeBSDSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FreeBSDSignals.h; path = Utility/FreeBSDSignals.h; sourceTree = "<group>"; };
AF254E2F170CCC33007AE5C9 /* PlatformDarwinKernel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformDarwinKernel.cpp; sourceTree = "<group>"; };
@@ -3069,6 +3071,7 @@
94EBAC8313D9EE26009BA64E /* PythonPointer.h */,
94BA8B6E176F8CA0005A91B5 /* Range.h */,
94BA8B6C176F8C9B005A91B5 /* Range.cpp */,
+ AF1FA8891A60A69500272AFC /* RegisterNumber.cpp */,
B2462249141AE62200F3D409 /* Utils.h */,
);
name = Utility;
@@ -5568,6 +5571,7 @@
94F48F251A01C687005C0EC6 /* StringPrinter.cpp in Sources */,
94094C6B163B6F840083A547 /* ValueObjectCast.cpp in Sources */,
AF9107EF168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp in Sources */,
+ AF1FA88A1A60A69500272AFC /* RegisterNumber.cpp in Sources */,
94CB255B16B069770059775D /* CXXFormatterFunctions.cpp in Sources */,
94CB255C16B069770059775D /* DataVisualization.cpp in Sources */,
94CD705016F8DF1C00CF1E42 /* LibCxxList.cpp in Sources */,
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h
index 636e95240..5f94a9774 100644
--- a/source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -16,6 +16,7 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/RegisterNumber.h"
#include "UnwindLLDB.h"
namespace lldb_private {
@@ -86,165 +87,6 @@ public:
private:
- //--------------------------------------------------------------------
- /// A convenience class for RegisterContextLLDB which can convert between
- /// different register kinds.
- ///
- /// This ends up being a common operation in RegisterContextLLDB as we try
- /// to bridge between the different register numbering systems -- having a
- /// simple object to enclose all of that conversion, and cache results so
- /// we don't re-fetch, simplifies the code significantly.
- //--------------------------------------------------------------------
- class RegisterNumber {
- public:
- RegisterNumber (lldb_private::Thread &thread, lldb::RegisterKind kind, uint32_t num) :
- m_reg_ctx_sp (thread.GetRegisterContext()),
- m_regnum (num),
- m_kind (kind),
- m_kind_regnum_map (),
- m_name ("")
- {
- if (m_reg_ctx_sp.get())
- {
- const lldb_private::RegisterInfo *reginfo = m_reg_ctx_sp->GetRegisterInfoAtIndex (GetAsKind (lldb::eRegisterKindLLDB));
- if (reginfo && reginfo->name)
- {
- m_name = reginfo->name;
- }
- }
- }
-
- // This constructor plus the init() method below allow for the placeholder
- // creation of an invalid object initially, possibly to be filled in. It
- // would be more consistent to have three Set* methods to set the three
- // data that the object needs.
- RegisterNumber () :
- m_reg_ctx_sp(),
- m_regnum (LLDB_INVALID_REGNUM),
- m_kind (lldb::kNumRegisterKinds),
- m_kind_regnum_map (),
- m_name (nullptr)
- {
- }
-
- void
- init (lldb_private::Thread &thread, lldb::RegisterKind kind, uint32_t num)
- {
- m_reg_ctx_sp = thread.GetRegisterContext();
- m_regnum = num;
- m_kind = kind;
- if (m_reg_ctx_sp.get())
- {
- const lldb_private::RegisterInfo *reginfo = m_reg_ctx_sp->GetRegisterInfoAtIndex (GetAsKind (lldb::eRegisterKindLLDB));
- if (reginfo && reginfo->name)
- {
- m_name = reginfo->name;
- }
- }
- }
-
- const RegisterNumber &
- operator = (const RegisterNumber &rhs)
- {
- m_reg_ctx_sp = rhs.m_reg_ctx_sp;
- m_regnum = rhs.m_regnum;
- m_kind = rhs.m_kind;
- for (auto it : rhs.m_kind_regnum_map)
- m_kind_regnum_map[it.first] = it.second;
- m_name = rhs.m_name;
- return *this;
- }
-
- bool
- operator == (RegisterNumber &rhs)
- {
- if (IsValid() != rhs.IsValid())
- return false;
-
- if (m_kind == rhs.m_kind)
- {
- if (m_regnum == rhs.m_regnum)
- return true;
- else
- return false;
- }
-
- uint32_t rhs_regnum = rhs.GetAsKind (m_kind);
- if (rhs_regnum != LLDB_INVALID_REGNUM)
- {
- if (m_regnum == rhs_regnum)
- return true;
- else
- return false;
- }
- uint32_t lhs_regnum = GetAsKind (rhs.m_kind);
- {
- if (lhs_regnum == rhs.m_regnum)
- return true;
- else
- return false;
- }
- return false;
- }
-
- bool
- IsValid () const
- {
- return m_regnum != LLDB_INVALID_REGNUM;
- }
-
- uint32_t
- GetAsKind (lldb::RegisterKind kind)
- {
- if (m_regnum == LLDB_INVALID_REGNUM)
- return LLDB_INVALID_REGNUM;
-
- if (kind == m_kind)
- return m_regnum;
-
- Collection::iterator iter = m_kind_regnum_map.find (kind);
- if (iter != m_kind_regnum_map.end())
- {
- return iter->second;
- }
- uint32_t output_regnum = LLDB_INVALID_REGNUM;
- if (m_reg_ctx_sp
- && m_reg_ctx_sp->ConvertBetweenRegisterKinds (m_kind, m_regnum, kind, output_regnum)
- && output_regnum != LLDB_INVALID_REGNUM)
- {
- m_kind_regnum_map[kind] = output_regnum;
- }
- return output_regnum;
- }
-
- uint32_t
- GetRegisterNumber () const
- {
- return m_regnum;
- }
-
- lldb::RegisterKind
- GetRegisterKind () const
- {
- return m_kind;
- }
-
- const char *
- GetName ()
- {
- return m_name;
- }
-
- private:
- typedef std::map<lldb::RegisterKind, uint32_t> Collection;
-
- lldb::RegisterContextSP m_reg_ctx_sp;
- uint32_t m_regnum;
- lldb::RegisterKind m_kind;
- Collection m_kind_regnum_map;
- const char *m_name;
- };
-
enum FrameType
{
eNormalFrame,
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index 730784bb2..af70858e5 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -23,6 +23,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnwindAssembly.h"
+#include "lldb/Utility/RegisterNumber.h"
using namespace lldb;
using namespace lldb_private;
@@ -955,7 +956,9 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
// If we already have one row for this instruction, we can continue.
while (row_id < unwind_plan.GetRowCount()
&& unwind_plan.GetRowAtIndex (row_id)->GetOffset() <= offset)
+ {
row_id++;
+ }
UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex (row_id - 1);
if (original_row->GetOffset() == offset)
{
@@ -1262,9 +1265,71 @@ UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Th
bool
UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
{
- ExecutionContext exe_ctx (thread.shared_from_this());
- AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
- return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
+ bool do_augment_unwindplan = true;
+
+ UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset (0);
+ UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset (-1);
+
+ // If the UnwindPlan correctly describes the prologue and the epilogue, then
+ // we shouldn't do any augmentation (and risk messing up correct unwind instructions)
+
+ // See if the first row (which should be the register state on function entry)
+ // and the last row (which should be the register state on function exit) match.
+
+ if (first_row != last_row && first_row->GetOffset() != last_row->GetOffset())
+ {
+ RegisterNumber sp_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // The first & last row have the same CFA register
+ // and the same CFA offset value
+ // and the CFA register is esp/rsp (the stack pointer).
+
+ // We're checking that both of them have an unwind rule like "CFA=esp+4" or CFA+rsp+8".
+
+ if (first_row->GetCFAType() == last_row->GetCFAType()
+ && first_row->GetCFAType() == UnwindPlan::Row::CFAType::CFAIsRegisterPlusOffset
+ && first_row->GetCFARegister() == last_row->GetCFARegister()
+ && first_row->GetCFAOffset() == last_row->GetCFAOffset()
+ && RegisterNumber (thread, unwind_plan.GetRegisterKind(), first_row->GetCFARegister()) == sp_regnum)
+ {
+ RegisterNumber pc_regnum (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+
+ // Get the register locations for eip/rip from the first & last rows.
+ // Are they both CFA plus an offset? Is it the same offset?
+
+ UnwindPlan::Row::RegisterLocation first_row_pc_loc;
+ UnwindPlan::Row::RegisterLocation last_row_pc_loc;
+ if (first_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), first_row_pc_loc)
+ && last_row->GetRegisterInfo (pc_regnum.GetAsKind (unwind_plan.GetRegisterKind()), last_row_pc_loc))
+ {
+ if (first_row_pc_loc.IsAtCFAPlusOffset()
+ && last_row_pc_loc.IsAtCFAPlusOffset()
+ && first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset())
+ {
+
+ // One last sanity check: Is the unwind rule for getting the caller pc value
+ // "deref the CFA-4" or "deref the CFA-8"?
+
+ // If so, we have an UnwindPlan that already describes the epilogue and we don't need
+ // to modify it at all.
+
+ if (first_row_pc_loc.GetOffset() == -4 || first_row_pc_loc.GetOffset() == -8)
+ {
+ do_augment_unwindplan = false;
+ }
+ }
+ }
+ }
+ }
+
+ if (do_augment_unwindplan)
+ {
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
+ }
+
+ return false;
}
bool
diff --git a/source/Utility/RegisterNumber.cpp b/source/Utility/RegisterNumber.cpp
new file mode 100644
index 000000000..ba9afed47
--- /dev/null
+++ b/source/Utility/RegisterNumber.cpp
@@ -0,0 +1,151 @@
+//===--------------------- RegisterNumber.cpp -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/RegisterNumber.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb_private;
+
+
+RegisterNumber::RegisterNumber (lldb_private::Thread &thread, lldb::RegisterKind kind, uint32_t num) :
+ m_reg_ctx_sp (thread.GetRegisterContext()),
+ m_regnum (num),
+ m_kind (kind),
+ m_kind_regnum_map (),
+ m_name ("")
+{
+ if (m_reg_ctx_sp.get())
+ {
+ const lldb_private::RegisterInfo *reginfo = m_reg_ctx_sp->GetRegisterInfoAtIndex (GetAsKind (lldb::eRegisterKindLLDB));
+ if (reginfo && reginfo->name)
+ {
+ m_name = reginfo->name;
+ }
+ }
+}
+
+RegisterNumber::RegisterNumber () :
+ m_reg_ctx_sp(),
+ m_regnum (LLDB_INVALID_REGNUM),
+ m_kind (lldb::kNumRegisterKinds),
+ m_kind_regnum_map (),
+ m_name (nullptr)
+{
+}
+
+void
+RegisterNumber::init (lldb_private::Thread &thread, lldb::RegisterKind kind, uint32_t num)
+{
+ m_reg_ctx_sp = thread.GetRegisterContext();
+ m_regnum = num;
+ m_kind = kind;
+ if (m_reg_ctx_sp.get())
+ {
+ const lldb_private::RegisterInfo *reginfo = m_reg_ctx_sp->GetRegisterInfoAtIndex (GetAsKind (lldb::eRegisterKindLLDB));
+ if (reginfo && reginfo->name)
+ {
+ m_name = reginfo->name;
+ }
+ }
+}
+
+const RegisterNumber &
+RegisterNumber::operator = (const RegisterNumber &rhs)
+{
+ m_reg_ctx_sp = rhs.m_reg_ctx_sp;
+ m_regnum = rhs.m_regnum;
+ m_kind = rhs.m_kind;
+ for (auto it : rhs.m_kind_regnum_map)
+ m_kind_regnum_map[it.first] = it.second;
+ m_name = rhs.m_name;
+ return *this;
+}
+
+bool
+RegisterNumber::operator == (RegisterNumber &rhs)
+{
+ if (IsValid() != rhs.IsValid())
+ return false;
+
+ if (m_kind == rhs.m_kind)
+ {
+ if (m_regnum == rhs.m_regnum)
+ return true;
+ else
+ return false;
+ }
+
+ uint32_t rhs_regnum = rhs.GetAsKind (m_kind);
+ if (rhs_regnum != LLDB_INVALID_REGNUM)
+ {
+ if (m_regnum == rhs_regnum)
+ return true;
+ else
+ return false;
+ }
+ uint32_t lhs_regnum = GetAsKind (rhs.m_kind);
+ {
+ if (lhs_regnum == rhs.m_regnum)
+ return true;
+ else
+ return false;
+ }
+ return false;
+}
+
+bool
+RegisterNumber::IsValid () const
+{
+ return m_reg_ctx_sp.get()
+ && m_kind != lldb::kNumRegisterKinds
+ && m_regnum != LLDB_INVALID_REGNUM;
+}
+
+uint32_t
+RegisterNumber::GetAsKind (lldb::RegisterKind kind)
+{
+ if (m_regnum == LLDB_INVALID_REGNUM)
+ return LLDB_INVALID_REGNUM;
+
+ if (kind == m_kind)
+ return m_regnum;
+
+ Collection::iterator iter = m_kind_regnum_map.find (kind);
+ if (iter != m_kind_regnum_map.end())
+ {
+ return iter->second;
+ }
+ uint32_t output_regnum = LLDB_INVALID_REGNUM;
+ if (m_reg_ctx_sp
+ && m_reg_ctx_sp->ConvertBetweenRegisterKinds (m_kind, m_regnum, kind, output_regnum)
+ && output_regnum != LLDB_INVALID_REGNUM)
+ {
+ m_kind_regnum_map[kind] = output_regnum;
+ }
+ return output_regnum;
+}
+
+uint32_t
+RegisterNumber::GetRegisterNumber () const
+{
+ return m_regnum;
+}
+
+lldb::RegisterKind
+RegisterNumber::GetRegisterKind () const
+{
+ return m_kind;
+}
+
+const char *
+RegisterNumber::GetName ()
+{
+ return m_name;
+}
diff --git a/test/functionalities/unwind/sigtramp/Makefile b/test/functionalities/unwind/sigtramp/Makefile
new file mode 100644
index 000000000..b09a57915
--- /dev/null
+++ b/test/functionalities/unwind/sigtramp/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/test/functionalities/unwind/sigtramp/TestSigtrampUnwind.py b/test/functionalities/unwind/sigtramp/TestSigtrampUnwind.py
new file mode 100644
index 000000000..09eeddf30
--- /dev/null
+++ b/test/functionalities/unwind/sigtramp/TestSigtrampUnwind.py
@@ -0,0 +1,94 @@
+"""
+Test that we can backtrace correctly with 'sigtramp' functions on the stack
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class SigtrampUnwind(TestBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ # On different platforms the "_sigtramp" and "__kill" frames are likely to be different.
+ # This test could probably be adapted to run on linux/*bsd easily enough.
+ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+ @dsym_test
+ def test_with_dsym (self):
+ """Test that we can backtrace correctly with _sigtramp on the stack"""
+ self.buildDsym()
+ self.setTearDownCleanup()
+ self.sigtramp_unwind_tests()
+
+ @dwarf_test
+ def test_with_dwarf (self):
+ """Test that we can backtrace correctly with _sigtramp on the stack"""
+ self.buildDwarf()
+ self.setTearDownCleanup()
+ self.sigtramp_unwind_tests()
+
+ def sigtramp_unwind_tests (self):
+ exe = os.path.join(os.getcwd(), "a.out")
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+
+ lldbutil.run_break_set_by_file_and_line (self, "main.c", line_number('main.c', '// Set breakpoint here'), num_expected_locations=1)
+
+ 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()))
+
+ self.expect("pro handle -n false -p true -s false SIGUSR1", "Have lldb pass SIGUSR1 signals",
+ substrs = ["SIGUSR1", "true", "false", "false"])
+
+ lldbutil.run_break_set_by_symbol (self, "handler", num_expected_locations=1, module_name="a.out")
+
+ self.runCmd("continue")
+
+ thread = process.GetThreadAtIndex(0)
+
+ found_handler = False
+ found_sigtramp = False
+ found_kill = False
+ found_main = False
+
+ for f in thread.frames:
+ if f.GetFunctionName() == "handler":
+ found_handler = True
+ if f.GetFunctionName() == "_sigtramp":
+ found_sigtramp = True
+ if f.GetFunctionName() == "__kill":
+ found_kill = True
+ if f.GetFunctionName() == "main":
+ found_main = True
+
+ if self.TraceOn():
+ print "Backtrace once we're stopped:"
+ for f in thread.frames:
+ print " %d %s" % (f.GetFrameID(), f.GetFunctionName())
+
+ if found_handler == False:
+ self.fail("Unable to find handler() in backtrace.")
+
+ if found_sigtramp == False:
+ self.fail("Unable to find _sigtramp() in backtrace.")
+
+ if found_kill == False:
+ self.fail("Unable to find kill() in backtrace.")
+
+ if found_main == False:
+ self.fail("Unable to find main() in backtrace.")
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/test/functionalities/unwind/sigtramp/main.c b/test/functionalities/unwind/sigtramp/main.c
new file mode 100644
index 000000000..aaa03e7aa
--- /dev/null
+++ b/test/functionalities/unwind/sigtramp/main.c
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void handler (int in)
+{
+ puts ("in handler routine");
+ while (1)
+ ;
+}
+
+void
+foo ()
+{
+ puts ("in foo ()");
+ kill (getpid(), SIGUSR1);
+}
+int main ()
+{
+ puts ("in main"); // Set breakpoint here
+ signal (SIGUSR1, handler);
+ puts ("signal handler set up");
+ foo();
+ puts ("exiting");
+ return 0;
+}