[Lldb-commits] [lldb] 92b036d - debugserver should advance pc past builtin_debugtrap insn
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Thu Nov 12 23:31:25 PST 2020
Author: Jason Molenda
Date: 2020-11-12T23:31:14-08:00
New Revision: 92b036dea24b6e7ebfd950facdbf5543135eda05
URL: https://github.com/llvm/llvm-project/commit/92b036dea24b6e7ebfd950facdbf5543135eda05
DIFF: https://github.com/llvm/llvm-project/commit/92b036dea24b6e7ebfd950facdbf5543135eda05.diff
LOG: debugserver should advance pc past builtin_debugtrap insn
On x86_64, when you hit a __builtin_debugtrap instruction, you
can continue past this in the debugger. This patch has debugserver
recognize the specific instruction used for __builtin_debugtrap
and advance the pc past it, so that the user can continue execution
once they've hit one of these.
In the patch discussion, we were in agreement that it would be better
to have this knowledge up in lldb instead of depending on each
stub rewriting the pc behind the debugger's back, but that's a
larger scale change for another day.
<rdar://problem/65521634>
Differential revision: https://reviews.llvm.org/D91238
Added:
lldb/test/API/macosx/builtin-debugtrap/Makefile
lldb/test/API/macosx/builtin-debugtrap/TestBuiltinDebugTrap.py
lldb/test/API/macosx/builtin-debugtrap/main.cpp
Modified:
lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
Removed:
################################################################################
diff --git a/lldb/test/API/macosx/builtin-debugtrap/Makefile b/lldb/test/API/macosx/builtin-debugtrap/Makefile
new file mode 100644
index 000000000000..99998b20bcb0
--- /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
index 000000000000..d645da460df4
--- /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
index 000000000000..2cbe2a48b503
--- /dev/null
+++ b/lldb/test/API/macosx/builtin-debugtrap/main.cpp
@@ -0,0 +1,11 @@
+#include <stdio.h>
+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
index 7e1af7a75021..ab1623ba4217 100644
--- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
@@ -524,6 +524,28 @@ bool DNBArchMachARM64::NotifyException(MachException::Data &exc) {
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;
More information about the lldb-commits
mailing list