12850b1beSTodd Fiala //===-- NativeRegisterContextLinux_x86_64.cpp ---------------*- C++ -*-===//
22850b1beSTodd Fiala //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62850b1beSTodd Fiala //
72850b1beSTodd Fiala //===----------------------------------------------------------------------===//
82850b1beSTodd Fiala 
9068f8a7eSTamas Berghammer #if defined(__i386__) || defined(__x86_64__)
10068f8a7eSTamas Berghammer 
112850b1beSTodd Fiala #include "NativeRegisterContextLinux_x86_64.h"
122850b1beSTodd Fiala 
13068f8a7eSTamas Berghammer #include "lldb/Host/HostInfo.h"
14666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
156f9e6901SZachary Turner #include "lldb/Utility/Log.h"
16d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h"
1797206d57SZachary Turner #include "lldb/Utility/Status.h"
18068f8a7eSTamas Berghammer 
19068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
20068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
212850b1beSTodd Fiala 
226ec13991SPavel Labath #include <linux/elf.h>
236ec13991SPavel Labath 
242850b1beSTodd Fiala using namespace lldb_private;
25db264a6dSTamas Berghammer using namespace lldb_private::process_linux;
262850b1beSTodd Fiala 
272850b1beSTodd Fiala // ----------------------------------------------------------------------------
282850b1beSTodd Fiala // Private namespace.
292850b1beSTodd Fiala // ----------------------------------------------------------------------------
302850b1beSTodd Fiala 
31b9c1b51eSKate Stone namespace {
322850b1beSTodd Fiala // x86 32-bit general purpose registers.
33b9c1b51eSKate Stone const uint32_t g_gpr_regnums_i386[] = {
34b9c1b51eSKate Stone     lldb_eax_i386,      lldb_ebx_i386,    lldb_ecx_i386, lldb_edx_i386,
35b9c1b51eSKate Stone     lldb_edi_i386,      lldb_esi_i386,    lldb_ebp_i386, lldb_esp_i386,
36b9c1b51eSKate Stone     lldb_eip_i386,      lldb_eflags_i386, lldb_cs_i386,  lldb_fs_i386,
37b9c1b51eSKate Stone     lldb_gs_i386,       lldb_ss_i386,     lldb_ds_i386,  lldb_es_i386,
38b9c1b51eSKate Stone     lldb_ax_i386,       lldb_bx_i386,     lldb_cx_i386,  lldb_dx_i386,
39b9c1b51eSKate Stone     lldb_di_i386,       lldb_si_i386,     lldb_bp_i386,  lldb_sp_i386,
40b9c1b51eSKate Stone     lldb_ah_i386,       lldb_bh_i386,     lldb_ch_i386,  lldb_dh_i386,
41b9c1b51eSKate Stone     lldb_al_i386,       lldb_bl_i386,     lldb_cl_i386,  lldb_dl_i386,
422850b1beSTodd Fiala     LLDB_INVALID_REGNUM // register sets need to end with this flag
432850b1beSTodd Fiala };
44b9c1b51eSKate Stone static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) -
45b9c1b51eSKate Stone                       1 ==
46b9c1b51eSKate Stone                   k_num_gpr_registers_i386,
472850b1beSTodd Fiala               "g_gpr_regnums_i386 has wrong number of register infos");
482850b1beSTodd Fiala 
492850b1beSTodd Fiala // x86 32-bit floating point registers.
50b9c1b51eSKate Stone const uint32_t g_fpu_regnums_i386[] = {
51b9c1b51eSKate Stone     lldb_fctrl_i386,    lldb_fstat_i386,     lldb_ftag_i386,  lldb_fop_i386,
52b9c1b51eSKate Stone     lldb_fiseg_i386,    lldb_fioff_i386,     lldb_foseg_i386, lldb_fooff_i386,
53b9c1b51eSKate Stone     lldb_mxcsr_i386,    lldb_mxcsrmask_i386, lldb_st0_i386,   lldb_st1_i386,
54b9c1b51eSKate Stone     lldb_st2_i386,      lldb_st3_i386,       lldb_st4_i386,   lldb_st5_i386,
55b9c1b51eSKate Stone     lldb_st6_i386,      lldb_st7_i386,       lldb_mm0_i386,   lldb_mm1_i386,
56b9c1b51eSKate Stone     lldb_mm2_i386,      lldb_mm3_i386,       lldb_mm4_i386,   lldb_mm5_i386,
57b9c1b51eSKate Stone     lldb_mm6_i386,      lldb_mm7_i386,       lldb_xmm0_i386,  lldb_xmm1_i386,
58b9c1b51eSKate Stone     lldb_xmm2_i386,     lldb_xmm3_i386,      lldb_xmm4_i386,  lldb_xmm5_i386,
59b9c1b51eSKate Stone     lldb_xmm6_i386,     lldb_xmm7_i386,
602850b1beSTodd Fiala     LLDB_INVALID_REGNUM // register sets need to end with this flag
612850b1beSTodd Fiala };
62b9c1b51eSKate Stone static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) -
63b9c1b51eSKate Stone                       1 ==
64b9c1b51eSKate Stone                   k_num_fpr_registers_i386,
652850b1beSTodd Fiala               "g_fpu_regnums_i386 has wrong number of register infos");
662850b1beSTodd Fiala 
672850b1beSTodd Fiala // x86 32-bit AVX registers.
68b9c1b51eSKate Stone const uint32_t g_avx_regnums_i386[] = {
69b9c1b51eSKate Stone     lldb_ymm0_i386,     lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386,
70b9c1b51eSKate Stone     lldb_ymm4_i386,     lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386,
712850b1beSTodd Fiala     LLDB_INVALID_REGNUM // register sets need to end with this flag
722850b1beSTodd Fiala };
73b9c1b51eSKate Stone static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) -
74b9c1b51eSKate Stone                       1 ==
75b9c1b51eSKate Stone                   k_num_avx_registers_i386,
762850b1beSTodd Fiala               " g_avx_regnums_i386 has wrong number of register infos");
772850b1beSTodd Fiala 
78cda0ae46SValentina Giusti // x64 32-bit MPX registers.
79cda0ae46SValentina Giusti static const uint32_t g_mpx_regnums_i386[] = {
80cda0ae46SValentina Giusti     lldb_bnd0_i386,     lldb_bnd1_i386, lldb_bnd2_i386, lldb_bnd3_i386,
81cda0ae46SValentina Giusti     lldb_bndcfgu_i386,  lldb_bndstatus_i386,
82cda0ae46SValentina Giusti     LLDB_INVALID_REGNUM // register sets need to end with this flag
83cda0ae46SValentina Giusti };
84cda0ae46SValentina Giusti static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) -
85cda0ae46SValentina Giusti                       1 ==
86cda0ae46SValentina Giusti                   k_num_mpx_registers_i386,
87cda0ae46SValentina Giusti               "g_mpx_regnums_x86_64 has wrong number of register infos");
88cda0ae46SValentina Giusti 
892850b1beSTodd Fiala // x86 64-bit general purpose registers.
90b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_x86_64[] = {
91b9c1b51eSKate Stone     lldb_rax_x86_64,    lldb_rbx_x86_64,    lldb_rcx_x86_64, lldb_rdx_x86_64,
92b9c1b51eSKate Stone     lldb_rdi_x86_64,    lldb_rsi_x86_64,    lldb_rbp_x86_64, lldb_rsp_x86_64,
93b9c1b51eSKate Stone     lldb_r8_x86_64,     lldb_r9_x86_64,     lldb_r10_x86_64, lldb_r11_x86_64,
94b9c1b51eSKate Stone     lldb_r12_x86_64,    lldb_r13_x86_64,    lldb_r14_x86_64, lldb_r15_x86_64,
95b9c1b51eSKate Stone     lldb_rip_x86_64,    lldb_rflags_x86_64, lldb_cs_x86_64,  lldb_fs_x86_64,
96b9c1b51eSKate Stone     lldb_gs_x86_64,     lldb_ss_x86_64,     lldb_ds_x86_64,  lldb_es_x86_64,
97b9c1b51eSKate Stone     lldb_eax_x86_64,    lldb_ebx_x86_64,    lldb_ecx_x86_64, lldb_edx_x86_64,
98b9c1b51eSKate Stone     lldb_edi_x86_64,    lldb_esi_x86_64,    lldb_ebp_x86_64, lldb_esp_x86_64,
997f013bcdSZachary Turner     lldb_r8d_x86_64,  // Low 32 bits or r8
1007f013bcdSZachary Turner     lldb_r9d_x86_64,  // Low 32 bits or r9
1017f013bcdSZachary Turner     lldb_r10d_x86_64, // Low 32 bits or r10
1027f013bcdSZachary Turner     lldb_r11d_x86_64, // Low 32 bits or r11
1037f013bcdSZachary Turner     lldb_r12d_x86_64, // Low 32 bits or r12
1047f013bcdSZachary Turner     lldb_r13d_x86_64, // Low 32 bits or r13
1057f013bcdSZachary Turner     lldb_r14d_x86_64, // Low 32 bits or r14
1067f013bcdSZachary Turner     lldb_r15d_x86_64, // Low 32 bits or r15
107b9c1b51eSKate Stone     lldb_ax_x86_64,     lldb_bx_x86_64,     lldb_cx_x86_64,  lldb_dx_x86_64,
108b9c1b51eSKate Stone     lldb_di_x86_64,     lldb_si_x86_64,     lldb_bp_x86_64,  lldb_sp_x86_64,
1097f013bcdSZachary Turner     lldb_r8w_x86_64,  // Low 16 bits or r8
1107f013bcdSZachary Turner     lldb_r9w_x86_64,  // Low 16 bits or r9
1117f013bcdSZachary Turner     lldb_r10w_x86_64, // Low 16 bits or r10
1127f013bcdSZachary Turner     lldb_r11w_x86_64, // Low 16 bits or r11
1137f013bcdSZachary Turner     lldb_r12w_x86_64, // Low 16 bits or r12
1147f013bcdSZachary Turner     lldb_r13w_x86_64, // Low 16 bits or r13
1157f013bcdSZachary Turner     lldb_r14w_x86_64, // Low 16 bits or r14
1167f013bcdSZachary Turner     lldb_r15w_x86_64, // Low 16 bits or r15
117b9c1b51eSKate Stone     lldb_ah_x86_64,     lldb_bh_x86_64,     lldb_ch_x86_64,  lldb_dh_x86_64,
118b9c1b51eSKate Stone     lldb_al_x86_64,     lldb_bl_x86_64,     lldb_cl_x86_64,  lldb_dl_x86_64,
119b9c1b51eSKate Stone     lldb_dil_x86_64,    lldb_sil_x86_64,    lldb_bpl_x86_64, lldb_spl_x86_64,
1207f013bcdSZachary Turner     lldb_r8l_x86_64,    // Low 8 bits or r8
1217f013bcdSZachary Turner     lldb_r9l_x86_64,    // Low 8 bits or r9
1227f013bcdSZachary Turner     lldb_r10l_x86_64,   // Low 8 bits or r10
1237f013bcdSZachary Turner     lldb_r11l_x86_64,   // Low 8 bits or r11
1247f013bcdSZachary Turner     lldb_r12l_x86_64,   // Low 8 bits or r12
1257f013bcdSZachary Turner     lldb_r13l_x86_64,   // Low 8 bits or r13
1267f013bcdSZachary Turner     lldb_r14l_x86_64,   // Low 8 bits or r14
1277f013bcdSZachary Turner     lldb_r15l_x86_64,   // Low 8 bits or r15
1282850b1beSTodd Fiala     LLDB_INVALID_REGNUM // register sets need to end with this flag
1292850b1beSTodd Fiala };
130b9c1b51eSKate Stone static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
131b9c1b51eSKate Stone                       1 ==
132b9c1b51eSKate Stone                   k_num_gpr_registers_x86_64,
1332850b1beSTodd Fiala               "g_gpr_regnums_x86_64 has wrong number of register infos");
1342850b1beSTodd Fiala 
1352850b1beSTodd Fiala // x86 64-bit floating point registers.
136b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_x86_64[] = {
137b9c1b51eSKate Stone     lldb_fctrl_x86_64,     lldb_fstat_x86_64, lldb_ftag_x86_64,
138b9c1b51eSKate Stone     lldb_fop_x86_64,       lldb_fiseg_x86_64, lldb_fioff_x86_64,
139b9c1b51eSKate Stone     lldb_foseg_x86_64,     lldb_fooff_x86_64, lldb_mxcsr_x86_64,
140b9c1b51eSKate Stone     lldb_mxcsrmask_x86_64, lldb_st0_x86_64,   lldb_st1_x86_64,
141b9c1b51eSKate Stone     lldb_st2_x86_64,       lldb_st3_x86_64,   lldb_st4_x86_64,
142b9c1b51eSKate Stone     lldb_st5_x86_64,       lldb_st6_x86_64,   lldb_st7_x86_64,
143b9c1b51eSKate Stone     lldb_mm0_x86_64,       lldb_mm1_x86_64,   lldb_mm2_x86_64,
144b9c1b51eSKate Stone     lldb_mm3_x86_64,       lldb_mm4_x86_64,   lldb_mm5_x86_64,
145b9c1b51eSKate Stone     lldb_mm6_x86_64,       lldb_mm7_x86_64,   lldb_xmm0_x86_64,
146b9c1b51eSKate Stone     lldb_xmm1_x86_64,      lldb_xmm2_x86_64,  lldb_xmm3_x86_64,
147b9c1b51eSKate Stone     lldb_xmm4_x86_64,      lldb_xmm5_x86_64,  lldb_xmm6_x86_64,
148b9c1b51eSKate Stone     lldb_xmm7_x86_64,      lldb_xmm8_x86_64,  lldb_xmm9_x86_64,
149b9c1b51eSKate Stone     lldb_xmm10_x86_64,     lldb_xmm11_x86_64, lldb_xmm12_x86_64,
150b9c1b51eSKate Stone     lldb_xmm13_x86_64,     lldb_xmm14_x86_64, lldb_xmm15_x86_64,
1512850b1beSTodd Fiala     LLDB_INVALID_REGNUM // register sets need to end with this flag
1522850b1beSTodd Fiala };
153b9c1b51eSKate Stone static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) -
154b9c1b51eSKate Stone                       1 ==
155b9c1b51eSKate Stone                   k_num_fpr_registers_x86_64,
1562850b1beSTodd Fiala               "g_fpu_regnums_x86_64 has wrong number of register infos");
1572850b1beSTodd Fiala 
1582850b1beSTodd Fiala // x86 64-bit AVX registers.
159b9c1b51eSKate Stone static const uint32_t g_avx_regnums_x86_64[] = {
160b9c1b51eSKate Stone     lldb_ymm0_x86_64,   lldb_ymm1_x86_64,  lldb_ymm2_x86_64,  lldb_ymm3_x86_64,
161b9c1b51eSKate Stone     lldb_ymm4_x86_64,   lldb_ymm5_x86_64,  lldb_ymm6_x86_64,  lldb_ymm7_x86_64,
162b9c1b51eSKate Stone     lldb_ymm8_x86_64,   lldb_ymm9_x86_64,  lldb_ymm10_x86_64, lldb_ymm11_x86_64,
163b9c1b51eSKate Stone     lldb_ymm12_x86_64,  lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64,
1642850b1beSTodd Fiala     LLDB_INVALID_REGNUM // register sets need to end with this flag
1652850b1beSTodd Fiala };
166b9c1b51eSKate Stone static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) -
167b9c1b51eSKate Stone                       1 ==
168b9c1b51eSKate Stone                   k_num_avx_registers_x86_64,
1692850b1beSTodd Fiala               "g_avx_regnums_x86_64 has wrong number of register infos");
1702850b1beSTodd Fiala 
171cda0ae46SValentina Giusti // x86 64-bit MPX registers.
172cda0ae46SValentina Giusti static const uint32_t g_mpx_regnums_x86_64[] = {
173cda0ae46SValentina Giusti     lldb_bnd0_x86_64,    lldb_bnd1_x86_64,    lldb_bnd2_x86_64,
174cda0ae46SValentina Giusti     lldb_bnd3_x86_64,    lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
175cda0ae46SValentina Giusti     LLDB_INVALID_REGNUM // register sets need to end with this flag
176cda0ae46SValentina Giusti };
177cda0ae46SValentina Giusti static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) -
178cda0ae46SValentina Giusti                       1 ==
179cda0ae46SValentina Giusti                   k_num_mpx_registers_x86_64,
180cda0ae46SValentina Giusti               "g_mpx_regnums_x86_64 has wrong number of register infos");
181cda0ae46SValentina Giusti 
1822850b1beSTodd Fiala // Number of register sets provided by this context.
183cda0ae46SValentina Giusti enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 };
1842850b1beSTodd Fiala 
1852850b1beSTodd Fiala // Register sets for x86 32-bit.
186b9c1b51eSKate Stone static const RegisterSet g_reg_sets_i386[k_num_register_sets] = {
187b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_i386,
188b9c1b51eSKate Stone      g_gpr_regnums_i386},
189b9c1b51eSKate Stone     {"Floating Point Registers", "fpu", k_num_fpr_registers_i386,
190b9c1b51eSKate Stone      g_fpu_regnums_i386},
191b9c1b51eSKate Stone     {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
192cda0ae46SValentina Giusti      g_avx_regnums_i386},
193cda0ae46SValentina Giusti     { "Memory Protection Extensions", "mpx", k_num_mpx_registers_i386,
194cda0ae46SValentina Giusti      g_mpx_regnums_i386}};
1952850b1beSTodd Fiala 
1962850b1beSTodd Fiala // Register sets for x86 64-bit.
197b9c1b51eSKate Stone static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
198b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
199b9c1b51eSKate Stone      g_gpr_regnums_x86_64},
200b9c1b51eSKate Stone     {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64,
201b9c1b51eSKate Stone      g_fpu_regnums_x86_64},
202b9c1b51eSKate Stone     {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
203cda0ae46SValentina Giusti      g_avx_regnums_x86_64},
204cda0ae46SValentina Giusti     { "Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64,
205cda0ae46SValentina Giusti      g_mpx_regnums_x86_64}};
2062850b1beSTodd Fiala }
2072850b1beSTodd Fiala 
2082850b1beSTodd Fiala #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize() + sizeof(FPR))
2092850b1beSTodd Fiala 
2102850b1beSTodd Fiala // ----------------------------------------------------------------------------
2112850b1beSTodd Fiala // Required ptrace defines.
2122850b1beSTodd Fiala // ----------------------------------------------------------------------------
2132850b1beSTodd Fiala 
2142850b1beSTodd Fiala // Support ptrace extensions even when compiled without required kernel support
2152850b1beSTodd Fiala #ifndef NT_X86_XSTATE
2162850b1beSTodd Fiala #define NT_X86_XSTATE 0x202
2172850b1beSTodd Fiala #endif
218296e063dSAbhishek Aggarwal #ifndef NT_PRXFPREG
219296e063dSAbhishek Aggarwal #define NT_PRXFPREG 0x46e62b7f
220296e063dSAbhishek Aggarwal #endif
2212850b1beSTodd Fiala 
2226ec13991SPavel Labath // On x86_64 NT_PRFPREG is used to access the FXSAVE area. On i386, we need to
2236ec13991SPavel Labath // use NT_PRXFPREG.
2246ec13991SPavel Labath static inline unsigned int fxsr_regset(const ArchSpec &arch) {
2256ec13991SPavel Labath   return arch.GetAddressByteSize() == 8 ? NT_PRFPREG : NT_PRXFPREG;
2266ec13991SPavel Labath }
2276ec13991SPavel Labath 
2285f957b54SValentina Giusti // ----------------------------------------------------------------------------
2295f957b54SValentina Giusti // Required MPX define.
2305f957b54SValentina Giusti // ----------------------------------------------------------------------------
2315f957b54SValentina Giusti 
2325f957b54SValentina Giusti // Support MPX extensions also if compiled with compiler without MPX support.
2335f957b54SValentina Giusti #ifndef bit_MPX
2345f957b54SValentina Giusti #define bit_MPX 0x4000
2355f957b54SValentina Giusti #endif
2365f957b54SValentina Giusti 
2375f957b54SValentina Giusti // ----------------------------------------------------------------------------
2385f957b54SValentina Giusti // XCR0 extended register sets masks.
2395f957b54SValentina Giusti // ----------------------------------------------------------------------------
2405f957b54SValentina Giusti #define mask_XSTATE_AVX (1ULL << 2)
2415f957b54SValentina Giusti #define mask_XSTATE_BNDREGS (1ULL << 3)
2425f957b54SValentina Giusti #define mask_XSTATE_BNDCFG (1ULL << 4)
2435f957b54SValentina Giusti #define mask_XSTATE_MPX (mask_XSTATE_BNDREGS | mask_XSTATE_BNDCFG)
2445f957b54SValentina Giusti 
245d37349f3SPavel Labath std::unique_ptr<NativeRegisterContextLinux>
246b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
247d37349f3SPavel Labath     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
248d37349f3SPavel Labath   return std::unique_ptr<NativeRegisterContextLinux>(
249d37349f3SPavel Labath       new NativeRegisterContextLinux_x86_64(target_arch, native_thread));
250068f8a7eSTamas Berghammer }
251068f8a7eSTamas Berghammer 
2522850b1beSTodd Fiala // ----------------------------------------------------------------------------
2532850b1beSTodd Fiala // NativeRegisterContextLinux_x86_64 members.
2542850b1beSTodd Fiala // ----------------------------------------------------------------------------
2552850b1beSTodd Fiala 
256068f8a7eSTamas Berghammer static RegisterInfoInterface *
257b9c1b51eSKate Stone CreateRegisterInfoInterface(const ArchSpec &target_arch) {
258b9c1b51eSKate Stone   if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
259068f8a7eSTamas Berghammer     // 32-bit hosts run with a RegisterContextLinux_i386 context.
260068f8a7eSTamas Berghammer     return new RegisterContextLinux_i386(target_arch);
261b9c1b51eSKate Stone   } else {
262068f8a7eSTamas Berghammer     assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
263068f8a7eSTamas Berghammer            "Register setting path assumes this is a 64-bit host");
264b9c1b51eSKate Stone     // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the
265b9c1b51eSKate Stone     // x86_64 register context.
266068f8a7eSTamas Berghammer     return new RegisterContextLinux_x86_64(target_arch);
267068f8a7eSTamas Berghammer   }
268068f8a7eSTamas Berghammer }
269068f8a7eSTamas Berghammer 
270b9c1b51eSKate Stone NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64(
271d37349f3SPavel Labath     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
272d37349f3SPavel Labath     : NativeRegisterContextLinux(native_thread,
273b9c1b51eSKate Stone                                  CreateRegisterInfoInterface(target_arch)),
27497e57e9bSValentina Giusti       m_xstate_type(XStateType::Invalid), m_fpr(), m_iovec(), m_ymm_set(),
275cda0ae46SValentina Giusti       m_mpx_set(), m_reg_info(), m_gpr_x86_64() {
2762850b1beSTodd Fiala   // Set up data about ranges of valid registers.
277b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
2782850b1beSTodd Fiala   case llvm::Triple::x86:
2792850b1beSTodd Fiala     m_reg_info.num_registers = k_num_registers_i386;
2802850b1beSTodd Fiala     m_reg_info.num_gpr_registers = k_num_gpr_registers_i386;
2812850b1beSTodd Fiala     m_reg_info.num_fpr_registers = k_num_fpr_registers_i386;
2822850b1beSTodd Fiala     m_reg_info.num_avx_registers = k_num_avx_registers_i386;
283cda0ae46SValentina Giusti     m_reg_info.num_mpx_registers = k_num_mpx_registers_i386;
2842850b1beSTodd Fiala     m_reg_info.last_gpr = k_last_gpr_i386;
2852850b1beSTodd Fiala     m_reg_info.first_fpr = k_first_fpr_i386;
2862850b1beSTodd Fiala     m_reg_info.last_fpr = k_last_fpr_i386;
2877f013bcdSZachary Turner     m_reg_info.first_st = lldb_st0_i386;
2887f013bcdSZachary Turner     m_reg_info.last_st = lldb_st7_i386;
2897f013bcdSZachary Turner     m_reg_info.first_mm = lldb_mm0_i386;
2907f013bcdSZachary Turner     m_reg_info.last_mm = lldb_mm7_i386;
2917f013bcdSZachary Turner     m_reg_info.first_xmm = lldb_xmm0_i386;
2927f013bcdSZachary Turner     m_reg_info.last_xmm = lldb_xmm7_i386;
2937f013bcdSZachary Turner     m_reg_info.first_ymm = lldb_ymm0_i386;
2947f013bcdSZachary Turner     m_reg_info.last_ymm = lldb_ymm7_i386;
295cda0ae46SValentina Giusti     m_reg_info.first_mpxr = lldb_bnd0_i386;
296cda0ae46SValentina Giusti     m_reg_info.last_mpxr = lldb_bnd3_i386;
297cda0ae46SValentina Giusti     m_reg_info.first_mpxc = lldb_bndcfgu_i386;
298cda0ae46SValentina Giusti     m_reg_info.last_mpxc = lldb_bndstatus_i386;
2997f013bcdSZachary Turner     m_reg_info.first_dr = lldb_dr0_i386;
3007f013bcdSZachary Turner     m_reg_info.gpr_flags = lldb_eflags_i386;
3012850b1beSTodd Fiala     break;
3022850b1beSTodd Fiala   case llvm::Triple::x86_64:
3032850b1beSTodd Fiala     m_reg_info.num_registers = k_num_registers_x86_64;
3042850b1beSTodd Fiala     m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64;
3052850b1beSTodd Fiala     m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64;
3062850b1beSTodd Fiala     m_reg_info.num_avx_registers = k_num_avx_registers_x86_64;
307cda0ae46SValentina Giusti     m_reg_info.num_mpx_registers = k_num_mpx_registers_x86_64;
3082850b1beSTodd Fiala     m_reg_info.last_gpr = k_last_gpr_x86_64;
3092850b1beSTodd Fiala     m_reg_info.first_fpr = k_first_fpr_x86_64;
3102850b1beSTodd Fiala     m_reg_info.last_fpr = k_last_fpr_x86_64;
3117f013bcdSZachary Turner     m_reg_info.first_st = lldb_st0_x86_64;
3127f013bcdSZachary Turner     m_reg_info.last_st = lldb_st7_x86_64;
3137f013bcdSZachary Turner     m_reg_info.first_mm = lldb_mm0_x86_64;
3147f013bcdSZachary Turner     m_reg_info.last_mm = lldb_mm7_x86_64;
3157f013bcdSZachary Turner     m_reg_info.first_xmm = lldb_xmm0_x86_64;
3167f013bcdSZachary Turner     m_reg_info.last_xmm = lldb_xmm15_x86_64;
3177f013bcdSZachary Turner     m_reg_info.first_ymm = lldb_ymm0_x86_64;
3187f013bcdSZachary Turner     m_reg_info.last_ymm = lldb_ymm15_x86_64;
319cda0ae46SValentina Giusti     m_reg_info.first_mpxr = lldb_bnd0_x86_64;
320cda0ae46SValentina Giusti     m_reg_info.last_mpxr = lldb_bnd3_x86_64;
321cda0ae46SValentina Giusti     m_reg_info.first_mpxc = lldb_bndcfgu_x86_64;
322cda0ae46SValentina Giusti     m_reg_info.last_mpxc = lldb_bndstatus_x86_64;
3237f013bcdSZachary Turner     m_reg_info.first_dr = lldb_dr0_x86_64;
3247f013bcdSZachary Turner     m_reg_info.gpr_flags = lldb_rflags_x86_64;
3252850b1beSTodd Fiala     break;
3262850b1beSTodd Fiala   default:
3272850b1beSTodd Fiala     assert(false && "Unhandled target architecture.");
3282850b1beSTodd Fiala     break;
3292850b1beSTodd Fiala   }
3302850b1beSTodd Fiala 
33105097246SAdrian Prantl   // Initialize m_iovec to point to the buffer and buffer size using the
33205097246SAdrian Prantl   // conventions of Berkeley style UIO structures, as required by PTRACE
33305097246SAdrian Prantl   // extensions.
334a0e3c6f6SPavel Labath   m_iovec.iov_base = &m_fpr;
335a0e3c6f6SPavel Labath   m_iovec.iov_len = sizeof(m_fpr);
3362850b1beSTodd Fiala 
3372850b1beSTodd Fiala   // Clear out the FPR state.
338a0e3c6f6SPavel Labath   ::memset(&m_fpr, 0, sizeof(m_fpr));
3397f658eddSAbhishek Aggarwal 
3407f658eddSAbhishek Aggarwal   // Store byte offset of fctrl (i.e. first register of FPR)
3417f658eddSAbhishek Aggarwal   const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl");
3427f658eddSAbhishek Aggarwal   m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset;
3432850b1beSTodd Fiala }
3442850b1beSTodd Fiala 
3452850b1beSTodd Fiala // CONSIDER after local and llgs debugging are merged, register set support can
3462850b1beSTodd Fiala // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
347b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_x86_64::GetRegisterSetCount() const {
3482850b1beSTodd Fiala   uint32_t sets = 0;
349b9c1b51eSKate Stone   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
3502850b1beSTodd Fiala     if (IsRegisterSetAvailable(set_index))
3512850b1beSTodd Fiala       ++sets;
3522850b1beSTodd Fiala   }
3532850b1beSTodd Fiala 
3542850b1beSTodd Fiala   return sets;
3552850b1beSTodd Fiala }
3562850b1beSTodd Fiala 
357b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_x86_64::GetUserRegisterCount() const {
3588fa23b8eSTamas Berghammer   uint32_t count = 0;
359b9c1b51eSKate Stone   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
360db264a6dSTamas Berghammer     const RegisterSet *set = GetRegisterSet(set_index);
3618fa23b8eSTamas Berghammer     if (set)
3628fa23b8eSTamas Berghammer       count += set->num_registers;
3638fa23b8eSTamas Berghammer   }
3648fa23b8eSTamas Berghammer   return count;
3658fa23b8eSTamas Berghammer }
3668fa23b8eSTamas Berghammer 
367db264a6dSTamas Berghammer const RegisterSet *
368b9c1b51eSKate Stone NativeRegisterContextLinux_x86_64::GetRegisterSet(uint32_t set_index) const {
3692850b1beSTodd Fiala   if (!IsRegisterSetAvailable(set_index))
3702850b1beSTodd Fiala     return nullptr;
3712850b1beSTodd Fiala 
372b9c1b51eSKate Stone   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
3732850b1beSTodd Fiala   case llvm::Triple::x86:
3742850b1beSTodd Fiala     return &g_reg_sets_i386[set_index];
3752850b1beSTodd Fiala   case llvm::Triple::x86_64:
3762850b1beSTodd Fiala     return &g_reg_sets_x86_64[set_index];
3772850b1beSTodd Fiala   default:
3782850b1beSTodd Fiala     assert(false && "Unhandled target architecture.");
3792850b1beSTodd Fiala     return nullptr;
3802850b1beSTodd Fiala   }
3812850b1beSTodd Fiala 
3822850b1beSTodd Fiala   return nullptr;
3832850b1beSTodd Fiala }
3842850b1beSTodd Fiala 
38597206d57SZachary Turner Status
38697206d57SZachary Turner NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info,
38797206d57SZachary Turner                                                 RegisterValue &reg_value) {
38897206d57SZachary Turner   Status error;
3892850b1beSTodd Fiala 
390b9c1b51eSKate Stone   if (!reg_info) {
3912850b1beSTodd Fiala     error.SetErrorString("reg_info NULL");
3922850b1beSTodd Fiala     return error;
3932850b1beSTodd Fiala   }
3942850b1beSTodd Fiala 
3952850b1beSTodd Fiala   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
396b9c1b51eSKate Stone   if (reg == LLDB_INVALID_REGNUM) {
397b9c1b51eSKate Stone     // This is likely an internal register for lldb use only and should not be
398b9c1b51eSKate Stone     // directly queried.
399b9c1b51eSKate Stone     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
400b9c1b51eSKate Stone                                    "register, cannot read directly",
401b9c1b51eSKate Stone                                    reg_info->name);
4022850b1beSTodd Fiala     return error;
4032850b1beSTodd Fiala   }
4042850b1beSTodd Fiala 
4055f957b54SValentina Giusti   if (IsFPR(reg) || IsAVX(reg) || IsMPX(reg)) {
406068f8a7eSTamas Berghammer     error = ReadFPR();
407068f8a7eSTamas Berghammer     if (error.Fail())
4082850b1beSTodd Fiala       return error;
409b9c1b51eSKate Stone   } else {
4102850b1beSTodd Fiala     uint32_t full_reg = reg;
411b9c1b51eSKate Stone     bool is_subreg = reg_info->invalidate_regs &&
412b9c1b51eSKate Stone                      (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
4132850b1beSTodd Fiala 
414b9c1b51eSKate Stone     if (is_subreg) {
4152850b1beSTodd Fiala       // Read the full aligned 64-bit register.
4162850b1beSTodd Fiala       full_reg = reg_info->invalidate_regs[0];
4172850b1beSTodd Fiala     }
4182850b1beSTodd Fiala 
4192850b1beSTodd Fiala     error = ReadRegisterRaw(full_reg, reg_value);
4202850b1beSTodd Fiala 
421b9c1b51eSKate Stone     if (error.Success()) {
42205097246SAdrian Prantl       // If our read was not aligned (for ah,bh,ch,dh), shift our returned
42305097246SAdrian Prantl       // value one byte to the right.
4242850b1beSTodd Fiala       if (is_subreg && (reg_info->byte_offset & 0x1))
4252850b1beSTodd Fiala         reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
4262850b1beSTodd Fiala 
427b9c1b51eSKate Stone       // If our return byte size was greater than the return value reg size,
42805097246SAdrian Prantl       // then use the type specified by reg_info rather than the uint64_t
42905097246SAdrian Prantl       // default
4302850b1beSTodd Fiala       if (reg_value.GetByteSize() > reg_info->byte_size)
4312850b1beSTodd Fiala         reg_value.SetType(reg_info);
4322850b1beSTodd Fiala     }
4332850b1beSTodd Fiala     return error;
4342850b1beSTodd Fiala   }
4352850b1beSTodd Fiala 
436b9c1b51eSKate Stone   if (reg_info->encoding == lldb::eEncodingVector) {
4372850b1beSTodd Fiala     lldb::ByteOrder byte_order = GetByteOrder();
4382850b1beSTodd Fiala 
439b9c1b51eSKate Stone     if (byte_order != lldb::eByteOrderInvalid) {
4402850b1beSTodd Fiala       if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
441a0e3c6f6SPavel Labath         reg_value.SetBytes(m_fpr.fxsave.stmm[reg - m_reg_info.first_st].bytes,
442b9c1b51eSKate Stone                            reg_info->byte_size, byte_order);
4432850b1beSTodd Fiala       if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
444a0e3c6f6SPavel Labath         reg_value.SetBytes(m_fpr.fxsave.stmm[reg - m_reg_info.first_mm].bytes,
445b9c1b51eSKate Stone                            reg_info->byte_size, byte_order);
4462850b1beSTodd Fiala       if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
447a0e3c6f6SPavel Labath         reg_value.SetBytes(m_fpr.fxsave.xmm[reg - m_reg_info.first_xmm].bytes,
448b9c1b51eSKate Stone                            reg_info->byte_size, byte_order);
449b9c1b51eSKate Stone       if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) {
45005097246SAdrian Prantl         // Concatenate ymm using the register halves in xmm.bytes and
45105097246SAdrian Prantl         // ymmh.bytes
4525f957b54SValentina Giusti         if (CopyXSTATEtoYMM(reg, byte_order))
453b9c1b51eSKate Stone           reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
454b9c1b51eSKate Stone                              reg_info->byte_size, byte_order);
455b9c1b51eSKate Stone         else {
4562850b1beSTodd Fiala           error.SetErrorString("failed to copy ymm register value");
4572850b1beSTodd Fiala           return error;
4582850b1beSTodd Fiala         }
4592850b1beSTodd Fiala       }
460cda0ae46SValentina Giusti       if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) {
4615f957b54SValentina Giusti         if (CopyXSTATEtoMPX(reg))
462cda0ae46SValentina Giusti           reg_value.SetBytes(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes,
463cda0ae46SValentina Giusti                              reg_info->byte_size, byte_order);
464cda0ae46SValentina Giusti         else {
465cda0ae46SValentina Giusti           error.SetErrorString("failed to copy mpx register value");
466cda0ae46SValentina Giusti           return error;
467cda0ae46SValentina Giusti         }
468cda0ae46SValentina Giusti       }
469cda0ae46SValentina Giusti       if (reg >= m_reg_info.first_mpxc && reg <= m_reg_info.last_mpxc) {
4705f957b54SValentina Giusti         if (CopyXSTATEtoMPX(reg))
471cda0ae46SValentina Giusti           reg_value.SetBytes(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes,
472cda0ae46SValentina Giusti                              reg_info->byte_size, byte_order);
473cda0ae46SValentina Giusti         else {
474cda0ae46SValentina Giusti           error.SetErrorString("failed to copy mpx register value");
475cda0ae46SValentina Giusti           return error;
476cda0ae46SValentina Giusti         }
477cda0ae46SValentina Giusti       }
478ee44a92dSDimitar Vlahovski 
4792850b1beSTodd Fiala       if (reg_value.GetType() != RegisterValue::eTypeBytes)
480b9c1b51eSKate Stone         error.SetErrorString(
481b9c1b51eSKate Stone             "write failed - type was expected to be RegisterValue::eTypeBytes");
4822850b1beSTodd Fiala 
4832850b1beSTodd Fiala       return error;
4842850b1beSTodd Fiala     }
4852850b1beSTodd Fiala 
4862850b1beSTodd Fiala     error.SetErrorString("byte order is invalid");
4872850b1beSTodd Fiala     return error;
4882850b1beSTodd Fiala   }
4892850b1beSTodd Fiala 
490a0e3c6f6SPavel Labath   // Get pointer to m_fpr.fxsave variable and set the data from it.
4917f658eddSAbhishek Aggarwal 
4927f658eddSAbhishek Aggarwal   // Byte offsets of all registers are calculated wrt 'UserArea' structure.
4937f658eddSAbhishek Aggarwal   // However, ReadFPR() reads fpu registers {using ptrace(PTRACE_GETFPREGS,..)}
494b9c1b51eSKate Stone   // and stores them in 'm_fpr' (of type FPR structure). To extract values of
49505097246SAdrian Prantl   // fpu registers, m_fpr should be read at byte offsets calculated wrt to FPR
496b9c1b51eSKate Stone   // structure.
4977f658eddSAbhishek Aggarwal 
4987f658eddSAbhishek Aggarwal   // Since, FPR structure is also one of the member of UserArea structure.
499b9c1b51eSKate Stone   // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) -
500b9c1b51eSKate Stone   // byte_offset(fctrl wrt UserArea)
5017f658eddSAbhishek Aggarwal   assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
502b9c1b51eSKate Stone   uint8_t *src =
503b9c1b51eSKate Stone       (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
504b9c1b51eSKate Stone   switch (reg_info->byte_size) {
505b352a1c8SAbhishek Aggarwal   case 1:
506b352a1c8SAbhishek Aggarwal     reg_value.SetUInt8(*(uint8_t *)src);
507b352a1c8SAbhishek Aggarwal     break;
5082850b1beSTodd Fiala   case 2:
5092850b1beSTodd Fiala     reg_value.SetUInt16(*(uint16_t *)src);
5102850b1beSTodd Fiala     break;
5112850b1beSTodd Fiala   case 4:
5122850b1beSTodd Fiala     reg_value.SetUInt32(*(uint32_t *)src);
5132850b1beSTodd Fiala     break;
5142850b1beSTodd Fiala   case 8:
5152850b1beSTodd Fiala     reg_value.SetUInt64(*(uint64_t *)src);
5162850b1beSTodd Fiala     break;
5172850b1beSTodd Fiala   default:
5182850b1beSTodd Fiala     assert(false && "Unhandled data size.");
519b9c1b51eSKate Stone     error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32,
520b9c1b51eSKate Stone                                    reg_info->byte_size);
5212850b1beSTodd Fiala     break;
5222850b1beSTodd Fiala   }
5232850b1beSTodd Fiala 
5242850b1beSTodd Fiala   return error;
5252850b1beSTodd Fiala }
5262850b1beSTodd Fiala 
527d2cfe0e5SPavel Labath void NativeRegisterContextLinux_x86_64::UpdateXSTATEforWrite(
528d2cfe0e5SPavel Labath     uint32_t reg_index) {
529a0e3c6f6SPavel Labath   XSAVE_HDR::XFeature &xstate_bv = m_fpr.xsave.header.xstate_bv;
530d2cfe0e5SPavel Labath   if (IsFPR(reg_index)) {
531d2cfe0e5SPavel Labath     // IsFPR considers both %st and %xmm registers as floating point, but these
532d2cfe0e5SPavel Labath     // map to two features. Set both flags, just in case.
533d2cfe0e5SPavel Labath     xstate_bv |= XSAVE_HDR::XFeature::FP | XSAVE_HDR::XFeature::SSE;
534d2cfe0e5SPavel Labath   } else if (IsAVX(reg_index)) {
535d2cfe0e5SPavel Labath     // Lower bytes of some %ymm registers are shared with %xmm registers.
536d2cfe0e5SPavel Labath     xstate_bv |= XSAVE_HDR::XFeature::YMM | XSAVE_HDR::XFeature::SSE;
537d2cfe0e5SPavel Labath   } else if (IsMPX(reg_index)) {
538d2cfe0e5SPavel Labath     // MPX registers map to two XSAVE features.
539d2cfe0e5SPavel Labath     xstate_bv |= XSAVE_HDR::XFeature::BNDREGS | XSAVE_HDR::XFeature::BNDCSR;
540d2cfe0e5SPavel Labath   }
541d2cfe0e5SPavel Labath }
542d2cfe0e5SPavel Labath 
54397206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::WriteRegister(
544b9c1b51eSKate Stone     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
5452850b1beSTodd Fiala   assert(reg_info && "reg_info is null");
5462850b1beSTodd Fiala 
5472850b1beSTodd Fiala   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
5482850b1beSTodd Fiala   if (reg_index == LLDB_INVALID_REGNUM)
54997206d57SZachary Turner     return Status("no lldb regnum for %s", reg_info && reg_info->name
550b9c1b51eSKate Stone                                                ? reg_info->name
551b9c1b51eSKate Stone                                                : "<unknown register>");
5522850b1beSTodd Fiala 
553d2cfe0e5SPavel Labath   UpdateXSTATEforWrite(reg_index);
554d2cfe0e5SPavel Labath 
5552850b1beSTodd Fiala   if (IsGPR(reg_index))
556068f8a7eSTamas Berghammer     return WriteRegisterRaw(reg_index, reg_value);
5572850b1beSTodd Fiala 
5585f957b54SValentina Giusti   if (IsFPR(reg_index) || IsAVX(reg_index) || IsMPX(reg_index)) {
559b9c1b51eSKate Stone     if (reg_info->encoding == lldb::eEncodingVector) {
5602850b1beSTodd Fiala       if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
561a0e3c6f6SPavel Labath         ::memcpy(m_fpr.fxsave.stmm[reg_index - m_reg_info.first_st].bytes,
562b9c1b51eSKate Stone                  reg_value.GetBytes(), reg_value.GetByteSize());
5632850b1beSTodd Fiala 
5642850b1beSTodd Fiala       if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm)
565a0e3c6f6SPavel Labath         ::memcpy(m_fpr.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes,
566b9c1b51eSKate Stone                  reg_value.GetBytes(), reg_value.GetByteSize());
5672850b1beSTodd Fiala 
5682850b1beSTodd Fiala       if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm)
569a0e3c6f6SPavel Labath         ::memcpy(m_fpr.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes,
570b9c1b51eSKate Stone                  reg_value.GetBytes(), reg_value.GetByteSize());
5712850b1beSTodd Fiala 
572b9c1b51eSKate Stone       if (reg_index >= m_reg_info.first_ymm &&
573b9c1b51eSKate Stone           reg_index <= m_reg_info.last_ymm) {
574b9c1b51eSKate Stone         // Store ymm register content, and split into the register halves in
575b9c1b51eSKate Stone         // xmm.bytes and ymmh.bytes
576b9c1b51eSKate Stone         ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
577b9c1b51eSKate Stone                  reg_value.GetBytes(), reg_value.GetByteSize());
5782850b1beSTodd Fiala         if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
57997206d57SZachary Turner           return Status("CopyYMMtoXSTATE() failed");
5802850b1beSTodd Fiala       }
581cda0ae46SValentina Giusti 
582cda0ae46SValentina Giusti       if (reg_index >= m_reg_info.first_mpxr &&
583cda0ae46SValentina Giusti           reg_index <= m_reg_info.last_mpxr) {
584cda0ae46SValentina Giusti         ::memcpy(m_mpx_set.mpxr[reg_index - m_reg_info.first_mpxr].bytes,
585cda0ae46SValentina Giusti                  reg_value.GetBytes(), reg_value.GetByteSize());
586cda0ae46SValentina Giusti         if (!CopyMPXtoXSTATE(reg_index))
58797206d57SZachary Turner           return Status("CopyMPXtoXSTATE() failed");
588cda0ae46SValentina Giusti       }
589cda0ae46SValentina Giusti 
590cda0ae46SValentina Giusti       if (reg_index >= m_reg_info.first_mpxc &&
591cda0ae46SValentina Giusti           reg_index <= m_reg_info.last_mpxc) {
592cda0ae46SValentina Giusti         ::memcpy(m_mpx_set.mpxc[reg_index - m_reg_info.first_mpxc].bytes,
593cda0ae46SValentina Giusti                  reg_value.GetBytes(), reg_value.GetByteSize());
594cda0ae46SValentina Giusti         if (!CopyMPXtoXSTATE(reg_index))
59597206d57SZachary Turner           return Status("CopyMPXtoXSTATE() failed");
596cda0ae46SValentina Giusti       }
597b9c1b51eSKate Stone     } else {
598a0e3c6f6SPavel Labath       // Get pointer to m_fpr.fxsave variable and set the data to it.
5997f658eddSAbhishek Aggarwal 
6007f658eddSAbhishek Aggarwal       // Byte offsets of all registers are calculated wrt 'UserArea' structure.
60105097246SAdrian Prantl       // However, WriteFPR() takes m_fpr (of type FPR structure) and writes
60205097246SAdrian Prantl       // only fpu registers using ptrace(PTRACE_SETFPREGS,..) API. Hence fpu
60305097246SAdrian Prantl       // registers should be written in m_fpr at byte offsets calculated wrt
60405097246SAdrian Prantl       // FPR structure.
6057f658eddSAbhishek Aggarwal 
6067f658eddSAbhishek Aggarwal       // Since, FPR structure is also one of the member of UserArea structure.
607b9c1b51eSKate Stone       // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) -
608b9c1b51eSKate Stone       // byte_offset(fctrl wrt UserArea)
609b9c1b51eSKate Stone       assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) <
610b9c1b51eSKate Stone              sizeof(m_fpr));
611b9c1b51eSKate Stone       uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset -
612b9c1b51eSKate Stone                      m_fctrl_offset_in_userarea;
613b9c1b51eSKate Stone       switch (reg_info->byte_size) {
614b352a1c8SAbhishek Aggarwal       case 1:
615b352a1c8SAbhishek Aggarwal         *(uint8_t *)dst = reg_value.GetAsUInt8();
616b352a1c8SAbhishek Aggarwal         break;
6172850b1beSTodd Fiala       case 2:
6182850b1beSTodd Fiala         *(uint16_t *)dst = reg_value.GetAsUInt16();
6192850b1beSTodd Fiala         break;
6202850b1beSTodd Fiala       case 4:
6212850b1beSTodd Fiala         *(uint32_t *)dst = reg_value.GetAsUInt32();
6222850b1beSTodd Fiala         break;
6232850b1beSTodd Fiala       case 8:
6242850b1beSTodd Fiala         *(uint64_t *)dst = reg_value.GetAsUInt64();
6252850b1beSTodd Fiala         break;
6262850b1beSTodd Fiala       default:
6272850b1beSTodd Fiala         assert(false && "Unhandled data size.");
62897206d57SZachary Turner         return Status("unhandled register data size %" PRIu32,
629b9c1b51eSKate Stone                       reg_info->byte_size);
6302850b1beSTodd Fiala       }
6312850b1beSTodd Fiala     }
6322850b1beSTodd Fiala 
63397206d57SZachary Turner     Status error = WriteFPR();
634068f8a7eSTamas Berghammer     if (error.Fail())
635068f8a7eSTamas Berghammer       return error;
636068f8a7eSTamas Berghammer 
637b9c1b51eSKate Stone     if (IsAVX(reg_index)) {
6382850b1beSTodd Fiala       if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
63997206d57SZachary Turner         return Status("CopyYMMtoXSTATE() failed");
6402850b1beSTodd Fiala     }
641cda0ae46SValentina Giusti 
642cda0ae46SValentina Giusti     if (IsMPX(reg_index)) {
643cda0ae46SValentina Giusti       if (!CopyMPXtoXSTATE(reg_index))
64497206d57SZachary Turner         return Status("CopyMPXtoXSTATE() failed");
645cda0ae46SValentina Giusti     }
64697206d57SZachary Turner     return Status();
6472850b1beSTodd Fiala   }
64897206d57SZachary Turner   return Status("failed - register wasn't recognized to be a GPR or an FPR, "
649b9c1b51eSKate Stone                 "write strategy unknown");
6502850b1beSTodd Fiala }
6512850b1beSTodd Fiala 
65297206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::ReadAllRegisterValues(
653b9c1b51eSKate Stone     lldb::DataBufferSP &data_sp) {
65497206d57SZachary Turner   Status error;
6552850b1beSTodd Fiala 
6562850b1beSTodd Fiala   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
657068f8a7eSTamas Berghammer   error = ReadGPR();
658068f8a7eSTamas Berghammer   if (error.Fail())
6592850b1beSTodd Fiala     return error;
6602850b1beSTodd Fiala 
661068f8a7eSTamas Berghammer   error = ReadFPR();
662068f8a7eSTamas Berghammer   if (error.Fail())
6632850b1beSTodd Fiala     return error;
6642850b1beSTodd Fiala 
6652850b1beSTodd Fiala   uint8_t *dst = data_sp->GetBytes();
6662850b1beSTodd Fiala   ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());
6672850b1beSTodd Fiala   dst += GetRegisterInfoInterface().GetGPRSize();
66858db5bb2SValentina Giusti   if (m_xstate_type == XStateType::FXSAVE)
669a0e3c6f6SPavel Labath     ::memcpy(dst, &m_fpr.fxsave, sizeof(m_fpr.fxsave));
67058db5bb2SValentina Giusti   else if (m_xstate_type == XStateType::XSAVE) {
6712850b1beSTodd Fiala     lldb::ByteOrder byte_order = GetByteOrder();
6722850b1beSTodd Fiala 
67397e57e9bSValentina Giusti     if (IsCPUFeatureAvailable(RegSet::avx)) {
6742850b1beSTodd Fiala       // Assemble the YMM register content from the register halves.
675b9c1b51eSKate Stone       for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm;
676b9c1b51eSKate Stone            ++reg) {
677b9c1b51eSKate Stone         if (!CopyXSTATEtoYMM(reg, byte_order)) {
6785f957b54SValentina Giusti           error.SetErrorStringWithFormat(
6795f957b54SValentina Giusti               "NativeRegisterContextLinux_x86_64::%s "
680b9c1b51eSKate Stone               "CopyXSTATEtoYMM() failed for reg num "
681b9c1b51eSKate Stone               "%" PRIu32,
682b9c1b51eSKate Stone               __FUNCTION__, reg);
6832850b1beSTodd Fiala           return error;
6842850b1beSTodd Fiala         }
6852850b1beSTodd Fiala       }
6865f957b54SValentina Giusti     }
6872850b1beSTodd Fiala 
68897e57e9bSValentina Giusti     if (IsCPUFeatureAvailable(RegSet::mpx)) {
689cda0ae46SValentina Giusti       for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc;
690cda0ae46SValentina Giusti            ++reg) {
691cda0ae46SValentina Giusti         if (!CopyXSTATEtoMPX(reg)) {
6925f957b54SValentina Giusti           error.SetErrorStringWithFormat(
6935f957b54SValentina Giusti               "NativeRegisterContextLinux_x86_64::%s "
694cda0ae46SValentina Giusti               "CopyXSTATEtoMPX() failed for reg num "
695cda0ae46SValentina Giusti               "%" PRIu32,
696cda0ae46SValentina Giusti               __FUNCTION__, reg);
697cda0ae46SValentina Giusti           return error;
698cda0ae46SValentina Giusti         }
699cda0ae46SValentina Giusti       }
7005f957b54SValentina Giusti     }
7012850b1beSTodd Fiala     // Copy the extended register state including the assembled ymm registers.
7022850b1beSTodd Fiala     ::memcpy(dst, &m_fpr, sizeof(m_fpr));
703b9c1b51eSKate Stone   } else {
7042850b1beSTodd Fiala     assert(false && "how do we save the floating point registers?");
7052850b1beSTodd Fiala     error.SetErrorString("unsure how to save the floating point registers");
7062850b1beSTodd Fiala   }
7074778e410SRavitheja Addepally   /** The following code is specific to Linux x86 based architectures,
7084778e410SRavitheja Addepally    *  where the register orig_eax (32 bit)/orig_rax (64 bit) is set to
7094778e410SRavitheja Addepally    *  -1 to solve the bug 23659, such a setting prevents the automatic
7104778e410SRavitheja Addepally    *  decrement of the instruction pointer which was causing the SIGILL
7114778e410SRavitheja Addepally    *  exception.
7124778e410SRavitheja Addepally    * **/
7134778e410SRavitheja Addepally 
7144778e410SRavitheja Addepally   RegisterValue value((uint64_t)-1);
715b9c1b51eSKate Stone   const RegisterInfo *reg_info =
716b9c1b51eSKate Stone       GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
7174778e410SRavitheja Addepally   if (reg_info == nullptr)
7184778e410SRavitheja Addepally     reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
7194778e410SRavitheja Addepally 
72064ad85ceSTamas Berghammer   if (reg_info != nullptr)
7214778e410SRavitheja Addepally     return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, value);
7222850b1beSTodd Fiala 
7232850b1beSTodd Fiala   return error;
7242850b1beSTodd Fiala }
7252850b1beSTodd Fiala 
72697206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::WriteAllRegisterValues(
727b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
72897206d57SZachary Turner   Status error;
7292850b1beSTodd Fiala 
730b9c1b51eSKate Stone   if (!data_sp) {
731b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
732b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
733b9c1b51eSKate Stone         __FUNCTION__);
7342850b1beSTodd Fiala     return error;
7352850b1beSTodd Fiala   }
7362850b1beSTodd Fiala 
737b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
738993f2a42SPavel Labath     error.SetErrorStringWithFormatv(
739993f2a42SPavel Labath         "data_sp contained mismatched data size, expected {0}, actual {1}",
740993f2a42SPavel Labath         REG_CONTEXT_SIZE, data_sp->GetByteSize());
7412850b1beSTodd Fiala     return error;
7422850b1beSTodd Fiala   }
7432850b1beSTodd Fiala 
7442850b1beSTodd Fiala   uint8_t *src = data_sp->GetBytes();
745b9c1b51eSKate Stone   if (src == nullptr) {
746b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
747b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
748b9c1b51eSKate Stone                                    "pointer",
749b9c1b51eSKate Stone                                    __FUNCTION__);
7502850b1beSTodd Fiala     return error;
7512850b1beSTodd Fiala   }
7522850b1beSTodd Fiala   ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize());
7532850b1beSTodd Fiala 
754068f8a7eSTamas Berghammer   error = WriteGPR();
755068f8a7eSTamas Berghammer   if (error.Fail())
7562850b1beSTodd Fiala     return error;
7572850b1beSTodd Fiala 
7582850b1beSTodd Fiala   src += GetRegisterInfoInterface().GetGPRSize();
75958db5bb2SValentina Giusti   if (m_xstate_type == XStateType::FXSAVE)
760a0e3c6f6SPavel Labath     ::memcpy(&m_fpr.fxsave, src, sizeof(m_fpr.fxsave));
76158db5bb2SValentina Giusti   else if (m_xstate_type == XStateType::XSAVE)
762a0e3c6f6SPavel Labath     ::memcpy(&m_fpr.xsave, src, sizeof(m_fpr.xsave));
7632850b1beSTodd Fiala 
764068f8a7eSTamas Berghammer   error = WriteFPR();
765068f8a7eSTamas Berghammer   if (error.Fail())
7662850b1beSTodd Fiala     return error;
7672850b1beSTodd Fiala 
76858db5bb2SValentina Giusti   if (m_xstate_type == XStateType::XSAVE) {
7692850b1beSTodd Fiala     lldb::ByteOrder byte_order = GetByteOrder();
7702850b1beSTodd Fiala 
77197e57e9bSValentina Giusti     if (IsCPUFeatureAvailable(RegSet::avx)) {
7722850b1beSTodd Fiala       // Parse the YMM register content from the register halves.
773b9c1b51eSKate Stone       for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm;
774b9c1b51eSKate Stone            ++reg) {
775b9c1b51eSKate Stone         if (!CopyYMMtoXSTATE(reg, byte_order)) {
7765f957b54SValentina Giusti           error.SetErrorStringWithFormat(
7775f957b54SValentina Giusti               "NativeRegisterContextLinux_x86_64::%s "
778b9c1b51eSKate Stone               "CopyYMMtoXSTATE() failed for reg num "
779b9c1b51eSKate Stone               "%" PRIu32,
780b9c1b51eSKate Stone               __FUNCTION__, reg);
7812850b1beSTodd Fiala           return error;
7822850b1beSTodd Fiala         }
7832850b1beSTodd Fiala       }
7845f957b54SValentina Giusti     }
785cda0ae46SValentina Giusti 
78697e57e9bSValentina Giusti     if (IsCPUFeatureAvailable(RegSet::mpx)) {
787cda0ae46SValentina Giusti       for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc;
788cda0ae46SValentina Giusti            ++reg) {
789cda0ae46SValentina Giusti         if (!CopyMPXtoXSTATE(reg)) {
7905f957b54SValentina Giusti           error.SetErrorStringWithFormat(
7915f957b54SValentina Giusti               "NativeRegisterContextLinux_x86_64::%s "
792cda0ae46SValentina Giusti               "CopyMPXtoXSTATE() failed for reg num "
793cda0ae46SValentina Giusti               "%" PRIu32,
794cda0ae46SValentina Giusti               __FUNCTION__, reg);
795cda0ae46SValentina Giusti           return error;
796cda0ae46SValentina Giusti         }
797cda0ae46SValentina Giusti       }
7982850b1beSTodd Fiala     }
7995f957b54SValentina Giusti   }
8002850b1beSTodd Fiala 
8012850b1beSTodd Fiala   return error;
8022850b1beSTodd Fiala }
8032850b1beSTodd Fiala 
8045f957b54SValentina Giusti bool NativeRegisterContextLinux_x86_64::IsCPUFeatureAvailable(
8055f957b54SValentina Giusti     RegSet feature_code) const {
80658db5bb2SValentina Giusti   if (m_xstate_type == XStateType::Invalid) {
80758db5bb2SValentina Giusti     if (const_cast<NativeRegisterContextLinux_x86_64 *>(this)->ReadFPR().Fail())
8085f957b54SValentina Giusti       return false;
80958db5bb2SValentina Giusti   }
8105f957b54SValentina Giusti   switch (feature_code) {
81158db5bb2SValentina Giusti   case RegSet::gpr:
81258db5bb2SValentina Giusti   case RegSet::fpu:
8135f957b54SValentina Giusti     return true;
81458db5bb2SValentina Giusti   case RegSet::avx: // Check if CPU has AVX and if there is kernel support, by
81558db5bb2SValentina Giusti                     // reading in the XCR0 area of XSAVE.
816a0e3c6f6SPavel Labath     if ((m_fpr.xsave.i387.xcr0 & mask_XSTATE_AVX) == mask_XSTATE_AVX)
8175f957b54SValentina Giusti       return true;
81858db5bb2SValentina Giusti      break;
81958db5bb2SValentina Giusti   case RegSet::mpx: // Check if CPU has MPX and if there is kernel support, by
82058db5bb2SValentina Giusti                     // reading in the XCR0 area of XSAVE.
821a0e3c6f6SPavel Labath     if ((m_fpr.xsave.i387.xcr0 & mask_XSTATE_MPX) == mask_XSTATE_MPX)
82258db5bb2SValentina Giusti       return true;
82358db5bb2SValentina Giusti     break;
8245f957b54SValentina Giusti   }
8255f957b54SValentina Giusti   return false;
8265f957b54SValentina Giusti }
8275f957b54SValentina Giusti 
828b9c1b51eSKate Stone bool NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable(
829b9c1b51eSKate Stone     uint32_t set_index) const {
8302850b1beSTodd Fiala   uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
8312850b1beSTodd Fiala 
83297e57e9bSValentina Giusti   switch (static_cast<RegSet>(set_index)) {
83397e57e9bSValentina Giusti   case RegSet::gpr:
83497e57e9bSValentina Giusti   case RegSet::fpu:
8352850b1beSTodd Fiala     return (set_index < num_sets);
83697e57e9bSValentina Giusti   case RegSet::avx:
83797e57e9bSValentina Giusti     return IsCPUFeatureAvailable(RegSet::avx);
83897e57e9bSValentina Giusti   case RegSet::mpx:
83997e57e9bSValentina Giusti     return IsCPUFeatureAvailable(RegSet::mpx);
8405f957b54SValentina Giusti   }
84158db5bb2SValentina Giusti   return false;
8422850b1beSTodd Fiala }
8432850b1beSTodd Fiala 
844b9c1b51eSKate Stone bool NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const {
8452850b1beSTodd Fiala   // GPRs come first.
8462850b1beSTodd Fiala   return reg_index <= m_reg_info.last_gpr;
8472850b1beSTodd Fiala }
8482850b1beSTodd Fiala 
849b9c1b51eSKate Stone bool NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const {
850b9c1b51eSKate Stone   return (m_reg_info.first_fpr <= reg_index &&
851b9c1b51eSKate Stone           reg_index <= m_reg_info.last_fpr);
8522850b1beSTodd Fiala }
8532850b1beSTodd Fiala 
85497206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::WriteFPR() {
85558db5bb2SValentina Giusti   switch (m_xstate_type) {
85697e57e9bSValentina Giusti   case XStateType::FXSAVE:
8576ec13991SPavel Labath     return WriteRegisterSet(
858a0e3c6f6SPavel Labath         &m_iovec, sizeof(m_fpr.fxsave),
8596ec13991SPavel Labath         fxsr_regset(GetRegisterInfoInterface().GetTargetArchitecture()));
86097e57e9bSValentina Giusti   case XStateType::XSAVE:
861a0e3c6f6SPavel Labath     return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xsave), NT_X86_XSTATE);
862068f8a7eSTamas Berghammer   default:
86397206d57SZachary Turner     return Status("Unrecognized FPR type.");
864068f8a7eSTamas Berghammer   }
8652850b1beSTodd Fiala }
8662850b1beSTodd Fiala 
867b9c1b51eSKate Stone bool NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const {
86897e57e9bSValentina Giusti   if (!IsCPUFeatureAvailable(RegSet::avx))
8695f957b54SValentina Giusti     return false;
870b9c1b51eSKate Stone   return (m_reg_info.first_ymm <= reg_index &&
871b9c1b51eSKate Stone           reg_index <= m_reg_info.last_ymm);
8722850b1beSTodd Fiala }
8732850b1beSTodd Fiala 
874b9c1b51eSKate Stone bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM(
875b9c1b51eSKate Stone     uint32_t reg_index, lldb::ByteOrder byte_order) {
8762850b1beSTodd Fiala   if (!IsAVX(reg_index))
8772850b1beSTodd Fiala     return false;
8782850b1beSTodd Fiala 
879b9c1b51eSKate Stone   if (byte_order == lldb::eByteOrderLittle) {
8802850b1beSTodd Fiala     ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
881a0e3c6f6SPavel Labath              m_fpr.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
8822850b1beSTodd Fiala              sizeof(XMMReg));
883b9c1b51eSKate Stone     ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes +
884b9c1b51eSKate Stone                  sizeof(XMMReg),
885a0e3c6f6SPavel Labath              m_fpr.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
8862850b1beSTodd Fiala              sizeof(YMMHReg));
8872850b1beSTodd Fiala     return true;
8882850b1beSTodd Fiala   }
8892850b1beSTodd Fiala 
890b9c1b51eSKate Stone   if (byte_order == lldb::eByteOrderBig) {
891b9c1b51eSKate Stone     ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes +
892b9c1b51eSKate Stone                  sizeof(XMMReg),
893a0e3c6f6SPavel Labath              m_fpr.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
8942850b1beSTodd Fiala              sizeof(XMMReg));
8952850b1beSTodd Fiala     ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
896a0e3c6f6SPavel Labath              m_fpr.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
8972850b1beSTodd Fiala              sizeof(YMMHReg));
8982850b1beSTodd Fiala     return true;
8992850b1beSTodd Fiala   }
9002850b1beSTodd Fiala   return false; // unsupported or invalid byte order
9012850b1beSTodd Fiala }
9022850b1beSTodd Fiala 
903b9c1b51eSKate Stone bool NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(
904b9c1b51eSKate Stone     uint32_t reg, lldb::ByteOrder byte_order) {
9052850b1beSTodd Fiala   if (!IsAVX(reg))
9062850b1beSTodd Fiala     return false;
9072850b1beSTodd Fiala 
908b9c1b51eSKate Stone   if (byte_order == lldb::eByteOrderLittle) {
909a0e3c6f6SPavel Labath     ::memcpy(m_fpr.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
910b9c1b51eSKate Stone              m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, sizeof(XMMReg));
911a0e3c6f6SPavel Labath     ::memcpy(m_fpr.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
9122850b1beSTodd Fiala              m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
9132850b1beSTodd Fiala              sizeof(YMMHReg));
9142850b1beSTodd Fiala     return true;
9152850b1beSTodd Fiala   }
9162850b1beSTodd Fiala 
917b9c1b51eSKate Stone   if (byte_order == lldb::eByteOrderBig) {
918a0e3c6f6SPavel Labath     ::memcpy(m_fpr.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
9192850b1beSTodd Fiala              m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
9202850b1beSTodd Fiala              sizeof(XMMReg));
921a0e3c6f6SPavel Labath     ::memcpy(m_fpr.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
922b9c1b51eSKate Stone              m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, sizeof(YMMHReg));
9232850b1beSTodd Fiala     return true;
9242850b1beSTodd Fiala   }
9252850b1beSTodd Fiala   return false; // unsupported or invalid byte order
9262850b1beSTodd Fiala }
9272850b1beSTodd Fiala 
928b9c1b51eSKate Stone void *NativeRegisterContextLinux_x86_64::GetFPRBuffer() {
92958db5bb2SValentina Giusti   switch (m_xstate_type) {
93097e57e9bSValentina Giusti   case XStateType::FXSAVE:
931a0e3c6f6SPavel Labath     return &m_fpr.fxsave;
93297e57e9bSValentina Giusti   case XStateType::XSAVE:
933068f8a7eSTamas Berghammer     return &m_iovec;
9342850b1beSTodd Fiala   default:
935068f8a7eSTamas Berghammer     return nullptr;
9362850b1beSTodd Fiala   }
9372850b1beSTodd Fiala }
9382850b1beSTodd Fiala 
939b9c1b51eSKate Stone size_t NativeRegisterContextLinux_x86_64::GetFPRSize() {
94058db5bb2SValentina Giusti   switch (m_xstate_type) {
94197e57e9bSValentina Giusti   case XStateType::FXSAVE:
942a0e3c6f6SPavel Labath     return sizeof(m_fpr.fxsave);
94397e57e9bSValentina Giusti   case XStateType::XSAVE:
944068f8a7eSTamas Berghammer     return sizeof(m_iovec);
945068f8a7eSTamas Berghammer   default:
946068f8a7eSTamas Berghammer     return 0;
947068f8a7eSTamas Berghammer   }
9482850b1beSTodd Fiala }
9492850b1beSTodd Fiala 
95097206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::ReadFPR() {
95197206d57SZachary Turner   Status error;
95258db5bb2SValentina Giusti 
95358db5bb2SValentina Giusti   // Probe XSAVE and if it is not supported fall back to FXSAVE.
95458db5bb2SValentina Giusti   if (m_xstate_type != XStateType::FXSAVE) {
955a0e3c6f6SPavel Labath     error = ReadRegisterSet(&m_iovec, sizeof(m_fpr.xsave), NT_X86_XSTATE);
95658db5bb2SValentina Giusti     if (!error.Fail()) {
95758db5bb2SValentina Giusti       m_xstate_type = XStateType::XSAVE;
95858db5bb2SValentina Giusti       return error;
959296e063dSAbhishek Aggarwal     }
960068f8a7eSTamas Berghammer   }
9616ec13991SPavel Labath   error = ReadRegisterSet(
962a0e3c6f6SPavel Labath       &m_iovec, sizeof(m_fpr.xsave),
9636ec13991SPavel Labath       fxsr_regset(GetRegisterInfoInterface().GetTargetArchitecture()));
96458db5bb2SValentina Giusti   if (!error.Fail()) {
96558db5bb2SValentina Giusti     m_xstate_type = XStateType::FXSAVE;
96658db5bb2SValentina Giusti     return error;
96758db5bb2SValentina Giusti   }
96897206d57SZachary Turner   return Status("Unrecognized FPR type.");
9692850b1beSTodd Fiala }
9702850b1beSTodd Fiala 
971cda0ae46SValentina Giusti bool NativeRegisterContextLinux_x86_64::IsMPX(uint32_t reg_index) const {
97297e57e9bSValentina Giusti   if (!IsCPUFeatureAvailable(RegSet::mpx))
9735f957b54SValentina Giusti     return false;
974cda0ae46SValentina Giusti   return (m_reg_info.first_mpxr <= reg_index &&
975cda0ae46SValentina Giusti           reg_index <= m_reg_info.last_mpxc);
976cda0ae46SValentina Giusti }
977cda0ae46SValentina Giusti 
978cda0ae46SValentina Giusti bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoMPX(uint32_t reg) {
979cda0ae46SValentina Giusti   if (!IsMPX(reg))
980cda0ae46SValentina Giusti     return false;
981cda0ae46SValentina Giusti 
982cda0ae46SValentina Giusti   if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) {
983cda0ae46SValentina Giusti     ::memcpy(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes,
984a0e3c6f6SPavel Labath              m_fpr.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes,
985cda0ae46SValentina Giusti              sizeof(MPXReg));
986cda0ae46SValentina Giusti   } else {
987cda0ae46SValentina Giusti     ::memcpy(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes,
988a0e3c6f6SPavel Labath              m_fpr.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes,
989cda0ae46SValentina Giusti              sizeof(MPXCsr));
990cda0ae46SValentina Giusti   }
991cda0ae46SValentina Giusti   return true;
992cda0ae46SValentina Giusti }
993cda0ae46SValentina Giusti 
994cda0ae46SValentina Giusti bool NativeRegisterContextLinux_x86_64::CopyMPXtoXSTATE(uint32_t reg) {
995cda0ae46SValentina Giusti   if (!IsMPX(reg))
996cda0ae46SValentina Giusti     return false;
997cda0ae46SValentina Giusti 
998cda0ae46SValentina Giusti   if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) {
999a0e3c6f6SPavel Labath     ::memcpy(m_fpr.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes,
1000cda0ae46SValentina Giusti              m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes, sizeof(MPXReg));
1001cda0ae46SValentina Giusti   } else {
1002a0e3c6f6SPavel Labath     ::memcpy(m_fpr.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes,
1003cda0ae46SValentina Giusti              m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes, sizeof(MPXCsr));
1004cda0ae46SValentina Giusti   }
1005cda0ae46SValentina Giusti   return true;
1006cda0ae46SValentina Giusti }
1007cda0ae46SValentina Giusti 
100897206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint32_t wp_index,
1009b9c1b51eSKate Stone                                                           bool &is_hit) {
101018fe6404SChaoren Lin   if (wp_index >= NumSupportedHardwareWatchpoints())
101197206d57SZachary Turner     return Status("Watchpoint index out of range");
101218fe6404SChaoren Lin 
101318fe6404SChaoren Lin   RegisterValue reg_value;
101497206d57SZachary Turner   Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
1015b9c1b51eSKate Stone   if (error.Fail()) {
1016c16f5dcaSChaoren Lin     is_hit = false;
1017c16f5dcaSChaoren Lin     return error;
1018c16f5dcaSChaoren Lin   }
101918fe6404SChaoren Lin 
102018fe6404SChaoren Lin   uint64_t status_bits = reg_value.GetAsUInt64();
102118fe6404SChaoren Lin 
1022c16f5dcaSChaoren Lin   is_hit = status_bits & (1 << wp_index);
102318fe6404SChaoren Lin 
102418fe6404SChaoren Lin   return error;
102518fe6404SChaoren Lin }
102618fe6404SChaoren Lin 
102797206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex(
1028b9c1b51eSKate Stone     uint32_t &wp_index, lldb::addr_t trap_addr) {
1029c16f5dcaSChaoren Lin   uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
1030b9c1b51eSKate Stone   for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
1031c16f5dcaSChaoren Lin     bool is_hit;
103297206d57SZachary Turner     Status error = IsWatchpointHit(wp_index, is_hit);
1033c16f5dcaSChaoren Lin     if (error.Fail()) {
1034c16f5dcaSChaoren Lin       wp_index = LLDB_INVALID_INDEX32;
1035c16f5dcaSChaoren Lin       return error;
1036c16f5dcaSChaoren Lin     } else if (is_hit) {
1037c16f5dcaSChaoren Lin       return error;
1038c16f5dcaSChaoren Lin     }
1039c16f5dcaSChaoren Lin   }
1040c16f5dcaSChaoren Lin   wp_index = LLDB_INVALID_INDEX32;
104197206d57SZachary Turner   return Status();
1042c16f5dcaSChaoren Lin }
1043c16f5dcaSChaoren Lin 
104497206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index,
1045b9c1b51eSKate Stone                                                              bool &is_vacant) {
104618fe6404SChaoren Lin   if (wp_index >= NumSupportedHardwareWatchpoints())
104797206d57SZachary Turner     return Status("Watchpoint index out of range");
104818fe6404SChaoren Lin 
104918fe6404SChaoren Lin   RegisterValue reg_value;
105097206d57SZachary Turner   Status error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
1051b9c1b51eSKate Stone   if (error.Fail()) {
1052c16f5dcaSChaoren Lin     is_vacant = false;
1053c16f5dcaSChaoren Lin     return error;
1054c16f5dcaSChaoren Lin   }
105518fe6404SChaoren Lin 
105618fe6404SChaoren Lin   uint64_t control_bits = reg_value.GetAsUInt64();
105718fe6404SChaoren Lin 
1058c16f5dcaSChaoren Lin   is_vacant = !(control_bits & (1 << (2 * wp_index)));
105918fe6404SChaoren Lin 
106018fe6404SChaoren Lin   return error;
106118fe6404SChaoren Lin }
106218fe6404SChaoren Lin 
106397206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex(
106418fe6404SChaoren Lin     lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
106518fe6404SChaoren Lin 
106618fe6404SChaoren Lin   if (wp_index >= NumSupportedHardwareWatchpoints())
106797206d57SZachary Turner     return Status("Watchpoint index out of range");
106818fe6404SChaoren Lin 
1069b9c1b51eSKate Stone   // Read only watchpoints aren't supported on x86_64. Fall back to read/write
1070b9c1b51eSKate Stone   // waitchpoints instead.
1071b9c1b51eSKate Stone   // TODO: Add logic to detect when a write happens and ignore that watchpoint
1072b9c1b51eSKate Stone   // hit.
1073cf8eb9daSOmair Javaid   if (watch_flags == 0x2)
107440caea63STamas Berghammer     watch_flags = 0x3;
1075cf8eb9daSOmair Javaid 
107618fe6404SChaoren Lin   if (watch_flags != 0x1 && watch_flags != 0x3)
107797206d57SZachary Turner     return Status("Invalid read/write bits for watchpoint");
107818fe6404SChaoren Lin 
107918fe6404SChaoren Lin   if (size != 1 && size != 2 && size != 4 && size != 8)
108097206d57SZachary Turner     return Status("Invalid size for watchpoint");
108118fe6404SChaoren Lin 
1082c16f5dcaSChaoren Lin   bool is_vacant;
108397206d57SZachary Turner   Status error = IsWatchpointVacant(wp_index, is_vacant);
1084b9c1b51eSKate Stone   if (error.Fail())
1085b9c1b51eSKate Stone     return error;
1086b9c1b51eSKate Stone   if (!is_vacant)
108797206d57SZachary Turner     return Status("Watchpoint index not vacant");
108818fe6404SChaoren Lin 
108918fe6404SChaoren Lin   RegisterValue reg_value;
10906a504f6eSChaoren Lin   error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
1091b9c1b51eSKate Stone   if (error.Fail())
1092b9c1b51eSKate Stone     return error;
109318fe6404SChaoren Lin 
109405097246SAdrian Prantl   // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7
109518fe6404SChaoren Lin   uint64_t enable_bit = 1 << (2 * wp_index);
109618fe6404SChaoren Lin 
109718fe6404SChaoren Lin   // set bits 16-17, 20-21, 24-25, or 28-29
109818fe6404SChaoren Lin   // with 0b01 for write, and 0b11 for read/write
109918fe6404SChaoren Lin   uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
110018fe6404SChaoren Lin 
110118fe6404SChaoren Lin   // set bits 18-19, 22-23, 26-27, or 30-31
110218fe6404SChaoren Lin   // with 0b00, 0b01, 0b10, or 0b11
110318fe6404SChaoren Lin   // for 1, 2, 8 (if supported), or 4 bytes, respectively
110418fe6404SChaoren Lin   uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
110518fe6404SChaoren Lin 
110618fe6404SChaoren Lin   uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
110718fe6404SChaoren Lin 
110818fe6404SChaoren Lin   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
110918fe6404SChaoren Lin 
111018fe6404SChaoren Lin   control_bits |= enable_bit | rw_bits | size_bits;
111118fe6404SChaoren Lin 
1112068f8a7eSTamas Berghammer   error = WriteRegisterRaw(m_reg_info.first_dr + wp_index, RegisterValue(addr));
1113b9c1b51eSKate Stone   if (error.Fail())
1114b9c1b51eSKate Stone     return error;
111518fe6404SChaoren Lin 
1116b9c1b51eSKate Stone   error =
1117b9c1b51eSKate Stone       WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
1118b9c1b51eSKate Stone   if (error.Fail())
1119b9c1b51eSKate Stone     return error;
112018fe6404SChaoren Lin 
112118fe6404SChaoren Lin   error.Clear();
112218fe6404SChaoren Lin   return error;
112318fe6404SChaoren Lin }
112418fe6404SChaoren Lin 
1125b9c1b51eSKate Stone bool NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(
1126b9c1b51eSKate Stone     uint32_t wp_index) {
112718fe6404SChaoren Lin   if (wp_index >= NumSupportedHardwareWatchpoints())
112818fe6404SChaoren Lin     return false;
112918fe6404SChaoren Lin 
113018fe6404SChaoren Lin   RegisterValue reg_value;
113118fe6404SChaoren Lin 
113205097246SAdrian Prantl   // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of
113305097246SAdrian Prantl   // the debug status register (DR6)
113497206d57SZachary Turner   Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
1135b9c1b51eSKate Stone   if (error.Fail())
1136b9c1b51eSKate Stone     return false;
113718fe6404SChaoren Lin   uint64_t bit_mask = 1 << wp_index;
113818fe6404SChaoren Lin   uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
1139068f8a7eSTamas Berghammer   error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
1140b9c1b51eSKate Stone   if (error.Fail())
1141b9c1b51eSKate Stone     return false;
114218fe6404SChaoren Lin 
114305097246SAdrian Prantl   // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19},
114405097246SAdrian Prantl   // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register
114505097246SAdrian Prantl   // (DR7)
11466a504f6eSChaoren Lin   error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
1147b9c1b51eSKate Stone   if (error.Fail())
1148b9c1b51eSKate Stone     return false;
114918fe6404SChaoren Lin   bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
115018fe6404SChaoren Lin   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1151b9c1b51eSKate Stone   return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits))
1152b9c1b51eSKate Stone       .Success();
115318fe6404SChaoren Lin }
115418fe6404SChaoren Lin 
115597206d57SZachary Turner Status NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints() {
115618fe6404SChaoren Lin   RegisterValue reg_value;
115718fe6404SChaoren Lin 
115818fe6404SChaoren Lin   // clear bits {0-4} of the debug status register (DR6)
115997206d57SZachary Turner   Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
1160b9c1b51eSKate Stone   if (error.Fail())
1161b9c1b51eSKate Stone     return error;
116218fe6404SChaoren Lin   uint64_t bit_mask = 0xF;
116318fe6404SChaoren Lin   uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
1164068f8a7eSTamas Berghammer   error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
1165b9c1b51eSKate Stone   if (error.Fail())
1166b9c1b51eSKate Stone     return error;
116718fe6404SChaoren Lin 
116818fe6404SChaoren Lin   // clear bits {0-7,16-31} of the debug control register (DR7)
11696a504f6eSChaoren Lin   error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
1170b9c1b51eSKate Stone   if (error.Fail())
1171b9c1b51eSKate Stone     return error;
117218fe6404SChaoren Lin   bit_mask = 0xFF | (0xFFFF << 16);
117318fe6404SChaoren Lin   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1174068f8a7eSTamas Berghammer   return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
117518fe6404SChaoren Lin }
117618fe6404SChaoren Lin 
1177b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint(
1178b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
1179c16f5dcaSChaoren Lin   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
118018fe6404SChaoren Lin   const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
1181b9c1b51eSKate Stone   for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
1182c16f5dcaSChaoren Lin     bool is_vacant;
118397206d57SZachary Turner     Status error = IsWatchpointVacant(wp_index, is_vacant);
1184b9c1b51eSKate Stone     if (is_vacant) {
1185c16f5dcaSChaoren Lin       error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
1186c16f5dcaSChaoren Lin       if (error.Success())
118718fe6404SChaoren Lin         return wp_index;
118818fe6404SChaoren Lin     }
1189b9c1b51eSKate Stone     if (error.Fail() && log) {
1190c16f5dcaSChaoren Lin       log->Printf("NativeRegisterContextLinux_x86_64::%s Error: %s",
1191c16f5dcaSChaoren Lin                   __FUNCTION__, error.AsCString());
1192c16f5dcaSChaoren Lin     }
1193c16f5dcaSChaoren Lin   }
119418fe6404SChaoren Lin   return LLDB_INVALID_INDEX32;
119518fe6404SChaoren Lin }
119618fe6404SChaoren Lin 
119718fe6404SChaoren Lin lldb::addr_t
1198b9c1b51eSKate Stone NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index) {
119918fe6404SChaoren Lin   if (wp_index >= NumSupportedHardwareWatchpoints())
120018fe6404SChaoren Lin     return LLDB_INVALID_ADDRESS;
120118fe6404SChaoren Lin   RegisterValue reg_value;
120218fe6404SChaoren Lin   if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail())
120318fe6404SChaoren Lin     return LLDB_INVALID_ADDRESS;
120418fe6404SChaoren Lin   return reg_value.GetAsUInt64();
120518fe6404SChaoren Lin }
120618fe6404SChaoren Lin 
1207b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints() {
120818fe6404SChaoren Lin   // Available debug address registers: dr0, dr1, dr2, dr3
120918fe6404SChaoren Lin   return 4;
121018fe6404SChaoren Lin }
1211068f8a7eSTamas Berghammer 
1212068f8a7eSTamas Berghammer #endif // defined(__i386__) || defined(__x86_64__)
1213