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 | #ifndef DEBUGGER_COMMON_H |
6 | #define DEBUGGER_COMMON_H |
7 | |
8 | // |
9 | // Conversions between pointers and CORDB_ADDRESS |
10 | // These are 3gb safe - we use zero-extension for CORDB_ADDRESS. |
11 | // Note that this is a different semantics from CLRDATA_ADDRESS which is sign-extended. |
12 | // |
13 | // @dbgtodo : This confuses the host and target address spaces. Ideally we'd have |
14 | // conversions between PTR types (eg. DPTR) and CORDB_ADDRESS, and not need conversions |
15 | // from host pointer types to CORDB_ADDRESS. |
16 | // |
17 | #if defined(_TARGET_X86_) || defined(_TARGET_ARM_) |
18 | inline CORDB_ADDRESS PTR_TO_CORDB_ADDRESS(const void* ptr) |
19 | { |
20 | SUPPORTS_DAC; |
21 | // Cast a void* to a ULONG is not 64-bit safe and triggers compiler warning C3411. |
22 | // But this is x86 only, so we know it's ok. Use PtrToUlong to do the conversion |
23 | // without invoking the error. |
24 | return (CORDB_ADDRESS)(PtrToUlong(ptr)); |
25 | } |
26 | inline CORDB_ADDRESS PTR_TO_CORDB_ADDRESS(UINT_PTR ptr) |
27 | { |
28 | SUPPORTS_DAC; |
29 | // PtrToUlong |
30 | return (CORDB_ADDRESS)(ULONG)(ptr); |
31 | } |
32 | #else |
33 | #define PTR_TO_CORDB_ADDRESS(_ptr) (CORDB_ADDRESS)(ULONG_PTR)(_ptr) |
34 | #endif //_TARGET_X86_ || _TARGET_ARM_ |
35 | |
36 | #define CORDB_ADDRESS_TO_PTR(_cordb_addr) ((LPVOID)(SIZE_T)(_cordb_addr)) |
37 | |
38 | |
39 | // Determine if an exception record is for a CLR debug event, and get the payload. |
40 | CORDB_ADDRESS IsEventDebuggerNotification(const EXCEPTION_RECORD * pRecord, CORDB_ADDRESS pClrBaseAddress); |
41 | #if defined(FEATURE_DBGIPC_TRANSPORT_DI) || defined(FEATURE_DBGIPC_TRANSPORT_VM) |
42 | struct DebuggerIPCEvent; |
43 | void InitEventForDebuggerNotification(DEBUG_EVENT * pDebugEvent, |
44 | CORDB_ADDRESS pClrBaseAddress, |
45 | DebuggerIPCEvent * pIPCEvent); |
46 | #endif // (FEATURE_DBGIPC_TRANSPORT_DI || FEATURE_DBGIPC_TRANSPORT_VM) |
47 | |
48 | |
49 | void GetPidDecoratedName(__out_z __out_ecount(cBufSizeInChars) WCHAR * pBuf, |
50 | int cBufSizeInChars, |
51 | const WCHAR * pPrefix, |
52 | DWORD pid); |
53 | |
54 | |
55 | // |
56 | // This macro is used in CORDbgCopyThreadContext(). |
57 | // |
58 | // CORDbgCopyThreadContext() does an intelligent copy |
59 | // from pSrc to pDst, respecting the ContextFlags of both contexts. |
60 | // |
61 | #define CopyContextChunk(_t, _f, _end, _flag) \ |
62 | { \ |
63 | LOG((LF_CORDB, LL_INFO1000000, \ |
64 | "CP::CTC: copying " #_flag ":" FMT_ADDR "<---" FMT_ADDR "(%d)\n", \ |
65 | DBG_ADDR(_t), DBG_ADDR(_f), ((UINT_PTR)(_end) - (UINT_PTR)_t))); \ |
66 | memcpy((_t), (_f), ((UINT_PTR)(_end) - (UINT_PTR)(_t))); \ |
67 | } |
68 | |
69 | // |
70 | // CORDbgCopyThreadContext() does an intelligent copy from pSrc to pDst, |
71 | // respecting the ContextFlags of both contexts. |
72 | // |
73 | struct DebuggerREGDISPLAY; |
74 | |
75 | extern void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc); |
76 | extern void CORDbgSetDebuggerREGDISPLAYFromContext(DebuggerREGDISPLAY *pDRD, |
77 | DT_CONTEXT* pContext); |
78 | |
79 | //--------------------------------------------------------------------------------------- |
80 | // |
81 | // Return the size of the CONTEXT required for the specified context flags. |
82 | // |
83 | // Arguments: |
84 | // flags - this is the equivalent of the ContextFlags field of a CONTEXT |
85 | // |
86 | // Return Value: |
87 | // size of the CONTEXT required |
88 | // |
89 | // Notes: |
90 | // On WIN64 platforms this function will always return sizeof(CONTEXT). |
91 | // |
92 | |
93 | inline |
94 | ULONG32 ContextSizeForFlags(ULONG32 flags) |
95 | { |
96 | #if defined(CONTEXT_EXTENDED_REGISTERS) && defined(_TARGET_X86_) |
97 | // Older platforms didn't have extended registers in |
98 | // the context definition so only enforce that size |
99 | // if the extended register flag is set. |
100 | if ((flags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) |
101 | { |
102 | return offsetof(T_CONTEXT, ExtendedRegisters); |
103 | } |
104 | else |
105 | #endif // _TARGET_X86_ |
106 | { |
107 | return sizeof(T_CONTEXT); |
108 | } |
109 | } |
110 | |
111 | //--------------------------------------------------------------------------------------- |
112 | // |
113 | // Given the size of a buffer and the context flags, check whether the buffer is sufficient large |
114 | // to hold the CONTEXT. |
115 | // |
116 | // Arguments: |
117 | // size - size of a buffer |
118 | // flags - this is the equivalent of the ContextFlags field of a CONTEXT |
119 | // |
120 | // Return Value: |
121 | // TRUE if the buffer is large enough to hold the CONTEXT |
122 | // |
123 | |
124 | inline |
125 | BOOL CheckContextSizeForFlags(ULONG32 size, ULONG32 flags) |
126 | { |
127 | return (size >= ContextSizeForFlags(flags)); |
128 | } |
129 | |
130 | //--------------------------------------------------------------------------------------- |
131 | // |
132 | // Given the size of a buffer and the BYTE array representation of a CONTEXT, |
133 | // check whether the buffer is sufficient large to hold the CONTEXT. |
134 | // |
135 | // Arguments: |
136 | // size - size of a buffer |
137 | // flags - this is the equivalent of the ContextFlags field of a CONTEXT |
138 | // |
139 | // Return Value: |
140 | // TRUE if the buffer is large enough to hold the CONTEXT |
141 | // |
142 | |
143 | inline |
144 | BOOL CheckContextSizeForBuffer(ULONG32 size, const BYTE * pbBuffer) |
145 | { |
146 | return ( ( size >= (offsetof(T_CONTEXT, ContextFlags) + sizeof(ULONG32)) ) && |
147 | CheckContextSizeForFlags(size, (reinterpret_cast<const T_CONTEXT *>(pbBuffer))->ContextFlags) ); |
148 | } |
149 | |
150 | /* ------------------------------------------------------------------------- * |
151 | * Constant declarations |
152 | * ------------------------------------------------------------------------- */ |
153 | |
154 | enum |
155 | { |
156 | NULL_THREAD_ID = -1, |
157 | NULL_PROCESS_ID = -1 |
158 | }; |
159 | |
160 | /* ------------------------------------------------------------------------- * |
161 | * Macros |
162 | * ------------------------------------------------------------------------- */ |
163 | |
164 | // |
165 | // CANNOT USE IsBad*Ptr() methods here. They are *banned* APIs because of various |
166 | // reasons (see http://winweb/wincet/bannedapis.htm). |
167 | // |
168 | |
169 | #define VALIDATE_POINTER_TO_OBJECT(ptr, type) \ |
170 | if ((ptr) == NULL) \ |
171 | { \ |
172 | return E_INVALIDARG; \ |
173 | } |
174 | |
175 | #define VALIDATE_POINTER_TO_OBJECT_OR_NULL(ptr, type) |
176 | |
177 | // |
178 | // CANNOT USE IsBad*Ptr() methods here. They are *banned* APIs because of various |
179 | // reasons (see http://winweb/wincet/bannedapis.htm). |
180 | // |
181 | #define VALIDATE_POINTER_TO_OBJECT_ARRAY(ptr, type, cElt, fRead, fWrite) \ |
182 | if ((ptr) == NULL) \ |
183 | { \ |
184 | return E_INVALIDARG; \ |
185 | } |
186 | |
187 | #define VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(ptr, type,cElt,fRead,fWrite) |
188 | |
189 | /* ------------------------------------------------------------------------- * |
190 | * Function Prototypes |
191 | * ------------------------------------------------------------------------- */ |
192 | |
193 | |
194 | |
195 | // Linear search through an array of NativeVarInfos, to find |
196 | // the variable of index dwIndex, valid at the given ip. |
197 | // |
198 | // returns CORDBG_E_IL_VAR_NOT_AVAILABLE if the variable isn't |
199 | // valid at the given ip. |
200 | // |
201 | // This should be inlined |
202 | HRESULT FindNativeInfoInILVariableArray(DWORD dwIndex, |
203 | SIZE_T ip, |
204 | ICorDebugInfo::NativeVarInfo **ppNativeInfo, |
205 | unsigned int nativeInfoCount, |
206 | ICorDebugInfo::NativeVarInfo *nativeInfo); |
207 | |
208 | |
209 | #define VALIDATE_HEAP |
210 | //HeapValidate(GetProcessHeap(), 0, NULL); |
211 | |
212 | // struct DebuggerILToNativeMap: Holds the IL to Native offset map |
213 | // Great pains are taken to ensure that this each entry corresponds to the |
214 | // first IL instruction in a source line. It isn't actually a mapping |
215 | // of _every_ IL instruction in a method, just those for source lines. |
216 | // SIZE_T ilOffset: IL offset of a source line. |
217 | // SIZE_T nativeStartOffset: Offset within the method where the native |
218 | // instructions corresponding to the IL offset begin. |
219 | // SIZE_T nativeEndOffset: Offset within the method where the native |
220 | // instructions corresponding to the IL offset end. |
221 | // |
222 | // Note: any changes to this struct need to be reflected in |
223 | // COR_DEBUG_IL_TO_NATIVE_MAP in CorDebug.idl. These structs must |
224 | // match exactly. |
225 | // |
226 | struct DebuggerILToNativeMap |
227 | { |
228 | ULONG ilOffset; |
229 | ULONG nativeStartOffset; |
230 | ULONG nativeEndOffset; |
231 | ICorDebugInfo::SourceTypes source; |
232 | }; |
233 | |
234 | void ExportILToNativeMap(ULONG32 cMap, |
235 | COR_DEBUG_IL_TO_NATIVE_MAP mapExt[], |
236 | struct DebuggerILToNativeMap mapInt[], |
237 | SIZE_T sizeOfCode); |
238 | |
239 | #include <primitives.h> |
240 | |
241 | // ---------------------------------------------------------------------------- |
242 | // IsPatchInRequestedRange |
243 | // |
244 | // Description: |
245 | // This function checks if a patch falls (fully or partially) in the requested range of memory. |
246 | // |
247 | // Arguments: |
248 | // * requestedAddr - the address of the memory range |
249 | // * requestedSize - the size of the memory range |
250 | // * patchAddr - the address of the patch |
251 | // * pPRD - the opcode of the patch |
252 | // |
253 | // Return Value: |
254 | // Return TRUE if the patch is fully or partially in the requested memory range. |
255 | // |
256 | // Notes: |
257 | // Currently this function is called both from the RS (via code:CordbProcess.ReadMemory and |
258 | // code:CordbProcess.WriteMemory) and from DAC. When we DACize the two functions mentioned above, |
259 | // this function should be called from DAC only, and we should use a MemoryRange here. |
260 | // |
261 | |
262 | inline bool IsPatchInRequestedRange(CORDB_ADDRESS requestedAddr, |
263 | SIZE_T requestedSize, |
264 | CORDB_ADDRESS patchAddr) |
265 | { |
266 | SUPPORTS_DAC; |
267 | |
268 | if (requestedAddr == 0) |
269 | return false; |
270 | |
271 | // Note that patchEnd points to the byte immediately AFTER the patch, so patchEnd is NOT |
272 | // part of the patch. |
273 | CORDB_ADDRESS patchEnd = GetPatchEndAddr(patchAddr); |
274 | |
275 | // We have three cases: |
276 | // 1) the entire patch is in the requested range |
277 | // 2) the beginning of the requested range is covered by the patch |
278 | // 3) the end of the requested range is covered by the patch |
279 | // |
280 | // Note that on x86, since the break instruction only takes up one byte, the following condition |
281 | // degenerates to case 1 only. |
282 | return (((requestedAddr <= patchAddr) && (patchEnd <= (requestedAddr + requestedSize))) || |
283 | ((patchAddr <= requestedAddr) && (requestedAddr < patchEnd)) || |
284 | ((patchAddr <= (requestedAddr + requestedSize - 1)) && ((requestedAddr + requestedSize - 1) < patchEnd))); |
285 | } |
286 | |
287 | inline CORDB_ADDRESS ALIGN_ADDRESS( CORDB_ADDRESS val, CORDB_ADDRESS alignment ) |
288 | { |
289 | LIMITED_METHOD_DAC_CONTRACT; |
290 | |
291 | // alignment must be a power of 2 for this implementation to work (need modulo otherwise) |
292 | _ASSERTE( 0 == (alignment & (alignment - 1)) ); |
293 | CORDB_ADDRESS result = (val + (alignment - 1)) & ~(alignment - 1); |
294 | _ASSERTE( result >= val ); // check for overflow |
295 | return result; |
296 | } |
297 | |
298 | #include "dacprivate.h" // for MSLAYOUT |
299 | #include "dumpcommon.h" |
300 | |
301 | #endif //DEBUGGER_COMMON_H |
302 | |