1 //===-- NativeRegisterContextFreeBSD_x86_64.cpp ---------------------------===//
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(__i386__) || defined(__x86_64__)
10 
11 #include "NativeRegisterContextFreeBSD_x86_64.h"
12 
13 // clang-format off
14 #include <x86/fpu.h>
15 #include <x86/specialreg.h>
16 #include <cpuid.h>
17 // clang-format on
18 
19 #include "lldb/Host/HostInfo.h"
20 #include "lldb/Utility/DataBufferHeap.h"
21 #include "lldb/Utility/Log.h"
22 #include "lldb/Utility/RegisterValue.h"
23 #include "lldb/Utility/Status.h"
24 
25 #include "NativeProcessFreeBSD.h"
26 #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
27 #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
28 
29 using namespace lldb_private;
30 using namespace lldb_private::process_freebsd;
31 
32 // x86 64-bit general purpose registers.
33 static const uint32_t g_gpr_regnums_x86_64[] = {
34     lldb_rax_x86_64,    lldb_rbx_x86_64,    lldb_rcx_x86_64, lldb_rdx_x86_64,
35     lldb_rdi_x86_64,    lldb_rsi_x86_64,    lldb_rbp_x86_64, lldb_rsp_x86_64,
36     lldb_r8_x86_64,     lldb_r9_x86_64,     lldb_r10_x86_64, lldb_r11_x86_64,
37     lldb_r12_x86_64,    lldb_r13_x86_64,    lldb_r14_x86_64, lldb_r15_x86_64,
38     lldb_rip_x86_64,    lldb_rflags_x86_64, lldb_cs_x86_64,  lldb_fs_x86_64,
39     lldb_gs_x86_64,     lldb_ss_x86_64,     lldb_ds_x86_64,  lldb_es_x86_64,
40     lldb_eax_x86_64,    lldb_ebx_x86_64,    lldb_ecx_x86_64, lldb_edx_x86_64,
41     lldb_edi_x86_64,    lldb_esi_x86_64,    lldb_ebp_x86_64, lldb_esp_x86_64,
42     lldb_r8d_x86_64,  // Low 32 bits or r8
43     lldb_r9d_x86_64,  // Low 32 bits or r9
44     lldb_r10d_x86_64, // Low 32 bits or r10
45     lldb_r11d_x86_64, // Low 32 bits or r11
46     lldb_r12d_x86_64, // Low 32 bits or r12
47     lldb_r13d_x86_64, // Low 32 bits or r13
48     lldb_r14d_x86_64, // Low 32 bits or r14
49     lldb_r15d_x86_64, // Low 32 bits or r15
50     lldb_ax_x86_64,     lldb_bx_x86_64,     lldb_cx_x86_64,  lldb_dx_x86_64,
51     lldb_di_x86_64,     lldb_si_x86_64,     lldb_bp_x86_64,  lldb_sp_x86_64,
52     lldb_r8w_x86_64,  // Low 16 bits or r8
53     lldb_r9w_x86_64,  // Low 16 bits or r9
54     lldb_r10w_x86_64, // Low 16 bits or r10
55     lldb_r11w_x86_64, // Low 16 bits or r11
56     lldb_r12w_x86_64, // Low 16 bits or r12
57     lldb_r13w_x86_64, // Low 16 bits or r13
58     lldb_r14w_x86_64, // Low 16 bits or r14
59     lldb_r15w_x86_64, // Low 16 bits or r15
60     lldb_ah_x86_64,     lldb_bh_x86_64,     lldb_ch_x86_64,  lldb_dh_x86_64,
61     lldb_al_x86_64,     lldb_bl_x86_64,     lldb_cl_x86_64,  lldb_dl_x86_64,
62     lldb_dil_x86_64,    lldb_sil_x86_64,    lldb_bpl_x86_64, lldb_spl_x86_64,
63     lldb_r8l_x86_64,    // Low 8 bits or r8
64     lldb_r9l_x86_64,    // Low 8 bits or r9
65     lldb_r10l_x86_64,   // Low 8 bits or r10
66     lldb_r11l_x86_64,   // Low 8 bits or r11
67     lldb_r12l_x86_64,   // Low 8 bits or r12
68     lldb_r13l_x86_64,   // Low 8 bits or r13
69     lldb_r14l_x86_64,   // Low 8 bits or r14
70     lldb_r15l_x86_64,   // Low 8 bits or r15
71     LLDB_INVALID_REGNUM // register sets need to end with this flag
72 };
73 static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
74                       1 ==
75                   k_num_gpr_registers_x86_64,
76               "g_gpr_regnums_x86_64 has wrong number of register infos");
77 
78 // x86 64-bit floating point registers.
79 static const uint32_t g_fpu_regnums_x86_64[] = {
80     lldb_fctrl_x86_64,  lldb_fstat_x86_64, lldb_ftag_x86_64,
81     lldb_fop_x86_64,    lldb_fiseg_x86_64, lldb_fioff_x86_64,
82     lldb_fip_x86_64,    lldb_foseg_x86_64, lldb_fooff_x86_64,
83     lldb_fdp_x86_64,    lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64,
84     lldb_st0_x86_64,    lldb_st1_x86_64,   lldb_st2_x86_64,
85     lldb_st3_x86_64,    lldb_st4_x86_64,   lldb_st5_x86_64,
86     lldb_st6_x86_64,    lldb_st7_x86_64,   lldb_mm0_x86_64,
87     lldb_mm1_x86_64,    lldb_mm2_x86_64,   lldb_mm3_x86_64,
88     lldb_mm4_x86_64,    lldb_mm5_x86_64,   lldb_mm6_x86_64,
89     lldb_mm7_x86_64,    lldb_xmm0_x86_64,  lldb_xmm1_x86_64,
90     lldb_xmm2_x86_64,   lldb_xmm3_x86_64,  lldb_xmm4_x86_64,
91     lldb_xmm5_x86_64,   lldb_xmm6_x86_64,  lldb_xmm7_x86_64,
92     lldb_xmm8_x86_64,   lldb_xmm9_x86_64,  lldb_xmm10_x86_64,
93     lldb_xmm11_x86_64,  lldb_xmm12_x86_64, lldb_xmm13_x86_64,
94     lldb_xmm14_x86_64,  lldb_xmm15_x86_64,
95     LLDB_INVALID_REGNUM // register sets need to end with this flag
96 };
97 static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) -
98                       1 ==
99                   k_num_fpr_registers_x86_64,
100               "g_fpu_regnums_x86_64 has wrong number of register infos");
101 
102 static const uint32_t g_avx_regnums_x86_64[] = {
103     lldb_ymm0_x86_64,   lldb_ymm1_x86_64,  lldb_ymm2_x86_64,  lldb_ymm3_x86_64,
104     lldb_ymm4_x86_64,   lldb_ymm5_x86_64,  lldb_ymm6_x86_64,  lldb_ymm7_x86_64,
105     lldb_ymm8_x86_64,   lldb_ymm9_x86_64,  lldb_ymm10_x86_64, lldb_ymm11_x86_64,
106     lldb_ymm12_x86_64,  lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64,
107     LLDB_INVALID_REGNUM // register sets need to end with this flag
108 };
109 static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) -
110                       1 ==
111                   k_num_avx_registers_x86_64,
112               "g_avx_regnums_x86_64 has wrong number of register infos");
113 
114 static const uint32_t g_mpx_regnums_x86_64[] = {
115     // Note: we currently do not provide them but this is needed to avoid
116     // unnamed groups in SBFrame::GetRegisterContext().
117     lldb_bnd0_x86_64,   lldb_bnd1_x86_64,    lldb_bnd2_x86_64,
118     lldb_bnd3_x86_64,   lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
119     LLDB_INVALID_REGNUM // register sets need to end with this flag
120 };
121 static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) -
122                       1 ==
123                   k_num_mpx_registers_x86_64,
124               "g_mpx_regnums_x86_64 has wrong number of register infos");
125 
126 // x86 debug registers.
127 static const uint32_t g_dbr_regnums_x86_64[] = {
128     lldb_dr0_x86_64,    lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64,
129     lldb_dr4_x86_64,    lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64,
130     LLDB_INVALID_REGNUM // register sets need to end with this flag
131 };
132 static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) -
133                       1 ==
134                   k_num_dbr_registers_x86_64,
135               "g_dbr_regnums_x86_64 has wrong number of register infos");
136 
137 // x86 32-bit general purpose registers.
138 static const uint32_t g_gpr_regnums_i386[] = {
139     lldb_eax_i386,      lldb_ebx_i386,    lldb_ecx_i386, lldb_edx_i386,
140     lldb_edi_i386,      lldb_esi_i386,    lldb_ebp_i386, lldb_esp_i386,
141     lldb_eip_i386,      lldb_eflags_i386, lldb_cs_i386,  lldb_fs_i386,
142     lldb_gs_i386,       lldb_ss_i386,     lldb_ds_i386,  lldb_es_i386,
143     lldb_ax_i386,       lldb_bx_i386,     lldb_cx_i386,  lldb_dx_i386,
144     lldb_di_i386,       lldb_si_i386,     lldb_bp_i386,  lldb_sp_i386,
145     lldb_ah_i386,       lldb_bh_i386,     lldb_ch_i386,  lldb_dh_i386,
146     lldb_al_i386,       lldb_bl_i386,     lldb_cl_i386,  lldb_dl_i386,
147     LLDB_INVALID_REGNUM // register sets need to end with this flag
148 };
149 static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) -
150                       1 ==
151                   k_num_gpr_registers_i386,
152               "g_gpr_regnums_i386 has wrong number of register infos");
153 
154 // x86 32-bit floating point registers.
155 static const uint32_t g_fpu_regnums_i386[] = {
156     lldb_fctrl_i386,    lldb_fstat_i386,     lldb_ftag_i386,  lldb_fop_i386,
157     lldb_fiseg_i386,    lldb_fioff_i386,     lldb_foseg_i386, lldb_fooff_i386,
158     lldb_mxcsr_i386,    lldb_mxcsrmask_i386, lldb_st0_i386,   lldb_st1_i386,
159     lldb_st2_i386,      lldb_st3_i386,       lldb_st4_i386,   lldb_st5_i386,
160     lldb_st6_i386,      lldb_st7_i386,       lldb_mm0_i386,   lldb_mm1_i386,
161     lldb_mm2_i386,      lldb_mm3_i386,       lldb_mm4_i386,   lldb_mm5_i386,
162     lldb_mm6_i386,      lldb_mm7_i386,       lldb_xmm0_i386,  lldb_xmm1_i386,
163     lldb_xmm2_i386,     lldb_xmm3_i386,      lldb_xmm4_i386,  lldb_xmm5_i386,
164     lldb_xmm6_i386,     lldb_xmm7_i386,
165     LLDB_INVALID_REGNUM // register sets need to end with this flag
166 };
167 static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) -
168                       1 ==
169                   k_num_fpr_registers_i386,
170               "g_fpu_regnums_i386 has wrong number of register infos");
171 
172 static const uint32_t g_avx_regnums_i386[] = {
173     lldb_ymm0_i386,     lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386,
174     lldb_ymm4_i386,     lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386,
175     LLDB_INVALID_REGNUM // register sets need to end with this flag
176 };
177 static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) -
178                       1 ==
179                   k_num_avx_registers_i386,
180               "g_avx_regnums_i386 has wrong number of register infos");
181 
182 static const uint32_t g_mpx_regnums_i386[] = {
183     // Note: we currently do not provide them but this is needed to avoid
184     // unnamed groups in SBFrame::GetRegisterContext().
185     lldb_bnd0_i386,     lldb_bnd1_i386,    lldb_bnd2_i386,
186     lldb_bnd3_i386,     lldb_bndcfgu_i386, lldb_bndstatus_i386,
187     LLDB_INVALID_REGNUM // register sets need to end with this flag
188 };
189 static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) -
190                       1 ==
191                   k_num_mpx_registers_i386,
192               "g_mpx_regnums_i386 has wrong number of register infos");
193 
194 // x86 debug registers.
195 static const uint32_t g_dbr_regnums_i386[] = {
196     lldb_dr0_i386,      lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386,
197     lldb_dr4_i386,      lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386,
198     LLDB_INVALID_REGNUM // register sets need to end with this flag
199 };
200 static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) -
201                       1 ==
202                   k_num_dbr_registers_i386,
203               "g_dbr_regnums_i386 has wrong number of register infos");
204 
205 // Number of register sets provided by this context.
206 enum { k_num_register_sets = 5 };
207 
208 // Register sets for x86 32-bit.
209 static const RegisterSet g_reg_sets_i386[k_num_register_sets] = {
210     {"General Purpose Registers", "gpr", k_num_gpr_registers_i386,
211      g_gpr_regnums_i386},
212     {"Floating Point Registers", "fpu", k_num_fpr_registers_i386,
213      g_fpu_regnums_i386},
214     {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386},
215     {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
216      g_avx_regnums_i386},
217     {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386,
218      g_mpx_regnums_i386},
219 };
220 
221 // Register sets for x86 64-bit.
222 static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
223     {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
224      g_gpr_regnums_x86_64},
225     {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64,
226      g_fpu_regnums_x86_64},
227     {"Debug Registers", "dbr", k_num_dbr_registers_x86_64,
228      g_dbr_regnums_x86_64},
229     {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
230      g_avx_regnums_x86_64},
231     {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64,
232      g_mpx_regnums_x86_64},
233 };
234 
235 #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
236 
237 NativeRegisterContextFreeBSD *
238 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
239     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
240   return new NativeRegisterContextFreeBSD_x86_64(target_arch, native_thread);
241 }
242 
243 // NativeRegisterContextFreeBSD_x86_64 members.
244 
245 static RegisterInfoInterface *
246 CreateRegisterInfoInterface(const ArchSpec &target_arch) {
247   if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
248     // 32-bit hosts run with a RegisterContextFreeBSD_i386 context.
249     return new RegisterContextFreeBSD_i386(target_arch);
250   } else {
251     assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
252            "Register setting path assumes this is a 64-bit host");
253     // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the
254     // x86_64 register context.
255     return new RegisterContextFreeBSD_x86_64(target_arch);
256   }
257 }
258 
259 NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64(
260     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
261     : NativeRegisterContextRegisterInfo(
262           native_thread, CreateRegisterInfoInterface(target_arch)),
263       m_regset_offsets({0}) {
264   assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize());
265   std::array<uint32_t, MaxRegSet + 1> first_regnos;
266 
267   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
268   case llvm::Triple::x86:
269     first_regnos[FPRegSet] = lldb_fctrl_i386;
270     first_regnos[DBRegSet] = lldb_dr0_i386;
271     break;
272   case llvm::Triple::x86_64:
273     first_regnos[FPRegSet] = lldb_fctrl_x86_64;
274     first_regnos[DBRegSet] = lldb_dr0_x86_64;
275     break;
276   default:
277     llvm_unreachable("Unhandled target architecture.");
278   }
279 
280   for (int i : {FPRegSet, DBRegSet})
281     m_regset_offsets[i] = GetRegisterInfoInterface()
282                               .GetRegisterInfo()[first_regnos[i]]
283                               .byte_offset;
284 }
285 
286 uint32_t NativeRegisterContextFreeBSD_x86_64::GetRegisterSetCount() const {
287   return k_num_register_sets;
288 }
289 
290 const RegisterSet *
291 NativeRegisterContextFreeBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
292   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
293   case llvm::Triple::x86:
294     return &g_reg_sets_i386[set_index];
295   case llvm::Triple::x86_64:
296     return &g_reg_sets_x86_64[set_index];
297   default:
298     llvm_unreachable("Unhandled target architecture.");
299   }
300 }
301 
302 llvm::Optional<NativeRegisterContextFreeBSD_x86_64::RegSetKind>
303 NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum(
304     uint32_t reg_num) const {
305   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
306   case llvm::Triple::x86:
307     if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386)
308       return GPRegSet;
309     if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386)
310       return FPRegSet;
311     if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386)
312       return YMMRegSet;
313     if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386)
314       return llvm::None; // MPXR
315     if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386)
316       return llvm::None; // MPXC
317     if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386)
318       return DBRegSet; // DBR
319     break;
320   case llvm::Triple::x86_64:
321     if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64)
322       return GPRegSet;
323     if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64)
324       return FPRegSet;
325     if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
326       return YMMRegSet;
327     if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64)
328       return llvm::None; // MPXR
329     if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64)
330       return llvm::None; // MPXC
331     if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64)
332       return DBRegSet; // DBR
333     break;
334   default:
335     llvm_unreachable("Unhandled target architecture.");
336   }
337 
338   llvm_unreachable("Register does not belong to any register set");
339 }
340 
341 Status NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet(RegSetKind set) {
342   switch (set) {
343   case GPRegSet:
344     return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
345                                                m_gpr.data());
346   case FPRegSet:
347 #if defined(__x86_64__)
348     return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(),
349                                                m_fpr.data());
350 #else
351     return NativeProcessFreeBSD::PtraceWrapper(PT_GETXMMREGS, m_thread.GetID(),
352                                                m_fpr.data());
353 #endif
354   case DBRegSet:
355     return NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, m_thread.GetID(),
356                                                m_dbr.data());
357   case YMMRegSet:
358   case MPXRegSet: {
359     struct ptrace_xstate_info info;
360     Status ret = NativeProcessFreeBSD::PtraceWrapper(
361         PT_GETXSTATE_INFO, GetProcessPid(), &info, sizeof(info));
362     if (!ret.Success())
363       return ret;
364 
365     assert(info.xsave_mask & XFEATURE_ENABLED_X87);
366     assert(info.xsave_mask & XFEATURE_ENABLED_SSE);
367 
368     m_xsave_offsets[YMMRegSet] = LLDB_INVALID_XSAVE_OFFSET;
369     if (info.xsave_mask & XFEATURE_ENABLED_YMM_HI128) {
370       uint32_t eax, ecx, edx;
371       __get_cpuid_count(0x0D, 2, &eax, &m_xsave_offsets[YMMRegSet], &ecx, &edx);
372     }
373 
374     m_xsave.resize(info.xsave_len);
375     return NativeProcessFreeBSD::PtraceWrapper(PT_GETXSTATE, GetProcessPid(),
376                                                m_xsave.data(), m_xsave.size());
377   }
378   }
379   llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet");
380 }
381 
382 Status NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet(RegSetKind set) {
383   switch (set) {
384   case GPRegSet:
385     return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
386                                                m_gpr.data());
387   case FPRegSet:
388 #if defined(__x86_64__)
389     return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(),
390                                                m_fpr.data());
391 #else
392     return NativeProcessFreeBSD::PtraceWrapper(PT_SETXMMREGS, m_thread.GetID(),
393                                                m_fpr.data());
394 #endif
395   case DBRegSet:
396     return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(),
397                                                m_dbr.data());
398   case YMMRegSet:
399   case MPXRegSet:
400     // ReadRegisterSet() must always be called before WriteRegisterSet().
401     assert(m_xsave.size() > 0);
402     return NativeProcessFreeBSD::PtraceWrapper(PT_SETXSTATE, GetProcessPid(),
403                                                m_xsave.data(), m_xsave.size());
404   }
405   llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet");
406 }
407 
408 Status
409 NativeRegisterContextFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
410                                                   RegisterValue &reg_value) {
411   Status error;
412 
413   if (!reg_info) {
414     error.SetErrorString("reg_info NULL");
415     return error;
416   }
417 
418   uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
419   if (reg == LLDB_INVALID_REGNUM) {
420     // This is likely an internal register for lldb use only and should not be
421     // directly queried.
422     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
423                                    "register, cannot read directly",
424                                    reg_info->name);
425     return error;
426   }
427 
428   llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
429   if (!opt_set) {
430     // This is likely an internal register for lldb use only and should not be
431     // directly queried.
432     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
433                                    reg_info->name);
434     return error;
435   }
436 
437   RegSetKind set = opt_set.getValue();
438   error = ReadRegisterSet(set);
439   if (error.Fail())
440     return error;
441 
442   switch (set) {
443   case GPRegSet:
444   case FPRegSet:
445   case DBRegSet: {
446     void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
447     FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_fpr.data());
448     if (data == &fpr->ftag) // ftag
449       reg_value.SetUInt16(
450           AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm));
451     else
452       reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder());
453     break;
454   }
455   case YMMRegSet: {
456     llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
457     if (!ymm_reg) {
458       error.SetErrorStringWithFormat(
459           "register \"%s\" not supported by CPU/kernel", reg_info->name);
460     } else {
461       YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi);
462       reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
463                          endian::InlHostByteOrder());
464     }
465     break;
466   }
467   case MPXRegSet:
468     llvm_unreachable("MPX regset should have returned error");
469   }
470 
471   return error;
472 }
473 
474 Status NativeRegisterContextFreeBSD_x86_64::WriteRegister(
475     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
476 
477   Status error;
478 
479   if (!reg_info) {
480     error.SetErrorString("reg_info NULL");
481     return error;
482   }
483 
484   uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
485   if (reg == LLDB_INVALID_REGNUM) {
486     // This is likely an internal register for lldb use only and should not be
487     // directly queried.
488     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
489                                    "register, cannot read directly",
490                                    reg_info->name);
491     return error;
492   }
493 
494   llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
495   if (!opt_set) {
496     // This is likely an internal register for lldb use only and should not be
497     // directly queried.
498     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
499                                    reg_info->name);
500     return error;
501   }
502 
503   RegSetKind set = opt_set.getValue();
504   error = ReadRegisterSet(set);
505   if (error.Fail())
506     return error;
507 
508   switch (set) {
509   case GPRegSet:
510   case FPRegSet:
511   case DBRegSet: {
512     void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
513     FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_fpr.data());
514     if (data == &fpr->ftag) // ftag
515       fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16());
516     else
517       ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize());
518     break;
519   }
520   case YMMRegSet: {
521     llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
522     if (!ymm_reg) {
523       error.SetErrorStringWithFormat(
524           "register \"%s\" not supported by CPU/kernel", reg_info->name);
525     } else {
526       YMMReg ymm;
527       ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
528       YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi);
529     }
530     break;
531   }
532   case MPXRegSet:
533     llvm_unreachable("MPX regset should have returned error");
534   }
535 
536   return WriteRegisterSet(set);
537 }
538 
539 Status NativeRegisterContextFreeBSD_x86_64::ReadAllRegisterValues(
540     lldb::DataBufferSP &data_sp) {
541   Status error;
542 
543   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
544   error = ReadRegisterSet(GPRegSet);
545   if (error.Fail())
546     return error;
547 
548   uint8_t *dst = data_sp->GetBytes();
549   ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize());
550   dst += GetRegisterInfoInterface().GetGPRSize();
551 
552   return error;
553 }
554 
555 Status NativeRegisterContextFreeBSD_x86_64::WriteAllRegisterValues(
556     const lldb::DataBufferSP &data_sp) {
557   Status error;
558 
559   if (!data_sp) {
560     error.SetErrorStringWithFormat(
561         "NativeRegisterContextFreeBSD_x86_64::%s invalid data_sp provided",
562         __FUNCTION__);
563     return error;
564   }
565 
566   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
567     error.SetErrorStringWithFormat(
568         "NativeRegisterContextFreeBSD_x86_64::%s data_sp contained mismatched "
569         "data size, expected %zu, actual %" PRIu64,
570         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
571     return error;
572   }
573 
574   uint8_t *src = data_sp->GetBytes();
575   if (src == nullptr) {
576     error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_x86_64::%s "
577                                    "DataBuffer::GetBytes() returned a null "
578                                    "pointer",
579                                    __FUNCTION__);
580     return error;
581   }
582   ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize());
583 
584   error = WriteRegisterSet(GPRegSet);
585   if (error.Fail())
586     return error;
587   src += GetRegisterInfoInterface().GetGPRSize();
588 
589   return error;
590 }
591 
592 llvm::Error NativeRegisterContextFreeBSD_x86_64::CopyHardwareWatchpointsFrom(
593     NativeRegisterContextFreeBSD &source) {
594   auto &r_source = static_cast<NativeRegisterContextFreeBSD_x86_64 &>(source);
595   // NB: This implicitly reads the whole dbreg set.
596   RegisterValue dr7;
597   Status res = r_source.ReadRegister(GetDR(7), dr7);
598   if (!res.Fail()) {
599     // copy dbregs only if any watchpoints were set
600     if ((dr7.GetAsUInt64() & 0xFF) == 0)
601       return llvm::Error::success();
602 
603     m_dbr = r_source.m_dbr;
604     res = WriteRegisterSet(DBRegSet);
605   }
606   return res.ToError();
607 }
608 
609 uint8_t *
610 NativeRegisterContextFreeBSD_x86_64::GetOffsetRegSetData(RegSetKind set,
611                                                          size_t reg_offset) {
612   uint8_t *base;
613   switch (set) {
614   case GPRegSet:
615     base = m_gpr.data();
616     break;
617   case FPRegSet:
618     base = m_fpr.data();
619     break;
620   case DBRegSet:
621     base = m_dbr.data();
622     break;
623   case YMMRegSet:
624     llvm_unreachable("GetRegSetData() is unsuitable for this regset.");
625   case MPXRegSet:
626     llvm_unreachable("MPX regset should have returned error");
627   }
628   assert(reg_offset >= m_regset_offsets[set]);
629   return base + (reg_offset - m_regset_offsets[set]);
630 }
631 
632 llvm::Optional<NativeRegisterContextFreeBSD_x86_64::YMMSplitPtr>
633 NativeRegisterContextFreeBSD_x86_64::GetYMMSplitReg(uint32_t reg) {
634   uint32_t offset = m_xsave_offsets[YMMRegSet];
635   if (offset == LLDB_INVALID_XSAVE_OFFSET)
636     return llvm::None;
637 
638   uint32_t reg_index;
639   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
640   case llvm::Triple::x86:
641     reg_index = reg - lldb_ymm0_i386;
642     break;
643   case llvm::Triple::x86_64:
644     reg_index = reg - lldb_ymm0_x86_64;
645     break;
646   default:
647     llvm_unreachable("Unhandled target architecture.");
648   }
649 
650   auto *fpreg = reinterpret_cast<struct savexmm_ymm *>(m_xsave.data());
651   auto *ymmreg = reinterpret_cast<struct ymmacc *>(m_xsave.data() + offset);
652 
653   return YMMSplitPtr{&fpreg->sv_xmm[reg_index], &ymmreg[reg_index]};
654 }
655 
656 #endif // defined(__x86_64__)
657