Warning: This file is not a C or C++ file. It does not have highlighting.
| 1 | //===-- DNBArchImplX86_64.h -------------------------------------*- C++ -*-===// |
|---|---|
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Created by Greg Clayton on 6/25/07. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_X86_64_DNBARCHIMPLX86_64_H |
| 14 | #define LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_X86_64_DNBARCHIMPLX86_64_H |
| 15 | |
| 16 | #if defined(__i386__) || defined(__x86_64__) |
| 17 | #include "DNBArch.h" |
| 18 | #include "MachRegisterStatesX86_64.h" |
| 19 | |
| 20 | #include <map> |
| 21 | |
| 22 | class MachThread; |
| 23 | |
| 24 | class DNBArchImplX86_64 : public DNBArchProtocol { |
| 25 | public: |
| 26 | DNBArchImplX86_64(MachThread *thread) |
| 27 | : DNBArchProtocol(), m_thread(thread), m_state(), m_2pc_dbg_checkpoint(), |
| 28 | m_2pc_trans_state(Trans_Done), m_saved_register_states() {} |
| 29 | virtual ~DNBArchImplX86_64() {} |
| 30 | |
| 31 | static void Initialize(); |
| 32 | |
| 33 | bool GetRegisterValue(uint32_t set, uint32_t reg, |
| 34 | DNBRegisterValue *value) override; |
| 35 | bool SetRegisterValue(uint32_t set, uint32_t reg, |
| 36 | const DNBRegisterValue *value) override; |
| 37 | nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len) override; |
| 38 | nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len) override; |
| 39 | uint32_t SaveRegisterState() override; |
| 40 | bool RestoreRegisterState(uint32_t save_id) override; |
| 41 | |
| 42 | kern_return_t GetRegisterState(int set, bool force) override; |
| 43 | kern_return_t SetRegisterState(int set) override; |
| 44 | bool RegisterSetStateIsValid(int set) const override; |
| 45 | |
| 46 | uint64_t GetPC(uint64_t failValue) override; // Get program counter |
| 47 | kern_return_t SetPC(uint64_t value) override; |
| 48 | uint64_t GetSP(uint64_t failValue) override; // Get stack pointer |
| 49 | void ThreadWillResume() override; |
| 50 | bool ThreadDidStop() override; |
| 51 | bool NotifyException(MachException::Data &exc) override; |
| 52 | |
| 53 | uint32_t NumSupportedHardwareBreakpoints() override; |
| 54 | uint32_t NumSupportedHardwareWatchpoints() override; |
| 55 | |
| 56 | uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, |
| 57 | bool also_set_on_task) override; |
| 58 | bool DisableHardwareBreakpoint(uint32_t hw_break_index, |
| 59 | bool also_set_on_task) override; |
| 60 | uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, |
| 61 | bool read, bool write, |
| 62 | bool also_set_on_task) override; |
| 63 | bool DisableHardwareWatchpoint(uint32_t hw_break_index, |
| 64 | bool also_set_on_task) override; |
| 65 | uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) override; |
| 66 | |
| 67 | protected: |
| 68 | kern_return_t EnableHardwareSingleStep(bool enable); |
| 69 | |
| 70 | typedef __x86_64_thread_state_t GPR; |
| 71 | typedef __x86_64_float_state_t FPU; |
| 72 | typedef __x86_64_exception_state_t EXC; |
| 73 | typedef __x86_64_avx_state_t AVX; |
| 74 | typedef __x86_64_debug_state_t DBG; |
| 75 | |
| 76 | static const DNBRegisterInfo g_gpr_registers[]; |
| 77 | static const DNBRegisterInfo g_fpu_registers_no_avx[]; |
| 78 | static const DNBRegisterInfo g_fpu_registers_avx[]; |
| 79 | static const DNBRegisterInfo g_exc_registers[]; |
| 80 | static const DNBRegisterSetInfo g_reg_sets_no_avx[]; |
| 81 | static const DNBRegisterSetInfo g_reg_sets_avx[]; |
| 82 | static const size_t k_num_gpr_registers; |
| 83 | static const size_t k_num_fpu_registers_no_avx; |
| 84 | static const size_t k_num_fpu_registers_avx; |
| 85 | static const size_t k_num_exc_registers; |
| 86 | static const size_t k_num_all_registers_no_avx; |
| 87 | static const size_t k_num_all_registers_avx; |
| 88 | static const size_t k_num_register_sets; |
| 89 | |
| 90 | typedef __x86_64_avx512f_state_t AVX512F; |
| 91 | static const DNBRegisterInfo g_fpu_registers_avx512f[]; |
| 92 | static const DNBRegisterSetInfo g_reg_sets_avx512f[]; |
| 93 | static const size_t k_num_fpu_registers_avx512f; |
| 94 | static const size_t k_num_all_registers_avx512f; |
| 95 | |
| 96 | enum RegisterSet { |
| 97 | e_regSetALL = REGISTER_SET_ALL, |
| 98 | e_regSetGPR, |
| 99 | e_regSetFPU, |
| 100 | e_regSetEXC, |
| 101 | e_regSetDBG, |
| 102 | kNumRegisterSets |
| 103 | }; |
| 104 | |
| 105 | enum RegisterSetWordSize { |
| 106 | e_regSetWordSizeGPR = (sizeof(GPR) - 32) / sizeof(int), |
| 107 | e_regSetWordSizeGPRFull = sizeof(GPR) / sizeof(int), |
| 108 | e_regSetWordSizeFPU = sizeof(FPU) / sizeof(int), |
| 109 | e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int), |
| 110 | e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int), |
| 111 | e_regSetWordSizeAVX512f = sizeof(AVX512F) / sizeof(int), |
| 112 | e_regSetWordSizeDBG = sizeof(DBG) / sizeof(int) |
| 113 | }; |
| 114 | |
| 115 | enum { Read = 0, Write = 1, kNumErrors = 2 }; |
| 116 | |
| 117 | struct Context { |
| 118 | GPR gpr; |
| 119 | union { |
| 120 | FPU no_avx; |
| 121 | AVX avx; |
| 122 | AVX512F avx512f; |
| 123 | } fpu; |
| 124 | EXC exc; |
| 125 | DBG dbg; |
| 126 | }; |
| 127 | |
| 128 | struct State { |
| 129 | Context context; |
| 130 | kern_return_t gpr_errs[2]; // Read/Write errors |
| 131 | kern_return_t fpu_errs[2]; // Read/Write errors |
| 132 | kern_return_t exc_errs[2]; // Read/Write errors |
| 133 | kern_return_t dbg_errs[2]; // Read/Write errors |
| 134 | bool hasFullGPRState; |
| 135 | |
| 136 | State() { |
| 137 | uint32_t i; |
| 138 | for (i = 0; i < kNumErrors; i++) { |
| 139 | gpr_errs[i] = -1; |
| 140 | fpu_errs[i] = -1; |
| 141 | exc_errs[i] = -1; |
| 142 | dbg_errs[i] = -1; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | void InvalidateAllRegisterStates() { SetError(e_regSetALL, Read, -1); } |
| 147 | |
| 148 | kern_return_t GetError(int flavor, uint32_t err_idx) const { |
| 149 | if (err_idx < kNumErrors) { |
| 150 | switch (flavor) { |
| 151 | // When getting all errors, just OR all values together to see if |
| 152 | // we got any kind of error. |
| 153 | case e_regSetALL: |
| 154 | return gpr_errs[err_idx] | fpu_errs[err_idx] | exc_errs[err_idx]; |
| 155 | case e_regSetGPR: |
| 156 | return gpr_errs[err_idx]; |
| 157 | case e_regSetFPU: |
| 158 | return fpu_errs[err_idx]; |
| 159 | case e_regSetEXC: |
| 160 | return exc_errs[err_idx]; |
| 161 | case e_regSetDBG: |
| 162 | return dbg_errs[err_idx]; |
| 163 | default: |
| 164 | break; |
| 165 | } |
| 166 | } |
| 167 | return -1; |
| 168 | } |
| 169 | |
| 170 | bool SetError(int flavor, uint32_t err_idx, kern_return_t err) { |
| 171 | if (err_idx < kNumErrors) { |
| 172 | switch (flavor) { |
| 173 | case e_regSetALL: |
| 174 | gpr_errs[err_idx] = fpu_errs[err_idx] = exc_errs[err_idx] = |
| 175 | dbg_errs[err_idx] = err; |
| 176 | return true; |
| 177 | |
| 178 | case e_regSetGPR: |
| 179 | gpr_errs[err_idx] = err; |
| 180 | return true; |
| 181 | |
| 182 | case e_regSetFPU: |
| 183 | fpu_errs[err_idx] = err; |
| 184 | return true; |
| 185 | |
| 186 | case e_regSetEXC: |
| 187 | exc_errs[err_idx] = err; |
| 188 | return true; |
| 189 | |
| 190 | case e_regSetDBG: |
| 191 | dbg_errs[err_idx] = err; |
| 192 | return true; |
| 193 | |
| 194 | default: |
| 195 | break; |
| 196 | } |
| 197 | } |
| 198 | return false; |
| 199 | } |
| 200 | |
| 201 | bool RegsAreValid(int flavor) const { |
| 202 | return GetError(flavor, Read) == KERN_SUCCESS; |
| 203 | } |
| 204 | }; |
| 205 | |
| 206 | kern_return_t GetGPRState(bool force); |
| 207 | kern_return_t GetFPUState(bool force); |
| 208 | kern_return_t GetEXCState(bool force); |
| 209 | kern_return_t GetDBGState(bool force); |
| 210 | |
| 211 | kern_return_t SetGPRState(); |
| 212 | kern_return_t SetFPUState(); |
| 213 | kern_return_t SetEXCState(); |
| 214 | kern_return_t SetDBGState(bool also_set_on_task); |
| 215 | |
| 216 | static DNBArchProtocol *Create(MachThread *thread); |
| 217 | |
| 218 | static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); |
| 219 | |
| 220 | static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets); |
| 221 | |
| 222 | static uint32_t GetRegisterContextSize(); |
| 223 | |
| 224 | static void SetHardwareBreakpoint(DBG &debug_state, uint32_t hw_index, |
| 225 | nub_addr_t addr, nub_size_t size); |
| 226 | |
| 227 | // Helper functions for watchpoint manipulations. |
| 228 | static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, |
| 229 | nub_addr_t addr, nub_size_t size, bool read, |
| 230 | bool write); |
| 231 | static void ClearWatchpoint(DBG &debug_state, uint32_t hw_index); |
| 232 | static bool IsWatchpointVacant(const DBG &debug_state, uint32_t hw_index); |
| 233 | static void ClearWatchpointHits(DBG &debug_state); |
| 234 | static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); |
| 235 | static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); |
| 236 | |
| 237 | bool StartTransForHWP() override; |
| 238 | bool RollbackTransForHWP() override; |
| 239 | bool FinishTransForHWP() override; |
| 240 | DBG GetDBGCheckpoint(); |
| 241 | |
| 242 | MachThread *m_thread; |
| 243 | State m_state; |
| 244 | DBG m_2pc_dbg_checkpoint; |
| 245 | uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning |
| 246 | // (0), Done (1), or Rolled Back (2)? |
| 247 | typedef std::map<uint32_t, Context> SaveRegisterStates; |
| 248 | SaveRegisterStates m_saved_register_states; |
| 249 | }; |
| 250 | |
| 251 | #endif // #if defined (__i386__) || defined (__x86_64__) |
| 252 | #endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_X86_64_DNBARCHIMPLX86_64_H |
| 253 |
Warning: This file is not a C or C++ file. It does not have highlighting.
