brintos

brintos / llvm-project-archived public Read only

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