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