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:
Kamil Rytarowski 2017-04-18 12:53:35 +00:00
parent 7ad2e8aae1
commit 36e23ecad0
8 changed files with 681 additions and 42 deletions

View File

@ -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;

View File

@ -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());

View File

@ -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();
}; };

View File

@ -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__)

View File

@ -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;

View File

@ -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.");
} }

View File

@ -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;

View File

@ -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 \
} }