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 ®_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 ®_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