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