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
3302850b1beSTodd Fiala 
331068f8a7eSTamas Berghammer NativeRegisterContextLinux*
332068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
333068f8a7eSTamas Berghammer                                                                  NativeThreadProtocol &native_thread,
334068f8a7eSTamas Berghammer                                                                  uint32_t concrete_frame_idx)
335068f8a7eSTamas Berghammer {
336068f8a7eSTamas Berghammer     return new NativeRegisterContextLinux_x86_64(target_arch, native_thread, concrete_frame_idx);
337068f8a7eSTamas Berghammer }
338068f8a7eSTamas Berghammer 
3392850b1beSTodd Fiala // ----------------------------------------------------------------------------
3402850b1beSTodd Fiala // NativeRegisterContextLinux_x86_64 members.
3412850b1beSTodd Fiala // ----------------------------------------------------------------------------
3422850b1beSTodd Fiala 
343068f8a7eSTamas Berghammer static RegisterInfoInterface*
344068f8a7eSTamas Berghammer CreateRegisterInfoInterface(const ArchSpec& target_arch)
345068f8a7eSTamas Berghammer {
346068f8a7eSTamas Berghammer     if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
347068f8a7eSTamas Berghammer     {
348068f8a7eSTamas Berghammer         // 32-bit hosts run with a RegisterContextLinux_i386 context.
349068f8a7eSTamas Berghammer         return new RegisterContextLinux_i386(target_arch);
350068f8a7eSTamas Berghammer     }
351068f8a7eSTamas Berghammer     else
352068f8a7eSTamas Berghammer     {
353068f8a7eSTamas Berghammer         assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
354068f8a7eSTamas Berghammer                "Register setting path assumes this is a 64-bit host");
355068f8a7eSTamas Berghammer         // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
356068f8a7eSTamas Berghammer         return new RegisterContextLinux_x86_64 (target_arch);
357068f8a7eSTamas Berghammer     }
358068f8a7eSTamas Berghammer }
359068f8a7eSTamas Berghammer 
360068f8a7eSTamas Berghammer NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const ArchSpec& target_arch,
361068f8a7eSTamas Berghammer                                                                       NativeThreadProtocol &native_thread,
362068f8a7eSTamas Berghammer                                                                       uint32_t concrete_frame_idx) :
363068f8a7eSTamas Berghammer     NativeRegisterContextLinux (native_thread, concrete_frame_idx, CreateRegisterInfoInterface(target_arch)),
3642850b1beSTodd Fiala     m_fpr_type (eFPRTypeNotValid),
3652850b1beSTodd Fiala     m_fpr (),
3662850b1beSTodd Fiala     m_iovec (),
3672850b1beSTodd Fiala     m_ymm_set (),
3682850b1beSTodd Fiala     m_reg_info (),
3692850b1beSTodd Fiala     m_gpr_x86_64 ()
3702850b1beSTodd Fiala {
3712850b1beSTodd Fiala     // Set up data about ranges of valid registers.
372068f8a7eSTamas Berghammer     switch (target_arch.GetMachine ())
3732850b1beSTodd Fiala     {
3742850b1beSTodd Fiala         case llvm::Triple::x86:
3752850b1beSTodd Fiala             m_reg_info.num_registers        = k_num_registers_i386;
3762850b1beSTodd Fiala             m_reg_info.num_gpr_registers    = k_num_gpr_registers_i386;
3772850b1beSTodd Fiala             m_reg_info.num_fpr_registers    = k_num_fpr_registers_i386;
3782850b1beSTodd Fiala             m_reg_info.num_avx_registers    = k_num_avx_registers_i386;
3792850b1beSTodd Fiala             m_reg_info.last_gpr             = k_last_gpr_i386;
3802850b1beSTodd Fiala             m_reg_info.first_fpr            = k_first_fpr_i386;
3812850b1beSTodd Fiala             m_reg_info.last_fpr             = k_last_fpr_i386;
3827f013bcdSZachary Turner             m_reg_info.first_st             = lldb_st0_i386;
3837f013bcdSZachary Turner             m_reg_info.last_st              = lldb_st7_i386;
3847f013bcdSZachary Turner             m_reg_info.first_mm             = lldb_mm0_i386;
3857f013bcdSZachary Turner             m_reg_info.last_mm              = lldb_mm7_i386;
3867f013bcdSZachary Turner             m_reg_info.first_xmm            = lldb_xmm0_i386;
3877f013bcdSZachary Turner             m_reg_info.last_xmm             = lldb_xmm7_i386;
3887f013bcdSZachary Turner             m_reg_info.first_ymm            = lldb_ymm0_i386;
3897f013bcdSZachary Turner             m_reg_info.last_ymm             = lldb_ymm7_i386;
3907f013bcdSZachary Turner             m_reg_info.first_dr             = lldb_dr0_i386;
3917f013bcdSZachary Turner             m_reg_info.gpr_flags            = lldb_eflags_i386;
3922850b1beSTodd Fiala             break;
3932850b1beSTodd Fiala         case llvm::Triple::x86_64:
3942850b1beSTodd Fiala             m_reg_info.num_registers        = k_num_registers_x86_64;
3952850b1beSTodd Fiala             m_reg_info.num_gpr_registers    = k_num_gpr_registers_x86_64;
3962850b1beSTodd Fiala             m_reg_info.num_fpr_registers    = k_num_fpr_registers_x86_64;
3972850b1beSTodd Fiala             m_reg_info.num_avx_registers    = k_num_avx_registers_x86_64;
3982850b1beSTodd Fiala             m_reg_info.last_gpr             = k_last_gpr_x86_64;
3992850b1beSTodd Fiala             m_reg_info.first_fpr            = k_first_fpr_x86_64;
4002850b1beSTodd Fiala             m_reg_info.last_fpr             = k_last_fpr_x86_64;
4017f013bcdSZachary Turner             m_reg_info.first_st             = lldb_st0_x86_64;
4027f013bcdSZachary Turner             m_reg_info.last_st              = lldb_st7_x86_64;
4037f013bcdSZachary Turner             m_reg_info.first_mm             = lldb_mm0_x86_64;
4047f013bcdSZachary Turner             m_reg_info.last_mm              = lldb_mm7_x86_64;
4057f013bcdSZachary Turner             m_reg_info.first_xmm            = lldb_xmm0_x86_64;
4067f013bcdSZachary Turner             m_reg_info.last_xmm             = lldb_xmm15_x86_64;
4077f013bcdSZachary Turner             m_reg_info.first_ymm            = lldb_ymm0_x86_64;
4087f013bcdSZachary Turner             m_reg_info.last_ymm             = lldb_ymm15_x86_64;
4097f013bcdSZachary Turner             m_reg_info.first_dr             = lldb_dr0_x86_64;
4107f013bcdSZachary Turner             m_reg_info.gpr_flags            = lldb_rflags_x86_64;
4112850b1beSTodd Fiala             break;
4122850b1beSTodd Fiala         default:
4132850b1beSTodd Fiala             assert(false && "Unhandled target architecture.");
4142850b1beSTodd Fiala             break;
4152850b1beSTodd Fiala     }
4162850b1beSTodd Fiala 
4172850b1beSTodd Fiala     // Initialize m_iovec to point to the buffer and buffer size
4182850b1beSTodd Fiala     // using the conventions of Berkeley style UIO structures, as required
4192850b1beSTodd Fiala     // by PTRACE extensions.
4202850b1beSTodd Fiala     m_iovec.iov_base = &m_fpr.xstate.xsave;
4212850b1beSTodd Fiala     m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
4222850b1beSTodd Fiala 
4232850b1beSTodd Fiala     // Clear out the FPR state.
4242850b1beSTodd Fiala     ::memset(&m_fpr, 0, sizeof(FPR));
4252850b1beSTodd Fiala }
4262850b1beSTodd Fiala 
4272850b1beSTodd Fiala // CONSIDER after local and llgs debugging are merged, register set support can
4282850b1beSTodd Fiala // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
4292850b1beSTodd Fiala uint32_t
4302850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetRegisterSetCount () const
4312850b1beSTodd Fiala {
4322850b1beSTodd Fiala     uint32_t sets = 0;
4332850b1beSTodd Fiala     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
4342850b1beSTodd Fiala     {
4352850b1beSTodd Fiala         if (IsRegisterSetAvailable (set_index))
4362850b1beSTodd Fiala             ++sets;
4372850b1beSTodd Fiala     }
4382850b1beSTodd Fiala 
4392850b1beSTodd Fiala     return sets;
4402850b1beSTodd Fiala }
4412850b1beSTodd Fiala 
4428fa23b8eSTamas Berghammer uint32_t
4438fa23b8eSTamas Berghammer NativeRegisterContextLinux_x86_64::GetUserRegisterCount() const
4448fa23b8eSTamas Berghammer {
4458fa23b8eSTamas Berghammer     uint32_t count = 0;
4468fa23b8eSTamas Berghammer     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
4478fa23b8eSTamas Berghammer     {
448db264a6dSTamas Berghammer         const RegisterSet* set = GetRegisterSet(set_index);
4498fa23b8eSTamas Berghammer         if (set)
4508fa23b8eSTamas Berghammer             count += set->num_registers;
4518fa23b8eSTamas Berghammer     }
4528fa23b8eSTamas Berghammer     return count;
4538fa23b8eSTamas Berghammer }
4548fa23b8eSTamas Berghammer 
455db264a6dSTamas Berghammer const RegisterSet *
4562850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetRegisterSet (uint32_t set_index) const
4572850b1beSTodd Fiala {
4582850b1beSTodd Fiala     if (!IsRegisterSetAvailable (set_index))
4592850b1beSTodd Fiala         return nullptr;
4602850b1beSTodd Fiala 
4612850b1beSTodd Fiala     switch (GetRegisterInfoInterface ().GetTargetArchitecture ().GetMachine ())
4622850b1beSTodd Fiala     {
4632850b1beSTodd Fiala         case llvm::Triple::x86:
4642850b1beSTodd Fiala             return &g_reg_sets_i386[set_index];
4652850b1beSTodd Fiala         case llvm::Triple::x86_64:
4662850b1beSTodd Fiala             return &g_reg_sets_x86_64[set_index];
4672850b1beSTodd Fiala         default:
4682850b1beSTodd Fiala             assert (false && "Unhandled target architecture.");
4692850b1beSTodd Fiala             return nullptr;
4702850b1beSTodd Fiala     }
4712850b1beSTodd Fiala 
4722850b1beSTodd Fiala     return nullptr;
4732850b1beSTodd Fiala }
4742850b1beSTodd Fiala 
475db264a6dSTamas Berghammer Error
4762850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
4772850b1beSTodd Fiala {
4782850b1beSTodd Fiala     Error error;
4792850b1beSTodd Fiala 
4802850b1beSTodd Fiala     if (!reg_info)
4812850b1beSTodd Fiala     {
4822850b1beSTodd Fiala         error.SetErrorString ("reg_info NULL");
4832850b1beSTodd Fiala         return error;
4842850b1beSTodd Fiala     }
4852850b1beSTodd Fiala 
4862850b1beSTodd Fiala     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
4872850b1beSTodd Fiala     if (reg == LLDB_INVALID_REGNUM)
4882850b1beSTodd Fiala     {
4892850b1beSTodd Fiala         // This is likely an internal register for lldb use only and should not be directly queried.
4902850b1beSTodd Fiala         error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name);
4912850b1beSTodd Fiala         return error;
4922850b1beSTodd Fiala     }
4932850b1beSTodd Fiala 
4942850b1beSTodd Fiala     if (IsFPR(reg, GetFPRType()))
4952850b1beSTodd Fiala     {
496068f8a7eSTamas Berghammer         error = ReadFPR();
497068f8a7eSTamas Berghammer         if (error.Fail())
4982850b1beSTodd Fiala             return error;
4992850b1beSTodd Fiala     }
5002850b1beSTodd Fiala     else
5012850b1beSTodd Fiala     {
5022850b1beSTodd Fiala         uint32_t full_reg = reg;
5032850b1beSTodd Fiala         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
5042850b1beSTodd Fiala 
5052850b1beSTodd Fiala         if (is_subreg)
5062850b1beSTodd Fiala         {
5072850b1beSTodd Fiala             // Read the full aligned 64-bit register.
5082850b1beSTodd Fiala             full_reg = reg_info->invalidate_regs[0];
5092850b1beSTodd Fiala         }
5102850b1beSTodd Fiala 
5112850b1beSTodd Fiala         error = ReadRegisterRaw(full_reg, reg_value);
5122850b1beSTodd Fiala 
5132850b1beSTodd Fiala         if (error.Success ())
5142850b1beSTodd Fiala         {
5152850b1beSTodd Fiala             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
5162850b1beSTodd Fiala             if (is_subreg && (reg_info->byte_offset & 0x1))
5172850b1beSTodd Fiala                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
5182850b1beSTodd Fiala 
5192850b1beSTodd Fiala             // If our return byte size was greater than the return value reg size, then
5202850b1beSTodd Fiala             // use the type specified by reg_info rather than the uint64_t default
5212850b1beSTodd Fiala             if (reg_value.GetByteSize() > reg_info->byte_size)
5222850b1beSTodd Fiala                 reg_value.SetType(reg_info);
5232850b1beSTodd Fiala         }
5242850b1beSTodd Fiala         return error;
5252850b1beSTodd Fiala     }
5262850b1beSTodd Fiala 
5272850b1beSTodd Fiala     if (reg_info->encoding == lldb::eEncodingVector)
5282850b1beSTodd Fiala     {
5292850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder();
5302850b1beSTodd Fiala 
5312850b1beSTodd Fiala         if (byte_order != lldb::eByteOrderInvalid)
5322850b1beSTodd Fiala         {
5332850b1beSTodd Fiala             if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
5342850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order);
5352850b1beSTodd Fiala             if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
5362850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order);
5372850b1beSTodd Fiala             if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
5382850b1beSTodd Fiala                 reg_value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order);
5392850b1beSTodd Fiala             if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
5402850b1beSTodd Fiala             {
5412850b1beSTodd Fiala                 // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
5422850b1beSTodd Fiala                 if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoYMM(reg, byte_order))
5432850b1beSTodd Fiala                     reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order);
5442850b1beSTodd Fiala                 else
5452850b1beSTodd Fiala                 {
5462850b1beSTodd Fiala                     error.SetErrorString ("failed to copy ymm register value");
5472850b1beSTodd Fiala                     return error;
5482850b1beSTodd Fiala                 }
5492850b1beSTodd Fiala             }
5502850b1beSTodd Fiala 
5512850b1beSTodd Fiala             if (reg_value.GetType() != RegisterValue::eTypeBytes)
5522850b1beSTodd Fiala                 error.SetErrorString ("write failed - type was expected to be RegisterValue::eTypeBytes");
5532850b1beSTodd Fiala 
5542850b1beSTodd Fiala             return error;
5552850b1beSTodd Fiala         }
5562850b1beSTodd Fiala 
5572850b1beSTodd Fiala         error.SetErrorString ("byte order is invalid");
5582850b1beSTodd Fiala         return error;
5592850b1beSTodd Fiala     }
5602850b1beSTodd Fiala 
5612850b1beSTodd Fiala     // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
5622850b1beSTodd Fiala     assert (reg_info->byte_offset < sizeof(m_fpr));
5632850b1beSTodd Fiala     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
5642850b1beSTodd Fiala     switch (reg_info->byte_size)
5652850b1beSTodd Fiala     {
5662850b1beSTodd Fiala         case 2:
5672850b1beSTodd Fiala             reg_value.SetUInt16(*(uint16_t *)src);
5682850b1beSTodd Fiala             break;
5692850b1beSTodd Fiala         case 4:
5702850b1beSTodd Fiala             reg_value.SetUInt32(*(uint32_t *)src);
5712850b1beSTodd Fiala             break;
5722850b1beSTodd Fiala         case 8:
5732850b1beSTodd Fiala             reg_value.SetUInt64(*(uint64_t *)src);
5742850b1beSTodd Fiala             break;
5752850b1beSTodd Fiala         default:
5762850b1beSTodd Fiala             assert(false && "Unhandled data size.");
5772850b1beSTodd Fiala             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
5782850b1beSTodd Fiala             break;
5792850b1beSTodd Fiala     }
5802850b1beSTodd Fiala 
5812850b1beSTodd Fiala     return error;
5822850b1beSTodd Fiala }
5832850b1beSTodd Fiala 
584db264a6dSTamas Berghammer Error
5852850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
5862850b1beSTodd Fiala {
5872850b1beSTodd Fiala     assert (reg_info && "reg_info is null");
5882850b1beSTodd Fiala 
5892850b1beSTodd Fiala     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
5902850b1beSTodd Fiala     if (reg_index == LLDB_INVALID_REGNUM)
5912850b1beSTodd Fiala         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
5922850b1beSTodd Fiala 
5932850b1beSTodd Fiala     if (IsGPR(reg_index))
594068f8a7eSTamas Berghammer         return WriteRegisterRaw(reg_index, reg_value);
5952850b1beSTodd Fiala 
5962850b1beSTodd Fiala     if (IsFPR(reg_index, GetFPRType()))
5972850b1beSTodd Fiala     {
5982850b1beSTodd Fiala         if (reg_info->encoding == lldb::eEncodingVector)
5992850b1beSTodd Fiala         {
6002850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
6012850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_st].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6022850b1beSTodd Fiala 
6032850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm)
6042850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6052850b1beSTodd Fiala 
6062850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm)
6072850b1beSTodd Fiala                 ::memcpy (m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6082850b1beSTodd Fiala 
6092850b1beSTodd Fiala             if (reg_index >= m_reg_info.first_ymm && reg_index <= m_reg_info.last_ymm)
6102850b1beSTodd Fiala             {
6112850b1beSTodd Fiala                 if (GetFPRType() != eFPRTypeXSAVE)
6122850b1beSTodd Fiala                     return Error ("target processor does not support AVX");
6132850b1beSTodd Fiala 
6142850b1beSTodd Fiala                 // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
6152850b1beSTodd Fiala                 ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
6162850b1beSTodd Fiala                 if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
6172850b1beSTodd Fiala                     return Error ("CopyYMMtoXSTATE() failed");
6182850b1beSTodd Fiala             }
6192850b1beSTodd Fiala         }
6202850b1beSTodd Fiala         else
6212850b1beSTodd Fiala         {
6222850b1beSTodd Fiala             // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
6232850b1beSTodd Fiala             assert (reg_info->byte_offset < sizeof(m_fpr));
6242850b1beSTodd Fiala             uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
6252850b1beSTodd Fiala             switch (reg_info->byte_size)
6262850b1beSTodd Fiala             {
6272850b1beSTodd Fiala                 case 2:
6282850b1beSTodd Fiala                     *(uint16_t *)dst = reg_value.GetAsUInt16();
6292850b1beSTodd Fiala                     break;
6302850b1beSTodd Fiala                 case 4:
6312850b1beSTodd Fiala                     *(uint32_t *)dst = reg_value.GetAsUInt32();
6322850b1beSTodd Fiala                     break;
6332850b1beSTodd Fiala                 case 8:
6342850b1beSTodd Fiala                     *(uint64_t *)dst = reg_value.GetAsUInt64();
6352850b1beSTodd Fiala                     break;
6362850b1beSTodd Fiala                 default:
6372850b1beSTodd Fiala                     assert(false && "Unhandled data size.");
6382850b1beSTodd Fiala                     return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
6392850b1beSTodd Fiala             }
6402850b1beSTodd Fiala         }
6412850b1beSTodd Fiala 
642068f8a7eSTamas Berghammer         Error error = WriteFPR();
643068f8a7eSTamas Berghammer         if (error.Fail())
644068f8a7eSTamas Berghammer             return error;
645068f8a7eSTamas Berghammer 
6462850b1beSTodd Fiala         if (IsAVX(reg_index))
6472850b1beSTodd Fiala         {
6482850b1beSTodd Fiala             if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
6492850b1beSTodd Fiala                 return Error ("CopyYMMtoXSTATE() failed");
6502850b1beSTodd Fiala         }
6512850b1beSTodd Fiala         return Error ();
6522850b1beSTodd Fiala     }
6532850b1beSTodd Fiala     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
6542850b1beSTodd Fiala }
6552850b1beSTodd Fiala 
656db264a6dSTamas Berghammer Error
6572850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
6582850b1beSTodd Fiala {
6592850b1beSTodd Fiala     Error error;
6602850b1beSTodd Fiala 
6612850b1beSTodd Fiala     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
6622850b1beSTodd Fiala     if (!data_sp)
6632850b1beSTodd Fiala     {
6642850b1beSTodd Fiala         error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
6652850b1beSTodd Fiala         return error;
6662850b1beSTodd Fiala     }
6672850b1beSTodd Fiala 
668068f8a7eSTamas Berghammer     error = ReadGPR();
669068f8a7eSTamas Berghammer     if (error.Fail())
6702850b1beSTodd Fiala         return error;
6712850b1beSTodd Fiala 
672068f8a7eSTamas Berghammer     error = ReadFPR();
673068f8a7eSTamas Berghammer     if (error.Fail())
6742850b1beSTodd Fiala         return error;
6752850b1beSTodd Fiala 
6762850b1beSTodd Fiala     uint8_t *dst = data_sp->GetBytes ();
6772850b1beSTodd Fiala     if (dst == nullptr)
6782850b1beSTodd Fiala     {
6792850b1beSTodd Fiala         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
6802850b1beSTodd Fiala         return error;
6812850b1beSTodd Fiala     }
6822850b1beSTodd Fiala 
6832850b1beSTodd Fiala     ::memcpy (dst, &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
6842850b1beSTodd Fiala     dst += GetRegisterInfoInterface ().GetGPRSize ();
6852850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeFXSAVE)
6862850b1beSTodd Fiala         ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
6872850b1beSTodd Fiala     else if (GetFPRType () == eFPRTypeXSAVE)
6882850b1beSTodd Fiala     {
6892850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder ();
6902850b1beSTodd Fiala 
6912850b1beSTodd Fiala         // Assemble the YMM register content from the register halves.
6922850b1beSTodd Fiala         for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
6932850b1beSTodd Fiala         {
6942850b1beSTodd Fiala             if (!CopyXSTATEtoYMM (reg, byte_order))
6952850b1beSTodd Fiala             {
6962850b1beSTodd Fiala                 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyXSTATEtoYMM() failed for reg num %" PRIu32, __FUNCTION__, reg);
6972850b1beSTodd Fiala                 return error;
6982850b1beSTodd Fiala             }
6992850b1beSTodd Fiala         }
7002850b1beSTodd Fiala 
7012850b1beSTodd Fiala         // Copy the extended register state including the assembled ymm registers.
7022850b1beSTodd Fiala         ::memcpy (dst, &m_fpr, sizeof (m_fpr));
7032850b1beSTodd Fiala     }
7042850b1beSTodd Fiala     else
7052850b1beSTodd Fiala     {
7062850b1beSTodd Fiala         assert (false && "how do we save the floating point registers?");
7072850b1beSTodd Fiala         error.SetErrorString ("unsure how to save the floating point registers");
7082850b1beSTodd Fiala     }
7092850b1beSTodd Fiala 
7102850b1beSTodd Fiala     return error;
7112850b1beSTodd Fiala }
7122850b1beSTodd Fiala 
713db264a6dSTamas Berghammer Error
7142850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
7152850b1beSTodd Fiala {
7162850b1beSTodd Fiala     Error error;
7172850b1beSTodd Fiala 
7182850b1beSTodd Fiala     if (!data_sp)
7192850b1beSTodd Fiala     {
7202850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
7212850b1beSTodd Fiala         return error;
7222850b1beSTodd Fiala     }
7232850b1beSTodd Fiala 
7242850b1beSTodd Fiala     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
7252850b1beSTodd Fiala     {
7262850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
7272850b1beSTodd Fiala         return error;
7282850b1beSTodd Fiala     }
7292850b1beSTodd Fiala 
7302850b1beSTodd Fiala 
7312850b1beSTodd Fiala     uint8_t *src = data_sp->GetBytes ();
7322850b1beSTodd Fiala     if (src == nullptr)
7332850b1beSTodd Fiala     {
7342850b1beSTodd Fiala         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
7352850b1beSTodd Fiala         return error;
7362850b1beSTodd Fiala     }
7372850b1beSTodd Fiala     ::memcpy (&m_gpr_x86_64, src, GetRegisterInfoInterface ().GetGPRSize ());
7382850b1beSTodd Fiala 
739068f8a7eSTamas Berghammer     error = WriteGPR();
740068f8a7eSTamas Berghammer     if (error.Fail())
7412850b1beSTodd Fiala         return error;
7422850b1beSTodd Fiala 
7432850b1beSTodd Fiala     src += GetRegisterInfoInterface ().GetGPRSize ();
7442850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeFXSAVE)
7452850b1beSTodd Fiala         ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
7462850b1beSTodd Fiala     else if (GetFPRType () == eFPRTypeXSAVE)
7472850b1beSTodd Fiala         ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
7482850b1beSTodd Fiala 
749068f8a7eSTamas Berghammer     error = WriteFPR();
750068f8a7eSTamas Berghammer     if (error.Fail())
7512850b1beSTodd Fiala         return error;
7522850b1beSTodd Fiala 
7532850b1beSTodd Fiala     if (GetFPRType() == eFPRTypeXSAVE)
7542850b1beSTodd Fiala     {
7552850b1beSTodd Fiala         lldb::ByteOrder byte_order = GetByteOrder();
7562850b1beSTodd Fiala 
7572850b1beSTodd Fiala         // Parse the YMM register content from the register halves.
7582850b1beSTodd Fiala         for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
7592850b1beSTodd Fiala         {
7602850b1beSTodd Fiala             if (!CopyYMMtoXSTATE (reg, byte_order))
7612850b1beSTodd Fiala             {
7622850b1beSTodd Fiala                 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyYMMtoXSTATE() failed for reg num %" PRIu32, __FUNCTION__, reg);
7632850b1beSTodd Fiala                 return error;
7642850b1beSTodd Fiala             }
7652850b1beSTodd Fiala         }
7662850b1beSTodd Fiala     }
7672850b1beSTodd Fiala 
7682850b1beSTodd Fiala     return error;
7692850b1beSTodd Fiala }
7702850b1beSTodd Fiala 
7712850b1beSTodd Fiala bool
7722850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable (uint32_t set_index) const
7732850b1beSTodd Fiala {
7742850b1beSTodd Fiala     // Note: Extended register sets are assumed to be at the end of g_reg_sets.
7752850b1beSTodd Fiala     uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
7762850b1beSTodd Fiala 
7772850b1beSTodd Fiala     if (GetFPRType () == eFPRTypeXSAVE)
7782850b1beSTodd Fiala     {
7792850b1beSTodd Fiala         // AVX is the first extended register set.
7802850b1beSTodd Fiala         ++num_sets;
7812850b1beSTodd Fiala     }
7822850b1beSTodd Fiala     return (set_index < num_sets);
7832850b1beSTodd Fiala }
7842850b1beSTodd Fiala 
7852850b1beSTodd Fiala bool
7862850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const
7872850b1beSTodd Fiala {
7882850b1beSTodd Fiala     // GPRs come first.
7892850b1beSTodd Fiala     return reg_index <= m_reg_info.last_gpr;
7902850b1beSTodd Fiala }
7912850b1beSTodd Fiala 
7922850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::FPRType
7932850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::GetFPRType () const
7942850b1beSTodd Fiala {
7952850b1beSTodd Fiala     if (m_fpr_type == eFPRTypeNotValid)
7962850b1beSTodd Fiala     {
7972850b1beSTodd Fiala         // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx.
7982850b1beSTodd Fiala 
7992850b1beSTodd Fiala         // Try and see if AVX register retrieval works.
8002850b1beSTodd Fiala         m_fpr_type = eFPRTypeXSAVE;
801068f8a7eSTamas Berghammer         if (const_cast<NativeRegisterContextLinux_x86_64*>(this)->ReadFPR().Fail())
8022850b1beSTodd Fiala         {
8032850b1beSTodd Fiala             // Fall back to general floating point with no AVX support.
8042850b1beSTodd Fiala             m_fpr_type = eFPRTypeFXSAVE;
8052850b1beSTodd Fiala         }
8062850b1beSTodd Fiala     }
8072850b1beSTodd Fiala 
8082850b1beSTodd Fiala     return m_fpr_type;
8092850b1beSTodd Fiala }
8102850b1beSTodd Fiala 
8112850b1beSTodd Fiala bool
8122850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const
8132850b1beSTodd Fiala {
8142850b1beSTodd Fiala     return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr);
8152850b1beSTodd Fiala }
8162850b1beSTodd Fiala 
8172850b1beSTodd Fiala bool
8182850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, FPRType fpr_type) const
8192850b1beSTodd Fiala {
8202850b1beSTodd Fiala     bool generic_fpr = IsFPR(reg_index);
8212850b1beSTodd Fiala 
8222850b1beSTodd Fiala     if (fpr_type == eFPRTypeXSAVE)
8232850b1beSTodd Fiala         return generic_fpr || IsAVX(reg_index);
8242850b1beSTodd Fiala     return generic_fpr;
8252850b1beSTodd Fiala }
8262850b1beSTodd Fiala 
827068f8a7eSTamas Berghammer Error
8282850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::WriteFPR()
8292850b1beSTodd Fiala {
830068f8a7eSTamas Berghammer     const FPRType fpr_type = GetFPRType ();
831068f8a7eSTamas Berghammer     switch (fpr_type)
832068f8a7eSTamas Berghammer     {
833068f8a7eSTamas Berghammer     case FPRType::eFPRTypeFXSAVE:
834068f8a7eSTamas Berghammer         return NativeRegisterContextLinux::WriteFPR();
835068f8a7eSTamas Berghammer     case FPRType::eFPRTypeXSAVE:
836068f8a7eSTamas Berghammer         return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
837068f8a7eSTamas Berghammer     default:
838068f8a7eSTamas Berghammer         return Error("Unrecognized FPR type");
839068f8a7eSTamas Berghammer     }
8402850b1beSTodd Fiala }
8412850b1beSTodd Fiala 
8422850b1beSTodd Fiala bool
8432850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const
8442850b1beSTodd Fiala {
8452850b1beSTodd Fiala     return (m_reg_info.first_ymm <= reg_index && reg_index <= m_reg_info.last_ymm);
8462850b1beSTodd Fiala }
8472850b1beSTodd Fiala 
8482850b1beSTodd Fiala bool
8492850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order)
8502850b1beSTodd Fiala {
8512850b1beSTodd Fiala     if (!IsAVX (reg_index))
8522850b1beSTodd Fiala         return false;
8532850b1beSTodd Fiala 
8542850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderLittle)
8552850b1beSTodd Fiala     {
8562850b1beSTodd Fiala         ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
8572850b1beSTodd Fiala                  m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
8582850b1beSTodd Fiala                  sizeof (XMMReg));
8592850b1beSTodd Fiala         ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
8602850b1beSTodd Fiala                  m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
8612850b1beSTodd Fiala                  sizeof (YMMHReg));
8622850b1beSTodd Fiala         return true;
8632850b1beSTodd Fiala     }
8642850b1beSTodd Fiala 
8652850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderBig)
8662850b1beSTodd Fiala     {
8672850b1beSTodd Fiala         ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
8682850b1beSTodd Fiala                  m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
8692850b1beSTodd Fiala                  sizeof (XMMReg));
8702850b1beSTodd Fiala         ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
8712850b1beSTodd Fiala                  m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
8722850b1beSTodd Fiala                  sizeof (YMMHReg));
8732850b1beSTodd Fiala         return true;
8742850b1beSTodd Fiala     }
8752850b1beSTodd Fiala     return false; // unsupported or invalid byte order
8762850b1beSTodd Fiala 
8772850b1beSTodd Fiala }
8782850b1beSTodd Fiala 
8792850b1beSTodd Fiala bool
8802850b1beSTodd Fiala NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
8812850b1beSTodd Fiala {
8822850b1beSTodd Fiala     if (!IsAVX(reg))
8832850b1beSTodd Fiala         return false;
8842850b1beSTodd Fiala 
8852850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderLittle)
8862850b1beSTodd Fiala     {
8872850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
8882850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
8892850b1beSTodd Fiala                  sizeof(XMMReg));
8902850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
8912850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
8922850b1beSTodd Fiala                  sizeof(YMMHReg));
8932850b1beSTodd Fiala         return true;
8942850b1beSTodd Fiala     }
8952850b1beSTodd Fiala 
8962850b1beSTodd Fiala     if (byte_order == lldb::eByteOrderBig)
8972850b1beSTodd Fiala     {
8982850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
8992850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
9002850b1beSTodd Fiala                  sizeof(XMMReg));
9012850b1beSTodd Fiala         ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
9022850b1beSTodd Fiala                  m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
9032850b1beSTodd Fiala                  sizeof(YMMHReg));
9042850b1beSTodd Fiala         return true;
9052850b1beSTodd Fiala     }
9062850b1beSTodd Fiala     return false; // unsupported or invalid byte order
9072850b1beSTodd Fiala }
9082850b1beSTodd Fiala 
909068f8a7eSTamas Berghammer void*
910068f8a7eSTamas Berghammer NativeRegisterContextLinux_x86_64::GetFPRBuffer()
9112850b1beSTodd Fiala {
9122850b1beSTodd Fiala     const FPRType fpr_type = GetFPRType ();
9132850b1beSTodd Fiala     switch (fpr_type)
9142850b1beSTodd Fiala     {
9152850b1beSTodd Fiala     case FPRType::eFPRTypeFXSAVE:
916068f8a7eSTamas Berghammer         return &m_fpr.xstate.fxsave;
9172850b1beSTodd Fiala     case FPRType::eFPRTypeXSAVE:
918068f8a7eSTamas Berghammer         return &m_iovec;
9192850b1beSTodd Fiala     default:
920068f8a7eSTamas Berghammer         return nullptr;
9212850b1beSTodd Fiala     }
9222850b1beSTodd Fiala }
9232850b1beSTodd Fiala 
924068f8a7eSTamas Berghammer size_t
925068f8a7eSTamas Berghammer NativeRegisterContextLinux_x86_64::GetFPRSize()
9262850b1beSTodd Fiala {
927068f8a7eSTamas Berghammer     const FPRType fpr_type = GetFPRType ();
928068f8a7eSTamas Berghammer     switch (fpr_type)
929068f8a7eSTamas Berghammer     {
930068f8a7eSTamas Berghammer     case FPRType::eFPRTypeFXSAVE:
931068f8a7eSTamas Berghammer         return sizeof(m_fpr.xstate.fxsave);
932068f8a7eSTamas Berghammer     case FPRType::eFPRTypeXSAVE:
933068f8a7eSTamas Berghammer         return sizeof(m_iovec);
934068f8a7eSTamas Berghammer     default:
935068f8a7eSTamas Berghammer         return 0;
936068f8a7eSTamas Berghammer     }
9372850b1beSTodd Fiala }
9382850b1beSTodd Fiala 
939068f8a7eSTamas Berghammer Error
940068f8a7eSTamas Berghammer NativeRegisterContextLinux_x86_64::ReadFPR ()
9412850b1beSTodd Fiala {
942068f8a7eSTamas Berghammer     const FPRType fpr_type = GetFPRType ();
943068f8a7eSTamas Berghammer     switch (fpr_type)
944068f8a7eSTamas Berghammer     {
945068f8a7eSTamas Berghammer     case FPRType::eFPRTypeFXSAVE:
946068f8a7eSTamas Berghammer         return NativeRegisterContextLinux::ReadFPR();
947068f8a7eSTamas Berghammer     case FPRType::eFPRTypeXSAVE:
948068f8a7eSTamas Berghammer         return ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
949068f8a7eSTamas Berghammer     default:
950068f8a7eSTamas Berghammer         return Error("Unrecognized FPR type");
951068f8a7eSTamas Berghammer     }
9522850b1beSTodd Fiala }
9532850b1beSTodd Fiala 
95418fe6404SChaoren Lin Error
955c16f5dcaSChaoren Lin NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint32_t wp_index, bool &is_hit)
95618fe6404SChaoren Lin {
95718fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
95818fe6404SChaoren Lin         return Error("Watchpoint index out of range");
95918fe6404SChaoren Lin 
96018fe6404SChaoren Lin     RegisterValue reg_value;
9616a504f6eSChaoren Lin     Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
962c16f5dcaSChaoren Lin     if (error.Fail())
963c16f5dcaSChaoren Lin     {
964c16f5dcaSChaoren Lin         is_hit = false;
965c16f5dcaSChaoren Lin         return error;
966c16f5dcaSChaoren Lin     }
96718fe6404SChaoren Lin 
96818fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64();
96918fe6404SChaoren Lin 
970c16f5dcaSChaoren Lin     is_hit = status_bits & (1 << wp_index);
97118fe6404SChaoren Lin 
97218fe6404SChaoren Lin     return error;
97318fe6404SChaoren Lin }
97418fe6404SChaoren Lin 
97518fe6404SChaoren Lin Error
976ea8c25a8SOmair Javaid NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) {
977c16f5dcaSChaoren Lin     uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
978c16f5dcaSChaoren Lin     for (wp_index = 0; wp_index < num_hw_wps; ++wp_index)
979c16f5dcaSChaoren Lin     {
980c16f5dcaSChaoren Lin         bool is_hit;
981c16f5dcaSChaoren Lin         Error error = IsWatchpointHit(wp_index, is_hit);
982c16f5dcaSChaoren Lin         if (error.Fail()) {
983c16f5dcaSChaoren Lin             wp_index = LLDB_INVALID_INDEX32;
984c16f5dcaSChaoren Lin             return error;
985c16f5dcaSChaoren Lin         } else if (is_hit) {
986c16f5dcaSChaoren Lin             return error;
987c16f5dcaSChaoren Lin         }
988c16f5dcaSChaoren Lin     }
989c16f5dcaSChaoren Lin     wp_index = LLDB_INVALID_INDEX32;
990c16f5dcaSChaoren Lin     return Error();
991c16f5dcaSChaoren Lin }
992c16f5dcaSChaoren Lin 
993c16f5dcaSChaoren Lin Error
994c16f5dcaSChaoren Lin NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index, bool &is_vacant)
99518fe6404SChaoren Lin {
99618fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
99718fe6404SChaoren Lin         return Error ("Watchpoint index out of range");
99818fe6404SChaoren Lin 
99918fe6404SChaoren Lin     RegisterValue reg_value;
10006a504f6eSChaoren Lin     Error error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
1001c16f5dcaSChaoren Lin     if (error.Fail())
1002c16f5dcaSChaoren Lin     {
1003c16f5dcaSChaoren Lin         is_vacant = false;
1004c16f5dcaSChaoren Lin         return error;
1005c16f5dcaSChaoren Lin     }
100618fe6404SChaoren Lin 
100718fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64();
100818fe6404SChaoren Lin 
1009c16f5dcaSChaoren Lin     is_vacant = !(control_bits & (1 << (2 * wp_index)));
101018fe6404SChaoren Lin 
101118fe6404SChaoren Lin     return error;
101218fe6404SChaoren Lin }
101318fe6404SChaoren Lin 
101418fe6404SChaoren Lin Error
101518fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex(
101618fe6404SChaoren Lin         lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
101718fe6404SChaoren Lin 
101818fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
101918fe6404SChaoren Lin         return Error ("Watchpoint index out of range");
102018fe6404SChaoren Lin 
1021*cf8eb9daSOmair Javaid     if (watch_flags == 0x2)
1022*cf8eb9daSOmair Javaid         return Error ("Read watchpoints currently unsupported on x86_64 architecture");
1023*cf8eb9daSOmair Javaid 
102418fe6404SChaoren Lin     if (watch_flags != 0x1 && watch_flags != 0x3)
102518fe6404SChaoren Lin         return Error ("Invalid read/write bits for watchpoint");
102618fe6404SChaoren Lin 
102718fe6404SChaoren Lin     if (size != 1 && size != 2 && size != 4 && size != 8)
102818fe6404SChaoren Lin         return Error ("Invalid size for watchpoint");
102918fe6404SChaoren Lin 
1030c16f5dcaSChaoren Lin     bool is_vacant;
1031c16f5dcaSChaoren Lin     Error error = IsWatchpointVacant (wp_index, is_vacant);
103218fe6404SChaoren Lin     if (error.Fail()) return error;
1033c16f5dcaSChaoren Lin     if (!is_vacant) return Error("Watchpoint index not vacant");
103418fe6404SChaoren Lin 
103518fe6404SChaoren Lin     RegisterValue reg_value;
10366a504f6eSChaoren Lin     error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
103718fe6404SChaoren Lin     if (error.Fail()) return error;
103818fe6404SChaoren Lin 
103918fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
104018fe6404SChaoren Lin     // set bits 1, 3, 5, or 7
104118fe6404SChaoren Lin     uint64_t enable_bit = 1 << (2 * wp_index);
104218fe6404SChaoren Lin 
104318fe6404SChaoren Lin     // set bits 16-17, 20-21, 24-25, or 28-29
104418fe6404SChaoren Lin     // with 0b01 for write, and 0b11 for read/write
104518fe6404SChaoren Lin     uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
104618fe6404SChaoren Lin 
104718fe6404SChaoren Lin     // set bits 18-19, 22-23, 26-27, or 30-31
104818fe6404SChaoren Lin     // with 0b00, 0b01, 0b10, or 0b11
104918fe6404SChaoren Lin     // for 1, 2, 8 (if supported), or 4 bytes, respectively
105018fe6404SChaoren Lin     uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
105118fe6404SChaoren Lin 
105218fe6404SChaoren Lin     uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
105318fe6404SChaoren Lin 
105418fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
105518fe6404SChaoren Lin 
105618fe6404SChaoren Lin     control_bits |= enable_bit | rw_bits | size_bits;
105718fe6404SChaoren Lin 
1058068f8a7eSTamas Berghammer     error = WriteRegisterRaw(m_reg_info.first_dr + wp_index, RegisterValue(addr));
105918fe6404SChaoren Lin     if (error.Fail()) return error;
106018fe6404SChaoren Lin 
1061068f8a7eSTamas Berghammer     error = WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
106218fe6404SChaoren Lin     if (error.Fail()) return error;
106318fe6404SChaoren Lin 
106418fe6404SChaoren Lin     error.Clear();
106518fe6404SChaoren Lin     return error;
106618fe6404SChaoren Lin }
106718fe6404SChaoren Lin 
106818fe6404SChaoren Lin bool
106918fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(uint32_t wp_index)
107018fe6404SChaoren Lin {
107118fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
107218fe6404SChaoren Lin         return false;
107318fe6404SChaoren Lin 
107418fe6404SChaoren Lin     RegisterValue reg_value;
107518fe6404SChaoren Lin 
107618fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
107718fe6404SChaoren Lin     // clear bits 0, 1, 2, or 3 of the debug status register (DR6)
10786a504f6eSChaoren Lin     Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
107918fe6404SChaoren Lin     if (error.Fail()) return false;
108018fe6404SChaoren Lin     uint64_t bit_mask = 1 << wp_index;
108118fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
1082068f8a7eSTamas Berghammer     error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
108318fe6404SChaoren Lin     if (error.Fail()) return false;
108418fe6404SChaoren Lin 
108518fe6404SChaoren Lin     // for watchpoints 0, 1, 2, or 3, respectively,
108618fe6404SChaoren Lin     // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
108718fe6404SChaoren Lin     // of the debug control register (DR7)
10886a504f6eSChaoren Lin     error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
108918fe6404SChaoren Lin     if (error.Fail()) return false;
109018fe6404SChaoren Lin     bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
109118fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1092068f8a7eSTamas Berghammer     return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)).Success();
109318fe6404SChaoren Lin }
109418fe6404SChaoren Lin 
109518fe6404SChaoren Lin Error
109618fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints()
109718fe6404SChaoren Lin {
109818fe6404SChaoren Lin     RegisterValue reg_value;
109918fe6404SChaoren Lin 
110018fe6404SChaoren Lin     // clear bits {0-4} of the debug status register (DR6)
11016a504f6eSChaoren Lin     Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
110218fe6404SChaoren Lin     if (error.Fail()) return error;
110318fe6404SChaoren Lin     uint64_t bit_mask = 0xF;
110418fe6404SChaoren Lin     uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
1105068f8a7eSTamas Berghammer     error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
110618fe6404SChaoren Lin     if (error.Fail()) return error;
110718fe6404SChaoren Lin 
110818fe6404SChaoren Lin     // clear bits {0-7,16-31} of the debug control register (DR7)
11096a504f6eSChaoren Lin     error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
111018fe6404SChaoren Lin     if (error.Fail()) return error;
111118fe6404SChaoren Lin     bit_mask = 0xFF | (0xFFFF << 16);
111218fe6404SChaoren Lin     uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
1113068f8a7eSTamas Berghammer     return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
111418fe6404SChaoren Lin }
111518fe6404SChaoren Lin 
111618fe6404SChaoren Lin uint32_t
111718fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint(
111818fe6404SChaoren Lin         lldb::addr_t addr, size_t size, uint32_t watch_flags)
111918fe6404SChaoren Lin {
1120c16f5dcaSChaoren Lin     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
112118fe6404SChaoren Lin     const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
112218fe6404SChaoren Lin     for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index)
112318fe6404SChaoren Lin     {
1124c16f5dcaSChaoren Lin         bool is_vacant;
1125c16f5dcaSChaoren Lin         Error error = IsWatchpointVacant(wp_index, is_vacant);
1126c16f5dcaSChaoren Lin         if (is_vacant)
1127c16f5dcaSChaoren Lin         {
1128c16f5dcaSChaoren Lin             error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
1129c16f5dcaSChaoren Lin             if (error.Success())
113018fe6404SChaoren Lin                 return wp_index;
113118fe6404SChaoren Lin         }
1132c16f5dcaSChaoren Lin         if (error.Fail() && log)
1133c16f5dcaSChaoren Lin         {
1134c16f5dcaSChaoren Lin             log->Printf("NativeRegisterContextLinux_x86_64::%s Error: %s",
1135c16f5dcaSChaoren Lin                     __FUNCTION__, error.AsCString());
1136c16f5dcaSChaoren Lin         }
1137c16f5dcaSChaoren Lin     }
113818fe6404SChaoren Lin     return LLDB_INVALID_INDEX32;
113918fe6404SChaoren Lin }
114018fe6404SChaoren Lin 
114118fe6404SChaoren Lin lldb::addr_t
114218fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index)
114318fe6404SChaoren Lin {
114418fe6404SChaoren Lin     if (wp_index >= NumSupportedHardwareWatchpoints())
114518fe6404SChaoren Lin         return LLDB_INVALID_ADDRESS;
114618fe6404SChaoren Lin     RegisterValue reg_value;
114718fe6404SChaoren Lin     if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail())
114818fe6404SChaoren Lin         return LLDB_INVALID_ADDRESS;
114918fe6404SChaoren Lin     return reg_value.GetAsUInt64();
115018fe6404SChaoren Lin }
115118fe6404SChaoren Lin 
115218fe6404SChaoren Lin uint32_t
115318fe6404SChaoren Lin NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints ()
115418fe6404SChaoren Lin {
115518fe6404SChaoren Lin     // Available debug address registers: dr0, dr1, dr2, dr3
115618fe6404SChaoren Lin     return 4;
115718fe6404SChaoren Lin }
1158068f8a7eSTamas Berghammer 
1159068f8a7eSTamas Berghammer #endif // defined(__i386__) || defined(__x86_64__)
1160