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 int NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
214   switch (set) {
215   case GPRegSet:
216     ReadGPR();
217     return 0;
218   case FPRegSet:
219     ReadFPR();
220     return 0;
221   case DBRegSet:
222     ReadDBR();
223     return 0;
224   default:
225     break;
226   }
227   return -1;
228 }
229 int NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
230   switch (set) {
231   case GPRegSet:
232     WriteGPR();
233     return 0;
234   case FPRegSet:
235     WriteFPR();
236     return 0;
237   case DBRegSet:
238     WriteDBR();
239     return 0;
240   default:
241     break;
242   }
243   return -1;
244 }
245 
246 Status
247 NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
248                                                  RegisterValue &reg_value) {
249   Status error;
250 
251   if (!reg_info) {
252     error.SetErrorString("reg_info NULL");
253     return error;
254   }
255 
256   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
257   if (reg == LLDB_INVALID_REGNUM) {
258     // This is likely an internal register for lldb use only and should not be
259     // directly queried.
260     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
261                                    "register, cannot read directly",
262                                    reg_info->name);
263     return error;
264   }
265 
266   int set = GetSetForNativeRegNum(reg);
267   if (set == -1) {
268     // This is likely an internal register for lldb use only and should not be
269     // directly queried.
270     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
271                                    reg_info->name);
272     return error;
273   }
274 
275   if (ReadRegisterSet(set) != 0) {
276     // This is likely an internal register for lldb use only and should not be
277     // directly queried.
278     error.SetErrorStringWithFormat(
279         "reading register set for register \"%s\" failed", reg_info->name);
280     return error;
281   }
282 
283   switch (reg) {
284   case lldb_rax_x86_64:
285     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX];
286     break;
287   case lldb_rbx_x86_64:
288     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX];
289     break;
290   case lldb_rcx_x86_64:
291     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX];
292     break;
293   case lldb_rdx_x86_64:
294     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX];
295     break;
296   case lldb_rdi_x86_64:
297     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI];
298     break;
299   case lldb_rsi_x86_64:
300     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI];
301     break;
302   case lldb_rbp_x86_64:
303     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP];
304     break;
305   case lldb_rsp_x86_64:
306     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP];
307     break;
308   case lldb_r8_x86_64:
309     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8];
310     break;
311   case lldb_r9_x86_64:
312     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9];
313     break;
314   case lldb_r10_x86_64:
315     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10];
316     break;
317   case lldb_r11_x86_64:
318     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11];
319     break;
320   case lldb_r12_x86_64:
321     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12];
322     break;
323   case lldb_r13_x86_64:
324     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13];
325     break;
326   case lldb_r14_x86_64:
327     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14];
328     break;
329   case lldb_r15_x86_64:
330     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15];
331     break;
332   case lldb_rip_x86_64:
333     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP];
334     break;
335   case lldb_rflags_x86_64:
336     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS];
337     break;
338   case lldb_cs_x86_64:
339     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS];
340     break;
341   case lldb_fs_x86_64:
342     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS];
343     break;
344   case lldb_gs_x86_64:
345     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS];
346     break;
347   case lldb_ss_x86_64:
348     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS];
349     break;
350   case lldb_ds_x86_64:
351     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS];
352     break;
353   case lldb_es_x86_64:
354     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
355     break;
356   case lldb_fctrl_x86_64:
357     reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_cw;
358     break;
359   case lldb_fstat_x86_64:
360     reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_sw;
361     break;
362   case lldb_ftag_x86_64:
363     reg_value = (uint8_t)m_fpr_x86_64.fxstate.fx_tw;
364     break;
365   case lldb_fop_x86_64:
366     reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_opcode;
367     break;
368   case lldb_fiseg_x86_64:
369     reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_ip.fa_64;
370     break;
371   case lldb_fioff_x86_64:
372     reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off;
373     break;
374   case lldb_foseg_x86_64:
375     reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_dp.fa_64;
376     break;
377   case lldb_fooff_x86_64:
378     reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off;
379     break;
380   case lldb_mxcsr_x86_64:
381     reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr;
382     break;
383   case lldb_mxcsrmask_x86_64:
384     reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr_mask;
385     break;
386   case lldb_st0_x86_64:
387   case lldb_st1_x86_64:
388   case lldb_st2_x86_64:
389   case lldb_st3_x86_64:
390   case lldb_st4_x86_64:
391   case lldb_st5_x86_64:
392   case lldb_st6_x86_64:
393   case lldb_st7_x86_64:
394     reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
395                        reg_info->byte_size, endian::InlHostByteOrder());
396     break;
397   case lldb_mm0_x86_64:
398   case lldb_mm1_x86_64:
399   case lldb_mm2_x86_64:
400   case lldb_mm3_x86_64:
401   case lldb_mm4_x86_64:
402   case lldb_mm5_x86_64:
403   case lldb_mm6_x86_64:
404   case lldb_mm7_x86_64:
405     reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64],
406                        reg_info->byte_size, endian::InlHostByteOrder());
407     break;
408   case lldb_xmm0_x86_64:
409   case lldb_xmm1_x86_64:
410   case lldb_xmm2_x86_64:
411   case lldb_xmm3_x86_64:
412   case lldb_xmm4_x86_64:
413   case lldb_xmm5_x86_64:
414   case lldb_xmm6_x86_64:
415   case lldb_xmm7_x86_64:
416   case lldb_xmm8_x86_64:
417   case lldb_xmm9_x86_64:
418   case lldb_xmm10_x86_64:
419   case lldb_xmm11_x86_64:
420   case lldb_xmm12_x86_64:
421   case lldb_xmm13_x86_64:
422   case lldb_xmm14_x86_64:
423   case lldb_xmm15_x86_64:
424     reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
425                        reg_info->byte_size, endian::InlHostByteOrder());
426     break;
427   case lldb_dr0_x86_64:
428   case lldb_dr1_x86_64:
429   case lldb_dr2_x86_64:
430   case lldb_dr3_x86_64:
431   case lldb_dr4_x86_64:
432   case lldb_dr5_x86_64:
433   case lldb_dr6_x86_64:
434   case lldb_dr7_x86_64:
435     reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64];
436     break;
437   }
438 
439   return error;
440 }
441 
442 Status NativeRegisterContextNetBSD_x86_64::WriteRegister(
443     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
444 
445   Status error;
446 
447   if (!reg_info) {
448     error.SetErrorString("reg_info NULL");
449     return error;
450   }
451 
452   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
453   if (reg == LLDB_INVALID_REGNUM) {
454     // This is likely an internal register for lldb use only and should not be
455     // directly queried.
456     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
457                                    "register, cannot read directly",
458                                    reg_info->name);
459     return error;
460   }
461 
462   int set = GetSetForNativeRegNum(reg);
463   if (set == -1) {
464     // This is likely an internal register for lldb use only and should not be
465     // directly queried.
466     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
467                                    reg_info->name);
468     return error;
469   }
470 
471   if (ReadRegisterSet(set) != 0) {
472     // This is likely an internal register for lldb use only and should not be
473     // directly queried.
474     error.SetErrorStringWithFormat(
475         "reading register set for register \"%s\" failed", reg_info->name);
476     return error;
477   }
478 
479   switch (reg) {
480   case lldb_rax_x86_64:
481     m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64();
482     break;
483   case lldb_rbx_x86_64:
484     m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64();
485     break;
486   case lldb_rcx_x86_64:
487     m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64();
488     break;
489   case lldb_rdx_x86_64:
490     m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64();
491     break;
492   case lldb_rdi_x86_64:
493     m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64();
494     break;
495   case lldb_rsi_x86_64:
496     m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64();
497     break;
498   case lldb_rbp_x86_64:
499     m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64();
500     break;
501   case lldb_rsp_x86_64:
502     m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64();
503     break;
504   case lldb_r8_x86_64:
505     m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64();
506     break;
507   case lldb_r9_x86_64:
508     m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64();
509     break;
510   case lldb_r10_x86_64:
511     m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64();
512     break;
513   case lldb_r11_x86_64:
514     m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64();
515     break;
516   case lldb_r12_x86_64:
517     m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64();
518     break;
519   case lldb_r13_x86_64:
520     m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64();
521     break;
522   case lldb_r14_x86_64:
523     m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64();
524     break;
525   case lldb_r15_x86_64:
526     m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64();
527     break;
528   case lldb_rip_x86_64:
529     m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64();
530     break;
531   case lldb_rflags_x86_64:
532     m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64();
533     break;
534   case lldb_cs_x86_64:
535     m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64();
536     break;
537   case lldb_fs_x86_64:
538     m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64();
539     break;
540   case lldb_gs_x86_64:
541     m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64();
542     break;
543   case lldb_ss_x86_64:
544     m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64();
545     break;
546   case lldb_ds_x86_64:
547     m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64();
548     break;
549   case lldb_es_x86_64:
550     m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
551     break;
552   case lldb_fctrl_x86_64:
553     m_fpr_x86_64.fxstate.fx_cw = reg_value.GetAsUInt16();
554     break;
555   case lldb_fstat_x86_64:
556     m_fpr_x86_64.fxstate.fx_sw = reg_value.GetAsUInt16();
557     break;
558   case lldb_ftag_x86_64:
559     m_fpr_x86_64.fxstate.fx_tw = reg_value.GetAsUInt8();
560     break;
561   case lldb_fop_x86_64:
562     m_fpr_x86_64.fxstate.fx_opcode = reg_value.GetAsUInt16();
563     break;
564   case lldb_fiseg_x86_64:
565     m_fpr_x86_64.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64();
566     break;
567   case lldb_fioff_x86_64:
568     m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32();
569     break;
570   case lldb_foseg_x86_64:
571     m_fpr_x86_64.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64();
572     break;
573   case lldb_fooff_x86_64:
574     m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32();
575     break;
576   case lldb_mxcsr_x86_64:
577     m_fpr_x86_64.fxstate.fx_mxcsr = reg_value.GetAsUInt32();
578     break;
579   case lldb_mxcsrmask_x86_64:
580     m_fpr_x86_64.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32();
581     break;
582   case lldb_st0_x86_64:
583   case lldb_st1_x86_64:
584   case lldb_st2_x86_64:
585   case lldb_st3_x86_64:
586   case lldb_st4_x86_64:
587   case lldb_st5_x86_64:
588   case lldb_st6_x86_64:
589   case lldb_st7_x86_64:
590     ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
591              reg_value.GetBytes(), reg_value.GetByteSize());
592     break;
593   case lldb_mm0_x86_64:
594   case lldb_mm1_x86_64:
595   case lldb_mm2_x86_64:
596   case lldb_mm3_x86_64:
597   case lldb_mm4_x86_64:
598   case lldb_mm5_x86_64:
599   case lldb_mm6_x86_64:
600   case lldb_mm7_x86_64:
601     ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64],
602              reg_value.GetBytes(), reg_value.GetByteSize());
603     break;
604   case lldb_xmm0_x86_64:
605   case lldb_xmm1_x86_64:
606   case lldb_xmm2_x86_64:
607   case lldb_xmm3_x86_64:
608   case lldb_xmm4_x86_64:
609   case lldb_xmm5_x86_64:
610   case lldb_xmm6_x86_64:
611   case lldb_xmm7_x86_64:
612   case lldb_xmm8_x86_64:
613   case lldb_xmm9_x86_64:
614   case lldb_xmm10_x86_64:
615   case lldb_xmm11_x86_64:
616   case lldb_xmm12_x86_64:
617   case lldb_xmm13_x86_64:
618   case lldb_xmm14_x86_64:
619   case lldb_xmm15_x86_64:
620     ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
621              reg_value.GetBytes(), reg_value.GetByteSize());
622     break;
623   case lldb_dr0_x86_64:
624   case lldb_dr1_x86_64:
625   case lldb_dr2_x86_64:
626   case lldb_dr3_x86_64:
627   case lldb_dr4_x86_64:
628   case lldb_dr5_x86_64:
629   case lldb_dr6_x86_64:
630   case lldb_dr7_x86_64:
631     m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64();
632     break;
633   }
634 
635   if (WriteRegisterSet(set) != 0)
636     error.SetErrorStringWithFormat("failed to write register set");
637 
638   return error;
639 }
640 
641 Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
642     lldb::DataBufferSP &data_sp) {
643   Status error;
644 
645   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
646   if (!data_sp) {
647     error.SetErrorStringWithFormat(
648         "failed to allocate DataBufferHeap instance of size %" PRIu64,
649         REG_CONTEXT_SIZE);
650     return error;
651   }
652 
653   error = ReadGPR();
654   if (error.Fail())
655     return error;
656 
657   uint8_t *dst = data_sp->GetBytes();
658   if (dst == nullptr) {
659     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
660                                    " returned a null pointer",
661                                    REG_CONTEXT_SIZE);
662     return error;
663   }
664 
665   ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());
666   dst += GetRegisterInfoInterface().GetGPRSize();
667 
668   RegisterValue value((uint64_t)-1);
669   const RegisterInfo *reg_info =
670       GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
671   if (reg_info == nullptr)
672     reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
673   return error;
674 }
675 
676 Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
677     const lldb::DataBufferSP &data_sp) {
678   Status error;
679 
680   if (!data_sp) {
681     error.SetErrorStringWithFormat(
682         "NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided",
683         __FUNCTION__);
684     return error;
685   }
686 
687   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
688     error.SetErrorStringWithFormat(
689         "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched "
690         "data size, expected %" PRIu64 ", actual %" PRIu64,
691         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
692     return error;
693   }
694 
695   uint8_t *src = data_sp->GetBytes();
696   if (src == nullptr) {
697     error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s "
698                                    "DataBuffer::GetBytes() returned a null "
699                                    "pointer",
700                                    __FUNCTION__);
701     return error;
702   }
703   ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize());
704 
705   error = WriteGPR();
706   if (error.Fail())
707     return error;
708   src += GetRegisterInfoInterface().GetGPRSize();
709 
710   return error;
711 }
712 
713 Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
714                                                            bool &is_hit) {
715   if (wp_index >= NumSupportedHardwareWatchpoints())
716     return Status("Watchpoint index out of range");
717 
718   RegisterValue reg_value;
719   const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64);
720   Status error = ReadRegister(reg_info, reg_value);
721   if (error.Fail()) {
722     is_hit = false;
723     return error;
724   }
725 
726   uint64_t status_bits = reg_value.GetAsUInt64();
727 
728   is_hit = status_bits & (1 << wp_index);
729 
730   return error;
731 }
732 
733 Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex(
734     uint32_t &wp_index, lldb::addr_t trap_addr) {
735   uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
736   for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
737     bool is_hit;
738     Status error = IsWatchpointHit(wp_index, is_hit);
739     if (error.Fail()) {
740       wp_index = LLDB_INVALID_INDEX32;
741       return error;
742     } else if (is_hit) {
743       return error;
744     }
745   }
746   wp_index = LLDB_INVALID_INDEX32;
747   return Status();
748 }
749 
750 Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
751                                                               bool &is_vacant) {
752   if (wp_index >= NumSupportedHardwareWatchpoints())
753     return Status("Watchpoint index out of range");
754 
755   RegisterValue reg_value;
756   const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64);
757   Status error = ReadRegister(reg_info, reg_value);
758   if (error.Fail()) {
759     is_vacant = false;
760     return error;
761   }
762 
763   uint64_t control_bits = reg_value.GetAsUInt64();
764 
765   is_vacant = !(control_bits & (1 << (2 * wp_index)));
766 
767   return error;
768 }
769 
770 Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex(
771     lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
772 
773   if (wp_index >= NumSupportedHardwareWatchpoints())
774     return Status("Watchpoint index out of range");
775 
776   // Read only watchpoints aren't supported on x86_64. Fall back to read/write
777   // waitchpoints instead.
778   // TODO: Add logic to detect when a write happens and ignore that watchpoint
779   // hit.
780   if (watch_flags == 0x2)
781     watch_flags = 0x3;
782 
783   if (watch_flags != 0x1 && watch_flags != 0x3)
784     return Status("Invalid read/write bits for watchpoint");
785 
786   if (size != 1 && size != 2 && size != 4 && size != 8)
787     return Status("Invalid size for watchpoint");
788 
789   bool is_vacant;
790   Status error = IsWatchpointVacant(wp_index, is_vacant);
791   if (error.Fail())
792     return error;
793   if (!is_vacant)
794     return Status("Watchpoint index not vacant");
795 
796   RegisterValue reg_value;
797   const RegisterInfo *const reg_info_dr7 =
798       GetRegisterInfoAtIndex(lldb_dr7_x86_64);
799   error = ReadRegister(reg_info_dr7, reg_value);
800   if (error.Fail())
801     return error;
802 
803   // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7
804   uint64_t enable_bit = 1 << (2 * wp_index);
805 
806   // set bits 16-17, 20-21, 24-25, or 28-29
807   // with 0b01 for write, and 0b11 for read/write
808   uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
809 
810   // set bits 18-19, 22-23, 26-27, or 30-31
811   // with 0b00, 0b01, 0b10, or 0b11
812   // for 1, 2, 8 (if supported), or 4 bytes, respectively
813   uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
814 
815   uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
816 
817   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
818 
819   control_bits |= enable_bit | rw_bits | size_bits;
820 
821   const RegisterInfo *const reg_info_drN =
822       GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
823   error = WriteRegister(reg_info_drN, RegisterValue(addr));
824   if (error.Fail())
825     return error;
826 
827   error = WriteRegister(reg_info_dr7, RegisterValue(control_bits));
828   if (error.Fail())
829     return error;
830 
831   error.Clear();
832   return error;
833 }
834 
835 bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint(
836     uint32_t wp_index) {
837   if (wp_index >= NumSupportedHardwareWatchpoints())
838     return false;
839 
840   RegisterValue reg_value;
841 
842   // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of
843   // the debug status register (DR6)
844   const RegisterInfo *const reg_info_dr6 =
845       GetRegisterInfoAtIndex(lldb_dr6_x86_64);
846   Status error = ReadRegister(reg_info_dr6, reg_value);
847   if (error.Fail())
848     return false;
849   uint64_t bit_mask = 1 << wp_index;
850   uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
851   error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
852   if (error.Fail())
853     return false;
854 
855   // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19},
856   // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register
857   // (DR7)
858   const RegisterInfo *const reg_info_dr7 =
859       GetRegisterInfoAtIndex(lldb_dr7_x86_64);
860   error = ReadRegister(reg_info_dr7, reg_value);
861   if (error.Fail())
862     return false;
863   bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
864   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
865   return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success();
866 }
867 
868 Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() {
869   RegisterValue reg_value;
870 
871   // clear bits {0-4} of the debug status register (DR6)
872   const RegisterInfo *const reg_info_dr6 =
873       GetRegisterInfoAtIndex(lldb_dr6_x86_64);
874   Status error = ReadRegister(reg_info_dr6, reg_value);
875   if (error.Fail())
876     return error;
877   uint64_t bit_mask = 0xF;
878   uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
879   error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
880   if (error.Fail())
881     return error;
882 
883   // clear bits {0-7,16-31} of the debug control register (DR7)
884   const RegisterInfo *const reg_info_dr7 =
885       GetRegisterInfoAtIndex(lldb_dr7_x86_64);
886   error = ReadRegister(reg_info_dr7, reg_value);
887   if (error.Fail())
888     return error;
889   bit_mask = 0xFF | (0xFFFF << 16);
890   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
891   return WriteRegister(reg_info_dr7, RegisterValue(control_bits));
892 }
893 
894 uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint(
895     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
896   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
897   const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
898   for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
899     bool is_vacant;
900     Status error = IsWatchpointVacant(wp_index, is_vacant);
901     if (is_vacant) {
902       error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
903       if (error.Success())
904         return wp_index;
905     }
906     if (error.Fail() && log) {
907       log->Printf("NativeRegisterContextNetBSD_x86_64::%s Error: %s",
908                   __FUNCTION__, error.AsCString());
909     }
910   }
911   return LLDB_INVALID_INDEX32;
912 }
913 
914 lldb::addr_t
915 NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
916   if (wp_index >= NumSupportedHardwareWatchpoints())
917     return LLDB_INVALID_ADDRESS;
918   RegisterValue reg_value;
919   const RegisterInfo *const reg_info_drN =
920       GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
921   if (ReadRegister(reg_info_drN, reg_value).Fail())
922     return LLDB_INVALID_ADDRESS;
923   return reg_value.GetAsUInt64();
924 }
925 
926 uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() {
927   // Available debug address registers: dr0, dr1, dr2, dr3
928   return 4;
929 }
930 
931 #endif // defined(__x86_64__)
932