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
17typedef const BYTE CORDB_ADDRESS_TYPE;
18typedef 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
25typedef 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
37inline 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
57SELECTANY 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//
81inline 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//
92inline 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
106inline 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
120inline 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}
133inline 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
152inline 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
180inline 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
187inline 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
196inline 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
209inline void CORDbgAdjustPCForBreakInstruction(DT_CONTEXT* pContext)
210{
211 LIMITED_METHOD_CONTRACT;
212
213 pContext->Rip -= 1;
214}
215
216inline bool AddressIsBreakpoint(CORDB_ADDRESS_TYPE *address)
217{
218 LIMITED_METHOD_CONTRACT;
219
220 return *address == CORDbg_BREAK_INSTRUCTION;
221}
222
223inline BOOL IsRunningOnWin95() {
224 return false;
225}
226
227inline void SetSSFlag(DT_CONTEXT *pContext)
228{
229 _ASSERTE(pContext != NULL);
230 pContext->EFlags |= 0x100;
231}
232
233inline void UnsetSSFlag(DT_CONTEXT *pContext)
234{
235 _ASSERTE(pContext != NULL);
236 pContext->EFlags &= ~0x100;
237}
238
239inline bool IsSSFlagEnabled(DT_CONTEXT * context)
240{
241 _ASSERTE(context != NULL);
242 return (context->EFlags & 0x100) != 0;
243}
244
245
246inline bool PRDIsEqual(PRD_TYPE p1, PRD_TYPE p2){
247 return p1 == p2;
248}
249inline void InitializePRD(PRD_TYPE *p1) {
250 *p1 = 0;
251}
252
253inline bool PRDIsEmpty(PRD_TYPE p1) {
254 return p1 == 0;
255}
256
257#endif // PRIMITIVES_H_
258