diff options
Diffstat (limited to 'src/debug/inc/common.h')
-rw-r--r-- | src/debug/inc/common.h | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/src/debug/inc/common.h b/src/debug/inc/common.h new file mode 100644 index 0000000000..4f2ea390af --- /dev/null +++ b/src/debug/inc/common.h @@ -0,0 +1,324 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef DEBUGGER_COMMON_H +#define DEBUGGER_COMMON_H + +// +// Conversions between pointers and CORDB_ADDRESS +// These are 3gb safe - we use zero-extension for CORDB_ADDRESS. +// Note that this is a different semantics from CLRDATA_ADDRESS which is sign-extended. +// +// @dbgtodo : This confuses the host and target address spaces. Ideally we'd have +// conversions between PTR types (eg. DPTR) and CORDB_ADDRESS, and not need conversions +// from host pointer types to CORDB_ADDRESS. +// +#if defined(_TARGET_X86_) || defined(_TARGET_ARM_) +inline CORDB_ADDRESS PTR_TO_CORDB_ADDRESS(const void* ptr) +{ + SUPPORTS_DAC; + // Cast a void* to a ULONG is not 64-bit safe and triggers compiler warning C3411. + // But this is x86 only, so we know it's ok. Use PtrToUlong to do the conversion + // without invoking the error. + return (CORDB_ADDRESS)(PtrToUlong(ptr)); +} +inline CORDB_ADDRESS PTR_TO_CORDB_ADDRESS(UINT_PTR ptr) +{ + SUPPORTS_DAC; + // PtrToUlong + return (CORDB_ADDRESS)(ULONG)(ptr); +} +#else +#define PTR_TO_CORDB_ADDRESS(_ptr) (CORDB_ADDRESS)(ULONG_PTR)(_ptr) +#endif //_TARGET_X86_ || _TARGET_ARM_ + +#define CORDB_ADDRESS_TO_PTR(_cordb_addr) ((LPVOID)(SIZE_T)(_cordb_addr)) + + +// Determine if an exception record is for a CLR debug event, and get the payload. +CORDB_ADDRESS IsEventDebuggerNotification(const EXCEPTION_RECORD * pRecord, CORDB_ADDRESS pClrBaseAddress); +#if defined(FEATURE_DBGIPC_TRANSPORT_DI) || defined(FEATURE_DBGIPC_TRANSPORT_VM) +struct DebuggerIPCEvent; +void InitEventForDebuggerNotification(DEBUG_EVENT * pDebugEvent, + CORDB_ADDRESS pClrBaseAddress, + DebuggerIPCEvent * pIPCEvent); +#endif // (FEATURE_DBGIPC_TRANSPORT_DI || FEATURE_DBGIPC_TRANSPORT_VM) + + +void GetPidDecoratedName(__out_z __out_ecount(cBufSizeInChars) WCHAR * pBuf, + int cBufSizeInChars, + const WCHAR * pPrefix, + DWORD pid); + + +// +// This macro is used in CORDbgCopyThreadContext(). +// +// CORDbgCopyThreadContext() does an intelligent copy +// from pSrc to pDst, respecting the ContextFlags of both contexts. +// +#define CopyContextChunk(_t, _f, _end, _flag) \ +{ \ + LOG((LF_CORDB, LL_INFO1000000, \ + "CP::CTC: copying " #_flag ":" FMT_ADDR "<---" FMT_ADDR "(%d)\n", \ + DBG_ADDR(_t), DBG_ADDR(_f), ((UINT_PTR)(_end) - (UINT_PTR)_t))); \ + memcpy((_t), (_f), ((UINT_PTR)(_end) - (UINT_PTR)(_t))); \ +} + +// +// CORDbgCopyThreadContext() does an intelligent copy from pSrc to pDst, +// respecting the ContextFlags of both contexts. +// +struct DebuggerREGDISPLAY; + +extern void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc); +extern void CORDbgSetDebuggerREGDISPLAYFromContext(DebuggerREGDISPLAY *pDRD, + DT_CONTEXT* pContext); + +//--------------------------------------------------------------------------------------- +// +// Return the size of the CONTEXT required for the specified context flags. +// +// Arguments: +// flags - this is the equivalent of the ContextFlags field of a CONTEXT +// +// Return Value: +// size of the CONTEXT required +// +// Notes: +// On WIN64 platforms this function will always return sizeof(CONTEXT). +// + +inline +ULONG32 ContextSizeForFlags(ULONG32 flags) +{ +#if defined(CONTEXT_EXTENDED_REGISTERS) && defined(_TARGET_X86_) + // Older platforms didn't have extended registers in + // the context definition so only enforce that size + // if the extended register flag is set. + if ((flags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) + { + return offsetof(T_CONTEXT, ExtendedRegisters); + } + else +#endif // _TARGET_X86_ + { + return sizeof(T_CONTEXT); + } +} + +//--------------------------------------------------------------------------------------- +// +// Given the size of a buffer and the context flags, check whether the buffer is sufficient large +// to hold the CONTEXT. +// +// Arguments: +// size - size of a buffer +// flags - this is the equivalent of the ContextFlags field of a CONTEXT +// +// Return Value: +// TRUE if the buffer is large enough to hold the CONTEXT +// + +inline +BOOL CheckContextSizeForFlags(ULONG32 size, ULONG32 flags) +{ + return (size >= ContextSizeForFlags(flags)); +} + +//--------------------------------------------------------------------------------------- +// +// Given the size of a buffer and the BYTE array representation of a CONTEXT, +// check whether the buffer is sufficient large to hold the CONTEXT. +// +// Arguments: +// size - size of a buffer +// flags - this is the equivalent of the ContextFlags field of a CONTEXT +// +// Return Value: +// TRUE if the buffer is large enough to hold the CONTEXT +// + +inline +BOOL CheckContextSizeForBuffer(ULONG32 size, const BYTE * pbBuffer) +{ + return ( ( size >= (offsetof(T_CONTEXT, ContextFlags) + sizeof(ULONG32)) ) && + CheckContextSizeForFlags(size, (reinterpret_cast<const T_CONTEXT *>(pbBuffer))->ContextFlags) ); +} + +/* ------------------------------------------------------------------------- * + * Constant declarations + * ------------------------------------------------------------------------- */ + +enum +{ + NULL_THREAD_ID = -1, + NULL_PROCESS_ID = -1 +}; + +/* ------------------------------------------------------------------------- * + * Macros + * ------------------------------------------------------------------------- */ + +// +// CANNOT USE IsBad*Ptr() methods here. They are *banned* APIs because of various +// reasons (see http://winweb/wincet/bannedapis.htm). +// + +#define VALIDATE_POINTER_TO_OBJECT(ptr, type) \ +if ((ptr) == NULL) \ +{ \ + return E_INVALIDARG; \ +} + +#define VALIDATE_POINTER_TO_OBJECT_OR_NULL(ptr, type) + +// +// CANNOT USE IsBad*Ptr() methods here. They are *banned* APIs because of various +// reasons (see http://winweb/wincet/bannedapis.htm). +// +#define VALIDATE_POINTER_TO_OBJECT_ARRAY(ptr, type, cElt, fRead, fWrite) \ +if ((ptr) == NULL) \ +{ \ + return E_INVALIDARG; \ +} + +#define VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(ptr, type,cElt,fRead,fWrite) + +/* ------------------------------------------------------------------------- * + * Function Prototypes + * ------------------------------------------------------------------------- */ + + + +// Linear search through an array of NativeVarInfos, to find +// the variable of index dwIndex, valid at the given ip. +// +// returns CORDBG_E_IL_VAR_NOT_AVAILABLE if the variable isn't +// valid at the given ip. +// +// This should be inlined +HRESULT FindNativeInfoInILVariableArray(DWORD dwIndex, + SIZE_T ip, + ICorDebugInfo::NativeVarInfo **ppNativeInfo, + unsigned int nativeInfoCount, + ICorDebugInfo::NativeVarInfo *nativeInfo); + + +#define VALIDATE_HEAP +//HeapValidate(GetProcessHeap(), 0, NULL); + +// struct DebuggerILToNativeMap: Holds the IL to Native offset map +// Great pains are taken to ensure that this each entry corresponds to the +// first IL instruction in a source line. It isn't actually a mapping +// of _every_ IL instruction in a method, just those for source lines. +// SIZE_T ilOffset: IL offset of a source line. +// SIZE_T nativeStartOffset: Offset within the method where the native +// instructions corresponding to the IL offset begin. +// SIZE_T nativeEndOffset: Offset within the method where the native +// instructions corresponding to the IL offset end. +// +// Note: any changes to this struct need to be reflected in +// COR_DEBUG_IL_TO_NATIVE_MAP in CorDebug.idl. These structs must +// match exactly. +// +struct DebuggerILToNativeMap +{ + ULONG ilOffset; + ULONG nativeStartOffset; + ULONG nativeEndOffset; + ICorDebugInfo::SourceTypes source; +}; + +void ExportILToNativeMap(ULONG32 cMap, + COR_DEBUG_IL_TO_NATIVE_MAP mapExt[], + struct DebuggerILToNativeMap mapInt[], + SIZE_T sizeOfCode); + +#include <primitives.h> + +// ---------------------------------------------------------------------------- +// IsPatchInRequestedRange +// +// Description: +// This function checks if a patch falls (fully or partially) in the requested range of memory. +// +// Arguments: +// * requestedAddr - the address of the memory range +// * requestedSize - the size of the memory range +// * patchAddr - the address of the patch +// * pPRD - the opcode of the patch +// +// Return Value: +// Return TRUE if the patch is fully or partially in the requested memory range. +// +// Notes: +// Currently this function is called both from the RS (via code:CordbProcess.ReadMemory and +// code:CordbProcess.WriteMemory) and from DAC. When we DACize the two functions mentioned above, +// this function should be called from DAC only, and we should use a MemoryRange here. +// + +inline bool IsPatchInRequestedRange(CORDB_ADDRESS requestedAddr, + SIZE_T requestedSize, + CORDB_ADDRESS patchAddr) +{ + SUPPORTS_DAC; + + if (requestedAddr == 0) + return false; + + // Note that patchEnd points to the byte immediately AFTER the patch, so patchEnd is NOT + // part of the patch. + CORDB_ADDRESS patchEnd = GetPatchEndAddr(patchAddr); + + // We have three cases: + // 1) the entire patch is in the requested range + // 2) the beginning of the requested range is covered by the patch + // 3) the end of the requested range is covered by the patch + // + // Note that on x86, since the break instruction only takes up one byte, the following condition + // degenerates to case 1 only. + return (((requestedAddr <= patchAddr) && (patchEnd <= (requestedAddr + requestedSize))) || + ((patchAddr <= requestedAddr) && (requestedAddr < patchEnd)) || + ((patchAddr <= (requestedAddr + requestedSize - 1)) && ((requestedAddr + requestedSize - 1) < patchEnd))); +} + +inline CORDB_ADDRESS ALIGN_ADDRESS( CORDB_ADDRESS val, CORDB_ADDRESS alignment ) +{ + LIMITED_METHOD_DAC_CONTRACT; + + // alignment must be a power of 2 for this implementation to work (need modulo otherwise) + _ASSERTE( 0 == (alignment & (alignment - 1)) ); + CORDB_ADDRESS result = (val + (alignment - 1)) & ~(alignment - 1); + _ASSERTE( result >= val ); // check for overflow + return result; +} + +// +// Whenever a structure is marshalled between different platforms, we need to ensure the +// layout is the same in both cases. We tell GCC to use the MSVC-style packing with +// the following attribute. The main thing this appears to control is whether +// 8-byte values are aligned at 4-bytes (GCC default) or 8-bytes (MSVC default). +// This attribute affects only the immediate struct it is applied to, you must also apply +// it to any nested structs if you want their layout affected as well. You also must +// apply this to unions embedded in other structures, since it can influence the starting +// alignment. +// +// Note that there doesn't appear to be any disadvantage to applying this a little +// more agressively than necessary, so we generally use it on all classes / structures +// defined in a file that defines marshalled data types (eg. DacDbiStructures.h) +// The -mms-bitfields compiler option also does this for the whole file, but we don't +// want to go changing the layout of, for example, structures defined in OS header files +// so we explicitly opt-in with this attribute. +// +#ifdef __GNUC__ +#define MSLAYOUT __attribute__((__ms_struct__)) +#else +#define MSLAYOUT +#endif + +#include "dumpcommon.h" + +#endif //DEBUGGER_COMMON_H |