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