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