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_)
18inline 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}
26inline 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.
40CORDB_ADDRESS IsEventDebuggerNotification(const EXCEPTION_RECORD * pRecord, CORDB_ADDRESS pClrBaseAddress);
41#if defined(FEATURE_DBGIPC_TRANSPORT_DI) || defined(FEATURE_DBGIPC_TRANSPORT_VM)
42struct DebuggerIPCEvent;
43void InitEventForDebuggerNotification(DEBUG_EVENT * pDebugEvent,
44 CORDB_ADDRESS pClrBaseAddress,
45 DebuggerIPCEvent * pIPCEvent);
46#endif // (FEATURE_DBGIPC_TRANSPORT_DI || FEATURE_DBGIPC_TRANSPORT_VM)
47
48
49void 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//
73struct DebuggerREGDISPLAY;
74
75extern void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc);
76extern 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
93inline
94ULONG32 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
124inline
125BOOL 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
143inline
144BOOL 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
154enum
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) \
170if ((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) \
182if ((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
202HRESULT 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//
226struct DebuggerILToNativeMap
227{
228 ULONG ilOffset;
229 ULONG nativeStartOffset;
230 ULONG nativeEndOffset;
231 ICorDebugInfo::SourceTypes source;
232};
233
234void 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
262inline 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
287inline 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