1 //===-- NativeRegisterContextOpenBSD_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 "NativeRegisterContextOpenBSD_x86_64.h"
13 
14 #include <cpuid.h>
15 #include <elf.h>
16 #include <err.h>
17 #include <stdint.h>
18 #include <stdlib.h>
19 
20 #include "lldb/Host/HostInfo.h"
21 #include "lldb/Utility/DataBufferHeap.h"
22 #include "lldb/Utility/Log.h"
23 #include "lldb/Utility/RegisterValue.h"
24 #include "lldb/Utility/Status.h"
25 
26 #include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h"
27 #include "Plugins/Process/Utility/RegisterContext_x86.h"
28 
29 // clang-format off
30 #include <sys/types.h>
31 #include <sys/ptrace.h>
32 #include <sys/sysctl.h>
33 #include <sys/time.h>
34 #include <machine/cpu.h>
35 // clang-format on
36 
37 using namespace lldb_private;
38 using namespace lldb_private::process_openbsd;
39 
40 // ----------------------------------------------------------------------------
41 // Private namespace.
42 // ----------------------------------------------------------------------------
43 
44 namespace {
45 // x86 64-bit general purpose registers.
46 static const uint32_t g_gpr_regnums_x86_64[] = {
47     lldb_rax_x86_64,    lldb_rbx_x86_64,    lldb_rcx_x86_64,  lldb_rdx_x86_64,
48     lldb_rdi_x86_64,    lldb_rsi_x86_64,    lldb_rbp_x86_64,  lldb_rsp_x86_64,
49     lldb_r8_x86_64,     lldb_r9_x86_64,     lldb_r10_x86_64,  lldb_r11_x86_64,
50     lldb_r12_x86_64,    lldb_r13_x86_64,    lldb_r14_x86_64,  lldb_r15_x86_64,
51     lldb_rip_x86_64,    lldb_rflags_x86_64, lldb_cs_x86_64,   lldb_fs_x86_64,
52     lldb_gs_x86_64,     lldb_ss_x86_64,     lldb_ds_x86_64,   lldb_es_x86_64,
53     lldb_eax_x86_64,    lldb_ebx_x86_64,    lldb_ecx_x86_64,  lldb_edx_x86_64,
54     lldb_edi_x86_64,    lldb_esi_x86_64,    lldb_ebp_x86_64,  lldb_esp_x86_64,
55     lldb_r8d_x86_64,    lldb_r9d_x86_64,    lldb_r10d_x86_64, lldb_r11d_x86_64,
56     lldb_r12d_x86_64,   lldb_r13d_x86_64,   lldb_r14d_x86_64, lldb_r15d_x86_64,
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,    lldb_r9w_x86_64,    lldb_r10w_x86_64, lldb_r11w_x86_64,
60     lldb_r12w_x86_64,   lldb_r13w_x86_64,   lldb_r14w_x86_64, lldb_r15w_x86_64,
61     lldb_ah_x86_64,     lldb_bh_x86_64,     lldb_ch_x86_64,   lldb_dh_x86_64,
62     lldb_al_x86_64,     lldb_bl_x86_64,     lldb_cl_x86_64,   lldb_dl_x86_64,
63     lldb_dil_x86_64,    lldb_sil_x86_64,    lldb_bpl_x86_64,  lldb_spl_x86_64,
64     lldb_r8l_x86_64,    lldb_r9l_x86_64,    lldb_r10l_x86_64, lldb_r11l_x86_64,
65     lldb_r12l_x86_64,   lldb_r13l_x86_64,   lldb_r14l_x86_64, lldb_r15l_x86_64,
66     LLDB_INVALID_REGNUM // register sets need to end with this flag
67 };
68 static_assert(
69   (sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1
70       == k_num_gpr_registers_x86_64,
71   "g_gpr_regnums_x86_64 has wrong number of register infos");
72 
73 // x86 64-bit floating point registers.
74 static const uint32_t g_fpu_regnums_x86_64[] = {
75     lldb_fctrl_x86_64,     lldb_fstat_x86_64, lldb_ftag_x86_64,
76     lldb_fop_x86_64,       lldb_fiseg_x86_64, lldb_fioff_x86_64,
77     lldb_fip_x86_64,       lldb_foseg_x86_64, lldb_fooff_x86_64,
78     lldb_fdp_x86_64,       lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64,
79     lldb_st0_x86_64,       lldb_st1_x86_64,
80     lldb_st2_x86_64,       lldb_st3_x86_64,   lldb_st4_x86_64,
81     lldb_st5_x86_64,       lldb_st6_x86_64,   lldb_st7_x86_64,
82     lldb_mm0_x86_64,       lldb_mm1_x86_64,   lldb_mm2_x86_64,
83     lldb_mm3_x86_64,       lldb_mm4_x86_64,   lldb_mm5_x86_64,
84     lldb_mm6_x86_64,       lldb_mm7_x86_64,   lldb_xmm0_x86_64,
85     lldb_xmm1_x86_64,      lldb_xmm2_x86_64,  lldb_xmm3_x86_64,
86     lldb_xmm4_x86_64,      lldb_xmm5_x86_64,  lldb_xmm6_x86_64,
87     lldb_xmm7_x86_64,      lldb_xmm8_x86_64,  lldb_xmm9_x86_64,
88     lldb_xmm10_x86_64,     lldb_xmm11_x86_64, lldb_xmm12_x86_64,
89     lldb_xmm13_x86_64,     lldb_xmm14_x86_64, lldb_xmm15_x86_64,
90     LLDB_INVALID_REGNUM // register sets need to end with this flag
91 };
92 static_assert(
93   (sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1
94       == k_num_fpr_registers_x86_64,
95   "g_fpu_regnums_x86_64 has wrong number of register infos");
96 
97 static const uint32_t g_avx_regnums_x86_64[] = {
98     lldb_ymm0_x86_64,   lldb_ymm1_x86_64,  lldb_ymm2_x86_64,  lldb_ymm3_x86_64,
99     lldb_ymm4_x86_64,   lldb_ymm5_x86_64,  lldb_ymm6_x86_64,  lldb_ymm7_x86_64,
100     lldb_ymm8_x86_64,   lldb_ymm9_x86_64,  lldb_ymm10_x86_64, lldb_ymm11_x86_64,
101     lldb_ymm12_x86_64,  lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64,
102     LLDB_INVALID_REGNUM // register sets need to end with this flag
103 };
104 static_assert(
105   (sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1
106        == k_num_avx_registers_x86_64,
107   "g_avx_regnums_x86_64 has wrong number of register infos");
108 
109 // Number of register sets provided by this context.
110 enum { k_num_register_sets = 3 };
111 
112 // Register sets for x86 64-bit.
113 static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
114     {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
115      g_gpr_regnums_x86_64},
116     {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64,
117      g_fpu_regnums_x86_64},
118     {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
119      g_avx_regnums_x86_64},
120 };
121 
122 struct x86_fpu_addr {
123   uint32_t offset;
124   uint32_t selector;
125 };
126 
127 enum {
128   k_xsave_offset_legacy_region = 160,
129   k_xsave_offset_invalid = UINT32_MAX,
130 };
131 
132 } // namespace
133 
134 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
135 
136 std::unique_ptr<NativeRegisterContextOpenBSD>
CreateHostNativeRegisterContextOpenBSD(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)137 NativeRegisterContextOpenBSD::CreateHostNativeRegisterContextOpenBSD(
138     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
139   return std::make_unique<NativeRegisterContextOpenBSD_x86_64>(target_arch, native_thread);
140 }
141 
142 // ----------------------------------------------------------------------------
143 // NativeRegisterContextOpenBSD_x86_64 members.
144 // ----------------------------------------------------------------------------
145 
146 static RegisterInfoInterface *
CreateRegisterInfoInterface(const ArchSpec & target_arch)147 CreateRegisterInfoInterface(const ArchSpec &target_arch) {
148   assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
149          "Register setting path assumes this is a 64-bit host");
150   // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64
151   // register context.
152   return new RegisterContextOpenBSD_x86_64(target_arch);
153 }
154 
NativeRegisterContextOpenBSD_x86_64(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)155 NativeRegisterContextOpenBSD_x86_64::NativeRegisterContextOpenBSD_x86_64(
156     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
157     : NativeRegisterContextOpenBSD(native_thread,
158                                   CreateRegisterInfoInterface(target_arch)),
159       m_gpr(), m_fpr() {
160   uint32_t a, b, c, d;
161 
162   struct ptrace_xstate_info info;
163   const Status error = NativeProcessOpenBSD::PtraceWrapper(
164       PT_GETXSTATE_INFO, GetProcessPid(), &info, sizeof(info));
165   if (error.Success())
166       m_xsave.resize(info.xsave_len);
167 
168   __get_cpuid_count(0xd, 2, &a, &b, &c, &d);
169   m_xsave_offsets[YMMRegSet] = b > 0 ? b : k_xsave_offset_invalid;
170 }
171 
GetUserRegisterCount() const172 uint32_t NativeRegisterContextOpenBSD_x86_64::GetUserRegisterCount() const {
173 	uint32_t count = 0;
174 	for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
175 		count += g_reg_sets_x86_64[set_index].num_registers;
176 	return count;
177 }
178 
GetRegisterSetCount() const179 uint32_t NativeRegisterContextOpenBSD_x86_64::GetRegisterSetCount() const {
180   return k_num_register_sets;
181 }
182 
183 const RegisterSet *
GetRegisterSet(uint32_t set_index) const184 NativeRegisterContextOpenBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
185   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
186   case llvm::Triple::x86_64:
187     return &g_reg_sets_x86_64[set_index];
188   default:
189     assert(false && "Unhandled target architecture.");
190     return nullptr;
191   }
192 
193   return nullptr;
194 }
195 
GetSetForNativeRegNum(int reg_num) const196 int NativeRegisterContextOpenBSD_x86_64::GetSetForNativeRegNum(
197     int reg_num) const {
198   if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64)
199     return GPRegSet;
200   else if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64)
201     return FPRegSet;
202   else if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
203     return YMMRegSet;
204   else
205     return -1;
206 }
207 
ReadRegisterSet(uint32_t set)208 int NativeRegisterContextOpenBSD_x86_64::ReadRegisterSet(uint32_t set) {
209   switch (set) {
210   case GPRegSet:
211     ReadGPR();
212     return 0;
213   case FPRegSet:
214     ReadFPR();
215     return 0;
216   case YMMRegSet: {
217     const Status error = NativeProcessOpenBSD::PtraceWrapper(
218         PT_GETXSTATE, GetProcessPid(), m_xsave.data(), m_xsave.size());
219     return error.Success() ? 0 : -1;
220   }
221   default:
222     break;
223   }
224   return -1;
225 }
WriteRegisterSet(uint32_t set)226 int NativeRegisterContextOpenBSD_x86_64::WriteRegisterSet(uint32_t set) {
227   switch (set) {
228   case GPRegSet:
229     WriteGPR();
230     return 0;
231   case FPRegSet:
232     WriteFPR();
233     return 0;
234   case YMMRegSet: {
235     const Status error = NativeProcessOpenBSD::PtraceWrapper(
236         PT_SETXSTATE, GetProcessPid(), m_xsave.data(), m_xsave.size());
237     return error.Success() ? 0 : -1;
238   }
239   default:
240     break;
241   }
242   return -1;
243 }
244 
245 Status
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)246 NativeRegisterContextOpenBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
247                                                  RegisterValue &reg_value) {
248   Status error;
249 
250   if (!reg_info) {
251     error.SetErrorString("reg_info NULL");
252     return error;
253   }
254 
255   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
256   if (reg == LLDB_INVALID_REGNUM) {
257     // This is likely an internal register for lldb use only and should not be
258     // directly queried.
259     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
260                                    "register, cannot read directly",
261                                    reg_info->name);
262     return error;
263   }
264 
265   int set = GetSetForNativeRegNum(reg);
266   if (set == -1) {
267     // This is likely an internal register for lldb use only and should not be
268     // directly queried.
269     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
270                                    reg_info->name);
271     return error;
272   }
273 
274   if (ReadRegisterSet(set) != 0) {
275     // This is likely an internal register for lldb use only and should not be
276     // directly queried.
277     error.SetErrorStringWithFormat(
278         "reading register set for register \"%s\" failed", reg_info->name);
279     return error;
280   }
281 
282   switch (reg) {
283   case lldb_rax_x86_64:
284     reg_value = (uint64_t)m_gpr.r_rax;
285     break;
286   case lldb_rbx_x86_64:
287     reg_value = (uint64_t)m_gpr.r_rbx;
288     break;
289   case lldb_rcx_x86_64:
290     reg_value = (uint64_t)m_gpr.r_rcx;
291     break;
292   case lldb_rdx_x86_64:
293     reg_value = (uint64_t)m_gpr.r_rdx;
294     break;
295   case lldb_rdi_x86_64:
296     reg_value = (uint64_t)m_gpr.r_rdi;
297     break;
298   case lldb_rsi_x86_64:
299     reg_value = (uint64_t)m_gpr.r_rsi;
300     break;
301   case lldb_rbp_x86_64:
302     reg_value = (uint64_t)m_gpr.r_rbp;
303     break;
304   case lldb_rsp_x86_64:
305     reg_value = (uint64_t)m_gpr.r_rsp;
306     break;
307   case lldb_r8_x86_64:
308     reg_value = (uint64_t)m_gpr.r_r8;
309     break;
310   case lldb_r9_x86_64:
311     reg_value = (uint64_t)m_gpr.r_r9;
312     break;
313   case lldb_r10_x86_64:
314     reg_value = (uint64_t)m_gpr.r_r10;
315     break;
316   case lldb_r11_x86_64:
317     reg_value = (uint64_t)m_gpr.r_r11;
318     break;
319   case lldb_r12_x86_64:
320     reg_value = (uint64_t)m_gpr.r_r12;
321     break;
322   case lldb_r13_x86_64:
323     reg_value = (uint64_t)m_gpr.r_r13;
324     break;
325   case lldb_r14_x86_64:
326     reg_value = (uint64_t)m_gpr.r_r14;
327     break;
328   case lldb_r15_x86_64:
329     reg_value = (uint64_t)m_gpr.r_r15;
330     break;
331   case lldb_rip_x86_64:
332     reg_value = (uint64_t)m_gpr.r_rip;
333     break;
334   case lldb_rflags_x86_64:
335     reg_value = (uint64_t)m_gpr.r_rflags;
336     break;
337   case lldb_cs_x86_64:
338     reg_value = (uint64_t)m_gpr.r_cs;
339     break;
340   case lldb_fs_x86_64:
341     reg_value = (uint64_t)m_gpr.r_fs;
342     break;
343   case lldb_gs_x86_64:
344     reg_value = (uint64_t)m_gpr.r_gs;
345     break;
346   case lldb_ss_x86_64:
347     reg_value = (uint64_t)m_gpr.r_ss;
348     break;
349   case lldb_ds_x86_64:
350     reg_value = (uint64_t)m_gpr.r_ds;
351     break;
352   case lldb_es_x86_64:
353     reg_value = (uint64_t)m_gpr.r_es;
354     break;
355   case lldb_fctrl_x86_64:
356     reg_value = (uint16_t)m_fpr.fxstate.fx_fcw;
357     break;
358   case lldb_fstat_x86_64:
359     reg_value = (uint16_t)m_fpr.fxstate.fx_fsw;
360     break;
361   case lldb_ftag_x86_64:
362     reg_value = (uint8_t)m_fpr.fxstate.fx_ftw;
363     break;
364   case lldb_fop_x86_64:
365     reg_value = (uint64_t)m_fpr.fxstate.fx_fop;
366     break;
367   case lldb_fioff_x86_64:
368     {
369       struct x86_fpu_addr *fp = (struct x86_fpu_addr *)&m_fpr.fxstate.fx_rip;
370       reg_value = fp->offset;
371       break;
372     }
373   case lldb_fiseg_x86_64:
374     {
375       struct x86_fpu_addr *fp = (struct x86_fpu_addr *)&m_fpr.fxstate.fx_rip;
376       reg_value = fp->selector;
377       break;
378     }
379   case lldb_fooff_x86_64:
380     {
381       struct x86_fpu_addr *fp = (struct x86_fpu_addr *)&m_fpr.fxstate.fx_rdp;
382       reg_value = fp->offset;
383       break;
384     }
385   case lldb_foseg_x86_64:
386     {
387       struct x86_fpu_addr *fp = (struct x86_fpu_addr *)&m_fpr.fxstate.fx_rdp;
388       reg_value = fp->selector;
389       break;
390     }
391   case lldb_mxcsr_x86_64:
392     reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr;
393     break;
394   case lldb_mxcsrmask_x86_64:
395     reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr_mask;
396     break;
397   case lldb_st0_x86_64:
398   case lldb_st1_x86_64:
399   case lldb_st2_x86_64:
400   case lldb_st3_x86_64:
401   case lldb_st4_x86_64:
402   case lldb_st5_x86_64:
403   case lldb_st6_x86_64:
404   case lldb_st7_x86_64:
405     reg_value.SetBytes(&m_fpr.fxstate.fx_st[reg - lldb_st0_x86_64],
406                        reg_info->byte_size, endian::InlHostByteOrder());
407     break;
408   case lldb_mm0_x86_64:
409   case lldb_mm1_x86_64:
410   case lldb_mm2_x86_64:
411   case lldb_mm3_x86_64:
412   case lldb_mm4_x86_64:
413   case lldb_mm5_x86_64:
414   case lldb_mm6_x86_64:
415   case lldb_mm7_x86_64:
416     reg_value.SetBytes(&m_fpr.fxstate.fx_st[reg - lldb_mm0_x86_64],
417                        reg_info->byte_size, endian::InlHostByteOrder());
418     break;
419   case lldb_xmm0_x86_64:
420   case lldb_xmm1_x86_64:
421   case lldb_xmm2_x86_64:
422   case lldb_xmm3_x86_64:
423   case lldb_xmm4_x86_64:
424   case lldb_xmm5_x86_64:
425   case lldb_xmm6_x86_64:
426   case lldb_xmm7_x86_64:
427   case lldb_xmm8_x86_64:
428   case lldb_xmm9_x86_64:
429   case lldb_xmm10_x86_64:
430   case lldb_xmm11_x86_64:
431   case lldb_xmm12_x86_64:
432   case lldb_xmm13_x86_64:
433   case lldb_xmm14_x86_64:
434   case lldb_xmm15_x86_64:
435     reg_value.SetBytes(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
436                        reg_info->byte_size, endian::InlHostByteOrder());
437     break;
438   }
439 
440   if (set == YMMRegSet) {
441     std::optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
442     if (ymm_reg) {
443       YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi);
444       reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
445                          endian::InlHostByteOrder());
446     } else {
447       error.SetErrorStringWithFormat("register \"%s\" not supported",
448                                      reg_info->name);
449     }
450   }
451 
452   return error;
453 }
454 
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)455 Status NativeRegisterContextOpenBSD_x86_64::WriteRegister(
456     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
457 
458   Status error;
459 
460   if (!reg_info) {
461     error.SetErrorString("reg_info NULL");
462     return error;
463   }
464 
465   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
466   if (reg == LLDB_INVALID_REGNUM) {
467     // This is likely an internal register for lldb use only and should not be
468     // directly queried.
469     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
470                                    "register, cannot read directly",
471                                    reg_info->name);
472     return error;
473   }
474 
475   int set = GetSetForNativeRegNum(reg);
476   if (set == -1) {
477     // This is likely an internal register for lldb use only and should not be
478     // directly queried.
479     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
480                                    reg_info->name);
481     return error;
482   }
483 
484   if (ReadRegisterSet(set) != 0) {
485     // This is likely an internal register for lldb use only and should not be
486     // directly queried.
487     error.SetErrorStringWithFormat(
488         "reading register set for register \"%s\" failed", reg_info->name);
489     return error;
490   }
491 
492   switch (reg) {
493   case lldb_rax_x86_64:
494     m_gpr.r_rax = reg_value.GetAsUInt64();
495     break;
496   case lldb_rbx_x86_64:
497     m_gpr.r_rbx = reg_value.GetAsUInt64();
498     break;
499   case lldb_rcx_x86_64:
500     m_gpr.r_rcx = reg_value.GetAsUInt64();
501     break;
502   case lldb_rdx_x86_64:
503     m_gpr.r_rdx = reg_value.GetAsUInt64();
504     break;
505   case lldb_rdi_x86_64:
506     m_gpr.r_rdi = reg_value.GetAsUInt64();
507     break;
508   case lldb_rsi_x86_64:
509     m_gpr.r_rsi = reg_value.GetAsUInt64();
510     break;
511   case lldb_rbp_x86_64:
512     m_gpr.r_rbp = reg_value.GetAsUInt64();
513     break;
514   case lldb_rsp_x86_64:
515     m_gpr.r_rsp = reg_value.GetAsUInt64();
516     break;
517   case lldb_r8_x86_64:
518     m_gpr.r_r8 = reg_value.GetAsUInt64();
519     break;
520   case lldb_r9_x86_64:
521     m_gpr.r_r9 = reg_value.GetAsUInt64();
522     break;
523   case lldb_r10_x86_64:
524     m_gpr.r_r10 = reg_value.GetAsUInt64();
525     break;
526   case lldb_r11_x86_64:
527     m_gpr.r_r11 = reg_value.GetAsUInt64();
528     break;
529   case lldb_r12_x86_64:
530     m_gpr.r_r12 = reg_value.GetAsUInt64();
531     break;
532   case lldb_r13_x86_64:
533     m_gpr.r_r13 = reg_value.GetAsUInt64();
534     break;
535   case lldb_r14_x86_64:
536     m_gpr.r_r14 = reg_value.GetAsUInt64();
537     break;
538   case lldb_r15_x86_64:
539     m_gpr.r_r15 = reg_value.GetAsUInt64();
540     break;
541   case lldb_rip_x86_64:
542     m_gpr.r_rip = reg_value.GetAsUInt64();
543     break;
544   case lldb_rflags_x86_64:
545     m_gpr.r_rflags = reg_value.GetAsUInt64();
546     break;
547   case lldb_cs_x86_64:
548     m_gpr.r_cs = reg_value.GetAsUInt64();
549     break;
550   case lldb_fs_x86_64:
551     m_gpr.r_fs = reg_value.GetAsUInt64();
552     break;
553   case lldb_gs_x86_64:
554     m_gpr.r_gs = reg_value.GetAsUInt64();
555     break;
556   case lldb_ss_x86_64:
557     m_gpr.r_ss = reg_value.GetAsUInt64();
558     break;
559   case lldb_ds_x86_64:
560     m_gpr.r_ds = reg_value.GetAsUInt64();
561     break;
562   case lldb_es_x86_64:
563     m_gpr.r_es = reg_value.GetAsUInt64();
564     break;
565   case lldb_fctrl_x86_64:
566     m_fpr.fxstate.fx_fcw = reg_value.GetAsUInt16();
567     break;
568   case lldb_fstat_x86_64:
569     m_fpr.fxstate.fx_fsw = reg_value.GetAsUInt16();
570     break;
571   case lldb_ftag_x86_64:
572     m_fpr.fxstate.fx_ftw = reg_value.GetAsUInt8();
573     break;
574   case lldb_fop_x86_64:
575     m_fpr.fxstate.fx_fop = reg_value.GetAsUInt16();
576     break;
577   case lldb_fioff_x86_64:
578     {
579       struct x86_fpu_addr *fp = (struct x86_fpu_addr *)&m_fpr.fxstate.fx_rip;
580       fp->offset = reg_value.GetAsUInt32();
581       break;
582     }
583   case lldb_fiseg_x86_64:
584     {
585       struct x86_fpu_addr *fp = (struct x86_fpu_addr *)&m_fpr.fxstate.fx_rip;
586       fp->selector = reg_value.GetAsUInt32();
587       break;
588     }
589   case lldb_fooff_x86_64:
590     {
591       struct x86_fpu_addr *fp = (struct x86_fpu_addr *)&m_fpr.fxstate.fx_rdp;
592       fp->offset = reg_value.GetAsUInt32();
593       break;
594     }
595   case lldb_foseg_x86_64:
596     {
597       struct x86_fpu_addr *fp = (struct x86_fpu_addr *)&m_fpr.fxstate.fx_rdp;
598       fp->selector = reg_value.GetAsUInt32();
599       break;
600     }
601   case lldb_mxcsr_x86_64:
602     m_fpr.fxstate.fx_mxcsr = reg_value.GetAsUInt32();
603     break;
604   case lldb_mxcsrmask_x86_64:
605     m_fpr.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32();
606     break;
607   case lldb_st0_x86_64:
608   case lldb_st1_x86_64:
609   case lldb_st2_x86_64:
610   case lldb_st3_x86_64:
611   case lldb_st4_x86_64:
612   case lldb_st5_x86_64:
613   case lldb_st6_x86_64:
614   case lldb_st7_x86_64:
615     ::memcpy(&m_fpr.fxstate.fx_st[reg - lldb_st0_x86_64],
616              reg_value.GetBytes(), reg_value.GetByteSize());
617     break;
618   case lldb_mm0_x86_64:
619   case lldb_mm1_x86_64:
620   case lldb_mm2_x86_64:
621   case lldb_mm3_x86_64:
622   case lldb_mm4_x86_64:
623   case lldb_mm5_x86_64:
624   case lldb_mm6_x86_64:
625   case lldb_mm7_x86_64:
626     ::memcpy(&m_fpr.fxstate.fx_st[reg - lldb_mm0_x86_64],
627              reg_value.GetBytes(), reg_value.GetByteSize());
628     break;
629   case lldb_xmm0_x86_64:
630   case lldb_xmm1_x86_64:
631   case lldb_xmm2_x86_64:
632   case lldb_xmm3_x86_64:
633   case lldb_xmm4_x86_64:
634   case lldb_xmm5_x86_64:
635   case lldb_xmm6_x86_64:
636   case lldb_xmm7_x86_64:
637   case lldb_xmm8_x86_64:
638   case lldb_xmm9_x86_64:
639   case lldb_xmm10_x86_64:
640   case lldb_xmm11_x86_64:
641   case lldb_xmm12_x86_64:
642   case lldb_xmm13_x86_64:
643   case lldb_xmm14_x86_64:
644   case lldb_xmm15_x86_64:
645     ::memcpy(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
646              reg_value.GetBytes(), reg_value.GetByteSize());
647     break;
648   }
649 
650   if (set == YMMRegSet) {
651     std::optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
652     if (!ymm_reg) {
653       error.SetErrorStringWithFormat("register \"%s\" not supported",
654                                      reg_info->name);
655       return error;
656     }
657     YMMReg ymm;
658     ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
659     YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi);
660   }
661 
662   if (WriteRegisterSet(set) != 0)
663     error.SetErrorStringWithFormat("failed to write register set");
664 
665   return error;
666 }
667 
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)668 Status NativeRegisterContextOpenBSD_x86_64::ReadAllRegisterValues(
669     lldb::WritableDataBufferSP &data_sp) {
670   Status error;
671 
672   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
673   if (!data_sp) {
674     error.SetErrorStringWithFormat(
675         "failed to allocate DataBufferHeap instance of size %zu",
676         REG_CONTEXT_SIZE);
677     return error;
678   }
679 
680   uint8_t *dst = data_sp->GetBytes();
681   if (dst == nullptr) {
682     error.SetErrorStringWithFormat("DataBufferHeap instance of size %zu"
683                                    " returned a null pointer",
684                                    REG_CONTEXT_SIZE);
685     return error;
686   }
687 
688   error = ReadGPR();
689   if (error.Fail())
690     return error;
691   ::memcpy(dst, &m_gpr, GetGPRSize());
692   dst += GetGPRSize();
693 
694   error = ReadFPR();
695   if (error.Fail())
696     return error;
697   ::memcpy(dst, &m_fpr, GetFPRSize());
698   dst += GetFPRSize();
699 
700   return error;
701 }
702 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)703 Status NativeRegisterContextOpenBSD_x86_64::WriteAllRegisterValues(
704     const lldb::DataBufferSP &data_sp) {
705   Status error;
706 
707   if (!data_sp) {
708     error.SetErrorStringWithFormat(
709         "NativeRegisterContextOpenBSD_x86_64::%s invalid data_sp provided",
710         __FUNCTION__);
711     return error;
712   }
713 
714   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
715     error.SetErrorStringWithFormat(
716         "NativeRegisterContextOpenBSD_x86_64::%s data_sp contained mismatched "
717         "data size, expected %zu, actual %llu",
718         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
719     return error;
720   }
721 
722   const uint8_t *src = data_sp->GetBytes();
723   if (src == nullptr) {
724     error.SetErrorStringWithFormat("NativeRegisterContextOpenBSD_x86_64::%s "
725                                    "DataBuffer::GetBytes() returned a null "
726                                    "pointer",
727                                    __FUNCTION__);
728     return error;
729   }
730 
731   ::memcpy(&m_gpr, src, GetGPRSize());
732   error = WriteGPR();
733   if (error.Fail())
734     return error;
735   src += GetGPRSize();
736 
737   ::memcpy(&m_fpr, src, GetFPRSize());
738   error = WriteFPR();
739   if (error.Fail())
740     return error;
741   src += GetFPRSize();
742 
743   return error;
744 }
745 
746 std::optional<NativeRegisterContextOpenBSD_x86_64::YMMSplitPtr>
GetYMMSplitReg(uint32_t reg)747 NativeRegisterContextOpenBSD_x86_64::GetYMMSplitReg(uint32_t reg) {
748   if (m_xsave_offsets[YMMRegSet] == k_xsave_offset_invalid)
749     return std::nullopt;
750 
751   uint32_t reg_index = reg - lldb_ymm0_x86_64;
752   auto *xmm =
753       reinterpret_cast<XMMReg *>(m_xsave.data() + k_xsave_offset_legacy_region);
754   auto *ymm =
755       reinterpret_cast<XMMReg *>(m_xsave.data() + m_xsave_offsets[YMMRegSet]);
756   return YMMSplitPtr{&xmm[reg_index], &ymm[reg_index]};
757 }
758 
759 #endif
760