diff options
Diffstat (limited to 'src/ToolBox/SOS/Strike/util.h')
-rw-r--r-- | src/ToolBox/SOS/Strike/util.h | 3222 |
1 files changed, 0 insertions, 3222 deletions
diff --git a/src/ToolBox/SOS/Strike/util.h b/src/ToolBox/SOS/Strike/util.h deleted file mode 100644 index 55c822e150..0000000000 --- a/src/ToolBox/SOS/Strike/util.h +++ /dev/null @@ -1,3222 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// ==++== -// - -// -// ==--== -#ifndef __util_h__ -#define __util_h__ - -#define LIMITED_METHOD_CONTRACT - -// So we can use the PAL_TRY_NAKED family of macros without dependencies on utilcode. -inline void RestoreSOToleranceState() {} - -#include <cor.h> -#include <corsym.h> -#include <clrdata.h> -#include <palclr.h> -#include <metahost.h> -#include <new> - -#if !defined(FEATURE_PAL) -#include <dia2.h> -#endif - -#ifdef STRIKE -#if defined(_MSC_VER) -#pragma warning(disable:4200) -#pragma warning(default:4200) -#endif -#include "data.h" -#endif //STRIKE - -#include "cordebug.h" -#include "static_assert.h" - -typedef LPCSTR LPCUTF8; -typedef LPSTR LPUTF8; - -DECLARE_HANDLE(OBJECTHANDLE); - -struct IMDInternalImport; - -#if defined(_TARGET_WIN64_) -#define WIN64_8SPACES "" -#define WIN86_8SPACES " " -#define POINTERSIZE "16" -#define POINTERSIZE_HEX 16 -#define POINTERSIZE_BYTES 8 -#define POINTERSIZE_TYPE "I64" -#else -#define WIN64_8SPACES " " -#define WIN86_8SPACES "" -#define POINTERSIZE "8" -#define POINTERSIZE_HEX 8 -#define POINTERSIZE_BYTES 4 -#define POINTERSIZE_TYPE "I32" -#endif - -#ifndef TARGET_POINTER_SIZE -#define TARGET_POINTER_SIZE POINTERSIZE_BYTES -#endif // TARGET_POINTER_SIZE - -#if defined(_MSC_VER) -#pragma warning(disable:4510 4512 4610) -#endif - -#ifndef _ASSERTE -#ifdef _DEBUG -#define _ASSERTE(expr) \ - do { if (!(expr) ) { ExtErr("_ASSERTE fired:\n\t%s\n", #expr); if (IsDebuggerPresent()) DebugBreak(); } } while (0) -#else -#define _ASSERTE(x) -#endif -#endif // ASSERTE - -#ifdef _DEBUG -#define ASSERT_CHECK(expr, msg, reason) \ - do { if (!(expr) ) { ExtOut(reason); ExtOut(msg); ExtOut(#expr); DebugBreak(); } } while (0) -#endif - -// The native symbol reader dll name -#if defined(_AMD64_) -#define NATIVE_SYMBOL_READER_DLL W("Microsoft.DiaSymReader.Native.amd64.dll") -#elif defined(_X86_) -#define NATIVE_SYMBOL_READER_DLL W("Microsoft.DiaSymReader.Native.x86.dll") -#elif defined(_ARM_) -#define NATIVE_SYMBOL_READER_DLL W("Microsoft.DiaSymReader.Native.arm.dll") -#elif defined(_ARM64_) -// Use diasymreader until the package has an arm64 version - issue #7360 -//#define NATIVE_SYMBOL_READER_DLL W("Microsoft.DiaSymReader.Native.arm64.dll") -#define NATIVE_SYMBOL_READER_DLL W("diasymreader.dll") -#endif - -// PREFIX macros - Begin - -// SOS does not have support for Contracts. Therefore we needed to duplicate -// some of the PREFIX infrastructure from inc\check.h in here. - -// Issue - PREFast_:510 v4.51 does not support __assume(0) -#if (defined(_MSC_VER) && !defined(_PREFAST_)) || defined(_PREFIX_) -#if defined(_AMD64_) -// Empty methods that consist of UNREACHABLE() result in a zero-sized declspec(noreturn) method -// which causes the pdb file to make the next method declspec(noreturn) as well, thus breaking BBT -// Remove when we get a VC compiler that fixes VSW 449170 -# define __UNREACHABLE() DebugBreak(); __assume(0); -#else -# define __UNREACHABLE() __assume(0) -#endif -#else -#define __UNREACHABLE() do { } while(true) -#endif - - -#if defined(_PREFAST_) || defined(_PREFIX_) -#define COMPILER_ASSUME_MSG(_condition, _message) if (!(_condition)) __UNREACHABLE(); -#else - -#if defined(DACCESS_COMPILE) -#define COMPILER_ASSUME_MSG(_condition, _message) do { } while (0) -#else - -#if defined(_DEBUG) -#define COMPILER_ASSUME_MSG(_condition, _message) \ - ASSERT_CHECK(_condition, _message, "Compiler optimization assumption invalid") -#else -#define COMPILER_ASSUME_MSG(_condition, _message) __assume(_condition) -#endif // _DEBUG - -#endif // DACCESS_COMPILE - -#endif // _PREFAST_ || _PREFIX_ - -#define PREFIX_ASSUME(_condition) \ - COMPILER_ASSUME_MSG(_condition, "") - -// PREFIX macros - End - -class MethodTable; - -#define MD_NOT_YET_LOADED ((DWORD_PTR)-1) -/* - * HANDLES - * - * The default type of handle is a strong handle. - * - */ -#define HNDTYPE_DEFAULT HNDTYPE_STRONG -#define HNDTYPE_WEAK_DEFAULT HNDTYPE_WEAK_LONG -#define HNDTYPE_WEAK_SHORT (0) -#define HNDTYPE_WEAK_LONG (1) -#define HNDTYPE_STRONG (2) -#define HNDTYPE_PINNED (3) -#define HNDTYPE_VARIABLE (4) -#define HNDTYPE_REFCOUNTED (5) -#define HNDTYPE_DEPENDENT (6) -#define HNDTYPE_ASYNCPINNED (7) -#define HNDTYPE_SIZEDREF (8) -#define HNDTYPE_WEAK_WINRT (9) - -// Anything above this we consider abnormal and stop processing heap information -const int nMaxHeapSegmentCount = 1000; - -class BaseObject -{ - MethodTable *m_pMethTab; -}; - - -const BYTE gElementTypeInfo[] = { -#define TYPEINFO(e,ns,c,s,g,ia,ip,if,im,gv) s, -#include "cortypeinfo.h" -#undef TYPEINFO -}; - -typedef struct tagLockEntry -{ - tagLockEntry *pNext; // next entry - tagLockEntry *pPrev; // prev entry - DWORD dwULockID; - DWORD dwLLockID; // owning lock - WORD wReaderLevel; // reader nesting level -} LockEntry; - -#define MAX_CLASSNAME_LENGTH 1024 - -enum EEFLAVOR {UNKNOWNEE, MSCOREE, MSCORWKS, MSCOREND}; - -#include "sospriv.h" -extern IXCLRDataProcess *g_clrData; -extern ISOSDacInterface *g_sos; - -#include "dacprivate.h" - -interface ICorDebugProcess; -extern ICorDebugProcess * g_pCorDebugProcess; - -// This class is templated for easy modification. We may need to update the CachedString -// or related classes to use WCHAR instead of char in the future. -template <class T, int count, int size> -class StaticData -{ -public: - StaticData() - { - for (int i = 0; i < count; ++i) - InUse[i] = false; - } - - // Whether the individual data pointers in the cache are in use. - bool InUse[count]; - - // The actual data itself. - T Data[count][size]; - - // The number of arrays in the cache. - static const int Count; - - // The size of each individual array. - static const int Size; -}; - -class CachedString -{ -public: - CachedString(); - CachedString(const CachedString &str); - ~CachedString(); - - const CachedString &operator=(const CachedString &str); - - // Returns the capacity of this string. - size_t GetStrLen() const - { - return mSize; - } - - // Returns a mutable character pointer. Be sure not to write past the - // length of this string. - inline operator char *() - { - return mPtr; - } - - // Returns a const char representation of this string. - inline operator const char *() const - { - return GetPtr(); - } - - // To ensure no AV's, any time a constant pointer is requested, we will - // return an empty string "" if we hit an OOM. This will only happen - // if we hit an OOM and do not check for it before using the string. - // If you request a non-const char pointer out of this class, it may be - // null (see operator char *). - inline const char *GetPtr() const - { - if (!mPtr || IsOOM()) - return ""; - - return mPtr; - } - - // Returns true if we ran out of memory trying to allocate the string - // or the refcount. - bool IsOOM() const - { - return mIndex == -2; - } - - // allocate a string of the specified size. this will Clear() any - // previously allocated string. call IsOOM() to check for failure. - void Allocate(int size); - -private: - // Copies rhs into this string. - void Copy(const CachedString &rhs); - - // Clears this string, releasing any underlying memory. - void Clear(); - - // Creates a new string. - void Create(); - - // Sets an out of memory state. - void SetOOM(); - -private: - char *mPtr; - - // The reference count. This may be null if there is only one copy - // of this string. - mutable unsigned int *mRefCount; - - // mIndex contains the index of the cached pointer we are using, or: - // ~0 - poison value we initialize it to for debugging purposes - // -1 - mPtr points to a pointer we have new'ed - // -2 - We hit an oom trying to allocate either mCount or mPtr - int mIndex; - - // contains the size of current string - int mSize; - -private: - static StaticData<char, 4, 1024> cache; -}; - -// Things in this namespace should not be directly accessed/called outside of -// the output-related functions. -namespace Output -{ - extern unsigned int g_bSuppressOutput; - extern unsigned int g_Indent; - extern unsigned int g_DMLEnable; - extern bool g_bDbgOutput; - extern bool g_bDMLExposed; - - inline bool IsOutputSuppressed() - { return g_bSuppressOutput > 0; } - - inline void ResetIndent() - { g_Indent = 0; } - - inline void SetDebugOutputEnabled(bool enabled) - { g_bDbgOutput = enabled; } - - inline bool IsDebugOutputEnabled() - { return g_bDbgOutput; } - - inline void SetDMLExposed(bool exposed) - { g_bDMLExposed = exposed; } - - inline bool IsDMLExposed() - { return g_bDMLExposed; } - - enum FormatType - { - DML_None, - DML_MethodTable, - DML_MethodDesc, - DML_EEClass, - DML_Module, - DML_IP, - DML_Object, - DML_Domain, - DML_Assembly, - DML_ThreadID, - DML_ValueClass, - DML_DumpHeapMT, - DML_ListNearObj, - DML_ThreadState, - DML_PrintException, - DML_RCWrapper, - DML_CCWrapper, - DML_ManagedVar, - DML_Async, - }; - - /**********************************************************************\ - * This function builds a DML string for a ValueClass. If DML is * - * enabled, this function returns a DML string based on the format * - * type. Otherwise this returns a string containing only the hex value * - * of addr. * - * * - * Params: * - * mt - the method table of the ValueClass * - * addr - the address of the ValueClass * - * type - the format type to use to output this object * - * fill - whether or not to pad the hex value with zeros * - * * - \**********************************************************************/ - CachedString BuildVCValue(CLRDATA_ADDRESS mt, CLRDATA_ADDRESS addr, FormatType type, bool fill = true); - - - /**********************************************************************\ - * This function builds a DML string for an object. If DML is enabled, * - * this function returns a DML string based on the format type. * - * Otherwise this returns a string containing only the hex value of * - * addr. * - * * - * Params: * - * addr - the address of the object * - * type - the format type to use to output this object * - * fill - whether or not to pad the hex value with zeros * - * * - \**********************************************************************/ - CachedString BuildHexValue(CLRDATA_ADDRESS addr, FormatType type, bool fill = true); - - /**********************************************************************\ - * This function builds a DML string for an managed variable name. * - * If DML is enabled, this function returns a DML string that will * - * enable the expansion of that managed variable using the !ClrStack * - * command to display the variable's fields, otherwise it will just * - * return the variable's name as a string. - * * - * Params: * - * expansionName - the current variable expansion string * - * frame - the frame that contains the variable of interest * - * simpleName - simple name of the managed variable * - * * - \**********************************************************************/ - CachedString BuildManagedVarValue(__in_z LPCWSTR expansionName, ULONG frame, __in_z LPCWSTR simpleName, FormatType type); - CachedString BuildManagedVarValue(__in_z LPCWSTR expansionName, ULONG frame, int indexInArray, FormatType type); //used for array indices (simpleName = "[<indexInArray>]") -} - -class NoOutputHolder -{ -public: - NoOutputHolder(BOOL bSuppress = TRUE); - ~NoOutputHolder(); - -private: - BOOL mSuppress; -}; - -class EnableDMLHolder -{ -public: - EnableDMLHolder(BOOL enable); - ~EnableDMLHolder(); - -private: - BOOL mEnable; -}; - -size_t CountHexCharacters(CLRDATA_ADDRESS val); - -// Normal output. -void DMLOut(PCSTR format, ...); /* Prints out DML strings. */ -void IfDMLOut(PCSTR format, ...); /* Prints given DML string ONLY if DML is enabled; prints nothing otherwise. */ -void ExtOut(PCSTR Format, ...); /* Prints out to ExtOut (no DML). */ -void ExtWarn(PCSTR Format, ...); /* Prints out to ExtWarn (no DML). */ -void ExtErr(PCSTR Format, ...); /* Prints out to ExtErr (no DML). */ -void ExtDbgOut(PCSTR Format, ...); /* Prints out to ExtOut in a checked build (no DML). */ -void WhitespaceOut(int count); /* Prints out "count" number of spaces in the output. */ - -// Change indent for ExtOut -inline void IncrementIndent() { Output::g_Indent++; } -inline void DecrementIndent() { if (Output::g_Indent > 0) Output::g_Indent--; } -inline void ExtOutIndent() { WhitespaceOut(Output::g_Indent << 2); } - -// DML Generation Methods -#define DMLListNearObj(addr) Output::BuildHexValue(addr, Output::DML_ListNearObj).GetPtr() -#define DMLDumpHeapMT(addr) Output::BuildHexValue(addr, Output::DML_DumpHeapMT).GetPtr() -#define DMLMethodTable(addr) Output::BuildHexValue(addr, Output::DML_MethodTable).GetPtr() -#define DMLMethodDesc(addr) Output::BuildHexValue(addr, Output::DML_MethodDesc).GetPtr() -#define DMLClass(addr) Output::BuildHexValue(addr, Output::DML_EEClass).GetPtr() -#define DMLModule(addr) Output::BuildHexValue(addr, Output::DML_Module).GetPtr() -#define DMLIP(ip) Output::BuildHexValue(ip, Output::DML_IP).GetPtr() -#define DMLObject(addr) Output::BuildHexValue(addr, Output::DML_Object).GetPtr() -#define DMLDomain(addr) Output::BuildHexValue(addr, Output::DML_Domain).GetPtr() -#define DMLAssembly(addr) Output::BuildHexValue(addr, Output::DML_Assembly).GetPtr() -#define DMLThreadID(id) Output::BuildHexValue(id, Output::DML_ThreadID, false).GetPtr() -#define DMLValueClass(mt, addr) Output::BuildVCValue(mt, addr, Output::DML_ValueClass).GetPtr() -#define DMLRCWrapper(addr) Output::BuildHexValue(addr, Output::DML_RCWrapper).GetPtr() -#define DMLCCWrapper(addr) Output::BuildHexValue(addr, Output::DML_CCWrapper).GetPtr() -#define DMLManagedVar(expansionName,frame,simpleName) Output::BuildManagedVarValue(expansionName, frame, simpleName, Output::DML_ManagedVar).GetPtr() -#define DMLAsync(addr) Output::BuildHexValue(addr, Output::DML_Async).GetPtr() - -bool IsDMLEnabled(); - - -#ifndef SOS_Assert -#define SOS_Assert(x) -#endif - -void ConvertToLower(__out_ecount(len) char *buffer, size_t len); - -extern const char * const DMLFormats[]; -int GetHex(CLRDATA_ADDRESS addr, __out_ecount(len) char *out, size_t len, bool fill); - -// A simple string class for mutable strings. We cannot use STL, so this is a stand in replacement -// for std::string (though it doesn't use the same interface). -template <class T, size_t (__cdecl *LEN)(const T *), errno_t (__cdecl *COPY)(T *, size_t, const T * _Src)> -class BaseString -{ -public: - BaseString() - : mStr(0), mSize(0), mLength(0) - { - const size_t size = 64; - - mStr = new T[size]; - mSize = size; - mStr[0] = 0; - } - - BaseString(const T *str) - : mStr(0), mSize(0), mLength(0) - { - CopyFrom(str, LEN(str)); - } - - BaseString(const BaseString<T, LEN, COPY> &rhs) - : mStr(0), mSize(0), mLength(0) - { - *this = rhs; - } - - ~BaseString() - { - Clear(); - } - - const BaseString<T, LEN, COPY> &operator=(const BaseString<T, LEN, COPY> &rhs) - { - Clear(); - CopyFrom(rhs.mStr, rhs.mLength); - return *this; - } - - const BaseString<T, LEN, COPY> &operator=(const T *str) - { - Clear(); - CopyFrom(str, LEN(str)); - return *this; - } - - const BaseString<T, LEN, COPY> &operator +=(const T *str) - { - size_t len = LEN(str); - CopyFrom(str, len); - return *this; - } - - const BaseString<T, LEN, COPY> &operator +=(const BaseString<T, LEN, COPY> &str) - { - CopyFrom(str.mStr, str.mLength); - return *this; - } - - BaseString<T, LEN, COPY> operator+(const T *str) const - { - return BaseString<T, LEN, COPY>(mStr, mLength, str, LEN(str)); - } - - BaseString<T, LEN, COPY> operator+(const BaseString<T, LEN, COPY> &str) const - { - return BaseString<T, LEN, COPY>(mStr, mLength, str.mStr, str.mLength); - } - - operator const T *() const - { - return mStr; - } - - const T *c_str() const - { - return mStr; - } - - size_t GetLength() const - { - return mLength; - } - -private: - BaseString(const T * str1, size_t len1, const T * str2, size_t len2) - : mStr(0), mSize(0), mLength(0) - { - const size_t size = len1 + len2 + 1 + ((len1 + len2) >> 1); - mStr = new T[size]; - mSize = size; - - CopyFrom(str1, len1); - CopyFrom(str2, len2); - } - - void Clear() - { - mLength = 0; - mSize = 0; - if (mStr) - { - delete [] mStr; - mStr = 0; - } - } - - void CopyFrom(const T *str, size_t len) - { - if (mLength + len + 1 >= mSize) - Resize(mLength + len + 1); - - COPY(mStr+mLength, mSize-mLength, str); - mLength += len; - } - - void Resize(size_t size) - { - /* We always resize at least one half bigger than we need. When CopyFrom requests a resize - * it asks for the exact size that's needed to concatenate strings. However in practice - * it's common to add multiple strings together in a row, e.g.: - * String foo = "One " + "Two " + "Three " + "Four " + "\n"; - * Ensuring the size of the string is bigger than we need, and that the minimum size is 64, - * we will cut down on a lot of needless resizes at the cost of a few bytes wasted in some - * cases. - */ - size += size >> 1; - if (size < 64) - size = 64; - - T *newStr = new T[size]; - - if (mStr) - { - COPY(newStr, size, mStr); - delete [] mStr; - } - else - { - newStr[0] = 0; - } - - mStr = newStr; - mSize = size; - } -private: - T *mStr; - size_t mSize, mLength; -}; - -typedef BaseString<char, strlen, strcpy_s> String; -typedef BaseString<WCHAR, _wcslen, wcscpy_s> WString; - - -template<class T> -void Flatten(__out_ecount(len) T *data, unsigned int len) -{ - for (unsigned int i = 0; i < len; ++i) - if (data[i] < 32 || (data[i] > 126 && data[i] <= 255)) - data[i] = '.'; - data[len] = 0; -} - -void Flatten(__out_ecount(len) char *data, unsigned int len); - -/* Formats for the Format class. We support the following formats: - * Pointer - Same as %p. - * Hex - Same as %x (same as %p, but does not output preceding zeros. - * PrefixHex - Same as %x, but prepends 0x. - * Decimal - Same as %d. - * Strings and wide strings don't use this. - */ -class Formats -{ -public: - enum Format - { - Default, - Pointer, - Hex, - PrefixHex, - Decimal, - }; -}; - -enum Alignment -{ - AlignLeft, - AlignRight -}; - -namespace Output -{ - /* Defines how a value will be printed. This class understands how to format - * and print values according to the format and DML settings provided. - * The raw templated class handles the pointer/integer case. Support for - * character arrays and wide character arrays are handled by template - * specializations. - * - * Note that this class is not used directly. Instead use the typedefs and - * macros which define the type of data you are outputing (for example ObjectPtr, - * MethodTablePtr, etc). - */ - template <class T> - class Format - { - public: - Format(T value) - : mValue(value), mFormat(Formats::Default), mDml(Output::DML_None) - { - } - - Format(T value, Formats::Format format, Output::FormatType dmlType) - : mValue(value), mFormat(format), mDml(dmlType) - { - } - - Format(const Format<T> &rhs) - : mValue(rhs.mValue), mFormat(rhs.mFormat), mDml(rhs.mDml) - { - } - - /* Prints out the value according to the Format and DML settings provided. - */ - void Output() const - { - if (IsDMLEnabled() && mDml != Output::DML_None) - { - const int len = GetDMLWidth(mDml); - char *buffer = (char*)alloca(len); - - BuildDML(buffer, len, (CLRDATA_ADDRESS)mValue, mFormat, mDml); - DMLOut(buffer); - } - else - { - if (mFormat == Formats::Default || mFormat == Formats::Pointer) - { - ExtOut("%p", SOS_PTR(mValue)); - } - else - { - const char *format = NULL; - if (mFormat == Formats::PrefixHex) - { - format = "0x%x"; - } - else if (mFormat == Formats::Hex) - { - format = "%x"; - } - else if (mFormat == Formats::Decimal) - { - format = "%d"; - } - - ExtOut(format, (__int32)mValue); - } - - } - } - - /* Prints out the value based on a specified width and alignment. - * Params: - * align - Whether the output should be left or right justified. - * width - The output width to fill. - * Note: - * This function guarantees that exactly width will be printed out (so if width is 24, - * exactly 24 characters will be printed), even if the output wouldn't normally fit - * in the space provided. This function makes no guarantees as to what part of the - * data will be printed in the case that width isn't wide enough. - */ - void OutputColumn(Alignment align, int width) const - { - bool leftAlign = align == AlignLeft; - if (IsDMLEnabled() && mDml != Output::DML_None) - { - const int len = GetDMLColWidth(mDml, width); - char *buffer = (char*)alloca(len); - - BuildDMLCol(buffer, len, (CLRDATA_ADDRESS)mValue, mFormat, mDml, leftAlign, width); - DMLOut(buffer); - } - else - { - int precision = GetPrecision(); - if (mFormat == Formats::Default || mFormat == Formats::Pointer) - { - if (precision > width) - precision = width; - - ExtOut(leftAlign ? "%-*.*p" : "%*.*p", width, precision, SOS_PTR(mValue)); - } - else - { - const char *format = NULL; - if (mFormat == Formats::PrefixHex) - { - format = leftAlign ? "0x%-*.*x" : "0x%*.*x"; - width -= 2; - } - else if (mFormat == Formats::Hex) - { - format = leftAlign ? "%-*.*x" : "%*.*x"; - } - else if (mFormat == Formats::Decimal) - { - format = leftAlign ? "%-*.*d" : "%*.*d"; - } - - if (precision > width) - precision = width; - - ExtOut(format, width, precision, (__int32)mValue); - } - } - } - - /* Converts this object into a Wide char string. This allows you to write the following code: - * WString foo = L"bar " + ObjectPtr(obj); - * Where ObjectPtr is a subclass/typedef of this Format class. - */ - operator WString() const - { - String str = *this; - const char *cstr = (const char *)str; - - int len = MultiByteToWideChar(CP_ACP, 0, cstr, -1, NULL, 0); - WCHAR *buffer = (WCHAR *)alloca(len*sizeof(WCHAR)); - - MultiByteToWideChar(CP_ACP, 0, cstr, -1, buffer, len); - - return WString(buffer); - } - - /* Converts this object into a String object. This allows you to write the following code: - * String foo = "bar " + ObjectPtr(obj); - * Where ObjectPtr is a subclass/typedef of this Format class. - */ - operator String() const - { - if (IsDMLEnabled() && mDml != Output::DML_None) - { - const int len = GetDMLColWidth(mDml, 0); - char *buffer = (char*)alloca(len); - - BuildDMLCol(buffer, len, (CLRDATA_ADDRESS)mValue, mFormat, mDml, false, 0); - return buffer; - } - else - { - char buffer[64]; - if (mFormat == Formats::Default || mFormat == Formats::Pointer) - { - sprintf_s(buffer, _countof(buffer), "%p", (int *)(SIZE_T)mValue); - ConvertToLower(buffer, _countof(buffer)); - } - else - { - const char *format = NULL; - if (mFormat == Formats::PrefixHex) - format = "0x%x"; - else if (mFormat == Formats::Hex) - format = "%x"; - else if (mFormat == Formats::Decimal) - format = "%d"; - - sprintf_s(buffer, _countof(buffer), format, (__int32)mValue); - ConvertToLower(buffer, _countof(buffer)); - } - - return buffer; - } - } - - private: - int GetPrecision() const - { - if (mFormat == Formats::Hex || mFormat == Formats::PrefixHex) - { - ULONGLONG val = mValue; - int count = 0; - while (val) - { - val >>= 4; - count++; - } - - if (count == 0) - count = 1; - - return count; - } - - else if (mFormat == Formats::Decimal) - { - T val = mValue; - int count = (val > 0) ? 0 : 1; - while (val) - { - val /= 10; - count++; - } - - return count; - } - - // mFormat == Formats::Pointer - return sizeof(int*)*2; - } - - static inline void BuildDML(__out_ecount(len) char *result, int len, CLRDATA_ADDRESS value, Formats::Format format, Output::FormatType dmlType) - { - BuildDMLCol(result, len, value, format, dmlType, true, 0); - } - - static int GetDMLWidth(Output::FormatType dmlType) - { - return GetDMLColWidth(dmlType, 0); - } - - static void BuildDMLCol(__out_ecount(len) char *result, int len, CLRDATA_ADDRESS value, Formats::Format format, Output::FormatType dmlType, bool leftAlign, int width) - { - char hex[64]; - int count = GetHex(value, hex, _countof(hex), format != Formats::Hex); - int i = 0; - - if (!leftAlign) - { - for (; i < width - count; ++i) - result[i] = ' '; - - result[i] = 0; - } - - int written = sprintf_s(result+i, len - i, DMLFormats[dmlType], hex, hex); - - SOS_Assert(written != -1); - if (written != -1) - { - for (i = i + written; i < width; ++i) - result[i] = ' '; - - result[i] = 0; - } - } - - static int GetDMLColWidth(Output::FormatType dmlType, int width) - { - return 1 + 4*sizeof(int*) + (int)strlen(DMLFormats[dmlType]) + width; - } - - private: - T mValue; - Formats::Format mFormat; - Output::FormatType mDml; - }; - - /* Format class used for strings. - */ - template <> - class Format<const char *> - { - public: - Format(const char *value) - : mValue(value) - { - } - - Format(const Format<const char *> &rhs) - : mValue(rhs.mValue) - { - } - - void Output() const - { - if (IsDMLEnabled()) - DMLOut("%s", mValue); - else - ExtOut("%s", mValue); - } - - void OutputColumn(Alignment align, int width) const - { - int precision = (int)strlen(mValue); - - if (precision > width) - precision = width; - - const char *format = align == AlignLeft ? "%-*.*s" : "%*.*s"; - - if (IsDMLEnabled()) - DMLOut(format, width, precision, mValue); - else - ExtOut(format, width, precision, mValue); - } - - private: - const char *mValue; - }; - - /* Format class for wide char strings. - */ - template <> - class Format<const WCHAR *> - { - public: - Format(const WCHAR *value) - : mValue(value) - { - } - - Format(const Format<const WCHAR *> &rhs) - : mValue(rhs.mValue) - { - } - - void Output() const - { - if (IsDMLEnabled()) - DMLOut("%S", mValue); - else - ExtOut("%S", mValue); - } - - void OutputColumn(Alignment align, int width) const - { - int precision = (int)_wcslen(mValue); - if (precision > width) - precision = width; - - const char *format = align == AlignLeft ? "%-*.*S" : "%*.*S"; - - if (IsDMLEnabled()) - DMLOut(format, width, precision, mValue); - else - ExtOut(format, width, precision, mValue); - } - - private: - const WCHAR *mValue; - }; - - - template <class T> - void InternalPrint(const T &t) - { - Format<T>(t).Output(); - } - - template <class T> - void InternalPrint(const Format<T> &t) - { - t.Output(); - } - - inline void InternalPrint(const char t[]) - { - Format<const char *>(t).Output(); - } -} - -#define DefineFormatClass(name, format, dml) \ - template <class T> \ - Output::Format<T> name(T value) \ - { return Output::Format<T>(value, format, dml); } - -DefineFormatClass(EEClassPtr, Formats::Pointer, Output::DML_EEClass); -DefineFormatClass(ObjectPtr, Formats::Pointer, Output::DML_Object); -DefineFormatClass(ExceptionPtr, Formats::Pointer, Output::DML_PrintException); -DefineFormatClass(ModulePtr, Formats::Pointer, Output::DML_Module); -DefineFormatClass(MethodDescPtr, Formats::Pointer, Output::DML_MethodDesc); -DefineFormatClass(AppDomainPtr, Formats::Pointer, Output::DML_Domain); -DefineFormatClass(ThreadState, Formats::Hex, Output::DML_ThreadState); -DefineFormatClass(ThreadID, Formats::Hex, Output::DML_ThreadID); -DefineFormatClass(RCWrapper, Formats::Pointer, Output::DML_RCWrapper); -DefineFormatClass(CCWrapper, Formats::Pointer, Output::DML_CCWrapper); -DefineFormatClass(InstructionPtr, Formats::Pointer, Output::DML_IP); -DefineFormatClass(NativePtr, Formats::Pointer, Output::DML_None); - -DefineFormatClass(Decimal, Formats::Decimal, Output::DML_None); -DefineFormatClass(Pointer, Formats::Pointer, Output::DML_None); -DefineFormatClass(PrefixHex, Formats::PrefixHex, Output::DML_None); -DefineFormatClass(Hex, Formats::Hex, Output::DML_None); - -#undef DefineFormatClass - -template <class T0> -void Print(const T0 &val0) -{ - Output::InternalPrint(val0); -} - -template <class T0, class T1> -void Print(const T0 &val0, const T1 &val1) -{ - Output::InternalPrint(val0); - Output::InternalPrint(val1); -} - -template <class T0> -void PrintLn(const T0 &val0) -{ - Output::InternalPrint(val0); - ExtOut("\n"); -} - -template <class T0, class T1> -void PrintLn(const T0 &val0, const T1 &val1) -{ - Output::InternalPrint(val0); - Output::InternalPrint(val1); - ExtOut("\n"); -} - -template <class T0, class T1, class T2> -void PrintLn(const T0 &val0, const T1 &val1, const T2 &val2) -{ - Output::InternalPrint(val0); - Output::InternalPrint(val1); - Output::InternalPrint(val2); - ExtOut("\n"); -} - - -/* This class handles the formatting for output which is in a table format. To use this class you define - * how the table is formatted by setting the number of columns in the table, the default column width, - * the default column alignment, the indentation (whitespace) for the table, and the amount of padding - * (whitespace) between each column. Once this has been setup, you output rows at a time or individual - * columns to build the output instead of manually tabbing out space. - * Also note that this class was built to work with the Format class. When outputing data, use the - * predefined output types to specify the format (such as ObjectPtr, MethodDescPtr, Decimal, etc). This - * tells the TableOutput class how to display the data, and where applicable, it automatically generates - * the appropriate DML output. See the DefineFormatClass macro. - */ -class TableOutput -{ -public: - - TableOutput() - : mColumns(0), mDefaultWidth(0), mIndent(0), mPadding(0), mCurrCol(0), mDefaultAlign(AlignLeft), - mWidths(0), mAlignments(0) - { - } - /* Constructor. - * Params: - * numColumns - the number of columns the table has - * defaultColumnWidth - the default width of each column - * alignmentDefault - whether columns are by default left aligned or right aligned - * indent - the amount of whitespace to prefix at the start of the row (in characters) - * padding - the amount of whitespace to place between each column (in characters) - */ - TableOutput(int numColumns, int defaultColumnWidth, Alignment alignmentDefault = AlignLeft, int indent = 0, int padding = 1) - : mColumns(numColumns), mDefaultWidth(defaultColumnWidth), mIndent(indent), mPadding(padding), mCurrCol(0), mDefaultAlign(alignmentDefault), - mWidths(0), mAlignments(0) - { - } - - ~TableOutput() - { - Clear(); - } - - /* See the documentation for the constructor. - */ - void ReInit(int numColumns, int defaultColumnWidth, Alignment alignmentDefault = AlignLeft, int indent = 0, int padding = 1); - - /* Sets the amount of whitespace to prefix at the start of the row (in characters). - */ - void SetIndent(int indent) - { - SOS_Assert(indent >= 0); - - mIndent = indent; - } - - /* Sets the exact widths for the the given columns. - * Params: - * columns - the number of columns you are providing the width for, starting at the first column - * ... - an int32 for each column (given by the number of columns in the first parameter). - * Example: - * If you have 5 columns in the table, you can set their widths like so: - * tableOutput.SetWidths(5, 2, 3, 5, 7, 13); - * Note: - * It's fine to pass a value for "columns" less than the number of columns in the table. This - * is useful when you set the default column width to be correct for most of the table, and need - * to make a minor adjustment to a few. - */ - void SetWidths(int columns, ...); - - /* Individually sets a column to the given width. - * Params: - * col - the column to set, 0 indexed - * width - the width of the column (note this must be non-negative) - */ - void SetColWidth(int col, int width); - - /* Individually sets the column alignment. - * Params: - * col - the column to set, 0 indexed - * align - the new alignment (left or right) for the column - */ - void SetColAlignment(int col, Alignment align); - - - /* The WriteRow family of functions allows you to write an entire row of the table at once. - * The common use case for the TableOutput class is to individually output each column after - * calculating what the value should contain. However, this would be tedious if you already - * knew the contents of the entire row which usually happenes when you are printing out the - * header for the table. To use this, simply pass each column as an individual parameter, - * for example: - * tableOutput.WriteRow("First Column", "Second Column", Decimal(3), PrefixHex(4), "Fifth Column"); - */ - template <class T0, class T1> - void WriteRow(T0 t0, T1 t1) - { - WriteColumn(0, t0); - WriteColumn(1, t1); - } - - template <class T0, class T1, class T2> - void WriteRow(T0 t0, T1 t1, T2 t2) - { - WriteColumn(0, t0); - WriteColumn(1, t1); - WriteColumn(2, t2); - } - - - template <class T0, class T1, class T2, class T3> - void WriteRow(T0 t0, T1 t1, T2 t2, T3 t3) - { - WriteColumn(0, t0); - WriteColumn(1, t1); - WriteColumn(2, t2); - WriteColumn(3, t3); - } - - - template <class T0, class T1, class T2, class T3, class T4> - void WriteRow(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4) - { - WriteColumn(0, t0); - WriteColumn(1, t1); - WriteColumn(2, t2); - WriteColumn(3, t3); - WriteColumn(4, t4); - } - - template <class T0, class T1, class T2, class T3, class T4, class T5> - void WriteRow(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) - { - WriteColumn(0, t0); - WriteColumn(1, t1); - WriteColumn(2, t2); - WriteColumn(3, t3); - WriteColumn(4, t4); - WriteColumn(5, t5); - } - - template <class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9> - void WriteRow(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) - { - WriteColumn(0, t0); - WriteColumn(1, t1); - WriteColumn(2, t2); - WriteColumn(3, t3); - WriteColumn(4, t4); - WriteColumn(5, t5); - WriteColumn(6, t6); - WriteColumn(7, t7); - WriteColumn(8, t8); - WriteColumn(9, t9); - } - - /* The WriteColumn family of functions is used to output individual columns in the table. - * The intent is that the bulk of the table will be generated in a loop like so: - * while (condition) { - * int value1 = CalculateFirstColumn(); - * table.WriteColumn(0, value1); - * - * String value2 = CalculateSecondColumn(); - * table.WriteColumn(1, value2); - * } - * Params: - * col - the column to write, 0 indexed - * t - the value to write - * Note: - * You should generally use the specific instances of the Format class to generate output. - * For example, use the "Decimal", "Pointer", "ObjectPtr", etc. When passing data to this - * function. This tells the Table class how to display the value. - */ - template <class T> - void WriteColumn(int col, const Output::Format<T> &t) - { - SOS_Assert(col >= 0); - SOS_Assert(col < mColumns); - - if (col != mCurrCol) - OutputBlankColumns(col); - - if (col == 0) - OutputIndent(); - - bool lastCol = col == mColumns - 1; - - if (!lastCol) - t.OutputColumn(GetColAlign(col), GetColumnWidth(col)); - else - t.Output(); - - ExtOut(lastCol ? "\n" : GetWhitespace(mPadding)); - - if (lastCol) - mCurrCol = 0; - else - mCurrCol = col+1; - } - - template <class T> - void WriteColumn(int col, T t) - { - WriteColumn(col, Output::Format<T>(t)); - } - - void WriteColumn(int col, const String &str) - { - WriteColumn(col, Output::Format<const char *>(str)); - } - - void WriteColumn(int col, const WString &str) - { - WriteColumn(col, Output::Format<const WCHAR *>(str)); - } - - void WriteColumn(int col, __in_z WCHAR *str) - { - WriteColumn(col, Output::Format<const WCHAR *>(str)); - } - - void WriteColumn(int col, const WCHAR *str) - { - WriteColumn(col, Output::Format<const WCHAR *>(str)); - } - - inline void WriteColumn(int col, __in_z char *str) - { - WriteColumn(col, Output::Format<const char *>(str)); - } - - /* Writes a column using a printf style format. You cannot use the Format class with - * this function to specify how the output should look, use printf style formatting - * with the appropriate parameters instead. - */ - void WriteColumnFormat(int col, const char *fmt, ...) - { - SOS_Assert(strstr(fmt, "%S") == NULL); - - char result[128]; - - va_list list; - va_start(list, fmt); - vsprintf_s(result, _countof(result), fmt, list); - va_end(list); - - WriteColumn(col, result); - } - - void WriteColumnFormat(int col, const WCHAR *fmt, ...) - { - WCHAR result[128]; - - va_list list; - va_start(list, fmt); - vswprintf_s(result, _countof(result), fmt, list); - va_end(list); - - WriteColumn(col, result); - } - - /* This function is a shortcut for writing the next column. (That is, the one after the - * one you just wrote.) - */ - template <class T> - void WriteColumn(T t) - { - WriteColumn(mCurrCol, t); - } - -private: - void Clear(); - void AllocWidths(); - int GetColumnWidth(int col); - Alignment GetColAlign(int col); - const char *GetWhitespace(int amount); - void OutputBlankColumns(int col); - void OutputIndent(); - -private: - int mColumns, mDefaultWidth, mIndent, mPadding, mCurrCol; - Alignment mDefaultAlign; - int *mWidths; - Alignment *mAlignments; -}; - -HRESULT GetMethodDefinitionsFromName(DWORD_PTR ModulePtr, IXCLRDataModule* mod, const char* name, IXCLRDataMethodDefinition **ppMethodDefinitions, int numMethods, int *numMethodsNeeded); -HRESULT GetMethodDescsFromName(DWORD_PTR ModulePtr, IXCLRDataModule* mod, const char* name, DWORD_PTR **pOut, int *numMethodDescs); - -HRESULT FileNameForModule (DacpModuleData *pModule, __out_ecount (MAX_LONGPATH) WCHAR *fileName); -HRESULT FileNameForModule (DWORD_PTR pModuleAddr, __out_ecount (MAX_LONGPATH) WCHAR *fileName); -void IP2MethodDesc (DWORD_PTR IP, DWORD_PTR &methodDesc, JITTypes &jitType, - DWORD_PTR &gcinfoAddr); -const char *ElementTypeName (unsigned type); -void DisplayFields (CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodTableFieldData *pMTFD, - DWORD_PTR dwStartAddr = 0, BOOL bFirst=TRUE, BOOL bValueClass=FALSE); -int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, __in_z LPCWSTR wszFieldName, BOOL bFirst=TRUE); -int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, CLRDATA_ADDRESS cdaMT, __in_z LPCWSTR wszFieldName, BOOL bFirst=TRUE, DacpFieldDescData* pDacpFieldDescData=NULL); -int GetValueFieldOffset(CLRDATA_ADDRESS cdaMT, __in_z LPCWSTR wszFieldName, DacpFieldDescData* pDacpFieldDescData); - -BOOL IsValidToken(DWORD_PTR ModuleAddr, mdTypeDef mb); -void NameForToken_s(DacpModuleData *pModule, mdTypeDef mb, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName, - bool bClassName=true); -void NameForToken_s(DWORD_PTR ModuleAddr, mdTypeDef mb, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName, - bool bClassName=true); -HRESULT NameForToken_s(mdTypeDef mb, IMetaDataImport *pImport, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName, - bool bClassName); -HRESULT NameForTokenNew_s(mdTypeDef mb, IMDInternalImport *pImport, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName, - bool bClassName); - -void vmmap(); -void vmstat(); - -#ifndef FEATURE_PAL -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Support for managed stack tracing -// - -DWORD_PTR GetDebuggerJitInfo(DWORD_PTR md); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -#endif // FEATURE_PAL - -template <typename SCALAR> -inline -int bitidx(SCALAR bitflag) -{ - for (int idx = 0; idx < static_cast<int>(sizeof(bitflag))*8; ++idx) - { - if (bitflag & (1 << idx)) - { - _ASSERTE((bitflag & (~(1 << idx))) == 0); - return idx; - } - } - return -1; -} - -HRESULT -DllsName( - ULONG_PTR addrContaining, - __out_ecount (MAX_LONGPATH) WCHAR *dllName - ); - -inline -BOOL IsElementValueType (CorElementType cet) -{ - return (cet >= ELEMENT_TYPE_BOOLEAN && cet <= ELEMENT_TYPE_R8) - || cet == ELEMENT_TYPE_VALUETYPE || cet == ELEMENT_TYPE_I || cet == ELEMENT_TYPE_U; -} - - -#define safemove(dst, src) \ -SafeReadMemory (TO_TADDR(src), &(dst), sizeof(dst), NULL) - -extern "C" PDEBUG_DATA_SPACES g_ExtData; - -#include <arrayholder.h> - -// This class acts a smart pointer which calls the Release method on any object -// you place in it when the ToRelease class falls out of scope. You may use it -// just like you would a standard pointer to a COM object (including if (foo), -// if (!foo), if (foo == 0), etc) except for two caveats: -// 1. This class never calls AddRef and it always calls Release when it -// goes out of scope. -// 2. You should never use & to try to get a pointer to a pointer unless -// you call Release first, or you will leak whatever this object contains -// prior to updating its internal pointer. -template<class T> -class ToRelease -{ -public: - ToRelease() - : m_ptr(NULL) - {} - - ToRelease(T* ptr) - : m_ptr(ptr) - {} - - ~ToRelease() - { - Release(); - } - - void operator=(T *ptr) - { - Release(); - - m_ptr = ptr; - } - - T* operator->() - { - return m_ptr; - } - - operator T*() - { - return m_ptr; - } - - T** operator&() - { - return &m_ptr; - } - - T* GetPtr() const - { - return m_ptr; - } - - T* Detach() - { - T* pT = m_ptr; - m_ptr = NULL; - return pT; - } - - void Release() - { - if (m_ptr != NULL) - { - m_ptr->Release(); - m_ptr = NULL; - } - } - -private: - T* m_ptr; -}; - -struct ModuleInfo -{ - ULONG64 baseAddr; - ULONG64 size; - BOOL hasPdb; -}; -extern ModuleInfo moduleInfo[]; - -BOOL InitializeHeapData(); -BOOL IsServerBuild (); -UINT GetMaxGeneration(); -UINT GetGcHeapCount(); -BOOL GetGcStructuresValid(); - -ULONG GetILSize(DWORD_PTR ilAddr); // REturns 0 if error occurs -HRESULT DecodeILFromAddress(IMetaDataImport *pImport, TADDR ilAddr); -void DecodeIL(IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize); -void DecodeDynamicIL(BYTE *data, ULONG Size, DacpObjectData& tokenArray); - -BOOL IsRetailBuild (size_t base); -EEFLAVOR GetEEFlavor (); -HRESULT InitCorDebugInterface(); -VOID UninitCorDebugInterface(); -#ifndef FEATURE_PAL -BOOL GetEEVersion(VS_FIXEDFILEINFO *pFileInfo); -BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo); -#endif - -BOOL IsDumpFile (); - -// IsMiniDumpFile will return true if 1) we are in -// a small format minidump, and g_InMinidumpSafeMode is true. -extern BOOL g_InMinidumpSafeMode; - -BOOL IsMiniDumpFile(); -void ReportOOM(); - -BOOL SafeReadMemory (TADDR offset, PVOID lpBuffer, ULONG cb, PULONG lpcbBytesRead); -#if !defined(_TARGET_WIN64_) && !defined(_ARM64_) -// on 64-bit platforms TADDR and CLRDATA_ADDRESS are identical -inline BOOL SafeReadMemory (CLRDATA_ADDRESS offset, PVOID lpBuffer, ULONG cb, PULONG lpcbBytesRead) -{ return SafeReadMemory(TO_TADDR(offset), lpBuffer, cb, lpcbBytesRead); } -#endif - -BOOL NameForMD_s (DWORD_PTR pMD, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName); -BOOL NameForMT_s (DWORD_PTR MTAddr, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName); - -WCHAR *CreateMethodTableName(TADDR mt, TADDR cmt = NULL); - -void isRetAddr(DWORD_PTR retAddr, DWORD_PTR* whereCalled); -DWORD_PTR GetValueFromExpression (___in __in_z const char *const str); - -enum ModuleHeapType -{ - ModuleHeapType_ThunkHeap, - ModuleHeapType_LookupTableHeap -}; - -HRESULT PrintDomainHeapInfo(const char *name, CLRDATA_ADDRESS adPtr, DWORD_PTR *size, DWORD_PTR *wasted = 0); -DWORD_PTR PrintModuleHeapInfo(DWORD_PTR *moduleList, int count, ModuleHeapType type, DWORD_PTR *wasted = 0); -void PrintHeapSize(DWORD_PTR total, DWORD_PTR wasted); -void DomainInfo(DacpAppDomainData *pDomain); -void AssemblyInfo(DacpAssemblyData *pAssembly); -DWORD_PTR LoaderHeapInfo(CLRDATA_ADDRESS pLoaderHeapAddr, DWORD_PTR *wasted = 0); -DWORD_PTR JitHeapInfo(); -DWORD_PTR VSDHeapInfo(CLRDATA_ADDRESS appDomain, DWORD_PTR *wasted = 0); - -DWORD GetNumComponents(TADDR obj); - -struct GenUsageStat -{ - size_t allocd; - size_t freed; - size_t unrooted; -}; - -struct HeapUsageStat -{ - GenUsageStat genUsage[4]; // gen0, 1, 2, LOH -}; - -extern DacpUsefulGlobalsData g_special_usefulGlobals; -BOOL GCHeapUsageStats(const DacpGcHeapDetails& heap, BOOL bIncUnreachable, HeapUsageStat *hpUsage); - -class HeapStat -{ -protected: - struct Node - { - DWORD_PTR data; - DWORD count; - size_t totalSize; - Node* left; - Node* right; - Node () - : data(0), count(0), totalSize(0), left(NULL), right(NULL) - { - } - }; - BOOL bHasStrings; - Node *head; - BOOL fLinear; -public: - HeapStat () - : bHasStrings(FALSE), head(NULL), fLinear(FALSE) - {} - ~HeapStat() - { - Delete(); - } - // TODO: Change the aSize argument to size_t when we start supporting - // TODO: object sizes above 4GB - void Add (DWORD_PTR aData, DWORD aSize); - void Sort (); - void Print (const char* label = NULL); - void Delete (); - void HasStrings(BOOL abHasStrings) - { - bHasStrings = abHasStrings; - } -private: - int CompareData(DWORD_PTR n1, DWORD_PTR n2); - void SortAdd (Node *&root, Node *entry); - void LinearAdd (Node *&root, Node *entry); - void ReverseLeftMost (Node *root); - void Linearize(); -}; - -class CGCDesc; - -// The information MethodTableCache returns. -struct MethodTableInfo -{ - bool IsInitialized() { return BaseSize != 0; } - - DWORD BaseSize; // Caching BaseSize and ComponentSize for a MethodTable - DWORD ComponentSize; // here has HUGE perf benefits in heap traversals. - BOOL bContainsPointers; - BOOL bCollectible; - DWORD_PTR* GCInfoBuffer; // Start of memory of GC info - CGCDesc* GCInfo; // Just past GC info (which is how it is stored) - bool ArrayOfVC; - TADDR LoaderAllocatorObjectHandle; -}; - -class MethodTableCache -{ -protected: - - struct Node - { - DWORD_PTR data; // This is the key (the method table pointer) - MethodTableInfo info; // The info associated with this MethodTable - Node* left; - Node* right; - Node (DWORD_PTR aData) : data(aData), left(NULL), right(NULL) - { - info.BaseSize = 0; - info.ComponentSize = 0; - info.bContainsPointers = false; - info.bCollectible = false; - info.GCInfo = NULL; - info.ArrayOfVC = false; - info.GCInfoBuffer = NULL; - info.LoaderAllocatorObjectHandle = NULL; - } - }; - Node *head; -public: - MethodTableCache () - : head(NULL) - {} - ~MethodTableCache() { Clear(); } - - // Always succeeds, if it is not present it adds an empty Info struct and returns that - // Thus you must call 'IsInitialized' on the returned value before using it - MethodTableInfo* Lookup(DWORD_PTR aData); - - void Clear (); -private: - int CompareData(DWORD_PTR n1, DWORD_PTR n2); - void ReverseLeftMost (Node *root); -}; - -extern MethodTableCache g_special_mtCache; - -struct DumpArrayFlags -{ - DWORD_PTR startIndex; - DWORD_PTR Length; - BOOL bDetail; - LPSTR strObject; - BOOL bNoFieldsForElement; - - DumpArrayFlags () - : startIndex(0), Length((DWORD_PTR)-1), bDetail(FALSE), strObject (0), bNoFieldsForElement(FALSE) - {} - ~DumpArrayFlags () - { - if (strObject) - delete [] strObject; - } -}; //DumpArrayFlags - - - -// ----------------------------------------------------------------------- - -#define BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX 0x08000000 -#define BIT_SBLK_FINALIZER_RUN 0x40000000 -#define BIT_SBLK_SPIN_LOCK 0x10000000 -#define SBLK_MASK_LOCK_THREADID 0x000003FF // special value of 0 + 1023 thread ids -#define SBLK_MASK_LOCK_RECLEVEL 0x0000FC00 // 64 recursion levels -#define SBLK_RECLEVEL_SHIFT 10 // shift right this much to get recursion level -#define BIT_SBLK_IS_HASHCODE 0x04000000 -#define MASK_HASHCODE ((1<<HASHCODE_BITS)-1) -#define SYNCBLOCKINDEX_BITS 26 -#define MASK_SYNCBLOCKINDEX ((1<<SYNCBLOCKINDEX_BITS)-1) - -HRESULT GetMTOfObject(TADDR obj, TADDR *mt); - -struct needed_alloc_context -{ - BYTE* alloc_ptr; // starting point for next allocation - BYTE* alloc_limit; // ending point for allocation region/quantum -}; - -struct AllocInfo -{ - needed_alloc_context *array; - int num; // number of allocation contexts in array - - AllocInfo() - : array(NULL) - , num(0) - {} - void Init() - { - extern void GetAllocContextPtrs(AllocInfo *pallocInfo); - GetAllocContextPtrs(this); - } - ~AllocInfo() - { - if (array != NULL) - delete[] array; - } -}; - -struct GCHandleStatistics -{ - HeapStat hs; - - DWORD strongHandleCount; - DWORD pinnedHandleCount; - DWORD asyncPinnedHandleCount; - DWORD refCntHandleCount; - DWORD weakLongHandleCount; - DWORD weakShortHandleCount; - DWORD variableCount; - DWORD sizedRefCount; - DWORD dependentCount; - DWORD weakWinRTHandleCount; - DWORD unknownHandleCount; - GCHandleStatistics() - : strongHandleCount(0), pinnedHandleCount(0), asyncPinnedHandleCount(0), refCntHandleCount(0), - weakLongHandleCount(0), weakShortHandleCount(0), variableCount(0), sizedRefCount(0), - dependentCount(0), weakWinRTHandleCount(0), unknownHandleCount(0) - {} - ~GCHandleStatistics() - { - hs.Delete(); - } -}; - -struct SegmentLookup -{ - DacpHeapSegmentData *m_segments; - int m_iSegmentsSize; - int m_iSegmentCount; - - SegmentLookup(); - ~SegmentLookup(); - - void Clear(); - BOOL AddSegment(DacpHeapSegmentData *pData); - CLRDATA_ADDRESS GetHeap(CLRDATA_ADDRESS object, BOOL& bFound); -}; - -class GCHeapSnapshot -{ -private: - BOOL m_isBuilt; - DacpGcHeapDetails *m_heapDetails; - DacpGcHeapData m_gcheap; - SegmentLookup m_segments; - - BOOL AddSegments(DacpGcHeapDetails& details); -public: - GCHeapSnapshot(); - - BOOL Build(); - void Clear(); - BOOL IsBuilt() { return m_isBuilt; } - - DacpGcHeapData *GetHeapData() { return &m_gcheap; } - - int GetHeapCount() { return m_gcheap.HeapCount; } - - DacpGcHeapDetails *GetHeap(CLRDATA_ADDRESS objectPointer); - int GetGeneration(CLRDATA_ADDRESS objectPointer); - - -}; -extern GCHeapSnapshot g_snapshot; - -BOOL IsSameModuleName (const char *str1, const char *str2); -BOOL IsModule (DWORD_PTR moduleAddr); -BOOL IsMethodDesc (DWORD_PTR value); -BOOL IsMethodTable (DWORD_PTR value); -BOOL IsStringObject (size_t obj); -BOOL IsObjectArray (DWORD_PTR objPointer); -BOOL IsObjectArray (DacpObjectData *pData); -BOOL IsDerivedFrom(CLRDATA_ADDRESS mtObj, __in_z LPCWSTR baseString); -BOOL TryGetMethodDescriptorForDelegate(CLRDATA_ADDRESS delegateAddr, CLRDATA_ADDRESS* pMD); - -/* Returns a list of all modules in the process. - * Params: - * name - The name of the module you would like. If mName is NULL the all modules are returned. - * numModules - The number of modules in the array returned. - * Returns: - * An array of modules whose length is *numModules, NULL if an error occurred. Note that if this - * function succeeds but finds no modules matching the name given, this function returns a valid - * array, but *numModules will equal 0. - * Note: - * You must clean up the return value of this array by calling delete [] on it, or using the - * ArrayHolder class. - */ -DWORD_PTR *ModuleFromName(__in_opt LPSTR name, int *numModules); -void GetInfoFromName(DWORD_PTR ModuleAddr, const char* name, mdTypeDef* retMdTypeDef=NULL); -void GetInfoFromModule (DWORD_PTR ModuleAddr, ULONG token, DWORD_PTR *ret=NULL); - - -typedef void (*VISITGCHEAPFUNC)(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable,LPVOID token); -BOOL GCHeapsTraverse(VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify=true); - -///////////////////////////////////////////////////////////////////////////////////////////////////////// - -struct strobjInfo -{ - size_t methodTable; - DWORD m_StringLength; -}; - -// Just to make figuring out which fill pointer element matches a generation -// a bit less confusing. This gen_segment function is ported from gc.cpp. -inline unsigned int gen_segment (int gen) -{ - return (DAC_NUMBERGENERATIONS - gen - 1); -} - -inline CLRDATA_ADDRESS SegQueue(DacpGcHeapDetails& heapDetails, int seg) -{ - return heapDetails.finalization_fill_pointers[seg - 1]; -} - -inline CLRDATA_ADDRESS SegQueueLimit(DacpGcHeapDetails& heapDetails, int seg) -{ - return heapDetails.finalization_fill_pointers[seg]; -} - -#define FinalizerListSeg (DAC_NUMBERGENERATIONS+1) -#define CriticalFinalizerListSeg (DAC_NUMBERGENERATIONS) - -void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, BOOL bAllReady, BOOL bShort); - -CLRDATA_ADDRESS GetAppDomainForMT(CLRDATA_ADDRESS mtPtr); -CLRDATA_ADDRESS GetAppDomain(CLRDATA_ADDRESS objPtr); -void GCHeapInfo(const DacpGcHeapDetails &heap, DWORD_PTR &total_size); -BOOL GCObjInHeap(TADDR taddrObj, const DacpGcHeapDetails &heap, - TADDR_SEGINFO& trngSeg, int& gen, TADDR_RANGE& allocCtx, BOOL &bLarge); - -BOOL VerifyObject(const DacpGcHeapDetails &heap, const DacpHeapSegmentData &seg, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize, - BOOL bVerifyMember); -BOOL VerifyObject(const DacpGcHeapDetails &heap, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize, - BOOL bVerifyMember); - -BOOL IsMTForFreeObj(DWORD_PTR pMT); -void DumpStackObjectsHelper (TADDR StackTop, TADDR StackBottom, BOOL verifyFields); - - -enum ARGTYPE {COBOOL,COSIZE_T,COHEX,COSTRING}; -struct CMDOption -{ - const char* name; - void *vptr; - ARGTYPE type; - BOOL hasValue; - BOOL hasSeen; -}; -struct CMDValue -{ - void *vptr; - ARGTYPE type; -}; -BOOL GetCMDOption(const char *string, CMDOption *option, size_t nOption, - CMDValue *arg, size_t maxArg, size_t *nArg); - -void DumpMDInfo(DWORD_PTR dwStartAddr, CLRDATA_ADDRESS dwRequestedIP = 0, BOOL fStackTraceFormat = FALSE); -void DumpMDInfoFromMethodDescData(DacpMethodDescData * pMethodDescData, BOOL fStackTraceFormat); -void GetDomainList(DWORD_PTR *&domainList, int &numDomain); -HRESULT GetThreadList(DWORD_PTR **threadList, int *numThread); -CLRDATA_ADDRESS GetCurrentManagedThread(); // returns current managed thread if any -void GetAllocContextPtrs(AllocInfo *pallocInfo); - -void ReloadSymbolWithLineInfo(); - -size_t FunctionType (size_t EIP); - -size_t Align (size_t nbytes); -// Aligns large objects -size_t AlignLarge (size_t nbytes); - -ULONG OSPageSize (); -size_t NextOSPageAddress (size_t addr); - -// This version of objectsize reduces the lookup of methodtables in the DAC. -// It uses g_special_mtCache for it's work. -BOOL GetSizeEfficient(DWORD_PTR dwAddrCurrObj, - DWORD_PTR dwAddrMethTable, BOOL bLarge, size_t& s, BOOL& bContainsPointers); - -BOOL GetCollectibleDataEfficient(DWORD_PTR dwAddrMethTable, BOOL& bCollectible, TADDR& loaderAllocatorObjectHandle); - -// ObjSize now uses the methodtable cache for its work too. -size_t ObjectSize (DWORD_PTR obj, BOOL fIsLargeObject=FALSE); -size_t ObjectSize(DWORD_PTR obj, DWORD_PTR mt, BOOL fIsValueClass, BOOL fIsLargeObject=FALSE); - -void CharArrayContent(TADDR pos, ULONG num, bool widechar); -void StringObjectContent (size_t obj, BOOL fLiteral=FALSE, const int length=-1); // length=-1: dump everything in the string object. - -UINT FindAllPinnedAndStrong (DWORD_PTR handlearray[],UINT arraySize); -void PrintNotReachableInRange(TADDR rngStart, TADDR rngEnd, BOOL bExcludeReadyForFinalization, - HeapStat* stat, BOOL bShort); - -const char *EHTypeName(EHClauseType et); - -struct StringHolder -{ - LPSTR data; - StringHolder() : data(NULL) { } - ~StringHolder() { if(data) delete [] data; } -}; - - -ULONG DebuggeeType(); - -inline BOOL IsKernelDebugger () -{ - return DebuggeeType() == DEBUG_CLASS_KERNEL; -} - -void ResetGlobals(void); -HRESULT LoadClrDebugDll(void); -extern "C" void UnloadClrDebugDll(void); - -extern IMetaDataImport* MDImportForModule (DacpModuleData *pModule); -extern IMetaDataImport* MDImportForModule (DWORD_PTR pModule); - -//***************************************************************************** -// -// **** CQuickBytes -// This helper class is useful for cases where 90% of the time you allocate 512 -// or less bytes for a data structure. This class contains a 512 byte buffer. -// Alloc() will return a pointer to this buffer if your allocation is small -// enough, otherwise it asks the heap for a larger buffer which is freed for -// you. No mutex locking is required for the small allocation case, making the -// code run faster, less heap fragmentation, etc... Each instance will allocate -// 520 bytes, so use accordinly. -// -//***************************************************************************** -template <DWORD SIZE, DWORD INCREMENT> -class CQuickBytesBase -{ -public: - CQuickBytesBase() : - pbBuff(0), - iSize(0), - cbTotal(SIZE) - { } - - void Destroy() - { - if (pbBuff) - { - delete[] (BYTE*)pbBuff; - pbBuff = 0; - } - } - - void *Alloc(SIZE_T iItems) - { - iSize = iItems; - if (iItems <= SIZE) - { - cbTotal = SIZE; - return (&rgData[0]); - } - else - { - if (pbBuff) - delete[] (BYTE*)pbBuff; - pbBuff = new BYTE[iItems]; - cbTotal = pbBuff ? iItems : 0; - return (pbBuff); - } - } - - // This is for conformity to the CQuickBytesBase that is defined by the runtime so - // that we can use it inside of some GC code that SOS seems to include as well. - // - // The plain vanilla "Alloc" version on this CQuickBytesBase doesn't throw either, - // so we'll just forward the call. - void *AllocNoThrow(SIZE_T iItems) - { - return Alloc(iItems); - } - - HRESULT ReSize(SIZE_T iItems) - { - void *pbBuffNew; - if (iItems <= cbTotal) - { - iSize = iItems; - return NOERROR; - } - - pbBuffNew = new BYTE[iItems + INCREMENT]; - if (!pbBuffNew) - return E_OUTOFMEMORY; - if (pbBuff) - { - memcpy(pbBuffNew, pbBuff, cbTotal); - delete[] (BYTE*)pbBuff; - } - else - { - _ASSERTE(cbTotal == SIZE); - memcpy(pbBuffNew, rgData, SIZE); - } - cbTotal = iItems + INCREMENT; - iSize = iItems; - pbBuff = pbBuffNew; - return NOERROR; - - } - - operator PVOID() - { return ((pbBuff) ? pbBuff : &rgData[0]); } - - void *Ptr() - { return ((pbBuff) ? pbBuff : &rgData[0]); } - - SIZE_T Size() - { return (iSize); } - - SIZE_T MaxSize() - { return (cbTotal); } - - void *pbBuff; - SIZE_T iSize; // number of bytes used - SIZE_T cbTotal; // total bytes allocated in the buffer - // use UINT64 to enforce the alignment of the memory - UINT64 rgData[(SIZE+sizeof(UINT64)-1)/sizeof(UINT64)]; -}; - -#define CQUICKBYTES_BASE_SIZE 512 -#define CQUICKBYTES_INCREMENTAL_SIZE 128 - -class CQuickBytesNoDtor : public CQuickBytesBase<CQUICKBYTES_BASE_SIZE, CQUICKBYTES_INCREMENTAL_SIZE> -{ -}; - -class CQuickBytes : public CQuickBytesNoDtor -{ -public: - CQuickBytes() { } - - ~CQuickBytes() - { - Destroy(); - } -}; - -template <DWORD CQUICKBYTES_BASE_SPECIFY_SIZE> -class CQuickBytesNoDtorSpecifySize : public CQuickBytesBase<CQUICKBYTES_BASE_SPECIFY_SIZE, CQUICKBYTES_INCREMENTAL_SIZE> -{ -}; - -template <DWORD CQUICKBYTES_BASE_SPECIFY_SIZE> -class CQuickBytesSpecifySize : public CQuickBytesNoDtorSpecifySize<CQUICKBYTES_BASE_SPECIFY_SIZE> -{ -public: - CQuickBytesSpecifySize() { } - - ~CQuickBytesSpecifySize() - { - CQuickBytesNoDtorSpecifySize<CQUICKBYTES_BASE_SPECIFY_SIZE>::Destroy(); - } -}; - - -#define STRING_SIZE 10 -class CQuickString : public CQuickBytesBase<STRING_SIZE, STRING_SIZE> -{ -public: - CQuickString() { } - - ~CQuickString() - { - Destroy(); - } - - void *Alloc(SIZE_T iItems) - { - return CQuickBytesBase<STRING_SIZE, STRING_SIZE>::Alloc(iItems*sizeof(WCHAR)); - } - - HRESULT ReSize(SIZE_T iItems) - { - return CQuickBytesBase<STRING_SIZE, STRING_SIZE>::ReSize(iItems * sizeof(WCHAR)); - } - - SIZE_T Size() - { - return CQuickBytesBase<STRING_SIZE, STRING_SIZE>::Size() / sizeof(WCHAR); - } - - SIZE_T MaxSize() - { - return CQuickBytesBase<STRING_SIZE, STRING_SIZE>::MaxSize() / sizeof(WCHAR); - } - - WCHAR* String() - { - return (WCHAR*) Ptr(); - } - -}; - -enum GetSignatureStringResults -{ - GSS_SUCCESS, - GSS_ERROR, - GSS_INSUFFICIENT_DATA, -}; - -GetSignatureStringResults GetMethodSignatureString (PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, DWORD_PTR dwModuleAddr, CQuickBytes *sigString); -GetSignatureStringResults GetSignatureString (PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, DWORD_PTR dwModuleAddr, CQuickBytes *sigString); -void GetMethodName(mdMethodDef methodDef, IMetaDataImport * pImport, CQuickBytes *fullName); - -#ifndef _TARGET_WIN64_ -#define itoa_s_ptr _itoa_s -#define itow_s_ptr _itow_s -#else -#define itoa_s_ptr _i64toa_s -#define itow_s_ptr _i64tow_s -#endif - -#ifdef FEATURE_PAL -extern "C" -int _itoa_s( int inValue, char* outBuffer, size_t inDestBufferSize, int inRadix ); -extern "C" -int _ui64toa_s( unsigned __int64 inValue, char* outBuffer, size_t inDestBufferSize, int inRadix ); -#endif // FEATURE_PAL - -struct MemRange -{ - MemRange (ULONG64 s = NULL, size_t l = 0, MemRange * n = NULL) - : start(s), len (l), next (n) - {} - - bool InRange (ULONG64 addr) - { - return addr >= start && addr < start + len; - } - - ULONG64 start; - size_t len; - MemRange * next; -}; //struct MemRange - -#ifndef FEATURE_PAL - -class StressLogMem -{ -private: - // use a linked list for now, could be optimazied later - MemRange * list; - - void AddRange (ULONG64 s, size_t l) - { - list = new MemRange (s, l, list); - } - -public: - StressLogMem () : list (NULL) - {} - ~StressLogMem (); - bool Init (ULONG64 stressLogAddr, IDebugDataSpaces* memCallBack); - bool IsInStressLog (ULONG64 addr); -}; //class StressLogMem - -// An adapter class that DIA consumes so that it can read PE data from the an image -// This implementation gets the backing data from the image loaded in debuggee memory -// that has been layed out identical to the disk format (ie not seperated by section) -class PEOffsetMemoryReader : IDiaReadExeAtOffsetCallback -{ -public: - PEOffsetMemoryReader(TADDR moduleBaseAddress); - - // IUnknown implementation - HRESULT __stdcall QueryInterface(REFIID riid, VOID** ppInterface); - ULONG __stdcall AddRef(); - ULONG __stdcall Release(); - - // IDiaReadExeAtOffsetCallback implementation - HRESULT __stdcall ReadExecutableAt(DWORDLONG fileOffset, DWORD cbData, DWORD* pcbData, BYTE data[]); - -private: - TADDR m_moduleBaseAddress; - volatile ULONG m_refCount; -}; - -// An adapter class that DIA consumes so that it can read PE data from the an image -// This implementation gets the backing data from the image loaded in debuggee memory -// that has been layed out in LoadLibrary format -class PERvaMemoryReader : IDiaReadExeAtRVACallback -{ -public: - PERvaMemoryReader(TADDR moduleBaseAddress); - - // IUnknown implementation - HRESULT __stdcall QueryInterface(REFIID riid, VOID** ppInterface); - ULONG __stdcall AddRef(); - ULONG __stdcall Release(); - - // IDiaReadExeAtOffsetCallback implementation - HRESULT __stdcall ReadExecutableAtRVA(DWORD relativeVirtualAddress, DWORD cbData, DWORD* pcbData, BYTE data[]); - -private: - TADDR m_moduleBaseAddress; - volatile ULONG m_refCount; -}; - -#endif // !FEATURE_PAL - -static const char *SymbolReaderDllName = "SOS.NETCore"; -static const char *SymbolReaderClassName = "SOS.SymbolReader"; - -typedef int (*ReadMemoryDelegate)(ULONG64, char *, int); -typedef PVOID (*LoadSymbolsForModuleDelegate)(const char*, BOOL, ULONG64, int, ULONG64, int, ReadMemoryDelegate); -typedef void (*DisposeDelegate)(PVOID); -typedef BOOL (*ResolveSequencePointDelegate)(PVOID, const char*, unsigned int, unsigned int*, unsigned int*); -typedef BOOL (*GetLocalVariableName)(PVOID, int, int, BSTR*); -typedef BOOL (*GetLineByILOffsetDelegate)(PVOID, mdMethodDef, ULONG64, ULONG *, BSTR*); - -class SymbolReader -{ -private: -#ifndef FEATURE_PAL - ISymUnmanagedReader* m_pSymReader; -#endif - PVOID m_symbolReaderHandle; - - static LoadSymbolsForModuleDelegate loadSymbolsForModuleDelegate; - static DisposeDelegate disposeDelegate; - static ResolveSequencePointDelegate resolveSequencePointDelegate; - static GetLocalVariableName getLocalVariableNameDelegate; - static GetLineByILOffsetDelegate getLineByILOffsetDelegate; - static HRESULT PrepareSymbolReader(); - - HRESULT GetNamedLocalVariable(___in ISymUnmanagedScope* pScope, ___in ICorDebugILFrame* pILFrame, ___in mdMethodDef methodToken, ___in ULONG localIndex, - __out_ecount(paramNameLen) WCHAR* paramName, ___in ULONG paramNameLen, ___out ICorDebugValue** ppValue); - HRESULT LoadSymbolsForWindowsPDB(___in IMetaDataImport* pMD, ___in ULONG64 peAddress, __in_z WCHAR* pModuleName, ___in BOOL isFileLayout); - HRESULT LoadSymbolsForPortablePDB(__in_z WCHAR* pModuleName, ___in BOOL isInMemory, ___in BOOL isFileLayout, ___in ULONG64 peAddress, ___in ULONG64 peSize, - ___in ULONG64 inMemoryPdbAddress, ___in ULONG64 inMemoryPdbSize); - -public: - SymbolReader() - { -#ifndef FEATURE_PAL - m_pSymReader = NULL; -#endif - m_symbolReaderHandle = 0; - } - - ~SymbolReader() - { -#ifndef FEATURE_PAL - if(m_pSymReader != NULL) - { - m_pSymReader->Release(); - m_pSymReader = NULL; - } -#endif - if (m_symbolReaderHandle != 0) - { - disposeDelegate(m_symbolReaderHandle); - m_symbolReaderHandle = 0; - } - } - - HRESULT LoadSymbols(___in IMetaDataImport* pMD, ___in ICorDebugModule* pModule); - HRESULT LoadSymbols(___in IMetaDataImport* pMD, ___in IXCLRDataModule* pModule); - HRESULT GetLineByILOffset(___in mdMethodDef MethodToken, ___in ULONG64 IlOffset, ___out ULONG *pLinenum, __out_ecount(cchFileName) WCHAR* pwszFileName, ___in ULONG cchFileName); - HRESULT GetNamedLocalVariable(___in ICorDebugFrame * pFrame, ___in ULONG localIndex, __out_ecount(paramNameLen) WCHAR* paramName, ___in ULONG paramNameLen, ___out ICorDebugValue** ppValue); - HRESULT ResolveSequencePoint(__in_z WCHAR* pFilename, ___in ULONG32 lineNumber, ___in TADDR mod, ___out mdMethodDef* ___out pToken, ___out ULONG32* pIlOffset); -}; - -HRESULT -GetLineByOffset( - ___in ULONG64 IP, - ___out ULONG *pLinenum, - __out_ecount(cchFileName) WCHAR* pwszFileName, - ___in ULONG cchFileName); - -/// X86 Context -#define X86_SIZE_OF_80387_REGISTERS 80 -#define X86_MAXIMUM_SUPPORTED_EXTENSION 512 - -typedef struct { - DWORD ControlWord; - DWORD StatusWord; - DWORD TagWord; - DWORD ErrorOffset; - DWORD ErrorSelector; - DWORD DataOffset; - DWORD DataSelector; - BYTE RegisterArea[X86_SIZE_OF_80387_REGISTERS]; - DWORD Cr0NpxState; -} X86_FLOATING_SAVE_AREA; - -typedef struct { - - DWORD ContextFlags; - DWORD Dr0; - DWORD Dr1; - DWORD Dr2; - DWORD Dr3; - DWORD Dr6; - DWORD Dr7; - - X86_FLOATING_SAVE_AREA FloatSave; - - DWORD SegGs; - DWORD SegFs; - DWORD SegEs; - DWORD SegDs; - - DWORD Edi; - DWORD Esi; - DWORD Ebx; - DWORD Edx; - DWORD Ecx; - DWORD Eax; - - DWORD Ebp; - DWORD Eip; - DWORD SegCs; - DWORD EFlags; - DWORD Esp; - DWORD SegSs; - - BYTE ExtendedRegisters[X86_MAXIMUM_SUPPORTED_EXTENSION]; - -} X86_CONTEXT; - -typedef struct { - ULONGLONG Low; - LONGLONG High; -} M128A_XPLAT; - - -/// AMD64 Context -typedef struct { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A_XPLAT FloatRegisters[8]; - -#if defined(_WIN64) - M128A_XPLAT XmmRegisters[16]; - BYTE Reserved4[96]; -#else - M128A_XPLAT XmmRegisters[8]; - BYTE Reserved4[220]; - - DWORD Cr0NpxState; -#endif - -} AMD64_XMM_SAVE_AREA32; - -typedef struct { - - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - - DWORD ContextFlags; - DWORD MxCsr; - - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - - DWORD64 Rip; - - union { - AMD64_XMM_SAVE_AREA32 FltSave; - struct { - M128A_XPLAT Header[2]; - M128A_XPLAT Legacy[8]; - M128A_XPLAT Xmm0; - M128A_XPLAT Xmm1; - M128A_XPLAT Xmm2; - M128A_XPLAT Xmm3; - M128A_XPLAT Xmm4; - M128A_XPLAT Xmm5; - M128A_XPLAT Xmm6; - M128A_XPLAT Xmm7; - M128A_XPLAT Xmm8; - M128A_XPLAT Xmm9; - M128A_XPLAT Xmm10; - M128A_XPLAT Xmm11; - M128A_XPLAT Xmm12; - M128A_XPLAT Xmm13; - M128A_XPLAT Xmm14; - M128A_XPLAT Xmm15; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - - M128A_XPLAT VectorRegister[26]; - DWORD64 VectorControl; - - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - -} AMD64_CONTEXT; - -typedef struct{ - __int64 LowPart; - __int64 HighPart; -} FLOAT128_XPLAT; - - -/// ARM Context -#define ARM_MAX_BREAKPOINTS_CONST 8 -#define ARM_MAX_WATCHPOINTS_CONST 1 -typedef DECLSPEC_ALIGN(8) struct { - - DWORD ContextFlags; - - DWORD R0; - DWORD R1; - DWORD R2; - DWORD R3; - DWORD R4; - DWORD R5; - DWORD R6; - DWORD R7; - DWORD R8; - DWORD R9; - DWORD R10; - DWORD R11; - DWORD R12; - - DWORD Sp; - DWORD Lr; - DWORD Pc; - DWORD Cpsr; - - DWORD Fpscr; - DWORD Padding; - union { - M128A_XPLAT Q[16]; - ULONGLONG D[32]; - DWORD S[32]; - } DUMMYUNIONNAME; - - DWORD Bvr[ARM_MAX_BREAKPOINTS_CONST]; - DWORD Bcr[ARM_MAX_BREAKPOINTS_CONST]; - DWORD Wvr[ARM_MAX_WATCHPOINTS_CONST]; - DWORD Wcr[ARM_MAX_WATCHPOINTS_CONST]; - - DWORD Padding2[2]; - -} ARM_CONTEXT; - -// On ARM this mask is or'ed with the address of code to get an instruction pointer -#ifndef THUMB_CODE -#define THUMB_CODE 1 -#endif - -///ARM64 Context -#define ARM64_MAX_BREAKPOINTS 8 -#define ARM64_MAX_WATCHPOINTS 2 -typedef struct { - - DWORD ContextFlags; - DWORD Cpsr; // NZVF + DAIF + CurrentEL + SPSel - union { - struct { - DWORD64 X0; - DWORD64 X1; - DWORD64 X2; - DWORD64 X3; - DWORD64 X4; - DWORD64 X5; - DWORD64 X6; - DWORD64 X7; - DWORD64 X8; - DWORD64 X9; - DWORD64 X10; - DWORD64 X11; - DWORD64 X12; - DWORD64 X13; - DWORD64 X14; - DWORD64 X15; - DWORD64 X16; - DWORD64 X17; - DWORD64 X18; - DWORD64 X19; - DWORD64 X20; - DWORD64 X21; - DWORD64 X22; - DWORD64 X23; - DWORD64 X24; - DWORD64 X25; - DWORD64 X26; - DWORD64 X27; - DWORD64 X28; - }; - - DWORD64 X[29]; - }; - - DWORD64 Fp; - DWORD64 Lr; - DWORD64 Sp; - DWORD64 Pc; - - - M128A_XPLAT V[32]; - DWORD Fpcr; - DWORD Fpsr; - - DWORD Bcr[ARM64_MAX_BREAKPOINTS]; - DWORD64 Bvr[ARM64_MAX_BREAKPOINTS]; - DWORD Wcr[ARM64_MAX_WATCHPOINTS]; - DWORD64 Wvr[ARM64_MAX_WATCHPOINTS]; - -} ARM64_CONTEXT; - -typedef struct _CROSS_PLATFORM_CONTEXT { - - _CROSS_PLATFORM_CONTEXT() {} - - union { - X86_CONTEXT X86Context; - AMD64_CONTEXT Amd64Context; - ARM_CONTEXT ArmContext; - ARM64_CONTEXT Arm64Context; - }; - -} CROSS_PLATFORM_CONTEXT, *PCROSS_PLATFORM_CONTEXT; - - - -WString BuildRegisterOutput(const SOSStackRefData &ref, bool printObj = true); -WString MethodNameFromIP(CLRDATA_ADDRESS methodDesc, BOOL bSuppressLines = FALSE, BOOL bAssemblyName = FALSE, BOOL bDisplacement = FALSE); -HRESULT GetGCRefs(ULONG osID, SOSStackRefData **ppRefs, unsigned int *pRefCnt, SOSStackRefError **ppErrors, unsigned int *pErrCount); -WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackwalk = NULL, BOOL bAssemblyName = FALSE); - -/* This cache is used to read data from the target process if the reads are known - * to be sequential. - */ -class LinearReadCache -{ -public: - LinearReadCache(ULONG pageSize = 0x10000); - ~LinearReadCache(); - - /* Reads an address out of the target process, caching the page of memory read. - * Params: - * addr - The address to read out of the target process. - * t - A pointer to the data to stuff it in. We will read sizeof(T) data - * from the process and write it into the location t points to. This - * parameter must be non-null. - * Returns: - * True if the read succeeded. False if it did not, usually as a result - * of the memory simply not being present in the target process. - * Note: - * The state of *t is undefined if this function returns false. We may - * have written partial data to it if we return false, so you must - * absolutely NOT use it if Read returns false. - */ - template <class T> - bool Read(TADDR addr, T *t, bool update = true) - { - _ASSERTE(t); - - // Unfortunately the ctor can fail the alloc for the byte array. In this case - // we'll just fall back to non-cached reads. - if (mPage == NULL) - return MisalignedRead(addr, t); - - // Is addr on the current page? If not read the page of memory addr is on. - // If this fails, we will fall back to a raw read out of the process (which - // is what MisalignedRead does). - if ((addr < mCurrPageStart) || (addr - mCurrPageStart > mCurrPageSize)) - if (!update || !MoveToPage(addr)) - return MisalignedRead(addr, t); - - // If MoveToPage succeeds, we MUST be on the right page. - _ASSERTE(addr >= mCurrPageStart); - - // However, the amount of data requested may fall off of the page. In that case, - // fall back to MisalignedRead. - TADDR offset = addr - mCurrPageStart; - if (offset + sizeof(T) > mCurrPageSize) - return MisalignedRead(addr, t); - - // If we reach here we know we are on the right page of memory in the cache, and - // that the read won't fall off of the end of the page. -#ifdef _DEBUG - mReads++; -#endif - - *t = *reinterpret_cast<T*>(mPage+offset); - return true; - } - - void EnsureRangeInCache(TADDR start, unsigned int size) - { - if (mCurrPageStart == start) - { - if (size <= mCurrPageSize) - return; - - // Total bytes to read, don't overflow buffer. - unsigned int total = size + mCurrPageSize; - if (total + mCurrPageSize > mPageSize) - total = mPageSize-mCurrPageSize; - - // Read into the middle of the buffer, update current page size. - ULONG read = 0; - HRESULT hr = g_ExtData->ReadVirtual(mCurrPageStart+mCurrPageSize, mPage+mCurrPageSize, total, &read); - mCurrPageSize += read; - - if (hr != S_OK) - { - mCurrPageStart = 0; - mCurrPageSize = 0; - } - } - else - { - MoveToPage(start, size); - } - } - - void ClearStats() - { -#ifdef _DEBUG - mMisses = 0; - mReads = 0; - mMisaligned = 0; -#endif - } - - void PrintStats(const char *func) - { -#ifdef _DEBUG - char buffer[1024]; - sprintf_s(buffer, _countof(buffer), "Cache (%s): %d reads (%2.1f%% hits), %d misses (%2.1f%%), %d misaligned (%2.1f%%).\n", - func, mReads, 100*(mReads-mMisses)/(float)(mReads+mMisaligned), mMisses, - 100*mMisses/(float)(mReads+mMisaligned), mMisaligned, 100*mMisaligned/(float)(mReads+mMisaligned)); - OutputDebugStringA(buffer); -#endif - } - -private: - /* Sets the cache to the page specified by addr, or false if we could not move to - * that page. - */ - bool MoveToPage(TADDR addr, unsigned int size = 0x18); - - /* Attempts to read from the target process if the data is possibly hanging off - * the end of a page. - */ - template<class T> - inline bool MisalignedRead(TADDR addr, T *t) - { - ULONG fetched = 0; - HRESULT hr = g_ExtData->ReadVirtual(addr, (BYTE*)t, sizeof(T), &fetched); - - if (FAILED(hr) || fetched != sizeof(T)) - return false; - - mMisaligned++; - return true; - } - -private: - TADDR mCurrPageStart; - ULONG mPageSize, mCurrPageSize; - BYTE *mPage; - - int mMisses, mReads, mMisaligned; -}; - - -/////////////////////////////////////////////////////////////////////////////////////////// -// -// Methods for creating a database out of the gc heap and it's roots in xml format or CLRProfiler format -// - -#include <unordered_map> -#include <unordered_set> -#include <list> - -class TypeTree; -enum { FORMAT_XML=0, FORMAT_CLRPROFILER=1 }; -enum { TYPE_START=0,TYPE_TYPES=1,TYPE_ROOTS=2,TYPE_OBJECTS=3,TYPE_HIGHEST=4}; -class HeapTraverser -{ -private: - TypeTree *m_pTypeTree; - size_t m_curNID; - FILE *m_file; - int m_format; // from the enum above - size_t m_objVisited; // for UI updates - bool m_verify; - LinearReadCache mCache; - - std::unordered_map<TADDR, std::list<TADDR>> mDependentHandleMap; - -public: - HeapTraverser(bool verify); - ~HeapTraverser(); - - FILE *getFile() { return m_file; } - - BOOL Initialize(); - BOOL CreateReport (FILE *fp, int format); - -private: - // First all types are added to a tree - void insert(size_t mTable); - size_t getID(size_t mTable); - - // Functions for writing to the output file. - void PrintType(size_t ID,LPCWSTR name); - - void PrintObjectHead(size_t objAddr,size_t typeID,size_t Size); - void PrintObjectMember(size_t memberValue, bool dependentHandle); - void PrintLoaderAllocator(size_t memberValue); - void PrintObjectTail(); - - void PrintRootHead(); - void PrintRoot(LPCWSTR kind,size_t Value); - void PrintRootTail(); - - void PrintSection(int Type,BOOL bOpening); - - // Root and object member helper functions - void FindGCRootOnStacks(); - void PrintRefs(size_t obj, size_t methodTable, size_t size); - - // Callback functions used during traversals - static void GatherTypes(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable, LPVOID token); - static void PrintHeap(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable, LPVOID token); - static void PrintOutTree(size_t methodTable, size_t ID, LPVOID token); - void TraceHandles(); -}; - - -class GCRootImpl -{ -private: - struct MTInfo - { - TADDR MethodTable; - WCHAR *TypeName; - - TADDR *Buffer; - CGCDesc *GCDesc; - - TADDR LoaderAllocatorObjectHandle; - bool ArrayOfVC; - bool ContainsPointers; - bool Collectible; - size_t BaseSize; - size_t ComponentSize; - - const WCHAR *GetTypeName() - { - if (!TypeName) - TypeName = CreateMethodTableName(MethodTable); - - if (!TypeName) - return W("<error>"); - - return TypeName; - } - - MTInfo() - : MethodTable(0), TypeName(0), Buffer(0), GCDesc(0), - ArrayOfVC(false), ContainsPointers(false), Collectible(false), BaseSize(0), ComponentSize(0) - { - } - - ~MTInfo() - { - if (Buffer) - delete [] Buffer; - - if (TypeName) - delete [] TypeName; - } - }; - - struct RootNode - { - RootNode *Next; - RootNode *Prev; - TADDR Object; - MTInfo *MTInfo; - - bool FilledRefs; - bool FromDependentHandle; - RootNode *GCRefs; - - - const WCHAR *GetTypeName() - { - if (!MTInfo) - return W("<unknown>"); - - return MTInfo->GetTypeName(); - } - - RootNode() - : Next(0), Prev(0) - { - Clear(); - } - - void Clear() - { - if (Next && Next->Prev == this) - Next->Prev = NULL; - - if (Prev && Prev->Next == this) - Prev->Next = NULL; - - Next = 0; - Prev = 0; - Object = 0; - MTInfo = 0; - FilledRefs = false; - FromDependentHandle = false; - GCRefs = 0; - } - - void Remove(RootNode *&list) - { - RootNode *curr_next = Next; - - // We've already considered this object, remove it. - if (Prev == NULL) - { - // If we've filtered out the head, update it. - list = curr_next; - - if (curr_next) - curr_next->Prev = NULL; - } - else - { - // Otherwise remove the current item from the list - Prev->Next = curr_next; - - if (curr_next) - curr_next->Prev = Prev; - } - } - }; - -public: - static void GetDependentHandleMap(std::unordered_map<TADDR, std::list<TADDR>> &map); - -public: - // Finds all objects which root "target" and prints the path from the root - // to "target". If all is true, all possible paths to the object are printed. - // If all is false, only completely unique paths will be printed. - int PrintRootsForObject(TADDR obj, bool all, bool noStacks); - - // Finds a path from root to target if it exists and prints it out. Returns - // true if it found a path, false otherwise. - bool PrintPathToObject(TADDR root, TADDR target); - - // Calculates the size of the closure of objects kept alive by root. - size_t ObjSize(TADDR root); - - // Walks each root, printing out the total amount of memory held alive by it. - void ObjSize(); - - // Returns the set of all live objects in the process. - const std::unordered_set<TADDR> &GetLiveObjects(bool excludeFQ = false); - - // See !FindRoots. - int FindRoots(int gen, TADDR target); - -private: - // typedefs - typedef void (*ReportCallback)(TADDR root, RootNode *path, bool printHeader); - - // Book keeping and debug. - void ClearAll(); - void ClearNodes(); - void ClearSizeData(); - - // Printing roots - int PrintRootsOnHandleTable(int gen = -1); - int PrintRootsOnAllThreads(); - int PrintRootsOnThread(DWORD osThreadId); - int PrintRootsOnFQ(bool notReadyForFinalization = false); - int PrintRootsInOlderGen(); - int PrintRootsInRange(LinearReadCache &cache, TADDR start, TADDR stop, ReportCallback func, bool printHeader); - - // Calculate gc root - RootNode *FilterRoots(RootNode *&list); - RootNode *FindPathToTarget(TADDR root); - RootNode *GetGCRefs(RootNode *path, RootNode *node); - - void InitDependentHandleMap(); - - //Reporting: - void ReportOneHandlePath(const SOSHandleData &handle, RootNode *node, bool printHeader); - void ReportOnePath(DWORD thread, const SOSStackRefData &stackRef, RootNode *node, bool printThread, bool printFrame); - static void ReportOneFQEntry(TADDR root, RootNode *path, bool printHeader); - static void ReportOlderGenEntry(TADDR root, RootNode *path, bool printHeader); - void ReportSizeInfo(const SOSHandleData &handle, TADDR obj); - void ReportSizeInfo(DWORD thread, const SOSStackRefData &ref, TADDR obj); - - // Data reads: - TADDR ReadPointer(TADDR location); - TADDR ReadPointerCached(TADDR location); - - // Object/MT data: - MTInfo *GetMTInfo(TADDR mt); - DWORD GetComponents(TADDR obj, TADDR mt); - size_t GetSizeOfObject(TADDR obj, MTInfo *info); - - // RootNode management: - RootNode *NewNode(TADDR obj = 0, MTInfo *mtinfo = 0, bool fromDependent = false); - void DeleteNode(RootNode *node); - -private: - - bool mAll, // Print all roots or just unique roots? - mSize; // Print rooting information or total size info? - - std::list<RootNode*> mCleanupList; // A list of RootNode's we've newed up. This is only used to delete all of them later. - std::list<RootNode*> mRootNewList; // A list of unused RootNodes that are free to use instead of having to "new" up more. - - std::unordered_map<TADDR, MTInfo*> mMTs; // The MethodTable cache which maps from MT -> MethodTable data (size, gcdesc, string typename) - std::unordered_map<TADDR, RootNode*> mTargets; // The objects that we are searching for. - std::unordered_set<TADDR> mConsidered; // A hashtable of objects we've already visited. - std::unordered_map<TADDR, size_t> mSizes; // A mapping from object address to total size of data the object roots. - - std::unordered_map<TADDR, std::list<TADDR>> mDependentHandleMap; - - LinearReadCache mCache; // A linear cache which stops us from having to read from the target process more than 1-2 times per object. -}; - -// -// Helper class used for type-safe bitflags -// T - the enum type specifying the individual bit flags -// U - the underlying/storage type -// Requirement: -// sizeof(T) <= sizeof(U) -// -template <typename T, typename U> -struct Flags -{ - typedef T UnderlyingType; - typedef U BitFlagEnumType; - - static_assert_no_msg(sizeof(BitFlagEnumType) <= sizeof(UnderlyingType)); - - Flags(UnderlyingType v) - : m_val(v) - { } - - Flags(BitFlagEnumType v) - : m_val(v) - { } - - Flags(const Flags& other) - : m_val(other.m_val) - { } - - Flags& operator = (const Flags& other) - { m_val = other.m_val; return *this; } - - Flags operator | (Flags other) const - { return Flags<T, U>(m_val | other._val); } - - void operator |= (Flags other) - { m_val |= other.m_val; } - - Flags operator & (Flags other) const - { return Flags<T, U>(m_val & other.m_val); } - - void operator &= (Flags other) - { m_val &= other.m_val; } - - Flags operator ^ (Flags other) const - { return Flags<T, U>(m_val ^ other._val); } - - void operator ^= (Flags other) - { m_val ^= other.m_val; } - - BOOL operator == (Flags other) const - { return m_val == other.m_val; } - - BOOL operator != (Flags other) const - { return m_val != other.m_val; } - - -private: - UnderlyingType m_val; -}; - -#ifndef FEATURE_PAL - -// Flags defining activation policy for COM objects -enum CIOptionsBits -{ - cciLatestFx = 0x01, // look in the most recent .NETFx installation - cciMatchFx = 0x02, // NYI: Look in the .NETFx installation matching the debuggee's runtime - cciAnyFx = 0x04, // look in any .NETFx installation - cciFxMask = 0x0f, - cciDbiColocated = 0x10, // NYI: Look next to the already loaded DBI module - cciDacColocated = 0x20, // Look next to the already loaded DAC module - cciDbgPath = 0x40, // Look in all folders in the debuggers symbols and binary path -}; - -typedef Flags<DWORD, CIOptionsBits> CIOptions; - -/**********************************************************************\ -* Routine Description: * -* * -* CreateInstanceCustom() provides a way to activate a COM object w/o * -* triggering the FeatureOnDemand dialog. In order to do this we * -* must avoid using the CoCreateInstance() API, which, on a machine * -* with v4+ installed and w/o v2, would trigger this. * -* CreateInstanceCustom() activates the requested COM object according * -* to the specified passed in CIOptions, in the following order * -* (skipping the steps not enabled in the CIOptions flags passed in): * -* 1. Attempt to activate the COM object using a framework install: * -* a. If the debugger machine has a V4+ shell shim use the shim * -* to activate the object * -* b. Otherwise simply call CoCreateInstance * -* 2. If unsuccessful attempt to activate looking for the dllName in * -* the same folder as the DAC was loaded from * -* 3. If unsuccessful attempt to activate the COM object looking in * -* every path specified in the debugger's .exepath and .sympath * -\**********************************************************************/ -HRESULT CreateInstanceCustom( - REFCLSID clsid, - REFIID iid, - LPCWSTR dllName, - CIOptions cciOptions, - void** ppItf); - - -//------------------------------------------------------------------------ -// A typesafe version of GetProcAddress -//------------------------------------------------------------------------ -template <typename T> -BOOL -GetProcAddressT( - ___in PCSTR FunctionName, - __in_opt PCWSTR DllName, - __inout T* OutFunctionPointer, - __inout HMODULE* InOutDllHandle - ) -{ - _ASSERTE(InOutDllHandle != NULL); - _ASSERTE(OutFunctionPointer != NULL); - - T FunctionPointer = NULL; - HMODULE DllHandle = *InOutDllHandle; - if (DllHandle == NULL) - { - DllHandle = LoadLibraryExW(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (DllHandle != NULL) - *InOutDllHandle = DllHandle; - } - if (DllHandle != NULL) - { - FunctionPointer = (T) GetProcAddress(DllHandle, FunctionName); - } - *OutFunctionPointer = FunctionPointer; - return FunctionPointer != NULL; -} - - -#endif // FEATURE_PAL - -struct ImageInfo -{ - ULONG64 modBase; -}; - -// Helper class used in ClrStackFromPublicInterface() to keep track of explicit EE Frames -// (i.e., "internal frames") on the stack. Call Init() with the appropriate -// ICorDebugThread3, and this class will initialize itself with the set of internal -// frames. You can then call PrintPrecedingInternalFrames during your stack walk to -// have this class output any internal frames that "precede" (i.e., that are closer to -// the leaf than) the specified ICorDebugFrame. -class InternalFrameManager -{ -private: - // TODO: Verify constructor AND destructor is called for each array element - // TODO: Comment about hard-coding 1000 - ToRelease<ICorDebugInternalFrame2> m_rgpInternalFrame2[1000]; - ULONG32 m_cInternalFramesActual; - ULONG32 m_iInternalFrameCur; - -public: - InternalFrameManager(); - HRESULT Init(ICorDebugThread3 * pThread3); - HRESULT PrintPrecedingInternalFrames(ICorDebugFrame * pFrame); - -private: - HRESULT PrintCurrentInternalFrame(); -}; - -#endif // __util_h__ |