| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | //***************************************************************************** |
| 5 | // File: primitives.h |
| 6 | // |
| 7 | |
| 8 | // |
| 9 | // Platform-specific debugger primitives |
| 10 | // |
| 11 | //***************************************************************************** |
| 12 | |
| 13 | #ifndef PRIMITIVES_H_ |
| 14 | #define PRIMITIVES_H_ |
| 15 | |
| 16 | #ifndef CORDB_ADDRESS_TYPE |
| 17 | typedef const BYTE CORDB_ADDRESS_TYPE; |
| 18 | typedef DPTR(CORDB_ADDRESS_TYPE) PTR_CORDB_ADDRESS_TYPE; |
| 19 | #endif |
| 20 | //This is an abstraction to keep x86/ia64 patch data separate |
| 21 | #ifndef PRD_TYPE |
| 22 | #define PRD_TYPE DWORD_PTR |
| 23 | #endif |
| 24 | |
| 25 | typedef M128A FPRegister64; |
| 26 | |
| 27 | // From section 1.1 of AMD64 Programmers Manual Vol 3. |
| 28 | #define MAX_INSTRUCTION_LENGTH 15 |
| 29 | |
| 30 | // Given a return address retrieved during stackwalk, |
| 31 | // this is the offset by which it should be decremented to lend somewhere in a call instruction. |
| 32 | #define STACKWALK_CONTROLPC_ADJUST_OFFSET 1 |
| 33 | |
| 34 | #define CORDbg_BREAK_INSTRUCTION_SIZE 1 |
| 35 | #define CORDbg_BREAK_INSTRUCTION (BYTE)0xCC |
| 36 | |
| 37 | inline CORDB_ADDRESS GetPatchEndAddr(CORDB_ADDRESS patchAddr) |
| 38 | { |
| 39 | LIMITED_METHOD_DAC_CONTRACT; |
| 40 | return patchAddr + CORDbg_BREAK_INSTRUCTION_SIZE; |
| 41 | } |
| 42 | |
| 43 | |
| 44 | #define InitializePRDToBreakInst(_pPRD) *(_pPRD) = CORDbg_BREAK_INSTRUCTION |
| 45 | #define PRDIsBreakInst(_pPRD) (*(_pPRD) == CORDbg_BREAK_INSTRUCTION) |
| 46 | |
| 47 | #define CORDbgGetInstructionEx(_buffer, _requestedAddr, _patchAddr, _dummy1, _dummy2) \ |
| 48 | CORDbgGetInstruction((CORDB_ADDRESS_TYPE *)((_buffer) + ((_patchAddr) - (_requestedAddr)))); |
| 49 | |
| 50 | #define CORDbgSetInstructionEx(_buffer, _requestedAddr, _patchAddr, _opcode, _dummy2) \ |
| 51 | CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)((_buffer) + ((_patchAddr) - (_requestedAddr))), (_opcode)); |
| 52 | |
| 53 | #define CORDbgInsertBreakpointEx(_buffer, _requestedAddr, _patchAddr, _dummy1, _dummy2) \ |
| 54 | CORDbgInsertBreakpoint((CORDB_ADDRESS_TYPE *)((_buffer) + ((_patchAddr) - (_requestedAddr)))); |
| 55 | |
| 56 | |
| 57 | SELECTANY const CorDebugRegister g_JITToCorDbgReg[] = |
| 58 | { |
| 59 | REGISTER_AMD64_RAX, |
| 60 | REGISTER_AMD64_RCX, |
| 61 | REGISTER_AMD64_RDX, |
| 62 | REGISTER_AMD64_RBX, |
| 63 | REGISTER_AMD64_RSP, |
| 64 | REGISTER_AMD64_RBP, |
| 65 | REGISTER_AMD64_RSI, |
| 66 | REGISTER_AMD64_RDI, |
| 67 | REGISTER_AMD64_R8, |
| 68 | REGISTER_AMD64_R9, |
| 69 | REGISTER_AMD64_R10, |
| 70 | REGISTER_AMD64_R11, |
| 71 | REGISTER_AMD64_R12, |
| 72 | REGISTER_AMD64_R13, |
| 73 | REGISTER_AMD64_R14, |
| 74 | REGISTER_AMD64_R15 |
| 75 | }; |
| 76 | |
| 77 | // |
| 78 | // Mapping from ICorDebugInfo register numbers to CorDebugRegister |
| 79 | // numbers. Note: this must match the order in corinfo.h. |
| 80 | // |
| 81 | inline CorDebugRegister ConvertRegNumToCorDebugRegister(ICorDebugInfo::RegNum reg) |
| 82 | { |
| 83 | _ASSERTE(reg >= 0); |
| 84 | _ASSERTE(static_cast<size_t>(reg) < _countof(g_JITToCorDbgReg)); |
| 85 | return g_JITToCorDbgReg[reg]; |
| 86 | } |
| 87 | |
| 88 | |
| 89 | // |
| 90 | // inline function to access/modify the CONTEXT |
| 91 | // |
| 92 | inline LPVOID CORDbgGetIP(DT_CONTEXT* context) |
| 93 | { |
| 94 | CONTRACTL |
| 95 | { |
| 96 | NOTHROW; |
| 97 | GC_NOTRIGGER; |
| 98 | |
| 99 | PRECONDITION(CheckPointer(context)); |
| 100 | } |
| 101 | CONTRACTL_END; |
| 102 | |
| 103 | return (LPVOID) context->Rip; |
| 104 | } |
| 105 | |
| 106 | inline void CORDbgSetIP(DT_CONTEXT* context, LPVOID rip) |
| 107 | { |
| 108 | CONTRACTL |
| 109 | { |
| 110 | NOTHROW; |
| 111 | GC_NOTRIGGER; |
| 112 | |
| 113 | PRECONDITION(CheckPointer(context)); |
| 114 | } |
| 115 | CONTRACTL_END; |
| 116 | |
| 117 | context->Rip = (DWORD64) rip; |
| 118 | } |
| 119 | |
| 120 | inline LPVOID CORDbgGetSP(const DT_CONTEXT * context) |
| 121 | { |
| 122 | CONTRACTL |
| 123 | { |
| 124 | NOTHROW; |
| 125 | GC_NOTRIGGER; |
| 126 | |
| 127 | PRECONDITION(CheckPointer(context)); |
| 128 | } |
| 129 | CONTRACTL_END; |
| 130 | |
| 131 | return (LPVOID)context->Rsp; |
| 132 | } |
| 133 | inline void CORDbgSetSP(DT_CONTEXT *context, LPVOID rsp) |
| 134 | { |
| 135 | CONTRACTL |
| 136 | { |
| 137 | NOTHROW; |
| 138 | GC_NOTRIGGER; |
| 139 | |
| 140 | PRECONDITION(CheckPointer(context)); |
| 141 | } |
| 142 | CONTRACTL_END; |
| 143 | |
| 144 | context->Rsp = (UINT_PTR)rsp; |
| 145 | } |
| 146 | |
| 147 | // AMD64 has no frame pointer stored in RBP |
| 148 | #define CORDbgSetFP(context, rbp) |
| 149 | #define CORDbgGetFP(context) 0 |
| 150 | |
| 151 | // compare the RIP, RSP, and RBP |
| 152 | inline BOOL CompareControlRegisters(const DT_CONTEXT * pCtx1, const DT_CONTEXT * pCtx2) |
| 153 | { |
| 154 | LIMITED_METHOD_DAC_CONTRACT; |
| 155 | |
| 156 | if ((pCtx1->Rip == pCtx2->Rip) && |
| 157 | (pCtx1->Rsp == pCtx2->Rsp) && |
| 158 | (pCtx1->Rbp == pCtx2->Rbp)) |
| 159 | { |
| 160 | return TRUE; |
| 161 | } |
| 162 | else |
| 163 | { |
| 164 | return FALSE; |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | /* ========================================================================= */ |
| 169 | // |
| 170 | // Routines used by debugger support functions such as codepatch.cpp or |
| 171 | // exception handling code. |
| 172 | // |
| 173 | // GetInstruction, InsertBreakpoint, and SetInstruction all operate on |
| 174 | // a _single_ byte of memory. This is really important. If you only |
| 175 | // save one byte from the instruction stream before placing a breakpoint, |
| 176 | // you need to make sure to only replace one byte later on. |
| 177 | // |
| 178 | |
| 179 | |
| 180 | inline PRD_TYPE CORDbgGetInstruction(UNALIGNED CORDB_ADDRESS_TYPE* address) |
| 181 | { |
| 182 | LIMITED_METHOD_CONTRACT; |
| 183 | |
| 184 | return *address; // retrieving only one byte is important |
| 185 | } |
| 186 | |
| 187 | inline void CORDbgInsertBreakpoint(UNALIGNED CORDB_ADDRESS_TYPE *address) |
| 188 | { |
| 189 | LIMITED_METHOD_CONTRACT; |
| 190 | |
| 191 | *((unsigned char*)address) = 0xCC; // int 3 (single byte patch) |
| 192 | FlushInstructionCache(GetCurrentProcess(), address, 1); |
| 193 | |
| 194 | } |
| 195 | |
| 196 | inline void CORDbgSetInstruction(UNALIGNED CORDB_ADDRESS_TYPE* address, |
| 197 | PRD_TYPE instruction) |
| 198 | { |
| 199 | // In a DAC build, this function assumes the input is an host address. |
| 200 | LIMITED_METHOD_DAC_CONTRACT; |
| 201 | |
| 202 | *((unsigned char*)address) = |
| 203 | (unsigned char) instruction; // setting one byte is important |
| 204 | FlushInstructionCache(GetCurrentProcess(), address, 1); |
| 205 | |
| 206 | } |
| 207 | |
| 208 | |
| 209 | inline void CORDbgAdjustPCForBreakInstruction(DT_CONTEXT* pContext) |
| 210 | { |
| 211 | LIMITED_METHOD_CONTRACT; |
| 212 | |
| 213 | pContext->Rip -= 1; |
| 214 | } |
| 215 | |
| 216 | inline bool AddressIsBreakpoint(CORDB_ADDRESS_TYPE *address) |
| 217 | { |
| 218 | LIMITED_METHOD_CONTRACT; |
| 219 | |
| 220 | return *address == CORDbg_BREAK_INSTRUCTION; |
| 221 | } |
| 222 | |
| 223 | inline BOOL IsRunningOnWin95() { |
| 224 | return false; |
| 225 | } |
| 226 | |
| 227 | inline void SetSSFlag(DT_CONTEXT *pContext) |
| 228 | { |
| 229 | _ASSERTE(pContext != NULL); |
| 230 | pContext->EFlags |= 0x100; |
| 231 | } |
| 232 | |
| 233 | inline void UnsetSSFlag(DT_CONTEXT *pContext) |
| 234 | { |
| 235 | _ASSERTE(pContext != NULL); |
| 236 | pContext->EFlags &= ~0x100; |
| 237 | } |
| 238 | |
| 239 | inline bool IsSSFlagEnabled(DT_CONTEXT * context) |
| 240 | { |
| 241 | _ASSERTE(context != NULL); |
| 242 | return (context->EFlags & 0x100) != 0; |
| 243 | } |
| 244 | |
| 245 | |
| 246 | inline bool PRDIsEqual(PRD_TYPE p1, PRD_TYPE p2){ |
| 247 | return p1 == p2; |
| 248 | } |
| 249 | inline void InitializePRD(PRD_TYPE *p1) { |
| 250 | *p1 = 0; |
| 251 | } |
| 252 | |
| 253 | inline bool PRDIsEmpty(PRD_TYPE p1) { |
| 254 | return p1 == 0; |
| 255 | } |
| 256 | |
| 257 | #endif // PRIMITIVES_H_ |
| 258 | |