12850b1beSTodd Fiala //===-- NativeRegisterContextLinux_x86_64.cpp ---------------*- C++ -*-===//
22850b1beSTodd Fiala //
32850b1beSTodd Fiala //                     The LLVM Compiler Infrastructure
42850b1beSTodd Fiala //
52850b1beSTodd Fiala // This file is distributed under the University of Illinois Open Source
62850b1beSTodd Fiala // License. See LICENSE.TXT for details.
72850b1beSTodd Fiala //
82850b1beSTodd Fiala //===----------------------------------------------------------------------===//
92850b1beSTodd Fiala 
102850b1beSTodd Fiala #include "NativeRegisterContextLinux_x86_64.h"
112850b1beSTodd Fiala 
122850b1beSTodd Fiala #include "lldb/lldb-private-forward.h"
132850b1beSTodd Fiala #include "lldb/Core/DataBufferHeap.h"
142850b1beSTodd Fiala #include "lldb/Core/Error.h"
152850b1beSTodd Fiala #include "lldb/Core/RegisterValue.h"
162fe1d0abSChaoren Lin #include "lldb/Host/common/NativeProcessProtocol.h"
172fe1d0abSChaoren Lin #include "lldb/Host/common/NativeThreadProtocol.h"
182850b1beSTodd Fiala #include "Plugins/Process/Linux/NativeProcessLinux.h"
192850b1beSTodd Fiala 
202850b1beSTodd Fiala using namespace lldb_private;
212850b1beSTodd Fiala 
222850b1beSTodd Fiala // ----------------------------------------------------------------------------
232850b1beSTodd Fiala // Private namespace.
242850b1beSTodd Fiala // ----------------------------------------------------------------------------
252850b1beSTodd Fiala 
262850b1beSTodd Fiala namespace
272850b1beSTodd Fiala {
282850b1beSTodd Fiala     // x86 32-bit general purpose registers.
292850b1beSTodd Fiala     const uint32_t
302850b1beSTodd Fiala     g_gpr_regnums_i386[] =
312850b1beSTodd Fiala     {
327f013bcdSZachary Turner         lldb_eax_i386,
337f013bcdSZachary Turner         lldb_ebx_i386,
347f013bcdSZachary Turner         lldb_ecx_i386,
357f013bcdSZachary Turner         lldb_edx_i386,
367f013bcdSZachary Turner         lldb_edi_i386,
377f013bcdSZachary Turner         lldb_esi_i386,
387f013bcdSZachary Turner         lldb_ebp_i386,
397f013bcdSZachary Turner         lldb_esp_i386,
407f013bcdSZachary Turner         lldb_eip_i386,
417f013bcdSZachary Turner         lldb_eflags_i386,
427f013bcdSZachary Turner         lldb_cs_i386,
437f013bcdSZachary Turner         lldb_fs_i386,
447f013bcdSZachary Turner         lldb_gs_i386,
457f013bcdSZachary Turner         lldb_ss_i386,
467f013bcdSZachary Turner         lldb_ds_i386,
477f013bcdSZachary Turner         lldb_es_i386,
487f013bcdSZachary Turner         lldb_ax_i386,
497f013bcdSZachary Turner         lldb_bx_i386,
507f013bcdSZachary Turner         lldb_cx_i386,
517f013bcdSZachary Turner         lldb_dx_i386,
527f013bcdSZachary Turner         lldb_di_i386,
537f013bcdSZachary Turner         lldb_si_i386,
547f013bcdSZachary Turner         lldb_bp_i386,
557f013bcdSZachary Turner         lldb_sp_i386,
567f013bcdSZachary Turner         lldb_ah_i386,
577f013bcdSZachary Turner         lldb_bh_i386,
587f013bcdSZachary Turner         lldb_ch_i386,
597f013bcdSZachary Turner         lldb_dh_i386,
607f013bcdSZachary Turner         lldb_al_i386,
617f013bcdSZachary Turner         lldb_bl_i386,
627f013bcdSZachary Turner         lldb_cl_i386,
637f013bcdSZachary Turner         lldb_dl_i386,
642850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
652850b1beSTodd Fiala     };
662850b1beSTodd Fiala     static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386,
672850b1beSTodd Fiala                   "g_gpr_regnums_i386 has wrong number of register infos");
682850b1beSTodd Fiala 
692850b1beSTodd Fiala     // x86 32-bit floating point registers.
702850b1beSTodd Fiala     const uint32_t
712850b1beSTodd Fiala     g_fpu_regnums_i386[] =
722850b1beSTodd Fiala     {
737f013bcdSZachary Turner         lldb_fctrl_i386,
747f013bcdSZachary Turner         lldb_fstat_i386,
757f013bcdSZachary Turner         lldb_ftag_i386,
767f013bcdSZachary Turner         lldb_fop_i386,
777f013bcdSZachary Turner         lldb_fiseg_i386,
787f013bcdSZachary Turner         lldb_fioff_i386,
797f013bcdSZachary Turner         lldb_foseg_i386,
807f013bcdSZachary Turner         lldb_fooff_i386,
817f013bcdSZachary Turner         lldb_mxcsr_i386,
827f013bcdSZachary Turner         lldb_mxcsrmask_i386,
837f013bcdSZachary Turner         lldb_st0_i386,
847f013bcdSZachary Turner         lldb_st1_i386,
857f013bcdSZachary Turner         lldb_st2_i386,
867f013bcdSZachary Turner         lldb_st3_i386,
877f013bcdSZachary Turner         lldb_st4_i386,
887f013bcdSZachary Turner         lldb_st5_i386,
897f013bcdSZachary Turner         lldb_st6_i386,
907f013bcdSZachary Turner         lldb_st7_i386,
917f013bcdSZachary Turner         lldb_mm0_i386,
927f013bcdSZachary Turner         lldb_mm1_i386,
937f013bcdSZachary Turner         lldb_mm2_i386,
947f013bcdSZachary Turner         lldb_mm3_i386,
957f013bcdSZachary Turner         lldb_mm4_i386,
967f013bcdSZachary Turner         lldb_mm5_i386,
977f013bcdSZachary Turner         lldb_mm6_i386,
987f013bcdSZachary Turner         lldb_mm7_i386,
997f013bcdSZachary Turner         lldb_xmm0_i386,
1007f013bcdSZachary Turner         lldb_xmm1_i386,
1017f013bcdSZachary Turner         lldb_xmm2_i386,
1027f013bcdSZachary Turner         lldb_xmm3_i386,
1037f013bcdSZachary Turner         lldb_xmm4_i386,
1047f013bcdSZachary Turner         lldb_xmm5_i386,
1057f013bcdSZachary Turner         lldb_xmm6_i386,
1067f013bcdSZachary Turner         lldb_xmm7_i386,
1072850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
1082850b1beSTodd Fiala     };
1092850b1beSTodd Fiala     static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
1102850b1beSTodd Fiala                   "g_fpu_regnums_i386 has wrong number of register infos");
1112850b1beSTodd Fiala 
1122850b1beSTodd Fiala     // x86 32-bit AVX registers.
1132850b1beSTodd Fiala     const uint32_t
1142850b1beSTodd Fiala     g_avx_regnums_i386[] =
1152850b1beSTodd Fiala     {
1167f013bcdSZachary Turner         lldb_ymm0_i386,
1177f013bcdSZachary Turner         lldb_ymm1_i386,
1187f013bcdSZachary Turner         lldb_ymm2_i386,
1197f013bcdSZachary Turner         lldb_ymm3_i386,
1207f013bcdSZachary Turner         lldb_ymm4_i386,
1217f013bcdSZachary Turner         lldb_ymm5_i386,
1227f013bcdSZachary Turner         lldb_ymm6_i386,
1237f013bcdSZachary Turner         lldb_ymm7_i386,
1242850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
1252850b1beSTodd Fiala     };
1262850b1beSTodd Fiala     static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386,
1272850b1beSTodd Fiala                   " g_avx_regnums_i386 has wrong number of register infos");
1282850b1beSTodd Fiala 
1292850b1beSTodd Fiala     // x86 64-bit general purpose registers.
1302850b1beSTodd Fiala     static const
1312850b1beSTodd Fiala     uint32_t g_gpr_regnums_x86_64[] =
1322850b1beSTodd Fiala     {
1337f013bcdSZachary Turner         lldb_rax_x86_64,
1347f013bcdSZachary Turner         lldb_rbx_x86_64,
1357f013bcdSZachary Turner         lldb_rcx_x86_64,
1367f013bcdSZachary Turner         lldb_rdx_x86_64,
1377f013bcdSZachary Turner         lldb_rdi_x86_64,
1387f013bcdSZachary Turner         lldb_rsi_x86_64,
1397f013bcdSZachary Turner         lldb_rbp_x86_64,
1407f013bcdSZachary Turner         lldb_rsp_x86_64,
1417f013bcdSZachary Turner         lldb_r8_x86_64,
1427f013bcdSZachary Turner         lldb_r9_x86_64,
1437f013bcdSZachary Turner         lldb_r10_x86_64,
1447f013bcdSZachary Turner         lldb_r11_x86_64,
1457f013bcdSZachary Turner         lldb_r12_x86_64,
1467f013bcdSZachary Turner         lldb_r13_x86_64,
1477f013bcdSZachary Turner         lldb_r14_x86_64,
1487f013bcdSZachary Turner         lldb_r15_x86_64,
1497f013bcdSZachary Turner         lldb_rip_x86_64,
1507f013bcdSZachary Turner         lldb_rflags_x86_64,
1517f013bcdSZachary Turner         lldb_cs_x86_64,
1527f013bcdSZachary Turner         lldb_fs_x86_64,
1537f013bcdSZachary Turner         lldb_gs_x86_64,
1547f013bcdSZachary Turner         lldb_ss_x86_64,
1557f013bcdSZachary Turner         lldb_ds_x86_64,
1567f013bcdSZachary Turner         lldb_es_x86_64,
1577f013bcdSZachary Turner         lldb_eax_x86_64,
1587f013bcdSZachary Turner         lldb_ebx_x86_64,
1597f013bcdSZachary Turner         lldb_ecx_x86_64,
1607f013bcdSZachary Turner         lldb_edx_x86_64,
1617f013bcdSZachary Turner         lldb_edi_x86_64,
1627f013bcdSZachary Turner         lldb_esi_x86_64,
1637f013bcdSZachary Turner         lldb_ebp_x86_64,
1647f013bcdSZachary Turner         lldb_esp_x86_64,
1657f013bcdSZachary Turner         lldb_r8d_x86_64,    // Low 32 bits or r8
1667f013bcdSZachary Turner         lldb_r9d_x86_64,    // Low 32 bits or r9
1677f013bcdSZachary Turner         lldb_r10d_x86_64,   // Low 32 bits or r10
1687f013bcdSZachary Turner         lldb_r11d_x86_64,   // Low 32 bits or r11
1697f013bcdSZachary Turner         lldb_r12d_x86_64,   // Low 32 bits or r12
1707f013bcdSZachary Turner         lldb_r13d_x86_64,   // Low 32 bits or r13
1717f013bcdSZachary Turner         lldb_r14d_x86_64,   // Low 32 bits or r14
1727f013bcdSZachary Turner         lldb_r15d_x86_64,   // Low 32 bits or r15
1737f013bcdSZachary Turner         lldb_ax_x86_64,
1747f013bcdSZachary Turner         lldb_bx_x86_64,
1757f013bcdSZachary Turner         lldb_cx_x86_64,
1767f013bcdSZachary Turner         lldb_dx_x86_64,
1777f013bcdSZachary Turner         lldb_di_x86_64,
1787f013bcdSZachary Turner         lldb_si_x86_64,
1797f013bcdSZachary Turner         lldb_bp_x86_64,
1807f013bcdSZachary Turner         lldb_sp_x86_64,
1817f013bcdSZachary Turner         lldb_r8w_x86_64,    // Low 16 bits or r8
1827f013bcdSZachary Turner         lldb_r9w_x86_64,    // Low 16 bits or r9
1837f013bcdSZachary Turner         lldb_r10w_x86_64,   // Low 16 bits or r10
1847f013bcdSZachary Turner         lldb_r11w_x86_64,   // Low 16 bits or r11
1857f013bcdSZachary Turner         lldb_r12w_x86_64,   // Low 16 bits or r12
1867f013bcdSZachary Turner         lldb_r13w_x86_64,   // Low 16 bits or r13
1877f013bcdSZachary Turner         lldb_r14w_x86_64,   // Low 16 bits or r14
1887f013bcdSZachary Turner         lldb_r15w_x86_64,   // Low 16 bits or r15
1897f013bcdSZachary Turner         lldb_ah_x86_64,
1907f013bcdSZachary Turner         lldb_bh_x86_64,
1917f013bcdSZachary Turner         lldb_ch_x86_64,
1927f013bcdSZachary Turner         lldb_dh_x86_64,
1937f013bcdSZachary Turner         lldb_al_x86_64,
1947f013bcdSZachary Turner         lldb_bl_x86_64,
1957f013bcdSZachary Turner         lldb_cl_x86_64,
1967f013bcdSZachary Turner         lldb_dl_x86_64,
1977f013bcdSZachary Turner         lldb_dil_x86_64,
1987f013bcdSZachary Turner         lldb_sil_x86_64,
1997f013bcdSZachary Turner         lldb_bpl_x86_64,
2007f013bcdSZachary Turner         lldb_spl_x86_64,
2017f013bcdSZachary Turner         lldb_r8l_x86_64,    // Low 8 bits or r8
2027f013bcdSZachary Turner         lldb_r9l_x86_64,    // Low 8 bits or r9
2037f013bcdSZachary Turner         lldb_r10l_x86_64,   // Low 8 bits or r10
2047f013bcdSZachary Turner         lldb_r11l_x86_64,   // Low 8 bits or r11
2057f013bcdSZachary Turner         lldb_r12l_x86_64,   // Low 8 bits or r12
2067f013bcdSZachary Turner         lldb_r13l_x86_64,   // Low 8 bits or r13
2077f013bcdSZachary Turner         lldb_r14l_x86_64,   // Low 8 bits or r14
2087f013bcdSZachary Turner         lldb_r15l_x86_64,   // Low 8 bits or r15
2092850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
2102850b1beSTodd Fiala     };
2112850b1beSTodd Fiala     static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64,
2122850b1beSTodd Fiala                   "g_gpr_regnums_x86_64 has wrong number of register infos");
2132850b1beSTodd Fiala 
2142850b1beSTodd Fiala     // x86 64-bit floating point registers.
2152850b1beSTodd Fiala     static const uint32_t
2162850b1beSTodd Fiala     g_fpu_regnums_x86_64[] =
2172850b1beSTodd Fiala     {
2187f013bcdSZachary Turner         lldb_fctrl_x86_64,
2197f013bcdSZachary Turner         lldb_fstat_x86_64,
2207f013bcdSZachary Turner         lldb_ftag_x86_64,
2217f013bcdSZachary Turner         lldb_fop_x86_64,
2227f013bcdSZachary Turner         lldb_fiseg_x86_64,
2237f013bcdSZachary Turner         lldb_fioff_x86_64,
2247f013bcdSZachary Turner         lldb_foseg_x86_64,
2257f013bcdSZachary Turner         lldb_fooff_x86_64,
2267f013bcdSZachary Turner         lldb_mxcsr_x86_64,
2277f013bcdSZachary Turner         lldb_mxcsrmask_x86_64,
2287f013bcdSZachary Turner         lldb_st0_x86_64,
2297f013bcdSZachary Turner         lldb_st1_x86_64,
2307f013bcdSZachary Turner         lldb_st2_x86_64,
2317f013bcdSZachary Turner         lldb_st3_x86_64,
2327f013bcdSZachary Turner         lldb_st4_x86_64,
2337f013bcdSZachary Turner         lldb_st5_x86_64,
2347f013bcdSZachary Turner         lldb_st6_x86_64,
2357f013bcdSZachary Turner         lldb_st7_x86_64,
2367f013bcdSZachary Turner         lldb_mm0_x86_64,
2377f013bcdSZachary Turner         lldb_mm1_x86_64,
2387f013bcdSZachary Turner         lldb_mm2_x86_64,
2397f013bcdSZachary Turner         lldb_mm3_x86_64,
2407f013bcdSZachary Turner         lldb_mm4_x86_64,
2417f013bcdSZachary Turner         lldb_mm5_x86_64,
2427f013bcdSZachary Turner         lldb_mm6_x86_64,
2437f013bcdSZachary Turner         lldb_mm7_x86_64,
2447f013bcdSZachary Turner         lldb_xmm0_x86_64,
2457f013bcdSZachary Turner         lldb_xmm1_x86_64,
2467f013bcdSZachary Turner         lldb_xmm2_x86_64,
2477f013bcdSZachary Turner         lldb_xmm3_x86_64,
2487f013bcdSZachary Turner         lldb_xmm4_x86_64,
2497f013bcdSZachary Turner         lldb_xmm5_x86_64,
2507f013bcdSZachary Turner         lldb_xmm6_x86_64,
2517f013bcdSZachary Turner         lldb_xmm7_x86_64,
2527f013bcdSZachary Turner         lldb_xmm8_x86_64,
2537f013bcdSZachary Turner         lldb_xmm9_x86_64,
2547f013bcdSZachary Turner         lldb_xmm10_x86_64,
2557f013bcdSZachary Turner         lldb_xmm11_x86_64,
2567f013bcdSZachary Turner         lldb_xmm12_x86_64,
2577f013bcdSZachary Turner         lldb_xmm13_x86_64,
2587f013bcdSZachary Turner         lldb_xmm14_x86_64,
2597f013bcdSZachary Turner         lldb_xmm15_x86_64,
2602850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
2612850b1beSTodd Fiala     };
2622850b1beSTodd Fiala     static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
2632850b1beSTodd Fiala                   "g_fpu_regnums_x86_64 has wrong number of register infos");
2642850b1beSTodd Fiala 
2652850b1beSTodd Fiala     // x86 64-bit AVX registers.
2662850b1beSTodd Fiala     static const uint32_t
2672850b1beSTodd Fiala     g_avx_regnums_x86_64[] =
2682850b1beSTodd Fiala     {
2697f013bcdSZachary Turner         lldb_ymm0_x86_64,
2707f013bcdSZachary Turner         lldb_ymm1_x86_64,
2717f013bcdSZachary Turner         lldb_ymm2_x86_64,
2727f013bcdSZachary Turner         lldb_ymm3_x86_64,
2737f013bcdSZachary Turner         lldb_ymm4_x86_64,
2747f013bcdSZachary Turner         lldb_ymm5_x86_64,
2757f013bcdSZachary Turner         lldb_ymm6_x86_64,
2767f013bcdSZachary Turner         lldb_ymm7_x86_64,
2777f013bcdSZachary Turner         lldb_ymm8_x86_64,
2787f013bcdSZachary Turner         lldb_ymm9_x86_64,
2797f013bcdSZachary Turner         lldb_ymm10_x86_64,
2807f013bcdSZachary Turner         lldb_ymm11_x86_64,
2817f013bcdSZachary Turner         lldb_ymm12_x86_64,
2827f013bcdSZachary Turner         lldb_ymm13_x86_64,
2837f013bcdSZachary Turner         lldb_ymm14_x86_64,
2847f013bcdSZachary Turner         lldb_ymm15_x86_64,
2852850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
2862850b1beSTodd Fiala     };
2872850b1beSTodd Fiala     static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64,
2882850b1beSTodd Fiala                   "g_avx_regnums_x86_64 has wrong number of register infos");
2892850b1beSTodd Fiala 
2902850b1beSTodd Fiala     // Number of register sets provided by this context.
2912850b1beSTodd Fiala     enum
2922850b1beSTodd Fiala     {
2932850b1beSTodd Fiala         k_num_extended_register_sets = 1,
2942850b1beSTodd Fiala         k_num_register_sets = 3
2952850b1beSTodd Fiala     };
2962850b1beSTodd Fiala 
2972850b1beSTodd Fiala     // Register sets for x86 32-bit.
2982850b1beSTodd Fiala     static const RegisterSet
2992850b1beSTodd Fiala     g_reg_sets_i386[k_num_register_sets] =
3002850b1beSTodd Fiala     {
3012850b1beSTodd Fiala         { "General Purpose Registers",  "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 },
3022850b1beSTodd Fiala         { "Floating Point Registers",   "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 },
3032850b1beSTodd Fiala         { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 }
3042850b1beSTodd Fiala     };
3052850b1beSTodd Fiala 
3062850b1beSTodd Fiala     // Register sets for x86 64-bit.
3072850b1beSTodd Fiala     static const RegisterSet
3082850b1beSTodd Fiala     g_reg_sets_x86_64[k_num_register_sets] =
3092850b1beSTodd Fiala     {
3102850b1beSTodd Fiala         { "General Purpose Registers",  "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 },
3112850b1beSTodd Fiala         { "Floating Point Registers",   "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 },
3122850b1beSTodd Fiala         { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 }
3132850b1beSTodd Fiala     };
3142850b1beSTodd Fiala }
3152850b1beSTodd Fiala 
3162850b1beSTodd Fiala #define REG_CONTEXT_SIZE (GetRegisterInfoInterface ().GetGPRSize () + sizeof(FPR))
3172850b1beSTodd Fiala 
3182850b1beSTodd Fiala // ----------------------------------------------------------------------------
3192850b1beSTodd Fiala // Required ptrace defines.
3202850b1beSTodd Fiala // ----------------------------------------------------------------------------
3212850b1beSTodd Fiala 
3222850b1beSTodd Fiala // Support ptrace extensions even when compiled without required kernel support
3232850b1beSTodd Fiala #ifndef NT_X86_XSTATE
3242850b1beSTodd Fiala #define NT_X86_XSTATE 0x202
3252850b1beSTodd Fiala #endif
3262850b1beSTodd Fiala 
3272850b1beSTodd Fiala // ----------------------------------------------------------------------------
3282850b1beSTodd Fiala // NativeRegisterContextLinux_x86_64 members.
3292850b1beSTodd Fiala // ----------------------------------------------------------------------------
3302850b1beSTodd Fiala 
3312850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p) :
3322850b1beSTodd Fiala     NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p),
3332850b1beSTodd Fiala     m_fpr_type (eFPRTypeNotValid),
3342850b1beSTodd Fiala     m_fpr (),
3352850b1beSTodd Fiala     m_iovec (),
3362850b1beSTodd Fiala     m_ymm_set (),
3372850b1beSTodd Fiala     m_reg_info (),
3382850b1beSTodd Fiala     m_gpr_x86_64 ()
3392850b1beSTodd Fiala {
3402850b1beSTodd Fiala     // Set up data about ranges of valid registers.
3412850b1beSTodd Fiala     switch (reg_info_interface_p->GetTargetArchitecture ().GetMachine ())
3422850b1beSTodd Fiala     {
3432850b1beSTodd Fiala         case llvm::Triple::x86:
3442850b1beSTodd Fiala             m_reg_info.num_registers        = k_num_registers_i386;
3452850b1beSTodd Fiala             m_reg_info.num_gpr_registers    = k_num_gpr_registers_i386;
3462850b1beSTodd Fiala             m_reg_info.num_fpr_registers    = k_num_fpr_registers_i386;
3472850b1beSTodd Fiala             m_reg_info.num_avx_registers    = k_num_avx_registers_i386;
3482850b1beSTodd Fiala             m_reg_info.last_gpr             = k_last_gpr_i386;
3492850b1beSTodd Fiala             m_reg_info.first_fpr            = k_first_fpr_i386;
3502850b1beSTodd Fiala             m_reg_info.last_fpr             = k_last_fpr_i386;
3517f013bcdSZachary Turner             m_reg_info.first_st             = lldb_st0_i386;
3527f013bcdSZachary Turner             m_reg_info.last_st              = lldb_st7_i386;
3537f013bcdSZachary Turner             m_reg_info.first_mm             = lldb_mm0_i386;
3547f013bcdSZachary Turner             m_reg_info.last_mm              = lldb_mm7_i386;
3557f013bcdSZachary Turner             m_reg_info.first_xmm            = lldb_xmm0_i386;
3567f013bcdSZachary Turner             m_reg_info.last_xmm             = lldb_xmm7_i386;
3577f013bcdSZachary Turner             m_reg_info.first_ymm            = lldb_ymm0_i386;
3587f013bcdSZachary Turner             m_reg_info.last_ymm             = lldb_ymm7_i386;
3597f013bcdSZachary Turner             m_reg_info.first_dr             = lldb_dr0_i386;
3607f013bcdSZachary Turner             m_reg_info.gpr_flags            = lldb_eflags_i386;
3612850b1beSTodd Fiala             break;
3622850b1beSTodd Fiala         case llvm::Triple::x86_64:
3632850b1beSTodd Fiala             m_reg_info.num_registers        = k_num_registers_x86_64;
3642850b1beSTodd Fiala             m_reg_info.num_gpr_registers    = k_num_gpr_registers_x86_64;
3652850b1beSTodd Fiala             m_reg_info.num_fpr_registers    = k_num_fpr_registers_x86_64;
3662850b1beSTodd Fiala             m_reg_info.num_avx_registers    = k_num_avx_registers_x86_64;
3672850b1beSTodd Fiala             m_reg_info.last_gpr             = k_last_gpr_x86_64;
3682850b1beSTodd Fiala             m_reg_info.first_fpr            = k_first_fpr_x86_64;
3692850b1beSTodd Fiala             m_reg_info.last_fpr             = k_last_fpr_x86_64;
3707f013bcdSZachary Turner             m_reg_info.first_st             = lldb_st0_x86_64;
3717f013bcdSZachary Turner             m_reg_info.last_st              = lldb_st7_x86_64;
3727f013bcdSZachary Turner             m_reg_info.first_mm             = lldb_mm0_x86_64;
3737f013bcdSZachary Turner             m_reg_info.last_mm              = lldb_mm7_x86_64;
3747f013bcdSZachary Turner             m_reg_info.first_xmm            = lldb_xmm0_x86_64;
3757f013bcdSZachary Turner             m_reg_info.last_xmm             = lldb_xmm15_x86_64;
3767f013bcdSZachary Turner             m_reg_info.first_ymm            = lldb_ymm0_x86_64;
3777f013bcdSZachary Turner             m_reg_info.last_ymm             = lldb_ymm15_x86_64;
3787f013bcdSZachary Turner             m_reg_info.first_dr             = lldb_dr0_x86_64;
3797f013bcdSZachary Turner             m_reg_info.gpr_flags            = lldb_rflags_x86_64;
3802850b1beSTodd Fiala             break;
3812850b1beSTodd Fiala         default:
3822850b1beSTodd Fiala             assert(false && "Unhandled target architecture.");
3832850b1beSTodd Fiala             break;
3842850b1beSTodd Fiala     }
3852850b1beSTodd Fiala 
3862850b1beSTodd Fiala     // Initialize m_iovec to point to the buffer and buffer size
3872850b1beSTodd Fiala     // using the conventions of Berkeley style UIO structures, as required
3882850b1beSTodd Fiala     // by PTRACE extensions.
3892850b1beSTodd Fiala     m_iovec.iov_base = &m_fpr.xstate.xsave;
3902850b1beSTodd Fiala     m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
3912850b1beSTodd Fiala 
3922850b1beSTodd Fiala     // Clear out the FPR state.
3932850b1beSTodd Fiala     ::memset(&m_fpr, 0, sizeof(FPR));
3942850b1beSTodd Fiala }
3952850b1beSTodd Fiala 
3962850b1beSTodd Fiala // CONSIDER after local and llgs debugging are merged, register set support can
3972850b1beSTodd Fiala // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
3982850b1beSTodd Fiala uint32_t
3992850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetRegisterSetCount () const
4002850b1beSTodd Fiala {
4012850b1beSTodd Fiala     uint32_t sets = 0;
4022850b1beSTodd Fiala     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
4032850b1beSTodd Fiala     {
4042850b1beSTodd Fiala         if (IsRegisterSetAvailable (set_index))
4052850b1beSTodd Fiala             ++sets;
4062850b1beSTodd Fiala     }
4072850b1beSTodd Fiala 
4082850b1beSTodd Fiala     return sets;
4092850b1beSTodd Fiala }
4102850b1beSTodd Fiala 
4112850b1beSTodd Fiala const lldb_private::RegisterSet *
4122850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetRegisterSet (uint32_t set_index) const
4132850b1beSTodd Fiala {
4142850b1beSTodd Fiala     if (!IsRegisterSetAvailable (set_index))
4152850b1beSTodd Fiala         return nullptr;
4162850b1beSTodd Fiala 
4172850b1beSTodd Fiala     switch (GetRegisterInfoInterface ().GetTargetArchitecture ().GetMachine ())
4182850b1beSTodd Fiala     {
4192850b1beSTodd Fiala         case llvm::Triple::x86:
4202850b1beSTodd Fiala             return &g_reg_sets_i386[set_index];
4212850b1beSTodd Fiala         case llvm::Triple::x86_64:
4222850b1beSTodd Fiala             return &g_reg_sets_x86_64[set_index];
4232850b1beSTodd Fiala         default:
4242850b1beSTodd Fiala             assert (false && "Unhandled target architecture.");
4252850b1beSTodd Fiala             return nullptr;
4262850b1beSTodd Fiala     }
4272850b1beSTodd Fiala 
4282850b1beSTodd Fiala     return nullptr;
4292850b1beSTodd Fiala }
4302850b1beSTodd Fiala 
4312850b1beSTodd Fiala lldb_private::Error
4322850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadRegisterRaw (uint32_t reg_index, RegisterValue &reg_value)
4332850b1beSTodd Fiala {
4342850b1beSTodd Fiala     Error error;
4352850b1beSTodd Fiala     const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
4362850b1beSTodd Fiala     if (!reg_info)
4372850b1beSTodd Fiala     {
4382850b1beSTodd Fiala         error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
4392850b1beSTodd Fiala         return error;
4402850b1beSTodd Fiala     }
4412850b1beSTodd Fiala 
4422850b1beSTodd Fiala     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
4432850b1beSTodd Fiala     if (!process_sp)
4442850b1beSTodd Fiala     {
4452850b1beSTodd Fiala         error.SetErrorString ("NativeProcessProtocol is NULL");
4462850b1beSTodd Fiala         return error;
4472850b1beSTodd Fiala     }
4482850b1beSTodd Fiala 
4492850b1beSTodd Fiala     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
45097ccc294SChaoren Lin     return process_p->ReadRegisterValue(m_thread.GetID(),
4512850b1beSTodd Fiala                                         reg_info->byte_offset,
4522850b1beSTodd Fiala                                         reg_info->name,
4532850b1beSTodd Fiala                                         reg_info->byte_size,
45497ccc294SChaoren Lin                                         reg_value);
4552850b1beSTodd Fiala }
4562850b1beSTodd Fiala 
4572850b1beSTodd Fiala lldb_private::Error
4582850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
4592850b1beSTodd Fiala {
4602850b1beSTodd Fiala     Error error;
4612850b1beSTodd Fiala 
4622850b1beSTodd Fiala     if (!reg_info)
4632850b1beSTodd Fiala     {
4642850b1beSTodd Fiala         error.SetErrorString ("reg_info NULL");
4652850b1beSTodd Fiala         return error;
4662850b1beSTodd Fiala     }
4672850b1beSTodd Fiala 
4682850b1beSTodd Fiala     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
4692850b1beSTodd Fiala     if (reg == LLDB_INVALID_REGNUM)
4702850b1beSTodd Fiala     {
4712850b1beSTodd Fiala         // This is likely an internal register for lldb use only and should not be directly queried.
4722850b1beSTodd Fiala         error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name);
4732850b1beSTodd Fiala         return error;
4742850b1beSTodd Fiala     }
4752850b1beSTodd Fiala 
4762850b1beSTodd Fiala     if (IsFPR(reg, GetFPRType()))
4772850b1beSTodd Fiala     {
4782850b1beSTodd Fiala         if (!ReadFPR())
4792850b1beSTodd Fiala         {
4802850b1beSTodd Fiala             error.SetErrorString ("failed to read floating point register");
4812850b1beSTodd Fiala             return error;
4822850b1beSTodd Fiala         }
4832850b1beSTodd Fiala     }
4842850b1beSTodd Fiala     else
4852850b1beSTodd Fiala     {
4862850b1beSTodd Fiala         uint32_t full_reg = reg;
4872850b1beSTodd Fiala         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
4882850b1beSTodd Fiala 
4892850b1beSTodd Fiala         if (is_subreg)
4902850b1beSTodd Fiala         {
4912850b1beSTodd Fiala             // Read the full aligned 64-bit register.
4922850b1beSTodd Fiala             full_reg = reg_info->invalidate_regs[0];
4932850b1beSTodd Fiala         }
4942850b1beSTodd Fiala 
4952850b1beSTodd Fiala         error = ReadRegisterRaw(full_reg, reg_value);
4962850b1beSTodd Fiala 
4972850b1beSTodd Fiala         if (error.Success ())
4982850b1beSTodd Fiala         {
4992850b1beSTodd Fiala             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
5002850b1beSTodd Fiala             if (is_subreg && (reg_info->byte_offset & 0x1))
5012850b1beSTodd Fiala                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
5022850b1beSTodd Fiala 
5032850b1beSTodd Fiala             // If our return byte size was greater than the return value reg size, then
5042850b1beSTodd Fiala             // use the type specified by reg_info rather than the uint64_t default
5052850b1beSTodd Fiala             if (reg_value.GetByteSize() > reg_info->byte_size)
5062850b1beSTodd Fiala                 reg_value.SetType(reg_info);
5072850b1beSTodd Fiala         }
5082850b1beSTodd Fiala         return error;
5092850b1beSTodd Fiala     }
5102850b1beSTodd Fiala 
5112850b1beSTodd Fiala     if (reg_info->encoding == lldb::eEncodingVector)
5122850b1beSTodd Fiala     {
5132850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder();
5142850b1beSTodd Fiala 
5152850b1beSTodd Fiala         if (byte_order != lldb::eByteOrderInvalid)
5162850b1beSTodd Fiala         {
5172850b1beSTodd Fiala             if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
5182850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order);
5192850b1beSTodd Fiala             if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
5202850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order);
5212850b1beSTodd Fiala             if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
5222850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order);
5232850b1beSTodd Fiala             if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
5242850b1beSTodd Fiala             {
5252850b1beSTodd Fiala                 // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
5262850b1beSTodd Fiala                 if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoYMM(reg, byte_order))
5272850b1beSTodd Fiala                     reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order);
5282850b1beSTodd Fiala                 else
5292850b1beSTodd Fiala                 {
5302850b1beSTodd Fiala                     error.SetErrorString ("failed to copy ymm register value");
5312850b1beSTodd Fiala                     return error;
5322850b1beSTodd Fiala                 }
5332850b1beSTodd Fiala             }
5342850b1beSTodd Fiala 
5352850b1beSTodd Fiala             if (reg_value.GetType() != RegisterValue::eTypeBytes)
5362850b1beSTodd Fiala                 error.SetErrorString ("write failed - type was expected to be RegisterValue::eTypeBytes");
5372850b1beSTodd Fiala 
5382850b1beSTodd Fiala             return error;
5392850b1beSTodd Fiala         }
5402850b1beSTodd Fiala 
5412850b1beSTodd Fiala         error.SetErrorString ("byte order is invalid");
5422850b1beSTodd Fiala         return error;
5432850b1beSTodd Fiala     }
5442850b1beSTodd Fiala 
5452850b1beSTodd Fiala     // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
5462850b1beSTodd Fiala     assert (reg_info->byte_offset < sizeof(m_fpr));
5472850b1beSTodd Fiala     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
5482850b1beSTodd Fiala     switch (reg_info->byte_size)
5492850b1beSTodd Fiala     {
5502850b1beSTodd Fiala         case 2:
5512850b1beSTodd Fiala             reg_value.SetUInt16(*(uint16_t *)src);
5522850b1beSTodd Fiala             break;
5532850b1beSTodd Fiala         case 4:
5542850b1beSTodd Fiala             reg_value.SetUInt32(*(uint32_t *)src);
5552850b1beSTodd Fiala             break;
5562850b1beSTodd Fiala         case 8:
5572850b1beSTodd Fiala             reg_value.SetUInt64(*(uint64_t *)src);
5582850b1beSTodd Fiala             break;
5592850b1beSTodd Fiala         default:
5602850b1beSTodd Fiala             assert(false && "Unhandled data size.");
5612850b1beSTodd Fiala             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
5622850b1beSTodd Fiala             break;
5632850b1beSTodd Fiala     }
5642850b1beSTodd Fiala 
5652850b1beSTodd Fiala     return error;
5662850b1beSTodd Fiala }
5672850b1beSTodd Fiala 
5682850b1beSTodd Fiala lldb_private::Error
5692850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteRegister(const uint32_t reg,
5702850b1beSTodd Fiala                                                  const RegisterValue &value)
5712850b1beSTodd Fiala {
5722850b1beSTodd Fiala     Error error;
5732850b1beSTodd Fiala 
5742850b1beSTodd Fiala     uint32_t reg_to_write = reg;
5752850b1beSTodd Fiala     RegisterValue value_to_write = value;
5762850b1beSTodd Fiala 
5772850b1beSTodd Fiala     // Check if this is a subregister of a full register.
5782850b1beSTodd Fiala     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
5792850b1beSTodd Fiala     if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
5802850b1beSTodd Fiala     {
5812850b1beSTodd Fiala         RegisterValue full_value;
5822850b1beSTodd Fiala         uint32_t full_reg = reg_info->invalidate_regs[0];
5832850b1beSTodd Fiala         const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
5842850b1beSTodd Fiala 
5852850b1beSTodd Fiala         // Read the full register.
5862850b1beSTodd Fiala         error = ReadRegister(full_reg_info, full_value);
5872850b1beSTodd Fiala         if (error.Fail ())
5882850b1beSTodd Fiala             return error;
5892850b1beSTodd Fiala 
5902850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder();
5912850b1beSTodd Fiala         uint8_t dst[RegisterValue::kMaxRegisterByteSize];
5922850b1beSTodd Fiala 
5932850b1beSTodd Fiala         // Get the bytes for the full register.
5942850b1beSTodd Fiala         const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
5952850b1beSTodd Fiala                                                                dst,
5962850b1beSTodd Fiala                                                                sizeof(dst),
5972850b1beSTodd Fiala                                                                byte_order,
5982850b1beSTodd Fiala                                                                error);
5992850b1beSTodd Fiala         if (error.Success() && dest_size)
6002850b1beSTodd Fiala         {
6012850b1beSTodd Fiala             uint8_t src[RegisterValue::kMaxRegisterByteSize];
6022850b1beSTodd Fiala 
6032850b1beSTodd Fiala             // Get the bytes for the source data.
6042850b1beSTodd Fiala             const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
6052850b1beSTodd Fiala             if (error.Success() && src_size && (src_size < dest_size))
6062850b1beSTodd Fiala             {
6072850b1beSTodd Fiala                 // Copy the src bytes to the destination.
6082850b1beSTodd Fiala                 memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
6092850b1beSTodd Fiala                 // Set this full register as the value to write.
6102850b1beSTodd Fiala                 value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
6112850b1beSTodd Fiala                 value_to_write.SetType(full_reg_info);
6122850b1beSTodd Fiala                 reg_to_write = full_reg;
6132850b1beSTodd Fiala             }
6142850b1beSTodd Fiala         }
6152850b1beSTodd Fiala     }
6162850b1beSTodd Fiala 
6172850b1beSTodd Fiala 
6182850b1beSTodd Fiala     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
6192850b1beSTodd Fiala     if (!process_sp)
6202850b1beSTodd Fiala     {
6212850b1beSTodd Fiala         error.SetErrorString ("NativeProcessProtocol is NULL");
6222850b1beSTodd Fiala         return error;
6232850b1beSTodd Fiala     }
6242850b1beSTodd Fiala 
6252850b1beSTodd Fiala     const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
6262850b1beSTodd Fiala     assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
6272850b1beSTodd Fiala     if (!register_to_write_info_p)
6282850b1beSTodd Fiala     {
6292850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
6302850b1beSTodd Fiala         return error;
6312850b1beSTodd Fiala     }
6322850b1beSTodd Fiala 
6332850b1beSTodd Fiala     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
63497ccc294SChaoren Lin     return process_p->WriteRegisterValue(m_thread.GetID(),
6352850b1beSTodd Fiala                                          register_to_write_info_p->byte_offset,
6362850b1beSTodd Fiala                                          register_to_write_info_p->name,
63797ccc294SChaoren Lin                                          value_to_write);
6382850b1beSTodd Fiala }
6392850b1beSTodd Fiala 
6402850b1beSTodd Fiala lldb_private::Error
6412850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
6422850b1beSTodd Fiala {
6432850b1beSTodd Fiala     assert (reg_info && "reg_info is null");
6442850b1beSTodd Fiala 
6452850b1beSTodd Fiala     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
6462850b1beSTodd Fiala     if (reg_index == LLDB_INVALID_REGNUM)
6472850b1beSTodd Fiala         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
6482850b1beSTodd Fiala 
6492850b1beSTodd Fiala     if (IsGPR(reg_index))
6502850b1beSTodd Fiala         return WriteRegister(reg_index, reg_value);
6512850b1beSTodd Fiala 
6522850b1beSTodd Fiala     if (IsFPR(reg_index, GetFPRType()))
6532850b1beSTodd Fiala     {
6542850b1beSTodd Fiala         if (reg_info->encoding == lldb::eEncodingVector)
6552850b1beSTodd Fiala         {
6562850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
6572850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_st].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6582850b1beSTodd Fiala 
6592850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm)
6602850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6612850b1beSTodd Fiala 
6622850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm)
6632850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6642850b1beSTodd Fiala 
6652850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_ymm && reg_index <= m_reg_info.last_ymm)
6662850b1beSTodd Fiala             {
6672850b1beSTodd Fiala                 if (GetFPRType() != eFPRTypeXSAVE)
6682850b1beSTodd Fiala                     return Error ("target processor does not support AVX");
6692850b1beSTodd Fiala 
6702850b1beSTodd Fiala                 // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
6712850b1beSTodd Fiala                 ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6722850b1beSTodd Fiala                 if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
6732850b1beSTodd Fiala                     return Error ("CopyYMMtoXSTATE() failed");
6742850b1beSTodd Fiala             }
6752850b1beSTodd Fiala         }
6762850b1beSTodd Fiala         else
6772850b1beSTodd Fiala         {
6782850b1beSTodd Fiala             // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
6792850b1beSTodd Fiala             assert (reg_info->byte_offset < sizeof(m_fpr));
6802850b1beSTodd Fiala             uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
6812850b1beSTodd Fiala             switch (reg_info->byte_size)
6822850b1beSTodd Fiala             {
6832850b1beSTodd Fiala                 case 2:
6842850b1beSTodd Fiala                     *(uint16_t *)dst = reg_value.GetAsUInt16();
6852850b1beSTodd Fiala                     break;
6862850b1beSTodd Fiala                 case 4:
6872850b1beSTodd Fiala                     *(uint32_t *)dst = reg_value.GetAsUInt32();
6882850b1beSTodd Fiala                     break;
6892850b1beSTodd Fiala                 case 8:
6902850b1beSTodd Fiala                     *(uint64_t *)dst = reg_value.GetAsUInt64();
6912850b1beSTodd Fiala                     break;
6922850b1beSTodd Fiala                 default:
6932850b1beSTodd Fiala                     assert(false && "Unhandled data size.");
6942850b1beSTodd Fiala                     return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
6952850b1beSTodd Fiala             }
6962850b1beSTodd Fiala         }
6972850b1beSTodd Fiala 
6982850b1beSTodd Fiala         if (WriteFPR())
6992850b1beSTodd Fiala         {
7002850b1beSTodd Fiala             if (IsAVX(reg_index))
7012850b1beSTodd Fiala             {
7022850b1beSTodd Fiala                 if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
7032850b1beSTodd Fiala                     return Error ("CopyYMMtoXSTATE() failed");
7042850b1beSTodd Fiala             }
7052850b1beSTodd Fiala             return Error ();
7062850b1beSTodd Fiala         }
7072850b1beSTodd Fiala     }
7082850b1beSTodd Fiala     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
7092850b1beSTodd Fiala }
7102850b1beSTodd Fiala 
7112850b1beSTodd Fiala lldb_private::Error
7122850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
7132850b1beSTodd Fiala {
7142850b1beSTodd Fiala     Error error;
7152850b1beSTodd Fiala 
7162850b1beSTodd Fiala     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
7172850b1beSTodd Fiala     if (!data_sp)
7182850b1beSTodd Fiala     {
7192850b1beSTodd Fiala         error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
7202850b1beSTodd Fiala         return error;
7212850b1beSTodd Fiala     }
7222850b1beSTodd Fiala 
7232850b1beSTodd Fiala     if (!ReadGPR ())
7242850b1beSTodd Fiala     {
7252850b1beSTodd Fiala         error.SetErrorString ("ReadGPR() failed");
7262850b1beSTodd Fiala         return error;
7272850b1beSTodd Fiala     }
7282850b1beSTodd Fiala 
7292850b1beSTodd Fiala     if (!ReadFPR ())
7302850b1beSTodd Fiala     {
7312850b1beSTodd Fiala         error.SetErrorString ("ReadFPR() failed");
7322850b1beSTodd Fiala         return error;
7332850b1beSTodd Fiala     }
7342850b1beSTodd Fiala 
7352850b1beSTodd Fiala     uint8_t *dst = data_sp->GetBytes ();
7362850b1beSTodd Fiala     if (dst == nullptr)
7372850b1beSTodd Fiala     {
7382850b1beSTodd Fiala         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
7392850b1beSTodd Fiala         return error;
7402850b1beSTodd Fiala     }
7412850b1beSTodd Fiala 
7422850b1beSTodd Fiala     ::memcpy (dst, &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
7432850b1beSTodd Fiala     dst += GetRegisterInfoInterface ().GetGPRSize ();
7442850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeFXSAVE)
7452850b1beSTodd Fiala         ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
7462850b1beSTodd Fiala     else if (GetFPRType () == eFPRTypeXSAVE)
7472850b1beSTodd Fiala     {
7482850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder ();
7492850b1beSTodd Fiala 
7502850b1beSTodd Fiala         // Assemble the YMM register content from the register halves.
7512850b1beSTodd Fiala         for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
7522850b1beSTodd Fiala         {
7532850b1beSTodd Fiala             if (!CopyXSTATEtoYMM (reg, byte_order))
7542850b1beSTodd Fiala             {
7552850b1beSTodd Fiala                 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyXSTATEtoYMM() failed for reg num %" PRIu32, __FUNCTION__, reg);
7562850b1beSTodd Fiala                 return error;
7572850b1beSTodd Fiala             }
7582850b1beSTodd Fiala         }
7592850b1beSTodd Fiala 
7602850b1beSTodd Fiala         // Copy the extended register state including the assembled ymm registers.
7612850b1beSTodd Fiala         ::memcpy (dst, &m_fpr, sizeof (m_fpr));
7622850b1beSTodd Fiala     }
7632850b1beSTodd Fiala     else
7642850b1beSTodd Fiala     {
7652850b1beSTodd Fiala         assert (false && "how do we save the floating point registers?");
7662850b1beSTodd Fiala         error.SetErrorString ("unsure how to save the floating point registers");
7672850b1beSTodd Fiala     }
7682850b1beSTodd Fiala 
7692850b1beSTodd Fiala     return error;
7702850b1beSTodd Fiala }
7712850b1beSTodd Fiala 
7722850b1beSTodd Fiala lldb_private::Error
7732850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
7742850b1beSTodd Fiala {
7752850b1beSTodd Fiala     Error error;
7762850b1beSTodd Fiala 
7772850b1beSTodd Fiala     if (!data_sp)
7782850b1beSTodd Fiala     {
7792850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
7802850b1beSTodd Fiala         return error;
7812850b1beSTodd Fiala     }
7822850b1beSTodd Fiala 
7832850b1beSTodd Fiala     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
7842850b1beSTodd Fiala     {
7852850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
7862850b1beSTodd Fiala         return error;
7872850b1beSTodd Fiala     }
7882850b1beSTodd Fiala 
7892850b1beSTodd Fiala 
7902850b1beSTodd Fiala     uint8_t *src = data_sp->GetBytes ();
7912850b1beSTodd Fiala     if (src == nullptr)
7922850b1beSTodd Fiala     {
7932850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
7942850b1beSTodd Fiala         return error;
7952850b1beSTodd Fiala     }
7962850b1beSTodd Fiala     ::memcpy (&m_gpr_x86_64, src, GetRegisterInfoInterface ().GetGPRSize ());
7972850b1beSTodd Fiala 
7982850b1beSTodd Fiala     if (!WriteGPR ())
7992850b1beSTodd Fiala     {
8002850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
8012850b1beSTodd Fiala         return error;
8022850b1beSTodd Fiala     }
8032850b1beSTodd Fiala 
8042850b1beSTodd Fiala     src += GetRegisterInfoInterface ().GetGPRSize ();
8052850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeFXSAVE)
8062850b1beSTodd Fiala         ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
8072850b1beSTodd Fiala     else if (GetFPRType () == eFPRTypeXSAVE)
8082850b1beSTodd Fiala         ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
8092850b1beSTodd Fiala 
8102850b1beSTodd Fiala     if (!WriteFPR ())
8112850b1beSTodd Fiala     {
8122850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
8132850b1beSTodd Fiala         return error;
8142850b1beSTodd Fiala     }
8152850b1beSTodd Fiala 
8162850b1beSTodd Fiala     if (GetFPRType() == eFPRTypeXSAVE)
8172850b1beSTodd Fiala     {
8182850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder();
8192850b1beSTodd Fiala 
8202850b1beSTodd Fiala         // Parse the YMM register content from the register halves.
8212850b1beSTodd Fiala         for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
8222850b1beSTodd Fiala         {
8232850b1beSTodd Fiala             if (!CopyYMMtoXSTATE (reg, byte_order))
8242850b1beSTodd Fiala             {
8252850b1beSTodd Fiala                 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyYMMtoXSTATE() failed for reg num %" PRIu32, __FUNCTION__, reg);
8262850b1beSTodd Fiala                 return error;
8272850b1beSTodd Fiala             }
8282850b1beSTodd Fiala         }
8292850b1beSTodd Fiala     }
8302850b1beSTodd Fiala 
8312850b1beSTodd Fiala     return error;
8322850b1beSTodd Fiala }
8332850b1beSTodd Fiala 
8342850b1beSTodd Fiala bool
8352850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable (uint32_t set_index) const
8362850b1beSTodd Fiala {
8372850b1beSTodd Fiala     // Note: Extended register sets are assumed to be at the end of g_reg_sets.
8382850b1beSTodd Fiala     uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
8392850b1beSTodd Fiala 
8402850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeXSAVE)
8412850b1beSTodd Fiala     {
8422850b1beSTodd Fiala         // AVX is the first extended register set.
8432850b1beSTodd Fiala         ++num_sets;
8442850b1beSTodd Fiala     }
8452850b1beSTodd Fiala     return (set_index < num_sets);
8462850b1beSTodd Fiala }
8472850b1beSTodd Fiala 
8482850b1beSTodd Fiala lldb::ByteOrder
8492850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetByteOrder() const
8502850b1beSTodd Fiala {
8512850b1beSTodd Fiala     // Get the target process whose privileged thread was used for the register read.
8522850b1beSTodd Fiala     lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
8532850b1beSTodd Fiala 
8542850b1beSTodd Fiala     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
8552850b1beSTodd Fiala     if (!process_sp)
8562850b1beSTodd Fiala         return byte_order;
8572850b1beSTodd Fiala 
8582850b1beSTodd Fiala     if (!process_sp->GetByteOrder (byte_order))
8592850b1beSTodd Fiala     {
8602850b1beSTodd Fiala         // FIXME log here
8612850b1beSTodd Fiala     }
8622850b1beSTodd Fiala 
8632850b1beSTodd Fiala     return byte_order;
8642850b1beSTodd Fiala }
8652850b1beSTodd Fiala 
8662850b1beSTodd Fiala bool
8672850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const
8682850b1beSTodd Fiala {
8692850b1beSTodd Fiala     // GPRs come first.
8702850b1beSTodd Fiala     return reg_index <= m_reg_info.last_gpr;
8712850b1beSTodd Fiala }
8722850b1beSTodd Fiala 
8732850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::FPRType
8742850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetFPRType () const
8752850b1beSTodd Fiala {
8762850b1beSTodd Fiala     if (m_fpr_type == eFPRTypeNotValid)
8772850b1beSTodd Fiala     {
8782850b1beSTodd Fiala         // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx.
8792850b1beSTodd Fiala 
8802850b1beSTodd Fiala         // Try and see if AVX register retrieval works.
8812850b1beSTodd Fiala         m_fpr_type = eFPRTypeXSAVE;
8822850b1beSTodd Fiala         if (!const_cast<NativeRegisterContextLinux_x86_64*> (this)->ReadFPR ())
8832850b1beSTodd Fiala         {
8842850b1beSTodd Fiala             // Fall back to general floating point with no AVX support.
8852850b1beSTodd Fiala             m_fpr_type = eFPRTypeFXSAVE;
8862850b1beSTodd Fiala         }
8872850b1beSTodd Fiala     }
8882850b1beSTodd Fiala 
8892850b1beSTodd Fiala     return m_fpr_type;
8902850b1beSTodd Fiala }
8912850b1beSTodd Fiala 
8922850b1beSTodd Fiala bool
8932850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const
8942850b1beSTodd Fiala {
8952850b1beSTodd Fiala     return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr);
8962850b1beSTodd Fiala }
8972850b1beSTodd Fiala 
8982850b1beSTodd Fiala bool
8992850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, FPRType fpr_type) const
9002850b1beSTodd Fiala {
9012850b1beSTodd Fiala     bool generic_fpr = IsFPR(reg_index);
9022850b1beSTodd Fiala 
9032850b1beSTodd Fiala     if (fpr_type == eFPRTypeXSAVE)
9042850b1beSTodd Fiala         return generic_fpr || IsAVX(reg_index);
9052850b1beSTodd Fiala     return generic_fpr;
9062850b1beSTodd Fiala }
9072850b1beSTodd Fiala 
9082850b1beSTodd Fiala bool
9092850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteFPR()
9102850b1beSTodd Fiala {
9112850b1beSTodd Fiala     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
9122850b1beSTodd Fiala     if (!process_sp)
9132850b1beSTodd Fiala         return false;
9142850b1beSTodd Fiala     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
9152850b1beSTodd Fiala 
9162850b1beSTodd Fiala     if (GetFPRType() == eFPRTypeFXSAVE)
91797ccc294SChaoren Lin         return process_p->WriteFPR (m_thread.GetID (), &m_fpr.xstate.fxsave, sizeof (m_fpr.xstate.fxsave)).Success();
9182850b1beSTodd Fiala 
9192850b1beSTodd Fiala     if (GetFPRType() == eFPRTypeXSAVE)
92097ccc294SChaoren Lin         return process_p->WriteRegisterSet (m_thread.GetID (), &m_iovec, sizeof (m_fpr.xstate.xsave), NT_X86_XSTATE).Success();
9212850b1beSTodd Fiala     return false;
9222850b1beSTodd Fiala }
9232850b1beSTodd Fiala 
9242850b1beSTodd Fiala bool
9252850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const
9262850b1beSTodd Fiala {
9272850b1beSTodd Fiala     return (m_reg_info.first_ymm <= reg_index && reg_index <= m_reg_info.last_ymm);
9282850b1beSTodd Fiala }
9292850b1beSTodd Fiala 
9302850b1beSTodd Fiala bool
9312850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order)
9322850b1beSTodd Fiala {
9332850b1beSTodd Fiala     if (!IsAVX (reg_index))
9342850b1beSTodd Fiala         return false;
9352850b1beSTodd Fiala 
9362850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderLittle)
9372850b1beSTodd Fiala     {
9382850b1beSTodd Fiala         ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
9392850b1beSTodd Fiala                  m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
9402850b1beSTodd Fiala                  sizeof (XMMReg));
9412850b1beSTodd Fiala         ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
9422850b1beSTodd Fiala                  m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
9432850b1beSTodd Fiala                  sizeof (YMMHReg));
9442850b1beSTodd Fiala         return true;
9452850b1beSTodd Fiala     }
9462850b1beSTodd Fiala 
9472850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderBig)
9482850b1beSTodd Fiala     {
9492850b1beSTodd Fiala         ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
9502850b1beSTodd Fiala                  m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
9512850b1beSTodd Fiala                  sizeof (XMMReg));
9522850b1beSTodd Fiala         ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
9532850b1beSTodd Fiala                  m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
9542850b1beSTodd Fiala                  sizeof (YMMHReg));
9552850b1beSTodd Fiala         return true;
9562850b1beSTodd Fiala     }
9572850b1beSTodd Fiala     return false; // unsupported or invalid byte order
9582850b1beSTodd Fiala 
9592850b1beSTodd Fiala }
9602850b1beSTodd Fiala 
9612850b1beSTodd Fiala bool
9622850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
9632850b1beSTodd Fiala {
9642850b1beSTodd Fiala     if (!IsAVX(reg))
9652850b1beSTodd Fiala         return false;
9662850b1beSTodd Fiala 
9672850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderLittle)
9682850b1beSTodd Fiala     {
9692850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
9702850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
9712850b1beSTodd Fiala                  sizeof(XMMReg));
9722850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
9732850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
9742850b1beSTodd Fiala                  sizeof(YMMHReg));
9752850b1beSTodd Fiala         return true;
9762850b1beSTodd Fiala     }
9772850b1beSTodd Fiala 
9782850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderBig)
9792850b1beSTodd Fiala     {
9802850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
9812850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
9822850b1beSTodd Fiala                  sizeof(XMMReg));
9832850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
9842850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
9852850b1beSTodd Fiala                  sizeof(YMMHReg));
9862850b1beSTodd Fiala         return true;
9872850b1beSTodd Fiala     }
9882850b1beSTodd Fiala     return false; // unsupported or invalid byte order
9892850b1beSTodd Fiala }
9902850b1beSTodd Fiala 
9912850b1beSTodd Fiala bool
9922850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadFPR ()
9932850b1beSTodd Fiala {
9942850b1beSTodd Fiala     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
9952850b1beSTodd Fiala     if (!process_sp)
9962850b1beSTodd Fiala         return false;
9972850b1beSTodd Fiala     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
9982850b1beSTodd Fiala 
9992850b1beSTodd Fiala     const FPRType fpr_type = GetFPRType ();
10002850b1beSTodd Fiala     switch (fpr_type)
10012850b1beSTodd Fiala     {
10022850b1beSTodd Fiala     case FPRType::eFPRTypeFXSAVE:
100397ccc294SChaoren Lin         return process_p->ReadFPR (m_thread.GetID (), &m_fpr.xstate.fxsave, sizeof (m_fpr.xstate.fxsave)).Success();
10042850b1beSTodd Fiala 
10052850b1beSTodd Fiala     case FPRType::eFPRTypeXSAVE:
100697ccc294SChaoren Lin         return process_p->ReadRegisterSet (m_thread.GetID (), &m_iovec, sizeof (m_fpr.xstate.xsave), NT_X86_XSTATE).Success();
10072850b1beSTodd Fiala 
10082850b1beSTodd Fiala     default:
10092850b1beSTodd Fiala         return false;
10102850b1beSTodd Fiala     }
10112850b1beSTodd Fiala }
10122850b1beSTodd Fiala 
10132850b1beSTodd Fiala bool
10142850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadGPR()
10152850b1beSTodd Fiala {
10162850b1beSTodd Fiala     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
10172850b1beSTodd Fiala     if (!process_sp)
10182850b1beSTodd Fiala         return false;
10192850b1beSTodd Fiala     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
10202850b1beSTodd Fiala 
102197ccc294SChaoren Lin     return process_p->ReadGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
10222850b1beSTodd Fiala }
10232850b1beSTodd Fiala 
10242850b1beSTodd Fiala bool
10252850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteGPR()
10262850b1beSTodd Fiala {
10272850b1beSTodd Fiala     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
10282850b1beSTodd Fiala     if (!process_sp)
10292850b1beSTodd Fiala         return false;
10302850b1beSTodd Fiala     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
10312850b1beSTodd Fiala 
103297ccc294SChaoren Lin     return process_p->WriteGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
10332850b1beSTodd Fiala }
10342850b1beSTodd Fiala 
1035*18fe6404SChaoren Lin Error
1036*18fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint8_t wp_index)
1037*18fe6404SChaoren Lin {
1038*18fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
1039*18fe6404SChaoren Lin         return Error ("Watchpoint index out of range");
1040*18fe6404SChaoren Lin 
1041*18fe6404SChaoren Lin     RegisterValue reg_value;
1042*18fe6404SChaoren Lin     Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value);
1043*18fe6404SChaoren Lin     if (error.Fail()) return error;
1044*18fe6404SChaoren Lin 
1045*18fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64();
1046*18fe6404SChaoren Lin 
1047*18fe6404SChaoren Lin     bool is_hit = status_bits & (1 << wp_index);
1048*18fe6404SChaoren Lin 
1049*18fe6404SChaoren Lin     error.SetError (!is_hit, lldb::eErrorTypeInvalid);
1050*18fe6404SChaoren Lin 
1051*18fe6404SChaoren Lin     return error;
1052*18fe6404SChaoren Lin }
1053*18fe6404SChaoren Lin 
1054*18fe6404SChaoren Lin Error
1055*18fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index)
1056*18fe6404SChaoren Lin {
1057*18fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
1058*18fe6404SChaoren Lin         return Error ("Watchpoint index out of range");
1059*18fe6404SChaoren Lin 
1060*18fe6404SChaoren Lin     RegisterValue reg_value;
1061*18fe6404SChaoren Lin     Error error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value);
1062*18fe6404SChaoren Lin     if (error.Fail()) return error;
1063*18fe6404SChaoren Lin 
1064*18fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64();
1065*18fe6404SChaoren Lin 
1066*18fe6404SChaoren Lin     bool is_vacant = !(control_bits & (1 << (2 * wp_index)));
1067*18fe6404SChaoren Lin 
1068*18fe6404SChaoren Lin     error.SetError (!is_vacant, lldb::eErrorTypeInvalid);
1069*18fe6404SChaoren Lin 
1070*18fe6404SChaoren Lin     return error;
1071*18fe6404SChaoren Lin }
1072*18fe6404SChaoren Lin 
1073*18fe6404SChaoren Lin Error
1074*18fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex(
1075*18fe6404SChaoren Lin         lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
1076*18fe6404SChaoren Lin 
1077*18fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
1078*18fe6404SChaoren Lin         return Error ("Watchpoint index out of range");
1079*18fe6404SChaoren Lin 
1080*18fe6404SChaoren Lin     if (watch_flags != 0x1 && watch_flags != 0x3)
1081*18fe6404SChaoren Lin         return Error ("Invalid read/write bits for watchpoint");
1082*18fe6404SChaoren Lin 
1083*18fe6404SChaoren Lin     if (size != 1 && size != 2 && size != 4 && size != 8)
1084*18fe6404SChaoren Lin         return Error ("Invalid size for watchpoint");
1085*18fe6404SChaoren Lin 
1086*18fe6404SChaoren Lin     Error error = IsWatchpointVacant (wp_index);
1087*18fe6404SChaoren Lin     if (error.Fail()) return error;
1088*18fe6404SChaoren Lin 
1089*18fe6404SChaoren Lin     RegisterValue reg_value;
1090*18fe6404SChaoren Lin     error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value);
1091*18fe6404SChaoren Lin     if (error.Fail()) return error;
1092*18fe6404SChaoren Lin 
1093*18fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
1094*18fe6404SChaoren Lin     // set bits 1, 3, 5, or 7
1095*18fe6404SChaoren Lin     uint64_t enable_bit = 1 << (2 * wp_index);
1096*18fe6404SChaoren Lin 
1097*18fe6404SChaoren Lin     // set bits 16-17, 20-21, 24-25, or 28-29
1098*18fe6404SChaoren Lin     // with 0b01 for write, and 0b11 for read/write
1099*18fe6404SChaoren Lin     uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
1100*18fe6404SChaoren Lin 
1101*18fe6404SChaoren Lin     // set bits 18-19, 22-23, 26-27, or 30-31
1102*18fe6404SChaoren Lin     // with 0b00, 0b01, 0b10, or 0b11
1103*18fe6404SChaoren Lin     // for 1, 2, 8 (if supported), or 4 bytes, respectively
1104*18fe6404SChaoren Lin     uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
1105*18fe6404SChaoren Lin 
1106*18fe6404SChaoren Lin     uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
1107*18fe6404SChaoren Lin 
1108*18fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1109*18fe6404SChaoren Lin 
1110*18fe6404SChaoren Lin     control_bits |= enable_bit | rw_bits | size_bits;
1111*18fe6404SChaoren Lin 
1112*18fe6404SChaoren Lin     error = WriteRegister(m_reg_info.first_dr + wp_index, RegisterValue(addr));
1113*18fe6404SChaoren Lin     if (error.Fail()) return error;
1114*18fe6404SChaoren Lin 
1115*18fe6404SChaoren Lin     error = WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits));
1116*18fe6404SChaoren Lin     if (error.Fail()) return error;
1117*18fe6404SChaoren Lin 
1118*18fe6404SChaoren Lin     error.Clear();
1119*18fe6404SChaoren Lin     return error;
1120*18fe6404SChaoren Lin }
1121*18fe6404SChaoren Lin 
1122*18fe6404SChaoren Lin bool
1123*18fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(uint32_t wp_index)
1124*18fe6404SChaoren Lin {
1125*18fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
1126*18fe6404SChaoren Lin         return false;
1127*18fe6404SChaoren Lin 
1128*18fe6404SChaoren Lin     RegisterValue reg_value;
1129*18fe6404SChaoren Lin 
1130*18fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
1131*18fe6404SChaoren Lin     // clear bits 0, 1, 2, or 3 of the debug status register (DR6)
1132*18fe6404SChaoren Lin     Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value);
1133*18fe6404SChaoren Lin     if (error.Fail()) return false;
1134*18fe6404SChaoren Lin     uint64_t bit_mask = 1 << wp_index;
1135*18fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
1136*18fe6404SChaoren Lin     error = WriteRegister(lldb_dr6_x86_64, RegisterValue(status_bits));
1137*18fe6404SChaoren Lin     if (error.Fail()) return false;
1138*18fe6404SChaoren Lin 
1139*18fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
1140*18fe6404SChaoren Lin     // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
1141*18fe6404SChaoren Lin     // of the debug control register (DR7)
1142*18fe6404SChaoren Lin     error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value);
1143*18fe6404SChaoren Lin     if (error.Fail()) return false;
1144*18fe6404SChaoren Lin     bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
1145*18fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1146*18fe6404SChaoren Lin     return WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits)).Success();
1147*18fe6404SChaoren Lin }
1148*18fe6404SChaoren Lin 
1149*18fe6404SChaoren Lin Error
1150*18fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints()
1151*18fe6404SChaoren Lin {
1152*18fe6404SChaoren Lin     RegisterValue reg_value;
1153*18fe6404SChaoren Lin 
1154*18fe6404SChaoren Lin     // clear bits {0-4} of the debug status register (DR6)
1155*18fe6404SChaoren Lin     Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value);
1156*18fe6404SChaoren Lin     if (error.Fail()) return error;
1157*18fe6404SChaoren Lin     uint64_t bit_mask = 0xF;
1158*18fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
1159*18fe6404SChaoren Lin     error = WriteRegister(lldb_dr6_x86_64, RegisterValue(status_bits));
1160*18fe6404SChaoren Lin     if (error.Fail()) return error;
1161*18fe6404SChaoren Lin 
1162*18fe6404SChaoren Lin     // clear bits {0-7,16-31} of the debug control register (DR7)
1163*18fe6404SChaoren Lin     error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value);
1164*18fe6404SChaoren Lin     if (error.Fail()) return error;
1165*18fe6404SChaoren Lin     bit_mask = 0xFF | (0xFFFF << 16);
1166*18fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1167*18fe6404SChaoren Lin     return WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits));
1168*18fe6404SChaoren Lin }
1169*18fe6404SChaoren Lin 
1170*18fe6404SChaoren Lin uint32_t
1171*18fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint(
1172*18fe6404SChaoren Lin         lldb::addr_t addr, size_t size, uint32_t watch_flags)
1173*18fe6404SChaoren Lin {
1174*18fe6404SChaoren Lin     const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
1175*18fe6404SChaoren Lin     for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index)
1176*18fe6404SChaoren Lin         if (IsWatchpointVacant(wp_index).Success())
1177*18fe6404SChaoren Lin         {
1178*18fe6404SChaoren Lin             if (SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index).Fail())
1179*18fe6404SChaoren Lin                 continue;
1180*18fe6404SChaoren Lin             return wp_index;
1181*18fe6404SChaoren Lin         }
1182*18fe6404SChaoren Lin     return LLDB_INVALID_INDEX32;
1183*18fe6404SChaoren Lin }
1184*18fe6404SChaoren Lin 
1185*18fe6404SChaoren Lin lldb::addr_t
1186*18fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index)
1187*18fe6404SChaoren Lin {
1188*18fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
1189*18fe6404SChaoren Lin         return LLDB_INVALID_ADDRESS;
1190*18fe6404SChaoren Lin     RegisterValue reg_value;
1191*18fe6404SChaoren Lin     if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail())
1192*18fe6404SChaoren Lin         return LLDB_INVALID_ADDRESS;
1193*18fe6404SChaoren Lin     return reg_value.GetAsUInt64();
1194*18fe6404SChaoren Lin }
1195*18fe6404SChaoren Lin 
1196*18fe6404SChaoren Lin uint32_t
1197*18fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints ()
1198*18fe6404SChaoren Lin {
1199*18fe6404SChaoren Lin     // Available debug address registers: dr0, dr1, dr2, dr3
1200*18fe6404SChaoren Lin     return 4;
1201*18fe6404SChaoren Lin }
1202