forked from OSchip/llvm-project
Introduce FPR and Debug Registers/NetBSD/amd64 support
Summary: This code offers Debug Registers (80386) model in LLDB/amd64. This is initial support and has one issue that will be addressed later, Debug Register trap (TRAP_DBREG) is registered as (TRAP_TRACE) for unknown reason. On the other hand this works good enough to move on and leave this bug to be squashed later. Improve the NativeProcessNetBSD::ReinitializeThreads() function, stop setting inside it SetStoppedByExec(). This fixes incorrect stop reason on attaching (SetStoppedBySignal(SIGSTOP)). This commits also has no functional style improvements from clang-format. This code also ships with FXSAVE support on NetBSD. Demo: ``` $ lldb ./watch (lldb) target create "./watch" Current executable set to './watch' (x86_64). (lldb) b main Breakpoint 1: where = watch`main + 15 at watch.c:8, address = 0x000000000040087f (lldb) r Process 1573 launched: './watch' (x86_64) Process 1573 stopped * thread #1, stop reason = breakpoint 1.1 frame #0: 0x000000000040087f watch`main(argc=1, argv=0x00007f7fffa12b88) at watch.c:8 5 { 6 int i, j, k; 7 -> 8 for (i = 0; i < 3; i++) 9 for (j = 0; j < 3; j++) 10 for (k = 0; k < 3; k++) 11 printf("Hello world! i=%d j=%d k=%d\n", i, j, k); (lldb) watch set var i Watchpoint created: Watchpoint 1: addr = 0x7f7fffa12b4c size = 4 state = enabled type = w declare @ '/public/lldb_devel/watch.c:6' watchpoint spec = 'i' new value: 0 (lldb) c Process 1573 resuming Hello world! i=0 j=0 k=0 Hello world! i=0 j=0 k=1 Hello world! i=0 j=0 k=2 Hello world! i=0 j=1 k=0 Hello world! i=0 j=1 k=1 Hello world! i=0 j=1 k=2 Hello world! i=0 j=2 k=0 Hello world! i=0 j=2 k=1 Hello world! i=0 j=2 k=2 Process 1573 stopped * thread #1, stop reason = trace frame #0: 0x00000000004008cc watch`main(argc=1, argv=0x00007f7fffa12b88) at watch.c:8 5 { 6 int i, j, k; 7 -> 8 for (i = 0; i < 3; i++) 9 for (j = 0; j < 3; j++) 10 for (k = 0; k < 3; k++) 11 printf("Hello world! i=%d j=%d k=%d\n", i, j, k) ``` FPR (in another program using libm) ``` (lldb) register read --all General Purpose Registers: rax = 0x000000000000001c rbx = 0x00007f7fff1d4fe0 rcx = 0x000000000000000c rdx = 0x0000000000000002 rdi = 0x0000746711d5b018 __sF + 152 rsi = 0x0000000000000001 rbp = 0x00007f7fff1d3d80 rsp = 0x00007f7fff1d3d60 r8 = 0x00007f7fff1d3470 r9 = 0x0000000000000000 r10 = 0x0000000000000001 r11 = 0x0000000000000202 r12 = 0x00007f7fff1d3da0 r13 = 0x00007d8ad2d88500 r14 = 0x0000000000000002 r15 = 0x00007f7fffa627e0 rip = 0x00000000004009e9 fpr`main + 217 at fpr.c:15 rflags = 0x0000000000000202 cs = 0x0000000000000047 fs = 0x0000000000000000 gs = 0x0000000000000000 ss = 0x000000000000003f ds = 0x000000000000003f es = 0x000000000000003f eax = 0x0000001c ebx = 0xff1d4fe0 ecx = 0x0000000c edx = 0x00000002 edi = 0x11d5b018 esi = 0x00000001 ebp = 0xff1d3d80 esp = 0xff1d3d60 r8d = 0xff1d3470 r9d = 0x00000000 r10d = 0x00000001 r11d = 0x00000202 r12d = 0xff1d3da0 r13d = 0xd2d88500 r14d = 0x00000002 r15d = 0xffa627e0 ax = 0x001c bx = 0x4fe0 cx = 0x000c dx = 0x0002 di = 0xb018 si = 0x0001 bp = 0x3d80 sp = 0x3d60 r8w = 0x3470 r9w = 0x0000 r10w = 0x0001 r11w = 0x0202 r12w = 0x3da0 r13w = 0x8500 r14w = 0x0002 r15w = 0x27e0 ah = 0x00 bh = 0x4f ch = 0x00 dh = 0x00 al = 0x1c bl = 0xe0 cl = 0x0c dl = 0x02 dil = 0x18 sil = 0x01 bpl = 0x80 spl = 0x60 r8l = 0x70 r9l = 0x00 r10l = 0x01 r11l = 0x02 r12l = 0xa0 r13l = 0x00 r14l = 0x02 r15l = 0xe0 unknown: fctrl = 0x037f fstat = 0x0220 ftag = 0x00 fop = 0x0000 fiseg = 0x11e1a52c fioff = 0x11e1a52c foseg = 0xff1d3d54 fooff = 0xff1d3d54 mxcsr = 0x00001fa0 mxcsrmask = 0x0000ffff st0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} st1 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} st2 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} st3 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} st4 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} st5 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} st6 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} st7 = {0xa5 0xdb 0x2d 0xbd 0x93 0xae 0xb9 0xfe 0xfe 0x3f} mm0 = 0x3fe9d13800000000 mm1 = 0x3e0485fcce89c000 mm2 = 0x3fefd735e0000000 mm3 = 0x0000000000000000 mm4 = 0x3fe0000000000000 mm5 = 0x3fe00000005217f3 mm6 = 0x0000000000000000 mm7 = 0x3fefd735e0000000 xmm0 = {0x00 0x00 0x00 0x00 0x38 0xd1 0xe9 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm1 = {0x00 0xc0 0x89 0xce 0xfc 0x85 0x04 0x3e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm2 = {0x00 0x00 0x00 0xe0 0x35 0xd7 0xef 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm3 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm4 = {0x00 0x00 0x00 0x00 0x00 0x00 0xe0 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm5 = {0xf3 0x17 0x52 0x00 0x00 0x00 0xe0 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm6 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm7 = {0x00 0x00 0x00 0xe0 0x35 0xd7 0xef 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm8 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm9 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm10 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm11 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm12 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm13 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm14 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} xmm15 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} dr0 = 0x0000000000000000 dr1 = 0x0000000000000000 dr2 = 0x0000000000000000 dr3 = 0x0000000000000000 dr4 = 0x0000000000000000 dr5 = 0x0000000000000000 dr6 = 0x00000000ffff0ff0 dr7 = 0x0000000000000400 22 registers were unavailable. ``` Sponsored by <The NetBSD Foundation> Reviewers: labath, emaste, joerg, kettenis Reviewed By: labath Subscribers: #lldb Tags: #lldb Differential Revision: https://reviews.llvm.org/D32080 llvm-svn: 300548
This commit is contained in:
parent
7ad2e8aae1
commit
36e23ecad0
|
@ -224,36 +224,83 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
|
||||||
PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
|
PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
|
||||||
|
|
||||||
// Get details on the signal raised.
|
// Get details on the signal raised.
|
||||||
if (siginfo_err.Success()) {
|
if (siginfo_err.Fail()) {
|
||||||
switch (info.psi_siginfo.si_code) {
|
return;
|
||||||
case TRAP_BRKPT:
|
}
|
||||||
|
|
||||||
|
switch (info.psi_siginfo.si_code) {
|
||||||
|
case TRAP_BRKPT:
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)
|
||||||
|
->SetStoppedByBreakpoint();
|
||||||
|
FixupBreakpointPCAsNeeded(
|
||||||
|
*static_pointer_cast<NativeThreadNetBSD>(thread_sp));
|
||||||
|
}
|
||||||
|
SetState(StateType::eStateStopped, true);
|
||||||
|
break;
|
||||||
|
case TRAP_TRACE:
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByTrace();
|
||||||
|
}
|
||||||
|
SetState(StateType::eStateStopped, true);
|
||||||
|
break;
|
||||||
|
case TRAP_EXEC: {
|
||||||
|
Error error = ReinitializeThreads();
|
||||||
|
if (error.Fail()) {
|
||||||
|
SetState(StateType::eStateInvalid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let our delegate know we have just exec'd.
|
||||||
|
NotifyDidExec();
|
||||||
|
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByExec();
|
||||||
|
}
|
||||||
|
SetState(StateType::eStateStopped, true);
|
||||||
|
} break;
|
||||||
|
case TRAP_DBREG: {
|
||||||
|
// If a watchpoint was hit, report it
|
||||||
|
uint32_t wp_index;
|
||||||
|
Error error =
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(m_threads[info.psi_lwpid])
|
||||||
|
->GetRegisterContext()
|
||||||
|
->GetWatchpointHitIndex(wp_index,
|
||||||
|
(uintptr_t)info.psi_siginfo.si_addr);
|
||||||
|
if (error.Fail())
|
||||||
|
LLDB_LOG(log,
|
||||||
|
"received error while checking for watchpoint hits, pid = "
|
||||||
|
"{0}, LWP = {1}, error = {2}",
|
||||||
|
GetID(), info.psi_lwpid, error);
|
||||||
|
if (wp_index != LLDB_INVALID_INDEX32) {
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)
|
||||||
|
->SetStoppedByWatchpoint(wp_index);
|
||||||
|
}
|
||||||
|
SetState(StateType::eStateStopped, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a breakpoint was hit, report it
|
||||||
|
uint32_t bp_index;
|
||||||
|
error = static_pointer_cast<NativeThreadNetBSD>(m_threads[info.psi_lwpid])
|
||||||
|
->GetRegisterContext()
|
||||||
|
->GetHardwareBreakHitIndex(bp_index,
|
||||||
|
(uintptr_t)info.psi_siginfo.si_addr);
|
||||||
|
if (error.Fail())
|
||||||
|
LLDB_LOG(log,
|
||||||
|
"received error while checking for hardware "
|
||||||
|
"breakpoint hits, pid = {0}, LWP = {1}, error = {2}",
|
||||||
|
GetID(), info.psi_lwpid, error);
|
||||||
|
if (bp_index != LLDB_INVALID_INDEX32) {
|
||||||
for (const auto &thread_sp : m_threads) {
|
for (const auto &thread_sp : m_threads) {
|
||||||
static_pointer_cast<NativeThreadNetBSD>(thread_sp)
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)
|
||||||
->SetStoppedByBreakpoint();
|
->SetStoppedByBreakpoint();
|
||||||
FixupBreakpointPCAsNeeded(
|
|
||||||
*static_pointer_cast<NativeThreadNetBSD>(thread_sp));
|
|
||||||
}
|
}
|
||||||
SetState(StateType::eStateStopped, true);
|
SetState(StateType::eStateStopped, true);
|
||||||
break;
|
break;
|
||||||
case TRAP_TRACE:
|
|
||||||
for (const auto &thread_sp : m_threads) {
|
|
||||||
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByTrace();
|
|
||||||
}
|
|
||||||
SetState(StateType::eStateStopped, true);
|
|
||||||
break;
|
|
||||||
case TRAP_EXEC: {
|
|
||||||
Error error = ReinitializeThreads();
|
|
||||||
if (error.Fail()) {
|
|
||||||
SetState(StateType::eStateInvalid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let our delegate know we have just exec'd.
|
|
||||||
NotifyDidExec();
|
|
||||||
|
|
||||||
SetState(StateType::eStateStopped, true);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,8 +375,8 @@ Error NativeProcessNetBSD::FixupBreakpointPCAsNeeded(
|
||||||
return error;
|
return error;
|
||||||
} else
|
} else
|
||||||
LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size);
|
LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size);
|
||||||
// First try probing for a breakpoint at a software breakpoint location: PC -
|
// First try probing for a breakpoint at a software breakpoint location: PC
|
||||||
// breakpoint size.
|
// - breakpoint size.
|
||||||
const lldb::addr_t initial_pc_addr =
|
const lldb::addr_t initial_pc_addr =
|
||||||
context_sp->GetPCfromBreakpointLocation();
|
context_sp->GetPCfromBreakpointLocation();
|
||||||
lldb::addr_t breakpoint_addr = initial_pc_addr;
|
lldb::addr_t breakpoint_addr = initial_pc_addr;
|
||||||
|
@ -439,7 +486,7 @@ Error NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
|
||||||
llvm_unreachable("Unexpected state");
|
llvm_unreachable("Unexpected state");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return Error("NativeProcessLinux::%s (): unexpected state %s specified "
|
return Error("NativeProcessNetBSD::%s (): unexpected state %s specified "
|
||||||
"for pid %" PRIu64 ", tid %" PRIu64,
|
"for pid %" PRIu64 ", tid %" PRIu64,
|
||||||
__FUNCTION__, StateAsCString(action->state), GetID(),
|
__FUNCTION__, StateAsCString(action->state), GetID(),
|
||||||
thread_sp->GetID());
|
thread_sp->GetID());
|
||||||
|
@ -540,8 +587,8 @@ Error NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
|
||||||
"descending memory map entries detected, unexpected");
|
"descending memory map entries detected, unexpected");
|
||||||
prev_base_address = proc_entry_info.GetRange().GetRangeBase();
|
prev_base_address = proc_entry_info.GetRange().GetRangeBase();
|
||||||
UNUSED_IF_ASSERT_DISABLED(prev_base_address);
|
UNUSED_IF_ASSERT_DISABLED(prev_base_address);
|
||||||
// If the target address comes before this entry, indicate distance to next
|
// If the target address comes before this entry, indicate distance to
|
||||||
// region.
|
// next region.
|
||||||
if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
|
if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
|
||||||
range_info.GetRange().SetRangeBase(load_addr);
|
range_info.GetRange().SetRangeBase(load_addr);
|
||||||
range_info.GetRange().SetByteSize(
|
range_info.GetRange().SetByteSize(
|
||||||
|
@ -561,9 +608,8 @@ Error NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
|
||||||
}
|
}
|
||||||
// If we made it here, we didn't find an entry that contained the given
|
// If we made it here, we didn't find an entry that contained the given
|
||||||
// address. Return the
|
// address. Return the
|
||||||
// load_addr as start and the amount of bytes betwwen load address and the end
|
// load_addr as start and the amount of bytes betwwen load address and the
|
||||||
// of the memory as
|
// end of the memory as size.
|
||||||
// size.
|
|
||||||
range_info.GetRange().SetRangeBase(load_addr);
|
range_info.GetRange().SetRangeBase(load_addr);
|
||||||
range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
|
range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
|
||||||
range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
|
range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
|
||||||
|
@ -722,8 +768,8 @@ Error NativeProcessNetBSD::LaunchInferior(MainLoop &mainloop,
|
||||||
LLDB_LOG(log, "waitpid for inferior failed with %s", error);
|
LLDB_LOG(log, "waitpid for inferior failed with %s", error);
|
||||||
|
|
||||||
// Mark the inferior as invalid.
|
// Mark the inferior as invalid.
|
||||||
// FIXME this could really use a new state - eStateLaunchFailure. For now,
|
// FIXME this could really use a new state - eStateLaunchFailure. For
|
||||||
// using eStateInvalid.
|
// now, using eStateInvalid.
|
||||||
SetState(StateType::eStateInvalid);
|
SetState(StateType::eStateInvalid);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@ -766,6 +812,11 @@ Error NativeProcessNetBSD::LaunchInferior(MainLoop &mainloop,
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
|
||||||
|
SIGSTOP);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set process stopped */
|
/* Set process stopped */
|
||||||
SetState(StateType::eStateStopped);
|
SetState(StateType::eStateStopped);
|
||||||
|
|
||||||
|
@ -894,6 +945,11 @@ NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &thread_sp : m_threads) {
|
||||||
|
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
|
||||||
|
SIGSTOP);
|
||||||
|
}
|
||||||
|
|
||||||
// Let our process instance know the thread has stopped.
|
// Let our process instance know the thread has stopped.
|
||||||
SetState(StateType::eStateStopped);
|
SetState(StateType::eStateStopped);
|
||||||
|
|
||||||
|
@ -1007,7 +1063,6 @@ Error NativeProcessNetBSD::ReinitializeThreads() {
|
||||||
// Reinitialize from scratch threads and register them in process
|
// Reinitialize from scratch threads and register them in process
|
||||||
while (info.pl_lwpid != 0) {
|
while (info.pl_lwpid != 0) {
|
||||||
NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
|
NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
|
||||||
thread_sp->SetStoppedByExec();
|
|
||||||
error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info));
|
error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info));
|
||||||
if (error.Fail()) {
|
if (error.Fail()) {
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -57,6 +57,22 @@ Error NativeRegisterContextNetBSD::WriteFPR() {
|
||||||
return DoWriteFPR(buf);
|
return DoWriteFPR(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD::ReadDBR() {
|
||||||
|
void *buf = GetDBRBuffer();
|
||||||
|
if (!buf)
|
||||||
|
return Error("DBR buffer is NULL");
|
||||||
|
|
||||||
|
return DoReadDBR(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD::WriteDBR() {
|
||||||
|
void *buf = GetDBRBuffer();
|
||||||
|
if (!buf)
|
||||||
|
return Error("DBR buffer is NULL");
|
||||||
|
|
||||||
|
return DoWriteDBR(buf);
|
||||||
|
}
|
||||||
|
|
||||||
Error NativeRegisterContextNetBSD::DoReadGPR(void *buf) {
|
Error NativeRegisterContextNetBSD::DoReadGPR(void *buf) {
|
||||||
return NativeProcessNetBSD::PtraceWrapper(PT_GETREGS, GetProcessPid(), buf,
|
return NativeProcessNetBSD::PtraceWrapper(PT_GETREGS, GetProcessPid(), buf,
|
||||||
m_thread.GetID());
|
m_thread.GetID());
|
||||||
|
@ -77,6 +93,16 @@ Error NativeRegisterContextNetBSD::DoWriteFPR(void *buf) {
|
||||||
m_thread.GetID());
|
m_thread.GetID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD::DoReadDBR(void *buf) {
|
||||||
|
return NativeProcessNetBSD::PtraceWrapper(PT_GETDBREGS, GetProcessPid(), buf,
|
||||||
|
m_thread.GetID());
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD::DoWriteDBR(void *buf) {
|
||||||
|
return NativeProcessNetBSD::PtraceWrapper(PT_SETDBREGS, GetProcessPid(), buf,
|
||||||
|
m_thread.GetID());
|
||||||
|
}
|
||||||
|
|
||||||
NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
|
NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
|
||||||
auto process_sp =
|
auto process_sp =
|
||||||
std::static_pointer_cast<NativeProcessNetBSD>(m_thread.GetProcess());
|
std::static_pointer_cast<NativeProcessNetBSD>(m_thread.GetProcess());
|
||||||
|
|
|
@ -41,6 +41,9 @@ protected:
|
||||||
virtual Error ReadFPR();
|
virtual Error ReadFPR();
|
||||||
virtual Error WriteFPR();
|
virtual Error WriteFPR();
|
||||||
|
|
||||||
|
virtual Error ReadDBR();
|
||||||
|
virtual Error WriteDBR();
|
||||||
|
|
||||||
virtual void *GetGPRBuffer() { return nullptr; }
|
virtual void *GetGPRBuffer() { return nullptr; }
|
||||||
virtual size_t GetGPRSize() {
|
virtual size_t GetGPRSize() {
|
||||||
return GetRegisterInfoInterface().GetGPRSize();
|
return GetRegisterInfoInterface().GetGPRSize();
|
||||||
|
@ -49,12 +52,18 @@ protected:
|
||||||
virtual void *GetFPRBuffer() { return nullptr; }
|
virtual void *GetFPRBuffer() { return nullptr; }
|
||||||
virtual size_t GetFPRSize() { return 0; }
|
virtual size_t GetFPRSize() { return 0; }
|
||||||
|
|
||||||
|
virtual void *GetDBRBuffer() { return nullptr; }
|
||||||
|
virtual size_t GetDBRSize() { return 0; }
|
||||||
|
|
||||||
virtual Error DoReadGPR(void *buf);
|
virtual Error DoReadGPR(void *buf);
|
||||||
virtual Error DoWriteGPR(void *buf);
|
virtual Error DoWriteGPR(void *buf);
|
||||||
|
|
||||||
virtual Error DoReadFPR(void *buf);
|
virtual Error DoReadFPR(void *buf);
|
||||||
virtual Error DoWriteFPR(void *buf);
|
virtual Error DoWriteFPR(void *buf);
|
||||||
|
|
||||||
|
virtual Error DoReadDBR(void *buf);
|
||||||
|
virtual Error DoWriteDBR(void *buf);
|
||||||
|
|
||||||
virtual NativeProcessNetBSD &GetProcess();
|
virtual NativeProcessNetBSD &GetProcess();
|
||||||
virtual ::pid_t GetProcessPid();
|
virtual ::pid_t GetProcessPid();
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,15 @@
|
||||||
|
|
||||||
#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
|
#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <x86/cpu.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
using namespace lldb_private;
|
using namespace lldb_private;
|
||||||
using namespace lldb_private::process_netbsd;
|
using namespace lldb_private::process_netbsd;
|
||||||
|
@ -86,6 +94,57 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
|
||||||
|
|
||||||
#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
|
#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
|
||||||
|
|
||||||
|
const int fpu_present = []() -> int {
|
||||||
|
int mib[2];
|
||||||
|
int error;
|
||||||
|
size_t len;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
len = sizeof(val);
|
||||||
|
mib[0] = CTL_MACHDEP;
|
||||||
|
mib[1] = CPU_FPU_PRESENT;
|
||||||
|
|
||||||
|
error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0);
|
||||||
|
if (error)
|
||||||
|
errx(EXIT_FAILURE, "sysctl");
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const int osfxsr = []() -> int {
|
||||||
|
int mib[2];
|
||||||
|
int error;
|
||||||
|
size_t len;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
len = sizeof(val);
|
||||||
|
mib[0] = CTL_MACHDEP;
|
||||||
|
mib[1] = CPU_OSFXSR;
|
||||||
|
|
||||||
|
error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0);
|
||||||
|
if (error)
|
||||||
|
errx(EXIT_FAILURE, "sysctl");
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const int fpu_save = []() -> int {
|
||||||
|
int mib[2];
|
||||||
|
int error;
|
||||||
|
size_t len;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
len = sizeof(val);
|
||||||
|
mib[0] = CTL_MACHDEP;
|
||||||
|
mib[1] = CPU_FPU_SAVE;
|
||||||
|
|
||||||
|
error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0);
|
||||||
|
if (error)
|
||||||
|
errx(EXIT_FAILURE, "sysctl");
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}();
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
NativeRegisterContextNetBSD *
|
NativeRegisterContextNetBSD *
|
||||||
|
@ -114,7 +173,7 @@ NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64(
|
||||||
uint32_t concrete_frame_idx)
|
uint32_t concrete_frame_idx)
|
||||||
: NativeRegisterContextNetBSD(native_thread, concrete_frame_idx,
|
: NativeRegisterContextNetBSD(native_thread, concrete_frame_idx,
|
||||||
CreateRegisterInfoInterface(target_arch)),
|
CreateRegisterInfoInterface(target_arch)),
|
||||||
m_gpr_x86_64() {}
|
m_gpr_x86_64(), m_fpr_x86_64(), m_dbr_x86_64() {}
|
||||||
|
|
||||||
// CONSIDER after local and llgs debugging are merged, register set support can
|
// CONSIDER after local and llgs debugging are merged, register set support can
|
||||||
// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
|
// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
|
||||||
|
@ -143,8 +202,18 @@ NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
|
||||||
|
|
||||||
int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
|
int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
|
||||||
int reg_num) const {
|
int reg_num) const {
|
||||||
if (reg_num < lldb_fctrl_x86_64)
|
if (reg_num <= k_last_gpr_x86_64)
|
||||||
return GPRegSet;
|
return GPRegSet;
|
||||||
|
else if (reg_num <= k_last_fpr_x86_64)
|
||||||
|
return (fpu_present == 1 && osfxsr == 1 && fpu_save >= 1) ? FPRegSet : -1;
|
||||||
|
else if (reg_num <= k_last_avx_x86_64)
|
||||||
|
return -1; // AVX
|
||||||
|
else if (reg_num <= k_last_mpxr_x86_64)
|
||||||
|
return -1; // MPXR
|
||||||
|
else if (reg_num <= k_last_mpxc_x86_64)
|
||||||
|
return -1; // MPXC
|
||||||
|
else if (reg_num <= lldb_dr7_x86_64)
|
||||||
|
return DBRegSet; // DBR
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -157,6 +226,9 @@ int NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
|
||||||
case FPRegSet:
|
case FPRegSet:
|
||||||
ReadFPR();
|
ReadFPR();
|
||||||
return 0;
|
return 0;
|
||||||
|
case DBRegSet:
|
||||||
|
ReadDBR();
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -170,6 +242,9 @@ int NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
|
||||||
case FPRegSet:
|
case FPRegSet:
|
||||||
WriteFPR();
|
WriteFPR();
|
||||||
return 0;
|
return 0;
|
||||||
|
case DBRegSet:
|
||||||
|
WriteDBR();
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -285,6 +360,87 @@ Error NativeRegisterContextNetBSD_x86_64::ReadRegister(
|
||||||
case lldb_es_x86_64:
|
case lldb_es_x86_64:
|
||||||
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
|
reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
|
||||||
break;
|
break;
|
||||||
|
case lldb_fctrl_x86_64:
|
||||||
|
reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_cw;
|
||||||
|
break;
|
||||||
|
case lldb_fstat_x86_64:
|
||||||
|
reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_sw;
|
||||||
|
break;
|
||||||
|
case lldb_ftag_x86_64:
|
||||||
|
reg_value = (uint8_t)m_fpr_x86_64.fxstate.fx_tw;
|
||||||
|
break;
|
||||||
|
case lldb_fop_x86_64:
|
||||||
|
reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_opcode;
|
||||||
|
break;
|
||||||
|
case lldb_fiseg_x86_64:
|
||||||
|
reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_ip.fa_64;
|
||||||
|
break;
|
||||||
|
case lldb_fioff_x86_64:
|
||||||
|
reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off;
|
||||||
|
break;
|
||||||
|
case lldb_foseg_x86_64:
|
||||||
|
reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_dp.fa_64;
|
||||||
|
break;
|
||||||
|
case lldb_fooff_x86_64:
|
||||||
|
reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off;
|
||||||
|
break;
|
||||||
|
case lldb_mxcsr_x86_64:
|
||||||
|
reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr;
|
||||||
|
break;
|
||||||
|
case lldb_mxcsrmask_x86_64:
|
||||||
|
reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr_mask;
|
||||||
|
break;
|
||||||
|
case lldb_st0_x86_64:
|
||||||
|
case lldb_st1_x86_64:
|
||||||
|
case lldb_st2_x86_64:
|
||||||
|
case lldb_st3_x86_64:
|
||||||
|
case lldb_st4_x86_64:
|
||||||
|
case lldb_st5_x86_64:
|
||||||
|
case lldb_st6_x86_64:
|
||||||
|
case lldb_st7_x86_64:
|
||||||
|
reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
|
||||||
|
reg_info->byte_size, endian::InlHostByteOrder());
|
||||||
|
break;
|
||||||
|
case lldb_mm0_x86_64:
|
||||||
|
case lldb_mm1_x86_64:
|
||||||
|
case lldb_mm2_x86_64:
|
||||||
|
case lldb_mm3_x86_64:
|
||||||
|
case lldb_mm4_x86_64:
|
||||||
|
case lldb_mm5_x86_64:
|
||||||
|
case lldb_mm6_x86_64:
|
||||||
|
case lldb_mm7_x86_64:
|
||||||
|
reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_mm0_x86_64],
|
||||||
|
reg_info->byte_size, endian::InlHostByteOrder());
|
||||||
|
break;
|
||||||
|
case lldb_xmm0_x86_64:
|
||||||
|
case lldb_xmm1_x86_64:
|
||||||
|
case lldb_xmm2_x86_64:
|
||||||
|
case lldb_xmm3_x86_64:
|
||||||
|
case lldb_xmm4_x86_64:
|
||||||
|
case lldb_xmm5_x86_64:
|
||||||
|
case lldb_xmm6_x86_64:
|
||||||
|
case lldb_xmm7_x86_64:
|
||||||
|
case lldb_xmm8_x86_64:
|
||||||
|
case lldb_xmm9_x86_64:
|
||||||
|
case lldb_xmm10_x86_64:
|
||||||
|
case lldb_xmm11_x86_64:
|
||||||
|
case lldb_xmm12_x86_64:
|
||||||
|
case lldb_xmm13_x86_64:
|
||||||
|
case lldb_xmm14_x86_64:
|
||||||
|
case lldb_xmm15_x86_64:
|
||||||
|
reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
|
||||||
|
reg_info->byte_size, endian::InlHostByteOrder());
|
||||||
|
break;
|
||||||
|
case lldb_dr0_x86_64:
|
||||||
|
case lldb_dr1_x86_64:
|
||||||
|
case lldb_dr2_x86_64:
|
||||||
|
case lldb_dr3_x86_64:
|
||||||
|
case lldb_dr4_x86_64:
|
||||||
|
case lldb_dr5_x86_64:
|
||||||
|
case lldb_dr6_x86_64:
|
||||||
|
case lldb_dr7_x86_64:
|
||||||
|
reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@ -400,6 +556,87 @@ Error NativeRegisterContextNetBSD_x86_64::WriteRegister(
|
||||||
case lldb_es_x86_64:
|
case lldb_es_x86_64:
|
||||||
m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
|
m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
|
||||||
break;
|
break;
|
||||||
|
case lldb_fctrl_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_cw = reg_value.GetAsUInt16();
|
||||||
|
break;
|
||||||
|
case lldb_fstat_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_sw = reg_value.GetAsUInt16();
|
||||||
|
break;
|
||||||
|
case lldb_ftag_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_tw = reg_value.GetAsUInt8();
|
||||||
|
break;
|
||||||
|
case lldb_fop_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_opcode = reg_value.GetAsUInt16();
|
||||||
|
break;
|
||||||
|
case lldb_fiseg_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_fioff_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32();
|
||||||
|
break;
|
||||||
|
case lldb_foseg_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
|
case lldb_fooff_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32();
|
||||||
|
break;
|
||||||
|
case lldb_mxcsr_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_mxcsr = reg_value.GetAsUInt32();
|
||||||
|
break;
|
||||||
|
case lldb_mxcsrmask_x86_64:
|
||||||
|
m_fpr_x86_64.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32();
|
||||||
|
break;
|
||||||
|
case lldb_st0_x86_64:
|
||||||
|
case lldb_st1_x86_64:
|
||||||
|
case lldb_st2_x86_64:
|
||||||
|
case lldb_st3_x86_64:
|
||||||
|
case lldb_st4_x86_64:
|
||||||
|
case lldb_st5_x86_64:
|
||||||
|
case lldb_st6_x86_64:
|
||||||
|
case lldb_st7_x86_64:
|
||||||
|
::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
|
||||||
|
reg_value.GetBytes(), reg_value.GetByteSize());
|
||||||
|
break;
|
||||||
|
case lldb_mm0_x86_64:
|
||||||
|
case lldb_mm1_x86_64:
|
||||||
|
case lldb_mm2_x86_64:
|
||||||
|
case lldb_mm3_x86_64:
|
||||||
|
case lldb_mm4_x86_64:
|
||||||
|
case lldb_mm5_x86_64:
|
||||||
|
case lldb_mm6_x86_64:
|
||||||
|
case lldb_mm7_x86_64:
|
||||||
|
::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_mm0_x86_64],
|
||||||
|
reg_value.GetBytes(), reg_value.GetByteSize());
|
||||||
|
break;
|
||||||
|
case lldb_xmm0_x86_64:
|
||||||
|
case lldb_xmm1_x86_64:
|
||||||
|
case lldb_xmm2_x86_64:
|
||||||
|
case lldb_xmm3_x86_64:
|
||||||
|
case lldb_xmm4_x86_64:
|
||||||
|
case lldb_xmm5_x86_64:
|
||||||
|
case lldb_xmm6_x86_64:
|
||||||
|
case lldb_xmm7_x86_64:
|
||||||
|
case lldb_xmm8_x86_64:
|
||||||
|
case lldb_xmm9_x86_64:
|
||||||
|
case lldb_xmm10_x86_64:
|
||||||
|
case lldb_xmm11_x86_64:
|
||||||
|
case lldb_xmm12_x86_64:
|
||||||
|
case lldb_xmm13_x86_64:
|
||||||
|
case lldb_xmm14_x86_64:
|
||||||
|
case lldb_xmm15_x86_64:
|
||||||
|
::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
|
||||||
|
reg_value.GetBytes(), reg_value.GetByteSize());
|
||||||
|
break;
|
||||||
|
case lldb_dr0_x86_64:
|
||||||
|
case lldb_dr1_x86_64:
|
||||||
|
case lldb_dr2_x86_64:
|
||||||
|
case lldb_dr3_x86_64:
|
||||||
|
case lldb_dr4_x86_64:
|
||||||
|
case lldb_dr5_x86_64:
|
||||||
|
case lldb_dr6_x86_64:
|
||||||
|
case lldb_dr7_x86_64:
|
||||||
|
m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WriteRegisterSet(set) != 0)
|
if (WriteRegisterSet(set) != 0)
|
||||||
|
@ -480,4 +717,223 @@ Error NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
|
||||||
|
bool &is_hit) {
|
||||||
|
if (wp_index >= NumSupportedHardwareWatchpoints())
|
||||||
|
return Error("Watchpoint index out of range");
|
||||||
|
|
||||||
|
RegisterValue reg_value;
|
||||||
|
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64);
|
||||||
|
Error error = ReadRegister(reg_info, reg_value);
|
||||||
|
if (error.Fail()) {
|
||||||
|
is_hit = false;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t status_bits = reg_value.GetAsUInt64();
|
||||||
|
|
||||||
|
is_hit = status_bits & (1 << wp_index);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex(
|
||||||
|
uint32_t &wp_index, lldb::addr_t trap_addr) {
|
||||||
|
uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
|
||||||
|
for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
|
||||||
|
bool is_hit;
|
||||||
|
Error error = IsWatchpointHit(wp_index, is_hit);
|
||||||
|
if (error.Fail()) {
|
||||||
|
wp_index = LLDB_INVALID_INDEX32;
|
||||||
|
return error;
|
||||||
|
} else if (is_hit) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wp_index = LLDB_INVALID_INDEX32;
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
|
||||||
|
bool &is_vacant) {
|
||||||
|
if (wp_index >= NumSupportedHardwareWatchpoints())
|
||||||
|
return Error("Watchpoint index out of range");
|
||||||
|
|
||||||
|
RegisterValue reg_value;
|
||||||
|
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64);
|
||||||
|
Error error = ReadRegister(reg_info, reg_value);
|
||||||
|
if (error.Fail()) {
|
||||||
|
is_vacant = false;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t control_bits = reg_value.GetAsUInt64();
|
||||||
|
|
||||||
|
is_vacant = !(control_bits & (1 << (2 * wp_index)));
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex(
|
||||||
|
lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
|
||||||
|
|
||||||
|
if (wp_index >= NumSupportedHardwareWatchpoints())
|
||||||
|
return Error("Watchpoint index out of range");
|
||||||
|
|
||||||
|
// Read only watchpoints aren't supported on x86_64. Fall back to read/write
|
||||||
|
// waitchpoints instead.
|
||||||
|
// TODO: Add logic to detect when a write happens and ignore that watchpoint
|
||||||
|
// hit.
|
||||||
|
if (watch_flags == 0x2)
|
||||||
|
watch_flags = 0x3;
|
||||||
|
|
||||||
|
if (watch_flags != 0x1 && watch_flags != 0x3)
|
||||||
|
return Error("Invalid read/write bits for watchpoint");
|
||||||
|
|
||||||
|
if (size != 1 && size != 2 && size != 4 && size != 8)
|
||||||
|
return Error("Invalid size for watchpoint");
|
||||||
|
|
||||||
|
bool is_vacant;
|
||||||
|
Error error = IsWatchpointVacant(wp_index, is_vacant);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
if (!is_vacant)
|
||||||
|
return Error("Watchpoint index not vacant");
|
||||||
|
|
||||||
|
RegisterValue reg_value;
|
||||||
|
const RegisterInfo *const reg_info_dr7 =
|
||||||
|
GetRegisterInfoAtIndex(lldb_dr7_x86_64);
|
||||||
|
error = ReadRegister(reg_info_dr7, reg_value);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// for watchpoints 0, 1, 2, or 3, respectively,
|
||||||
|
// set bits 1, 3, 5, or 7
|
||||||
|
uint64_t enable_bit = 1 << (2 * wp_index);
|
||||||
|
|
||||||
|
// set bits 16-17, 20-21, 24-25, or 28-29
|
||||||
|
// with 0b01 for write, and 0b11 for read/write
|
||||||
|
uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
|
||||||
|
|
||||||
|
// set bits 18-19, 22-23, 26-27, or 30-31
|
||||||
|
// with 0b00, 0b01, 0b10, or 0b11
|
||||||
|
// for 1, 2, 8 (if supported), or 4 bytes, respectively
|
||||||
|
uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
|
||||||
|
|
||||||
|
uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
|
||||||
|
|
||||||
|
uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||||
|
|
||||||
|
control_bits |= enable_bit | rw_bits | size_bits;
|
||||||
|
|
||||||
|
const RegisterInfo *const reg_info_drN =
|
||||||
|
GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
|
||||||
|
error = WriteRegister(reg_info_drN, RegisterValue(addr));
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error = WriteRegister(reg_info_dr7, RegisterValue(control_bits));
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error.Clear();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint(
|
||||||
|
uint32_t wp_index) {
|
||||||
|
if (wp_index >= NumSupportedHardwareWatchpoints())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RegisterValue reg_value;
|
||||||
|
|
||||||
|
// for watchpoints 0, 1, 2, or 3, respectively,
|
||||||
|
// clear bits 0, 1, 2, or 3 of the debug status register (DR6)
|
||||||
|
const RegisterInfo *const reg_info_dr6 =
|
||||||
|
GetRegisterInfoAtIndex(lldb_dr6_x86_64);
|
||||||
|
Error error = ReadRegister(reg_info_dr6, reg_value);
|
||||||
|
if (error.Fail())
|
||||||
|
return false;
|
||||||
|
uint64_t bit_mask = 1 << wp_index;
|
||||||
|
uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||||
|
error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
|
||||||
|
if (error.Fail())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// for watchpoints 0, 1, 2, or 3, respectively,
|
||||||
|
// clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
|
||||||
|
// of the debug control register (DR7)
|
||||||
|
const RegisterInfo *const reg_info_dr7 =
|
||||||
|
GetRegisterInfoAtIndex(lldb_dr7_x86_64);
|
||||||
|
error = ReadRegister(reg_info_dr7, reg_value);
|
||||||
|
if (error.Fail())
|
||||||
|
return false;
|
||||||
|
bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
|
||||||
|
uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||||
|
return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() {
|
||||||
|
RegisterValue reg_value;
|
||||||
|
|
||||||
|
// clear bits {0-4} of the debug status register (DR6)
|
||||||
|
const RegisterInfo *const reg_info_dr6 =
|
||||||
|
GetRegisterInfoAtIndex(lldb_dr6_x86_64);
|
||||||
|
Error error = ReadRegister(reg_info_dr6, reg_value);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
uint64_t bit_mask = 0xF;
|
||||||
|
uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||||
|
error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// clear bits {0-7,16-31} of the debug control register (DR7)
|
||||||
|
const RegisterInfo *const reg_info_dr7 =
|
||||||
|
GetRegisterInfoAtIndex(lldb_dr7_x86_64);
|
||||||
|
error = ReadRegister(reg_info_dr7, reg_value);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
bit_mask = 0xFF | (0xFFFF << 16);
|
||||||
|
uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||||
|
return WriteRegister(reg_info_dr7, RegisterValue(control_bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint(
|
||||||
|
lldb::addr_t addr, size_t size, uint32_t watch_flags) {
|
||||||
|
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
|
||||||
|
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
|
||||||
|
for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
|
||||||
|
bool is_vacant;
|
||||||
|
Error error = IsWatchpointVacant(wp_index, is_vacant);
|
||||||
|
if (is_vacant) {
|
||||||
|
error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
|
||||||
|
if (error.Success())
|
||||||
|
return wp_index;
|
||||||
|
}
|
||||||
|
if (error.Fail() && log) {
|
||||||
|
log->Printf("NativeRegisterContextNetBSD_x86_64::%s Error: %s",
|
||||||
|
__FUNCTION__, error.AsCString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LLDB_INVALID_INDEX32;
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::addr_t
|
||||||
|
NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
|
||||||
|
if (wp_index >= NumSupportedHardwareWatchpoints())
|
||||||
|
return LLDB_INVALID_ADDRESS;
|
||||||
|
RegisterValue reg_value;
|
||||||
|
const RegisterInfo *const reg_info_drN =
|
||||||
|
GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
|
||||||
|
if (ReadRegister(reg_info_drN, reg_value).Fail())
|
||||||
|
return LLDB_INVALID_ADDRESS;
|
||||||
|
return reg_value.GetAsUInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() {
|
||||||
|
// Available debug address registers: dr0, dr1, dr2, dr3
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // defined(__x86_64__)
|
#endif // defined(__x86_64__)
|
||||||
|
|
|
@ -46,17 +46,40 @@ public:
|
||||||
|
|
||||||
Error WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
|
Error WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
|
||||||
|
|
||||||
|
Error IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
|
||||||
|
|
||||||
|
Error GetWatchpointHitIndex(uint32_t &wp_index,
|
||||||
|
lldb::addr_t trap_addr) override;
|
||||||
|
|
||||||
|
Error IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
|
||||||
|
|
||||||
|
bool ClearHardwareWatchpoint(uint32_t wp_index) override;
|
||||||
|
|
||||||
|
Error ClearAllHardwareWatchpoints() override;
|
||||||
|
|
||||||
|
Error SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
|
||||||
|
uint32_t watch_flags, uint32_t wp_index);
|
||||||
|
|
||||||
|
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
|
||||||
|
uint32_t watch_flags) override;
|
||||||
|
|
||||||
|
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
|
||||||
|
|
||||||
|
uint32_t NumSupportedHardwareWatchpoints() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void *GetGPRBuffer() override { return &m_gpr_x86_64; }
|
void *GetGPRBuffer() override { return &m_gpr_x86_64; }
|
||||||
void *GetFPRBuffer() override { return &m_fpr_x86_64; }
|
void *GetFPRBuffer() override { return &m_fpr_x86_64; }
|
||||||
|
void *GetDBRBuffer() override { return &m_dbr_x86_64; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Private member types.
|
// Private member types.
|
||||||
enum { GPRegSet, FPRegSet };
|
enum { GPRegSet, FPRegSet, DBRegSet };
|
||||||
|
|
||||||
// Private member variables.
|
// Private member variables.
|
||||||
struct reg m_gpr_x86_64;
|
struct reg m_gpr_x86_64;
|
||||||
struct fpreg m_fpr_x86_64;
|
struct fpreg m_fpr_x86_64;
|
||||||
|
struct dbreg m_dbr_x86_64;
|
||||||
|
|
||||||
int GetSetForNativeRegNum(int reg_num) const;
|
int GetSetForNativeRegNum(int reg_num) const;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
|
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
|
||||||
#include "lldb/Core/RegisterValue.h"
|
#include "lldb/Core/RegisterValue.h"
|
||||||
#include "lldb/Core/State.h"
|
#include "lldb/Core/State.h"
|
||||||
|
#include "lldb/Utility/LLDBAssert.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
using namespace lldb;
|
using namespace lldb;
|
||||||
using namespace lldb_private;
|
using namespace lldb_private;
|
||||||
|
@ -68,6 +71,23 @@ void NativeThreadNetBSD::SetStoppedByExec() {
|
||||||
m_stop_info.details.signal.signo = SIGTRAP;
|
m_stop_info.details.signal.signo = SIGTRAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
|
||||||
|
SetStopped();
|
||||||
|
|
||||||
|
lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
|
||||||
|
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " ";
|
||||||
|
ostr << wp_index;
|
||||||
|
|
||||||
|
ostr << " " << GetRegisterContext()->GetWatchpointHitAddress(wp_index);
|
||||||
|
|
||||||
|
m_stop_description = ostr.str();
|
||||||
|
|
||||||
|
m_stop_info.reason = StopReason::eStopReasonWatchpoint;
|
||||||
|
m_stop_info.details.signal.signo = SIGTRAP;
|
||||||
|
}
|
||||||
|
|
||||||
void NativeThreadNetBSD::SetStopped() {
|
void NativeThreadNetBSD::SetStopped() {
|
||||||
const StateType new_state = StateType::eStateStopped;
|
const StateType new_state = StateType::eStateStopped;
|
||||||
m_state = new_state;
|
m_state = new_state;
|
||||||
|
@ -142,18 +162,61 @@ NativeRegisterContextSP NativeThreadNetBSD::GetRegisterContext() {
|
||||||
|
|
||||||
Error NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
|
Error NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
|
||||||
uint32_t watch_flags, bool hardware) {
|
uint32_t watch_flags, bool hardware) {
|
||||||
return Error("Unimplemented");
|
if (!hardware)
|
||||||
|
return Error("not implemented");
|
||||||
|
if (m_state == eStateLaunching)
|
||||||
|
return Error();
|
||||||
|
Error error = RemoveWatchpoint(addr);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
NativeRegisterContextSP reg_ctx = GetRegisterContext();
|
||||||
|
uint32_t wp_index = reg_ctx->SetHardwareWatchpoint(addr, size, watch_flags);
|
||||||
|
if (wp_index == LLDB_INVALID_INDEX32)
|
||||||
|
return Error("Setting hardware watchpoint failed.");
|
||||||
|
m_watchpoint_index_map.insert({addr, wp_index});
|
||||||
|
return Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
|
Error NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
|
||||||
return Error("Unimplemented");
|
auto wp = m_watchpoint_index_map.find(addr);
|
||||||
|
if (wp == m_watchpoint_index_map.end())
|
||||||
|
return Error();
|
||||||
|
uint32_t wp_index = wp->second;
|
||||||
|
m_watchpoint_index_map.erase(wp);
|
||||||
|
if (GetRegisterContext()->ClearHardwareWatchpoint(wp_index))
|
||||||
|
return Error();
|
||||||
|
return Error("Clearing hardware watchpoint failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Error NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
|
Error NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
|
||||||
size_t size) {
|
size_t size) {
|
||||||
return Error("Unimplemented");
|
if (m_state == eStateLaunching)
|
||||||
|
return Error();
|
||||||
|
|
||||||
|
Error error = RemoveHardwareBreakpoint(addr);
|
||||||
|
if (error.Fail())
|
||||||
|
return error;
|
||||||
|
|
||||||
|
NativeRegisterContextSP reg_ctx = GetRegisterContext();
|
||||||
|
uint32_t bp_index = reg_ctx->SetHardwareBreakpoint(addr, size);
|
||||||
|
|
||||||
|
if (bp_index == LLDB_INVALID_INDEX32)
|
||||||
|
return Error("Setting hardware breakpoint failed.");
|
||||||
|
|
||||||
|
m_hw_break_index_map.insert({addr, bp_index});
|
||||||
|
return Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
|
Error NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
|
||||||
return Error("Unimplemented");
|
auto bp = m_hw_break_index_map.find(addr);
|
||||||
|
if (bp == m_hw_break_index_map.end())
|
||||||
|
return Error();
|
||||||
|
|
||||||
|
uint32_t bp_index = bp->second;
|
||||||
|
if (GetRegisterContext()->ClearHardwareBreakpoint(bp_index)) {
|
||||||
|
m_hw_break_index_map.erase(bp);
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Error("Clearing hardware breakpoint failed.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
|
|
||||||
#include "lldb/Host/common/NativeThreadProtocol.h"
|
#include "lldb/Host/common/NativeThreadProtocol.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace lldb_private {
|
namespace lldb_private {
|
||||||
namespace process_netbsd {
|
namespace process_netbsd {
|
||||||
|
|
||||||
|
@ -53,6 +56,7 @@ private:
|
||||||
void SetStoppedByBreakpoint();
|
void SetStoppedByBreakpoint();
|
||||||
void SetStoppedByTrace();
|
void SetStoppedByTrace();
|
||||||
void SetStoppedByExec();
|
void SetStoppedByExec();
|
||||||
|
void SetStoppedByWatchpoint(uint32_t wp_index);
|
||||||
void SetStopped();
|
void SetStopped();
|
||||||
void SetRunning();
|
void SetRunning();
|
||||||
void SetStepping();
|
void SetStepping();
|
||||||
|
@ -64,6 +68,9 @@ private:
|
||||||
ThreadStopInfo m_stop_info;
|
ThreadStopInfo m_stop_info;
|
||||||
NativeRegisterContextSP m_reg_context_sp;
|
NativeRegisterContextSP m_reg_context_sp;
|
||||||
std::string m_stop_description;
|
std::string m_stop_description;
|
||||||
|
using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
|
||||||
|
WatchpointIndexMap m_watchpoint_index_map;
|
||||||
|
WatchpointIndexMap m_hw_break_index_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
|
typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
DR_OFFSET(i), eEncodingUint, eFormatHex, \
|
DR_OFFSET(i), eEncodingUint, eFormatHex, \
|
||||||
{LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
|
{LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
|
||||||
LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
|
LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
|
||||||
LLDB_INVALID_REGNUM }, \
|
lldb_##reg##i##_x86_64 }, \
|
||||||
nullptr, nullptr, nullptr, 0 \
|
nullptr, nullptr, nullptr, 0 \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue