| 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 | |