1 //===-- NativeRegisterContextNetBSD_x86_64.cpp ---------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #if defined(__x86_64__)
10 
11 #include "NativeRegisterContextNetBSD_x86_64.h"
12 
13 #include "lldb/Host/HostInfo.h"
14 #include "lldb/Utility/DataBufferHeap.h"
15 #include "lldb/Utility/Log.h"
16 #include "lldb/Utility/RegisterValue.h"
17 #include "lldb/Utility/Status.h"
18 
19 #include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
20 
21 // clang-format off
22 #include <sys/types.h>
23 #include <sys/ptrace.h>
24 #include <sys/sysctl.h>
25 #include <x86/cpu.h>
26 #include <elf.h>
27 #include <err.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 // clang-format on
31 
32 using namespace lldb_private;
33 using namespace lldb_private::process_netbsd;
34 
35 // Private namespace.
36 
37 namespace {
38 // x86 64-bit general purpose registers.
39 static const uint32_t g_gpr_regnums_x86_64[] = {
40     lldb_rax_x86_64,    lldb_rbx_x86_64,    lldb_rcx_x86_64, lldb_rdx_x86_64,
41     lldb_rdi_x86_64,    lldb_rsi_x86_64,    lldb_rbp_x86_64, lldb_rsp_x86_64,
42     lldb_r8_x86_64,     lldb_r9_x86_64,     lldb_r10_x86_64, lldb_r11_x86_64,
43     lldb_r12_x86_64,    lldb_r13_x86_64,    lldb_r14_x86_64, lldb_r15_x86_64,
44     lldb_rip_x86_64,    lldb_rflags_x86_64, lldb_cs_x86_64,  lldb_fs_x86_64,
45     lldb_gs_x86_64,     lldb_ss_x86_64,     lldb_ds_x86_64,  lldb_es_x86_64,
46     lldb_eax_x86_64,    lldb_ebx_x86_64,    lldb_ecx_x86_64, lldb_edx_x86_64,
47     lldb_edi_x86_64,    lldb_esi_x86_64,    lldb_ebp_x86_64, lldb_esp_x86_64,
48     lldb_r8d_x86_64,  // Low 32 bits or r8
49     lldb_r9d_x86_64,  // Low 32 bits or r9
50     lldb_r10d_x86_64, // Low 32 bits or r10
51     lldb_r11d_x86_64, // Low 32 bits or r11
52     lldb_r12d_x86_64, // Low 32 bits or r12
53     lldb_r13d_x86_64, // Low 32 bits or r13
54     lldb_r14d_x86_64, // Low 32 bits or r14
55     lldb_r15d_x86_64, // Low 32 bits or r15
56     lldb_ax_x86_64,     lldb_bx_x86_64,     lldb_cx_x86_64,  lldb_dx_x86_64,
57     lldb_di_x86_64,     lldb_si_x86_64,     lldb_bp_x86_64,  lldb_sp_x86_64,
58     lldb_r8w_x86_64,  // Low 16 bits or r8
59     lldb_r9w_x86_64,  // Low 16 bits or r9
60     lldb_r10w_x86_64, // Low 16 bits or r10
61     lldb_r11w_x86_64, // Low 16 bits or r11
62     lldb_r12w_x86_64, // Low 16 bits or r12
63     lldb_r13w_x86_64, // Low 16 bits or r13
64     lldb_r14w_x86_64, // Low 16 bits or r14
65     lldb_r15w_x86_64, // Low 16 bits or r15
66     lldb_ah_x86_64,     lldb_bh_x86_64,     lldb_ch_x86_64,  lldb_dh_x86_64,
67     lldb_al_x86_64,     lldb_bl_x86_64,     lldb_cl_x86_64,  lldb_dl_x86_64,
68     lldb_dil_x86_64,    lldb_sil_x86_64,    lldb_bpl_x86_64, lldb_spl_x86_64,
69     lldb_r8l_x86_64,    // Low 8 bits or r8
70     lldb_r9l_x86_64,    // Low 8 bits or r9
71     lldb_r10l_x86_64,   // Low 8 bits or r10
72     lldb_r11l_x86_64,   // Low 8 bits or r11
73     lldb_r12l_x86_64,   // Low 8 bits or r12
74     lldb_r13l_x86_64,   // Low 8 bits or r13
75     lldb_r14l_x86_64,   // Low 8 bits or r14
76     lldb_r15l_x86_64,   // Low 8 bits or r15
77     LLDB_INVALID_REGNUM // register sets need to end with this flag
78 };
79 static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
80                       1 ==
81                   k_num_gpr_registers_x86_64,
82               "g_gpr_regnums_x86_64 has wrong number of register infos");
83 
84 // Number of register sets provided by this context.
85 enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 };
86 
87 // Register sets for x86 64-bit.
88 static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
89     {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
90      g_gpr_regnums_x86_64},
91 };
92 
93 #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
94 } // namespace
95 
96 NativeRegisterContextNetBSD *
97 NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
98     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
99   return new NativeRegisterContextNetBSD_x86_64(target_arch, native_thread);
100 }
101 
102 // NativeRegisterContextNetBSD_x86_64 members.
103 
104 static RegisterInfoInterface *
105 CreateRegisterInfoInterface(const ArchSpec &target_arch) {
106   assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
107          "Register setting path assumes this is a 64-bit host");
108   // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64
109   // register context.
110   return new RegisterContextNetBSD_x86_64(target_arch);
111 }
112 
113 NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64(
114     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
115     : NativeRegisterContextNetBSD(native_thread,
116                                   CreateRegisterInfoInterface(target_arch)),
117       m_gpr_x86_64(), m_fpr_x86_64(), m_dbr_x86_64() {}
118 
119 // CONSIDER after local and llgs debugging are merged, register set support can
120 // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
121 uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
122   uint32_t sets = 0;
123   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
124     if (GetSetForNativeRegNum(set_index) != -1)
125       ++sets;
126   }
127 
128   return sets;
129 }
130 
131 const RegisterSet *
132 NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
133   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
134   case llvm::Triple::x86_64:
135     return &g_reg_sets_x86_64[set_index];
136   default:
137     assert(false && "Unhandled target architecture.");
138     return nullptr;
139   }
140 
141   return nullptr;
142 }
143 
144 int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
145     int reg_num) const {
146   if (reg_num <= k_last_gpr_x86_64)
147     return GPRegSet;
148   else if (reg_num <= k_last_fpr_x86_64)
149     return FPRegSet;
150   else if (reg_num <= k_last_avx_x86_64)
151     return -1; // AVX
152   else if (reg_num <= k_last_mpxr_x86_64)
153     return -1; // MPXR
154   else if (reg_num <= k_last_mpxc_x86_64)
155     return -1; // MPXC
156   else if (reg_num <= lldb_dr7_x86_64)
157     return DBRegSet; // DBR
158   else
159     return -1;
160 }
161 
162 Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
163   switch (set) {
164   case GPRegSet:
165     return DoRegisterSet(PT_GETREGS, &m_gpr_x86_64);
166   case FPRegSet:
167     return DoRegisterSet(PT_GETFPREGS, &m_fpr_x86_64);
168   case DBRegSet:
169     return DoRegisterSet(PT_GETDBREGS, &m_dbr_x86_64);
170   }
171   llvm_unreachable("NativeRegisterContextNetBSD_x86_64::ReadRegisterSet");
172 }
173 
174 Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
175   switch (set) {
176   case GPRegSet:
177     return DoRegisterSet(PT_SETREGS, &m_gpr_x86_64);
178   case FPRegSet:
179     return DoRegisterSet(PT_SETFPREGS, &m_fpr_x86_64);
180   case DBRegSet:
181     return DoRegisterSet(PT_SETDBREGS, &m_dbr_x86_64);
182   }
183   llvm_unreachable("NativeRegisterContextNetBSD_x86_64::WriteRegisterSet");
184 }
185 
186 Status
187 NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
188                                                  RegisterValue &reg_value) {
189   Status error;
190 
191   if (!reg_info) {
192     error.SetErrorString("reg_info NULL");
193     return error;
194   }
195 
196   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
197   if (reg == LLDB_INVALID_REGNUM) {
198     // This is likely an internal register for lldb use only and should not be
199     // directly queried.
200     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
201                                    "register, cannot read directly",
202                                    reg_info->name);
203     return error;
204   }
205 
206   int set = GetSetForNativeRegNum(reg);
207   if (set == -1) {
208     // This is likely an internal register for lldb use only and should not be
209     // directly queried.
210     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
211                                    reg_info->name);
212     return error;
213   }
214 
215   error = ReadRegisterSet(set);
216   if (error.Fail())
217     return error;
218 
219   switch (reg) {
220   case lldb_rax_x86_64:
221     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX];
222     break;
223   case lldb_rbx_x86_64:
224     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX];
225     break;
226   case lldb_rcx_x86_64:
227     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX];
228     break;
229   case lldb_rdx_x86_64:
230     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX];
231     break;
232   case lldb_rdi_x86_64:
233     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI];
234     break;
235   case lldb_rsi_x86_64:
236     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI];
237     break;
238   case lldb_rbp_x86_64:
239     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP];
240     break;
241   case lldb_rsp_x86_64:
242     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP];
243     break;
244   case lldb_r8_x86_64:
245     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8];
246     break;
247   case lldb_r9_x86_64:
248     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9];
249     break;
250   case lldb_r10_x86_64:
251     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10];
252     break;
253   case lldb_r11_x86_64:
254     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11];
255     break;
256   case lldb_r12_x86_64:
257     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12];
258     break;
259   case lldb_r13_x86_64:
260     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13];
261     break;
262   case lldb_r14_x86_64:
263     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14];
264     break;
265   case lldb_r15_x86_64:
266     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15];
267     break;
268   case lldb_rip_x86_64:
269     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP];
270     break;
271   case lldb_rflags_x86_64:
272     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS];
273     break;
274   case lldb_cs_x86_64:
275     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS];
276     break;
277   case lldb_fs_x86_64:
278     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS];
279     break;
280   case lldb_gs_x86_64:
281     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS];
282     break;
283   case lldb_ss_x86_64:
284     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS];
285     break;
286   case lldb_ds_x86_64:
287     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS];
288     break;
289   case lldb_es_x86_64:
290     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
291     break;
292   case lldb_fctrl_x86_64:
293     reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_cw;
294     break;
295   case lldb_fstat_x86_64:
296     reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_sw;
297     break;
298   case lldb_ftag_x86_64:
299     reg_value = (uint8_t)m_fpr_x86_64.fxstate.fx_tw;
300     break;
301   case lldb_fop_x86_64:
302     reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_opcode;
303     break;
304   case lldb_fiseg_x86_64:
305     reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_ip.fa_64;
306     break;
307   case lldb_fioff_x86_64:
308     reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off;
309     break;
310   case lldb_foseg_x86_64:
311     reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_dp.fa_64;
312     break;
313   case lldb_fooff_x86_64:
314     reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off;
315     break;
316   case lldb_mxcsr_x86_64:
317     reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr;
318     break;
319   case lldb_mxcsrmask_x86_64:
320     reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr_mask;
321     break;
322   case lldb_st0_x86_64:
323   case lldb_st1_x86_64:
324   case lldb_st2_x86_64:
325   case lldb_st3_x86_64:
326   case lldb_st4_x86_64:
327   case lldb_st5_x86_64:
328   case lldb_st6_x86_64:
329   case lldb_st7_x86_64:
330     reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
331                        reg_info->byte_size, endian::InlHostByteOrder());
332     break;
333   case lldb_mm0_x86_64:
334   case lldb_mm1_x86_64:
335   case lldb_mm2_x86_64:
336   case lldb_mm3_x86_64:
337   case lldb_mm4_x86_64:
338   case lldb_mm5_x86_64:
339   case lldb_mm6_x86_64:
340   case lldb_mm7_x86_64:
341     reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64],
342                        reg_info->byte_size, endian::InlHostByteOrder());
343     break;
344   case lldb_xmm0_x86_64:
345   case lldb_xmm1_x86_64:
346   case lldb_xmm2_x86_64:
347   case lldb_xmm3_x86_64:
348   case lldb_xmm4_x86_64:
349   case lldb_xmm5_x86_64:
350   case lldb_xmm6_x86_64:
351   case lldb_xmm7_x86_64:
352   case lldb_xmm8_x86_64:
353   case lldb_xmm9_x86_64:
354   case lldb_xmm10_x86_64:
355   case lldb_xmm11_x86_64:
356   case lldb_xmm12_x86_64:
357   case lldb_xmm13_x86_64:
358   case lldb_xmm14_x86_64:
359   case lldb_xmm15_x86_64:
360     reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
361                        reg_info->byte_size, endian::InlHostByteOrder());
362     break;
363   case lldb_dr0_x86_64:
364   case lldb_dr1_x86_64:
365   case lldb_dr2_x86_64:
366   case lldb_dr3_x86_64:
367   case lldb_dr4_x86_64:
368   case lldb_dr5_x86_64:
369   case lldb_dr6_x86_64:
370   case lldb_dr7_x86_64:
371     reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64];
372     break;
373   }
374 
375   return error;
376 }
377 
378 Status NativeRegisterContextNetBSD_x86_64::WriteRegister(
379     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
380 
381   Status error;
382 
383   if (!reg_info) {
384     error.SetErrorString("reg_info NULL");
385     return error;
386   }
387 
388   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
389   if (reg == LLDB_INVALID_REGNUM) {
390     // This is likely an internal register for lldb use only and should not be
391     // directly queried.
392     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
393                                    "register, cannot read directly",
394                                    reg_info->name);
395     return error;
396   }
397 
398   int set = GetSetForNativeRegNum(reg);
399   if (set == -1) {
400     // This is likely an internal register for lldb use only and should not be
401     // directly queried.
402     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
403                                    reg_info->name);
404     return error;
405   }
406 
407   error = ReadRegisterSet(set);
408   if (error.Fail())
409     return error;
410 
411   switch (reg) {
412   case lldb_rax_x86_64:
413     m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64();
414     break;
415   case lldb_rbx_x86_64:
416     m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64();
417     break;
418   case lldb_rcx_x86_64:
419     m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64();
420     break;
421   case lldb_rdx_x86_64:
422     m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64();
423     break;
424   case lldb_rdi_x86_64:
425     m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64();
426     break;
427   case lldb_rsi_x86_64:
428     m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64();
429     break;
430   case lldb_rbp_x86_64:
431     m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64();
432     break;
433   case lldb_rsp_x86_64:
434     m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64();
435     break;
436   case lldb_r8_x86_64:
437     m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64();
438     break;
439   case lldb_r9_x86_64:
440     m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64();
441     break;
442   case lldb_r10_x86_64:
443     m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64();
444     break;
445   case lldb_r11_x86_64:
446     m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64();
447     break;
448   case lldb_r12_x86_64:
449     m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64();
450     break;
451   case lldb_r13_x86_64:
452     m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64();
453     break;
454   case lldb_r14_x86_64:
455     m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64();
456     break;
457   case lldb_r15_x86_64:
458     m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64();
459     break;
460   case lldb_rip_x86_64:
461     m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64();
462     break;
463   case lldb_rflags_x86_64:
464     m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64();
465     break;
466   case lldb_cs_x86_64:
467     m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64();
468     break;
469   case lldb_fs_x86_64:
470     m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64();
471     break;
472   case lldb_gs_x86_64:
473     m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64();
474     break;
475   case lldb_ss_x86_64:
476     m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64();
477     break;
478   case lldb_ds_x86_64:
479     m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64();
480     break;
481   case lldb_es_x86_64:
482     m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
483     break;
484   case lldb_fctrl_x86_64:
485     m_fpr_x86_64.fxstate.fx_cw = reg_value.GetAsUInt16();
486     break;
487   case lldb_fstat_x86_64:
488     m_fpr_x86_64.fxstate.fx_sw = reg_value.GetAsUInt16();
489     break;
490   case lldb_ftag_x86_64:
491     m_fpr_x86_64.fxstate.fx_tw = reg_value.GetAsUInt8();
492     break;
493   case lldb_fop_x86_64:
494     m_fpr_x86_64.fxstate.fx_opcode = reg_value.GetAsUInt16();
495     break;
496   case lldb_fiseg_x86_64:
497     m_fpr_x86_64.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64();
498     break;
499   case lldb_fioff_x86_64:
500     m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32();
501     break;
502   case lldb_foseg_x86_64:
503     m_fpr_x86_64.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64();
504     break;
505   case lldb_fooff_x86_64:
506     m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32();
507     break;
508   case lldb_mxcsr_x86_64:
509     m_fpr_x86_64.fxstate.fx_mxcsr = reg_value.GetAsUInt32();
510     break;
511   case lldb_mxcsrmask_x86_64:
512     m_fpr_x86_64.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32();
513     break;
514   case lldb_st0_x86_64:
515   case lldb_st1_x86_64:
516   case lldb_st2_x86_64:
517   case lldb_st3_x86_64:
518   case lldb_st4_x86_64:
519   case lldb_st5_x86_64:
520   case lldb_st6_x86_64:
521   case lldb_st7_x86_64:
522     ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
523              reg_value.GetBytes(), reg_value.GetByteSize());
524     break;
525   case lldb_mm0_x86_64:
526   case lldb_mm1_x86_64:
527   case lldb_mm2_x86_64:
528   case lldb_mm3_x86_64:
529   case lldb_mm4_x86_64:
530   case lldb_mm5_x86_64:
531   case lldb_mm6_x86_64:
532   case lldb_mm7_x86_64:
533     ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64],
534              reg_value.GetBytes(), reg_value.GetByteSize());
535     break;
536   case lldb_xmm0_x86_64:
537   case lldb_xmm1_x86_64:
538   case lldb_xmm2_x86_64:
539   case lldb_xmm3_x86_64:
540   case lldb_xmm4_x86_64:
541   case lldb_xmm5_x86_64:
542   case lldb_xmm6_x86_64:
543   case lldb_xmm7_x86_64:
544   case lldb_xmm8_x86_64:
545   case lldb_xmm9_x86_64:
546   case lldb_xmm10_x86_64:
547   case lldb_xmm11_x86_64:
548   case lldb_xmm12_x86_64:
549   case lldb_xmm13_x86_64:
550   case lldb_xmm14_x86_64:
551   case lldb_xmm15_x86_64:
552     ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
553              reg_value.GetBytes(), reg_value.GetByteSize());
554     break;
555   case lldb_dr0_x86_64:
556   case lldb_dr1_x86_64:
557   case lldb_dr2_x86_64:
558   case lldb_dr3_x86_64:
559   case lldb_dr4_x86_64:
560   case lldb_dr5_x86_64:
561   case lldb_dr6_x86_64:
562   case lldb_dr7_x86_64:
563     m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64();
564     break;
565   }
566 
567   return WriteRegisterSet(set);
568 }
569 
570 Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
571     lldb::DataBufferSP &data_sp) {
572   Status error;
573 
574   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
575   if (!data_sp) {
576     error.SetErrorStringWithFormat(
577         "failed to allocate DataBufferHeap instance of size %" PRIu64,
578         REG_CONTEXT_SIZE);
579     return error;
580   }
581 
582   error = ReadRegisterSet(GPRegSet);
583   if (error.Fail())
584     return error;
585 
586   uint8_t *dst = data_sp->GetBytes();
587   if (dst == nullptr) {
588     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
589                                    " returned a null pointer",
590                                    REG_CONTEXT_SIZE);
591     return error;
592   }
593 
594   ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());
595   dst += GetRegisterInfoInterface().GetGPRSize();
596 
597   RegisterValue value((uint64_t)-1);
598   const RegisterInfo *reg_info =
599       GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
600   if (reg_info == nullptr)
601     reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
602   return error;
603 }
604 
605 Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
606     const lldb::DataBufferSP &data_sp) {
607   Status error;
608 
609   if (!data_sp) {
610     error.SetErrorStringWithFormat(
611         "NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided",
612         __FUNCTION__);
613     return error;
614   }
615 
616   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
617     error.SetErrorStringWithFormat(
618         "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched "
619         "data size, expected %" PRIu64 ", actual %" PRIu64,
620         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
621     return error;
622   }
623 
624   uint8_t *src = data_sp->GetBytes();
625   if (src == nullptr) {
626     error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s "
627                                    "DataBuffer::GetBytes() returned a null "
628                                    "pointer",
629                                    __FUNCTION__);
630     return error;
631   }
632   ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize());
633 
634   error = WriteRegisterSet(GPRegSet);
635   if (error.Fail())
636     return error;
637   src += GetRegisterInfoInterface().GetGPRSize();
638 
639   return error;
640 }
641 
642 Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
643                                                            bool &is_hit) {
644   if (wp_index >= NumSupportedHardwareWatchpoints())
645     return Status("Watchpoint index out of range");
646 
647   RegisterValue reg_value;
648   const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64);
649   Status error = ReadRegister(reg_info, reg_value);
650   if (error.Fail()) {
651     is_hit = false;
652     return error;
653   }
654 
655   uint64_t status_bits = reg_value.GetAsUInt64();
656 
657   is_hit = status_bits & (1 << wp_index);
658 
659   return error;
660 }
661 
662 Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex(
663     uint32_t &wp_index, lldb::addr_t trap_addr) {
664   uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
665   for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
666     bool is_hit;
667     Status error = IsWatchpointHit(wp_index, is_hit);
668     if (error.Fail()) {
669       wp_index = LLDB_INVALID_INDEX32;
670       return error;
671     } else if (is_hit) {
672       return error;
673     }
674   }
675   wp_index = LLDB_INVALID_INDEX32;
676   return Status();
677 }
678 
679 Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
680                                                               bool &is_vacant) {
681   if (wp_index >= NumSupportedHardwareWatchpoints())
682     return Status("Watchpoint index out of range");
683 
684   RegisterValue reg_value;
685   const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64);
686   Status error = ReadRegister(reg_info, reg_value);
687   if (error.Fail()) {
688     is_vacant = false;
689     return error;
690   }
691 
692   uint64_t control_bits = reg_value.GetAsUInt64();
693 
694   is_vacant = !(control_bits & (1 << (2 * wp_index)));
695 
696   return error;
697 }
698 
699 Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex(
700     lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
701 
702   if (wp_index >= NumSupportedHardwareWatchpoints())
703     return Status("Watchpoint index out of range");
704 
705   // Read only watchpoints aren't supported on x86_64. Fall back to read/write
706   // waitchpoints instead.
707   // TODO: Add logic to detect when a write happens and ignore that watchpoint
708   // hit.
709   if (watch_flags == 0x2)
710     watch_flags = 0x3;
711 
712   if (watch_flags != 0x1 && watch_flags != 0x3)
713     return Status("Invalid read/write bits for watchpoint");
714 
715   if (size != 1 && size != 2 && size != 4 && size != 8)
716     return Status("Invalid size for watchpoint");
717 
718   bool is_vacant;
719   Status error = IsWatchpointVacant(wp_index, is_vacant);
720   if (error.Fail())
721     return error;
722   if (!is_vacant)
723     return Status("Watchpoint index not vacant");
724 
725   RegisterValue reg_value;
726   const RegisterInfo *const reg_info_dr7 =
727       GetRegisterInfoAtIndex(lldb_dr7_x86_64);
728   error = ReadRegister(reg_info_dr7, reg_value);
729   if (error.Fail())
730     return error;
731 
732   // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7
733   uint64_t enable_bit = 1 << (2 * wp_index);
734 
735   // set bits 16-17, 20-21, 24-25, or 28-29
736   // with 0b01 for write, and 0b11 for read/write
737   uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
738 
739   // set bits 18-19, 22-23, 26-27, or 30-31
740   // with 0b00, 0b01, 0b10, or 0b11
741   // for 1, 2, 8 (if supported), or 4 bytes, respectively
742   uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
743 
744   uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
745 
746   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
747 
748   control_bits |= enable_bit | rw_bits | size_bits;
749 
750   const RegisterInfo *const reg_info_drN =
751       GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
752   error = WriteRegister(reg_info_drN, RegisterValue(addr));
753   if (error.Fail())
754     return error;
755 
756   error = WriteRegister(reg_info_dr7, RegisterValue(control_bits));
757   if (error.Fail())
758     return error;
759 
760   error.Clear();
761   return error;
762 }
763 
764 bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint(
765     uint32_t wp_index) {
766   if (wp_index >= NumSupportedHardwareWatchpoints())
767     return false;
768 
769   RegisterValue reg_value;
770 
771   // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of
772   // the debug status register (DR6)
773   const RegisterInfo *const reg_info_dr6 =
774       GetRegisterInfoAtIndex(lldb_dr6_x86_64);
775   Status error = ReadRegister(reg_info_dr6, reg_value);
776   if (error.Fail())
777     return false;
778   uint64_t bit_mask = 1 << wp_index;
779   uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
780   error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
781   if (error.Fail())
782     return false;
783 
784   // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19},
785   // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register
786   // (DR7)
787   const RegisterInfo *const reg_info_dr7 =
788       GetRegisterInfoAtIndex(lldb_dr7_x86_64);
789   error = ReadRegister(reg_info_dr7, reg_value);
790   if (error.Fail())
791     return false;
792   bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
793   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
794   return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success();
795 }
796 
797 Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() {
798   RegisterValue reg_value;
799 
800   // clear bits {0-4} of the debug status register (DR6)
801   const RegisterInfo *const reg_info_dr6 =
802       GetRegisterInfoAtIndex(lldb_dr6_x86_64);
803   Status error = ReadRegister(reg_info_dr6, reg_value);
804   if (error.Fail())
805     return error;
806   uint64_t bit_mask = 0xF;
807   uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
808   error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
809   if (error.Fail())
810     return error;
811 
812   // clear bits {0-7,16-31} of the debug control register (DR7)
813   const RegisterInfo *const reg_info_dr7 =
814       GetRegisterInfoAtIndex(lldb_dr7_x86_64);
815   error = ReadRegister(reg_info_dr7, reg_value);
816   if (error.Fail())
817     return error;
818   bit_mask = 0xFF | (0xFFFF << 16);
819   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
820   return WriteRegister(reg_info_dr7, RegisterValue(control_bits));
821 }
822 
823 uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint(
824     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
825   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
826   const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
827   for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
828     bool is_vacant;
829     Status error = IsWatchpointVacant(wp_index, is_vacant);
830     if (is_vacant) {
831       error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
832       if (error.Success())
833         return wp_index;
834     }
835     if (error.Fail() && log) {
836       log->Printf("NativeRegisterContextNetBSD_x86_64::%s Error: %s",
837                   __FUNCTION__, error.AsCString());
838     }
839   }
840   return LLDB_INVALID_INDEX32;
841 }
842 
843 lldb::addr_t
844 NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
845   if (wp_index >= NumSupportedHardwareWatchpoints())
846     return LLDB_INVALID_ADDRESS;
847   RegisterValue reg_value;
848   const RegisterInfo *const reg_info_drN =
849       GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
850   if (ReadRegister(reg_info_drN, reg_value).Fail())
851     return LLDB_INVALID_ADDRESS;
852   return reg_value.GetAsUInt64();
853 }
854 
855 uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() {
856   // Available debug address registers: dr0, dr1, dr2, dr3
857   return 4;
858 }
859 
860 #endif // defined(__x86_64__)
861