brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.4 KiB · c5c53a9 Raw
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 &reg_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 &reg_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