diff --git a/lldb/test/API/macosx/builtin-debugtrap/Makefile b/lldb/test/API/macosx/builtin-debugtrap/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/macosx/builtin-debugtrap/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/macosx/builtin-debugtrap/TestBuiltinDebugTrap.py b/lldb/test/API/macosx/builtin-debugtrap/TestBuiltinDebugTrap.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/macosx/builtin-debugtrap/TestBuiltinDebugTrap.py @@ -0,0 +1,70 @@ +""" +Test that lldb can continue past a __builtin_debugtrap, but not a __builtin_trap +""" + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + +class BuiltinDebugTrapTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + # Currently this depends on behavior in debugserver to + # advance the pc past __builtin_trap instructions so that + # continue works. Everyone is in agreement that this + # should be moved up into lldb instead of depending on the + # remote stub rewriting the pc values. + @skipUnlessDarwin + + def test(self): + self.build() + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "// Set a breakpoint here", lldb.SBFileSpec("main.cpp")) + + # Continue to __builtin_debugtrap() + process.Continue() + if self.TraceOn(): + self.runCmd("f") + self.runCmd("bt") + self.runCmd("ta v global") + + self.assertEqual(process.GetSelectedThread().GetStopReason(), + lldb.eStopReasonException) + + list = target.FindGlobalVariables("global", 1, lldb.eMatchTypeNormal) + self.assertEqual(list.GetSize(), 1) + global_value = list.GetValueAtIndex(0) + + self.assertEqual(global_value.GetValueAsUnsigned(), 5) + + # Continue to the __builtin_trap() -- we should be able to + # continue past __builtin_debugtrap. + process.Continue() + if self.TraceOn(): + self.runCmd("f") + self.runCmd("bt") + self.runCmd("ta v global") + + self.assertEqual(process.GetSelectedThread().GetStopReason(), + lldb.eStopReasonException) + + # "global" is now 10. + self.assertEqual(global_value.GetValueAsUnsigned(), 10) + + # We should be at the same point as before -- cannot advance + # past a __builtin_trap(). + process.Continue() + if self.TraceOn(): + self.runCmd("f") + self.runCmd("bt") + self.runCmd("ta v global") + + self.assertEqual(process.GetSelectedThread().GetStopReason(), + lldb.eStopReasonException) + + # "global" is still 10. + self.assertEqual(global_value.GetValueAsUnsigned(), 10) diff --git a/lldb/test/API/macosx/builtin-debugtrap/main.cpp b/lldb/test/API/macosx/builtin-debugtrap/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/macosx/builtin-debugtrap/main.cpp @@ -0,0 +1,11 @@ +#include +int global = 0; +int main() +{ + global = 5; // Set a breakpoint here + __builtin_debugtrap(); + global = 10; + __builtin_trap(); + global = 15; + return global; +} diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp --- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp @@ -524,6 +524,28 @@ return true; } + // detect a __builtin_debugtrap instruction pattern ("brk #0xf000") + // and advance the $pc past it, so that the user can continue execution. + // Generally speaking, this knowledge should be centralized in lldb, + // recognizing the builtin_trap instruction and knowing how to advance + // the pc past it, so that continue etc work. + if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_BREAKPOINT) { + nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS); + if (pc != INVALID_NUB_ADDRESS && pc > 0) { + DNBBreakpoint *bp = + m_thread->Process()->Breakpoints().FindByAddress(pc); + if (bp == nullptr) { + uint8_t insnbuf[4]; + if (m_thread->Process()->ReadMemory(pc, 4, insnbuf) == 4) { + uint8_t builtin_debugtrap_insn[4] = {0x00, 0x00, 0x3e, + 0xd4}; // brk #0xf000 + if (memcmp(insnbuf, builtin_debugtrap_insn, 4) == 0) { + SetPC(pc + 4); + } + } + } + } + } break; } return false;