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