diff options
Diffstat (limited to 'src/debug/daccess/dacimpl.h')
-rw-r--r-- | src/debug/daccess/dacimpl.h | 3998 |
1 files changed, 3998 insertions, 0 deletions
diff --git a/src/debug/daccess/dacimpl.h b/src/debug/daccess/dacimpl.h new file mode 100644 index 0000000000..aaeeeae9e6 --- /dev/null +++ b/src/debug/daccess/dacimpl.h @@ -0,0 +1,3998 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +//***************************************************************************** +// File: dacimpl.h +// + +// +// Central header file for external data access implementation. +// +//***************************************************************************** + + +#ifndef __DACIMPL_H__ +#define __DACIMPL_H__ + +#if defined(_TARGET_ARM_) || defined(FEATURE_CORESYSTEM) // @ARMTODO: STL breaks the build with current VC headers +//--------------------------------------------------------------------------------------- +// Setting DAC_HASHTABLE tells the DAC to use the hand rolled hashtable for +// storing code:DAC_INSTANCE . Otherwise, the DAC uses the STL hash_map to. + +#define DAC_HASHTABLE +#endif // _TARGET_ARM_|| FEATURE_CORESYSTEM + +#ifndef DAC_HASHTABLE +#pragma push_macro("return") +#undef return +#include <hash_map> +#pragma pop_macro("return") +#endif //DAC_HASHTABLE +extern CRITICAL_SECTION g_dacCritSec; + +// Convert between CLRDATA_ADDRESS and TADDR. +// Note that CLRDATA_ADDRESS is sign-extended (for compat with Windbg and OS conventions). Converting +// from pointer-size values to CLRDATA_ADDRESS should ALWAYS use this TO_CDADDR macro to avoid bugs when +// dealing with 3/4GB 32-bit address spaces. You must not rely on the compiler's implicit conversion +// from ULONG32 to ULONG64 - it is incorrect. Ideally we'd use some compiler tricks or static analysis +// to help detect such errors (they are nefarious since 3/4GB addresses aren't well tested) . +// +// Note: We're in the process of switching the implementation over to CORDB_ADDRESS instead, which is also +// 64 bits, but 0-extended. This means that conversions between TADDR and CORDB_ADDRESS are simple and natural, +// but as long as we have some legacy code, conversions involving CLRDATA_ADDRESS are a pain. Eventually we +// should eliminate CLRDATA_ADDRESS entirely from the implementation, but that will require moving SOS off of +// the old DAC stuff etc. +// +// Here are the possible conversions: +// TADDR -> CLRDATA_ADDRESS: TO_CDADDR +// CORDB_ADDRESS -> CLRDATA_ADDRESS: TO_CDADDR +// CLRDATA_ADDRESS -> TADDR: CLRDATA_ADDRESS_TO_TADDR +// CORDB_ADDRESS -> TADDR: CORDB_ADDRESS_TO_TADDR +// TADDR -> CORDB_ADDRESS: implicit +// CLRDATA_ADDRESS -> CORDB_ADDRESS: CLRDATA_ADDRESS_TO_TADDR +// +#define TO_CDADDR(taddr) ((CLRDATA_ADDRESS)(LONG_PTR)(taddr)) + +// Convert a CLRDATA_ADDRESS (64-bit unsigned sign-extended target address) to a TADDR +inline TADDR CLRDATA_ADDRESS_TO_TADDR(CLRDATA_ADDRESS cdAddr) +{ + SUPPORTS_DAC; +#ifndef _WIN64 + static_assert_no_msg(sizeof(TADDR)==sizeof(UINT)); + INT64 iSignedAddr = (INT64)cdAddr; + if (iSignedAddr > INT_MAX || iSignedAddr < INT_MIN) + { + _ASSERTE_MSG(false, "CLRDATA_ADDRESS out of range for this platform"); + DacError(E_INVALIDARG); + } +#endif + return (TADDR)cdAddr; +} + +// No throw, Convert a CLRDATA_ADDRESS (64-bit unsigned sign-extended target address) to a TADDR +// Use this in places where we know windbg may pass in bad addresses +inline HRESULT TRY_CLRDATA_ADDRESS_TO_TADDR(CLRDATA_ADDRESS cdAddr, TADDR* pOutTaddr) +{ + SUPPORTS_DAC; +#ifndef _WIN64 + static_assert_no_msg(sizeof(TADDR)==sizeof(UINT)); + INT64 iSignedAddr = (INT64)cdAddr; + if (iSignedAddr > INT_MAX || iSignedAddr < INT_MIN) + { + *pOutTaddr = 0; + return E_INVALIDARG; + } +#endif + *pOutTaddr = (TADDR)cdAddr; + return S_OK; +} + +// Convert a CORDB_ADDRESS (64-bit unsigned 0-extended target address) to a TADDR +inline TADDR CORDB_ADDRESS_TO_TADDR(CORDB_ADDRESS cdbAddr) +{ + SUPPORTS_DAC; +#ifndef _WIN64 + static_assert_no_msg(sizeof(TADDR)==sizeof(UINT)); + if (cdbAddr > UINT_MAX) + { + _ASSERTE_MSG(false, "CORDB_ADDRESS out of range for this platform"); + DacError(E_INVALIDARG); + } +#endif + return (TADDR)cdbAddr; +} + +// TO_TADDR is the old way of converting CLRDATA_ADDRESSes to TADDRs. Unfortunately, +// this has been used in many places to also cast pointers (void* etc.) to TADDR, and +// so we can't actually require the argument to be a valid CLRDATA_ADDRESS. New code +// should use CLRDATA_ADDRESS_TO_TADDR instead. +#define TO_TADDR(cdaddr) ((TADDR)(cdaddr)) + +#define TO_CDENUM(ptr) ((CLRDATA_ENUM)(ULONG_PTR)(ptr)) +#define FROM_CDENUM(type, cdenum) ((type*)(ULONG_PTR)(cdenum)) + +#define SIMPFRAME_ALL \ + (CLRDATA_SIMPFRAME_UNRECOGNIZED | \ + CLRDATA_SIMPFRAME_MANAGED_METHOD | \ + CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE | \ + CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE) + +enum DAC_USAGE_TYPE +{ + DAC_DPTR, + DAC_VPTR, + DAC_STRA, + DAC_STRW, +}; + +// mscordacwks's module handle +extern HINSTANCE g_thisModule; + +class ReflectionModule; + +struct DAC_MD_IMPORT +{ + DAC_MD_IMPORT* next; // list link field + TADDR peFile; // a TADDR for a PEFile* or a ReflectionModule* + IMDInternalImport* impl; // Associated metadata interface + bool isAlternate; // for NGEN images set to true if the metadata corresponds to the IL image + + DAC_MD_IMPORT(TADDR peFile_, + IMDInternalImport* impl_, + bool isAlt_ = false, + DAC_MD_IMPORT* next_ = NULL) + : next(next_) + , peFile(peFile_) + , impl(impl_) + , isAlternate(isAlt_) + { + SUPPORTS_DAC_HOST_ONLY; + } +}; + + +// This class maintains a cache of IMDInternalImport* and their corresponding +// source (a PEFile* or a ReflectionModule*), as a singly-linked list of +// DAC_MD_IMPORT nodes. The cache is flushed whenever the process state changes +// by calling its Flush() member function. +class MDImportsCache +{ +public: + + MDImportsCache() + : m_head(NULL) + {} + + ~MDImportsCache() + { + Flush(); + } + + FORCEINLINE + IMDInternalImport* Get(TADDR key) const + { + SUPPORTS_DAC; + for (DAC_MD_IMPORT* importList = m_head; importList; importList = importList->next) + { + if (importList->peFile == key) + { + return importList->impl; + } + } + return NULL; + } + + FORCEINLINE + DAC_MD_IMPORT* Add(TADDR peFile, IMDInternalImport* impl, bool isAlt) + { + SUPPORTS_DAC; + DAC_MD_IMPORT* importList = new (nothrow) DAC_MD_IMPORT(peFile, impl, isAlt, m_head); + if (!importList) + { + return NULL; + } + + m_head = importList; + return importList; + } + + void Flush() + { + DAC_MD_IMPORT* importList; + + while (m_head) + { + importList = m_head; + m_head = importList->next; + importList->impl->Release(); + delete importList; + } + } + +private: + + DAC_MD_IMPORT* m_head; // the beginning of the list of cached MD imports + +}; + +struct METH_EXTENTS +{ + ULONG32 numExtents; + ULONG32 curExtent; + // Currently only one is needed. + CLRDATA_ADDRESS_RANGE extents[1]; +}; + +HRESULT ConvertUtf8(__in LPCUTF8 utf8, + ULONG32 bufLen, + ULONG32* nameLen, + __out_ecount_part_opt(bufLen, *nameLen) PWSTR buffer); +HRESULT AllocUtf8(__in_opt LPCWSTR wstr, + ULONG32 srcChars, + __deref_out LPUTF8* utf8); + +HRESULT GetFullClassNameFromMetadata(IMDInternalImport* mdImport, + mdTypeDef classToken, + ULONG32 bufferChars, + __inout_ecount(bufferChars) LPUTF8 buffer); +HRESULT GetFullMethodNameFromMetadata(IMDInternalImport* mdImport, + mdMethodDef methodToken, + ULONG32 bufferChars, + __inout_ecount(bufferChars) LPUTF8 buffer); + +enum SplitSyntax +{ + SPLIT_METHOD, + SPLIT_TYPE, + SPLIT_FIELD, + SPLIT_NO_NAME, +}; + +HRESULT SplitFullName(__in_z __in PCWSTR fullName, + SplitSyntax syntax, + ULONG32 memberDots, + __deref_out_opt LPUTF8* namespaceName, + __deref_out_opt LPUTF8* typeName, + __deref_out_opt LPUTF8* memberName, + __deref_out_opt LPUTF8* params); + +int CompareUtf8(__in LPCUTF8 str1, __in LPCUTF8 str2, __in ULONG32 nameFlags); + +#define INH_STATIC \ + (CLRDATA_VALUE_ALL_KINDS | \ + CLRDATA_VALUE_IS_INHERITED | CLRDATA_VALUE_FROM_STATIC) + +HRESULT InitFieldIter(DeepFieldDescIterator* fieldIter, + TypeHandle typeHandle, + bool canHaveFields, + ULONG32 flags, + IXCLRDataTypeInstance* fromType); + +ULONG32 GetTypeFieldValueFlags(TypeHandle typeHandle, + FieldDesc* fieldDesc, + ULONG32 otherFlags, + bool isDeref); + +//---------------------------------------------------------------------------- +// +// MetaEnum. +// +//---------------------------------------------------------------------------- + +class MetaEnum +{ +public: + MetaEnum(void) + : m_domainIter(FALSE) + { + Clear(); + m_appDomain = NULL; + } + ~MetaEnum(void) + { + End(); + } + + void Clear(void) + { + m_mdImport = NULL; + m_kind = 0; + m_lastToken = mdTokenNil; + } + + HRESULT Start(IMDInternalImport* mdImport, ULONG32 kind, + mdToken container); + void End(void); + + HRESULT NextToken(mdToken* token, + __deref_opt_out_opt LPCUTF8* namespaceName, + __deref_opt_out_opt LPCUTF8* name); + HRESULT NextDomainToken(AppDomain** appDomain, + mdToken* token); + HRESULT NextTokenByName(__in_opt LPCUTF8 namespaceName, + __in_opt LPCUTF8 name, + ULONG32 nameFlags, + mdToken* token); + HRESULT NextDomainTokenByName(__in_opt LPCUTF8 namespaceName, + __in_opt LPCUTF8 name, + ULONG32 nameFlags, + AppDomain** appDomain, mdToken* token); + + static HRESULT CdNextToken(CLRDATA_ENUM* handle, + mdToken* token) + { + MetaEnum* iter = FROM_CDENUM(MetaEnum, *handle); + if (!iter) + { + return S_FALSE; + } + + return iter->NextToken(token, NULL, NULL); + } + static HRESULT CdNextDomainToken(CLRDATA_ENUM* handle, + AppDomain** appDomain, + mdToken* token) + { + MetaEnum* iter = FROM_CDENUM(MetaEnum, *handle); + if (!iter) + { + return S_FALSE; + } + + return iter->NextDomainToken(appDomain, token); + } + static HRESULT CdEnd(CLRDATA_ENUM handle) + { + MetaEnum* iter = FROM_CDENUM(MetaEnum, handle); + if (iter) + { + delete iter; + return S_OK; + } + else + { + return E_INVALIDARG; + } + } + + IMDInternalImport* m_mdImport; + ULONG32 m_kind; + HENUMInternal m_enum; + AppDomain* m_appDomain; + AppDomainIterator m_domainIter; + mdToken m_lastToken; + + static HRESULT New(Module* mod, + ULONG32 kind, + mdToken container, + IXCLRDataAppDomain* pubAppDomain, + MetaEnum** metaEnum, + CLRDATA_ENUM* handle); +}; + +//---------------------------------------------------------------------------- +// +// SplitName. +// +//---------------------------------------------------------------------------- + +class SplitName +{ +public: + // Type of name and splitting being done in this instance. + SplitSyntax m_syntax; + ULONG32 m_nameFlags; + ULONG32 m_memberDots; + + // Split fields. + LPUTF8 m_namespaceName; + LPUTF8 m_typeName; + mdTypeDef m_typeToken; + LPUTF8 m_memberName; + mdMethodDef m_memberToken; + LPUTF8 m_params; + // XXX Microsoft - Translated signature. + + // Arbitrary extra data. + Thread* m_tlsThread; + Module* m_module; + MetaEnum m_metaEnum; + DeepFieldDescIterator m_fieldEnum; + ULONG64 m_objBase; + FieldDesc* m_lastField; + + SplitName(SplitSyntax syntax, ULONG32 nameFlags, + ULONG32 memberDots); + ~SplitName(void) + { + Delete(); + } + + void Delete(void); + void Clear(void); + + HRESULT SplitString(__in_opt PCWSTR fullName); + + bool FindType(IMDInternalImport* mdInternal); + bool FindMethod(IMDInternalImport* mdInternal); + bool FindField(IMDInternalImport* mdInternal); + + int Compare(LPCUTF8 str1, LPCUTF8 str2) + { + return CompareUtf8(str1, str2, m_nameFlags); + } + + static HRESULT AllocAndSplitString(__in_opt PCWSTR fullName, + SplitSyntax syntax, + ULONG32 nameFlags, + ULONG32 memberDots, + SplitName** split); + + static HRESULT CdStartMethod(__in_opt PCWSTR fullName, + ULONG32 nameFlags, + Module* mod, + mdTypeDef typeToken, + AppDomain* appDomain, + IXCLRDataAppDomain* pubAppDomain, + SplitName** split, + CLRDATA_ENUM* handle); + static HRESULT CdNextMethod(CLRDATA_ENUM* handle, + mdMethodDef* token); + static HRESULT CdNextDomainMethod(CLRDATA_ENUM* handle, + AppDomain** appDomain, + mdMethodDef* token); + + static HRESULT CdStartField(__in_opt PCWSTR fullName, + ULONG32 nameFlags, + ULONG32 fieldFlags, + IXCLRDataTypeInstance* fromTypeInst, + TypeHandle typeHandle, + Module* mod, + mdTypeDef typeToken, + ULONG64 objBase, + Thread* tlsThread, + IXCLRDataTask* pubTlsThread, + AppDomain* appDomain, + IXCLRDataAppDomain* pubAppDomain, + SplitName** split, + CLRDATA_ENUM* handle); + static HRESULT CdNextField(ClrDataAccess* dac, + CLRDATA_ENUM* handle, + IXCLRDataTypeDefinition** fieldType, + ULONG32* fieldFlags, + IXCLRDataValue** value, + ULONG32 nameBufRetLen, + ULONG32* nameLenRet, + __out_ecount_part_opt(nameBufRetLen, *nameLenRet) WCHAR nameBufRet[ ], + IXCLRDataModule** tokenScopeRet, + mdFieldDef* tokenRet); + static HRESULT CdNextDomainField(ClrDataAccess* dac, + CLRDATA_ENUM* handle, + IXCLRDataValue** value); + + static HRESULT CdStartType(__in_opt PCWSTR fullName, + ULONG32 nameFlags, + Module* mod, + AppDomain* appDomain, + IXCLRDataAppDomain* pubAppDomain, + SplitName** split, + CLRDATA_ENUM* handle); + static HRESULT CdNextType(CLRDATA_ENUM* handle, + mdTypeDef* token); + static HRESULT CdNextDomainType(CLRDATA_ENUM* handle, + AppDomain** appDomain, + mdTypeDef* token); + + static HRESULT CdEnd(CLRDATA_ENUM handle) + { + SplitName* split = FROM_CDENUM(SplitName, handle); + if (split) + { + delete split; + return S_OK; + } + else + { + return E_INVALIDARG; + } + } +}; + +//---------------------------------------------------------------------------- +// +// ProcessModIter. +// +//---------------------------------------------------------------------------- + +struct ProcessModIter +{ + AppDomainIterator m_domainIter; + bool m_nextDomain; + AppDomain::AssemblyIterator m_assemIter; + bool m_iterShared; +#ifdef FEATURE_LOADER_OPTIMIZATION + SharedDomain::SharedAssemblyIterator m_sharedIter; +#endif + Assembly* m_curAssem; + Assembly::ModuleIterator m_modIter; + + ProcessModIter(void) + : m_domainIter(FALSE) + { + SUPPORTS_DAC; + m_nextDomain = true; + m_iterShared = false; + m_curAssem = NULL; + } + + Assembly * NextAssem() + { + SUPPORTS_DAC; + while (!m_iterShared) + { + if (m_nextDomain) + { + if (!m_domainIter.Next()) + { + m_iterShared = true; + break; + } + + m_nextDomain = false; + + m_assemIter = m_domainIter.GetDomain()->IterateAssembliesEx((AssemblyIterationFlags)( + kIncludeLoaded | kIncludeExecution)); + } + + CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly; + if (!m_assemIter.Next(pDomainAssembly.This())) + { + m_nextDomain = true; + continue; + } + + // Note: DAC doesn't need to keep the assembly alive - see code:CollectibleAssemblyHolder#CAH_DAC + CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly(); + if (!pAssembly->IsDomainNeutral()) + { + // We've found a domain-specific assembly, so this is a unique element in the Assembly + // iteration. + return pAssembly; + } + + // Found a shared assembly, which may be duplicated + // across app domains. Ignore it now and let + // it get picked up in the shared iteration where + // it'll only occur once. + } +#ifdef FEATURE_LOADER_OPTIMIZATION + if (!m_sharedIter.Next()) + { + return NULL; + } + return m_sharedIter.GetAssembly(); +#else + return NULL; +#endif + } + + Module* NextModule(void) + { + SUPPORTS_DAC; + for (;;) + { + if (!m_curAssem) + { + m_curAssem = NextAssem(); + if (!m_curAssem) + { + return NULL; + } + + m_modIter = m_curAssem->IterateModules(); + } + + if (!m_modIter.Next()) + { + m_curAssem = NULL; + continue; + } + + return m_modIter.GetModule(); + } + } +}; + +//---------------------------------------------------------------------------- +// +// DacInstanceManager. +// +//---------------------------------------------------------------------------- + +// The data for an access may have special alignment needs and +// the cache must provide similar semantics. +#define DAC_INSTANCE_ALIGN 16 + +#define DAC_INSTANCE_SIG 0xdac1 + +// The instance manager allocates large blocks and then +// suballocates those for particular instances. +struct DAC_INSTANCE_BLOCK +{ + DAC_INSTANCE_BLOCK* next; + ULONG32 bytesUsed; + ULONG32 bytesFree; +}; + +#define DAC_INSTANCE_BLOCK_ALLOCATION 0x40000 + +// Sufficient memory is allocated to guarantee storage of the +// instance header plus room for alignment padding. +// Once the aligned pointer is found, this structure is prepended to +// the aligned pointer and therefore doesn't affect the alignment +// of the actual instance data. +struct DAC_INSTANCE +{ + DAC_INSTANCE* next; + TADDR addr; + ULONG32 size; + // Identifying marker to give a simple + // check for host->taddr validity. + ULONG32 sig:16; + // DPTR or VPTR. See code:DAC_USAGE_TYPE + ULONG32 usage:2; + + // Marker that can be used to prevent reporting this memory to the callback + // object (via ICLRDataEnumMemoryRegionsCallback:EnumMemoryRegion) + // more than once. This bit is checked only by the DacEnumHost?PtrMem + // macros, so consistent use of those macros ensures that the memory is + // reported at most once + ULONG32 enumMem:1; + + // Marker to prevent metadata gets reported to mini-dump + ULONG32 noReport:1; + + // Marker to determine if EnumMemoryRegions has been called on + // a method descriptor + ULONG32 MDEnumed:1; + +#ifdef _WIN64 + // Keep DAC_INSTANCE a multiple of DAC_INSTANCE_ALIGN + // bytes in size. + ULONG32 pad[2]; +#endif +}; + +struct DAC_INSTANCE_PUSH +{ + DAC_INSTANCE_PUSH* next; + DAC_INSTANCE_BLOCK* blocks; + ULONG64 blockMemUsage; + ULONG32 numInst; + ULONG64 instMemUsage; +}; + +// The runtime will want the best access locality possible, +// so it's likely that many instances will be clustered. +// The hash function needs to spread near addresses across +// hash entries, so hash on the low bits of the target address. +// Not all the way down to the LSB, though, as there generally +// won't be individual accesses at the byte level. Assume that +// most accesses will be natural-word aligned. +#define DAC_INSTANCE_HASH_BITS 10 +#define DAC_INSTANCE_HASH_SHIFT 2 + +#define DAC_INSTANCE_HASH(addr) \ + (((ULONG32)(ULONG_PTR)(addr) >> DAC_INSTANCE_HASH_SHIFT) & \ + ((1 << DAC_INSTANCE_HASH_BITS) - 1)) +#define DAC_INSTANCE_HASH_SIZE (1 << DAC_INSTANCE_HASH_BITS) + + +struct DumpMemoryReportStatics +{ + TSIZE_T m_cbStack; // number of bytes that we report directly for stack walk + TSIZE_T m_cbNgen; // number of bytes that we report directly for ngen images + TSIZE_T m_cbModuleList; // number of bytes that we report for module list directly + TSIZE_T m_cbClrStatics; // number of bytes that we report for CLR statics + TSIZE_T m_cbClrHeapStatics; // number of bytes that we report for CLR heap statics + TSIZE_T m_cbImplicity; // number of bytes that we report implicitly +}; + + +class DacInstanceManager +{ +public: + DacInstanceManager(void); + ~DacInstanceManager(void); + + DAC_INSTANCE* Add(DAC_INSTANCE* inst); + + DAC_INSTANCE* Alloc(TADDR addr, ULONG32 size, DAC_USAGE_TYPE usage); + void ReturnAlloc(DAC_INSTANCE* inst); + DAC_INSTANCE* Find(TADDR addr); + HRESULT Write(DAC_INSTANCE* inst, bool throwEx); + void Supersede(DAC_INSTANCE* inst); + void Flush(void); + void Flush(bool fSaveBlock); + void ClearEnumMemMarker(void); + + void AddSuperseded(DAC_INSTANCE* inst) + { + SUPPORTS_DAC; + inst->next = m_superseded; + m_superseded = inst; + } + + UINT DumpAllInstances(ICLRDataEnumMemoryRegionsCallback *pCallBack); + +private: + + DAC_INSTANCE_BLOCK* FindInstanceBlock(DAC_INSTANCE* inst); + void FreeAllBlocks(bool fSaveBlock); + + void InitEmpty(void) + { + m_blocks = NULL; + // m_unusedBlock is not NULLed here; it can contain one block we will use after + // a flush is complete. + m_blockMemUsage = 0; + m_numInst = 0; + m_instMemUsage = 0; +#ifdef DAC_HASHTABLE + ZeroMemory(m_hash, sizeof(m_hash)); +#endif + m_superseded = NULL; + m_instPushed = NULL; + } + +#if defined(DAC_HASHTABLE) + + typedef struct _HashInstanceKey { + TADDR addr; + DAC_INSTANCE* instance; + } HashInstanceKey; + + typedef struct _HashInstanceKeyBlock { + // Blocks are chained in reverse order of allocation so that the most recently allocated + // block is searched first. + _HashInstanceKeyBlock* next; + + // Entries to a block are added from the max index on down so that recently added + // entries are at the start of the block. + DWORD firstElement; + HashInstanceKey instanceKeys[] ; + } HashInstanceKeyBlock; + +// The hashing function does a good job of distributing the entries across buckets. To handle a +// SO on x86, we have under 250 entries in a bucket. A 4K block size allows 511 entries on x86 and +// about half that on x64. On x64, the number of entries added to the hash table is significantly +// smaller than on x86 (and the max recursion depth for default stack sizes is also far less), so +// 4K is generally adequate. + +#define HASH_INSTANCE_BLOCK_ALLOC_SIZE (4 * 1024) +#define HASH_INSTANCE_BLOCK_NUM_ELEMENTS ((HASH_INSTANCE_BLOCK_ALLOC_SIZE - offsetof(_HashInstanceKeyBlock, instanceKeys))/sizeof(HashInstanceKey)) +#endif // #if defined(DAC_HASHTABLE) + + DAC_INSTANCE_BLOCK* m_blocks; + DAC_INSTANCE_BLOCK* m_unusedBlock; + ULONG64 m_blockMemUsage; + ULONG32 m_numInst; + ULONG64 m_instMemUsage; + +#if defined(DAC_HASHTABLE) + HashInstanceKeyBlock* m_hash[DAC_INSTANCE_HASH_SIZE]; +#else //DAC_HASHTABLE + + // We're going to use the STL hash_map for our instance hash. + // This has the benefit of scaling to different workloads appropriately (as opposed to having a + // fixed number of buckets). + + class DacHashCompare : public std::hash_compare<TADDR> + { + public: + // Custom hash function + // The default hash function uses a pseudo-randomizing function to get a random + // distribution. In our case, we'd actually like a more even distribution to get + // better access locality (see comments for DAC_INSTANCE_HASH_BITS). + // + // Also, when enumerating the hash during dump generation, clustering nearby addresses + // together can have a significant positive impact on the performance of the minidump + // library (at least the un-optimized version 6.5 linked into our dw20.exe - on Vista+ + // we use the OS's version 6.7+ with radically improved perf characteristics). Having + // a random distribution is actually the worst-case because it means most blocks won't + // be merged until near the end, and a large number of intermediate blocks will have to + // be searched with each call. + // + // The default pseudo-randomizing function also requires a call to ldiv which shows up as + // a 3%-5% perf hit in most perf-sensitive scenarios, so this should also always be + // faster. + inline size_t operator()(const TADDR& keyval) const + { + return (unsigned)(keyval >>DAC_INSTANCE_HASH_SHIFT); + } + + // Explicitly bring in the two-argument comparison function from the base class (just less-than) + // This is necessary because once we override one form of operator() above, we don't automatically + // get the others by C++ inheritance rules. + using std::hash_compare<TADDR>::operator(); + +#ifdef NIDUMP_CUSTOMIZED_DAC_HASH // not set + //this particular number is supposed to be roughly the same amount of + //memory as the old code (buckets * number of entries in the old + //blocks.) + //disabled for now. May tweak implementation later. It turns out that + //having a large number of initial buckets is excellent for nidump, but it + // is terrible for most other scenarios due to the cost of clearing them at + // every Flush. Once there is a better perf suite, we can tweak these values more. + static const size_t min_buckets = DAC_INSTANCE_HASH_SIZE * 256; +#endif + + }; + typedef stdext::hash_map<TADDR, DAC_INSTANCE*, DacHashCompare > DacInstanceHash; + typedef DacInstanceHash::value_type DacInstanceHashValue; + typedef DacInstanceHash::iterator DacInstanceHashIterator; + DacInstanceHash m_hash; +#endif //DAC_HASHTABLE + + DAC_INSTANCE* m_superseded; + DAC_INSTANCE_PUSH* m_instPushed; +}; + + +#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS + +class DacStreamManager; + +#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS + + +//---------------------------------------------------------------------------- +// +// ClrDataAccess. +// +//---------------------------------------------------------------------------- + +class ClrDataAccess + : public IXCLRDataProcess2, + public ICLRDataEnumMemoryRegions, + public ISOSDacInterface, + public ISOSDacInterface2 +{ +public: + ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLegacyTarget=0); + ~ClrDataAccess(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataProcess. + // + + virtual HRESULT STDMETHODCALLTYPE Flush( void); + + virtual HRESULT STDMETHODCALLTYPE StartEnumTasks( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumTask( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataTask **task); + + virtual HRESULT STDMETHODCALLTYPE EndEnumTasks( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetTaskByOSThreadID( + /* [in] */ ULONG32 OSThreadID, + /* [out] */ IXCLRDataTask **task); + + virtual HRESULT STDMETHODCALLTYPE GetTaskByUniqueID( + /* [in] */ ULONG64 uniqueID, + /* [out] */ IXCLRDataTask **task); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataProcess *process); + + virtual HRESULT STDMETHODCALLTYPE GetManagedObject( + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE GetDesiredExecutionState( + /* [out] */ ULONG32 *state); + + virtual HRESULT STDMETHODCALLTYPE SetDesiredExecutionState( + /* [in] */ ULONG32 state); + + virtual HRESULT STDMETHODCALLTYPE GetAddressType( + /* [in] */ CLRDATA_ADDRESS address, + /* [out] */ CLRDataAddressType* type); + + virtual HRESULT STDMETHODCALLTYPE GetRuntimeNameByAddress( + /* [in] */ CLRDATA_ADDRESS address, + /* [in] */ ULONG32 flags, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_opt(bufLen) WCHAR nameBuf[ ], + /* [out] */ CLRDATA_ADDRESS* displacement); + + virtual HRESULT STDMETHODCALLTYPE StartEnumAppDomains( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumAppDomain( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataAppDomain **appDomain); + + virtual HRESULT STDMETHODCALLTYPE EndEnumAppDomains( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetAppDomainByUniqueID( + /* [in] */ ULONG64 uniqueID, + /* [out] */ IXCLRDataAppDomain **appDomain); + + virtual HRESULT STDMETHODCALLTYPE StartEnumAssemblies( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumAssembly( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataAssembly **assembly); + + virtual HRESULT STDMETHODCALLTYPE EndEnumAssemblies( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumModules( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumModule( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataModule **mod); + + virtual HRESULT STDMETHODCALLTYPE EndEnumModules( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetModuleByAddress( + /* [in] */ CLRDATA_ADDRESS address, + /* [out] */ IXCLRDataModule** mod); + + virtual HRESULT STDMETHODCALLTYPE StartEnumMethodDefinitionsByAddress( + /* [in] */ CLRDATA_ADDRESS address, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumMethodDefinitionByAddress( + /* [in] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataMethodDefinition **method); + + virtual HRESULT STDMETHODCALLTYPE EndEnumMethodDefinitionsByAddress( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumMethodInstancesByAddress( + /* [in] */ CLRDATA_ADDRESS address, + /* [in] */ IXCLRDataAppDomain* appDomain, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumMethodInstanceByAddress( + /* [in] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataMethodInstance **method); + + virtual HRESULT STDMETHODCALLTYPE EndEnumMethodInstancesByAddress( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetDataByAddress( + /* [in] */ CLRDATA_ADDRESS address, + /* [in] */ ULONG32 flags, + /* [in] */ IXCLRDataAppDomain* appDomain, + /* [in] */ IXCLRDataTask* tlsTask, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ IXCLRDataValue **value, + /* [out] */ CLRDATA_ADDRESS *displacement); + + virtual HRESULT STDMETHODCALLTYPE GetExceptionStateByExceptionRecord( + /* [in] */ EXCEPTION_RECORD64 *record, + /* [out] */ IXCLRDataExceptionState **exception); + + virtual HRESULT STDMETHODCALLTYPE TranslateExceptionRecordToNotification( + /* [in] */ EXCEPTION_RECORD64 *record, + /* [in] */ IXCLRDataExceptionNotification *notify); + + virtual HRESULT STDMETHODCALLTYPE CreateMemoryValue( + /* [in] */ IXCLRDataAppDomain* appDomain, + /* [in] */ IXCLRDataTask* tlsTask, + /* [in] */ IXCLRDataTypeInstance* type, + /* [in] */ CLRDATA_ADDRESS addr, + /* [out] */ IXCLRDataValue** value); + + virtual HRESULT STDMETHODCALLTYPE SetAllTypeNotifications( + /* [in] */ IXCLRDataModule* mod, + /* [in] */ ULONG32 flags); + + virtual HRESULT STDMETHODCALLTYPE SetAllCodeNotifications( + /* [in] */ IXCLRDataModule* mod, + /* [in] */ ULONG32 flags); + + virtual HRESULT STDMETHODCALLTYPE GetTypeNotifications( + /* [in] */ ULONG32 numTokens, + /* [in, size_is(numTokens)] */ IXCLRDataModule* mods[], + /* [in] */ IXCLRDataModule* singleMod, + /* [in, size_is(numTokens)] */ mdTypeDef tokens[], + /* [out, size_is(numTokens)] */ ULONG32 flags[]); + + virtual HRESULT STDMETHODCALLTYPE SetTypeNotifications( + /* [in] */ ULONG32 numTokens, + /* [in, size_is(numTokens)] */ IXCLRDataModule* mods[], + /* [in] */ IXCLRDataModule* singleMod, + /* [in, size_is(numTokens)] */ mdTypeDef tokens[], + /* [in, size_is(numTokens)] */ ULONG32 flags[], + /* [in] */ ULONG32 singleFlags); + + virtual HRESULT STDMETHODCALLTYPE GetCodeNotifications( + /* [in] */ ULONG32 numTokens, + /* [in, size_is(numTokens)] */ IXCLRDataModule* mods[], + /* [in] */ IXCLRDataModule* singleMod, + /* [in, size_is(numTokens)] */ mdMethodDef tokens[], + /* [out, size_is(numTokens)] */ ULONG32 flags[]); + + virtual HRESULT STDMETHODCALLTYPE SetCodeNotifications( + /* [in] */ ULONG32 numTokens, + /* [in, size_is(numTokens)] */ IXCLRDataModule* mods[], + /* [in] */ IXCLRDataModule* singleMod, + /* [in, size_is(numTokens)] */ mdMethodDef tokens[], + /* [in, size_is(numTokens)] */ ULONG32 flags[], + /* [in] */ ULONG32 singleFlags); + + virtual HRESULT STDMETHODCALLTYPE GetOtherNotificationFlags( + /* [out] */ ULONG32* flags); + + virtual HRESULT STDMETHODCALLTYPE SetOtherNotificationFlags( + /* [in] */ ULONG32 flags); + + virtual HRESULT STDMETHODCALLTYPE FollowStub( + /* [in] */ ULONG32 inFlags, + /* [in] */ CLRDATA_ADDRESS inAddr, + /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER* inBuffer, + /* [out] */ CLRDATA_ADDRESS* outAddr, + /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER* outBuffer, + /* [out] */ ULONG32* outFlags); + + virtual HRESULT STDMETHODCALLTYPE FollowStub2( + /* [in] */ IXCLRDataTask* task, + /* [in] */ ULONG32 inFlags, + /* [in] */ CLRDATA_ADDRESS inAddr, + /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER* inBuffer, + /* [out] */ CLRDATA_ADDRESS* outAddr, + /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER* outBuffer, + /* [out] */ ULONG32* outFlags); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + + // + // IXCLRDataProcess2. + // + STDMETHOD(GetGcNotification)(/* [out] */ GcEvtArgs* gcEvtArgs); + STDMETHOD(SetGcNotification)(/* [in] */ GcEvtArgs gcEvtArgs); + + // + // ICLRDataEnumMemoryRegions. + // + virtual HRESULT STDMETHODCALLTYPE EnumMemoryRegions( + /* [in] */ ICLRDataEnumMemoryRegionsCallback *callback, + /* [in] */ ULONG32 miniDumpFlags, + /* [in] */ CLRDataEnumMemoryFlags clrFlags); + + + // ISOSDacInterface + virtual HRESULT STDMETHODCALLTYPE GetThreadStoreData(struct DacpThreadStoreData *data); + virtual HRESULT STDMETHODCALLTYPE GetAppDomainStoreData(struct DacpAppDomainStoreData *data); + virtual HRESULT STDMETHODCALLTYPE GetAppDomainList(unsigned int count, CLRDATA_ADDRESS values[], unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetAppDomainData(CLRDATA_ADDRESS addr, struct DacpAppDomainData *data); + virtual HRESULT STDMETHODCALLTYPE GetAppDomainName(CLRDATA_ADDRESS addr, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetAssemblyList(CLRDATA_ADDRESS appDomain, int count, CLRDATA_ADDRESS values[], int *fetched); + virtual HRESULT STDMETHODCALLTYPE GetAssemblyData(CLRDATA_ADDRESS baseDomainPtr, CLRDATA_ADDRESS assembly, struct DacpAssemblyData *data); + virtual HRESULT STDMETHODCALLTYPE GetAssemblyName(CLRDATA_ADDRESS assembly, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetThreadData(CLRDATA_ADDRESS thread, struct DacpThreadData *data); + virtual HRESULT STDMETHODCALLTYPE GetThreadFromThinlockID(UINT thinLockId, CLRDATA_ADDRESS *pThread); + virtual HRESULT STDMETHODCALLTYPE GetStackLimits(CLRDATA_ADDRESS threadPtr, CLRDATA_ADDRESS *lower, CLRDATA_ADDRESS *upper, CLRDATA_ADDRESS *fp); + virtual HRESULT STDMETHODCALLTYPE GetDomainFromContext(CLRDATA_ADDRESS context, CLRDATA_ADDRESS *domain); + + virtual HRESULT STDMETHODCALLTYPE GetMethodDescData(CLRDATA_ADDRESS methodDesc, CLRDATA_ADDRESS ip, struct DacpMethodDescData *data, ULONG cRevertedRejitVersions, DacpReJitData * rgRevertedRejitData, ULONG * pcNeededRevertedRejitData); + virtual HRESULT STDMETHODCALLTYPE GetMethodDescPtrFromIP(CLRDATA_ADDRESS ip, CLRDATA_ADDRESS * ppMD); + virtual HRESULT STDMETHODCALLTYPE GetMethodDescName(CLRDATA_ADDRESS methodDesc, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetMethodDescPtrFromFrame(CLRDATA_ADDRESS frameAddr, CLRDATA_ADDRESS * ppMD); + virtual HRESULT STDMETHODCALLTYPE GetCodeHeaderData(CLRDATA_ADDRESS ip, struct DacpCodeHeaderData *data); + virtual HRESULT STDMETHODCALLTYPE GetThreadpoolData(struct DacpThreadpoolData *data); + virtual HRESULT STDMETHODCALLTYPE GetWorkRequestData(CLRDATA_ADDRESS addrWorkRequest, struct DacpWorkRequestData *data); + virtual HRESULT STDMETHODCALLTYPE GetObjectData(CLRDATA_ADDRESS objAddr, struct DacpObjectData *data); + virtual HRESULT STDMETHODCALLTYPE GetObjectStringData(CLRDATA_ADDRESS obj, unsigned int count, __out_z __inout_ecount(count) wchar_t *stringData, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetObjectClassName(CLRDATA_ADDRESS obj, unsigned int count, __out_z __inout_ecount(count) wchar_t *className, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetMethodTableName(CLRDATA_ADDRESS mt, unsigned int count, __out_z __inout_ecount(count) wchar_t *mtName, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetMethodTableData(CLRDATA_ADDRESS mt, struct DacpMethodTableData *data); + virtual HRESULT STDMETHODCALLTYPE GetMethodTableFieldData(CLRDATA_ADDRESS mt, struct DacpMethodTableFieldData *data); + virtual HRESULT STDMETHODCALLTYPE GetMethodTableTransparencyData(CLRDATA_ADDRESS mt, struct DacpMethodTableTransparencyData *data); + virtual HRESULT STDMETHODCALLTYPE GetMethodTableForEEClass(CLRDATA_ADDRESS eeClass, CLRDATA_ADDRESS *value); + virtual HRESULT STDMETHODCALLTYPE GetFieldDescData(CLRDATA_ADDRESS fieldDesc, struct DacpFieldDescData *data); + virtual HRESULT STDMETHODCALLTYPE GetFrameName(CLRDATA_ADDRESS vtable, unsigned int count, __out_z __inout_ecount(count) wchar_t *frameName, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetModule(CLRDATA_ADDRESS addr, IXCLRDataModule **mod); + virtual HRESULT STDMETHODCALLTYPE GetModuleData(CLRDATA_ADDRESS moduleAddr, struct DacpModuleData *data); + virtual HRESULT STDMETHODCALLTYPE TraverseModuleMap(ModuleMapType mmt, CLRDATA_ADDRESS moduleAddr, MODULEMAPTRAVERSE pCallback, LPVOID token); + virtual HRESULT STDMETHODCALLTYPE GetMethodDescFromToken(CLRDATA_ADDRESS moduleAddr, mdToken token, CLRDATA_ADDRESS *methodDesc); + virtual HRESULT STDMETHODCALLTYPE GetPEFileBase(CLRDATA_ADDRESS addr, CLRDATA_ADDRESS *base); + virtual HRESULT STDMETHODCALLTYPE GetPEFileName(CLRDATA_ADDRESS addr, unsigned int count, __out_z __inout_ecount(count) wchar_t *fileName, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetAssemblyModuleList(CLRDATA_ADDRESS assembly, unsigned int count, CLRDATA_ADDRESS modules[], unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetGCHeapData(struct DacpGcHeapData *data); + virtual HRESULT STDMETHODCALLTYPE GetGCHeapList(unsigned int count, CLRDATA_ADDRESS heaps[], unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetGCHeapDetails(CLRDATA_ADDRESS heap, struct DacpGcHeapDetails *details); + virtual HRESULT STDMETHODCALLTYPE GetGCHeapStaticData(struct DacpGcHeapDetails *data); + virtual HRESULT STDMETHODCALLTYPE GetHeapSegmentData(CLRDATA_ADDRESS seg, struct DacpHeapSegmentData *data); + virtual HRESULT STDMETHODCALLTYPE GetDomainLocalModuleData(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *data); + virtual HRESULT STDMETHODCALLTYPE GetDomainLocalModuleDataFromAppDomain(CLRDATA_ADDRESS appDomainAddr, int moduleID, struct DacpDomainLocalModuleData *data); + virtual HRESULT STDMETHODCALLTYPE GetDomainLocalModuleDataFromModule(CLRDATA_ADDRESS moduleAddr, struct DacpDomainLocalModuleData *data); + virtual HRESULT STDMETHODCALLTYPE GetSyncBlockData(unsigned int number, struct DacpSyncBlockData *data); + virtual HRESULT STDMETHODCALLTYPE GetSyncBlockCleanupData(CLRDATA_ADDRESS addr, struct DacpSyncBlockCleanupData *data); + virtual HRESULT STDMETHODCALLTYPE TraverseRCWCleanupList(CLRDATA_ADDRESS cleanupListPtr, VISITRCWFORCLEANUP pCallback, LPVOID token); + virtual HRESULT STDMETHODCALLTYPE TraverseEHInfo(CLRDATA_ADDRESS ip, DUMPEHINFO pCallback, LPVOID token); + virtual HRESULT STDMETHODCALLTYPE GetStressLogAddress(CLRDATA_ADDRESS *stressLog); + virtual HRESULT STDMETHODCALLTYPE GetJitManagerList(unsigned int count, struct DacpJitManagerInfo managers[], unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetJitHelperFunctionName(CLRDATA_ADDRESS ip, unsigned int count, __out_z __inout_ecount(count) char *name, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetJumpThunkTarget(T_CONTEXT *ctx, CLRDATA_ADDRESS *targetIP, CLRDATA_ADDRESS *targetMD); + virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, VISITHEAP pCallback); + virtual HRESULT STDMETHODCALLTYPE GetCodeHeapList(CLRDATA_ADDRESS jitManager, unsigned int count, struct DacpJitCodeHeapInfo codeHeaps[], unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetMethodTableSlot(CLRDATA_ADDRESS mt, unsigned int slot, CLRDATA_ADDRESS *value); + virtual HRESULT STDMETHODCALLTYPE TraverseVirtCallStubHeap(CLRDATA_ADDRESS pAppDomain, VCSHeapType heaptype, VISITHEAP pCallback); + virtual HRESULT STDMETHODCALLTYPE GetNestedExceptionData(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS *exceptionObject, CLRDATA_ADDRESS *nextNestedException); + virtual HRESULT STDMETHODCALLTYPE GetUsefulGlobals(struct DacpUsefulGlobalsData *data); + virtual HRESULT STDMETHODCALLTYPE GetILForModule(CLRDATA_ADDRESS moduleAddr, DWORD rva, CLRDATA_ADDRESS *il); + virtual HRESULT STDMETHODCALLTYPE GetClrWatsonBuckets(CLRDATA_ADDRESS thread, void *pGenericModeBlock); + virtual HRESULT STDMETHODCALLTYPE GetOOMData(CLRDATA_ADDRESS oomAddr, struct DacpOomData *data); + virtual HRESULT STDMETHODCALLTYPE GetOOMStaticData(struct DacpOomData *data); + virtual HRESULT STDMETHODCALLTYPE GetHeapAnalyzeData(CLRDATA_ADDRESS addr,struct DacpGcHeapAnalyzeData *data); + virtual HRESULT STDMETHODCALLTYPE GetHeapAnalyzeStaticData(struct DacpGcHeapAnalyzeData *data); + virtual HRESULT STDMETHODCALLTYPE GetMethodDescTransparencyData(CLRDATA_ADDRESS methodDesc, struct DacpMethodDescTransparencyData *data); + virtual HRESULT STDMETHODCALLTYPE GetHillClimbingLogEntry(CLRDATA_ADDRESS addr, struct DacpHillClimbingLogEntry *data); + virtual HRESULT STDMETHODCALLTYPE GetThreadLocalModuleData(CLRDATA_ADDRESS thread, unsigned int index, struct DacpThreadLocalModuleData *data); + virtual HRESULT STDMETHODCALLTYPE GetRCWData(CLRDATA_ADDRESS addr, struct DacpRCWData *data); + virtual HRESULT STDMETHODCALLTYPE GetRCWInterfaces(CLRDATA_ADDRESS rcw, unsigned int count, struct DacpCOMInterfacePointerData interfaces[], unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetCCWData(CLRDATA_ADDRESS ccw, struct DacpCCWData *data); + virtual HRESULT STDMETHODCALLTYPE GetCCWInterfaces(CLRDATA_ADDRESS ccw, unsigned int count, struct DacpCOMInterfacePointerData interfaces[], unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetTLSIndex(ULONG *pIndex); + virtual HRESULT STDMETHODCALLTYPE GetDacModuleHandle(HMODULE *phModule); + + virtual HRESULT STDMETHODCALLTYPE GetFailedAssemblyList(CLRDATA_ADDRESS appDomain, int count, CLRDATA_ADDRESS values[], unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetPrivateBinPaths(CLRDATA_ADDRESS appDomain, int count, __out_z __inout_ecount(count) wchar_t *paths, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetAssemblyLocation(CLRDATA_ADDRESS assembly, int count, __out_z __inout_ecount(count) wchar_t *location, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetAppDomainConfigFile(CLRDATA_ADDRESS appDomain, int count, __out_z __inout_ecount(count) wchar_t *configFile, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetApplicationBase(CLRDATA_ADDRESS appDomain, int count, __out_z __inout_ecount(count) wchar_t *base, unsigned int *pNeeded); + + virtual HRESULT STDMETHODCALLTYPE GetFailedAssemblyData(CLRDATA_ADDRESS assembly, unsigned int *pContext, HRESULT *pResult); + virtual HRESULT STDMETHODCALLTYPE GetFailedAssemblyLocation(CLRDATA_ADDRESS assembly, unsigned int count, __out_z __inout_ecount(count) wchar_t *location, unsigned int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetFailedAssemblyDisplayName(CLRDATA_ADDRESS assembly, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded); + + virtual HRESULT STDMETHODCALLTYPE GetStackReferences(DWORD osThreadID, ISOSStackRefEnum **ppEnum); + virtual HRESULT STDMETHODCALLTYPE GetRegisterName(int regNum, unsigned int count, __out_z __inout_ecount(count) wchar_t *buffer, unsigned int *pNeeded); + + virtual HRESULT STDMETHODCALLTYPE GetHandleEnum(ISOSHandleEnum **ppHandleEnum); + virtual HRESULT STDMETHODCALLTYPE GetHandleEnumForTypes(unsigned int types[], unsigned int count, ISOSHandleEnum **ppHandleEnum); + virtual HRESULT STDMETHODCALLTYPE GetHandleEnumForGC(unsigned int gen, ISOSHandleEnum **ppHandleEnum); + + virtual HRESULT STDMETHODCALLTYPE GetThreadAllocData(CLRDATA_ADDRESS thread, struct DacpAllocData *data); + virtual HRESULT STDMETHODCALLTYPE GetHeapAllocData(unsigned int count, struct DacpGenerationAllocData *data, unsigned int *pNeeded); + + // ISOSDacInterface2 + virtual HRESULT STDMETHODCALLTYPE GetObjectExceptionData(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data); + virtual HRESULT STDMETHODCALLTYPE IsRCWDCOMProxy(CLRDATA_ADDRESS rcwAddr, BOOL* isDCOMProxy); + + // + // ClrDataAccess. + // + + HRESULT Initialize(void); + + BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord); +#ifndef FEATURE_PAL + HRESULT GetWatsonBuckets(DWORD dwThreadId, GenericModeBlock * pGM); +#endif // FEATURE_PAL + + + Thread* FindClrThreadByTaskId(ULONG64 taskId); + HRESULT IsPossibleCodeAddress(IN TADDR address); + + PCSTR GetJitHelperName(IN TADDR address, + IN bool dynamicHelpersOnly = false); + HRESULT GetFullMethodName(IN MethodDesc* methodDesc, + IN ULONG32 symbolChars, + IN ULONG32* symbolLen, + __out_ecount_part_opt(symbolChars, *symbolLen) LPWSTR symbol); + HRESULT RawGetMethodName(/* [in] */ CLRDATA_ADDRESS address, + /* [in] */ ULONG32 flags, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_opt(bufLen) WCHAR nameBuf[ ], + /* [out] */ CLRDATA_ADDRESS* displacement); + + HRESULT FollowStubStep( + /* [in] */ Thread* thread, + /* [in] */ ULONG32 inFlags, + /* [in] */ TADDR inAddr, + /* [in] */ union STUB_BUF* inBuffer, + /* [out] */ TADDR* outAddr, + /* [out] */ union STUB_BUF* outBuffer, + /* [out] */ ULONG32* outFlags); + + DebuggerJitInfo* GetDebuggerJitInfo(MethodDesc* methodDesc, + TADDR addr) + { + if (g_pDebugger) + { + return g_pDebugger->GetJitInfo(methodDesc, (PBYTE)addr, NULL); + } + + return NULL; + } + + HRESULT GetMethodExtents(MethodDesc* methodDesc, + METH_EXTENTS** extents); + HRESULT GetMethodVarInfo(MethodDesc* methodDesc, + TADDR address, + ULONG32* numVarInfo, + ICorDebugInfo::NativeVarInfo** varInfo, + ULONG32* codeOffset); + + // If the method has multiple copies of code (because of EnC or code-pitching), + // this returns the info corresponding to address. + // If 'address' and 'codeOffset' are both non-NULL, *codeOffset gets set to + // the offset of 'address' from the start of the method. + HRESULT GetMethodNativeMap(MethodDesc* methodDesc, + TADDR address, + ULONG32* numMap, + DebuggerILToNativeMap** map, + bool* mapAllocated, + CLRDATA_ADDRESS* codeStart, + ULONG32* codeOffset); + + // Get the MethodDesc for a function + MethodDesc * FindLoadedMethodRefOrDef(Module* pModule, mdToken memberRef); + +#ifndef FEATURE_PAL + HRESULT GetClrWatsonBucketsWorker(Thread * pThread, GenericModeBlock * pGM); +#endif // FEATURE_PAL + + HRESULT ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, + DacpGcHeapDetails *detailsData); + HRESULT GetServerAllocData(unsigned int count, struct DacpGenerationAllocData *data, unsigned int *pNeeded); + HRESULT ServerOomData(CLRDATA_ADDRESS addr, DacpOomData *oomData); + HRESULT ServerGCHeapAnalyzeData(CLRDATA_ADDRESS heapAddr, + DacpGcHeapAnalyzeData *analyzeData); + + // + // Memory enumeration. + // + + HRESULT EnumMemoryRegionsWrapper(CLRDataEnumMemoryFlags flags); + + // skinny minidump functions + HRESULT EnumMemoryRegionsWorkerSkinny(CLRDataEnumMemoryFlags flags); + // triage minidump functions + HRESULT EnumMemoryRegionsWorkerMicroTriage(CLRDataEnumMemoryFlags flags); + HRESULT EnumMemoryRegionsWorkerHeap(CLRDataEnumMemoryFlags flags); + + HRESULT EnumMemWalkStackHelper(CLRDataEnumMemoryFlags flags, IXCLRDataStackWalk *pStackWalk, Thread * pThread); + HRESULT DumpManagedObject(CLRDataEnumMemoryFlags flags, OBJECTREF objRef); + HRESULT DumpManagedExcepObject(CLRDataEnumMemoryFlags flags, OBJECTREF objRef); + HRESULT DumpManagedStackTraceStringObject(CLRDataEnumMemoryFlags flags, STRINGREF orefStackTrace); +#ifdef FEATURE_COMINTEROP + HRESULT DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, CLRDATA_ADDRESS ccwPtr); + HRESULT EnumMemStowedException(CLRDataEnumMemoryFlags flags); +#endif + + HRESULT EnumMemWriteDataSegment(); + + // Custom Dump + HRESULT EnumMemoryRegionsWorkerCustom(); + + // helper function for dump code + void EnumWksGlobalMemoryRegions(CLRDataEnumMemoryFlags flags); + void EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags); + + HRESULT EnumMemCollectImages(); + HRESULT EnumMemCLRStatic(CLRDataEnumMemoryFlags flags); + HRESULT EnumMemCLRHeapCrticalStatic(CLRDataEnumMemoryFlags flags); + HRESULT EnumMemDumpModuleList(CLRDataEnumMemoryFlags flags); + HRESULT EnumMemDumpAppDomainInfo(CLRDataEnumMemoryFlags flags); + HRESULT EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags); + HRESULT EnumMemCLRMainModuleInfo(); + + bool ReportMem(TADDR addr, TSIZE_T size, bool fExpectSuccess = true); + bool DacUpdateMemoryRegion(TADDR addr, TSIZE_T bufferSize, BYTE* buffer); + + void ClearDumpStats(); + JITNotification* GetHostJitNotificationTable(); + GcNotification* GetHostGcNotificationTable(); + + void* GetMetaDataFromHost(PEFile* peFile, + bool* isAlternate); + + virtual + interface IMDInternalImport* GetMDImport(const PEFile* peFile, + const ReflectionModule* reflectionModule, + bool throwEx); + + interface IMDInternalImport* GetMDImport(const PEFile* peFile, + bool throwEx) + { + return GetMDImport(peFile, NULL, throwEx); + } + + interface IMDInternalImport* GetMDImport(const ReflectionModule* reflectionModule, + bool throwEx) + { + return GetMDImport(NULL, reflectionModule, throwEx); + } + + //ClrDump support + HRESULT STDMETHODCALLTYPE DumpNativeImage(CLRDATA_ADDRESS loadedBase, + LPCWSTR name, + IXCLRDataDisplay *display, + IXCLRLibrarySupport *support, + IXCLRDisassemblySupport *dis); + + // Set whether inconsistencies in the target should raise asserts. + void SetTargetConsistencyChecks(bool fEnableAsserts); + + // Get whether inconsistencies in the target should raise asserts. + bool TargetConsistencyAssertsEnabled(); + + // Get the ICLRDataTarget2 instance, if any + ICLRDataTarget2 * GetLegacyTarget2() { return m_pLegacyTarget2; } + + // Get the ICLRDataTarget3 instance, if any + ICLRDataTarget3 * GetLegacyTarget3() { return m_pLegacyTarget3; } + + // + // Public Fields + // Note that it would be nice if all of these were made private. However, the visibility + // model of the DAC implementation is that the public surface area is declared in daccess.h + // (implemented in dacfn.cpp), and the private surface area (like ClrDataAccess) is declared + // in dacimpl.h which is only included by the DAC infrastructure. Therefore the DAC + // infrastructure agressively uses these fields, and we don't get a huge amount of benefit from + // reworking this model (since there is some form of encapsulation in place already). + // + + // The underlying data target - always present (strong reference) + ICorDebugDataTarget * m_pTarget; + + // Mutable version of the data target if any - optional (strong reference) + ICorDebugMutableDataTarget * m_pMutableTarget; + + TADDR m_globalBase; + DacInstanceManager m_instances; + ULONG32 m_instanceAge; + bool m_debugMode; + +#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS + +protected: + DacStreamManager * m_streams; + +public: + // Used to mark the point after which enumerated EE structs of interest + // will get their names cached in the triage/mini-dump + void InitStreamsForWriting(IN CLRDataEnumMemoryFlags flags); + + // Used during triage/mini-dump collection to populate the map of + // pointers to EE struct (MethodDesc* for now) to their corresponding + // name. + bool MdCacheAddEEName(TADDR taEEStruct, const SString& name); + + // Used to mark the end point for the name caching. Will update streams + // based on built caches + void EnumStreams(IN CLRDataEnumMemoryFlags flags); + + // Used during triage/mini-dump analysis to retrieve the name associated + // with an EE struct pointer (MethodDesc* for now). + bool MdCacheGetEEName(TADDR taEEStruct, SString & eeName); + +#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS + +private: + // Read the DAC table and initialize g_dacGlobals + HRESULT GetDacGlobals(); + + // Verify the target mscorwks.dll matches the version expected + HRESULT VerifyDlls(); + + // Check whether a region of memory is fully readable. + bool IsFullyReadable(TADDR addr, TSIZE_T size); + + // Legacy target interfaces - optional + ICLRDataTarget * m_pLegacyTarget; + ICLRDataTarget2 * m_pLegacyTarget2; + ICLRDataTarget3 * m_pLegacyTarget3; + IXCLRDataTarget3 * m_target3; + ICLRMetadataLocator * m_legacyMetaDataLocator; + + LONG m_refs; + HRESULT m_memStatus; + MDImportsCache m_mdImports; + ICLRDataEnumMemoryRegionsCallback* m_enumMemCb; + ICLRDataEnumMemoryRegionsCallback2* m_updateMemCb; + CLRDataEnumMemoryFlags m_enumMemFlags; + JITNotification* m_jitNotificationTable; + GcNotification* m_gcNotificationTable; + TSIZE_T m_cbMemoryReported; + DumpMemoryReportStatics m_dumpStats; + + // If true, inconsistencies in the target will cause ASSERTs to be raised in DEBUG builds + bool m_fEnableTargetConsistencyAsserts; + +#ifdef _DEBUG +protected: + // If true, a mscorwks/mscordacwks mismatch will trigger a nice assert dialog + bool m_fEnableDllVerificationAsserts; +private: +#endif + +#ifdef FEATURE_COMINTEROP +protected: + // Returns CCW pointer based on a target address. + PTR_ComCallWrapper DACGetCCWFromAddress(CLRDATA_ADDRESS addr); + +private: + // Returns COM interface pointer corresponding to a given CCW and internal vtable + // index. Returns NULL if the vtable is unused or not fully laid out. + PTR_IUnknown DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtableIndex); +#endif + + static LONG s_procInit; + +public: + // APIs for picking up the info needed for a debugger to look up an ngen image or IL image + // from it's search path. + static bool GetMetaDataFileInfoFromPEFile(PEFile *pPEFile, + DWORD &dwImageTimestamp, + DWORD &dwImageSize, + DWORD &dwDataSize, + DWORD &dwRvaHint, + bool &isNGEN, + __out_ecount(cchFilePath) LPWSTR wszFilePath, + DWORD cchFilePath); + + static bool GetILImageInfoFromNgenPEFile(PEFile *peFile, + DWORD &dwTimeStamp, + DWORD &dwSize, + __out_ecount(cchPath) LPWSTR wszPath, + const DWORD cchPath); +#if defined(FEATURE_CORESYSTEM) + static bool ClrDataAccess::GetILImageNameFromNgenImage(LPCWSTR ilExtension, + __out_ecount(cchFilePath) LPWSTR wszFilePath, + const DWORD cchFilePath); +#endif // FEATURE_CORESYSTEM +}; + +extern ClrDataAccess* g_dacImpl; + +/* DacHandleWalker. + * + * Iterates over the handle table, enumerating all handles of the requested type on the + * handle table. This also will report the handle type, whether the handle is a strong + * reference, the AppDomain the handle comes from, as well as the reference count (in + * the case of a RefCount handle). Optionally this class can also be used to filter + * based on GC generation that would be collected (that is, to emulate a GC scan of the + * handle table). + * + * General implementation details: + * We have four sets of variables: + * 1. Overhead variables needed to operate in the Dac. + * 2. Variables needed to walk the handle table. We walk the handle table one bucket + * at a time, filling the array the user gave us until we have either enumerated + * all handles, or filled the array. + * 3. Storage variables to hold the overflow. That is, we were walking the handle + * table, filled the array that the user gave us, then needed to store the extra + * handles the handle table continued to enumerate to us. This is implmeneted + * as a linked list of arrays (mHead, mHead.Next, etc). + * 4. Variables which store the location of where we are in the overflow data. + * + * Note that "mHead" is a HandleChunkHead where we stuff the user's array. Everything + * which follows mHead (mHead.Next, etc) is a HandleChunk containing overflow data. + * + * Lastly, note this does not do robust error handling. If we fail to allocate a + * HandleChunk while walking the handle table, we will miss handles and not report + * this to the user. Unfortunately this will have to be fixed in the next iteration + * when we add more robust error handling to SOS's interface. + */ + template <class T> +class DefaultCOMImpl : public T +{ +public: + DefaultCOMImpl() + : mRef(0) + { + } + + ULONG STDMETHODCALLTYPE AddRef() + { + return ++mRef; + } + + ULONG STDMETHODCALLTYPE Release() + { + ULONG res = mRef--; + if (res == 0) + delete this; + return res; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppObj) + { + if (ppObj == NULL) + return E_INVALIDARG; + + if (IsEqualIID(riid, IID_IUnknown)) + { + AddRef(); + *ppObj = static_cast<IUnknown*>(this); + return S_OK; + } + else if (IsEqualIID(riid, __uuidof(T))) + { + AddRef(); + *ppObj = static_cast<T*>(this); + return S_OK; + } + + *ppObj = NULL; + return E_NOINTERFACE; + } + +private: + ULONG mRef; +}; + + +// A stuct representing a thread's allocation context. +struct AllocInfo +{ + CORDB_ADDRESS Ptr; + CORDB_ADDRESS Limit; + + AllocInfo() + : Ptr(0), Limit(0) + { + } +}; + +// A struct representing a segment in the heap. +struct SegmentData +{ + CORDB_ADDRESS Start; + CORDB_ADDRESS End; + + // Whether this segment is part of the large object heap. + int Generation; + + SegmentData() + : Start(0), End(0), Generation(0) + { + } +}; + +// A struct representing a gc heap in the process. +struct HeapData +{ + CORDB_ADDRESS YoungestGenPtr; + CORDB_ADDRESS YoungestGenLimit; + + CORDB_ADDRESS Gen0Start; + CORDB_ADDRESS Gen0End; + + CORDB_ADDRESS Gen1Start; + size_t EphemeralSegment; + + size_t SegmentCount; + SegmentData *Segments; + + HeapData(); + ~HeapData(); +}; + +/* This cache is used to read data from the target process if the reads are known + * to be sequential. This will object will read one page of memory out of the + * process at a time, aligned to the page boundary, to + */ +class LinearReadCache +{ +public: + LinearReadCache(); + ~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(CORDB_ADDRESS addr, T *t) + { + _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 (!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. + CORDB_ADDRESS 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. + *t = *reinterpret_cast<T*>(mPage+offset); + return true; + } + + // helper used to read the MethodTable + bool ReadMT(CORDB_ADDRESS addr, TADDR *mt) + { + if (!Read(addr, mt)) + return false; + + // clear the GC flag bits off the MethodTable + // equivalent to Object::GetGCSafeMethodTable() + *mt &= ~3; + return true; + } + +private: + /* Sets the cache to the page specified by addr, or false if we could not move to + * that page. + */ + bool MoveToPage(CORDB_ADDRESS addr); + + /* 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(CORDB_ADDRESS addr, T *t) + { + return SUCCEEDED(DacReadAll(TO_TADDR(addr), t, sizeof(t), false)); + } + +private: + CORDB_ADDRESS mCurrPageStart; + ULONG32 mPageSize, mCurrPageSize; + BYTE *mPage; +}; + +DWORD DacGetNumHeaps(); + +/* The implementation of the dac heap walker. This class will enumerate all objects on + * the heap with three important caveats: + * - This class will skip all Free objects in the heap. Free objects are an + * implementation detail of the GC, and ICorDebug does not have a mechanism + * to expose them. + * - This class does NOT guarantee that all objects will be enumerated. In + * the event that we find heap corruption on a segment, or if the background + * GC is modifying a segment, the remainder of that segment will be skipped + * by design. + * - The GC heap must be in a walkable state before you attempt to use this + * class on it. The IDacDbiInterface::AreGCStructuresValid function will + * tell you whether it is safe to walk the heap or not. + */ +class DacHeapWalker +{ + static CORDB_ADDRESS HeapStart; + static CORDB_ADDRESS HeapEnd; + +public: + DacHeapWalker(); + ~DacHeapWalker(); + + /* Initializes the heap walker. This must be called before Next or + * HasMoreObjects. Returns false if the initialization was not successful. + * (In practice this should only return false if we hit an OOM trying + * to allocate space for data structures.) Limits the heap walk to be in the range + * [start, end] (inclusive). Use DacHeapWalker::HeapStart, DacHeapWalker::HeapEnd + * as start or end to start from the beginning or end. + */ + HRESULT Init(CORDB_ADDRESS start=HeapStart, CORDB_ADDRESS end=HeapEnd); + + /* Returns a CORDB_ADDRESS which points to the next value on the heap. + * You must call HasMoreObjects on this class, and it must return true + * before calling Next. + */ + HRESULT Next(CORDB_ADDRESS *pValue, CORDB_ADDRESS *pMT, ULONG64 *size); + + /* Returns true if there are more objects on the heap, false otherwise. + */ + inline bool HasMoreObjects() const + { + return mCurrHeap < mHeapCount; + } + + HRESULT Reset(CORDB_ADDRESS start, CORDB_ADDRESS end); + + static HRESULT InitHeapDataWks(HeapData *&pHeaps, size_t &count); + static HRESULT InitHeapDataSvr(HeapData *&pHeaps, size_t &count); + + HRESULT GetHeapData(HeapData **ppHeapData, size_t *pNumHeaps); + + SegmentData *FindSegment(CORDB_ADDRESS obj); + + HRESULT ListNearObjects(CORDB_ADDRESS obj, CORDB_ADDRESS *pPrev, CORDB_ADDRESS *pContaining, CORDB_ADDRESS *pNext); + +private: + HRESULT MoveToNextObject(); + + bool GetSize(TADDR tMT, size_t &size); + + inline static size_t Align(size_t size) + { + if (sizeof(TADDR) == 4) + return (size+3) & ~3; + else + return (size+7) & ~7; + } + + inline static size_t AlignLarge(size_t size) + { + return (size + 7) & ~7; + } + + template <class T> + static int GetSegmentCount(T seg_start) + { + int count = 0; + while (seg_start) + { + // If we find this many segments, something is seriously wrong. + if (count++ > 4096) + break; + + seg_start = seg_start->next; + } + + return count; + } + + HRESULT NextSegment(); + void CheckAllocAndSegmentRange(); + +private: + int mThreadCount; + AllocInfo *mAllocInfo; + + size_t mHeapCount; + HeapData *mHeaps; + + CORDB_ADDRESS mCurrObj; + size_t mCurrSize; + TADDR mCurrMT; + + size_t mCurrHeap; + size_t mCurrSeg; + + CORDB_ADDRESS mStart; + CORDB_ADDRESS mEnd; + + LinearReadCache mCache; + static CORDB_ADDRESS sFreeMT; +}; + +struct DacGcReference; +struct SOSStackErrorList +{ + SOSStackRefError error; + SOSStackErrorList *pNext; + + SOSStackErrorList() + : pNext(0) + { + } +}; + +class DacStackReferenceWalker; +class DacStackReferenceErrorEnum : public DefaultCOMImpl<ISOSStackRefErrorEnum> +{ +public: + DacStackReferenceErrorEnum(DacStackReferenceWalker *pEnum, SOSStackErrorList *pErrors); + ~DacStackReferenceErrorEnum(); + + HRESULT STDMETHODCALLTYPE Skip(unsigned int count); + HRESULT STDMETHODCALLTYPE Reset(); + HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pCount); + HRESULT STDMETHODCALLTYPE Next(unsigned int count, SOSStackRefError ref[], unsigned int *pFetched); + +private: + // The lifetime of the error list is tied to the enum, so we must addref/release it. + DacStackReferenceWalker *mEnum; + SOSStackErrorList *mHead; + SOSStackErrorList *mCurr; +}; + +// For GCCONTEXT +#include "gcenv.h" + + /* DacStackReferenceWalker. + */ +class DacStackReferenceWalker : public DefaultCOMImpl<ISOSStackRefEnum> +{ + struct DacScanContext : public ScanContext + { + DacStackReferenceWalker *pWalker; + Frame *pFrame; + TADDR sp, pc; + bool stop; + GCEnumCallback pEnumFunc; + + DacScanContext() + : pWalker(NULL), pFrame(0), sp(0), pc(0), stop(false), pEnumFunc(0) + { + } + }; + + typedef struct _StackRefChunkHead + { + struct _StackRefChunkHead *next; // Next chunk + unsigned int count; // The count of how many StackRefs were written to pData + unsigned int size; // The capacity of pData (in bytes) + void *pData; // The overflow data + + _StackRefChunkHead() + : next(0), count(0), size(0), pData(0) + { + } + } StackRefChunkHead; + + // The actual struct used for storing overflow StackRefs + typedef struct _StackRefChunk : public StackRefChunkHead + { + SOSStackRefData data[64]; + + _StackRefChunk() + { + pData = data; + size = sizeof(data); + } + } StackRefChunk; +public: + DacStackReferenceWalker(ClrDataAccess *dac, DWORD osThreadID); + ~DacStackReferenceWalker(); + + HRESULT Init(); + + HRESULT STDMETHODCALLTYPE Skip(unsigned int count); + HRESULT STDMETHODCALLTYPE Reset(); + HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pCount); + HRESULT STDMETHODCALLTYPE Next(unsigned int count, + SOSStackRefData refs[], + unsigned int *pFetched); + + // Dac-Dbi Functions + HRESULT Next(ULONG celt, DacGcReference roots[], ULONG *pceltFetched); + Thread *GetThread() const + { + return mThread; + } + + HRESULT STDMETHODCALLTYPE EnumerateErrors(ISOSStackRefErrorEnum **ppEnum); + +private: + static StackWalkAction Callback(CrawlFrame *pCF, VOID *pData); + static void GCEnumCallbackSOS(LPVOID hCallback, OBJECTREF *pObject, DWORD flags, DacSlotLocation loc); + static void GCReportCallbackSOS(PTR_PTR_Object ppObj, ScanContext *sc, DWORD flags); + static void GCEnumCallbackDac(LPVOID hCallback, OBJECTREF *pObject, DWORD flags, DacSlotLocation loc); + static void GCReportCallbackDac(PTR_PTR_Object ppObj, ScanContext *sc, DWORD flags); + + CLRDATA_ADDRESS ReadPointer(TADDR addr); + + template <class StructType> + StructType *GetNextObject(DacScanContext *ctx) + { + SUPPORTS_DAC; + + // If we failed on a previous call (OOM) don't keep trying to allocate, it's not going to work. + if (ctx->stop || !mCurr) + return NULL; + + // We've moved past the size of the current chunk. We'll allocate a new chunk + // and stuff the references there. These are cleaned up by the destructor. + if (mCurr->count >= mCurr->size/sizeof(StructType)) + { + if (mCurr->next == NULL) + { + StackRefChunk *next = new (nothrow) StackRefChunk; + if (next != NULL) + { + mCurr->next = next; + } + else + { + ctx->stop = true; + return NULL; + } + } + + mCurr = mCurr->next; + } + + // Fill the current ref. + StructType *pData = (StructType*)mCurr->pData; + return &pData[mCurr->count++]; + } + + + template <class IntType, class StructType> + IntType WalkStack(IntType count, StructType refs[], promote_func promote, GCEnumCallback enumFunc) + { + _ASSERTE(mThread); + _ASSERTE(!mEnumerated); + + // If this is the first time we were called, fill local data structures. + // This will fill out the user's handles as well. + _ASSERTE(mCurr == NULL); + _ASSERTE(mHead.next == NULL); + + // Get the current thread's context and set that as the filter context + if (mThread->GetFilterContext() == NULL && mThread->GetProfilerFilterContext() == NULL) + { + T_CONTEXT ctx; + mDac->m_pTarget->GetThreadContext(mThread->GetOSThreadId(), CONTEXT_FULL, sizeof(ctx), (BYTE*)&ctx); + mThread->SetProfilerFilterContext(&ctx); + } + + // Setup GCCONTEXT structs for the stackwalk. + GCCONTEXT gcctx; + DacScanContext dsc; + dsc.pWalker = this; + dsc.pEnumFunc = enumFunc; + gcctx.f = promote; + gcctx.sc = &dsc; + + // Put the user's array/count in the + mHead.size = count*sizeof(StructType); + mHead.pData = refs; + mHead.count = 0; + + mCurr = &mHead; + + // Walk the stack, set mEnumerated to true to ensure we don't do it again. + unsigned int flagsStackWalk = ALLOW_INVALID_OBJECTS|ALLOW_ASYNC_STACK_WALK; +#if defined(WIN64EXCEPTIONS) + flagsStackWalk |= GC_FUNCLET_REFERENCE_REPORTING; +#endif // defined(WIN64EXCEPTIONS) + + mEnumerated = true; + mThread->StackWalkFrames(DacStackReferenceWalker::Callback, &gcctx, flagsStackWalk); + + // We have filled the user's array as much as we could. If there's more data than + // could fit, mHead.Next will contain a linked list of refs to enumerate. + mCurr = mHead.next; + + // Return how many we put in the user's array. + return mHead.count; + } + + template <class IntType, class StructType, promote_func PromoteFunc, GCEnumCallback EnumFunc> + HRESULT DoStackWalk(IntType count, StructType stackRefs[], IntType *pFetched) + { + HRESULT hr = S_OK; + IntType fetched = 0; + if (!mEnumerated) + { + // If this is the first time we were called, fill local data structures. + // This will fill out the user's handles as well. + fetched = (IntType)WalkStack((unsigned int)count, stackRefs, PromoteFunc, EnumFunc); + } + + while (fetched < count) + { + if (mCurr == NULL) + { + // Case 1: We have no more refs to walk. + hr = S_FALSE; + break; + } + else if (mChunkIndex >= mCurr->count) + { + // Case 2: We have exhausted the current chunk. + mCurr = mCurr->next; + mChunkIndex = 0; + } + else + { + // Case 3: The last call to "Next" filled the user's array and had some ref + // data leftover. Walk the linked-list of arrays copying them into the user's + // buffer until we have either exhausted the user's array or the leftover data. + IntType toCopy = count - fetched; // Fill the user's buffer... + + // ...unless that would go past the bounds of the current chunk. + if (toCopy + mChunkIndex > mCurr->count) + toCopy = mCurr->count - mChunkIndex; + + memcpy(stackRefs+fetched, (StructType*)mCurr->pData+mChunkIndex, toCopy*sizeof(StructType)); + mChunkIndex += toCopy; + fetched += toCopy; + } + } + + *pFetched = fetched; + + return hr; + } + +private: + // Dac variables required for entering/leaving the dac. + ClrDataAccess *mDac; + ULONG32 m_instanceAge; + + // Operational variables + Thread *mThread; + SOSStackErrorList *mErrors; + bool mEnumerated; + + // Storage variables + StackRefChunkHead mHead; + unsigned int mChunkIndex; + + // Iterator variables + StackRefChunkHead *mCurr; + int mIteratorIndex; + + // Heap. Used to resolve interior pointers. + DacHeapWalker mHeap; +}; + + + +struct DacGcReference; +class DacHandleWalker : public DefaultCOMImpl<ISOSHandleEnum> +{ + typedef struct _HandleChunkHead + { + struct _HandleChunkHead *Next; // Next chunk + unsigned int Count; // The count of how many handles were written to pData + unsigned int Size; // The capacity of pData + void *pData; // The overflow data + + _HandleChunkHead() + : Next(0), Count(0), Size(0), pData(0) + { + } + } HandleChunkHead; + + // The actual struct used for storing overflow handles + typedef struct _HandleChunk : public HandleChunkHead + { + SOSHandleData Data[128]; + + _HandleChunk() + { + pData = Data; + Size = sizeof(Data); + } + } HandleChunk; + + // Parameter used in HndEnumHandles callback. + struct DacHandleWalkerParam + { + HandleChunkHead *Curr; // The current chunk to write to + HRESULT Result; // HRESULT of the current enumeration + CLRDATA_ADDRESS AppDomain; // The AppDomain for the current bucket we are walking + unsigned int Type; // The type of handle we are currently walking + + DacHandleWalkerParam(HandleChunk *curr) + : Curr(curr), Result(S_OK), AppDomain(0), Type(0) + { + } + }; + +public: + DacHandleWalker(); + ~DacHandleWalker(); + + HRESULT Init(ClrDataAccess *dac, UINT types[], UINT typeCount); + HRESULT Init(ClrDataAccess *dac, UINT types[], UINT typeCount, int gen); + HRESULT Init(UINT32 typemask); + + // SOS functions + HRESULT STDMETHODCALLTYPE Skip(unsigned int count); + HRESULT STDMETHODCALLTYPE Reset(); + HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pCount); + HRESULT STDMETHODCALLTYPE Next(unsigned int count, + SOSHandleData handles[], + unsigned int *pNeeded); + + // Dac-Dbi Functions + HRESULT Next(ULONG celt, DacGcReference roots[], ULONG *pceltFetched); +private: + static void CALLBACK EnumCallback(PTR_UNCHECKED_OBJECTREF pref, LPARAM *pExtraInfo, LPARAM userParam, LPARAM type); + static void GetRefCountedHandleInfo( + OBJECTREF oref, unsigned int uType, + unsigned int *pRefCount, unsigned int *pJupiterRefCount, BOOL *pIsPegged, BOOL *pIsStrong); + static UINT32 BuildTypemask(UINT types[], UINT typeCount); + +private: + static void CALLBACK EnumCallbackSOS(PTR_UNCHECKED_OBJECTREF pref, LPARAM *pExtraInfo, LPARAM userParam, LPARAM type); + static void CALLBACK EnumCallbackDac(PTR_UNCHECKED_OBJECTREF pref, LPARAM *pExtraInfo, LPARAM userParam, LPARAM type); + + bool FetchMoreHandles(HANDLESCANPROC proc); + static inline bool IsAlwaysStrongReference(unsigned int type) + { + return type == HNDTYPE_STRONG || type == HNDTYPE_PINNED || type == HNDTYPE_ASYNCPINNED || type == HNDTYPE_SIZEDREF; + } + + template <class StructType, class IntType, HANDLESCANPROC EnumFunc> + HRESULT DoHandleWalk(IntType celt, StructType handles[], IntType *pceltFetched) + { + SUPPORTS_DAC; + + if (handles == NULL || pceltFetched == NULL) + return E_POINTER; + + HRESULT hr = S_OK; + IntType fetched = 0; + bool done = false; + + // On each iteration of the loop, either fetch more handles (filling in + // the user's data structure), or copy handles from previous calls to + // FetchMoreHandles which we could not store in the user's data (or simply + // advance the current chunk to the next chunk). + while (fetched < celt) + { + if (mCurr == NULL) + { + // Case 1: We have no overflow data. Stuff the user's array/size into + // mHead, fetch more handles. Additionally, if the previous call to + // FetchMoreHandles returned false (mMap == NULL), break. + if (mMap == NULL) + break; + + mHead.pData = handles+fetched; + mHead.Size = (celt - fetched)*sizeof(StructType); + + done = !FetchMoreHandles(EnumFunc); + fetched += mHead.Count; + + // Sanity check to make sure we haven't overflowed. This should not happen. + _ASSERTE(fetched <= celt); + } + else if (mChunkIndex >= mCurr->Count) + { + // Case 2: We have overflow data, but the current index into the current + // chunk is past the bounds. Move to the next. This could set mCurr to + // null, which we'll catch on the next iteration. + mCurr = mCurr->Next; + mChunkIndex = 0; + } + else + { + // Case 3: The last call to "Next" filled the user's array and had some handle + // data leftover. Walk the linked-list of arrays copying them into the user's + // buffer until we have either exhausted the user's array or the leftover data. + unsigned int toCopy = celt - fetched; // Fill the user's buffer... + + // ...unless that would go past the bounds of the current chunk. + if (toCopy + mChunkIndex > mCurr->Count) + toCopy = mCurr->Count - mChunkIndex; + + memcpy(handles+fetched, ((StructType*)(mCurr->pData))+mChunkIndex, toCopy*sizeof(StructType)); + mChunkIndex += toCopy; + fetched += toCopy; + } + } + + if (fetched < celt) + hr = S_FALSE; + + *pceltFetched = fetched; + + return hr; + } + +private: + // Dac variables required for entering/leaving the dac. + ClrDataAccess *mDac; + ULONG32 m_instanceAge; + + // Handle table walking variables. + HandleTableMap *mMap; + int mIndex; + UINT32 mTypeMask; + int mGenerationFilter; + + // Storage variables + HandleChunk mHead; + unsigned int mChunkIndex; + + // Iterator variables + HandleChunkHead *mCurr; + int mIteratorIndex; +}; + + +//---------------------------------------------------------------------------- +// +// ClrDataAppDomain. +// +//---------------------------------------------------------------------------- + +class ClrDataAppDomain : public IXCLRDataAppDomain +{ +public: + ClrDataAppDomain(ClrDataAccess* dac, + AppDomain* appDomain); + ~ClrDataAppDomain(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataAppDomain. + // + + virtual HRESULT STDMETHODCALLTYPE GetProcess( + /* [out] */ IXCLRDataProcess **process); + + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetUniqueID( + /* [out] */ ULONG64 *id); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataAppDomain *appDomain); + + virtual HRESULT STDMETHODCALLTYPE GetManagedObject( + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + AppDomain* GetAppDomain(void) + { + SUPPORTS_DAC; + return m_appDomain; + } + +private: + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + AppDomain* m_appDomain; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataAssembly. +// +//---------------------------------------------------------------------------- + +class ClrDataAssembly : public IXCLRDataAssembly +{ +public: + ClrDataAssembly(ClrDataAccess* dac, + Assembly* assembly); + ~ClrDataAssembly(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataAssembly. + // + + virtual HRESULT STDMETHODCALLTYPE StartEnumModules( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumModule( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataModule **mod); + + virtual HRESULT STDMETHODCALLTYPE EndEnumModules( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumAppDomains( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumAppDomain( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataAppDomain **appDomain); + + virtual HRESULT STDMETHODCALLTYPE EndEnumAppDomains( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetFileName( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetDisplayName( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataAssembly *assembly); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + +private: + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + Assembly* m_assembly; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataModule. +// +//---------------------------------------------------------------------------- + +class ClrDataModule : public IXCLRDataModule, IXCLRDataModule2 +{ +public: + ClrDataModule(ClrDataAccess* dac, + Module* module); + ~ClrDataModule(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataModule. + // + + virtual HRESULT STDMETHODCALLTYPE StartEnumAssemblies( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumAssembly( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataAssembly **assembly); + + virtual HRESULT STDMETHODCALLTYPE EndEnumAssemblies( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumAppDomains( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumAppDomain( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataAppDomain **appDomain); + + virtual HRESULT STDMETHODCALLTYPE EndEnumAppDomains( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumTypeDefinitions( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumTypeDefinition( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataTypeDefinition **typeDefinition); + + virtual HRESULT STDMETHODCALLTYPE EndEnumTypeDefinitions( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumTypeInstances( + /* [in] */ IXCLRDataAppDomain* appDomain, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumTypeInstance( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataTypeInstance **typeInstance); + + virtual HRESULT STDMETHODCALLTYPE EndEnumTypeInstances( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumTypeDefinitionsByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 flags, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumTypeDefinitionByName( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataTypeDefinition **type); + + virtual HRESULT STDMETHODCALLTYPE EndEnumTypeDefinitionsByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumTypeInstancesByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 flags, + /* [in] */ IXCLRDataAppDomain *appDomain, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumTypeInstanceByName( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataTypeInstance **type); + + virtual HRESULT STDMETHODCALLTYPE EndEnumTypeInstancesByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetTypeDefinitionByToken( + /* [in] */ mdTypeDef token, + /* [out] */ IXCLRDataTypeDefinition **typeDefinition); + + virtual HRESULT STDMETHODCALLTYPE StartEnumMethodDefinitionsByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 flags, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumMethodDefinitionByName( + /* [in] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataMethodDefinition **method); + + virtual HRESULT STDMETHODCALLTYPE EndEnumMethodDefinitionsByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumMethodInstancesByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 flags, + /* [in] */ IXCLRDataAppDomain* appDomain, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumMethodInstanceByName( + /* [in] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataMethodInstance **method); + + virtual HRESULT STDMETHODCALLTYPE EndEnumMethodInstancesByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetMethodDefinitionByToken( + /* [in] */ mdMethodDef token, + /* [out] */ IXCLRDataMethodDefinition **methodDefinition); + + virtual HRESULT STDMETHODCALLTYPE StartEnumDataByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 flags, + /* [in] */ IXCLRDataAppDomain* appDomain, + /* [in] */ IXCLRDataTask* tlsTask, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumDataByName( + /* [in] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE EndEnumDataByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetFileName( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetVersionId( + /* [out] */ GUID* vid); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataModule *mod); + + virtual HRESULT STDMETHODCALLTYPE StartEnumExtents( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumExtent( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ CLRDATA_MODULE_EXTENT *extent); + + virtual HRESULT STDMETHODCALLTYPE EndEnumExtents( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + HRESULT RequestGetModulePtr(IN ULONG32 inBufferSize, + IN BYTE* inBuffer, + IN ULONG32 outBufferSize, + OUT BYTE* outBuffer); + + Module* GetModule(void) + { + return m_module; + } + + // + // IXCLRDataModule2 + // + virtual HRESULT STDMETHODCALLTYPE SetJITCompilerFlags( + /* [in] */ DWORD dwFlags ); + +private: + // Returns an instance of IID_IMetaDataImport. + HRESULT GetMdInterface(PVOID* retIface); + + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + Module* m_module; + IMetaDataImport* m_mdImport; + bool m_setExtents; + CLRDATA_MODULE_EXTENT m_extents[2]; + CLRDATA_MODULE_EXTENT* m_extentsEnd; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataTypeDefinition. +// +//---------------------------------------------------------------------------- + +class ClrDataTypeDefinition : public IXCLRDataTypeDefinition +{ +public: + ClrDataTypeDefinition(ClrDataAccess* dac, + Module* module, + mdTypeDef token, + TypeHandle typeHandle); + ~ClrDataTypeDefinition(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataTypeDefinition. + // + + virtual HRESULT STDMETHODCALLTYPE GetModule( + /* [out] */ IXCLRDataModule **mod); + + virtual HRESULT STDMETHODCALLTYPE StartEnumMethodDefinitions( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumMethodDefinition( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataMethodDefinition **methodDefinition); + + virtual HRESULT STDMETHODCALLTYPE EndEnumMethodDefinitions( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumMethodDefinitionsByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 flags, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumMethodDefinitionByName( + /* [in] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataMethodDefinition **method); + + virtual HRESULT STDMETHODCALLTYPE EndEnumMethodDefinitionsByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetMethodDefinitionByToken( + /* [in] */ mdMethodDef token, + /* [out] */ IXCLRDataMethodDefinition **methodDefinition); + + virtual HRESULT STDMETHODCALLTYPE StartEnumInstances( + /* [in] */ IXCLRDataAppDomain* appDomain, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumInstance( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataTypeInstance **instance); + + virtual HRESULT STDMETHODCALLTYPE EndEnumInstances( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetNumFields( + /* [in] */ ULONG32 flags, + /* [out] */ ULONG32 *numFields); + + virtual HRESULT STDMETHODCALLTYPE StartEnumFields( + /* [in] */ ULONG32 flags, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumField( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [in] */ ULONG32 nameBufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(nameBufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ IXCLRDataTypeDefinition **type, + /* [out] */ ULONG32 *flags, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EnumField2( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [in] */ ULONG32 nameBufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(nameBufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ IXCLRDataTypeDefinition **type, + /* [out] */ ULONG32 *flags, + /* [out] */ IXCLRDataModule** tokenScope, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EndEnumFields( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumFieldsByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 nameFlags, + /* [in] */ ULONG32 fieldFlags, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumFieldByName( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataTypeDefinition **type, + /* [out] */ ULONG32 *flags, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EnumFieldByName2( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataTypeDefinition **type, + /* [out] */ ULONG32 *flags, + /* [out] */ IXCLRDataModule** tokenScope, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EndEnumFieldsByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetFieldByToken( + /* [in] */ mdFieldDef token, + /* [in] */ ULONG32 nameBufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(nameBufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ IXCLRDataTypeDefinition **type, + /* [out] */ ULONG32* flags); + + virtual HRESULT STDMETHODCALLTYPE GetFieldByToken2( + /* [in] */ IXCLRDataModule* tokenScope, + /* [in] */ mdFieldDef token, + /* [in] */ ULONG32 nameBufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(nameBufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ IXCLRDataTypeDefinition **type, + /* [out] */ ULONG32* flags); + + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [in] */ ULONG32 flags, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetTokenAndScope( + /* [out] */ mdTypeDef *token, + /* [out] */ IXCLRDataModule **mod); + + virtual HRESULT STDMETHODCALLTYPE GetCorElementType( + /* [out] */ CorElementType *type); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE GetBase( + /* [out] */ IXCLRDataTypeDefinition **base); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataTypeDefinition *type); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + virtual HRESULT STDMETHODCALLTYPE GetArrayRank( + /* [out] */ ULONG32* rank); + + virtual HRESULT STDMETHODCALLTYPE GetTypeNotification( + /* [out] */ ULONG32* flags); + + virtual HRESULT STDMETHODCALLTYPE SetTypeNotification( + /* [in] */ ULONG32 flags); + + static HRESULT NewFromModule(ClrDataAccess* dac, + Module* module, + mdTypeDef token, + ClrDataTypeDefinition** typeDef, + IXCLRDataTypeDefinition** pubTypeDef); + + TypeHandle GetTypeHandle(void) + { + return m_typeHandle; + } + +private: + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + Module* m_module; + mdTypeDef m_token; + TypeHandle m_typeHandle; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataTypeInstance. +// +//---------------------------------------------------------------------------- + +class ClrDataTypeInstance : public IXCLRDataTypeInstance +{ +public: + ClrDataTypeInstance(ClrDataAccess* dac, + AppDomain* appDomain, + TypeHandle typeHandle); + ~ClrDataTypeInstance(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataTypeInstance. + // + + virtual HRESULT STDMETHODCALLTYPE StartEnumMethodInstances( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumMethodInstance( + /* [in, out] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataMethodInstance **methodInstance); + + virtual HRESULT STDMETHODCALLTYPE EndEnumMethodInstances( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumMethodInstancesByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 flags, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumMethodInstanceByName( + /* [in] */ CLRDATA_ENUM* handle, + /* [out] */ IXCLRDataMethodInstance **method); + + virtual HRESULT STDMETHODCALLTYPE EndEnumMethodInstancesByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetNumStaticFields( + /* [out] */ ULONG32 *numFields); + + virtual HRESULT STDMETHODCALLTYPE GetStaticFieldByIndex( + /* [in] */ ULONG32 index, + /* [in] */ IXCLRDataTask *tlsTask, + /* [out] */ IXCLRDataValue **field, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE StartEnumStaticFieldsByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 flags, + /* [in] */ IXCLRDataTask *tlsTask, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumStaticFieldByName( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE EndEnumStaticFieldsByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetNumStaticFields2( + /* [in] */ ULONG32 flags, + /* [out] */ ULONG32 *numFields); + + virtual HRESULT STDMETHODCALLTYPE StartEnumStaticFields( + /* [in] */ ULONG32 flags, + /* [in] */ IXCLRDataTask *tlsTask, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumStaticField( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE EnumStaticField2( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **value, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ IXCLRDataModule** tokenScope, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EndEnumStaticFields( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumStaticFieldsByName2( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 nameFlags, + /* [in] */ ULONG32 fieldFlags, + /* [in] */ IXCLRDataTask *tlsTask, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumStaticFieldByName3( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **value, + /* [out] */ IXCLRDataModule** tokenScope, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EnumStaticFieldByName2( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE EndEnumStaticFieldsByName2( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetStaticFieldByToken( + /* [in] */ mdFieldDef token, + /* [in] */ IXCLRDataTask *tlsTask, + /* [out] */ IXCLRDataValue **field, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetStaticFieldByToken2( + /* [in] */ IXCLRDataModule* tokenScope, + /* [in] */ mdFieldDef token, + /* [in] */ IXCLRDataTask *tlsTask, + /* [out] */ IXCLRDataValue **field, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [in] */ ULONG32 flags, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetModule( + /* [out] */ IXCLRDataModule **mod); + + virtual HRESULT STDMETHODCALLTYPE GetDefinition( + /* [out] */ IXCLRDataTypeDefinition **typeDefinition); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE GetBase( + /* [out] */ IXCLRDataTypeInstance **base); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataTypeInstance *type); + + virtual HRESULT STDMETHODCALLTYPE GetNumTypeArguments( + /* [out] */ ULONG32 *numTypeArgs); + + virtual HRESULT STDMETHODCALLTYPE GetTypeArgumentByIndex( + /* [in] */ ULONG32 index, + /* [out] */ IXCLRDataTypeInstance **typeArg); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + static HRESULT NewFromModule(ClrDataAccess* dac, + AppDomain* appDomain, + Module* module, + mdTypeDef token, + ClrDataTypeInstance** typeInst, + IXCLRDataTypeInstance** pubTypeInst); + + TypeHandle GetTypeHandle(void) + { + return m_typeHandle; + } + +private: + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + AppDomain* m_appDomain; + TypeHandle m_typeHandle; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataMethodDefinition. +// +//---------------------------------------------------------------------------- + +class ClrDataMethodDefinition : public IXCLRDataMethodDefinition +{ +public: + ClrDataMethodDefinition(ClrDataAccess* dac, + Module* module, + mdMethodDef token, + MethodDesc* methodDesc); + ~ClrDataMethodDefinition(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataMethodDefinition. + // + + virtual HRESULT STDMETHODCALLTYPE GetTypeDefinition( + /* [out] */ IXCLRDataTypeDefinition **typeDefinition); + + virtual HRESULT STDMETHODCALLTYPE StartEnumInstances( + /* [in] */ IXCLRDataAppDomain* appDomain, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumInstance( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataMethodInstance **instance); + + virtual HRESULT STDMETHODCALLTYPE EndEnumInstances( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [in] */ ULONG32 flags, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetTokenAndScope( + /* [out] */ mdMethodDef *token, + /* [out] */ IXCLRDataModule **mod); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataMethodDefinition *method); + + virtual HRESULT STDMETHODCALLTYPE GetLatestEnCVersion( + /* [out] */ ULONG32* version); + + virtual HRESULT STDMETHODCALLTYPE StartEnumExtents( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumExtent( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ CLRDATA_METHDEF_EXTENT *extent); + + virtual HRESULT STDMETHODCALLTYPE EndEnumExtents( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetCodeNotification( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE SetCodeNotification( + /* [in] */ ULONG32 flags); + + virtual HRESULT STDMETHODCALLTYPE GetRepresentativeEntryAddress( + /* [out] */ CLRDATA_ADDRESS* addr); + + virtual HRESULT STDMETHODCALLTYPE HasClassOrMethodInstantiation( + /*[out]*/ BOOL* bGeneric); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + COR_ILMETHOD* GetIlMethod(void); + + static HRESULT NewFromModule(ClrDataAccess* dac, + Module* module, + mdMethodDef token, + ClrDataMethodDefinition** methDef, + IXCLRDataMethodDefinition** pubMethDef); + + static HRESULT GetSharedMethodFlags(MethodDesc* methodDesc, + ULONG32* flags); + + // We don't need this if we are able to form name using token + MethodDesc *GetMethodDesc() { return m_methodDesc;} +private: + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + Module* m_module; + mdMethodDef m_token; + MethodDesc* m_methodDesc; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataMethodInstance. +// +//---------------------------------------------------------------------------- + +class ClrDataMethodInstance : public IXCLRDataMethodInstance +{ +public: + ClrDataMethodInstance(ClrDataAccess* dac, + AppDomain* appDomain, + MethodDesc* methodDesc); + ~ClrDataMethodInstance(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataMethodInstance. + // + + virtual HRESULT STDMETHODCALLTYPE GetTypeInstance( + /* [out] */ IXCLRDataTypeInstance **typeInstance); + + virtual HRESULT STDMETHODCALLTYPE GetDefinition( + /* [out] */ IXCLRDataMethodDefinition **methodDefinition); + + virtual HRESULT STDMETHODCALLTYPE GetTokenAndScope( + /* [out] */ mdMethodDef *token, + /* [out] */ IXCLRDataModule **mod); + + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [in] */ ULONG32 flags, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataMethodInstance *method); + + virtual HRESULT STDMETHODCALLTYPE GetEnCVersion( + /* [out] */ ULONG32* version); + + virtual HRESULT STDMETHODCALLTYPE GetNumTypeArguments( + /* [out] */ ULONG32 *numTypeArgs); + + virtual HRESULT STDMETHODCALLTYPE GetTypeArgumentByIndex( + /* [in] */ ULONG32 index, + /* [out] */ IXCLRDataTypeInstance **typeArg); + + virtual HRESULT STDMETHODCALLTYPE GetILOffsetsByAddress( + /* [in] */ CLRDATA_ADDRESS address, + /* [in] */ ULONG32 offsetsLen, + /* [out] */ ULONG32 *offsetsNeeded, + /* [size_is][out] */ ULONG32 ilOffsets[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetAddressRangesByILOffset( + /* [in] */ ULONG32 ilOffset, + /* [in] */ ULONG32 rangesLen, + /* [out] */ ULONG32 *rangesNeeded, + /* [size_is][out] */ CLRDATA_ADDRESS_RANGE addressRanges[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetILAddressMap( + /* [in] */ ULONG32 mapLen, + /* [out] */ ULONG32 *mapNeeded, + /* [size_is][out] */ CLRDATA_IL_ADDRESS_MAP maps[ ]); + + virtual HRESULT STDMETHODCALLTYPE StartEnumExtents( + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumExtent( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ CLRDATA_ADDRESS_RANGE *extent); + + virtual HRESULT STDMETHODCALLTYPE EndEnumExtents( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetRepresentativeEntryAddress( + /* [out] */ CLRDATA_ADDRESS* addr); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + static HRESULT NewFromModule(ClrDataAccess* dac, + AppDomain* appDomain, + Module* module, + mdMethodDef token, + ClrDataMethodInstance** methInst, + IXCLRDataMethodInstance** pubMethInst); + +private: + friend class ClrDataAccess; + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + AppDomain* m_appDomain; + MethodDesc* m_methodDesc; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataTask. +// +//---------------------------------------------------------------------------- + +class ClrDataTask : public IXCLRDataTask +{ +public: + ClrDataTask(ClrDataAccess* dac, + Thread* Thread); + ~ClrDataTask(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataTask. + // + + virtual HRESULT STDMETHODCALLTYPE GetProcess( + /* [out] */ IXCLRDataProcess **process); + + virtual HRESULT STDMETHODCALLTYPE GetCurrentAppDomain( + /* [out] */ IXCLRDataAppDomain **appDomain); + + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetUniqueID( + /* [out] */ ULONG64 *id); + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE IsSameObject( + /* [in] */ IXCLRDataTask *task); + + virtual HRESULT STDMETHODCALLTYPE GetManagedObject( + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE GetDesiredExecutionState( + /* [out] */ ULONG32 *state); + + virtual HRESULT STDMETHODCALLTYPE SetDesiredExecutionState( + /* [in] */ ULONG32 state); + + virtual HRESULT STDMETHODCALLTYPE CreateStackWalk( + /* [in] */ ULONG32 flags, + /* [out] */ IXCLRDataStackWalk **stackWalk); + + virtual HRESULT STDMETHODCALLTYPE GetOSThreadID( + /* [out] */ ULONG32 *id); + + virtual HRESULT STDMETHODCALLTYPE GetContext( + /* [in] */ ULONG32 contextFlags, + /* [in] */ ULONG32 contextBufSize, + /* [out] */ ULONG32 *contextSize, + /* [size_is][out] */ BYTE contextBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE SetContext( + /* [in] */ ULONG32 contextSize, + /* [size_is][in] */ BYTE context[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetCurrentExceptionState( + /* [out] */ IXCLRDataExceptionState **exception); + + virtual HRESULT STDMETHODCALLTYPE GetLastExceptionState( + /* [out] */ IXCLRDataExceptionState **exception); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + Thread* GetThread(void) + { + return m_thread; + } + +private: + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + Thread* m_thread; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataStackWalk. +// +//---------------------------------------------------------------------------- + +class ClrDataStackWalk : public IXCLRDataStackWalk +{ +public: + ClrDataStackWalk(ClrDataAccess* dac, + Thread* Thread, + ULONG32 flags); + ~ClrDataStackWalk(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataStackWalk. + // + + virtual HRESULT STDMETHODCALLTYPE GetContext( + /* [in] */ ULONG32 contextFlags, + /* [in] */ ULONG32 contextBufSize, + /* [out] */ ULONG32 *contextSize, + /* [size_is][out] */ BYTE contextBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE SetContext( + /* [in] */ ULONG32 contextSize, + /* [size_is][in] */ BYTE context[ ]); + + virtual HRESULT STDMETHODCALLTYPE Next( void); + + virtual HRESULT STDMETHODCALLTYPE GetStackSizeSkipped( + /* [out] */ ULONG64 *stackSizeSkipped); + + virtual HRESULT STDMETHODCALLTYPE GetFrameType( + /* [out] */ CLRDataSimpleFrameType *simpleType, + /* [out] */ CLRDataDetailedFrameType *detailedType); + + virtual HRESULT STDMETHODCALLTYPE GetFrame( + /* [out] */ IXCLRDataFrame **frame); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + virtual HRESULT STDMETHODCALLTYPE SetContext2( + /* [in] */ ULONG32 flags, + /* [in] */ ULONG32 contextSize, + /* [size_is][in] */ BYTE context[ ]); + + HRESULT Init(void); + +private: + void FilterFrames(void); + void RawGetFrameType( + /* [out] */ CLRDataSimpleFrameType* simpleType, + /* [out] */ CLRDataDetailedFrameType* detailedType); + + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + Thread* m_thread; + ULONG32 m_walkFlags; + StackFrameIterator m_frameIter; + REGDISPLAY m_regDisp; + T_CONTEXT m_context; + TADDR m_stackPrev; + + // This is part of a test hook for debugging. Unless you're code:ClrDataStackWalk::Next + // you should never do anything with this member. + INDEBUG( int m_framesUnwound; ) + +}; + +//---------------------------------------------------------------------------- +// +// ClrDataFrame. +// +//---------------------------------------------------------------------------- + +class ClrDataFrame : public IXCLRDataFrame, + IXCLRDataFrame2 +{ + friend class ClrDataStackWalk; + +public: + ClrDataFrame(ClrDataAccess* dac, + CLRDataSimpleFrameType simpleType, + CLRDataDetailedFrameType detailedType, + AppDomain* appDomain, + MethodDesc* methodDesc); + ~ClrDataFrame(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataFrame. + // + + virtual HRESULT STDMETHODCALLTYPE GetContext( + /* [in] */ ULONG32 contextFlags, + /* [in] */ ULONG32 contextBufSize, + /* [out] */ ULONG32 *contextSize, + /* [size_is][out] */ BYTE contextBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetFrameType( + /* [out] */ CLRDataSimpleFrameType *simpleType, + /* [out] */ CLRDataDetailedFrameType *detailedType); + + virtual HRESULT STDMETHODCALLTYPE GetAppDomain( + /* [out] */ IXCLRDataAppDomain **appDomain); + + virtual HRESULT STDMETHODCALLTYPE GetNumArguments( + /* [out] */ ULONG32 *numParams); + + virtual HRESULT STDMETHODCALLTYPE GetArgumentByIndex( + /* [in] */ ULONG32 index, + /* [out] */ IXCLRDataValue **arg, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetNumLocalVariables( + /* [out] */ ULONG32 *numLocals); + + virtual HRESULT STDMETHODCALLTYPE GetLocalVariableByIndex( + /* [in] */ ULONG32 index, + /* [out] */ IXCLRDataValue **localVariable, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part(bufLen, *nameLen) WCHAR name[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetNumTypeArguments( + /* [out] */ ULONG32 *numTypeArgs); + + virtual HRESULT STDMETHODCALLTYPE GetTypeArgumentByIndex( + /* [in] */ ULONG32 index, + /* [out] */ IXCLRDataTypeInstance **typeArg); + + virtual HRESULT STDMETHODCALLTYPE GetCodeName( + /* [in] */ ULONG32 flags, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_opt(bufLen) WCHAR nameBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetMethodInstance( + /* [out] */ IXCLRDataMethodInstance **method); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + // + // IXCLRDataFrame2. + // + + virtual HRESULT STDMETHODCALLTYPE GetExactGenericArgsToken( + /* [out] */ IXCLRDataValue ** genericToken); + +private: + HRESULT GetMethodSig(MetaSig** sig, + ULONG32* count); + HRESULT GetLocalSig(MetaSig** sig, + ULONG32* count); + HRESULT ValueFromDebugInfo(MetaSig* sig, + bool isArg, + DWORD sigIndex, + DWORD varInfoSlot, + IXCLRDataValue** value); + + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + CLRDataSimpleFrameType m_simpleType; + CLRDataDetailedFrameType m_detailedType; + AppDomain* m_appDomain; + MethodDesc* m_methodDesc; + REGDISPLAY m_regDisp; + T_CONTEXT m_context; + MetaSig* m_methodSig; + MetaSig* m_localSig; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataExceptionState. +// +//---------------------------------------------------------------------------- + +#ifdef WIN64EXCEPTIONS +typedef ExceptionTracker ClrDataExStateType; +#else // WIN64EXCEPTIONS +typedef ExInfo ClrDataExStateType; +#endif // WIN64EXCEPTIONS + + +class ClrDataExceptionState : public IXCLRDataExceptionState +{ +public: + ClrDataExceptionState(ClrDataAccess* dac, + AppDomain* appDomain, + Thread* thread, + ULONG32 flags, + ClrDataExStateType* exInfo, + OBJECTHANDLE throwable, + ClrDataExStateType* prevExInfo); + ~ClrDataExceptionState(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataExceptionState. + // + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE GetPrevious( + /* [out] */ IXCLRDataExceptionState **exState); + + virtual HRESULT STDMETHODCALLTYPE GetManagedObject( + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE GetBaseType( + /* [out] */ CLRDataBaseExceptionType *type); + + virtual HRESULT STDMETHODCALLTYPE GetCode( + /* [out] */ ULONG32 *code); + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *strLen, + /* [size_is][out] */ __out_ecount_part(bufLen, *strLen) WCHAR str[ ]); + + virtual HRESULT STDMETHODCALLTYPE IsSameState( + /* [in] */ EXCEPTION_RECORD64 *exRecord, + /* [in] */ ULONG32 contextSize, + /* [size_is][in] */ BYTE cxRecord[ ]); + + virtual HRESULT STDMETHODCALLTYPE IsSameState2( + /* [in] */ ULONG32 flags, + /* [in] */ EXCEPTION_RECORD64 *exRecord, + /* [in] */ ULONG32 contextSize, + /* [size_is][in] */ BYTE cxRecord[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetTask( + /* [out] */ IXCLRDataTask** task); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + static HRESULT NewFromThread(ClrDataAccess* dac, + Thread* thread, + ClrDataExceptionState** exception, + IXCLRDataExceptionState** pubException); + + PTR_CONTEXT GetCurrentContextRecord(); + PTR_EXCEPTION_RECORD GetCurrentExceptionRecord(); + +friend class ClrDataAccess; +private: + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + AppDomain* m_appDomain; + Thread* m_thread; + ULONG32 m_flags; + ClrDataExStateType* m_exInfo; + OBJECTHANDLE m_throwable; + ClrDataExStateType* m_prevExInfo; +}; + +//---------------------------------------------------------------------------- +// +// ClrDataValue. +// +//---------------------------------------------------------------------------- + +class ClrDataValue : public IXCLRDataValue +{ +public: + ClrDataValue(ClrDataAccess* dac, + AppDomain* appDomain, + Thread* thread, + ULONG32 flags, + TypeHandle typeHandle, + ULONG64 baseAddr, + ULONG32 numLocs, + NativeVarLocation* locs); + ~ClrDataValue(void); + + // IUnknown. + STDMETHOD(QueryInterface)(THIS_ + IN REFIID interfaceId, + OUT PVOID* iface); + STDMETHOD_(ULONG, AddRef)(THIS); + STDMETHOD_(ULONG, Release)(THIS); + + // + // IXCLRDataValue. + // + + virtual HRESULT STDMETHODCALLTYPE GetFlags( + /* [out] */ ULONG32 *flags); + + virtual HRESULT STDMETHODCALLTYPE GetAddress( + /* [out] */ CLRDATA_ADDRESS *address); + + virtual HRESULT STDMETHODCALLTYPE GetSize( + /* [out] */ ULONG64 *size); + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *dataSize, + /* [size_is][out] */ BYTE buffer[ ]); + + virtual HRESULT STDMETHODCALLTYPE SetBytes( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *dataSize, + /* [size_is][in] */ BYTE buffer[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetType( + /* [out] */ IXCLRDataTypeInstance **typeInstance); + + virtual HRESULT STDMETHODCALLTYPE GetNumFields( + /* [out] */ ULONG32 *numFields); + + virtual HRESULT STDMETHODCALLTYPE GetFieldByIndex( + /* [in] */ ULONG32 index, + /* [out] */ IXCLRDataValue **field, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE GetNumFields2( + /* [in] */ ULONG32 flags, + /* [in] */ IXCLRDataTypeInstance *fromType, + /* [out] */ ULONG32 *numFields); + + virtual HRESULT STDMETHODCALLTYPE StartEnumFields( + /* [in] */ ULONG32 flags, + /* [in] */ IXCLRDataTypeInstance *fromType, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumField( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **field, + /* [in] */ ULONG32 nameBufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(nameBufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EnumField2( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **field, + /* [in] */ ULONG32 nameBufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(nameBufLen, *nameLen) WCHAR nameBuf[ ], + /* [out] */ IXCLRDataModule** tokenScope, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EndEnumFields( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE StartEnumFieldsByName( + /* [in] */ LPCWSTR name, + /* [in] */ ULONG32 nameFlags, + /* [in] */ ULONG32 fieldFlags, + /* [in] */ IXCLRDataTypeInstance *fromType, + /* [out] */ CLRDATA_ENUM *handle); + + virtual HRESULT STDMETHODCALLTYPE EnumFieldByName( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **field, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EnumFieldByName2( + /* [out][in] */ CLRDATA_ENUM *handle, + /* [out] */ IXCLRDataValue **field, + /* [out] */ IXCLRDataModule** tokenScope, + /* [out] */ mdFieldDef *token); + + virtual HRESULT STDMETHODCALLTYPE EndEnumFieldsByName( + /* [in] */ CLRDATA_ENUM handle); + + virtual HRESULT STDMETHODCALLTYPE GetFieldByToken( + /* [in] */ mdFieldDef token, + /* [out] */ IXCLRDataValue **field, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetFieldByToken2( + /* [in] */ IXCLRDataModule* tokenScope, + /* [in] */ mdFieldDef token, + /* [out] */ IXCLRDataValue **field, + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *nameLen, + /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetAssociatedValue( + /* [out] */ IXCLRDataValue **assocValue); + + virtual HRESULT STDMETHODCALLTYPE GetAssociatedType( + /* [out] */ IXCLRDataTypeInstance **assocType); + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ ULONG32 bufLen, + /* [out] */ ULONG32 *strLen, + /* [size_is][out] */ __out_ecount_part(bufLen, *strLen) WCHAR str[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetArrayProperties( + /* [out] */ ULONG32 *rank, + /* [out] */ ULONG32 *totalElements, + /* [in] */ ULONG32 numDim, + /* [size_is][out] */ ULONG32 dims[ ], + /* [in] */ ULONG32 numBases, + /* [size_is][out] */ LONG32 bases[ ]); + + virtual HRESULT STDMETHODCALLTYPE GetArrayElement( + /* [in] */ ULONG32 numInd, + /* [size_is][in] */ LONG32 indices[ ], + /* [out] */ IXCLRDataValue **value); + + virtual HRESULT STDMETHODCALLTYPE GetNumLocations( + /* [out] */ ULONG32* numLocs); + + virtual HRESULT STDMETHODCALLTYPE GetLocationByIndex( + /* [in] */ ULONG32 loc, + /* [out] */ ULONG32* flags, + /* [out] */ CLRDATA_ADDRESS* arg); + + virtual HRESULT STDMETHODCALLTYPE Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer); + + HRESULT GetRefAssociatedValue(IXCLRDataValue** assocValue); + + static HRESULT NewFromFieldDesc(ClrDataAccess* dac, + AppDomain* appDomain, + ULONG32 flags, + FieldDesc* fieldDesc, + ULONG64 objBase, + Thread* tlsThread, + ClrDataValue** value, + IXCLRDataValue** pubValue, + ULONG32 nameBufRetLen, + ULONG32* nameLenRet, + __out_ecount_part_opt(nameBufRetLen, *nameLenRet) WCHAR nameBufRet[ ], + IXCLRDataModule** tokenScopeRet, + mdFieldDef* tokenRet); + + HRESULT NewFromSubField(FieldDesc* fieldDesc, + ULONG32 flags, + ClrDataValue** value, + IXCLRDataValue** pubValue, + ULONG32 nameBufRetLen, + ULONG32* nameLenRet, + __out_ecount_part_opt(nameBufRetLen, *nameLenRet) WCHAR nameBufRet[ ], + IXCLRDataModule** tokenScopeRet, + mdFieldDef* tokenRet) + { + return ClrDataValue::NewFromFieldDesc(m_dac, + m_appDomain, + flags, + fieldDesc, + m_baseAddr, + m_thread, + value, + pubValue, + nameBufRetLen, + nameLenRet, + nameBufRet, + tokenScopeRet, + tokenRet); + } + + bool CanHaveFields(void) + { + return (m_flags & CLRDATA_VALUE_IS_REFERENCE) == 0; + } + + HRESULT IntGetBytes( + /* [in] */ ULONG32 bufLen, + /* [size_is][out] */ BYTE buffer[ ]); + +private: + LONG m_refs; + ClrDataAccess* m_dac; + ULONG32 m_instanceAge; + AppDomain* m_appDomain; + Thread* m_thread; + ULONG32 m_flags; + TypeHandle m_typeHandle; + ULONG64 m_totalSize; + ULONG64 m_baseAddr; + ULONG32 m_numLocs; + NativeVarLocation m_locs[MAX_NATIVE_VAR_LOCS]; +}; + +//---------------------------------------------------------------------------- +// +// EnumMethodDefinitions. +// +//---------------------------------------------------------------------------- + +class EnumMethodDefinitions +{ +public: + HRESULT Start(Module* mod, + bool useAddrFilter, + CLRDATA_ADDRESS addrFilter); + HRESULT Next(ClrDataAccess* dac, + IXCLRDataMethodDefinition **method); + + static HRESULT CdStart(Module* mod, + bool useAddrFilter, + CLRDATA_ADDRESS addrFilter, + CLRDATA_ENUM* handle); + static HRESULT CdNext(ClrDataAccess* dac, + CLRDATA_ENUM* handle, + IXCLRDataMethodDefinition** method); + static HRESULT CdEnd(CLRDATA_ENUM handle); + + Module* m_module; + bool m_useAddrFilter; + CLRDATA_ADDRESS m_addrFilter; + MetaEnum m_typeEnum; + mdToken m_typeToken; + bool m_needMethodStart; + MetaEnum m_methodEnum; +}; + +//---------------------------------------------------------------------------- +// +// EnumMethodInstances. +// +//---------------------------------------------------------------------------- + +class EnumMethodInstances +{ +public: + EnumMethodInstances(MethodDesc* methodDesc, + IXCLRDataAppDomain* givenAppDomain); + + HRESULT Next(ClrDataAccess* dac, + IXCLRDataMethodInstance **instance); + + static HRESULT CdStart(MethodDesc* methodDesc, + IXCLRDataAppDomain* appDomain, + CLRDATA_ENUM* handle); + static HRESULT CdNext(ClrDataAccess* dac, + CLRDATA_ENUM* handle, + IXCLRDataMethodInstance** method); + static HRESULT CdEnd(CLRDATA_ENUM handle); + + MethodDesc* m_methodDesc; + AppDomain* m_givenAppDomain; + bool m_givenAppDomainUsed; + AppDomainIterator m_domainIter; + AppDomain* m_appDomain; + LoadedMethodDescIterator m_methodIter; +}; + +//---------------------------------------------------------------------------- +// +// Internal functions. +// +//---------------------------------------------------------------------------- + +#define DAC_ENTER() \ + EnterCriticalSection(&g_dacCritSec); \ + ClrDataAccess* __prevDacImpl = g_dacImpl; \ + g_dacImpl = this; + +// When entering a child object we validate that +// the process's host instance cache hasn't been flushed +// since the child was created. +#define DAC_ENTER_SUB(dac) \ + EnterCriticalSection(&g_dacCritSec); \ + if (dac->m_instanceAge != m_instanceAge) \ + { \ + LeaveCriticalSection(&g_dacCritSec); \ + return E_INVALIDARG; \ + } \ + ClrDataAccess* __prevDacImpl = g_dacImpl; \ + g_dacImpl = (dac) + +#define DAC_LEAVE() \ + g_dacImpl = __prevDacImpl; \ + LeaveCriticalSection(&g_dacCritSec) + + +#define SOSHelperEnter() \ + DAC_ENTER_SUB(mDac); \ + HRESULT hr = S_OK; \ + EX_TRY \ + { + +#define SOSHelperLeave() \ + } \ + EX_CATCH \ + { \ + if (!DacExceptionFilter(GET_EXCEPTION(), mDac, &hr)) \ + { \ + EX_RETHROW; \ + } \ + } \ + EX_END_CATCH(SwallowAllExceptions) \ + DAC_LEAVE(); + +HRESULT DacGetHostVtPtrs(void); +bool DacExceptionFilter(Exception* ex, ClrDataAccess* process, + HRESULT* status); +Thread* __stdcall DacGetThread(ULONG32 osThread); +BOOL DacGetThreadContext(Thread* thread, T_CONTEXT* context); + +// Imports from request_svr.cpp, to provide data we need from the SVR namespace +int GCHeapCount(); +HRESULT GetServerHeapData(CLRDATA_ADDRESS addr, DacpHeapSegmentData *pSegment); +HRESULT GetServerHeaps(CLRDATA_ADDRESS pGCHeaps[], ICorDebugDataTarget* pTarget); + +#if defined(DAC_MEASURE_PERF) + +#if defined(_TARGET_X86_) + +// Assume Pentium CPU + +#define CCNT_OVERHEAD_32 8 +#define CCNT_OVERHEAD 13 + +#pragma warning( disable: 4035 ) /* Don't complain about lack of return value */ + +__inline unsigned __int64 GetCycleCount () +{ +__asm _emit 0x0F +__asm _emit 0x31 /* rdtsc */ + // return EDX:EAX causes annoying warning +}; + +__inline unsigned GetCycleCount32 () // enough for about 40 seconds +{ + LIMITED_METHOD_CONTRACT; + +__asm push EDX +__asm _emit 0x0F +__asm _emit 0x31 /* rdtsc */ +__asm pop EDX + // return EAX causes annoying warning +}; + +#pragma warning( default: 4035 ) + +#else // #if defined(_TARGET_X86_) + +#define CCNT_OVERHEAD 0 // Don't know + +__inline unsigned __int64 GetCycleCount() +{ + LIMITED_METHOD_CONTRACT; + + LARGE_INTEGER qwTmp; + QueryPerformanceCounter(&qwTmp); + return qwTmp.QuadPart; +} + +#endif // #if defined(_TARGET_X86_) + +extern unsigned __int64 g_nTotalTime; +extern unsigned __int64 g_nStackTotalTime; +extern unsigned __int64 g_nReadVirtualTotalTime; +extern unsigned __int64 g_nFindTotalTime; +extern unsigned __int64 g_nFindHashTotalTime; +extern unsigned __int64 g_nFindHits; +extern unsigned __int64 g_nFindCalls; +extern unsigned __int64 g_nFindFails; +extern unsigned __int64 g_nStackWalk; +extern unsigned __int64 g_nFindStackTotalTime; + +#endif // #if defined(DAC_MEASURE_PERF) + +#endif // #ifndef __DACIMPL_H__ |