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 *
CreateHostNativeRegisterContextFreeBSD(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)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 *
CreateRegisterInfoInterface(const ArchSpec & target_arch)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
NativeRegisterContextFreeBSD_x86_64(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)259 NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64(
260 const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
261 : NativeRegisterContextRegisterInfo(
262 native_thread, CreateRegisterInfoInterface(target_arch)),
263 NativeRegisterContextDBReg_x86(native_thread), 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
GetRegisterSetCount() const286 uint32_t NativeRegisterContextFreeBSD_x86_64::GetRegisterSetCount() const {
287 return k_num_register_sets;
288 }
289
290 const RegisterSet *
GetRegisterSet(uint32_t set_index) const291 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>
GetSetForNativeRegNum(uint32_t reg_num) const303 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
ReadRegisterSet(RegSetKind set)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
WriteRegisterSet(RegSetKind set)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
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)409 NativeRegisterContextFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
410 RegisterValue ®_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
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)474 Status NativeRegisterContextFreeBSD_x86_64::WriteRegister(
475 const RegisterInfo *reg_info, const RegisterValue ®_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
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)539 Status NativeRegisterContextFreeBSD_x86_64::ReadAllRegisterValues(
540 lldb::WritableDataBufferSP &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
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)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 const 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
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD & source)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 *
GetOffsetRegSetData(RegSetKind set,size_t reg_offset)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>
GetYMMSplitReg(uint32_t reg)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