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