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 
10068f8a7eSTamas Berghammer #if defined(__i386__) || defined(__x86_64__)
11068f8a7eSTamas Berghammer 
122850b1beSTodd Fiala #include "NativeRegisterContextLinux_x86_64.h"
132850b1beSTodd Fiala 
14c16f5dcaSChaoren Lin #include "lldb/Core/Log.h"
152850b1beSTodd Fiala #include "lldb/Core/DataBufferHeap.h"
162850b1beSTodd Fiala #include "lldb/Core/Error.h"
172850b1beSTodd Fiala #include "lldb/Core/RegisterValue.h"
18068f8a7eSTamas Berghammer #include "lldb/Host/HostInfo.h"
19068f8a7eSTamas Berghammer 
20068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
21068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
222850b1beSTodd Fiala 
232850b1beSTodd Fiala using namespace lldb_private;
24db264a6dSTamas Berghammer using namespace lldb_private::process_linux;
252850b1beSTodd Fiala 
262850b1beSTodd Fiala // ----------------------------------------------------------------------------
272850b1beSTodd Fiala // Private namespace.
282850b1beSTodd Fiala // ----------------------------------------------------------------------------
292850b1beSTodd Fiala 
302850b1beSTodd Fiala namespace
312850b1beSTodd Fiala {
322850b1beSTodd Fiala     // x86 32-bit general purpose registers.
332850b1beSTodd Fiala     const uint32_t
342850b1beSTodd Fiala     g_gpr_regnums_i386[] =
352850b1beSTodd Fiala     {
367f013bcdSZachary Turner         lldb_eax_i386,
377f013bcdSZachary Turner         lldb_ebx_i386,
387f013bcdSZachary Turner         lldb_ecx_i386,
397f013bcdSZachary Turner         lldb_edx_i386,
407f013bcdSZachary Turner         lldb_edi_i386,
417f013bcdSZachary Turner         lldb_esi_i386,
427f013bcdSZachary Turner         lldb_ebp_i386,
437f013bcdSZachary Turner         lldb_esp_i386,
447f013bcdSZachary Turner         lldb_eip_i386,
457f013bcdSZachary Turner         lldb_eflags_i386,
467f013bcdSZachary Turner         lldb_cs_i386,
477f013bcdSZachary Turner         lldb_fs_i386,
487f013bcdSZachary Turner         lldb_gs_i386,
497f013bcdSZachary Turner         lldb_ss_i386,
507f013bcdSZachary Turner         lldb_ds_i386,
517f013bcdSZachary Turner         lldb_es_i386,
527f013bcdSZachary Turner         lldb_ax_i386,
537f013bcdSZachary Turner         lldb_bx_i386,
547f013bcdSZachary Turner         lldb_cx_i386,
557f013bcdSZachary Turner         lldb_dx_i386,
567f013bcdSZachary Turner         lldb_di_i386,
577f013bcdSZachary Turner         lldb_si_i386,
587f013bcdSZachary Turner         lldb_bp_i386,
597f013bcdSZachary Turner         lldb_sp_i386,
607f013bcdSZachary Turner         lldb_ah_i386,
617f013bcdSZachary Turner         lldb_bh_i386,
627f013bcdSZachary Turner         lldb_ch_i386,
637f013bcdSZachary Turner         lldb_dh_i386,
647f013bcdSZachary Turner         lldb_al_i386,
657f013bcdSZachary Turner         lldb_bl_i386,
667f013bcdSZachary Turner         lldb_cl_i386,
677f013bcdSZachary Turner         lldb_dl_i386,
682850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
692850b1beSTodd Fiala     };
702850b1beSTodd Fiala     static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386,
712850b1beSTodd Fiala                   "g_gpr_regnums_i386 has wrong number of register infos");
722850b1beSTodd Fiala 
732850b1beSTodd Fiala     // x86 32-bit floating point registers.
742850b1beSTodd Fiala     const uint32_t
752850b1beSTodd Fiala     g_fpu_regnums_i386[] =
762850b1beSTodd Fiala     {
777f013bcdSZachary Turner         lldb_fctrl_i386,
787f013bcdSZachary Turner         lldb_fstat_i386,
797f013bcdSZachary Turner         lldb_ftag_i386,
807f013bcdSZachary Turner         lldb_fop_i386,
817f013bcdSZachary Turner         lldb_fiseg_i386,
827f013bcdSZachary Turner         lldb_fioff_i386,
837f013bcdSZachary Turner         lldb_foseg_i386,
847f013bcdSZachary Turner         lldb_fooff_i386,
857f013bcdSZachary Turner         lldb_mxcsr_i386,
867f013bcdSZachary Turner         lldb_mxcsrmask_i386,
877f013bcdSZachary Turner         lldb_st0_i386,
887f013bcdSZachary Turner         lldb_st1_i386,
897f013bcdSZachary Turner         lldb_st2_i386,
907f013bcdSZachary Turner         lldb_st3_i386,
917f013bcdSZachary Turner         lldb_st4_i386,
927f013bcdSZachary Turner         lldb_st5_i386,
937f013bcdSZachary Turner         lldb_st6_i386,
947f013bcdSZachary Turner         lldb_st7_i386,
957f013bcdSZachary Turner         lldb_mm0_i386,
967f013bcdSZachary Turner         lldb_mm1_i386,
977f013bcdSZachary Turner         lldb_mm2_i386,
987f013bcdSZachary Turner         lldb_mm3_i386,
997f013bcdSZachary Turner         lldb_mm4_i386,
1007f013bcdSZachary Turner         lldb_mm5_i386,
1017f013bcdSZachary Turner         lldb_mm6_i386,
1027f013bcdSZachary Turner         lldb_mm7_i386,
1037f013bcdSZachary Turner         lldb_xmm0_i386,
1047f013bcdSZachary Turner         lldb_xmm1_i386,
1057f013bcdSZachary Turner         lldb_xmm2_i386,
1067f013bcdSZachary Turner         lldb_xmm3_i386,
1077f013bcdSZachary Turner         lldb_xmm4_i386,
1087f013bcdSZachary Turner         lldb_xmm5_i386,
1097f013bcdSZachary Turner         lldb_xmm6_i386,
1107f013bcdSZachary Turner         lldb_xmm7_i386,
1112850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
1122850b1beSTodd Fiala     };
1132850b1beSTodd Fiala     static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
1142850b1beSTodd Fiala                   "g_fpu_regnums_i386 has wrong number of register infos");
1152850b1beSTodd Fiala 
1162850b1beSTodd Fiala     // x86 32-bit AVX registers.
1172850b1beSTodd Fiala     const uint32_t
1182850b1beSTodd Fiala     g_avx_regnums_i386[] =
1192850b1beSTodd Fiala     {
1207f013bcdSZachary Turner         lldb_ymm0_i386,
1217f013bcdSZachary Turner         lldb_ymm1_i386,
1227f013bcdSZachary Turner         lldb_ymm2_i386,
1237f013bcdSZachary Turner         lldb_ymm3_i386,
1247f013bcdSZachary Turner         lldb_ymm4_i386,
1257f013bcdSZachary Turner         lldb_ymm5_i386,
1267f013bcdSZachary Turner         lldb_ymm6_i386,
1277f013bcdSZachary Turner         lldb_ymm7_i386,
1282850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
1292850b1beSTodd Fiala     };
1302850b1beSTodd Fiala     static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386,
1312850b1beSTodd Fiala                   " g_avx_regnums_i386 has wrong number of register infos");
1322850b1beSTodd Fiala 
1332850b1beSTodd Fiala     // x86 64-bit general purpose registers.
1342850b1beSTodd Fiala     static const
1352850b1beSTodd Fiala     uint32_t g_gpr_regnums_x86_64[] =
1362850b1beSTodd Fiala     {
1377f013bcdSZachary Turner         lldb_rax_x86_64,
1387f013bcdSZachary Turner         lldb_rbx_x86_64,
1397f013bcdSZachary Turner         lldb_rcx_x86_64,
1407f013bcdSZachary Turner         lldb_rdx_x86_64,
1417f013bcdSZachary Turner         lldb_rdi_x86_64,
1427f013bcdSZachary Turner         lldb_rsi_x86_64,
1437f013bcdSZachary Turner         lldb_rbp_x86_64,
1447f013bcdSZachary Turner         lldb_rsp_x86_64,
1457f013bcdSZachary Turner         lldb_r8_x86_64,
1467f013bcdSZachary Turner         lldb_r9_x86_64,
1477f013bcdSZachary Turner         lldb_r10_x86_64,
1487f013bcdSZachary Turner         lldb_r11_x86_64,
1497f013bcdSZachary Turner         lldb_r12_x86_64,
1507f013bcdSZachary Turner         lldb_r13_x86_64,
1517f013bcdSZachary Turner         lldb_r14_x86_64,
1527f013bcdSZachary Turner         lldb_r15_x86_64,
1537f013bcdSZachary Turner         lldb_rip_x86_64,
1547f013bcdSZachary Turner         lldb_rflags_x86_64,
1557f013bcdSZachary Turner         lldb_cs_x86_64,
1567f013bcdSZachary Turner         lldb_fs_x86_64,
1577f013bcdSZachary Turner         lldb_gs_x86_64,
1587f013bcdSZachary Turner         lldb_ss_x86_64,
1597f013bcdSZachary Turner         lldb_ds_x86_64,
1607f013bcdSZachary Turner         lldb_es_x86_64,
1617f013bcdSZachary Turner         lldb_eax_x86_64,
1627f013bcdSZachary Turner         lldb_ebx_x86_64,
1637f013bcdSZachary Turner         lldb_ecx_x86_64,
1647f013bcdSZachary Turner         lldb_edx_x86_64,
1657f013bcdSZachary Turner         lldb_edi_x86_64,
1667f013bcdSZachary Turner         lldb_esi_x86_64,
1677f013bcdSZachary Turner         lldb_ebp_x86_64,
1687f013bcdSZachary Turner         lldb_esp_x86_64,
1697f013bcdSZachary Turner         lldb_r8d_x86_64,    // Low 32 bits or r8
1707f013bcdSZachary Turner         lldb_r9d_x86_64,    // Low 32 bits or r9
1717f013bcdSZachary Turner         lldb_r10d_x86_64,   // Low 32 bits or r10
1727f013bcdSZachary Turner         lldb_r11d_x86_64,   // Low 32 bits or r11
1737f013bcdSZachary Turner         lldb_r12d_x86_64,   // Low 32 bits or r12
1747f013bcdSZachary Turner         lldb_r13d_x86_64,   // Low 32 bits or r13
1757f013bcdSZachary Turner         lldb_r14d_x86_64,   // Low 32 bits or r14
1767f013bcdSZachary Turner         lldb_r15d_x86_64,   // Low 32 bits or r15
1777f013bcdSZachary Turner         lldb_ax_x86_64,
1787f013bcdSZachary Turner         lldb_bx_x86_64,
1797f013bcdSZachary Turner         lldb_cx_x86_64,
1807f013bcdSZachary Turner         lldb_dx_x86_64,
1817f013bcdSZachary Turner         lldb_di_x86_64,
1827f013bcdSZachary Turner         lldb_si_x86_64,
1837f013bcdSZachary Turner         lldb_bp_x86_64,
1847f013bcdSZachary Turner         lldb_sp_x86_64,
1857f013bcdSZachary Turner         lldb_r8w_x86_64,    // Low 16 bits or r8
1867f013bcdSZachary Turner         lldb_r9w_x86_64,    // Low 16 bits or r9
1877f013bcdSZachary Turner         lldb_r10w_x86_64,   // Low 16 bits or r10
1887f013bcdSZachary Turner         lldb_r11w_x86_64,   // Low 16 bits or r11
1897f013bcdSZachary Turner         lldb_r12w_x86_64,   // Low 16 bits or r12
1907f013bcdSZachary Turner         lldb_r13w_x86_64,   // Low 16 bits or r13
1917f013bcdSZachary Turner         lldb_r14w_x86_64,   // Low 16 bits or r14
1927f013bcdSZachary Turner         lldb_r15w_x86_64,   // Low 16 bits or r15
1937f013bcdSZachary Turner         lldb_ah_x86_64,
1947f013bcdSZachary Turner         lldb_bh_x86_64,
1957f013bcdSZachary Turner         lldb_ch_x86_64,
1967f013bcdSZachary Turner         lldb_dh_x86_64,
1977f013bcdSZachary Turner         lldb_al_x86_64,
1987f013bcdSZachary Turner         lldb_bl_x86_64,
1997f013bcdSZachary Turner         lldb_cl_x86_64,
2007f013bcdSZachary Turner         lldb_dl_x86_64,
2017f013bcdSZachary Turner         lldb_dil_x86_64,
2027f013bcdSZachary Turner         lldb_sil_x86_64,
2037f013bcdSZachary Turner         lldb_bpl_x86_64,
2047f013bcdSZachary Turner         lldb_spl_x86_64,
2057f013bcdSZachary Turner         lldb_r8l_x86_64,    // Low 8 bits or r8
2067f013bcdSZachary Turner         lldb_r9l_x86_64,    // Low 8 bits or r9
2077f013bcdSZachary Turner         lldb_r10l_x86_64,   // Low 8 bits or r10
2087f013bcdSZachary Turner         lldb_r11l_x86_64,   // Low 8 bits or r11
2097f013bcdSZachary Turner         lldb_r12l_x86_64,   // Low 8 bits or r12
2107f013bcdSZachary Turner         lldb_r13l_x86_64,   // Low 8 bits or r13
2117f013bcdSZachary Turner         lldb_r14l_x86_64,   // Low 8 bits or r14
2127f013bcdSZachary Turner         lldb_r15l_x86_64,   // Low 8 bits or r15
2132850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
2142850b1beSTodd Fiala     };
2152850b1beSTodd Fiala     static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64,
2162850b1beSTodd Fiala                   "g_gpr_regnums_x86_64 has wrong number of register infos");
2172850b1beSTodd Fiala 
2182850b1beSTodd Fiala     // x86 64-bit floating point registers.
2192850b1beSTodd Fiala     static const uint32_t
2202850b1beSTodd Fiala     g_fpu_regnums_x86_64[] =
2212850b1beSTodd Fiala     {
2227f013bcdSZachary Turner         lldb_fctrl_x86_64,
2237f013bcdSZachary Turner         lldb_fstat_x86_64,
2247f013bcdSZachary Turner         lldb_ftag_x86_64,
2257f013bcdSZachary Turner         lldb_fop_x86_64,
2267f013bcdSZachary Turner         lldb_fiseg_x86_64,
2277f013bcdSZachary Turner         lldb_fioff_x86_64,
2287f013bcdSZachary Turner         lldb_foseg_x86_64,
2297f013bcdSZachary Turner         lldb_fooff_x86_64,
2307f013bcdSZachary Turner         lldb_mxcsr_x86_64,
2317f013bcdSZachary Turner         lldb_mxcsrmask_x86_64,
2327f013bcdSZachary Turner         lldb_st0_x86_64,
2337f013bcdSZachary Turner         lldb_st1_x86_64,
2347f013bcdSZachary Turner         lldb_st2_x86_64,
2357f013bcdSZachary Turner         lldb_st3_x86_64,
2367f013bcdSZachary Turner         lldb_st4_x86_64,
2377f013bcdSZachary Turner         lldb_st5_x86_64,
2387f013bcdSZachary Turner         lldb_st6_x86_64,
2397f013bcdSZachary Turner         lldb_st7_x86_64,
2407f013bcdSZachary Turner         lldb_mm0_x86_64,
2417f013bcdSZachary Turner         lldb_mm1_x86_64,
2427f013bcdSZachary Turner         lldb_mm2_x86_64,
2437f013bcdSZachary Turner         lldb_mm3_x86_64,
2447f013bcdSZachary Turner         lldb_mm4_x86_64,
2457f013bcdSZachary Turner         lldb_mm5_x86_64,
2467f013bcdSZachary Turner         lldb_mm6_x86_64,
2477f013bcdSZachary Turner         lldb_mm7_x86_64,
2487f013bcdSZachary Turner         lldb_xmm0_x86_64,
2497f013bcdSZachary Turner         lldb_xmm1_x86_64,
2507f013bcdSZachary Turner         lldb_xmm2_x86_64,
2517f013bcdSZachary Turner         lldb_xmm3_x86_64,
2527f013bcdSZachary Turner         lldb_xmm4_x86_64,
2537f013bcdSZachary Turner         lldb_xmm5_x86_64,
2547f013bcdSZachary Turner         lldb_xmm6_x86_64,
2557f013bcdSZachary Turner         lldb_xmm7_x86_64,
2567f013bcdSZachary Turner         lldb_xmm8_x86_64,
2577f013bcdSZachary Turner         lldb_xmm9_x86_64,
2587f013bcdSZachary Turner         lldb_xmm10_x86_64,
2597f013bcdSZachary Turner         lldb_xmm11_x86_64,
2607f013bcdSZachary Turner         lldb_xmm12_x86_64,
2617f013bcdSZachary Turner         lldb_xmm13_x86_64,
2627f013bcdSZachary Turner         lldb_xmm14_x86_64,
2637f013bcdSZachary Turner         lldb_xmm15_x86_64,
2642850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
2652850b1beSTodd Fiala     };
2662850b1beSTodd Fiala     static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
2672850b1beSTodd Fiala                   "g_fpu_regnums_x86_64 has wrong number of register infos");
2682850b1beSTodd Fiala 
2692850b1beSTodd Fiala     // x86 64-bit AVX registers.
2702850b1beSTodd Fiala     static const uint32_t
2712850b1beSTodd Fiala     g_avx_regnums_x86_64[] =
2722850b1beSTodd Fiala     {
2737f013bcdSZachary Turner         lldb_ymm0_x86_64,
2747f013bcdSZachary Turner         lldb_ymm1_x86_64,
2757f013bcdSZachary Turner         lldb_ymm2_x86_64,
2767f013bcdSZachary Turner         lldb_ymm3_x86_64,
2777f013bcdSZachary Turner         lldb_ymm4_x86_64,
2787f013bcdSZachary Turner         lldb_ymm5_x86_64,
2797f013bcdSZachary Turner         lldb_ymm6_x86_64,
2807f013bcdSZachary Turner         lldb_ymm7_x86_64,
2817f013bcdSZachary Turner         lldb_ymm8_x86_64,
2827f013bcdSZachary Turner         lldb_ymm9_x86_64,
2837f013bcdSZachary Turner         lldb_ymm10_x86_64,
2847f013bcdSZachary Turner         lldb_ymm11_x86_64,
2857f013bcdSZachary Turner         lldb_ymm12_x86_64,
2867f013bcdSZachary Turner         lldb_ymm13_x86_64,
2877f013bcdSZachary Turner         lldb_ymm14_x86_64,
2887f013bcdSZachary Turner         lldb_ymm15_x86_64,
2892850b1beSTodd Fiala         LLDB_INVALID_REGNUM // register sets need to end with this flag
2902850b1beSTodd Fiala     };
2912850b1beSTodd Fiala     static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64,
2922850b1beSTodd Fiala                   "g_avx_regnums_x86_64 has wrong number of register infos");
2932850b1beSTodd Fiala 
2942850b1beSTodd Fiala     // Number of register sets provided by this context.
2952850b1beSTodd Fiala     enum
2962850b1beSTodd Fiala     {
2972850b1beSTodd Fiala         k_num_extended_register_sets = 1,
2982850b1beSTodd Fiala         k_num_register_sets = 3
2992850b1beSTodd Fiala     };
3002850b1beSTodd Fiala 
3012850b1beSTodd Fiala     // Register sets for x86 32-bit.
3022850b1beSTodd Fiala     static const RegisterSet
3032850b1beSTodd Fiala     g_reg_sets_i386[k_num_register_sets] =
3042850b1beSTodd Fiala     {
3052850b1beSTodd Fiala         { "General Purpose Registers",  "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 },
3062850b1beSTodd Fiala         { "Floating Point Registers",   "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 },
3072850b1beSTodd Fiala         { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 }
3082850b1beSTodd Fiala     };
3092850b1beSTodd Fiala 
3102850b1beSTodd Fiala     // Register sets for x86 64-bit.
3112850b1beSTodd Fiala     static const RegisterSet
3122850b1beSTodd Fiala     g_reg_sets_x86_64[k_num_register_sets] =
3132850b1beSTodd Fiala     {
3142850b1beSTodd Fiala         { "General Purpose Registers",  "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 },
3152850b1beSTodd Fiala         { "Floating Point Registers",   "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 },
3162850b1beSTodd Fiala         { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 }
3172850b1beSTodd Fiala     };
3182850b1beSTodd Fiala }
3192850b1beSTodd Fiala 
3202850b1beSTodd Fiala #define REG_CONTEXT_SIZE (GetRegisterInfoInterface ().GetGPRSize () + sizeof(FPR))
3212850b1beSTodd Fiala 
3222850b1beSTodd Fiala // ----------------------------------------------------------------------------
3232850b1beSTodd Fiala // Required ptrace defines.
3242850b1beSTodd Fiala // ----------------------------------------------------------------------------
3252850b1beSTodd Fiala 
3262850b1beSTodd Fiala // Support ptrace extensions even when compiled without required kernel support
3272850b1beSTodd Fiala #ifndef NT_X86_XSTATE
3282850b1beSTodd Fiala #define NT_X86_XSTATE 0x202
3292850b1beSTodd Fiala #endif
330*296e063dSAbhishek Aggarwal #ifndef NT_PRXFPREG
331*296e063dSAbhishek Aggarwal #define NT_PRXFPREG 0x46e62b7f
332*296e063dSAbhishek Aggarwal #endif
3332850b1beSTodd Fiala 
334068f8a7eSTamas Berghammer NativeRegisterContextLinux*
335068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
336068f8a7eSTamas Berghammer                                                                  NativeThreadProtocol &native_thread,
337068f8a7eSTamas Berghammer                                                                  uint32_t concrete_frame_idx)
338068f8a7eSTamas Berghammer {
339068f8a7eSTamas Berghammer     return new NativeRegisterContextLinux_x86_64(target_arch, native_thread, concrete_frame_idx);
340068f8a7eSTamas Berghammer }
341068f8a7eSTamas Berghammer 
3422850b1beSTodd Fiala // ----------------------------------------------------------------------------
3432850b1beSTodd Fiala // NativeRegisterContextLinux_x86_64 members.
3442850b1beSTodd Fiala // ----------------------------------------------------------------------------
3452850b1beSTodd Fiala 
346068f8a7eSTamas Berghammer static RegisterInfoInterface*
347068f8a7eSTamas Berghammer CreateRegisterInfoInterface(const ArchSpec& target_arch)
348068f8a7eSTamas Berghammer {
349068f8a7eSTamas Berghammer     if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
350068f8a7eSTamas Berghammer     {
351068f8a7eSTamas Berghammer         // 32-bit hosts run with a RegisterContextLinux_i386 context.
352068f8a7eSTamas Berghammer         return new RegisterContextLinux_i386(target_arch);
353068f8a7eSTamas Berghammer     }
354068f8a7eSTamas Berghammer     else
355068f8a7eSTamas Berghammer     {
356068f8a7eSTamas Berghammer         assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
357068f8a7eSTamas Berghammer                "Register setting path assumes this is a 64-bit host");
358068f8a7eSTamas Berghammer         // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
359068f8a7eSTamas Berghammer         return new RegisterContextLinux_x86_64 (target_arch);
360068f8a7eSTamas Berghammer     }
361068f8a7eSTamas Berghammer }
362068f8a7eSTamas Berghammer 
363068f8a7eSTamas Berghammer NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const ArchSpec& target_arch,
364068f8a7eSTamas Berghammer                                                                       NativeThreadProtocol &native_thread,
365068f8a7eSTamas Berghammer                                                                       uint32_t concrete_frame_idx) :
366068f8a7eSTamas Berghammer     NativeRegisterContextLinux (native_thread, concrete_frame_idx, CreateRegisterInfoInterface(target_arch)),
3672850b1beSTodd Fiala     m_fpr_type (eFPRTypeNotValid),
3682850b1beSTodd Fiala     m_fpr (),
3692850b1beSTodd Fiala     m_iovec (),
3702850b1beSTodd Fiala     m_ymm_set (),
3712850b1beSTodd Fiala     m_reg_info (),
3722850b1beSTodd Fiala     m_gpr_x86_64 ()
3732850b1beSTodd Fiala {
3742850b1beSTodd Fiala     // Set up data about ranges of valid registers.
375068f8a7eSTamas Berghammer     switch (target_arch.GetMachine ())
3762850b1beSTodd Fiala     {
3772850b1beSTodd Fiala         case llvm::Triple::x86:
3782850b1beSTodd Fiala             m_reg_info.num_registers        = k_num_registers_i386;
3792850b1beSTodd Fiala             m_reg_info.num_gpr_registers    = k_num_gpr_registers_i386;
3802850b1beSTodd Fiala             m_reg_info.num_fpr_registers    = k_num_fpr_registers_i386;
3812850b1beSTodd Fiala             m_reg_info.num_avx_registers    = k_num_avx_registers_i386;
3822850b1beSTodd Fiala             m_reg_info.last_gpr             = k_last_gpr_i386;
3832850b1beSTodd Fiala             m_reg_info.first_fpr            = k_first_fpr_i386;
3842850b1beSTodd Fiala             m_reg_info.last_fpr             = k_last_fpr_i386;
3857f013bcdSZachary Turner             m_reg_info.first_st             = lldb_st0_i386;
3867f013bcdSZachary Turner             m_reg_info.last_st              = lldb_st7_i386;
3877f013bcdSZachary Turner             m_reg_info.first_mm             = lldb_mm0_i386;
3887f013bcdSZachary Turner             m_reg_info.last_mm              = lldb_mm7_i386;
3897f013bcdSZachary Turner             m_reg_info.first_xmm            = lldb_xmm0_i386;
3907f013bcdSZachary Turner             m_reg_info.last_xmm             = lldb_xmm7_i386;
3917f013bcdSZachary Turner             m_reg_info.first_ymm            = lldb_ymm0_i386;
3927f013bcdSZachary Turner             m_reg_info.last_ymm             = lldb_ymm7_i386;
3937f013bcdSZachary Turner             m_reg_info.first_dr             = lldb_dr0_i386;
3947f013bcdSZachary Turner             m_reg_info.gpr_flags            = lldb_eflags_i386;
3952850b1beSTodd Fiala             break;
3962850b1beSTodd Fiala         case llvm::Triple::x86_64:
3972850b1beSTodd Fiala             m_reg_info.num_registers        = k_num_registers_x86_64;
3982850b1beSTodd Fiala             m_reg_info.num_gpr_registers    = k_num_gpr_registers_x86_64;
3992850b1beSTodd Fiala             m_reg_info.num_fpr_registers    = k_num_fpr_registers_x86_64;
4002850b1beSTodd Fiala             m_reg_info.num_avx_registers    = k_num_avx_registers_x86_64;
4012850b1beSTodd Fiala             m_reg_info.last_gpr             = k_last_gpr_x86_64;
4022850b1beSTodd Fiala             m_reg_info.first_fpr            = k_first_fpr_x86_64;
4032850b1beSTodd Fiala             m_reg_info.last_fpr             = k_last_fpr_x86_64;
4047f013bcdSZachary Turner             m_reg_info.first_st             = lldb_st0_x86_64;
4057f013bcdSZachary Turner             m_reg_info.last_st              = lldb_st7_x86_64;
4067f013bcdSZachary Turner             m_reg_info.first_mm             = lldb_mm0_x86_64;
4077f013bcdSZachary Turner             m_reg_info.last_mm              = lldb_mm7_x86_64;
4087f013bcdSZachary Turner             m_reg_info.first_xmm            = lldb_xmm0_x86_64;
4097f013bcdSZachary Turner             m_reg_info.last_xmm             = lldb_xmm15_x86_64;
4107f013bcdSZachary Turner             m_reg_info.first_ymm            = lldb_ymm0_x86_64;
4117f013bcdSZachary Turner             m_reg_info.last_ymm             = lldb_ymm15_x86_64;
4127f013bcdSZachary Turner             m_reg_info.first_dr             = lldb_dr0_x86_64;
4137f013bcdSZachary Turner             m_reg_info.gpr_flags            = lldb_rflags_x86_64;
4142850b1beSTodd Fiala             break;
4152850b1beSTodd Fiala         default:
4162850b1beSTodd Fiala             assert(false && "Unhandled target architecture.");
4172850b1beSTodd Fiala             break;
4182850b1beSTodd Fiala     }
4192850b1beSTodd Fiala 
4202850b1beSTodd Fiala     // Initialize m_iovec to point to the buffer and buffer size
4212850b1beSTodd Fiala     // using the conventions of Berkeley style UIO structures, as required
4222850b1beSTodd Fiala     // by PTRACE extensions.
4232850b1beSTodd Fiala     m_iovec.iov_base = &m_fpr.xstate.xsave;
4242850b1beSTodd Fiala     m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
4252850b1beSTodd Fiala 
4262850b1beSTodd Fiala     // Clear out the FPR state.
4272850b1beSTodd Fiala     ::memset(&m_fpr, 0, sizeof(FPR));
4287f658eddSAbhishek Aggarwal 
4297f658eddSAbhishek Aggarwal     // Store byte offset of fctrl (i.e. first register of FPR)
4307f658eddSAbhishek Aggarwal     const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl");
4317f658eddSAbhishek Aggarwal     m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset;
4322850b1beSTodd Fiala }
4332850b1beSTodd Fiala 
4342850b1beSTodd Fiala // CONSIDER after local and llgs debugging are merged, register set support can
4352850b1beSTodd Fiala // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
4362850b1beSTodd Fiala uint32_t
4372850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetRegisterSetCount () const
4382850b1beSTodd Fiala {
4392850b1beSTodd Fiala     uint32_t sets = 0;
4402850b1beSTodd Fiala     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
4412850b1beSTodd Fiala     {
4422850b1beSTodd Fiala         if (IsRegisterSetAvailable (set_index))
4432850b1beSTodd Fiala             ++sets;
4442850b1beSTodd Fiala     }
4452850b1beSTodd Fiala 
4462850b1beSTodd Fiala     return sets;
4472850b1beSTodd Fiala }
4482850b1beSTodd Fiala 
4498fa23b8eSTamas Berghammer uint32_t
4508fa23b8eSTamas Berghammer NativeRegisterContextLinux_x86_64::GetUserRegisterCount() const
4518fa23b8eSTamas Berghammer {
4528fa23b8eSTamas Berghammer     uint32_t count = 0;
4538fa23b8eSTamas Berghammer     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
4548fa23b8eSTamas Berghammer     {
455db264a6dSTamas Berghammer         const RegisterSet* set = GetRegisterSet(set_index);
4568fa23b8eSTamas Berghammer         if (set)
4578fa23b8eSTamas Berghammer             count += set->num_registers;
4588fa23b8eSTamas Berghammer     }
4598fa23b8eSTamas Berghammer     return count;
4608fa23b8eSTamas Berghammer }
4618fa23b8eSTamas Berghammer 
462db264a6dSTamas Berghammer const RegisterSet *
4632850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetRegisterSet (uint32_t set_index) const
4642850b1beSTodd Fiala {
4652850b1beSTodd Fiala     if (!IsRegisterSetAvailable (set_index))
4662850b1beSTodd Fiala         return nullptr;
4672850b1beSTodd Fiala 
4682850b1beSTodd Fiala     switch (GetRegisterInfoInterface ().GetTargetArchitecture ().GetMachine ())
4692850b1beSTodd Fiala     {
4702850b1beSTodd Fiala         case llvm::Triple::x86:
4712850b1beSTodd Fiala             return &g_reg_sets_i386[set_index];
4722850b1beSTodd Fiala         case llvm::Triple::x86_64:
4732850b1beSTodd Fiala             return &g_reg_sets_x86_64[set_index];
4742850b1beSTodd Fiala         default:
4752850b1beSTodd Fiala             assert (false && "Unhandled target architecture.");
4762850b1beSTodd Fiala             return nullptr;
4772850b1beSTodd Fiala     }
4782850b1beSTodd Fiala 
4792850b1beSTodd Fiala     return nullptr;
4802850b1beSTodd Fiala }
4812850b1beSTodd Fiala 
482db264a6dSTamas Berghammer Error
4832850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
4842850b1beSTodd Fiala {
4852850b1beSTodd Fiala     Error error;
4862850b1beSTodd Fiala 
4872850b1beSTodd Fiala     if (!reg_info)
4882850b1beSTodd Fiala     {
4892850b1beSTodd Fiala         error.SetErrorString ("reg_info NULL");
4902850b1beSTodd Fiala         return error;
4912850b1beSTodd Fiala     }
4922850b1beSTodd Fiala 
4932850b1beSTodd Fiala     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
4942850b1beSTodd Fiala     if (reg == LLDB_INVALID_REGNUM)
4952850b1beSTodd Fiala     {
4962850b1beSTodd Fiala         // This is likely an internal register for lldb use only and should not be directly queried.
4972850b1beSTodd Fiala         error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name);
4982850b1beSTodd Fiala         return error;
4992850b1beSTodd Fiala     }
5002850b1beSTodd Fiala 
5012850b1beSTodd Fiala     if (IsFPR(reg, GetFPRType()))
5022850b1beSTodd Fiala     {
503068f8a7eSTamas Berghammer         error = ReadFPR();
504068f8a7eSTamas Berghammer         if (error.Fail())
5052850b1beSTodd Fiala             return error;
5062850b1beSTodd Fiala     }
5072850b1beSTodd Fiala     else
5082850b1beSTodd Fiala     {
5092850b1beSTodd Fiala         uint32_t full_reg = reg;
5102850b1beSTodd Fiala         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
5112850b1beSTodd Fiala 
5122850b1beSTodd Fiala         if (is_subreg)
5132850b1beSTodd Fiala         {
5142850b1beSTodd Fiala             // Read the full aligned 64-bit register.
5152850b1beSTodd Fiala             full_reg = reg_info->invalidate_regs[0];
5162850b1beSTodd Fiala         }
5172850b1beSTodd Fiala 
5182850b1beSTodd Fiala         error = ReadRegisterRaw(full_reg, reg_value);
5192850b1beSTodd Fiala 
5202850b1beSTodd Fiala         if (error.Success ())
5212850b1beSTodd Fiala         {
5222850b1beSTodd Fiala             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
5232850b1beSTodd Fiala             if (is_subreg && (reg_info->byte_offset & 0x1))
5242850b1beSTodd Fiala                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
5252850b1beSTodd Fiala 
5262850b1beSTodd Fiala             // If our return byte size was greater than the return value reg size, then
5272850b1beSTodd Fiala             // use the type specified by reg_info rather than the uint64_t default
5282850b1beSTodd Fiala             if (reg_value.GetByteSize() > reg_info->byte_size)
5292850b1beSTodd Fiala                 reg_value.SetType(reg_info);
5302850b1beSTodd Fiala         }
5312850b1beSTodd Fiala         return error;
5322850b1beSTodd Fiala     }
5332850b1beSTodd Fiala 
5342850b1beSTodd Fiala     if (reg_info->encoding == lldb::eEncodingVector)
5352850b1beSTodd Fiala     {
5362850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder();
5372850b1beSTodd Fiala 
5382850b1beSTodd Fiala         if (byte_order != lldb::eByteOrderInvalid)
5392850b1beSTodd Fiala         {
5402850b1beSTodd Fiala             if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
5412850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order);
5422850b1beSTodd Fiala             if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
5432850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order);
5442850b1beSTodd Fiala             if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
5452850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order);
5462850b1beSTodd Fiala             if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
5472850b1beSTodd Fiala             {
5482850b1beSTodd Fiala                 // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
5492850b1beSTodd Fiala                 if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoYMM(reg, byte_order))
5502850b1beSTodd Fiala                     reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order);
5512850b1beSTodd Fiala                 else
5522850b1beSTodd Fiala                 {
5532850b1beSTodd Fiala                     error.SetErrorString ("failed to copy ymm register value");
5542850b1beSTodd Fiala                     return error;
5552850b1beSTodd Fiala                 }
5562850b1beSTodd Fiala             }
5572850b1beSTodd Fiala 
5582850b1beSTodd Fiala             if (reg_value.GetType() != RegisterValue::eTypeBytes)
5592850b1beSTodd Fiala                 error.SetErrorString ("write failed - type was expected to be RegisterValue::eTypeBytes");
5602850b1beSTodd Fiala 
5612850b1beSTodd Fiala             return error;
5622850b1beSTodd Fiala         }
5632850b1beSTodd Fiala 
5642850b1beSTodd Fiala         error.SetErrorString ("byte order is invalid");
5652850b1beSTodd Fiala         return error;
5662850b1beSTodd Fiala     }
5672850b1beSTodd Fiala 
5682850b1beSTodd Fiala     // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
5697f658eddSAbhishek Aggarwal 
5707f658eddSAbhishek Aggarwal     // Byte offsets of all registers are calculated wrt 'UserArea' structure.
5717f658eddSAbhishek Aggarwal     // However, ReadFPR() reads fpu registers {using ptrace(PTRACE_GETFPREGS,..)}
5727f658eddSAbhishek Aggarwal     // and stores them in 'm_fpr' (of type FPR structure). To extract values of fpu
5737f658eddSAbhishek Aggarwal     // registers, m_fpr should be read at byte offsets calculated wrt to FPR structure.
5747f658eddSAbhishek Aggarwal 
5757f658eddSAbhishek Aggarwal     // Since, FPR structure is also one of the member of UserArea structure.
5767f658eddSAbhishek Aggarwal     // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea)
5777f658eddSAbhishek Aggarwal     assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
5787f658eddSAbhishek Aggarwal     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
5792850b1beSTodd Fiala     switch (reg_info->byte_size)
5802850b1beSTodd Fiala     {
581b352a1c8SAbhishek Aggarwal         case 1:
582b352a1c8SAbhishek Aggarwal             reg_value.SetUInt8(*(uint8_t *)src);
583b352a1c8SAbhishek Aggarwal             break;
5842850b1beSTodd Fiala         case 2:
5852850b1beSTodd Fiala             reg_value.SetUInt16(*(uint16_t *)src);
5862850b1beSTodd Fiala             break;
5872850b1beSTodd Fiala         case 4:
5882850b1beSTodd Fiala             reg_value.SetUInt32(*(uint32_t *)src);
5892850b1beSTodd Fiala             break;
5902850b1beSTodd Fiala         case 8:
5912850b1beSTodd Fiala             reg_value.SetUInt64(*(uint64_t *)src);
5922850b1beSTodd Fiala             break;
5932850b1beSTodd Fiala         default:
5942850b1beSTodd Fiala             assert(false && "Unhandled data size.");
5952850b1beSTodd Fiala             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
5962850b1beSTodd Fiala             break;
5972850b1beSTodd Fiala     }
5982850b1beSTodd Fiala 
5992850b1beSTodd Fiala     return error;
6002850b1beSTodd Fiala }
6012850b1beSTodd Fiala 
602db264a6dSTamas Berghammer Error
6032850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
6042850b1beSTodd Fiala {
6052850b1beSTodd Fiala     assert (reg_info && "reg_info is null");
6062850b1beSTodd Fiala 
6072850b1beSTodd Fiala     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
6082850b1beSTodd Fiala     if (reg_index == LLDB_INVALID_REGNUM)
6092850b1beSTodd Fiala         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
6102850b1beSTodd Fiala 
6112850b1beSTodd Fiala     if (IsGPR(reg_index))
612068f8a7eSTamas Berghammer         return WriteRegisterRaw(reg_index, reg_value);
6132850b1beSTodd Fiala 
6142850b1beSTodd Fiala     if (IsFPR(reg_index, GetFPRType()))
6152850b1beSTodd Fiala     {
6162850b1beSTodd Fiala         if (reg_info->encoding == lldb::eEncodingVector)
6172850b1beSTodd Fiala         {
6182850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
6192850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_st].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6202850b1beSTodd Fiala 
6212850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm)
6222850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6232850b1beSTodd Fiala 
6242850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm)
6252850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6262850b1beSTodd Fiala 
6272850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_ymm && reg_index <= m_reg_info.last_ymm)
6282850b1beSTodd Fiala             {
6292850b1beSTodd Fiala                 if (GetFPRType() != eFPRTypeXSAVE)
6302850b1beSTodd Fiala                     return Error ("target processor does not support AVX");
6312850b1beSTodd Fiala 
6322850b1beSTodd Fiala                 // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
6332850b1beSTodd Fiala                 ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6342850b1beSTodd Fiala                 if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
6352850b1beSTodd Fiala                     return Error ("CopyYMMtoXSTATE() failed");
6362850b1beSTodd Fiala             }
6372850b1beSTodd Fiala         }
6382850b1beSTodd Fiala         else
6392850b1beSTodd Fiala         {
6402850b1beSTodd Fiala             // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
6417f658eddSAbhishek Aggarwal 
6427f658eddSAbhishek Aggarwal             // Byte offsets of all registers are calculated wrt 'UserArea' structure.
6437f658eddSAbhishek Aggarwal             // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only fpu
6447f658eddSAbhishek Aggarwal             // registers using ptrace(PTRACE_SETFPREGS,..) API. Hence fpu registers should
6457f658eddSAbhishek Aggarwal             // be written in m_fpr at byte offsets calculated wrt FPR structure.
6467f658eddSAbhishek Aggarwal 
6477f658eddSAbhishek Aggarwal             // Since, FPR structure is also one of the member of UserArea structure.
6487f658eddSAbhishek Aggarwal             // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea)
6497f658eddSAbhishek Aggarwal             assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
6507f658eddSAbhishek Aggarwal             uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
6512850b1beSTodd Fiala             switch (reg_info->byte_size)
6522850b1beSTodd Fiala             {
653b352a1c8SAbhishek Aggarwal                 case 1:
654b352a1c8SAbhishek Aggarwal                     *(uint8_t *)dst = reg_value.GetAsUInt8();
655b352a1c8SAbhishek Aggarwal                     break;
6562850b1beSTodd Fiala                 case 2:
6572850b1beSTodd Fiala                     *(uint16_t *)dst = reg_value.GetAsUInt16();
6582850b1beSTodd Fiala                     break;
6592850b1beSTodd Fiala                 case 4:
6602850b1beSTodd Fiala                     *(uint32_t *)dst = reg_value.GetAsUInt32();
6612850b1beSTodd Fiala                     break;
6622850b1beSTodd Fiala                 case 8:
6632850b1beSTodd Fiala                     *(uint64_t *)dst = reg_value.GetAsUInt64();
6642850b1beSTodd Fiala                     break;
6652850b1beSTodd Fiala                 default:
6662850b1beSTodd Fiala                     assert(false && "Unhandled data size.");
6672850b1beSTodd Fiala                     return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
6682850b1beSTodd Fiala             }
6692850b1beSTodd Fiala         }
6702850b1beSTodd Fiala 
671068f8a7eSTamas Berghammer         Error error = WriteFPR();
672068f8a7eSTamas Berghammer         if (error.Fail())
673068f8a7eSTamas Berghammer             return error;
674068f8a7eSTamas Berghammer 
6752850b1beSTodd Fiala         if (IsAVX(reg_index))
6762850b1beSTodd Fiala         {
6772850b1beSTodd Fiala             if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
6782850b1beSTodd Fiala                 return Error ("CopyYMMtoXSTATE() failed");
6792850b1beSTodd Fiala         }
6802850b1beSTodd Fiala         return Error ();
6812850b1beSTodd Fiala     }
6822850b1beSTodd Fiala     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
6832850b1beSTodd Fiala }
6842850b1beSTodd Fiala 
685db264a6dSTamas Berghammer Error
6862850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
6872850b1beSTodd Fiala {
6882850b1beSTodd Fiala     Error error;
6892850b1beSTodd Fiala 
6902850b1beSTodd Fiala     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
6912850b1beSTodd Fiala     if (!data_sp)
6922850b1beSTodd Fiala     {
6932850b1beSTodd Fiala         error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
6942850b1beSTodd Fiala         return error;
6952850b1beSTodd Fiala     }
6962850b1beSTodd Fiala 
697068f8a7eSTamas Berghammer     error = ReadGPR();
698068f8a7eSTamas Berghammer     if (error.Fail())
6992850b1beSTodd Fiala         return error;
7002850b1beSTodd Fiala 
701068f8a7eSTamas Berghammer     error = ReadFPR();
702068f8a7eSTamas Berghammer     if (error.Fail())
7032850b1beSTodd Fiala         return error;
7042850b1beSTodd Fiala 
7052850b1beSTodd Fiala     uint8_t *dst = data_sp->GetBytes ();
7062850b1beSTodd Fiala     if (dst == nullptr)
7072850b1beSTodd Fiala     {
7082850b1beSTodd Fiala         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
7092850b1beSTodd Fiala         return error;
7102850b1beSTodd Fiala     }
7112850b1beSTodd Fiala 
7122850b1beSTodd Fiala     ::memcpy (dst, &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
7132850b1beSTodd Fiala     dst += GetRegisterInfoInterface ().GetGPRSize ();
7142850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeFXSAVE)
7152850b1beSTodd Fiala         ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
7162850b1beSTodd Fiala     else if (GetFPRType () == eFPRTypeXSAVE)
7172850b1beSTodd Fiala     {
7182850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder ();
7192850b1beSTodd Fiala 
7202850b1beSTodd Fiala         // Assemble the YMM register content from the register halves.
7212850b1beSTodd Fiala         for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
7222850b1beSTodd Fiala         {
7232850b1beSTodd Fiala             if (!CopyXSTATEtoYMM (reg, byte_order))
7242850b1beSTodd Fiala             {
7252850b1beSTodd Fiala                 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyXSTATEtoYMM() failed for reg num %" PRIu32, __FUNCTION__, reg);
7262850b1beSTodd Fiala                 return error;
7272850b1beSTodd Fiala             }
7282850b1beSTodd Fiala         }
7292850b1beSTodd Fiala 
7302850b1beSTodd Fiala         // Copy the extended register state including the assembled ymm registers.
7312850b1beSTodd Fiala         ::memcpy (dst, &m_fpr, sizeof (m_fpr));
7322850b1beSTodd Fiala     }
7332850b1beSTodd Fiala     else
7342850b1beSTodd Fiala     {
7352850b1beSTodd Fiala         assert (false && "how do we save the floating point registers?");
7362850b1beSTodd Fiala         error.SetErrorString ("unsure how to save the floating point registers");
7372850b1beSTodd Fiala     }
7384778e410SRavitheja Addepally     /** The following code is specific to Linux x86 based architectures,
7394778e410SRavitheja Addepally      *  where the register orig_eax (32 bit)/orig_rax (64 bit) is set to
7404778e410SRavitheja Addepally      *  -1 to solve the bug 23659, such a setting prevents the automatic
7414778e410SRavitheja Addepally      *  decrement of the instruction pointer which was causing the SIGILL
7424778e410SRavitheja Addepally      *  exception.
7434778e410SRavitheja Addepally      * **/
7444778e410SRavitheja Addepally 
7454778e410SRavitheja Addepally     RegisterValue value((uint64_t) -1);
7464778e410SRavitheja Addepally     const RegisterInfo *reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
7474778e410SRavitheja Addepally     if (reg_info == nullptr)
7484778e410SRavitheja Addepally         reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
7494778e410SRavitheja Addepally 
75064ad85ceSTamas Berghammer     if (reg_info != nullptr)
7514778e410SRavitheja Addepally         return DoWriteRegisterValue(reg_info->byte_offset,reg_info->name,value);
7522850b1beSTodd Fiala 
7532850b1beSTodd Fiala     return error;
7542850b1beSTodd Fiala }
7552850b1beSTodd Fiala 
756db264a6dSTamas Berghammer Error
7572850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
7582850b1beSTodd Fiala {
7592850b1beSTodd Fiala     Error error;
7602850b1beSTodd Fiala 
7612850b1beSTodd Fiala     if (!data_sp)
7622850b1beSTodd Fiala     {
7632850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
7642850b1beSTodd Fiala         return error;
7652850b1beSTodd Fiala     }
7662850b1beSTodd Fiala 
7672850b1beSTodd Fiala     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
7682850b1beSTodd Fiala     {
7692850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
7702850b1beSTodd Fiala         return error;
7712850b1beSTodd Fiala     }
7722850b1beSTodd Fiala 
7732850b1beSTodd Fiala 
7742850b1beSTodd Fiala     uint8_t *src = data_sp->GetBytes ();
7752850b1beSTodd Fiala     if (src == nullptr)
7762850b1beSTodd Fiala     {
7772850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
7782850b1beSTodd Fiala         return error;
7792850b1beSTodd Fiala     }
7802850b1beSTodd Fiala     ::memcpy (&m_gpr_x86_64, src, GetRegisterInfoInterface ().GetGPRSize ());
7812850b1beSTodd Fiala 
782068f8a7eSTamas Berghammer     error = WriteGPR();
783068f8a7eSTamas Berghammer     if (error.Fail())
7842850b1beSTodd Fiala         return error;
7852850b1beSTodd Fiala 
7862850b1beSTodd Fiala     src += GetRegisterInfoInterface ().GetGPRSize ();
7872850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeFXSAVE)
7882850b1beSTodd Fiala         ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
7892850b1beSTodd Fiala     else if (GetFPRType () == eFPRTypeXSAVE)
7902850b1beSTodd Fiala         ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
7912850b1beSTodd Fiala 
792068f8a7eSTamas Berghammer     error = WriteFPR();
793068f8a7eSTamas Berghammer     if (error.Fail())
7942850b1beSTodd Fiala         return error;
7952850b1beSTodd Fiala 
7962850b1beSTodd Fiala     if (GetFPRType() == eFPRTypeXSAVE)
7972850b1beSTodd Fiala     {
7982850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder();
7992850b1beSTodd Fiala 
8002850b1beSTodd Fiala         // Parse the YMM register content from the register halves.
8012850b1beSTodd Fiala         for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
8022850b1beSTodd Fiala         {
8032850b1beSTodd Fiala             if (!CopyYMMtoXSTATE (reg, byte_order))
8042850b1beSTodd Fiala             {
8052850b1beSTodd Fiala                 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyYMMtoXSTATE() failed for reg num %" PRIu32, __FUNCTION__, reg);
8062850b1beSTodd Fiala                 return error;
8072850b1beSTodd Fiala             }
8082850b1beSTodd Fiala         }
8092850b1beSTodd Fiala     }
8102850b1beSTodd Fiala 
8112850b1beSTodd Fiala     return error;
8122850b1beSTodd Fiala }
8132850b1beSTodd Fiala 
8142850b1beSTodd Fiala bool
8152850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable (uint32_t set_index) const
8162850b1beSTodd Fiala {
8172850b1beSTodd Fiala     // Note: Extended register sets are assumed to be at the end of g_reg_sets.
8182850b1beSTodd Fiala     uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
8192850b1beSTodd Fiala 
8202850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeXSAVE)
8212850b1beSTodd Fiala     {
8222850b1beSTodd Fiala         // AVX is the first extended register set.
8232850b1beSTodd Fiala         ++num_sets;
8242850b1beSTodd Fiala     }
8252850b1beSTodd Fiala     return (set_index < num_sets);
8262850b1beSTodd Fiala }
8272850b1beSTodd Fiala 
8282850b1beSTodd Fiala bool
8292850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const
8302850b1beSTodd Fiala {
8312850b1beSTodd Fiala     // GPRs come first.
8322850b1beSTodd Fiala     return reg_index <= m_reg_info.last_gpr;
8332850b1beSTodd Fiala }
8342850b1beSTodd Fiala 
8352850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::FPRType
8362850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetFPRType () const
8372850b1beSTodd Fiala {
838*296e063dSAbhishek Aggarwal     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
8392850b1beSTodd Fiala     if (m_fpr_type == eFPRTypeNotValid)
8402850b1beSTodd Fiala     {
8412850b1beSTodd Fiala         // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx.
8422850b1beSTodd Fiala 
8432850b1beSTodd Fiala         // Try and see if AVX register retrieval works.
8442850b1beSTodd Fiala         m_fpr_type = eFPRTypeXSAVE;
845068f8a7eSTamas Berghammer         if (const_cast<NativeRegisterContextLinux_x86_64*>(this)->ReadFPR().Fail())
8462850b1beSTodd Fiala         {
8472850b1beSTodd Fiala             // Fall back to general floating point with no AVX support.
8482850b1beSTodd Fiala             m_fpr_type = eFPRTypeFXSAVE;
8492850b1beSTodd Fiala 
850*296e063dSAbhishek Aggarwal             // Check if FXSAVE area can be read.
851*296e063dSAbhishek Aggarwal             if (const_cast<NativeRegisterContextLinux_x86_64*>(this)->ReadFPR().Fail())
852*296e063dSAbhishek Aggarwal             {
853*296e063dSAbhishek Aggarwal                 if (log)
854*296e063dSAbhishek Aggarwal                     log->Printf("NativeRegisterContextLinux_x86_64::%s ptrace APIs failed to read XSAVE/FXSAVE area", __FUNCTION__);
855*296e063dSAbhishek Aggarwal             }
856*296e063dSAbhishek Aggarwal         }
857*296e063dSAbhishek Aggarwal     }
8582850b1beSTodd Fiala     return m_fpr_type;
8592850b1beSTodd Fiala }
8602850b1beSTodd Fiala 
8612850b1beSTodd Fiala bool
8622850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const
8632850b1beSTodd Fiala {
8642850b1beSTodd Fiala     return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr);
8652850b1beSTodd Fiala }
8662850b1beSTodd Fiala 
8672850b1beSTodd Fiala bool
8682850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, FPRType fpr_type) const
8692850b1beSTodd Fiala {
8702850b1beSTodd Fiala     bool generic_fpr = IsFPR(reg_index);
8712850b1beSTodd Fiala 
8722850b1beSTodd Fiala     if (fpr_type == eFPRTypeXSAVE)
8732850b1beSTodd Fiala         return generic_fpr || IsAVX(reg_index);
8742850b1beSTodd Fiala     return generic_fpr;
8752850b1beSTodd Fiala }
8762850b1beSTodd Fiala 
877068f8a7eSTamas Berghammer Error
8782850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteFPR()
8792850b1beSTodd Fiala {
880068f8a7eSTamas Berghammer     const FPRType fpr_type = GetFPRType ();
881*296e063dSAbhishek Aggarwal     const lldb_private::ArchSpec& target_arch = GetRegisterInfoInterface().GetTargetArchitecture();
882068f8a7eSTamas Berghammer     switch (fpr_type)
883068f8a7eSTamas Berghammer     {
884068f8a7eSTamas Berghammer     case FPRType::eFPRTypeFXSAVE:
885*296e063dSAbhishek Aggarwal         // For 32-bit inferiors on x86_32/x86_64 architectures,
886*296e063dSAbhishek Aggarwal         // FXSAVE area can be written using PTRACE_SETREGSET ptrace api
887*296e063dSAbhishek Aggarwal         // For 64-bit inferiors on x86_64 architectures,
888*296e063dSAbhishek Aggarwal         // FXSAVE area can be written using PTRACE_SETFPREGS ptrace api
889*296e063dSAbhishek Aggarwal         switch (target_arch.GetMachine ())
890*296e063dSAbhishek Aggarwal         {
891*296e063dSAbhishek Aggarwal             case llvm::Triple::x86:
892*296e063dSAbhishek Aggarwal                 return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_PRXFPREG);
893*296e063dSAbhishek Aggarwal             case llvm::Triple::x86_64:
894068f8a7eSTamas Berghammer                 return NativeRegisterContextLinux::WriteFPR();
895*296e063dSAbhishek Aggarwal             default:
896*296e063dSAbhishek Aggarwal                 assert(false && "Unhandled target architecture.");
897*296e063dSAbhishek Aggarwal                 break;
898*296e063dSAbhishek Aggarwal         }
899068f8a7eSTamas Berghammer     case FPRType::eFPRTypeXSAVE:
900068f8a7eSTamas Berghammer         return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
901068f8a7eSTamas Berghammer     default:
902068f8a7eSTamas Berghammer         return Error("Unrecognized FPR type");
903068f8a7eSTamas Berghammer     }
9042850b1beSTodd Fiala }
9052850b1beSTodd Fiala 
9062850b1beSTodd Fiala bool
9072850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const
9082850b1beSTodd Fiala {
9092850b1beSTodd Fiala     return (m_reg_info.first_ymm <= reg_index && reg_index <= m_reg_info.last_ymm);
9102850b1beSTodd Fiala }
9112850b1beSTodd Fiala 
9122850b1beSTodd Fiala bool
9132850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order)
9142850b1beSTodd Fiala {
9152850b1beSTodd Fiala     if (!IsAVX (reg_index))
9162850b1beSTodd Fiala         return false;
9172850b1beSTodd Fiala 
9182850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderLittle)
9192850b1beSTodd Fiala     {
9202850b1beSTodd Fiala         ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
9212850b1beSTodd Fiala                  m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
9222850b1beSTodd Fiala                  sizeof (XMMReg));
9232850b1beSTodd Fiala         ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
9242850b1beSTodd Fiala                  m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
9252850b1beSTodd Fiala                  sizeof (YMMHReg));
9262850b1beSTodd Fiala         return true;
9272850b1beSTodd Fiala     }
9282850b1beSTodd Fiala 
9292850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderBig)
9302850b1beSTodd Fiala     {
9312850b1beSTodd Fiala         ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
9322850b1beSTodd Fiala                  m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
9332850b1beSTodd Fiala                  sizeof (XMMReg));
9342850b1beSTodd Fiala         ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
9352850b1beSTodd Fiala                  m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
9362850b1beSTodd Fiala                  sizeof (YMMHReg));
9372850b1beSTodd Fiala         return true;
9382850b1beSTodd Fiala     }
9392850b1beSTodd Fiala     return false; // unsupported or invalid byte order
9402850b1beSTodd Fiala 
9412850b1beSTodd Fiala }
9422850b1beSTodd Fiala 
9432850b1beSTodd Fiala bool
9442850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
9452850b1beSTodd Fiala {
9462850b1beSTodd Fiala     if (!IsAVX(reg))
9472850b1beSTodd Fiala         return false;
9482850b1beSTodd Fiala 
9492850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderLittle)
9502850b1beSTodd Fiala     {
9512850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
9522850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
9532850b1beSTodd Fiala                  sizeof(XMMReg));
9542850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
9552850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
9562850b1beSTodd Fiala                  sizeof(YMMHReg));
9572850b1beSTodd Fiala         return true;
9582850b1beSTodd Fiala     }
9592850b1beSTodd Fiala 
9602850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderBig)
9612850b1beSTodd Fiala     {
9622850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
9632850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
9642850b1beSTodd Fiala                  sizeof(XMMReg));
9652850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
9662850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
9672850b1beSTodd Fiala                  sizeof(YMMHReg));
9682850b1beSTodd Fiala         return true;
9692850b1beSTodd Fiala     }
9702850b1beSTodd Fiala     return false; // unsupported or invalid byte order
9712850b1beSTodd Fiala }
9722850b1beSTodd Fiala 
973068f8a7eSTamas Berghammer void*
974068f8a7eSTamas Berghammer NativeRegisterContextLinux_x86_64::GetFPRBuffer()
9752850b1beSTodd Fiala {
9762850b1beSTodd Fiala     const FPRType fpr_type = GetFPRType ();
9772850b1beSTodd Fiala     switch (fpr_type)
9782850b1beSTodd Fiala     {
9792850b1beSTodd Fiala     case FPRType::eFPRTypeFXSAVE:
980068f8a7eSTamas Berghammer         return &m_fpr.xstate.fxsave;
9812850b1beSTodd Fiala     case FPRType::eFPRTypeXSAVE:
982068f8a7eSTamas Berghammer         return &m_iovec;
9832850b1beSTodd Fiala     default:
984068f8a7eSTamas Berghammer         return nullptr;
9852850b1beSTodd Fiala     }
9862850b1beSTodd Fiala }
9872850b1beSTodd Fiala 
988068f8a7eSTamas Berghammer size_t
989068f8a7eSTamas Berghammer NativeRegisterContextLinux_x86_64::GetFPRSize()
9902850b1beSTodd Fiala {
991068f8a7eSTamas Berghammer     const FPRType fpr_type = GetFPRType ();
992068f8a7eSTamas Berghammer     switch (fpr_type)
993068f8a7eSTamas Berghammer     {
994068f8a7eSTamas Berghammer     case FPRType::eFPRTypeFXSAVE:
995068f8a7eSTamas Berghammer         return sizeof(m_fpr.xstate.fxsave);
996068f8a7eSTamas Berghammer     case FPRType::eFPRTypeXSAVE:
997068f8a7eSTamas Berghammer         return sizeof(m_iovec);
998068f8a7eSTamas Berghammer     default:
999068f8a7eSTamas Berghammer         return 0;
1000068f8a7eSTamas Berghammer     }
10012850b1beSTodd Fiala }
10022850b1beSTodd Fiala 
1003068f8a7eSTamas Berghammer Error
1004068f8a7eSTamas Berghammer NativeRegisterContextLinux_x86_64::ReadFPR ()
10052850b1beSTodd Fiala {
1006068f8a7eSTamas Berghammer     const FPRType fpr_type = GetFPRType ();
1007*296e063dSAbhishek Aggarwal     const lldb_private::ArchSpec& target_arch = GetRegisterInfoInterface().GetTargetArchitecture();
1008068f8a7eSTamas Berghammer     switch (fpr_type)
1009068f8a7eSTamas Berghammer     {
1010068f8a7eSTamas Berghammer     case FPRType::eFPRTypeFXSAVE:
1011*296e063dSAbhishek Aggarwal         // For 32-bit inferiors on x86_32/x86_64 architectures,
1012*296e063dSAbhishek Aggarwal         // FXSAVE area can be read using PTRACE_GETREGSET ptrace api
1013*296e063dSAbhishek Aggarwal         // For 64-bit inferiors on x86_64 architectures,
1014*296e063dSAbhishek Aggarwal         // FXSAVE area can be read using PTRACE_GETFPREGS ptrace api
1015*296e063dSAbhishek Aggarwal         switch (target_arch.GetMachine ())
1016*296e063dSAbhishek Aggarwal         {
1017*296e063dSAbhishek Aggarwal             case llvm::Triple::x86:
1018*296e063dSAbhishek Aggarwal                 return ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_PRXFPREG);
1019*296e063dSAbhishek Aggarwal             case llvm::Triple::x86_64:
1020068f8a7eSTamas Berghammer                 return NativeRegisterContextLinux::ReadFPR();
1021*296e063dSAbhishek Aggarwal             default:
1022*296e063dSAbhishek Aggarwal                 assert(false && "Unhandled target architecture.");
1023*296e063dSAbhishek Aggarwal                 break;
1024*296e063dSAbhishek Aggarwal         }
1025068f8a7eSTamas Berghammer     case FPRType::eFPRTypeXSAVE:
1026068f8a7eSTamas Berghammer         return ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
1027068f8a7eSTamas Berghammer     default:
1028068f8a7eSTamas Berghammer         return Error("Unrecognized FPR type");
1029068f8a7eSTamas Berghammer     }
10302850b1beSTodd Fiala }
10312850b1beSTodd Fiala 
103218fe6404SChaoren Lin Error
1033c16f5dcaSChaoren Lin NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint32_t wp_index, bool &is_hit)
103418fe6404SChaoren Lin {
103518fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
103618fe6404SChaoren Lin         return Error("Watchpoint index out of range");
103718fe6404SChaoren Lin 
103818fe6404SChaoren Lin     RegisterValue reg_value;
10396a504f6eSChaoren Lin     Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
1040c16f5dcaSChaoren Lin     if (error.Fail())
1041c16f5dcaSChaoren Lin     {
1042c16f5dcaSChaoren Lin         is_hit = false;
1043c16f5dcaSChaoren Lin         return error;
1044c16f5dcaSChaoren Lin     }
104518fe6404SChaoren Lin 
104618fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64();
104718fe6404SChaoren Lin 
1048c16f5dcaSChaoren Lin     is_hit = status_bits & (1 << wp_index);
104918fe6404SChaoren Lin 
105018fe6404SChaoren Lin     return error;
105118fe6404SChaoren Lin }
105218fe6404SChaoren Lin 
105318fe6404SChaoren Lin Error
1054ea8c25a8SOmair Javaid NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) {
1055c16f5dcaSChaoren Lin     uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
1056c16f5dcaSChaoren Lin     for (wp_index = 0; wp_index < num_hw_wps; ++wp_index)
1057c16f5dcaSChaoren Lin     {
1058c16f5dcaSChaoren Lin         bool is_hit;
1059c16f5dcaSChaoren Lin         Error error = IsWatchpointHit(wp_index, is_hit);
1060c16f5dcaSChaoren Lin         if (error.Fail()) {
1061c16f5dcaSChaoren Lin             wp_index = LLDB_INVALID_INDEX32;
1062c16f5dcaSChaoren Lin             return error;
1063c16f5dcaSChaoren Lin         } else if (is_hit) {
1064c16f5dcaSChaoren Lin             return error;
1065c16f5dcaSChaoren Lin         }
1066c16f5dcaSChaoren Lin     }
1067c16f5dcaSChaoren Lin     wp_index = LLDB_INVALID_INDEX32;
1068c16f5dcaSChaoren Lin     return Error();
1069c16f5dcaSChaoren Lin }
1070c16f5dcaSChaoren Lin 
1071c16f5dcaSChaoren Lin Error
1072c16f5dcaSChaoren Lin NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index, bool &is_vacant)
107318fe6404SChaoren Lin {
107418fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
107518fe6404SChaoren Lin         return Error ("Watchpoint index out of range");
107618fe6404SChaoren Lin 
107718fe6404SChaoren Lin     RegisterValue reg_value;
10786a504f6eSChaoren Lin     Error error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
1079c16f5dcaSChaoren Lin     if (error.Fail())
1080c16f5dcaSChaoren Lin     {
1081c16f5dcaSChaoren Lin         is_vacant = false;
1082c16f5dcaSChaoren Lin         return error;
1083c16f5dcaSChaoren Lin     }
108418fe6404SChaoren Lin 
108518fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64();
108618fe6404SChaoren Lin 
1087c16f5dcaSChaoren Lin     is_vacant = !(control_bits & (1 << (2 * wp_index)));
108818fe6404SChaoren Lin 
108918fe6404SChaoren Lin     return error;
109018fe6404SChaoren Lin }
109118fe6404SChaoren Lin 
109218fe6404SChaoren Lin Error
109318fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex(
109418fe6404SChaoren Lin         lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
109518fe6404SChaoren Lin 
109618fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
109718fe6404SChaoren Lin         return Error ("Watchpoint index out of range");
109818fe6404SChaoren Lin 
109940caea63STamas Berghammer     // Read only watchpoints aren't supported on x86_64. Fall back to read/write waitchpoints instead.
110040caea63STamas Berghammer     // TODO: Add logic to detect when a write happens and ignore that watchpoint hit.
1101cf8eb9daSOmair Javaid     if (watch_flags == 0x2)
110240caea63STamas Berghammer         watch_flags = 0x3;
1103cf8eb9daSOmair Javaid 
110418fe6404SChaoren Lin     if (watch_flags != 0x1 && watch_flags != 0x3)
110518fe6404SChaoren Lin         return Error ("Invalid read/write bits for watchpoint");
110618fe6404SChaoren Lin 
110718fe6404SChaoren Lin     if (size != 1 && size != 2 && size != 4 && size != 8)
110818fe6404SChaoren Lin         return Error ("Invalid size for watchpoint");
110918fe6404SChaoren Lin 
1110c16f5dcaSChaoren Lin     bool is_vacant;
1111c16f5dcaSChaoren Lin     Error error = IsWatchpointVacant (wp_index, is_vacant);
111218fe6404SChaoren Lin     if (error.Fail()) return error;
1113c16f5dcaSChaoren Lin     if (!is_vacant) return Error("Watchpoint index not vacant");
111418fe6404SChaoren Lin 
111518fe6404SChaoren Lin     RegisterValue reg_value;
11166a504f6eSChaoren Lin     error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
111718fe6404SChaoren Lin     if (error.Fail()) return error;
111818fe6404SChaoren Lin 
111918fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
112018fe6404SChaoren Lin     // set bits 1, 3, 5, or 7
112118fe6404SChaoren Lin     uint64_t enable_bit = 1 << (2 * wp_index);
112218fe6404SChaoren Lin 
112318fe6404SChaoren Lin     // set bits 16-17, 20-21, 24-25, or 28-29
112418fe6404SChaoren Lin     // with 0b01 for write, and 0b11 for read/write
112518fe6404SChaoren Lin     uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
112618fe6404SChaoren Lin 
112718fe6404SChaoren Lin     // set bits 18-19, 22-23, 26-27, or 30-31
112818fe6404SChaoren Lin     // with 0b00, 0b01, 0b10, or 0b11
112918fe6404SChaoren Lin     // for 1, 2, 8 (if supported), or 4 bytes, respectively
113018fe6404SChaoren Lin     uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
113118fe6404SChaoren Lin 
113218fe6404SChaoren Lin     uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
113318fe6404SChaoren Lin 
113418fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
113518fe6404SChaoren Lin 
113618fe6404SChaoren Lin     control_bits |= enable_bit | rw_bits | size_bits;
113718fe6404SChaoren Lin 
1138068f8a7eSTamas Berghammer     error = WriteRegisterRaw(m_reg_info.first_dr + wp_index, RegisterValue(addr));
113918fe6404SChaoren Lin     if (error.Fail()) return error;
114018fe6404SChaoren Lin 
1141068f8a7eSTamas Berghammer     error = WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
114218fe6404SChaoren Lin     if (error.Fail()) return error;
114318fe6404SChaoren Lin 
114418fe6404SChaoren Lin     error.Clear();
114518fe6404SChaoren Lin     return error;
114618fe6404SChaoren Lin }
114718fe6404SChaoren Lin 
114818fe6404SChaoren Lin bool
114918fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(uint32_t wp_index)
115018fe6404SChaoren Lin {
115118fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
115218fe6404SChaoren Lin         return false;
115318fe6404SChaoren Lin 
115418fe6404SChaoren Lin     RegisterValue reg_value;
115518fe6404SChaoren Lin 
115618fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
115718fe6404SChaoren Lin     // clear bits 0, 1, 2, or 3 of the debug status register (DR6)
11586a504f6eSChaoren Lin     Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
115918fe6404SChaoren Lin     if (error.Fail()) return false;
116018fe6404SChaoren Lin     uint64_t bit_mask = 1 << wp_index;
116118fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
1162068f8a7eSTamas Berghammer     error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
116318fe6404SChaoren Lin     if (error.Fail()) return false;
116418fe6404SChaoren Lin 
116518fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
116618fe6404SChaoren Lin     // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
116718fe6404SChaoren Lin     // of the debug control register (DR7)
11686a504f6eSChaoren Lin     error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
116918fe6404SChaoren Lin     if (error.Fail()) return false;
117018fe6404SChaoren Lin     bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
117118fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1172068f8a7eSTamas Berghammer     return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)).Success();
117318fe6404SChaoren Lin }
117418fe6404SChaoren Lin 
117518fe6404SChaoren Lin Error
117618fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints()
117718fe6404SChaoren Lin {
117818fe6404SChaoren Lin     RegisterValue reg_value;
117918fe6404SChaoren Lin 
118018fe6404SChaoren Lin     // clear bits {0-4} of the debug status register (DR6)
11816a504f6eSChaoren Lin     Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
118218fe6404SChaoren Lin     if (error.Fail()) return error;
118318fe6404SChaoren Lin     uint64_t bit_mask = 0xF;
118418fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
1185068f8a7eSTamas Berghammer     error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
118618fe6404SChaoren Lin     if (error.Fail()) return error;
118718fe6404SChaoren Lin 
118818fe6404SChaoren Lin     // clear bits {0-7,16-31} of the debug control register (DR7)
11896a504f6eSChaoren Lin     error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
119018fe6404SChaoren Lin     if (error.Fail()) return error;
119118fe6404SChaoren Lin     bit_mask = 0xFF | (0xFFFF << 16);
119218fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1193068f8a7eSTamas Berghammer     return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
119418fe6404SChaoren Lin }
119518fe6404SChaoren Lin 
119618fe6404SChaoren Lin uint32_t
119718fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint(
119818fe6404SChaoren Lin         lldb::addr_t addr, size_t size, uint32_t watch_flags)
119918fe6404SChaoren Lin {
1200c16f5dcaSChaoren Lin     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
120118fe6404SChaoren Lin     const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
120218fe6404SChaoren Lin     for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index)
120318fe6404SChaoren Lin     {
1204c16f5dcaSChaoren Lin         bool is_vacant;
1205c16f5dcaSChaoren Lin         Error error = IsWatchpointVacant(wp_index, is_vacant);
1206c16f5dcaSChaoren Lin         if (is_vacant)
1207c16f5dcaSChaoren Lin         {
1208c16f5dcaSChaoren Lin             error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
1209c16f5dcaSChaoren Lin             if (error.Success())
121018fe6404SChaoren Lin                 return wp_index;
121118fe6404SChaoren Lin         }
1212c16f5dcaSChaoren Lin         if (error.Fail() && log)
1213c16f5dcaSChaoren Lin         {
1214c16f5dcaSChaoren Lin             log->Printf("NativeRegisterContextLinux_x86_64::%s Error: %s",
1215c16f5dcaSChaoren Lin                     __FUNCTION__, error.AsCString());
1216c16f5dcaSChaoren Lin         }
1217c16f5dcaSChaoren Lin     }
121818fe6404SChaoren Lin     return LLDB_INVALID_INDEX32;
121918fe6404SChaoren Lin }
122018fe6404SChaoren Lin 
122118fe6404SChaoren Lin lldb::addr_t
122218fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index)
122318fe6404SChaoren Lin {
122418fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
122518fe6404SChaoren Lin         return LLDB_INVALID_ADDRESS;
122618fe6404SChaoren Lin     RegisterValue reg_value;
122718fe6404SChaoren Lin     if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail())
122818fe6404SChaoren Lin         return LLDB_INVALID_ADDRESS;
122918fe6404SChaoren Lin     return reg_value.GetAsUInt64();
123018fe6404SChaoren Lin }
123118fe6404SChaoren Lin 
123218fe6404SChaoren Lin uint32_t
123318fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints ()
123418fe6404SChaoren Lin {
123518fe6404SChaoren Lin     // Available debug address registers: dr0, dr1, dr2, dr3
123618fe6404SChaoren Lin     return 4;
123718fe6404SChaoren Lin }
1238068f8a7eSTamas Berghammer 
1239068f8a7eSTamas Berghammer #endif // defined(__i386__) || defined(__x86_64__)
1240