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
This commit is contained in:
1 parent
dabc914d2b
commit
92b036dea2
4 files changed
+106
No files matched your search
@@ -0,0 +1,3 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user