1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5
6//
7 /*vim: set foldmethod=marker: */
8#include <stdafx.h>
9
10#if defined(FEATURE_PREJIT)
11#include "nidump.h"
12
13#include <metadataexports.h>
14
15#include <comcallablewrapper.h>
16#include <gcdump.h>
17
18#if !defined(FEATURE_CORESYSTEM)
19#include <algorithm>
20#endif
21
22
23#include <formattype.h>
24
25#include <pedecoder.h>
26
27
28#include <mdfileformat.h>
29
30#if !defined(FEATURE_CORESYSTEM)
31#include <cassert>
32#undef _ASSERTE
33#define _ASSERTE(x) assert(x)
34#endif
35
36#include <compile.h>
37
38#ifdef USE_GC_INFO_DECODER
39#include <gcinfodecoder.h>
40#endif
41
42#include <ngenhash.inl>
43
44#define FEATURE_MSDIS
45
46//----------------------------------------------------------------------------
47//
48// ClrDump functionality
49//
50//----------------------------------------------------------------------------
51
52/////////////////////////////////////////////////////////////////////////////////////////////
53//
54// Given a compressed integer(*pData), expand the compressed int to *pDataOut.
55// Return value is the number of bytes that the integer occupies in the compressed format
56// It is caller's responsibility to ensure pDataOut has at least 4 bytes to be written to.
57//
58// This function returns -1 if pass in with an incorrectly compressed data, such as
59// (*pBytes & 0xE0) == 0XE0.
60/////////////////////////////////////////////////////////////////////////////////////////////
61/* XXX Wed 09/14/2005
62 * copied from cor.h. Modified to operate on PTR_PCCOR_SIGNATUREs
63 */
64inline ULONG DacSigUncompressBigData(
65 PTR_CCOR_SIGNATURE &pData) // [IN,OUT] compressed data
66{
67 ULONG res;
68
69 // 1 byte data is handled in DacSigUncompressData
70 // _ASSERTE(*pData & 0x80);
71
72 // Medium.
73 if ((*pData & 0xC0) == 0x80) // 10?? ????
74 {
75 res = (ULONG)((*pData++ & 0x3f) << 8);
76 res |= *pData++;
77 }
78 else // 110? ????
79 {
80 res = (*pData++ & 0x1f) << 24;
81 res |= *pData++ << 16;
82 res |= *pData++ << 8;
83 res |= *pData++;
84 }
85 return res;
86}
87FORCEINLINE ULONG DacSigUncompressData(
88 PTR_CCOR_SIGNATURE &pData) // [IN,OUT] compressed data
89{
90 // Handle smallest data inline.
91 if ((*pData & 0x80) == 0x00) // 0??? ????
92 return *pData++;
93 return DacSigUncompressBigData(pData);
94}
95//const static mdToken g_tkCorEncodeToken[4] ={mdtTypeDef, mdtTypeRef, mdtTypeSpec, mdtBaseType};
96
97// uncompress a token
98inline mdToken DacSigUncompressToken( // return the token.
99 PTR_CCOR_SIGNATURE &pData) // [IN,OUT] compressed data
100{
101 mdToken tk;
102 mdToken tkType;
103
104 tk = DacSigUncompressData(pData);
105 tkType = g_tkCorEncodeToken[tk & 0x3];
106 tk = TokenFromRid(tk >> 2, tkType);
107 return tk;
108}
109// uncompress encoded element type
110FORCEINLINE CorElementType DacSigUncompressElementType(//Element type
111 PTR_CCOR_SIGNATURE &pData) // [IN,OUT] compressed data
112{
113 return (CorElementType)*pData++;
114}
115
116
117
118const char * g_helperNames[] =
119{
120#define JITHELPER(val, fn, sig) # val,
121#include <jithelpers.h>
122#undef JITHELPER
123};
124
125
126
127#define dim(x) (sizeof(x)/sizeof((x)[0]))
128
129void EnumFlagsToString( DWORD value,
130 const NativeImageDumper::EnumMnemonics * table,
131 int count, const WCHAR * sep, SString& output )
132{
133 bool firstValue = true;
134 for( int i = 0; i < count; ++i )
135 {
136 bool match = false;
137 const NativeImageDumper::EnumMnemonics& entry = table[i];
138 if( entry.mask != 0 )
139 match = ((entry.mask & value) == entry.value);
140 else
141 match = (entry.value == value);
142
143 if( match )
144 {
145 if( !firstValue )
146 output.Append(sep);
147 firstValue = false;
148
149 output.Append( table[i].mnemonic );
150
151 value &= ~entry.value;
152 }
153 }
154}
155
156const NativeImageDumper::EnumMnemonics s_ImageSections[] =
157{
158#define IS_ENTRY(v, s) NativeImageDumper::EnumMnemonics(v, s)
159 IS_ENTRY(IMAGE_SCN_MEM_READ, W("read")),
160 IS_ENTRY(IMAGE_SCN_MEM_WRITE, W("write")),
161 IS_ENTRY(IMAGE_SCN_MEM_EXECUTE, W("execute")),
162 IS_ENTRY(IMAGE_SCN_CNT_CODE, W("code")),
163 IS_ENTRY(IMAGE_SCN_CNT_INITIALIZED_DATA, W("init data")),
164 IS_ENTRY(IMAGE_SCN_CNT_UNINITIALIZED_DATA, W("uninit data")),
165#undef IS_ENTRY
166};
167inline int CheckFlags( DWORD source, DWORD flags )
168{
169 return (source & flags) == flags;
170}
171
172HRESULT ClrDataAccess::DumpNativeImage(CLRDATA_ADDRESS loadedBase,
173 LPCWSTR name,
174 IXCLRDataDisplay * display,
175 IXCLRLibrarySupport * support,
176 IXCLRDisassemblySupport *dis)
177{
178 DAC_ENTER();
179 /* REVISIT_TODO Fri 09/09/2005
180 * catch exceptions
181 */
182 NativeImageDumper dump(dac_cast<PTR_VOID>(CLRDATA_ADDRESS_TO_TADDR(loadedBase)), name, display,
183 support, dis);
184 dump.DumpNativeImage();
185 DAC_LEAVE();
186 return S_OK;
187}
188
189
190
191static ULONG bigBufferSize = 8192;
192static WCHAR bigBuffer[8192];
193static BYTE bigByteBuffer[1024];
194
195//----------------------------------------------------------------------------
196//
197// NativeImageDumper
198//
199//----------------------------------------------------------------------------
200template<typename T>
201inline T combine(T a, T b)
202{
203 return (T)(((DWORD)a) | ((DWORD)b));
204}
205template<typename T>
206inline T combine(T a, T b, T c)
207{
208 return (T)(((DWORD)a) | ((DWORD)b) | ((DWORD)c));
209}
210#define CLRNATIVEIMAGE_ALWAYS ((CLRNativeImageDumpOptions)~0)
211#define CHECK_OPT(opt) CheckOptions(CLRNATIVEIMAGE_ ## opt)
212#define IF_OPT(opt) if( CHECK_OPT(opt) )
213#define IF_OPT_AND(opt1, opt2) if( CHECK_OPT(opt1) && CHECK_OPT(opt2) )
214#define IF_OPT_OR(opt1, opt2) if( CHECK_OPT(opt1) || CHECK_OPT(opt2) )
215#define IF_OPT_OR3(opt1, opt2, opt3) if( CHECK_OPT(opt1) || CHECK_OPT(opt2) || CHECK_OPT(opt3) )
216#define IF_OPT_OR4(opt1, opt2, opt3, opt4) if( CHECK_OPT(opt1) || CHECK_OPT(opt2) || CHECK_OPT(opt3) || CHECK_OPT(opt4) )
217#define IF_OPT_OR5(opt1, opt2, opt3, opt4, opt5) if( CHECK_OPT(opt1) || CHECK_OPT(opt2) || CHECK_OPT(opt3) || CHECK_OPT(opt4) || CHECK_OPT(opt5) )
218
219#define fieldsize(type, field) (sizeof(((type*)NULL)->field))
220
221
222/*{{{Display helpers*/
223#define DisplayStartCategory(name, filter)\
224 do { IF_OPT(filter) m_display->StartCategory(name); } while(0)
225#define DisplayEndCategory(filter)\
226 do { IF_OPT(filter) m_display->EndCategory(); } while(0)
227#define DisplayStartArray(name, fmt, filter) \
228 do { IF_OPT(filter) m_display->StartArray(name, fmt); } while(0)
229#define DisplayStartArrayWithOffset(field, fmt, type, filter) \
230 do { IF_OPT(filter) m_display->StartArrayWithOffset( # field, offsetof(type, field), fieldsize(type, field), fmt); } while(0)
231
232#define DisplayStartElement( name, filter ) \
233 do { IF_OPT(filter) m_display->StartElement( name ); } while(0)
234#define DisplayStartStructure( name, ptr, size, filter ) \
235 do { IF_OPT(filter) m_display->StartStructure( name, ptr, size ); } while(0)
236#define DisplayStartList(fmt, filter) \
237 do { IF_OPT(filter) m_display->StartList(fmt); } while(0)
238
239#define DisplayStartStructureWithOffset( field, ptr, size, type, filter ) \
240 do { IF_OPT(filter) m_display->StartStructureWithOffset( # field, offsetof(type, field), fieldsize(type, field), ptr, size ); } while(0)
241#define DisplayStartVStructure( name, filter ) \
242 do { IF_OPT(filter) m_display->StartVStructure( name ); } while(0)
243#define DisplayEndVStructure( filter ) \
244 do { IF_OPT(filter) m_display->EndVStructure(); } while(0)
245
246#define DisplayEndList(filter) \
247 do { IF_OPT(filter) m_display->EndList(); } while(0)
248#define DisplayEndArray(footer, filter) \
249 do { IF_OPT(filter) m_display->EndArray(footer); } while(0)
250#define DisplayEndStructure(filter) \
251 do { IF_OPT(filter) m_display->EndStructure(); } while(0)
252
253#define DisplayEndElement(filter) \
254 do { IF_OPT(filter) m_display->EndElement(); } while(0)
255
256#define DisplayWriteElementString(name, value, filter) \
257 do { IF_OPT(filter) m_display->WriteElementString(name, value); } while(0)
258#define DisplayWriteElementStringW(name, value, filter) \
259 do { IF_OPT(filter) m_display->WriteElementStringW(name, value); } while(0)
260
261#define DisplayWriteElementStringW(name, value, filter) \
262 do { IF_OPT(filter) m_display->WriteElementStringW(name, value); } while(0)
263
264#define DisplayWriteElementInt(name, value, filter) \
265 do { IF_OPT(filter) m_display->WriteElementInt(name, value); } while(0)
266#define DisplayWriteElementIntWithSuppress(name, value, defVal, filter) \
267 do { IF_OPT(filter) m_display->WriteElementIntWithSuppress(name, value, defVal); } while(0)
268#define DisplayWriteElementUInt(name, value, filter) \
269 do { IF_OPT(filter) m_display->WriteElementUInt(name, value); } while(0)
270#define DisplayWriteElementFlag(name, value, filter) \
271 do { IF_OPT(filter) m_display->WriteElementFlag(name, value); } while(0)
272#define DisplayWriteElementPointer(name, value, filter) \
273 do { IF_OPT(filter) m_display->WriteElementPointer(name, value); } while(0)
274#define DisplayWriteElementPointerAnnotated(name, value, annotation, filter) \
275 do { IF_OPT(filter) m_display->WriteElementPointerAnnotated(name, value, annotation ); } while(0)
276#define DisplayWriteEmptyElement(name, filter) \
277 do { IF_OPT(filter) m_display->WriteEmptyElement(name); } while(0)
278
279#define DisplayWriteElementEnumerated(name, value, mnemonics, sep, filter) \
280 do { \
281 IF_OPT(filter) { \
282 TempBuffer buf; \
283 EnumFlagsToString(value, mnemonics, _countof(mnemonics), sep, buf);\
284 m_display->WriteElementEnumerated( name, value, (const WCHAR*)buf ); \
285 }\
286 }while(0)
287#define DisplayWriteFieldEnumerated(field, value, type, mnemonics, sep, filter)\
288 do { \
289 IF_OPT(filter) { \
290 TempBuffer buf; \
291 EnumFlagsToString(value, mnemonics, _countof(mnemonics), sep, buf);\
292 m_display->WriteFieldEnumerated( # field, offsetof(type, field), \
293 fieldsize(type, field), value,\
294 (const WCHAR*)buf ); \
295 }\
296 }while(0)
297#define DisplayWriteElementAddress(name, ptr, size, filter) \
298 do { IF_OPT(filter) m_display->WriteElementAddress( name, ptr, size ); } while(0)
299#define DisplayWriteElementAddressNamed(eltName, name, ptr, size, filter) \
300 do { IF_OPT(filter) m_display->WriteElementAddressNamed( eltName, name, ptr, size ); } while(0)
301#define DisplayWriteElementAddressNamedW(eltName, name, ptr, size, filter) \
302 do { IF_OPT(filter) m_display->WriteElementAddressNamedW( eltName, name, ptr, size ); } while(0)
303
304#define DisplayWriteFieldString(field, value, type, filter) \
305 do { IF_OPT(filter) m_display->WriteFieldString( # field, offsetof(type, field), fieldsize(type, field), value ); } while(0)
306#define DisplayWriteFieldStringW(field, value, type, filter) \
307 do { IF_OPT(filter) m_display->WriteFieldStringW( # field, offsetof(type, field), fieldsize(type, field), value ); } while(0)
308#define DisplayWriteFieldInt(field, value, type, filter) \
309 do { IF_OPT(filter) m_display->WriteFieldInt( # field, offsetof(type, field), fieldsize(type, field), value ); } while(0)
310#define DisplayWriteFieldUInt(field, value, type, filter) \
311 do { IF_OPT(filter) m_display->WriteFieldUInt( # field, offsetof(type, field), fieldsize(type, field), value ); } while(0)
312#define DisplayWriteFieldPointer(field, ptr, type, filter) \
313 do { IF_OPT(filter) m_display->WriteFieldPointer( # field, offsetof(type, field), fieldsize(type, field), ptr ); } while(0)
314#define DisplayWriteFieldPointerWithSize(field, ptr, size, type, filter) \
315 do { IF_OPT(filter) m_display->WriteFieldPointerWithSize( # field, offsetof(type, field), fieldsize(type, field), ptr, size ); } while(0)
316#define DisplayWriteFieldEmpty(field, type, filter) \
317 do { IF_OPT(filter) m_display->WriteFieldEmpty( # field, offsetof(type, field), fieldsize(type, field) ); } while(0)
318#define DisplayWriteFieldFlag(field, value, type, filter) \
319 do { IF_OPT(filter) m_display->WriteFieldFlag(# field, offsetof(type, field), fieldsize(type, field), value); } while(0)
320#define WriteFieldFieldDesc(field, ptr, type, filter) \
321 do { IF_OPT(filter) DoWriteFieldFieldDesc( # field, offsetof(type, field), fieldsize(type, field), ptr ); } while(0)
322#define WriteFieldMethodDesc(field, ptr, type, filter) \
323 do { IF_OPT(filter) DoWriteFieldMethodDesc( # field, offsetof(type, field), fieldsize(type, field), ptr ); } while(0)
324#define WriteFieldStr(field, ptr, type, filter) \
325 do { IF_OPT(filter) DoWriteFieldStr( ptr, # field, offsetof(type, field), fieldsize(type, field) ); } while(0)
326#define WriteFieldMethodTable(field, ptr, type, filter) \
327 do { IF_OPT(filter) DoWriteFieldMethodTable( # field, offsetof(type, field), fieldsize(type, field), ptr ); } while(0)
328#define WriteFieldMDToken(field, token, type, filter) \
329 do { IF_OPT(filter) DoWriteFieldMDToken( # field, offsetof(type, field), fieldsize(type, field), token ); } while(0)
330#define WriteFieldAsHex(field, ptr, type, filter) \
331 do { IF_OPT(filter) DoWriteFieldAsHex( # field, offsetof(type, field), fieldsize(type, field), ptr, fieldsize(type, field)); } while(0)
332#define WriteFieldMDTokenImport(field, token, type, filter, import) \
333 do { IF_OPT(filter) DoWriteFieldMDToken( # field, offsetof(type, field), fieldsize(type, field), token, import); } while(0)
334#define WriteFieldTypeHandle(field, ptr, type, filter) \
335 do { IF_OPT(filter) DoWriteFieldTypeHandle( # field, offsetof(type, field), fieldsize(type, field), ptr ); } while(0)
336#define WriteFieldCorElementType(field, et, type, filter) \
337 do { IF_OPT(filter) DoWriteFieldCorElementType( # field, offsetof(type, field), fieldsize(type, field), et ); } while(0)
338#define DumpFieldStub(field, ptr, type, filter) \
339 do { IF_OPT(filter) DoDumpFieldStub( ptr, offsetof(type, field), fieldsize(type, field), # field ); } while(0)
340#define DumpComPlusCallInfo(compluscall, filter) \
341 do { IF_OPT(filter) DoDumpComPlusCallInfo( compluscall ); } while(0)
342#define DisplayWriteFieldPointerAnnotated(field, ptr, annotation, type, filter) \
343 do { IF_OPT(filter) m_display->WriteFieldPointer( # field, offsetof(type, field), fieldsize(type, field), ptr ); } while(0)
344#define DisplayWriteFieldAddress(field, ptr, size, type, filter) \
345 do { IF_OPT(filter) m_display->WriteFieldAddress( # field, offsetof(type, field), fieldsize(type, field), ptr, size ); } while(0)
346#define DisplayStartTextElement(name, filter) \
347 do { IF_OPT(filter) m_display->StartTextElement( name ); } while(0)
348#define DisplayEndTextElement(filter) \
349 do { IF_OPT(filter) m_display->EndTextElement(); } while(0)
350#define DisplayWriteXmlText( args, filter ) \
351 do { IF_OPT(filter) m_display->WriteXmlText args; } while(0)
352#define DisplayWriteXmlTextBlock( args, filter ) \
353 do { IF_OPT(filter) m_display->WriteXmlTextBlock args; } while(0)
354
355#define CoverageRead( ptr, size ) \
356 do { IF_OPT(DEBUG_COVERAGE) PTR_READ(TO_TADDR(ptr), size); } while(0)
357#define CoverageReadString( taddr ) \
358 do { PTR_BYTE ptr(TO_TADDR(taddr)); while( *ptr++ ); }while(0)
359
360void AppendNilToken( mdToken token, SString& buf )
361{
362 _ASSERTE(RidFromToken(token) == mdTokenNil);
363
364 const WCHAR * id = NULL;
365 switch(token)
366 {
367#define mdNilEnt(x) case x: \
368 id = W(#x); \
369 break
370 mdNilEnt(mdModuleNil);
371 mdNilEnt(mdTypeRefNil);
372 mdNilEnt(mdTypeDefNil);
373 mdNilEnt(mdFieldDefNil);
374 mdNilEnt(mdMethodDefNil);
375 mdNilEnt(mdParamDefNil);
376 mdNilEnt(mdInterfaceImplNil);
377 mdNilEnt(mdMemberRefNil);
378 mdNilEnt(mdCustomAttributeNil);
379 mdNilEnt(mdPermissionNil);
380 mdNilEnt(mdSignatureNil);
381 mdNilEnt(mdEventNil);
382 mdNilEnt(mdPropertyNil);
383 mdNilEnt(mdModuleRefNil);
384 mdNilEnt(mdTypeSpecNil);
385 mdNilEnt(mdAssemblyNil);
386 mdNilEnt(mdAssemblyRefNil);
387 mdNilEnt(mdFileNil);
388 mdNilEnt(mdExportedTypeNil);
389 mdNilEnt(mdManifestResourceNil);
390
391 mdNilEnt(mdGenericParamNil);
392 mdNilEnt(mdGenericParamConstraintNil);
393 mdNilEnt(mdMethodSpecNil);
394
395 mdNilEnt(mdStringNil);
396#undef mdNilEnt
397 }
398 buf.Append( id );
399}
400void appendByteArray(SString& buf, const BYTE * bytes, ULONG cbBytes)
401{
402 for( COUNT_T i = 0; i < cbBytes; ++i )
403 {
404 buf.AppendPrintf(W("%02x"), bytes[i]);
405 }
406}
407/*}}}*/
408
409
410
411
412struct OptionDependencies
413{
414 OptionDependencies(CLRNativeImageDumpOptions value,
415 CLRNativeImageDumpOptions dep) : m_value(value),
416 m_dep(dep)
417 {
418
419 }
420 CLRNativeImageDumpOptions m_value;
421 CLRNativeImageDumpOptions m_dep;
422};
423
424static OptionDependencies g_dependencies[] =
425{
426#define OPT_DEP(value, dep) OptionDependencies(CLRNATIVEIMAGE_ ## value,\
427 CLRNATIVEIMAGE_ ## dep)
428 OPT_DEP(RESOURCES, COR_INFO),
429 OPT_DEP(METADATA, COR_INFO),
430 OPT_DEP(PRECODES, MODULE),
431 //Does methoddescs require ModuleTables?
432 OPT_DEP(VERBOSE_TYPES, METHODDESCS),
433 OPT_DEP(GC_INFO, METHODS),
434 OPT_DEP(FROZEN_SEGMENT, MODULE),
435 OPT_DEP(SLIM_MODULE_TBLS, MODULE),
436 OPT_DEP(MODULE_TABLES, SLIM_MODULE_TBLS),
437 OPT_DEP(DISASSEMBLE_CODE, METHODS),
438
439 OPT_DEP(FIXUP_HISTOGRAM, FIXUP_TABLES),
440 OPT_DEP(FIXUP_THUNKS, FIXUP_TABLES),
441
442#undef OPT_DEP
443};
444
445// Metadata helpers for DAC
446// This is mostly copied from mscoree.cpp which isn't available in mscordacwks.dll.
447//
448
449// This function gets the Dispenser interface given the CLSID and REFIID.
450STDAPI MetaDataGetDispenser(
451 REFCLSID rclsid, // The class to desired.
452 REFIID riid, // Interface wanted on class factory.
453 LPVOID FAR * ppv) // Return interface pointer here.
454{
455 _ASSERTE(rclsid == CLSID_CorMetaDataDispenser);
456
457 return InternalCreateMetaDataDispenser(riid, ppv);
458}
459
460
461NativeImageDumper::NativeImageDumper(PTR_VOID loadedBase,
462 const WCHAR * const name,
463 IXCLRDataDisplay * display,
464 IXCLRLibrarySupport * support,
465 IXCLRDisassemblySupport *dis)
466 :
467 m_decoder(loadedBase),
468 m_name(name),
469 m_baseAddress(loadedBase),
470 m_display(display),
471 m_librarySupport(support),
472 m_import(NULL),
473 m_assemblyImport(NULL),
474 m_manifestAssemblyImport(NULL),
475 m_dependencies(NULL),
476 m_imports(NULL),
477 m_dis(dis),
478 m_MetadataSize(0),
479 m_ILHostCopy(NULL),
480 m_isMscorlibHardBound(false),
481 m_sectionAlignment(0)
482{
483 IfFailThrow(m_display->GetDumpOptions(&m_dumpOptions));
484
485 //set up mscorwks stuff.
486 m_mscorwksBase = DacGlobalBase();
487 _ASSERTE(m_mscorwksBase);
488 PEDecoder mscorwksDecoder(dac_cast<PTR_VOID>(m_mscorwksBase));
489 m_mscorwksSize = mscorwksDecoder.GetSize();
490 m_mscorwksPreferred = TO_TADDR(mscorwksDecoder.GetPreferredBase());
491 //add implied options (i.e. if you want to dump the module, you also have
492 //to dump the native info.
493 CLRNativeImageDumpOptions current;
494 do
495 {
496 current = m_dumpOptions;
497 for( unsigned i = 0; i < _countof(g_dependencies); ++i )
498 {
499 if( m_dumpOptions & g_dependencies[i].m_value )
500 m_dumpOptions |= g_dependencies[i].m_dep;
501 }
502 }while( current != m_dumpOptions );
503 IF_OPT(DISASSEMBLE_CODE)
504 {
505 //configure the disassembler
506 m_dis->SetTranslateAddrCallback(TranslateAddressCallback);
507 m_dis->SetTranslateFixupCallback(TranslateFixupCallback);
508 m_dis->PvClientSet(this);
509 }
510}
511
512void GuidToString( GUID& guid, SString& s )
513{
514 WCHAR guidString[64];
515 GuidToLPWSTR(guid, guidString, sizeof(guidString) / sizeof(WCHAR));
516 //prune the { and }
517 _ASSERTE(guidString[0] == W('{')
518 && guidString[wcslen(guidString) - 1] == W('}'));
519 guidString[wcslen(guidString) - 1] = W('\0');
520 s.Append( guidString + 1 );
521}
522
523NativeImageDumper::~NativeImageDumper()
524{
525}
526
527inline const void * ptr_add(const void * ptr, COUNT_T size)
528{
529 return reinterpret_cast<const BYTE *>(ptr) + size;
530}
531
532//This does pointer arithmetic on a DPtr.
533template<typename T>
534inline const DPTR(T) dptr_add(T* ptr, COUNT_T offset)
535{
536 return DPTR(T)(PTR_HOST_TO_TADDR(ptr) + (offset * sizeof(T)));
537}
538
539template<typename T>
540inline const DPTR(T) dptr_sub(T* ptr, COUNT_T offset)
541{
542 return DPTR(T)(PTR_HOST_TO_TADDR(ptr) - (offset * sizeof(T)));
543}
544template<typename T>
545inline const DPTR(T) dptr_sub(DPTR(T)* ptr, COUNT_T offset)
546{
547 return DPTR(T)(PTR_HOST_TO_TADDR(ptr) - (offset * sizeof(T)));
548}
549
550struct MDTableType
551{
552 MDTableType(unsigned t, const char * n) : m_token(t), m_name(n) { }
553 unsigned m_token;
554 const char * m_name;
555};
556
557static unsigned s_tableTypes[] =
558{
559 /*
560#ifdef MiniMdTable
561#undef MiniMdTable
562#endif
563#define MiniMdTable(x) TBL_##x << 24,
564 MiniMdTables()
565#undef MiniMdTable
566 mdtName
567 */
568 mdtModule,
569 mdtTypeRef,
570 mdtTypeDef,
571 mdtFieldDef,
572 mdtMethodDef,
573 mdtParamDef,
574 mdtInterfaceImpl,
575 mdtMemberRef,
576 mdtCustomAttribute,
577 mdtPermission,
578 mdtSignature,
579 mdtEvent,
580 mdtProperty,
581 mdtModuleRef,
582 mdtTypeSpec,
583 mdtAssembly,
584 mdtAssemblyRef,
585 mdtFile,
586 mdtExportedType,
587 mdtManifestResource,
588 mdtGenericParam,
589 mdtMethodSpec,
590 mdtGenericParamConstraint,
591};
592
593const NativeImageDumper::EnumMnemonics s_CorHdrFlags[] =
594{
595#define CHF_ENTRY(f,v) NativeImageDumper::EnumMnemonics(f, v)
596 CHF_ENTRY(COMIMAGE_FLAGS_ILONLY, W("IL Only")),
597 CHF_ENTRY(COMIMAGE_FLAGS_32BITREQUIRED, W("32-bit Required")),
598 CHF_ENTRY(COMIMAGE_FLAGS_IL_LIBRARY, W("IL Library")),
599 CHF_ENTRY(COMIMAGE_FLAGS_STRONGNAMESIGNED, W("Strong Name Signed")),
600 CHF_ENTRY(COMIMAGE_FLAGS_NATIVE_ENTRYPOINT, W("Has Native Entrypoint")),
601 CHF_ENTRY(COMIMAGE_FLAGS_TRACKDEBUGDATA, W("Track Debug Data")),
602 CHF_ENTRY(COMIMAGE_FLAGS_32BITPREFERRED, W("32-bit Preferred"))
603#undef CHF_ENTRY
604};
605
606void NativeImageDumper::DumpAssemblySignature(CORCOMPILE_ASSEMBLY_SIGNATURE & assemblySignature)
607{
608 {
609 TempBuffer buf;
610 GuidToString(assemblySignature.mvid, buf);
611 DisplayWriteFieldStringW( mvid, (const WCHAR*)buf,
612 CORCOMPILE_ASSEMBLY_SIGNATURE,
613 COR_INFO );
614 }
615 DisplayWriteFieldInt( timeStamp, assemblySignature.timeStamp,
616 CORCOMPILE_ASSEMBLY_SIGNATURE, COR_INFO );
617 DisplayWriteFieldInt( ilImageSize,
618 assemblySignature.ilImageSize,
619 CORCOMPILE_ASSEMBLY_SIGNATURE, COR_INFO );
620}
621
622
623//error code return?
624void
625NativeImageDumper::DumpNativeImage()
626{
627 COUNT_T size;
628 const void *data;
629
630 m_display->StartDocument();
631
632 DisplayStartCategory( "File", PE_INFO );
633 DisplayWriteElementStringW( "path", m_name, PE_INFO );
634
635 DisplayWriteElementInt( "diskSize", m_decoder.GetSize(), PE_INFO );
636 _ASSERTE(sizeof(IMAGE_DOS_HEADER) < m_decoder.GetSize());
637
638 PTR_IMAGE_DOS_HEADER dosHeader =
639 PTR_IMAGE_DOS_HEADER(dac_cast<TADDR>(m_baseAddress));
640 DisplayWriteElementAddress( "IMAGE_DOS_HEADER",
641 DPtrToPreferredAddr(dosHeader),
642 sizeof(*dosHeader), PE_INFO );
643
644 // NT headers
645
646 if (!m_decoder.HasNTHeaders())
647 {
648 IF_OPT(PE_INFO)
649 {
650 DisplayWriteElementString("isPEFile", "false", PE_INFO);
651 DisplayEndCategory(PE_INFO);
652 }
653 else
654 m_display->ErrorPrintF("Non-PE file");
655
656 m_display->EndDocument();
657 return;
658 }
659
660 CONSISTENCY_CHECK(m_decoder.CheckNTHeaders());
661 if (!m_decoder.CheckNTHeaders())
662 {
663 m_display->ErrorPrintF("*** NT headers are not valid ***");
664 return;
665 }
666
667 DisplayWriteElementString("imageType", m_decoder.Has32BitNTHeaders()
668 ? "32 bit image" : "64 bit image", PE_INFO);
669 DisplayWriteElementAddress("address", (SIZE_T)m_decoder.GetNativePreferredBase(),
670 m_decoder.GetVirtualSize(), PE_INFO);
671 DisplayWriteElementInt( "TimeDateStamp", m_decoder.GetTimeDateStamp(),
672 PE_INFO );
673
674 if( m_decoder.Has32BitNTHeaders() )
675 {
676 PTR_IMAGE_NT_HEADERS32 ntHeaders(m_decoder.GetNTHeaders32());
677 //base, size, sectionAlign
678 _ASSERTE(ntHeaders->OptionalHeader.SectionAlignment >=
679 ntHeaders->OptionalHeader.FileAlignment);
680 m_imageSize = ntHeaders->OptionalHeader.SizeOfImage;
681 m_display->NativeImageDimensions(PTR_TO_TADDR(m_decoder.GetBase()),
682 ntHeaders->OptionalHeader.SizeOfImage,
683 ntHeaders->OptionalHeader.SectionAlignment);
684 /* REVISIT_TODO Mon 11/21/2005
685 * I don't understand this. Sections start on a two page boundary, but
686 * data ends on a one page boundary. What's up with that?
687 */
688 m_sectionAlignment = GetOsPageSize(); //ntHeaders->OptionalHeader.SectionAlignment;
689 unsigned ntHeaderSize = sizeof(*ntHeaders)
690 - sizeof(ntHeaders->OptionalHeader)
691 + ntHeaders->FileHeader.SizeOfOptionalHeader;
692 DisplayWriteElementAddress( "IMAGE_NT_HEADERS32",
693 DPtrToPreferredAddr(ntHeaders),
694 ntHeaderSize, PE_INFO );
695
696 }
697 else
698 {
699 PTR_IMAGE_NT_HEADERS64 ntHeaders(m_decoder.GetNTHeaders64());
700 //base, size, sectionAlign
701 _ASSERTE(ntHeaders->OptionalHeader.SectionAlignment >=
702 ntHeaders->OptionalHeader.FileAlignment);
703 m_imageSize = ntHeaders->OptionalHeader.SizeOfImage;
704 m_display->NativeImageDimensions((SIZE_T)ntHeaders->OptionalHeader.ImageBase,
705 ntHeaders->OptionalHeader.SizeOfImage,
706 ntHeaders->OptionalHeader.SectionAlignment);
707 m_sectionAlignment = ntHeaders->OptionalHeader.SectionAlignment;
708 unsigned ntHeaderSize = sizeof(*ntHeaders)
709 - sizeof(ntHeaders->OptionalHeader)
710 + ntHeaders->FileHeader.SizeOfOptionalHeader;
711 DisplayWriteElementAddress( "IMAGE_NT_HEADERS64",
712 DPtrToPreferredAddr(ntHeaders),
713 ntHeaderSize, PE_INFO );
714 }
715 DisplayEndCategory(PE_INFO);
716
717 // PE Section info
718
719 DisplayStartArray("Sections", W("%-8s%s\t(disk %s) %s"), PE_INFO);
720
721 for (COUNT_T i = 0; i < m_decoder.GetNumberOfSections(); i++)
722 {
723 PTR_IMAGE_SECTION_HEADER section = m_decoder.FindFirstSection() + i;
724 m_display->Section(reinterpret_cast<char *>(section->Name),
725 section->VirtualAddress,
726 section->SizeOfRawData);
727 DisplayStartStructure( "Section", DPtrToPreferredAddr(section),
728 sizeof(*section), PE_INFO );
729 DisplayWriteElementString("name", (const char *)section->Name, PE_INFO);
730 DisplayWriteElementAddress( "address", RvaToDisplay(section->VirtualAddress),
731 section->Misc.VirtualSize, PE_INFO );
732 DisplayWriteElementAddress( "disk", section->PointerToRawData,
733 section->SizeOfRawData, PE_INFO );
734
735 DisplayWriteElementEnumerated( "access", section->Characteristics,
736 s_ImageSections, W(", "), PE_INFO );
737 DisplayEndStructure( PE_INFO ); //Section
738 }
739 DisplayEndArray("Total Sections", PE_INFO);
740
741 // Image directory info
742
743 DisplayStartArray( "Directories", W("%-40s%s"), PE_INFO );
744
745 for ( COUNT_T i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
746 {
747 static const char *directoryNames[] =
748 {
749 /* 0*/"IMAGE_DIRECTORY_ENTRY_EXPORT",
750 /* 1*/"IMAGE_DIRECTORY_ENTRY_IMPORT",
751 /* 2*/"IMAGE_DIRECTORY_ENTRY_RESOURCE",
752 /* 3*/"IMAGE_DIRECTORY_ENTRY_EXCEPTION",
753 /* 4*/"IMAGE_DIRECTORY_ENTRY_SECURITY",
754 /* 5*/"IMAGE_DIRECTORY_ENTRY_BASERELOC",
755 /* 6*/"IMAGE_DIRECTORY_ENTRY_DEBUG",
756 /* 7*/"IMAGE_DIRECTORY_ENTRY_ARCHITECTURE",
757 /* 8*/"IMAGE_DIRECTORY_ENTRY_GLOBALPTR",
758 /* 9*/"IMAGE_DIRECTORY_ENTRY_TLS",
759 /*10*/"IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG",
760 /*11*/"IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT",
761 /*12*/"IMAGE_DIRECTORY_ENTRY_IAT",
762 /*13*/"IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT",
763 /*14*/"IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR",
764 /* 2*/"",
765 };
766
767 IMAGE_DATA_DIRECTORY *entry = m_decoder.GetDirectoryEntry(i);
768
769 if (entry->VirtualAddress != 0)
770 {
771 DisplayStartElement("Directory", PE_INFO);
772 DisplayWriteElementString("name", directoryNames[i], PE_INFO);
773 DisplayWriteElementAddress("address",
774 RvaToDisplay(entry->VirtualAddress),
775 entry->Size, PE_INFO);
776
777 DisplayEndElement( PE_INFO ); //Directory
778 }
779 }
780 DisplayEndArray("Total Directories", PE_INFO); //Directories
781
782 // COM+ info
783
784 if (!m_decoder.HasCorHeader())
785 {
786 IF_OPT(COR_INFO)
787 DisplayWriteElementString("CLRInfo", "<none>", COR_INFO);
788 else
789 m_display->ErrorPrintF("Non-CLR image\n");
790
791 m_display->EndDocument();
792 return;
793 }
794
795 CONSISTENCY_CHECK(m_decoder.CheckCorHeader());
796 if (!m_decoder.CheckCorHeader())
797 {
798 m_display->ErrorPrintF("*** INVALID CLR Header ***");
799 m_display->EndDocument();
800 return;
801 }
802
803 DisplayStartCategory("CLRInfo", COR_INFO);
804 PTR_IMAGE_COR20_HEADER pCor(m_decoder.GetCorHeader());
805 {
806#define WRITE_COR20_FIELD( name ) m_display->WriteFieldAddress( \
807 # name, offsetof(IMAGE_COR20_HEADER, name), \
808 fieldsize(IMAGE_COR20_HEADER, name), \
809 RvaToDisplay( pCor-> name . VirtualAddress ), \
810 pCor-> name . Size )
811
812 m_display->StartStructure( "IMAGE_COR20_HEADER",
813 DPtrToPreferredAddr(pCor),
814 sizeof(*pCor) );
815
816 DisplayWriteFieldUInt( MajorRuntimeVersion, pCor->MajorRuntimeVersion, IMAGE_COR20_HEADER, COR_INFO );
817 DisplayWriteFieldUInt( MinorRuntimeVersion, pCor->MinorRuntimeVersion, IMAGE_COR20_HEADER, COR_INFO );
818
819 // Symbol table and startup information
820 WRITE_COR20_FIELD(MetaData);
821 DisplayWriteFieldEnumerated( Flags, pCor->Flags, IMAGE_COR20_HEADER, s_CorHdrFlags, W(", "), COR_INFO );
822 DisplayWriteFieldUInt( EntryPointToken, pCor->EntryPointToken, IMAGE_COR20_HEADER, COR_INFO );
823
824 // Binding information
825 WRITE_COR20_FIELD(Resources);
826 WRITE_COR20_FIELD(StrongNameSignature);
827
828 // Regular fixup and binding information
829 WRITE_COR20_FIELD(CodeManagerTable);
830 WRITE_COR20_FIELD(VTableFixups);
831 WRITE_COR20_FIELD(ExportAddressTableJumps);
832
833 // Precompiled image info
834 WRITE_COR20_FIELD(ManagedNativeHeader);
835
836 m_display->EndStructure(); //IMAGE_COR20_HEADER
837#undef WRITE_COR20_FIELD
838 }
839
840 //make sure to touch the strong name signature even if we won't print it.
841 if (m_decoder.HasStrongNameSignature())
842 {
843 if (m_decoder.IsStrongNameSigned())
844 {
845 DACCOP_IGNORE(CastBetweenAddressSpaces,"nidump is in-proc and doesn't maintain a clean separation of address spaces (target and host are the same.");
846 data = reinterpret_cast<void*>(dac_cast<TADDR>(m_decoder.GetStrongNameSignature(&size)));
847
848 IF_OPT(COR_INFO)
849 {
850 TempBuffer sig;
851
852 appendByteArray(sig, (BYTE*)data, size);
853
854 DisplayWriteElementStringW( "StrongName", (const WCHAR *)sig,
855 COR_INFO );
856 }
857 }
858 else
859 {
860 DisplayWriteEmptyElement("DelaySigned", COR_INFO);
861 }
862 }
863
864#ifdef FEATURE_READYTORUN
865 if (m_decoder.HasReadyToRunHeader())
866 DisplayWriteElementString( "imageType", "ReadyToRun image", COR_INFO);
867 else
868#endif
869 if (m_decoder.IsILOnly())
870 DisplayWriteElementString( "imageType", "IL only image", COR_INFO);
871 else
872 if (m_decoder.HasNativeHeader())
873 DisplayWriteElementString( "imageType", "Native image", COR_INFO);
874 else
875 DisplayWriteElementString( "imageType", "Mixed image", COR_INFO);
876
877 DACCOP_IGNORE(CastBetweenAddressSpaces,"nidump is in-proc and doesn't maintain a clean separation of address spaces (target and host are the same.");
878 data = reinterpret_cast<void*>(dac_cast<TADDR>(m_decoder.GetMetadata(&size)));
879 OpenMetadata();
880 IF_OPT(METADATA)
881 {
882 DWORD dwAssemblyFlags = 0;
883 IfFailThrow(m_manifestAssemblyImport->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL,
884 NULL, NULL,
885 NULL, NULL,
886 NULL, &dwAssemblyFlags));
887 if ((afContentType_WindowsRuntime & dwAssemblyFlags) == afContentType_WindowsRuntime)
888 {
889 // The WinMD adapter doesn't implement the IID_IMetaDataTables interface so we can't dump
890 // the raw metadata.
891 DisplayWriteElementString ("Metadata", "Not supported by WinRT", COR_INFO);
892 }
893 else
894 {
895 WriteElementsMetadata( "Metadata", TO_TADDR(data), size );
896 }
897 }
898
899 CoverageRead(TO_TADDR(data), size);
900
901 if (m_decoder.HasNativeHeader())
902 {
903 DACCOP_IGNORE(CastBetweenAddressSpaces,"nidump is in-proc and doesn't maintain a clean separation of address spaces (target and host are the same.");
904 data = reinterpret_cast<void*>(dac_cast<TADDR>(m_decoder.GetNativeManifestMetadata(&size)));
905
906 IF_OPT(METADATA)
907 {
908 WriteElementsMetadata( "NativeManifestMetadata", TO_TADDR(data), size );
909 }
910 else
911 {
912 DisplayWriteElementAddress( "NativeManifestMetadata",
913 DataPtrToDisplay((TADDR)data), size,
914 COR_INFO );
915 }
916
917
918 /* REVISIT_TODO Tue 09/20/2005
919 * Anything to display in the native metadata?
920 */
921 CoverageRead(TO_TADDR(data), size);
922
923 /* REVISIT_TODO Tue 09/20/2005
924 * Dump the debug map? Indexed by method RID... probably a good idea
925 */
926 data = reinterpret_cast<void*>(m_decoder.GetNativeDebugMap(&size));
927
928 DisplayWriteElementAddress( "debugMap", DataPtrToDisplay((TADDR)data), size,
929 COR_INFO);
930 CoverageRead(TO_TADDR(data), size);
931
932 //also read the entire debug map section
933 IMAGE_SECTION_HEADER * dbgmap = FindSection( ".dbgmap" );
934 if (dbgmap != NULL)
935 {
936 CoverageRead(TO_TADDR(dbgmap->VirtualAddress)
937 + PTR_TO_TADDR(m_decoder.GetBase()),
938 (ULONG32)ALIGN_UP(dbgmap->Misc.VirtualSize, GetSectionAlignment()));
939 }
940
941 //read the .il and .rsrc sections in their entirety
942 IF_OPT(DEBUG_COVERAGE)
943 {
944 IMAGE_SECTION_HEADER *hdr;
945 hdr = FindSection( ".rsrc" );
946 if( hdr != NULL )
947 {
948 CoverageRead( m_decoder.GetRvaData(hdr->VirtualAddress),
949 (ULONG32)hdr->Misc.VirtualSize );
950 }
951 }
952 IF_OPT_OR(DEBUG_COVERAGE, IL)
953 {
954 IMAGE_SECTION_HEADER *hdr = FindSection( ".text" );
955
956 if( hdr != NULL )
957 {
958 m_ILSectionStart = hdr->VirtualAddress;
959 m_ILHostCopy = (BYTE*)PTR_READ(m_decoder.GetRvaData(hdr->VirtualAddress), hdr->Misc.VirtualSize);
960#ifdef _DEBUG
961 m_ILSectionSize = hdr->Misc.VirtualSize;
962#endif
963 }
964 else
965 {
966 m_ILSectionStart = 0;
967 m_ILHostCopy = NULL;
968#ifdef _DEBUG
969 m_ILSectionSize = 0;
970#endif
971 }
972 _ASSERTE( (((TADDR)m_ILHostCopy) & 3) == 0 );
973 _ASSERTE((m_ILSectionStart & 3) == 0);
974
975 }
976 }
977
978 data = m_decoder.GetResources(&size);
979 IF_OPT(RESOURCES)
980 {
981 DisplayStartStructure( "resource", DataPtrToDisplay((TADDR)data), size,
982 COR_INFO );
983 DisplayStartArray( "Resources", NULL, COR_INFO );
984 HCORENUM hEnum = NULL;
985 for(;;)
986 {
987 mdManifestResource resTokens[1];
988 ULONG numTokens = 0;
989 IfFailThrow(m_assemblyImport->EnumManifestResources(&hEnum,
990 resTokens,
991 1,
992 &numTokens));
993 if( numTokens == 0 )
994 break;
995
996 WCHAR resourceName[256];
997 ULONG nameLen;
998 mdToken impl;
999 DWORD offset, flags;
1000 IfFailThrow(m_assemblyImport->GetManifestResourceProps(resTokens[0],
1001 resourceName,
1002 _countof(resourceName),
1003 &nameLen,
1004 &impl,
1005 &offset,
1006 &flags));
1007 if( RidFromToken(impl) != 0 )
1008 continue; //skip all non-zero providers
1009 resourceName[nameLen] = W('\0');
1010 DPTR(DWORD UNALIGNED) res(TO_TADDR(data) + offset);
1011 DWORD resSize = *res;
1012 DisplayWriteElementAddressNamedW( "Resource", resourceName,
1013 DPtrToPreferredAddr(res),
1014 resSize + sizeof(DWORD),
1015 RESOURCES );
1016 }
1017 DisplayEndArray( "Total Resources", COR_INFO ); //Resources
1018 DisplayEndStructure( COR_INFO ); //resource
1019 }
1020 else
1021 {
1022 DisplayWriteElementAddress( "resource", DataPtrToDisplay((TADDR)data), size,
1023 COR_INFO );
1024 }
1025
1026 ULONG resultSize;
1027 GUID mvid;
1028 m_manifestImport->GetScopeProps(bigBuffer, bigBufferSize, &resultSize, &mvid);
1029 /* REVISIT_TODO Wed 09/07/2005
1030 * The name is the .module entry. Why isn't it present in the ngen image?
1031 */
1032 TempBuffer guidString;
1033 GuidToString( mvid, guidString );
1034 if( wcslen(bigBuffer) )
1035 DisplayWriteElementStringW( "scopeName", bigBuffer, COR_INFO );
1036 DisplayWriteElementStringW( "mvid", (const WCHAR *)guidString, COR_INFO );
1037
1038 if (m_decoder.HasManagedEntryPoint())
1039 {
1040 DisplayStartVStructure( "ManagedEntryPoint", COR_INFO );
1041 unsigned token = m_decoder.GetEntryPointToken();
1042 DisplayWriteElementUInt( "Token", token, COR_INFO );
1043 TempBuffer buf;
1044 AppendTokenName( token, buf );
1045 DisplayWriteElementStringW( "TokenName", (const WCHAR *)buf, COR_INFO );
1046 DisplayEndVStructure( COR_INFO );
1047 }
1048 else if (m_decoder.HasNativeEntryPoint())
1049 {
1050 DisplayWriteElementPointer( "NativeEntryPoint", (SIZE_T)m_decoder.GetNativeEntryPoint(),
1051 COR_INFO );
1052 }
1053
1054 /* REVISIT_TODO Mon 11/21/2005
1055 * Dump the version info completely
1056 */
1057 if( m_decoder.HasNativeHeader() )
1058 {
1059 PTR_CORCOMPILE_VERSION_INFO versionInfo( m_decoder.GetNativeVersionInfo() );
1060
1061 DisplayStartStructure("CORCOMPILE_VERSION_INFO",
1062 DPtrToPreferredAddr(versionInfo),
1063 sizeof(*versionInfo), COR_INFO);
1064
1065 DisplayStartStructureWithOffset( sourceAssembly,
1066 DPtrToPreferredAddr(versionInfo) + offsetof(CORCOMPILE_VERSION_INFO, sourceAssembly),
1067 sizeof(versionInfo->sourceAssembly),
1068 CORCOMPILE_VERSION_INFO, COR_INFO );
1069 DumpAssemblySignature(versionInfo->sourceAssembly);
1070 DisplayEndStructure(COR_INFO); //sourceAssembly
1071
1072 COUNT_T numDeps;
1073 PTR_CORCOMPILE_DEPENDENCY deps(TO_TADDR(m_decoder.GetNativeDependencies(&numDeps)));
1074
1075 DisplayStartArray( "Dependencies", NULL, COR_INFO );
1076
1077 for( COUNT_T i = 0; i < numDeps; ++i )
1078 {
1079 DisplayStartStructure("CORCOMPILE_DEPENDENCY", DPtrToPreferredAddr(deps + i),
1080 sizeof(deps[i]), COR_INFO );
1081 WriteFieldMDTokenImport( dwAssemblyRef, deps[i].dwAssemblyRef,
1082 CORCOMPILE_DEPENDENCY, COR_INFO,
1083 m_manifestImport );
1084 WriteFieldMDTokenImport( dwAssemblyDef, deps[i].dwAssemblyDef,
1085 CORCOMPILE_DEPENDENCY, COR_INFO,
1086 m_manifestImport );
1087 DisplayStartStructureWithOffset( signAssemblyDef,
1088 DPtrToPreferredAddr(deps + i) + offsetof(CORCOMPILE_DEPENDENCY, signAssemblyDef),
1089 sizeof(deps[i]).signAssemblyDef,
1090 CORCOMPILE_DEPENDENCY, COR_INFO );
1091 DumpAssemblySignature(deps[i].signAssemblyDef);
1092 DisplayEndStructure(COR_INFO); //signAssemblyDef
1093
1094 {
1095 TempBuffer buf;
1096 if( deps[i].signNativeImage == INVALID_NGEN_SIGNATURE )
1097 {
1098 buf.Append( W("INVALID_NGEN_SIGNATURE") );
1099 }
1100 else
1101 {
1102 GuidToString(deps[i].signNativeImage, buf);
1103 }
1104 DisplayWriteFieldStringW( signNativeImage, (const WCHAR*)buf,
1105 CORCOMPILE_DEPENDENCY, COR_INFO );
1106#if 0
1107 if( m_librarySupport
1108 && deps[i].signNativeImage != INVALID_NGEN_SIGNATURE )
1109 {
1110 buf.Clear();
1111 AppendTokenName(deps[i].dwAssemblyRef, buf, m_import );
1112 IfFailThrow(m_librarySupport->LoadDependency( (const WCHAR*)buf,
1113 deps[i].signNativeImage ));
1114 }
1115#endif
1116
1117 }
1118
1119
1120 DisplayEndStructure(COR_INFO); //CORCOMPILE_DEPENDENCY
1121 }
1122 DisplayEndArray( "Total Dependencies", COR_INFO );
1123 DisplayEndStructure(COR_INFO); //CORCOMPILE_VERSION_INFO
1124
1125 NativeImageDumper::Dependency * traceDependency = OpenDependency(0);
1126 TraceDumpDependency( 0, traceDependency );
1127
1128 for( COUNT_T i = 0; i < numDeps; ++i )
1129 {
1130 traceDependency = OpenDependency( i + 1 );
1131 TraceDumpDependency( i + 1, traceDependency );
1132 }
1133 _ASSERTE(m_dependencies[0].pModule != NULL);
1134
1135 /* XXX Wed 12/14/2005
1136 * Now for the real insanity. I need to initialize static classes in
1137 * the DAC. First I need to find mscorlib's dependency entry. Search
1138 * through all of the dependencies to find the one marked as
1139 * fIsMscorlib. If I don't find anything marked that way, then "self"
1140 * is mscorlib.
1141 */
1142 Dependency * mscorlib = NULL;
1143 for( COUNT_T i = 0; i < m_numDependencies; ++i )
1144 {
1145 if( m_dependencies[i].fIsMscorlib )
1146 {
1147 mscorlib = &m_dependencies[i];
1148 break;
1149 }
1150 }
1151
1152 //If we're actually dumping mscorlib, remap the mscorlib dependency to our own native image.
1153 if( (mscorlib == NULL) || !wcscmp(m_name, CoreLibName_W))
1154 {
1155 mscorlib = GetDependency(0);
1156 mscorlib->fIsMscorlib = TRUE;
1157 _ASSERTE(mscorlib->fIsHardbound);
1158 }
1159
1160 _ASSERTE(mscorlib != NULL);
1161 if( mscorlib->fIsHardbound )
1162 {
1163 m_isMscorlibHardBound = true;
1164 }
1165 if( m_isMscorlibHardBound )
1166 {
1167 //go through the module to the binder.
1168 PTR_Module mscorlibModule = mscorlib->pModule;
1169
1170 PTR_MscorlibBinder binder = mscorlibModule->m_pBinder;
1171 g_Mscorlib = *binder;
1172
1173 PTR_MethodTable mt = MscorlibBinder::GetExistingClass(CLASS__OBJECT);
1174 g_pObjectClass = mt;
1175 }
1176
1177
1178 if (g_pObjectClass == NULL)
1179 {
1180 //if mscorlib is not hard bound, then warn the user (many features of nidump are shut off)
1181 m_display->ErrorPrintF( "Assembly %S is soft bound to mscorlib. nidump cannot dump MethodTables completely.\n", m_name );
1182 // TritonTODO: reason?
1183 // reset "hard bound state"
1184 m_isMscorlibHardBound = false;
1185
1186 }
1187 }
1188
1189
1190 // @todo: VTable Fixups
1191
1192 // @todo: EAT Jumps
1193
1194 DisplayEndCategory(COR_INFO); //CLRInfo
1195
1196#ifdef FEATURE_READYTORUN
1197 if (m_decoder.HasReadyToRunHeader())
1198 {
1199 DumpReadyToRun();
1200 }
1201 else
1202#endif
1203 if (m_decoder.HasNativeHeader())
1204 {
1205 DumpNative();
1206 }
1207
1208 m_display->EndDocument();
1209}
1210
1211void NativeImageDumper::DumpNative()
1212{
1213 DisplayStartCategory("NativeInfo", NATIVE_INFO);
1214
1215 CONSISTENCY_CHECK(m_decoder.CheckNativeHeader());
1216 if (!m_decoder.CheckNativeHeader())
1217 {
1218 m_display->ErrorPrintF("*** INVALID NATIVE HEADER ***\n");
1219 return;
1220 }
1221
1222 IF_OPT(NATIVE_INFO)
1223 DumpNativeHeader();
1224
1225 //host pointer
1226 CORCOMPILE_EE_INFO_TABLE * infoTable = m_decoder.GetNativeEEInfoTable();
1227
1228 DisplayStartStructure( "CORCOMPILE_EE_INFO_TABLE",
1229 DataPtrToDisplay(PTR_HOST_TO_TADDR(infoTable)),
1230 sizeof(*infoTable), NATIVE_INFO );
1231
1232 /* REVISIT_TODO Mon 09/26/2005
1233 * Move this further down to include the dumping of the module, and
1234 * other things.
1235 */
1236 DisplayEndStructure(NATIVE_INFO); //NativeInfoTable
1237 DisplayEndCategory(NATIVE_INFO); //NativeInfo
1238#if LATER
1239 //come back here and dump all the fields of the CORCOMPILE_EE_INFO_TABLE
1240#endif
1241
1242 IF_OPT(RELOCATIONS)
1243 DumpBaseRelocs();
1244
1245 IF_OPT(NATIVE_TABLES)
1246 DumpHelperTable();
1247
1248 PTR_Module module = (TADDR)m_decoder.GetPersistedModuleImage();
1249
1250 //this needs to run for precodes to load the tables that identify precode ranges
1251 IF_OPT_OR5(MODULE, METHODTABLES, EECLASSES, TYPEDESCS, PRECODES)
1252 DumpModule(module);
1253
1254 IF_OPT_OR3(FIXUP_TABLES, FIXUP_HISTOGRAM, FIXUP_THUNKS)
1255 DumpFixupTables( module );
1256 IF_OPT_OR3(METHODS, GC_INFO, DISASSEMBLE_CODE )
1257 DumpMethods( module );
1258 IF_OPT_OR3(METHODTABLES, EECLASSES, TYPEDESCS)
1259 DumpTypes( module );
1260}
1261
1262void NativeImageDumper::TraceDumpDependency(int idx, NativeImageDumper::Dependency * dependency)
1263{
1264 IF_OPT(DEBUG_TRACE)
1265 {
1266 m_display->ErrorPrintF("Dependency: %d (%p)\n", idx, dependency);
1267 m_display->ErrorPrintF("\tPreferred: %p\n", dependency->pPreferredBase);
1268 m_display->ErrorPrintF("\tLoaded: %p\n", dependency->pLoadedAddress);
1269 m_display->ErrorPrintF("\tSize: %x (%d)\n", dependency->size, dependency->size);
1270 m_display->ErrorPrintF("\tModule: P=%p, L=%p\n", DataPtrToDisplay(dac_cast<TADDR>(dependency->pModule)),
1271 PTR_TO_TADDR(dependency->pModule));
1272 m_display->ErrorPrintF("Mscorlib=%s, Hardbound=%s\n",
1273 (dependency->fIsMscorlib ? "true" : "false"),
1274 (dependency->fIsHardbound ? "true" : "false"));
1275 m_display->ErrorPrintF("Name: %S\n", dependency->name);
1276 }
1277}
1278
1279void NativeImageDumper::WriteElementsMetadata( const char * elementName,
1280 TADDR data, SIZE_T size )
1281{
1282 DisplayStartStructure( elementName,
1283 DataPtrToDisplay(data), size, ALWAYS );
1284
1285 /* XXX Mon 03/13/2006
1286 * Create new metatadata dispenser. When I define the Emit for defining
1287 * assemblyrefs for dependencies, I copy the memory and totally hork any
1288 * mapping back to base addresses.
1289 */
1290 ReleaseHolder<IMetaDataTables> tables;
1291 ReleaseHolder<IMetaDataDispenserEx> pDispenser;
1292 IfFailThrow(MetaDataGetDispenser(CLSID_CorMetaDataDispenser,
1293 IID_IMetaDataDispenserEx, (void **) &pDispenser));
1294
1295 VARIANT opt;
1296
1297 TADDR hostCopyStart = TO_TADDR(PTR_READ(data, (ULONG32)size));
1298 TADDR rebasedPointer;
1299
1300 IfFailThrow(pDispenser->GetOption(MetaDataCheckDuplicatesFor, &opt));
1301 V_UI4(&opt) |= MDDupAssemblyRef | MDDupFile;
1302 IfFailThrow(pDispenser->SetOption(MetaDataCheckDuplicatesFor, &opt));
1303
1304 IfFailThrow(pDispenser->OpenScopeOnMemory((const void *)hostCopyStart, (DWORD)size,
1305 ofRead, IID_IMetaDataTables,
1306 (IUnknown **) &tables));
1307 DisplayStartArray( "Tables", W("%s"), ALWAYS );
1308
1309 for( unsigned i = 0; i < _countof(s_tableTypes); ++i )
1310 {
1311 HRESULT hr = S_OK;
1312 ULONG idx = 0;
1313 hr = tables->GetTableIndex(s_tableTypes[i], &idx);
1314 _ASSERTE(SUCCEEDED(hr));
1315 ULONG cbRow = 0, cRows = 0, cCols = 0, iKey = 0;
1316 const char * name = NULL;
1317 BYTE * ptr = NULL;
1318 hr = tables->GetTableInfo(idx, &cbRow, &cRows, &cCols,
1319 &iKey, &name);
1320 _ASSERTE(SUCCEEDED(hr) || hr == E_INVALIDARG);
1321 if( hr == E_INVALIDARG || cRows == 0 )
1322 {
1323 continue; //no such table.
1324 }
1325
1326 hr = tables->GetRow(idx, 1, (void**)&ptr);
1327 IfFailThrow(hr);
1328 _ASSERTE(SUCCEEDED(hr));
1329 //compute address
1330 rebasedPointer = data + (TO_TADDR(ptr) - hostCopyStart);
1331 _ASSERTE( rebasedPointer >= data && rebasedPointer < (data + size) );
1332 DisplayWriteElementAddressNamed( "table", name,
1333 DataPtrToDisplay(rebasedPointer),
1334 cbRow * cRows , ALWAYS );
1335#if 0
1336 DisplayStartElement( "table", ALWAYS );
1337 DisplayWriteElementString( "name", name, ALWAYS );
1338 //compute address
1339 rebasedPointer = data + (TO_TADDR(ptr) - hostCopyStart);
1340 _ASSERTE( rebasedPointer >= data && rebasedPointer < (data + size) );
1341 DisplayWriteElementAddress( "address", DataPtrToDisplay(rebasedPointer),
1342 cbRow * cRows, ALWAYS );
1343 DisplayEndElement( ALWAYS ); //Table
1344#endif
1345 }
1346 DisplayEndArray( "Total Tables", ALWAYS );
1347
1348 PTR_STORAGESIGNATURE root(data);
1349 _ASSERTE(root->lSignature == STORAGE_MAGIC_SIG);
1350 //the root is followed by the version string who's length is
1351 //root->iVersionString. After that is a storage header that counts the
1352 //number of streams.
1353 PTR_STORAGEHEADER sHdr(data + sizeof(*root) + root->iVersionString);
1354 DisplayStartArray( "Pools", NULL, ALWAYS );
1355
1356 //now check the pools
1357
1358 //start of stream headers
1359 PTR_STORAGESTREAM streamHeader( PTR_TO_TADDR(sHdr) + sizeof(*sHdr) );
1360 for( unsigned i = 0; i < sHdr->iStreams; ++i )
1361 {
1362 if( streamHeader->iSize > 0 )
1363 {
1364 DisplayWriteElementAddressNamed( "heap", streamHeader->rcName,
1365 DataPtrToDisplay( data + streamHeader->iOffset ),
1366 streamHeader->iSize, ALWAYS );
1367 }
1368 //Stream headers aren't fixed size. the size is aligned up based on a
1369 //variable length string at the end.
1370 streamHeader = PTR_STORAGESTREAM(PTR_TO_TADDR(streamHeader)
1371 + ALIGN_UP(offsetof(STORAGESTREAM, rcName) + strlen(streamHeader->rcName) + 1, 4));
1372 }
1373
1374 DisplayEndArray( "Total Pools", ALWAYS ); //Pools
1375 DisplayEndStructure( ALWAYS ); //nativeMetadata
1376}
1377void NativeImageDumper::OpenMetadata()
1378{
1379 COUNT_T size;
1380
1381 DACCOP_IGNORE(CastBetweenAddressSpaces,"nidump is in-proc and doesn't maintain a clean separation of address spaces (target and host are the same.");
1382 const void *data = reinterpret_cast<void*>(dac_cast<TADDR>(m_decoder.GetMetadata(&size)));
1383
1384 ReleaseHolder<IMetaDataDispenserEx> pDispenser;
1385 IfFailThrow(MetaDataGetDispenser(CLSID_CorMetaDataDispenser,
1386 IID_IMetaDataDispenserEx, (void **) &pDispenser));
1387
1388 VARIANT opt;
1389 IfFailThrow(pDispenser->GetOption(MetaDataCheckDuplicatesFor, &opt));
1390 V_UI4(&opt) |= MDDupAssemblyRef | MDDupFile;
1391 IfFailThrow(pDispenser->SetOption(MetaDataCheckDuplicatesFor, &opt));
1392
1393 data = PTR_READ(TO_TADDR(data), size);
1394 IfFailThrow(pDispenser->OpenScopeOnMemory(data, size, ofRead,
1395 IID_IMetaDataImport2, (IUnknown **) &m_import));
1396
1397 IfFailThrow(m_import->QueryInterface(IID_IMetaDataAssemblyImport,
1398 (void **)&m_assemblyImport));
1399
1400 m_MetadataStartTarget = TO_TADDR(data);
1401 m_MetadataSize = size;
1402 data = PTR_READ(TO_TADDR(data), size);
1403 m_MetadataStartHost = TO_TADDR(data);
1404
1405 if (m_decoder.HasNativeHeader())
1406 {
1407 DACCOP_IGNORE(CastBetweenAddressSpaces,"nidump is in-proc and doesn't maintain a clean separation of address spaces (target and host are the same.");
1408 data = reinterpret_cast<void*>(dac_cast<TADDR>(m_decoder.GetNativeManifestMetadata(&size)));
1409
1410 IfFailThrow(pDispenser->OpenScopeOnMemory(data, size, ofRead,
1411 IID_IMetaDataImport2, (IUnknown **) &m_manifestImport));
1412
1413 IfFailThrow(m_manifestImport->QueryInterface(IID_IMetaDataAssemblyImport,
1414 (void **)&m_manifestAssemblyImport));
1415 }
1416 else
1417 {
1418 m_manifestImport = m_import;
1419 m_manifestImport->AddRef();
1420
1421 m_manifestAssemblyImport = m_assemblyImport;
1422 m_manifestAssemblyImport->AddRef();
1423 }
1424}
1425void
1426NativeImageDumper::AppendTokenName(mdToken token, SString& buf)
1427{
1428 AppendTokenName(token, buf, NULL);
1429}
1430void
1431NativeImageDumper::AppendTokenName(mdToken token, SString& buf,
1432 IMetaDataImport2 *pImport,
1433 bool force)
1434{
1435 mdToken parent;
1436 ULONG size;
1437 DWORD attr;
1438 PCCOR_SIGNATURE pSig;
1439 PTR_CCOR_SIGNATURE dacSig;
1440 ULONG cSig;
1441 DWORD flags;
1442 ULONG rva;
1443 CQuickBytes bytes;
1444
1445 if( CHECK_OPT(DISABLE_NAMES) && !force )
1446 {
1447 buf.Append( W("Disabled") );
1448 return;
1449 }
1450
1451 if (pImport == NULL)
1452 pImport = m_import;
1453 if( RidFromToken(token) == mdTokenNil )
1454 {
1455 AppendNilToken( token, buf );
1456 }
1457 else
1458 {
1459 switch (TypeFromToken(token))
1460 {
1461 case mdtTypeDef:
1462 IfFailThrow(pImport->GetTypeDefProps(token, bigBuffer, bigBufferSize, &size, &flags, &parent));
1463 buf.Append(bigBuffer);
1464 break;
1465
1466 case mdtTypeRef:
1467 // TritonTODO: consolidate with desktop
1468 // IfFailThrow(pImport->GetTypeRefProps(token, &parent, bigBuffer, bigBufferSize, &size));
1469 if (FAILED(pImport->GetTypeRefProps(token, &parent, bigBuffer, bigBufferSize, &size)))
1470 buf.Append(W("ADDED TYPEREF (?)"));
1471 else
1472 buf.Append(bigBuffer);
1473 break;
1474
1475 case mdtTypeSpec:
1476 IfFailThrow(pImport->GetTypeSpecFromToken(token, &pSig, &cSig));
1477 dacSig = metadataToHostDAC(pSig, pImport);
1478 TypeToString(dacSig, buf, pImport);
1479 break;
1480
1481 case mdtFieldDef:
1482 IfFailThrow(pImport->GetFieldProps(token, &parent, bigBuffer, bigBufferSize, &size, &attr,
1483 &pSig, &cSig, &flags, NULL, NULL));
1484 AppendTokenName(parent, buf, pImport);
1485 IfFailThrow(pImport->GetFieldProps(token, &parent, bigBuffer, bigBufferSize, &size, &attr,
1486 &pSig, &cSig, &flags, NULL, NULL));
1487 buf.AppendPrintf( W("::%s"), bigBuffer );
1488 break;
1489
1490 case mdtMethodDef:
1491 IfFailThrow(pImport->GetMethodProps(token, &parent, bigBuffer, bigBufferSize, &size, &attr,
1492 &pSig, &cSig, &rva, &flags));
1493 AppendTokenName(parent, buf, pImport);
1494 IfFailThrow(pImport->GetMethodProps(token, &parent, bigBuffer, bigBufferSize, &size, &attr,
1495 &pSig, &cSig, &rva, &flags));
1496 buf.AppendPrintf( W("::%s"), bigBuffer );
1497 break;
1498
1499 case mdtMemberRef:
1500 IfFailThrow(pImport->GetMemberRefProps(token, &parent, bigBuffer, bigBufferSize, &size,
1501 &pSig, &cSig));
1502 AppendTokenName(parent, buf, pImport);
1503 IfFailThrow(pImport->GetMemberRefProps(token, &parent, bigBuffer, bigBufferSize, &size,
1504 &pSig, &cSig));
1505 buf.AppendPrintf( W("::%s"), bigBuffer );
1506 break;
1507
1508 case mdtSignature:
1509 IfFailThrow(pImport->GetSigFromToken(token, &pSig, &cSig));
1510#if LATER
1511 PrettyPrintSig(pSig, cSig, W(""), &bytes, pImport);
1512 m_display->ErrorPrintF("%S", bytes.Ptr());
1513#else
1514 _ASSERTE(!"Unimplemented");
1515 m_display->ErrorPrintF( "unimplemented" );
1516#endif
1517 break;
1518
1519 case mdtString:
1520 IfFailThrow(pImport->GetUserString(token, bigBuffer, bigBufferSize, &size));
1521 bigBuffer[min(size, bigBufferSize-1)] = 0;
1522 buf.Append( bigBuffer );
1523 break;
1524
1525 case mdtAssembly:
1526 case mdtAssemblyRef:
1527 case mdtFile:
1528 case mdtExportedType:
1529 {
1530 ReleaseHolder<IMetaDataAssemblyImport> pAssemblyImport;
1531 IfFailThrow(pImport->QueryInterface(IID_IMetaDataAssemblyImport,
1532 (void **)&pAssemblyImport));
1533 PrintManifestTokenName(token, buf, pAssemblyImport, force);
1534 }
1535 break;
1536
1537 case mdtGenericParam:
1538 {
1539 ULONG nameLen;
1540 IfFailThrow(pImport->GetGenericParamProps(token, NULL, NULL, NULL, NULL, bigBuffer,
1541 _countof(bigBuffer), &nameLen));
1542 bigBuffer[min(nameLen, _countof(bigBuffer) - 1)] = 0;
1543 buf.Append( bigBuffer );
1544 }
1545 break;
1546
1547 default:
1548 _ASSERTE( !"Unknown token type in AppendToken" );
1549 buf.AppendPrintf( W("token 0x%x"), token );
1550 }
1551 }
1552}
1553void NativeImageDumper::PrintManifestTokenName(mdToken token, SString& str)
1554{
1555 PrintManifestTokenName(token, str, NULL);
1556}
1557void
1558NativeImageDumper::PrintManifestTokenName(mdToken token,
1559 SString& buf,
1560 IMetaDataAssemblyImport *pAssemblyImport,
1561 bool force)
1562{
1563 ULONG size;
1564 const void *pSig;
1565 ULONG cSig;
1566 DWORD flags;
1567 CQuickBytes bytes;
1568 ULONG hash;
1569
1570 if( CHECK_OPT(DISABLE_NAMES) && !force )
1571 {
1572 buf.Append( W("Disabled") );
1573 return;
1574 }
1575
1576 if (pAssemblyImport == NULL)
1577 pAssemblyImport = m_manifestAssemblyImport;
1578
1579 if( RidFromToken(token) == mdTokenNil )
1580 {
1581 AppendNilToken( token, buf );
1582 }
1583 else
1584 {
1585 switch (TypeFromToken(token))
1586 {
1587 case mdtAssembly:
1588 IfFailThrow(pAssemblyImport->GetAssemblyProps(token, &pSig, &cSig,
1589 &hash, bigBuffer,
1590 bigBufferSize, &size,
1591 NULL, &flags));
1592
1593 buf.Append(bigBuffer);
1594 break;
1595
1596 case mdtAssemblyRef:
1597 IfFailThrow(pAssemblyImport->GetAssemblyRefProps(token, &pSig,
1598 &cSig, bigBuffer,
1599 bigBufferSize,
1600 &size, NULL, NULL,
1601 NULL, &flags));
1602 buf.Append(bigBuffer);
1603 break;
1604
1605 case mdtFile:
1606 IfFailThrow(pAssemblyImport->GetFileProps(token, bigBuffer,
1607 bigBufferSize, &size,
1608 NULL, NULL, &flags));
1609
1610 buf.Append(bigBuffer);
1611 break;
1612
1613 case mdtExportedType:
1614 IfFailThrow(pAssemblyImport->GetExportedTypeProps(token, bigBuffer,
1615 bigBufferSize, &size,
1616 NULL, NULL, &flags));
1617
1618 buf.Append(bigBuffer);
1619 break;
1620
1621 default:
1622 buf.AppendPrintf(W("token %x"), token);
1623 }
1624 }
1625}
1626
1627BOOL NativeImageDumper::HandleFixupForHistogram(PTR_CORCOMPILE_IMPORT_SECTION pSection,
1628 SIZE_T fixupIndex,
1629 SIZE_T *fixupCell)
1630{
1631 COUNT_T nImportSections;
1632 PTR_CORCOMPILE_IMPORT_SECTION pImportSections = m_decoder.GetNativeImportSections(&nImportSections);
1633
1634 COUNT_T tableSize;
1635 TADDR tableBase = m_decoder.GetDirectoryData(&pSection->Section, &tableSize);
1636
1637 COUNT_T table = (COUNT_T)(pSection - pImportSections);
1638 _ASSERTE(table < nImportSections);
1639
1640 SIZE_T offset = dac_cast<TADDR>(fixupCell) - tableBase;
1641 _ASSERTE( offset < tableSize );
1642
1643 COUNT_T entry = (COUNT_T)(offset / sizeof(TADDR));
1644 m_fixupHistogram[table][entry]++;
1645
1646 return TRUE;
1647}
1648
1649void NativeImageDumper::ComputeMethodFixupHistogram( PTR_Module module )
1650{
1651 COUNT_T nImportSections;
1652 PTR_CORCOMPILE_IMPORT_SECTION pImportSections = m_decoder.GetNativeImportSections(&nImportSections);
1653
1654 m_fixupHistogram = new COUNT_T * [nImportSections];
1655
1656 for (COUNT_T i=0; i < nImportSections; i++)
1657 {
1658 PTR_CORCOMPILE_IMPORT_SECTION pSection = m_decoder.GetNativeImportSectionFromIndex(i);
1659
1660 COUNT_T count = pSection->Section.Size / sizeof(TADDR);
1661
1662 m_fixupHistogram[i] = new COUNT_T [count];
1663 ZeroMemory(m_fixupHistogram[i], count * sizeof(COUNT_T));
1664 }
1665
1666 ZeroMemory(&m_fixupCountHistogram, sizeof(m_fixupCountHistogram));
1667 // profiled hot code
1668
1669 MethodIterator mi(module, &m_decoder, MethodIterator::Hot);
1670 while (mi.Next())
1671 {
1672 m_fixupCount = 0;
1673
1674 TADDR pFixupList = mi.GetMethodDesc()->GetFixupList();
1675
1676 if (pFixupList != NULL)
1677 {
1678 COUNT_T nImportSections;
1679 PTR_CORCOMPILE_IMPORT_SECTION pImportSections = m_decoder.GetNativeImportSections(&nImportSections);
1680
1681 module->FixupDelayListAux(pFixupList, this,
1682 &NativeImageDumper::HandleFixupForHistogram,
1683 pImportSections, nImportSections,
1684 &m_decoder);
1685 }
1686
1687 if (m_fixupCount < COUNT_HISTOGRAM_SIZE)
1688 m_fixupCountHistogram[m_fixupCount]++;
1689 else
1690 m_fixupCountHistogram[COUNT_HISTOGRAM_SIZE-1]++;
1691 }
1692
1693 // unprofiled code
1694 MethodIterator miUnprofiled(module, &m_decoder, MethodIterator::Unprofiled);
1695
1696 while(miUnprofiled.Next())
1697 {
1698 m_fixupCount = 0;
1699
1700 TADDR pFixupList = miUnprofiled.GetMethodDesc()->GetFixupList();
1701
1702 if (pFixupList != NULL)
1703 {
1704 COUNT_T nImportSections;
1705 PTR_CORCOMPILE_IMPORT_SECTION pImportSections = m_decoder.GetNativeImportSections(&nImportSections);
1706
1707 module->FixupDelayListAux(pFixupList, this,
1708 &NativeImageDumper::HandleFixupForHistogram,
1709 pImportSections, nImportSections,
1710 &m_decoder);
1711 }
1712
1713 if (m_fixupCount < COUNT_HISTOGRAM_SIZE)
1714 m_fixupCountHistogram[m_fixupCount]++;
1715 else
1716 m_fixupCountHistogram[COUNT_HISTOGRAM_SIZE-1]++;
1717 }
1718}
1719
1720void NativeImageDumper::DumpFixupTables( PTR_Module module )
1721{
1722 IF_OPT(FIXUP_HISTOGRAM)
1723 ComputeMethodFixupHistogram( module );
1724
1725 DisplayStartCategory( "Imports", FIXUP_TABLES );
1726
1727 COUNT_T nImportSections;
1728 PTR_CORCOMPILE_IMPORT_SECTION pImportSections = m_decoder.GetNativeImportSections(&nImportSections);
1729
1730 for (COUNT_T iImportSections = 0; iImportSections < nImportSections; iImportSections++)
1731 {
1732 PTR_CORCOMPILE_IMPORT_SECTION pImportSection = pImportSections + iImportSections;
1733
1734 COUNT_T size;
1735 TADDR pTable(m_decoder.GetDirectoryData(&pImportSection->Section, &size));
1736 TADDR pTableEnd = pTable + size;
1737
1738 TADDR pDataTable(NULL);
1739
1740 if (pImportSection->Signatures != 0)
1741 pDataTable = m_decoder.GetRvaData(pImportSection->Signatures);
1742
1743 switch (pImportSection->Type)
1744 {
1745 case CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD:
1746 {
1747 COUNT_T entrySize = pImportSection->EntrySize;
1748 COUNT_T count = size / entrySize;
1749 _ASSERTE(entrySize == sizeof(CORCOMPILE_VIRTUAL_IMPORT_THUNK));
1750
1751 for (TADDR pEntry = pTable; pEntry < pTableEnd; pEntry += entrySize)
1752 {
1753 PTR_CORCOMPILE_VIRTUAL_IMPORT_THUNK pThunk = pEntry;
1754
1755 DisplayStartStructure("VirtualImportThunk", DPtrToPreferredAddr(pThunk),
1756 entrySize, FIXUP_THUNKS );
1757
1758 DisplayWriteElementInt( "Slot", pThunk->slotNum, FIXUP_THUNKS);
1759
1760 DisplayEndStructure( FIXUP_THUNKS );
1761 }
1762 }
1763 break;
1764
1765 case CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD:
1766 {
1767 COUNT_T entrySize = pImportSection->EntrySize;
1768 COUNT_T count = size / entrySize;
1769 _ASSERTE(entrySize == sizeof(CORCOMPILE_EXTERNAL_METHOD_THUNK));
1770
1771 for (TADDR pEntry = pTable; pEntry < pTableEnd; pEntry += entrySize)
1772 {
1773 PTR_CORCOMPILE_EXTERNAL_METHOD_THUNK pThunk = pEntry;
1774
1775 DisplayStartStructure("ExternalImportThunk", DPtrToPreferredAddr(pThunk),
1776 entrySize, FIXUP_THUNKS );
1777
1778 TADDR pDataAddr = pDataTable + ((pEntry - pTable) / entrySize) * sizeof(DWORD);
1779 PTR_DWORD pData = pDataAddr;
1780
1781 DisplayWriteElementPointer( "DataAddress ", pDataAddr, FIXUP_THUNKS );
1782
1783 TADDR blobSigAddr = RvaToDisplay(*pData);
1784 DisplayWriteElementPointer( "TargetSigAddress", blobSigAddr, FIXUP_THUNKS );
1785 TempBuffer buf;
1786 FixupBlobToString(*pData, buf);
1787 DisplayWriteElementStringW( "TargetName", (const WCHAR*)buf, FIXUP_THUNKS );
1788
1789 DisplayEndStructure( FIXUP_THUNKS );
1790 }
1791 }
1792 break;
1793
1794 default:
1795 {
1796 COUNT_T count = size / sizeof(TADDR);
1797
1798 for (COUNT_T j = 0; j < count; j++)
1799 {
1800 if (dac_cast<PTR_TADDR>(pTable)[j] == 0)
1801 continue;
1802
1803 SIZE_T nNextEntry = j + 1;
1804 while (nNextEntry < count && dac_cast<PTR_TADDR>(pTable)[nNextEntry] == 0)
1805 nNextEntry++;
1806
1807 DisplayStartStructure("ImportEntry", DPtrToPreferredAddr(dac_cast<PTR_TADDR>(pTable) + j),
1808 (nNextEntry - j) * sizeof(TADDR), FIXUP_TABLES );
1809
1810 if (pDataTable != NULL)
1811 {
1812 DWORD rva = dac_cast<PTR_DWORD>(pDataTable)[j];
1813 WriteElementsFixupTargetAndName(rva);
1814 }
1815 else
1816 {
1817 SIZE_T token = dac_cast<PTR_TADDR>(pTable)[j];
1818 DisplayWriteElementPointer( "TaggedValue", token, FIXUP_TABLES );
1819 WriteElementsFixupBlob(pImportSection, token);
1820 }
1821
1822 DisplayWriteElementInt( "index", j, FIXUP_HISTOGRAM);
1823 DisplayWriteElementInt( "ReferenceCount", m_fixupHistogram[iImportSections][j], FIXUP_HISTOGRAM );
1824
1825 DisplayEndStructure( FIXUP_TABLES );
1826 }
1827 }
1828 }
1829 }
1830 DisplayEndCategory( FIXUP_TABLES );
1831}
1832
1833void NativeImageDumper::FixupThunkToString(PTR_CORCOMPILE_IMPORT_SECTION pImportSection, TADDR addr, SString& buf)
1834{
1835 switch (pImportSection->Type)
1836 {
1837 case CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD:
1838 {
1839 PTR_CORCOMPILE_VIRTUAL_IMPORT_THUNK pThunk = addr;
1840 buf.AppendPrintf( W("slot %d"), pThunk->slotNum );
1841 }
1842 break;
1843
1844 case CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD:
1845 case CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH:
1846 {
1847 TADDR pTable(m_decoder.GetDirectoryData(&pImportSection->Section));
1848 COUNT_T index = (COUNT_T)(addr - pTable) / pImportSection->EntrySize;
1849 TADDR pDataTable(m_decoder.GetRvaData(pImportSection->Signatures));
1850 TADDR pDataAddr = pDataTable + (index * sizeof(DWORD));
1851 PTR_DWORD pData = pDataAddr;
1852 FixupBlobToString(*pData, buf);
1853 }
1854 break;
1855
1856 default:
1857 _ASSERTE(!"Unknown import type");
1858 }
1859}
1860
1861void NativeImageDumper::WriteElementsFixupBlob(PTR_CORCOMPILE_IMPORT_SECTION pSection, SIZE_T fixup)
1862{
1863 if (pSection != NULL && !CORCOMPILE_IS_FIXUP_TAGGED(fixup, pSection))
1864 {
1865 TempBuffer buf;
1866 if (pSection->Type == CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE)
1867 {
1868 TypeHandleToString(TypeHandle::FromTAddr((TADDR)fixup), buf);
1869 }
1870 else
1871 if (pSection->Type == CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE)
1872 {
1873 MethodDescToString(PTR_MethodDesc((TADDR)fixup), buf);
1874 }
1875 else
1876 {
1877 _ASSERTE(!"Unknown Type");
1878 IfFailThrow(E_FAIL);
1879 }
1880 m_display->WriteElementStringW( "FixupTargetName", (const WCHAR*)buf );
1881 return;
1882 }
1883
1884 RVA rva = CORCOMPILE_UNTAG_TOKEN(fixup);
1885
1886 WriteElementsFixupTargetAndName(rva);
1887}
1888
1889const NativeImageDumper::EnumMnemonics s_EncodeMethodSigFlags[] =
1890{
1891#define EMS_ENTRY(f) NativeImageDumper::EnumMnemonics(ENCODE_METHOD_SIG_ ## f, W(#f))
1892 EMS_ENTRY(UnboxingStub),
1893 EMS_ENTRY(InstantiatingStub),
1894 EMS_ENTRY(MethodInstantiation),
1895 EMS_ENTRY(SlotInsteadOfToken),
1896 EMS_ENTRY(MemberRefToken),
1897 EMS_ENTRY(Constrained),
1898 EMS_ENTRY(OwnerType),
1899#undef EMS_ENTRY
1900};
1901
1902void NativeImageDumper::FixupBlobToString(RVA rva, SString& buf)
1903{
1904 PTR_CCOR_SIGNATURE sig = (TADDR) m_decoder.GetRvaData(rva);
1905 BYTE kind = *sig++;
1906
1907 CorTokenType tkType = (CorTokenType)0;
1908
1909 IMetaDataImport2 * pImport = m_import;
1910
1911 if (kind & ENCODE_MODULE_OVERRIDE)
1912 {
1913 Import *import = OpenImport(DacSigUncompressData(sig));
1914 kind &= ~ENCODE_MODULE_OVERRIDE;
1915
1916 Dependency *pDep = import->dependency;
1917 if (pDep == NULL)
1918 {
1919 return;
1920 }
1921
1922 pImport = pDep->pImport;
1923
1924 _ASSERTE(pImport != NULL);
1925
1926 // print assembly/module info
1927
1928 mdToken realRef =
1929 MapAssemblyRefToManifest(TokenFromRid(import->index,
1930 mdtAssemblyRef),
1931 m_assemblyImport);
1932 AppendToken(realRef, buf, m_manifestImport);
1933 buf.Append( W(" ") );
1934 }
1935
1936 // print further info
1937
1938 mdToken token;
1939
1940 switch (kind)
1941 {
1942 case ENCODE_MODULE_HANDLE:
1943 // No further info
1944 break;
1945
1946 case ENCODE_TYPE_HANDLE:
1947 EncodeType:
1948 if (pImport != NULL)
1949 TypeToString(sig, buf, pImport);
1950 else
1951 buf.Append( W("<unresolved type> ") );
1952
1953 break;
1954
1955 case ENCODE_METHOD_HANDLE:
1956 EncodeMethod:
1957 {
1958 //Flags are first
1959 DWORD methodFlags = DacSigUncompressData(sig);
1960
1961 // If the type portion for this generic method signature
1962 // is from a different module then both the generic type and the
1963 // generic method tokens are interpreted in the context of that module,
1964 // and not the current import. This is returned by TypeToString.
1965 //
1966 IMetaDataImport2 * pMethodImport = pImport;
1967 if (pImport != NULL)
1968 {
1969 if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
1970 {
1971 pMethodImport = TypeToString(sig, buf, pImport);
1972 }
1973 }
1974 else
1975 {
1976 buf.Append( W("<unresolved method signature>") );
1977 break;
1978 }
1979
1980 //If we have SlotInsteadOfToken set then this is a slot number (i.e. for an array)
1981 if( methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken )
1982 {
1983 buf.AppendPrintf( W(" method slot %d"), DacSigUncompressData(sig) );
1984 }
1985 else
1986 {
1987 // decode the methodToken (a rid is encoded)
1988 RID rid = DacSigUncompressData(sig);
1989
1990 mdMethodDef methodToken = ((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) ? mdtMemberRef : mdtMethodDef) | rid;
1991
1992 buf.Append( W(" ") );
1993
1994 // Get the full signature of method from external module
1995 // Need temporary buffer because method name will be inserted
1996 // in between the signature
1997
1998 TempBuffer tempName;
1999
2000 AppendTokenName( methodToken, tempName, pMethodImport );
2001
2002 if( methodFlags & ENCODE_METHOD_SIG_MethodInstantiation )
2003 {
2004 //for each generic arg, there is a type handle.
2005 ULONG numParams = DacSigUncompressData(sig);
2006
2007 tempName.Append( W("<") );
2008 for( unsigned i = 0;i < numParams; ++i )
2009 {
2010 if( i != 0 )
2011 tempName.Append( W(", ") );
2012
2013 // switch back to using pImport to resolve tokens
2014 TypeToString(sig, tempName, pImport);
2015 }
2016 tempName.Append( W(">") );
2017 }
2018
2019 PCCOR_SIGNATURE pvSigBlob;
2020 ULONG cbSigBlob;
2021
2022 if (methodFlags & ENCODE_METHOD_SIG_MemberRefToken)
2023 {
2024 IfFailThrow(pMethodImport->GetMemberRefProps(methodToken,
2025 NULL,
2026 NULL,
2027 0,
2028 NULL,
2029 &pvSigBlob,
2030 &cbSigBlob));
2031 }
2032 else
2033 {
2034 IfFailThrow(pMethodImport->GetMethodProps(methodToken,
2035 NULL,
2036 NULL,
2037 0,
2038 NULL,
2039 NULL,
2040 &pvSigBlob,
2041 &cbSigBlob,
2042 NULL,
2043 NULL));
2044 }
2045
2046 CQuickBytes prettySig;
2047 ReleaseHolder<IMDInternalImport> pInternal;
2048 IfFailThrow(GetMDInternalInterfaceFromPublic(pMethodImport, IID_IMDInternalImport,
2049 (void**)&pInternal));
2050 StackScratchBuffer buffer;
2051 const ANSI * ansi = tempName.GetANSI(buffer);
2052 ansi = PrettyPrintSig(pvSigBlob, cbSigBlob, ansi, &prettySig, pInternal, NULL);
2053 tempName.SetANSI( ansi );
2054 buf.Append(tempName);
2055 }
2056
2057 buf.Append( W(" flags=(") );
2058 EnumFlagsToString( methodFlags, s_EncodeMethodSigFlags, _countof(s_EncodeMethodSigFlags),
2059 W(", "), buf );
2060 buf.Append( W(")") );
2061 }
2062 break;
2063
2064 case ENCODE_FIELD_HANDLE:
2065 EncodeField:
2066 {
2067 //Flags are first
2068 DWORD fieldFlags = DacSigUncompressData(sig);
2069
2070 IMetaDataImport2 * pFieldImport = pImport;
2071 if (pImport != NULL)
2072 {
2073 if (fieldFlags & ENCODE_FIELD_SIG_OwnerType)
2074 {
2075 pFieldImport = TypeToString(sig, buf, pImport);
2076 }
2077 }
2078 else
2079 buf.Append( W("<unresolved type>") );
2080
2081 if (fieldFlags & ENCODE_FIELD_SIG_IndexInsteadOfToken)
2082 {
2083 buf.AppendPrintf( W(" field index %d"), DacSigUncompressData(sig) );
2084 }
2085 else
2086 {
2087 // decode the methodToken (a rid is encoded)
2088 RID rid = DacSigUncompressData(sig);
2089
2090 mdMethodDef fieldToken = ((fieldFlags & ENCODE_FIELD_SIG_MemberRefToken) ? mdtMemberRef : mdtFieldDef) | rid;
2091
2092 buf.Append( W(" ") );
2093
2094 AppendTokenName( fieldToken, buf, pFieldImport );
2095 }
2096 }
2097 break;
2098
2099 case ENCODE_STRING_HANDLE:
2100 token = TokenFromRid(DacSigUncompressData(sig), mdtString);
2101 if (pImport != NULL)
2102 AppendToken(token, buf, pImport);
2103 else
2104 buf.AppendPrintf( W("<unresolved token %d>"), token );
2105 break;
2106
2107 case ENCODE_VARARGS_SIG:
2108 tkType = mdtFieldDef;
2109 goto DataToTokenCore;
2110 case ENCODE_VARARGS_METHODREF:
2111 tkType = mdtMemberRef;
2112 goto DataToTokenCore;
2113 case ENCODE_VARARGS_METHODDEF:
2114 tkType = mdtMemberRef;
2115 goto DataToTokenCore;
2116DataToTokenCore:
2117 token = TokenFromRid(DacSigUncompressData(sig), tkType);
2118 if (pImport != NULL)
2119 AppendToken(token, buf, pImport);
2120 else
2121 buf.AppendPrintf( "<unresolved token %d>", token );
2122 break;
2123
2124 case ENCODE_METHOD_ENTRY:
2125 buf.Append( W("Entrypoint for ") );
2126 goto EncodeMethod;
2127
2128 case ENCODE_METHOD_ENTRY_DEF_TOKEN:
2129 {
2130 buf.Append( W("Entrypoint for ") );
2131 token = TokenFromRid(DacSigUncompressData(sig), mdtMethodDef);
2132 AppendTokenName(token, buf, pImport);
2133 }
2134 break;
2135
2136 case ENCODE_METHOD_ENTRY_REF_TOKEN:
2137 {
2138 buf.Append( W("Entrypoint for ref ") );
2139 token = TokenFromRid(DacSigUncompressData(sig), mdtMemberRef);
2140 AppendTokenName(token, buf, pImport);
2141 }
2142 break;
2143
2144 case ENCODE_VIRTUAL_ENTRY:
2145 buf.Append( W("Entrypoint for ") );
2146 goto EncodeMethod;
2147
2148 case ENCODE_VIRTUAL_ENTRY_DEF_TOKEN:
2149 {
2150 buf.Append( W("Virtual call for ") );
2151 token = TokenFromRid(DacSigUncompressData(sig), mdtMethodDef);
2152 AppendTokenName(token, buf, pImport);
2153 }
2154 break;
2155
2156 case ENCODE_VIRTUAL_ENTRY_REF_TOKEN:
2157 {
2158 buf.Append( W("Virtual call for ref ") );
2159 token = TokenFromRid(DacSigUncompressData(sig), mdtMemberRef);
2160 AppendTokenName(token, buf, pImport);
2161 }
2162 break;
2163
2164 case ENCODE_VIRTUAL_ENTRY_SLOT:
2165 {
2166 buf.Append( W("Virtual call for ") );
2167 int slot = DacSigUncompressData(sig);
2168 buf.AppendPrintf( W("slot %d "), slot );
2169 goto EncodeType;
2170 }
2171
2172 case ENCODE_MODULE_ID_FOR_STATICS:
2173 buf.Append( W("Module For Statics") );
2174 // No further info
2175 break;
2176
2177 case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
2178 buf.Append( W("Module For Statics for ") );
2179 goto EncodeType;
2180
2181 case ENCODE_CLASS_ID_FOR_STATICS:
2182 buf.Append( W("Statics ID for ") );
2183 goto EncodeType;
2184
2185 case ENCODE_STATIC_FIELD_ADDRESS:
2186 buf.Append( W("Static field address for ") );
2187 goto EncodeField;
2188
2189 case ENCODE_SYNC_LOCK:
2190 buf.Append( W("Synchronization handle for ") );
2191 break;
2192
2193 case ENCODE_INDIRECT_PINVOKE_TARGET:
2194 buf.Append( W("Indirect P/Invoke target for ") );
2195 break;
2196
2197 case ENCODE_PROFILING_HANDLE:
2198 buf.Append( W("Profiling handle for ") );
2199 goto EncodeMethod;
2200
2201 case ENCODE_ACTIVE_DEPENDENCY:
2202 {
2203 buf.Append( W("Active dependency for ") );
2204
2205 int targetModuleIndex = DacSigUncompressData(sig);
2206 Import *targetImport = OpenImport(targetModuleIndex);
2207
2208 mdToken realRef =
2209 MapAssemblyRefToManifest(TokenFromRid(targetImport->index,
2210 mdtAssemblyRef),
2211 m_assemblyImport);
2212 AppendToken(realRef, buf, m_manifestImport);
2213 buf.Append( W(" ") );
2214 }
2215 break;
2216
2217 default:
2218 buf.Append( W("Unknown fixup kind") );
2219 _ASSERTE(!"Unknown fixup kind");
2220 }
2221}
2222
2223void NativeImageDumper::WriteElementsFixupTargetAndName(RVA rva)
2224{
2225 if( rva == NULL )
2226 {
2227 /* XXX Tue 04/11/2006
2228 * This should only happen for static fields. If the field is
2229 * unaligned, we need an extra cell for an indirection.
2230 */
2231 m_display->WriteElementPointer( "FixupTargetValue", NULL );
2232 m_display->WriteElementStringW( "FixupTargetName", W("NULL") );
2233 return;
2234 }
2235
2236 m_display->WriteElementPointer( "FixupTargetValue", RvaToDisplay(rva) );
2237
2238 TempBuffer buf;
2239 FixupBlobToString(rva, buf);
2240
2241 m_display->WriteElementStringW( "FixupTargetName", (const WCHAR*)buf );
2242}
2243
2244NativeImageDumper::Dependency * NativeImageDumper::GetDependency(mdAssemblyRef token, IMetaDataAssemblyImport *pImport)
2245{
2246 if (RidFromToken(token) == 0)
2247 return OpenDependency(0);
2248
2249 if (pImport == NULL)
2250 pImport = m_assemblyImport;
2251
2252 // Need to map from IL token to manifest token
2253 mdAssemblyRef manifestToken = MapAssemblyRefToManifest(token, pImport);
2254
2255 if( manifestToken == mdAssemblyNil )
2256 {
2257 //this is "self"
2258 return OpenDependency(0);
2259 }
2260
2261 COUNT_T count;
2262 PTR_CORCOMPILE_DEPENDENCY deps(TO_TADDR(m_decoder.GetNativeDependencies(&count)));
2263
2264 for (COUNT_T i = 0; i < count; i++)
2265 {
2266 if (deps[i].dwAssemblyRef == manifestToken)
2267 return OpenDependency(i+1);
2268 }
2269
2270 TempBuffer buf;
2271 AppendTokenName(manifestToken, buf, m_manifestImport);
2272 m_display->ErrorPrintF("Error: unlisted assembly dependency %S\n", (const WCHAR*)buf);
2273
2274 return NULL;
2275}
2276
2277mdAssemblyRef NativeImageDumper::MapAssemblyRefToManifest(mdAssemblyRef token, IMetaDataAssemblyImport *pAssemblyImport)
2278{
2279 // Reference may be to self
2280 if (TypeFromToken(token) == mdtAssembly)
2281 return token;
2282
2283 // Additional tokens not originally present overflow to manifest automatically during emit
2284 /* REVISIT_TODO Tue 01/31/2006
2285 * Factor this code out so that it is shared with the module index code in the CLR that looks
2286 * exactly thes same
2287 */
2288 //count the assembly refs.
2289 ULONG count = 0;
2290
2291 HCORENUM iter = NULL;
2292 for (;;)
2293 {
2294 ULONG tokens = 0;
2295 mdAssemblyRef tmp;
2296 IfFailThrow(pAssemblyImport->EnumAssemblyRefs(&iter, &tmp, 1,
2297 &tokens));
2298 if (tokens == 0)
2299 break;
2300 count ++;
2301 }
2302 pAssemblyImport->CloseEnum(iter);
2303
2304 if( RidFromToken(token) > count )
2305 {
2306 //out of range import. This means that it has spilled over. Subtract
2307 //off the max number of assembly refs and return it as a manifest
2308 //token.
2309 return token - (count + 1);
2310 }
2311
2312 ULONG cchName;
2313 ASSEMBLYMETADATA metadata;
2314
2315 ZeroMemory(&metadata, sizeof(metadata));
2316
2317 IfFailThrow(pAssemblyImport->GetAssemblyRefProps(token, NULL, NULL,
2318 NULL, 0, &cchName,
2319 &metadata, NULL, NULL,
2320 NULL));
2321
2322 LPWSTR szAssemblyName = NULL;
2323
2324 if (cchName > 0)
2325 szAssemblyName = (LPWSTR) _alloca(cchName * sizeof(WCHAR));
2326
2327 if (metadata.cbLocale > 0)
2328 metadata.szLocale = (LPWSTR) _alloca(metadata.cbLocale * sizeof(WCHAR));
2329 if (metadata.ulProcessor > 0)
2330 metadata.rProcessor = (DWORD*) _alloca(metadata.ulProcessor * sizeof(DWORD));
2331 if (metadata.ulOS > 0)
2332 metadata.rOS = (OSINFO*) _alloca(metadata.ulOS * sizeof(OSINFO));
2333
2334 const void *pbPublicKey;
2335 ULONG cbPublicKey;
2336 DWORD flags;
2337 const void *pbHashValue;
2338 ULONG cbHashValue;
2339
2340
2341 IfFailThrow(pAssemblyImport->GetAssemblyRefProps(token, &pbPublicKey, &cbPublicKey,
2342 szAssemblyName, cchName, NULL,
2343 &metadata, &pbHashValue, &cbHashValue,
2344 &flags));
2345
2346 //Notice that we're searching for the provided metadata for the dependency info and then looking in the
2347 //image we're dumping for the dependency.
2348 //
2349 //Also, sometimes we find "self" in these searches. If so, return mdAssemblyDefNil as a canary value.
2350
2351 if( !wcscmp(szAssemblyName, m_name) )
2352 {
2353 //we need "self".
2354 return mdAssemblyNil;
2355 }
2356
2357 mdAssemblyRef ret = mdAssemblyRefNil;
2358 /*HCORENUM*/ iter = NULL;
2359 for(;;)
2360 {
2361 //Walk through all the assemblyRefs and search for a match. I would use DefineAssemblyRef here, but
2362 //if I do it will create an assemblyRef is one is not found. Then I fail in a bad place. This
2363 //way I can fail in a less bad place.
2364 mdAssemblyRef currentRef;
2365 //ULONG count;
2366 IfFailThrow(m_manifestAssemblyImport->EnumAssemblyRefs(&iter, &currentRef, 1, &count));
2367 if( 0 == count )
2368 break;
2369
2370 //get the information about the assembly ref and compare.
2371 const void * publicKeyToken;
2372 ULONG pktSize = 0;
2373 WCHAR name[128];
2374 /*ULONG*/ cchName = _countof(name);
2375 ASSEMBLYMETADATA curMD = {0};
2376
2377 IfFailThrow(m_manifestAssemblyImport->GetAssemblyRefProps(currentRef, &publicKeyToken, &pktSize, name,
2378 cchName, &cchName, &curMD,
2379 NULL /*ppbHashValue*/, NULL/*pcbHashValue*/,
2380 NULL/*pdwAssemblyRefFlags*/));
2381 if( !wcscmp(name, szAssemblyName) )
2382 {
2383 if( cbPublicKey == pktSize && !memcmp(pbPublicKey, publicKeyToken, pktSize)
2384 && curMD.usMajorVersion == metadata.usMajorVersion
2385 && curMD.usMinorVersion == metadata.usMinorVersion)
2386 {
2387 ret = currentRef;
2388 break;
2389 }
2390 else if (wcscmp(szAssemblyName, CoreLibName_W) == 0)
2391 {
2392 // Mscorlib is special - version number and public key token are ignored.
2393 ret = currentRef;
2394 break;
2395 }
2396 else if (metadata.usMajorVersion == 255 &&
2397 metadata.usMinorVersion == 255 &&
2398 metadata.usBuildNumber == 255 &&
2399 metadata.usRevisionNumber == 255)
2400 {
2401 // WinMDs encode all assemblyrefs with version 255.255.255.255 including CLR assembly dependencies (mscorlib, System).
2402 ret = currentRef;
2403 }
2404 else
2405 {
2406 //there was an assembly with the correct name, but with the wrong version number. Let the
2407 //user know.
2408 m_display->ErrorPrintF("MapAssemblyRefToManifest: found %S with version %d.%d in manifest. Wanted version %d.%d.\n", szAssemblyName, curMD.usMajorVersion, curMD.usMinorVersion, metadata.usMajorVersion, metadata.usMinorVersion);
2409 // TritonTODO: why?
2410 ret = currentRef;
2411 break;
2412 }
2413
2414 }
2415 }
2416 pAssemblyImport->CloseEnum(iter);
2417 if( ret == mdAssemblyRefNil )
2418 {
2419 TempBuffer pkt;
2420 appendByteArray(pkt, (const BYTE*)pbPublicKey, cbPublicKey);
2421 m_display->ErrorPrintF("MapAssemblyRefToManifest could not find token for %S, Version=%d.%d, PublicKeyToken=%S\n", szAssemblyName, metadata.usMajorVersion, metadata.usMinorVersion, (const WCHAR *)pkt);
2422 _ASSERTE(!"MapAssemblyRefToManifest failed to find a match");
2423 }
2424
2425 return ret;
2426}
2427
2428NativeImageDumper::Import * NativeImageDumper::OpenImport(int i)
2429{
2430 if (m_imports == NULL)
2431 {
2432 COUNT_T count;
2433 m_decoder.GetNativeDependencies(&count);
2434 m_numImports = count;
2435 m_imports = new Import [count];
2436 ZeroMemory(m_imports, count * sizeof(m_imports[0]));
2437 }
2438
2439 if (m_imports[i].index == 0)
2440 {
2441 //GetNativeImportFromIndex returns a host pointer.
2442 m_imports[i].index = i;
2443
2444 /*
2445 mdToken tok = TokenFromRid(entry->index, mdtAssemblyRef);
2446 Dependency * dependency = GetDependency( MapAssemblyRefToManifest(tok,
2447 */
2448 Dependency *dependency = GetDependency(TokenFromRid(i, mdtAssemblyRef));
2449 m_imports[i].dependency = dependency;
2450 _ASSERTE(dependency); //Why can this be null?
2451
2452 }
2453
2454 return &m_imports[i];
2455}
2456
2457
2458const NativeImageDumper::Dependency *NativeImageDumper::GetDependencyForFixup(RVA rva)
2459{
2460 PTR_CCOR_SIGNATURE sig = (TADDR) m_decoder.GetRvaData(rva);
2461 if (*sig++ & ENCODE_MODULE_OVERRIDE)
2462 {
2463 unsigned idx = DacSigUncompressData(sig);
2464
2465 _ASSERTE(idx >= 0 && idx < (int)m_numImports);
2466 return OpenImport(idx)->dependency;
2467 }
2468
2469 return &m_dependencies[0];
2470}
2471
2472
2473void NativeImageDumper::AppendToken(mdToken token, SString& buf)
2474{
2475 return NativeImageDumper::AppendToken(token, buf, NULL);
2476}
2477void NativeImageDumper::AppendToken(mdToken token, SString& buf,
2478 IMetaDataImport2 *pImport)
2479{
2480 IF_OPT(DISABLE_NAMES)
2481 {
2482 buf.Append( W("Disabled") );
2483 return;
2484 }
2485 switch (TypeFromToken(token))
2486 {
2487 case mdtTypeDef:
2488 buf.Append( W("TypeDef ") );
2489 break;
2490
2491 case mdtTypeRef:
2492 buf.Append( W("TypeRef ") );
2493 break;
2494
2495 case mdtTypeSpec:
2496 buf.Append( W("TypeRef ") );
2497 break;
2498
2499 case mdtFieldDef:
2500 buf.Append( W("FieldDef "));
2501 break;
2502
2503 case mdtMethodDef:
2504 buf.Append( W("MethodDef ") );
2505 break;
2506
2507 case mdtMemberRef:
2508 buf.Append( W("MemberRef ") );
2509 break;
2510
2511 case mdtAssemblyRef:
2512 buf.Append( W("AssemblyRef ") );
2513 break;
2514
2515 case mdtFile:
2516 buf.Append( W("File ") );
2517 break;
2518
2519 case mdtString:
2520 buf.Append( W("String ") );
2521 break;
2522
2523 case mdtSignature:
2524 buf.Append( W("Signature ") );
2525 break;
2526
2527 }
2528 if( RidFromToken(token) == mdTokenNil )
2529 buf.Append( W("Nil") );
2530 else
2531 AppendTokenName(token, buf, pImport);
2532}
2533
2534NativeImageDumper::Dependency *NativeImageDumper::OpenDependency(int index)
2535{
2536 CORCOMPILE_VERSION_INFO *info = m_decoder.GetNativeVersionInfo();
2537
2538 if (m_dependencies == NULL)
2539 {
2540 COUNT_T count;
2541 m_decoder.GetNativeDependencies(&count);
2542
2543 // Add one for self
2544 count++;
2545
2546 m_numDependencies = count;
2547 m_dependencies = new Dependency [count];
2548 ZeroMemory(m_dependencies, count * sizeof (Dependency));
2549 }
2550
2551 if (m_dependencies[index].entry == NULL)
2552 {
2553 CORCOMPILE_DEPENDENCY *entry;
2554
2555 if (index == 0)
2556 {
2557 // Make dummy entry for self
2558 entry = &m_self;
2559 m_self.dwAssemblyRef = TokenFromRid(1, mdtAssembly);
2560 m_self.dwAssemblyDef = TokenFromRid(1, mdtAssembly);
2561 m_self.signAssemblyDef = info->sourceAssembly;
2562 m_manifestImport->GetScopeProps(NULL, NULL, 0, &m_self.signNativeImage);
2563 m_dependencies[index].pLoadedAddress = dac_cast<TADDR>(m_baseAddress);
2564 m_dependencies[index].pPreferredBase =
2565 TO_TADDR(m_decoder.GetNativePreferredBase());
2566 m_dependencies[index].size = m_imageSize;
2567 m_dependencies[index].pImport = m_import;
2568 m_dependencies[index].pMetadataStartTarget =
2569 m_MetadataStartTarget;
2570 m_dependencies[index].pMetadataStartHost =
2571 m_MetadataStartHost;
2572 m_dependencies[index].MetadataSize = m_MetadataSize;
2573 m_dependencies[index].pModule =
2574 (TADDR)m_decoder.GetPersistedModuleImage();
2575 m_dependencies[index].fIsHardbound = TRUE;
2576 _ASSERTE( (m_dependencies[index].pModule
2577 > m_dependencies[index].pLoadedAddress)
2578 && (m_dependencies[index].pModule
2579 < m_dependencies[index].pLoadedAddress
2580 + m_dependencies[index].size) );
2581 // patch the Module vtable so that the DAC is able to instantiate it
2582 TADDR vtbl = DacGetTargetVtForHostVt(Module::VPtrHostVTable(), true);
2583 DacWriteAll( m_dependencies[index].pModule.GetAddr(), &vtbl, sizeof(vtbl), false );
2584 }
2585 else
2586 {
2587 COUNT_T numDeps;
2588 PTR_CORCOMPILE_DEPENDENCY deps(TO_TADDR(m_decoder.GetNativeDependencies(&numDeps)));
2589
2590 entry = deps + (index-1);
2591
2592 //load the dependency, get the pointer, and use the PEDecoder
2593 //to open the metadata.
2594
2595 TempBuffer buf;
2596 TADDR loadedBase;
2597 /* REVISIT_TODO Tue 11/22/2005
2598 * Is this the right name?
2599 */
2600 Dependency& dependency = m_dependencies[index];
2601 AppendTokenName(entry->dwAssemblyRef, buf, m_manifestImport, true);
2602 bool isHardBound = !!(entry->signNativeImage != INVALID_NGEN_SIGNATURE);
2603 SString mscorlibStr(SString::Literal, CoreLibName_W);
2604 bool isMscorlib = (0 == buf.Compare( mscorlibStr ));
2605 dependency.fIsHardbound = isHardBound;
2606 wcscpy_s(dependency.name, _countof(dependency.name),
2607 (const WCHAR*)buf);
2608 if( isHardBound )
2609 {
2610 IfFailThrow(m_librarySupport->LoadHardboundDependency((const WCHAR*)buf,
2611 entry->signNativeImage, &loadedBase));
2612
2613 dependency.pLoadedAddress = loadedBase;
2614 }
2615 else
2616 {
2617 ASSEMBLYMETADATA asmData = {0};
2618 const void * hashValue;
2619 ULONG hashLength, size, flags;
2620 IfFailThrow(m_manifestAssemblyImport->GetAssemblyRefProps(entry->dwAssemblyRef, &hashValue, &hashLength, bigBuffer, bigBufferSize, &size, &asmData, NULL, NULL, &flags));
2621
2622
2623 HRESULT hr =
2624 m_librarySupport->LoadSoftboundDependency((const WCHAR*)buf,
2625 (const BYTE*)&asmData, (const BYTE*)hashValue, hashLength,
2626 &loadedBase);
2627 if( FAILED(hr) )
2628 {
2629 TempBuffer pkt;
2630 if( hashLength > 0 )
2631 {
2632 appendByteArray(pkt, (BYTE*)hashValue, hashLength);
2633 }
2634 else
2635 {
2636 pkt.Set( W("<No Hash>") );
2637 }
2638 //try to continue without loading this softbound
2639 //dependency.
2640 m_display->ErrorPrintF( "WARNING Failed to load softbound dependency:\n\t%S,Version=%d.%d.0.0,PublicKeyToken=%S.\n\tAttempting to continue. May crash later in due to missing metadata\n",
2641 (const WCHAR *)buf, asmData.usMajorVersion,
2642 asmData.usMinorVersion, (const WCHAR *)pkt );
2643 m_dependencies[index].entry = entry;
2644 return &m_dependencies[index];
2645
2646 }
2647 //save this off to the side so OpenImport can find the metadata.
2648 m_dependencies[index].pLoadedAddress = loadedBase;
2649 }
2650 /* REVISIT_TODO Wed 11/23/2005
2651 * Refactor this with OpenMetadata from above.
2652 */
2653 //now load the metadata from the new image.
2654 PEDecoder decoder(dac_cast<PTR_VOID>(loadedBase));
2655 if( isHardBound )
2656 {
2657 dependency.pPreferredBase =
2658 TO_TADDR(decoder.GetNativePreferredBase());
2659 dependency.size = decoder.Has32BitNTHeaders() ?
2660 decoder.GetNTHeaders32()->OptionalHeader.SizeOfImage :
2661 decoder.GetNTHeaders64()->OptionalHeader.SizeOfImage;
2662 }
2663 ReleaseHolder<IMetaDataDispenserEx> pDispenser;
2664 IfFailThrow(MetaDataGetDispenser(CLSID_CorMetaDataDispenser,
2665 IID_IMetaDataDispenserEx,
2666 (void **) &pDispenser));
2667
2668 VARIANT opt;
2669 IfFailThrow(pDispenser->GetOption(MetaDataCheckDuplicatesFor,
2670 &opt));
2671 V_UI4(&opt) |= MDDupAssemblyRef | MDDupFile;
2672 IfFailThrow(pDispenser->SetOption(MetaDataCheckDuplicatesFor,
2673 &opt));
2674 if( decoder.HasNativeHeader() )
2675 {
2676 dependency.pModule =
2677 TO_TADDR(decoder.GetPersistedModuleImage());
2678 _ASSERTE( (PTR_TO_TADDR(dependency.pModule) > loadedBase)
2679 && (PTR_TO_TADDR(dependency.pModule) < loadedBase +
2680 decoder.GetSize()) );
2681 // patch the Module vtable so that the DAC is able to instantiate it
2682 TADDR vtbl = DacGetTargetVtForHostVt(Module::VPtrHostVTable(), true);
2683 DacWriteAll( m_dependencies[index].pModule.GetAddr(), &vtbl, sizeof(vtbl), false );
2684 }
2685 else
2686 {
2687 dependency.pModule = NULL;
2688 }
2689
2690 const void * data;
2691 COUNT_T size;
2692
2693 DACCOP_IGNORE(CastBetweenAddressSpaces,"nidump is in-proc and doesn't maintain a clean separation of address spaces (target and host are the same.");
2694 data = reinterpret_cast<void*>(dac_cast<TADDR>(decoder.GetMetadata(&size)));
2695
2696 dependency.pMetadataStartTarget = TO_TADDR(data);
2697 dependency.MetadataSize = size;
2698 data = PTR_READ(TO_TADDR(data), size);
2699 dependency.pMetadataStartHost = TO_TADDR(data);
2700 IfFailThrow(pDispenser->OpenScopeOnMemory(data, size,
2701 ofRead,
2702 IID_IMetaDataImport2,
2703 (IUnknown **) &dependency.pImport));
2704 dependency.fIsMscorlib = isMscorlib;
2705 }
2706
2707 m_dependencies[index].entry = entry;
2708
2709 }
2710
2711 return &m_dependencies[index];
2712}
2713
2714IMetaDataImport2* NativeImageDumper::TypeToString(PTR_CCOR_SIGNATURE &sig, SString& buf)
2715{
2716 return TypeToString(sig, buf, NULL);
2717}
2718#if 0
2719void NativeImageDumper::TypeToString(PTR_CCOR_SIGNATURE &sig,
2720 IMetaDataImport2 *pImport)
2721{
2722 CQuickBytes tmp;
2723
2724 if (pImport == NULL)
2725 pImport = m_import;
2726
2727 LPCWSTR type = PrettyPrintSig( sig, INT_MAX, W(""), &tmp, pImport );
2728 _ASSERTE(type);
2729 m_display->ErrorPrintF( "%S", type );
2730}
2731#endif
2732
2733IMetaDataImport2 * NativeImageDumper::TypeToString(PTR_CCOR_SIGNATURE &sig,
2734 SString& buf,
2735 IMetaDataImport2 *pImport,
2736 IMetaDataImport2 *pOrigImport /* =NULL */)
2737
2738{
2739 IF_OPT(DISABLE_NAMES)
2740 {
2741 buf.Append( W("Disabled") );
2742 return pImport;
2743 }
2744
2745 if (pImport == NULL)
2746 pImport = m_import;
2747 if (pOrigImport == NULL)
2748 pOrigImport = pImport;
2749
2750 IMetaDataImport2 * pRet = pImport;
2751#define TYPEINFO(enumName, classSpace, className, size, gcType, isArray, isPrim, isFloat, isModifier, isGenVar) \
2752 className,
2753 static const char *elementNames[] = {
2754#include "cortypeinfo.h"
2755 };
2756#undef TYPEINFO
2757
2758 CorElementType type = DacSigUncompressElementType(sig);
2759
2760 if (type == (CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG)
2761 {
2762 unsigned idx = DacSigUncompressData(sig);
2763 buf.AppendPrintf( W("module %d "), idx );
2764 //switch module
2765 const Import * import = OpenImport(idx);
2766 pImport = import->dependency->pImport;
2767
2768 //if there was a module switch, return the import for the new module.
2769 //This is useful for singatures, where the module index applies to
2770 //subsequent tokens.
2771 pRet = pImport;
2772
2773 type = DacSigUncompressElementType(sig);
2774 }
2775 if (type >= 0 && (size_t)type < _countof(elementNames)
2776 && elementNames[type] != NULL)
2777 {
2778 buf.AppendPrintf( "%s", elementNames[type] );
2779 }
2780 else switch ((DWORD)type)
2781 {
2782 case ELEMENT_TYPE_CANON_ZAPSIG:
2783 buf.Append( W("System.__Canon") );
2784 break;
2785
2786 case ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG:
2787 case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG:
2788 {
2789 buf.Append( W("native ") );
2790 TypeToString(sig, buf, pImport);
2791 }
2792 break;
2793
2794 case ELEMENT_TYPE_VALUETYPE:
2795 case ELEMENT_TYPE_CLASS:
2796 {
2797 if (type == ELEMENT_TYPE_VALUETYPE)
2798 buf.Append( W("struct ") );
2799
2800 mdToken token = DacSigUncompressToken(sig);
2801 AppendTokenName(token, buf, pImport);
2802 }
2803 break;
2804
2805 case ELEMENT_TYPE_SZARRAY:
2806 TypeToString(sig, buf, pImport);
2807 buf.Append( W("[]") );
2808 break;
2809
2810 case ELEMENT_TYPE_ARRAY:
2811 {
2812 TypeToString(sig, buf, pImport, pOrigImport);
2813 unsigned rank = DacSigUncompressData(sig);
2814 if (rank == 0)
2815 buf.Append( W("[??]") );
2816 else
2817 {
2818 size_t cbLowerBounds;
2819 if (!ClrSafeInt<size_t>::multiply(rank, 2*sizeof(int), cbLowerBounds/* passed by ref */))
2820 ThrowHR(COR_E_OVERFLOW);
2821 int* lowerBounds = (int*) _alloca(cbLowerBounds);
2822 int* sizes = &lowerBounds[rank];
2823 memset(lowerBounds, 0, sizeof(int)*2*rank);
2824
2825 unsigned numSizes = DacSigUncompressData(sig);
2826 _ASSERTE(numSizes <= rank);
2827 unsigned int i;
2828 for(i =0; i < numSizes; i++)
2829 sizes[i] = DacSigUncompressData(sig);
2830
2831 unsigned numLowBounds = DacSigUncompressData(sig);
2832 _ASSERTE(numLowBounds <= rank);
2833 for(i = 0; i < numLowBounds; i++)
2834 lowerBounds[i] = DacSigUncompressData(sig);
2835
2836 buf.Append(W("["));
2837 for(i = 0; i < rank; i++)
2838 {
2839 if (sizes[i] != 0 && lowerBounds[i] != 0)
2840 {
2841 if (lowerBounds[i] == 0)
2842 buf.AppendPrintf( W("%s"), sizes[i] );
2843 else
2844 {
2845 buf.AppendPrintf( W("%d ..."), lowerBounds[i] );
2846 if (sizes[i] != 0)
2847 buf.AppendPrintf( W("%d"),
2848 lowerBounds[i] + sizes[i]
2849 + 1 );
2850 }
2851 }
2852 if (i < rank-1)
2853 buf.Append( W(",") );
2854 }
2855 buf.Append( W("]") );
2856 }
2857 }
2858 break;
2859
2860 case ELEMENT_TYPE_MVAR:
2861 buf.Append( W("!") );
2862 // fall through
2863 case ELEMENT_TYPE_VAR:
2864 buf.AppendPrintf( W("!%d"), DacSigUncompressData(sig));
2865 break;
2866
2867 case ELEMENT_TYPE_VAR_ZAPSIG:
2868 {
2869 buf.Append( W("var ") );
2870
2871 mdToken token = TokenFromRid(DacSigUncompressData(sig), mdtGenericParam);
2872 AppendTokenName(token, buf, pImport);
2873 }
2874 break;
2875
2876 case ELEMENT_TYPE_GENERICINST:
2877 {
2878 TypeToString(sig, buf, pImport, pOrigImport);
2879 unsigned ntypars = DacSigUncompressData(sig);
2880 buf.Append( W("<") );
2881 for (unsigned i = 0; i < ntypars; i++)
2882 {
2883 if (i > 0)
2884 buf.Append( W(",") );
2885 // switch pImport back to our original Metadata importer
2886 TypeToString(sig, buf, pOrigImport, pOrigImport);
2887 }
2888 buf.Append( W(">") );
2889 }
2890 break;
2891
2892 case ELEMENT_TYPE_FNPTR:
2893 buf.Append( W("(fnptr)") );
2894 break;
2895
2896 // Modifiers or depedant types
2897 case ELEMENT_TYPE_PINNED:
2898 TypeToString(sig, buf, pImport, pOrigImport);
2899 buf.Append( W(" pinned") );
2900 break;
2901
2902 case ELEMENT_TYPE_PTR:
2903 TypeToString(sig, buf, pImport, pOrigImport);
2904 buf.Append( W("*") );
2905 break;
2906
2907 case ELEMENT_TYPE_BYREF:
2908 TypeToString(sig, buf, pImport, pOrigImport);
2909 buf.Append( W("&") );
2910 break;
2911
2912 case ELEMENT_TYPE_SENTINEL:
2913 case ELEMENT_TYPE_END:
2914 default:
2915 _ASSERTE(!"Unknown Type");
2916 IfFailThrow(E_FAIL);
2917 break;
2918 }
2919 return pRet;
2920}
2921
2922void NativeImageDumper::DumpMethods(PTR_Module module)
2923{
2924 COUNT_T hotCodeSize;
2925 PCODE hotCode = m_decoder.GetNativeHotCode(&hotCodeSize);
2926
2927
2928 COUNT_T codeSize;
2929 PCODE code = m_decoder.GetNativeCode(&codeSize);
2930
2931 COUNT_T coldCodeSize;
2932 PCODE coldCode = m_decoder.GetNativeColdCode(&coldCodeSize);
2933
2934 DisplayStartCategory( "Code", METHODS );
2935 DisplayWriteElementAddress( "HotCode", DataPtrToDisplay(hotCode),
2936 hotCodeSize, METHODS );
2937
2938 DisplayWriteElementAddress( "UnprofiledCode",
2939 DataPtrToDisplay(code),
2940 codeSize, METHODS );
2941 DisplayWriteElementAddress( "ColdCode",
2942 DataPtrToDisplay(coldCode),
2943 coldCodeSize, METHODS );
2944
2945 PTR_CORCOMPILE_CODE_MANAGER_ENTRY codeEntry(m_decoder.GetNativeCodeManagerTable());
2946
2947 DisplayWriteElementAddress( "ROData",
2948 RvaToDisplay(codeEntry->ROData.VirtualAddress),
2949 codeEntry->ROData.Size, METHODS );
2950
2951 DisplayWriteElementAddress( "HotCommonCode",
2952 DataPtrToDisplay(hotCode),
2953 codeEntry->HotIBCMethodOffset, METHODS );
2954
2955 DisplayWriteElementAddress( "HotIBCMethodCode",
2956 DataPtrToDisplay(hotCode
2957 + codeEntry->HotIBCMethodOffset),
2958 codeEntry->HotGenericsMethodOffset
2959 - codeEntry->HotIBCMethodOffset,
2960 METHODS );
2961
2962 DisplayWriteElementAddress( "HotGenericsMethodCode",
2963 DataPtrToDisplay(hotCode
2964 + codeEntry->HotGenericsMethodOffset),
2965 hotCodeSize - codeEntry->HotGenericsMethodOffset,
2966 METHODS );
2967
2968 DisplayWriteElementAddress( "ColdIBCMethodCode",
2969 DataPtrToDisplay(coldCode),
2970 codeEntry->ColdUntrainedMethodOffset,
2971 METHODS );
2972
2973 MethodIterator mi(module, &m_decoder);
2974
2975 DisplayStartArray( "Methods", NULL, METHODS );
2976
2977 while( mi.Next() )
2978 {
2979 DumpCompleteMethod( module, mi );
2980 }
2981
2982 DisplayEndArray( "Total Methods", METHODS ); //Methods
2983
2984 /* REVISIT_TODO Wed 12/14/2005
2985 * I have this coverage read in here because there is some other data between the
2986 * methods in debug builds. For now just whack the whole text section. Go
2987 * back later and check out that I really got everything.
2988 */
2989 CoverageRead( hotCode, hotCodeSize );
2990 CoverageRead( coldCode, coldCodeSize );
2991#ifdef USE_CORCOMPILE_HEADER
2992 CoverageRead( hotCodeTable, hotCodeTableSize );
2993 CoverageRead( coldCodeTable, coldCodeTableSize );
2994#endif
2995
2996 DisplayEndCategory( METHODS ); //Code
2997
2998 //m_display->StartCategory( "Methods" );
2999}
3000
3001static SString g_holdStringOutData;
3002
3003static void stringOut( const char* fmt, ... )
3004{
3005 va_list args;
3006 va_start(args, fmt);
3007 g_holdStringOutData.AppendVPrintf(fmt, args);
3008 va_end(args);
3009}
3010
3011static void nullStringOut( const char * fmt, ... ) { }
3012
3013const NativeImageDumper::EnumMnemonics s_CorExceptionFlags[] =
3014{
3015#define CEF_ENTRY(f,v) NativeImageDumper::EnumMnemonics(f, v)
3016 CEF_ENTRY(COR_ILEXCEPTION_CLAUSE_NONE, W("none")),
3017 CEF_ENTRY(COR_ILEXCEPTION_CLAUSE_FILTER, W("filter")),
3018 CEF_ENTRY(COR_ILEXCEPTION_CLAUSE_FINALLY, W("finally")),
3019 CEF_ENTRY(COR_ILEXCEPTION_CLAUSE_FAULT, W("fault")),
3020 CEF_ENTRY(COR_ILEXCEPTION_CLAUSE_DUPLICATED, W("duplicated")),
3021#undef CEF_ENTRY
3022};
3023
3024void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi)
3025{
3026 PTR_MethodDesc md = mi.GetMethodDesc();
3027
3028#ifdef WIN64EXCEPTIONS
3029 PTR_RUNTIME_FUNCTION pRuntimeFunction = mi.GetRuntimeFunction();
3030#endif
3031
3032 //Read the GCInfo to get the total method size.
3033 unsigned methodSize = 0;
3034 unsigned gcInfoSize = UINT_MAX;
3035
3036 //parse GCInfo for size information.
3037 GCInfoToken gcInfoToken = mi.GetGCInfoToken();
3038 PTR_CBYTE gcInfo = dac_cast<PTR_CBYTE>(gcInfoToken.Info);
3039
3040 void (* stringOutFn)(const char *, ...);
3041 IF_OPT(GC_INFO)
3042 {
3043 stringOutFn = stringOut;
3044 }
3045 else
3046 {
3047 stringOutFn = nullStringOut;
3048 }
3049 if (gcInfo != NULL)
3050 {
3051 PTR_CBYTE curGCInfoPtr = gcInfo;
3052 g_holdStringOutData.Clear();
3053 GCDump gcDump(gcInfoToken.Version);
3054 gcDump.gcPrintf = stringOutFn;
3055#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
3056 GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_CODE_LENGTH);
3057 methodSize = gcInfoDecoder.GetCodeLength();
3058#endif
3059
3060 //dump the data to a string first so we can get the gcinfo size.
3061#ifdef _TARGET_X86_
3062 InfoHdr hdr;
3063 stringOutFn( "method info Block:\n" );
3064 curGCInfoPtr += gcDump.DumpInfoHdr(curGCInfoPtr, &hdr, &methodSize, 0);
3065 stringOutFn( "\n" );
3066#endif
3067
3068 IF_OPT(METHODS)
3069 {
3070#ifdef _TARGET_X86_
3071 stringOutFn( "PointerTable:\n" );
3072 curGCInfoPtr += gcDump.DumpGCTable( curGCInfoPtr,
3073 hdr,
3074 methodSize, 0);
3075 gcInfoSize = curGCInfoPtr - gcInfo;
3076#elif defined(USE_GC_INFO_DECODER)
3077 stringOutFn( "PointerTable:\n" );
3078 curGCInfoPtr += gcDump.DumpGCTable( curGCInfoPtr,
3079 methodSize, 0);
3080 gcInfoSize = (unsigned)(curGCInfoPtr - gcInfo);
3081#endif
3082 }
3083
3084 //data is output below.
3085 }
3086
3087 TADDR hotCodePtr = mi.GetMethodStartAddress();
3088 TADDR coldCodePtr = mi.GetMethodColdStartAddress();
3089
3090 size_t hotCodeSize = methodSize;
3091 size_t coldCodeSize = 0;
3092
3093 if (coldCodePtr != NULL)
3094 {
3095 hotCodeSize = mi.GetHotCodeSize();
3096 coldCodeSize = methodSize - hotCodeSize;
3097 }
3098
3099 _ASSERTE(!CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(md)));
3100 const Dependency* mdDep = GetDependencyFromMD(md);
3101 TempBuffer buffer;
3102 _ASSERTE(mdDep->pImport);
3103 MethodDescToString(md, buffer);
3104
3105 DisplayStartElement( "Method", METHODS );
3106 DisplayWriteElementStringW( "Name", (const WCHAR *)buffer, METHODS );
3107
3108 /* REVISIT_TODO Mon 10/24/2005
3109 * Do I have to annotate this?
3110 */
3111 DisplayWriteElementPointer("m_methodDesc",
3112 DPtrToPreferredAddr(md),
3113 METHODS);
3114
3115 DisplayStartStructure( "m_gcInfo",
3116 DPtrToPreferredAddr(gcInfo),
3117 gcInfoSize,
3118 METHODS );
3119
3120 DisplayStartTextElement( "Contents", GC_INFO );
3121 DisplayWriteXmlTextBlock( ("%S", (const WCHAR *)g_holdStringOutData), GC_INFO );
3122 DisplayEndTextElement( GC_INFO ); //Contents
3123
3124 DisplayEndStructure( METHODS ); //GCInfo
3125
3126 PTR_CORCOMPILE_EXCEPTION_LOOKUP_TABLE pExceptionInfoTable (PTR_TO_TADDR(module->GetNGenLayoutInfo()->m_ExceptionInfoLookupTable.StartAddress()));
3127 if (pExceptionInfoTable)
3128 {
3129 COUNT_T numLookupEntries = (COUNT_T) (module->GetNGenLayoutInfo()->m_ExceptionInfoLookupTable.Size() / sizeof(CORCOMPILE_EXCEPTION_LOOKUP_TABLE_ENTRY));
3130 DWORD methodStartRVA = m_decoder.GetDataRva(TO_TADDR(hotCodePtr));
3131
3132 COUNT_T ehInfoSize = 0;
3133 DWORD exceptionInfoRVA = NativeExceptionInfoLookupTable::LookupExceptionInfoRVAForMethod(pExceptionInfoTable,
3134 numLookupEntries,
3135 methodStartRVA,
3136 &ehInfoSize);
3137
3138 if( exceptionInfoRVA != 0 )
3139 {
3140 PTR_CORCOMPILE_EXCEPTION_CLAUSE pExceptionInfoArray = dac_cast<PTR_CORCOMPILE_EXCEPTION_CLAUSE>(PTR_TO_TADDR(m_decoder.GetBase()) + exceptionInfoRVA);
3141 COUNT_T ehCount = ehInfoSize / sizeof(CORCOMPILE_EXCEPTION_CLAUSE);
3142 _ASSERTE(ehCount > 0);
3143 DisplayStartArray("EHClauses", NULL, METHODS );
3144 for( unsigned i = 0; i < ehCount; ++i )
3145 {
3146 PTR_CORCOMPILE_EXCEPTION_CLAUSE host = pExceptionInfoArray + i;
3147
3148 DisplayStartStructure( "Clause", DPtrToPreferredAddr(host), sizeof(PTR_CORCOMPILE_EXCEPTION_CLAUSE), METHODS);
3149 DisplayWriteFieldEnumerated( Flags, host->Flags,
3150 EE_ILEXCEPTION_CLAUSE,
3151 s_CorExceptionFlags, W(", "),
3152 METHODS );
3153 DisplayWriteFieldUInt( TryStartPC, host->TryStartPC,
3154 EE_ILEXCEPTION_CLAUSE, METHODS );
3155 DisplayWriteFieldUInt( TryEndPC, host->TryEndPC,
3156 EE_ILEXCEPTION_CLAUSE, METHODS );
3157 DisplayWriteFieldUInt( HandlerStartPC,
3158 host->HandlerStartPC,
3159 EE_ILEXCEPTION_CLAUSE, METHODS );
3160 DisplayWriteFieldUInt( HandlerEndPC,
3161 host->HandlerEndPC,
3162 EE_ILEXCEPTION_CLAUSE, METHODS );
3163 if( host->Flags & COR_ILEXCEPTION_CLAUSE_FILTER )
3164 {
3165 DisplayWriteFieldUInt( FilterOffset, host->FilterOffset,
3166 EE_ILEXCEPTION_CLAUSE, METHODS );
3167 }
3168 else if( !(host->Flags & (COR_ILEXCEPTION_CLAUSE_FAULT | COR_ILEXCEPTION_CLAUSE_FINALLY)) )
3169 {
3170 WriteFieldMDTokenImport( ClassToken, host->ClassToken,
3171 EE_ILEXCEPTION_CLAUSE, METHODS,
3172 mdDep->pImport );
3173 }
3174 DisplayEndStructure( METHODS ); //Clause
3175 }
3176 DisplayEndArray("Total EHClauses", METHODS ); // Clauses
3177 }
3178 }
3179
3180 TADDR fixupList = md->GetFixupList();
3181 if (fixupList != NULL)
3182 {
3183 DisplayStartArray( "Fixups", NULL, METHODS );
3184 DumpMethodFixups(module, fixupList);
3185 DisplayEndArray(NULL, METHODS); //Fixups
3186 }
3187
3188 DisplayStartStructure( "Code", DataPtrToDisplay(hotCodePtr), hotCodeSize,
3189 METHODS );
3190
3191 IF_OPT(DISASSEMBLE_CODE)
3192 {
3193 // Disassemble hot code. Read the code into the host process.
3194 /* REVISIT_TODO Mon 10/24/2005
3195 * Is this align up right?
3196 */
3197 BYTE * codeStartHost =
3198 reinterpret_cast<BYTE*>(PTR_READ(hotCodePtr,
3199 (ULONG32)ALIGN_UP(hotCodeSize,
3200 CODE_SIZE_ALIGN)));
3201 DisassembleMethod( codeStartHost, hotCodeSize );
3202 }
3203 else
3204 {
3205 CoverageRead(hotCodePtr,
3206 (ULONG32)ALIGN_UP(hotCodeSize, CODE_SIZE_ALIGN));
3207 }
3208
3209 DisplayEndStructure(METHODS); //HotCode
3210
3211 if( coldCodePtr != NULL )
3212 {
3213 DisplayStartStructure( "ColdCode", DataPtrToDisplay(coldCodePtr),
3214 coldCodeSize, METHODS );
3215 IF_OPT(DISASSEMBLE_CODE)
3216 {
3217 // Disassemble cold code. Read the code into the host process.
3218 BYTE * codeStartHost =
3219 reinterpret_cast<BYTE*>(PTR_READ(coldCodePtr,
3220 (ULONG32)ALIGN_UP(coldCodeSize,
3221 CODE_SIZE_ALIGN)));
3222 DisassembleMethod( codeStartHost, coldCodeSize );
3223 }
3224 else
3225 {
3226 CoverageRead(coldCodePtr,
3227 (ULONG32)ALIGN_UP(coldCodeSize, CODE_SIZE_ALIGN));
3228
3229 }
3230 DisplayEndStructure( METHODS ); //ColdCode
3231 }
3232 DisplayEndElement( METHODS ); //Method
3233}
3234#undef IDC_SWITCH
3235
3236
3237
3238void NativeImageDumper::DisassembleMethod(BYTE *code, SIZE_T size)
3239{
3240 _ASSERTE(CHECK_OPT(DISASSEMBLE_CODE));
3241
3242 m_display->StartTextElement( "NativeCode" );
3243
3244#ifdef FEATURE_MSDIS
3245
3246 BYTE *codeStart = code;
3247
3248 /* XXX Wed 8/22/2007
3249 * The way I compute code size includes the switch tables at the end of the hot and/or cold section.
3250 * When the disassembler gets there, it has a tendency to crash as it runs off the end of mapped
3251 * memory. In order to properly compute this I need to look at the UnwindData (which is a
3252 * kernel32!RUNTIME_FUNCTION structure that gives the address range for the code. However, I also need
3253 * to chase through the list of funclets to make sure I disassemble everything. Instead of doing that,
3254 * I'll just trap the AV.
3255 */
3256 EX_TRY
3257 {
3258 while (code < (codeStart + size))
3259 {
3260 const size_t count = m_dis->CbDisassemble(0, code, size);
3261
3262 if (count == 0)
3263 {
3264 m_display->WriteXmlText( "%04x\tUnknown instruction (%02x)\n", code-codeStart, *code);
3265 code++;
3266 continue;
3267 }
3268
3269 /* XXX Fri 09/16/2005
3270 * PTR_HOST_TO_TADDR doesn't work on interior pointers.
3271 */
3272 m_currentAddress = m_decoder.GetDataRva(PTR_HOST_TO_TADDR(codeStart)
3273 + (code - codeStart))
3274 + PTR_TO_TADDR(m_decoder.GetBase());
3275
3276 const size_t cinstr = m_dis->Cinstruction();
3277 size_t inum = 0;
3278 while (true)
3279 {
3280 WCHAR szOpcode[4096];
3281 size_t len = m_dis->CchFormatInstr(szOpcode, _countof(szOpcode));
3282 _ASSERTE(szOpcode[len-1] == 0);
3283 m_display->WriteXmlText( "%04x\t%S\n", (code-codeStart) + (inum * 4), szOpcode );
3284
3285NEXT_INSTR:
3286 if (++inum >= cinstr)
3287 break;
3288
3289 _ASSERTE((inum * 4) < count); // IA64 has 3 instructions per bundle commonly
3290 // referenced as offset 0, 4, and 8
3291 if (!m_dis->FSelectInstruction(inum))
3292 {
3293 m_display->WriteXmlText( "%04x\tUnknown instruction within bundle\n", (code-codeStart) + (inum * 4));
3294 goto NEXT_INSTR;
3295 }
3296 }
3297
3298 code += count;
3299 }
3300 }
3301 EX_CATCH
3302 {
3303
3304 }
3305 EX_END_CATCH(SwallowAllExceptions);
3306
3307#else // FEATURE_MSDIS
3308
3309 m_display->WriteXmlText( "Disassembly not supported\n" );
3310
3311#endif // FEATURE_MSDIS
3312
3313 m_display->EndTextElement(); //NativeCode
3314}
3315
3316SIZE_T NativeImageDumper::TranslateAddressCallback(IXCLRDisassemblySupport *dis,
3317 CLRDATA_ADDRESS addr,
3318 __out_ecount(nameSize) WCHAR *name, SIZE_T nameSize,
3319 DWORDLONG *offset)
3320{
3321 NativeImageDumper *pThis = (NativeImageDumper *) dis->PvClient();
3322
3323 SIZE_T ret = pThis->TranslateSymbol(dis,
3324 addr+(SIZE_T)pThis->m_currentAddress,
3325 name, nameSize, offset);
3326#ifdef _DEBUG
3327 if( ret == 0 )
3328 {
3329 _snwprintf_s(name, nameSize, _TRUNCATE, W("@TRANSLATED ADDRESS@ %p"),
3330 (TADDR)(addr + (SIZE_T)pThis->m_currentAddress) );
3331 ret = wcslen(name);
3332 *offset = -1;
3333 }
3334#endif
3335 return ret;
3336}
3337SIZE_T NativeImageDumper::TranslateFixupCallback(IXCLRDisassemblySupport *dis,
3338 CLRDATA_ADDRESS addr,
3339 SIZE_T size, __out_ecount(nameSize) WCHAR *name,
3340 SIZE_T nameSize,
3341 DWORDLONG *offset)
3342{
3343 NativeImageDumper *pThis = (NativeImageDumper *) dis->PvClient();
3344 if( !dis->TargetIsAddress() )
3345 return 0;
3346
3347 TADDR taddr = TO_TADDR(pThis->m_currentAddress) + (TADDR)addr;
3348 SSIZE_T targetOffset;
3349 switch (size)
3350 {
3351 case sizeof(void*):
3352 targetOffset = *PTR_SIZE_T(taddr);
3353 break;
3354#ifdef _WIN64
3355 case sizeof(INT32):
3356 targetOffset = *PTR_INT32(taddr);
3357 break;
3358#endif
3359 case sizeof(short):
3360 targetOffset = *(short*)(WORD*)PTR_WORD(taddr);
3361 break;
3362 case sizeof(signed char):
3363 targetOffset = *PTR_SBYTE(taddr);
3364 break;
3365 default:
3366 return 0;
3367 }
3368
3369 CLRDATA_ADDRESS address = targetOffset + TO_TADDR(pThis->m_currentAddress) + addr + size;
3370
3371 SIZE_T ret = pThis->TranslateSymbol(dis, address, name, nameSize, offset);
3372 if( ret == 0 )
3373 {
3374 _snwprintf_s(name, nameSize, _TRUNCATE, W("@TRANSLATED FIXUP@ %p"), (TADDR)address);
3375 ret = wcslen(name);
3376 *offset = -1;
3377 }
3378 return ret;
3379}
3380
3381size_t NativeImageDumper::TranslateSymbol(IXCLRDisassemblySupport *dis,
3382 CLRDATA_ADDRESS addr, __out_ecount(nameSize) WCHAR *name,
3383 SIZE_T nameSize, DWORDLONG *offset)
3384{
3385#ifdef FEATURE_READYTORUN
3386 if (m_pReadyToRunHeader != NULL)
3387 return 0;
3388#endif
3389
3390 if (isInRange((TADDR)addr))
3391 {
3392 COUNT_T rva = (COUNT_T)(addr - PTR_TO_TADDR(m_decoder.GetBase()));
3393
3394 COUNT_T helperTableSize;
3395 void *helperTable = m_decoder.GetNativeHelperTable(&helperTableSize);
3396
3397 if (rva >= m_decoder.GetDataRva(TO_TADDR(helperTable))
3398 && rva < (m_decoder.GetDataRva(TO_TADDR(helperTable))
3399 +helperTableSize))
3400 {
3401 int helperIndex = (USHORT)*PTR_DWORD(TO_TADDR(addr));
3402// _ASSERTE(helperIndex < CORINFO_HELP_COUNT);
3403 // because of literal blocks we might have bogus values
3404 if (helperIndex < CORINFO_HELP_COUNT)
3405 _snwprintf_s(name, nameSize, _TRUNCATE, W("<%S>"), g_helperNames[helperIndex]);
3406 else
3407 _snwprintf_s(name, nameSize, _TRUNCATE, W("Illegal HelperIndex<%04X>"), helperIndex);
3408 *offset = 0;
3409 return wcslen(name);
3410 }
3411
3412 PTR_Module module = (TADDR)m_decoder.GetPersistedModuleImage();
3413 PTR_NGenLayoutInfo pNgenLayout = module->GetNGenLayoutInfo();
3414
3415 for (int iRange = 0; iRange < 2; iRange++)
3416 {
3417 if (pNgenLayout->m_CodeSections[iRange].IsInRange((TADDR)addr))
3418 {
3419 int MethodIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod(rva, pNgenLayout->m_pRuntimeFunctions[iRange], 0, pNgenLayout->m_nRuntimeFunctions[iRange] - 1);
3420 if (MethodIndex >= 0)
3421 {
3422#ifdef WIN64EXCEPTIONS
3423 while (pNgenLayout->m_MethodDescs[iRange][MethodIndex] == 0)
3424 MethodIndex--;
3425#endif
3426
3427 PTR_RUNTIME_FUNCTION pRuntimeFunction = pNgenLayout->m_pRuntimeFunctions[iRange] + MethodIndex;
3428
3429 PTR_MethodDesc pMD = NativeUnwindInfoLookupTable::GetMethodDesc(pNgenLayout, pRuntimeFunction, PTR_TO_TADDR(m_decoder.GetBase()));
3430 TempBuffer buf;
3431 MethodDescToString( pMD, buf );
3432 _snwprintf_s(name, nameSize, _TRUNCATE, W("%s "), (const WCHAR *)buf );
3433 *offset = rva - RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction);
3434 return wcslen(name);
3435 }
3436 }
3437 }
3438
3439 if (pNgenLayout->m_CodeSections[2].IsInRange((TADDR)addr))
3440 {
3441 int ColdMethodIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod(rva, pNgenLayout->m_pRuntimeFunctions[2], 0, pNgenLayout->m_nRuntimeFunctions[2] - 1);
3442 if (ColdMethodIndex >= 0)
3443 {
3444 PTR_RUNTIME_FUNCTION pRuntimeFunction;
3445
3446 PTR_CORCOMPILE_COLD_METHOD_ENTRY pColdCodeMap = pNgenLayout->m_ColdCodeMap;
3447
3448#ifdef WIN64EXCEPTIONS
3449 while (pColdCodeMap[ColdMethodIndex].mainFunctionEntryRVA == 0)
3450 ColdMethodIndex--;
3451
3452 pRuntimeFunction = dac_cast<PTR_RUNTIME_FUNCTION>(PTR_TO_TADDR(m_decoder.GetBase()) + pColdCodeMap[ColdMethodIndex].mainFunctionEntryRVA);
3453#else
3454 DWORD ColdUnwindData = pNgenLayout->m_pRuntimeFunctions[2][ColdMethodIndex].UnwindData;
3455 _ASSERTE((ColdUnwindData & RUNTIME_FUNCTION_INDIRECT) != 0);
3456 pRuntimeFunction = dac_cast<PTR_RUNTIME_FUNCTION>(PTR_TO_TADDR(m_decoder.GetBase()) + (ColdUnwindData & ~RUNTIME_FUNCTION_INDIRECT));
3457#endif
3458
3459 PTR_MethodDesc pMD = NativeUnwindInfoLookupTable::GetMethodDesc(pNgenLayout, pRuntimeFunction, PTR_TO_TADDR(m_decoder.GetBase()));
3460 TempBuffer buf;
3461 MethodDescToString( pMD, buf );
3462 _snwprintf_s(name, nameSize, _TRUNCATE, W("%s (cold region)"), (const WCHAR *)buf );
3463 *offset = rva - RUNTIME_FUNCTION__BeginAddress(&pNgenLayout->m_pRuntimeFunctions[2][ColdMethodIndex]);
3464 return wcslen(name);
3465 }
3466 }
3467
3468 //Dumping precodes by name requires some information from the module (the precode ranges).
3469 IF_OPT_OR(PRECODES, MODULE)
3470 {
3471 TempBuffer precodeBuf;
3472 //maybe it is a precode
3473 PTR_Precode maybePrecode((TADDR)addr);
3474 const char * precodeName = NULL;
3475 if (isPrecode((TADDR)addr))
3476 {
3477 switch(maybePrecode->GetType())
3478 {
3479 case PRECODE_INVALID:
3480 precodeName = "InvalidPrecode"; break;
3481 case PRECODE_STUB:
3482 precodeName = "StubPrecode"; break;
3483#ifdef HAS_NDIRECT_IMPORT_PRECODE
3484 case PRECODE_NDIRECT_IMPORT:
3485 precodeName = "NDirectImportPrecode"; break;
3486#endif // HAS_NDIRECT_IMPORT_PRECODE
3487#ifdef HAS_FIXUP_PRECODE
3488 case PRECODE_FIXUP:
3489 precodeName = "FixupPrecode"; break;
3490#endif // HAS_FIXUP_PRECODE
3491#ifdef HAS_THISPTR_RETBUF_PRECODE
3492 case PRECODE_THISPTR_RETBUF:
3493 precodeName = "ThisPtrRetBufPrecode"; break;
3494#endif // HAS_THISPTR_RETBUF_PRECODE
3495 }
3496
3497 if( precodeName )
3498 {
3499 //hot or cold?
3500 precodeBuf.AppendPrintf( W("%S (0x%p)"), precodeName, addr );
3501 }
3502 //get MethodDesc from precode and dump the target
3503 PTR_MethodDesc precodeMD(maybePrecode->GetMethodDesc());
3504 precodeBuf.Append( W(" for ") );
3505 MethodDescToString(precodeMD, precodeBuf);
3506
3507 _snwprintf_s(name, nameSize, _TRUNCATE, W("%s"), (const WCHAR *)precodeBuf);
3508
3509 *offset = 0;
3510 return wcslen(name);
3511 }
3512 }
3513
3514 PTR_CORCOMPILE_IMPORT_SECTION pImportSection = m_decoder.GetNativeImportSectionForRVA(rva);
3515 if (pImportSection != NULL)
3516 {
3517 const char * wbRangeName = NULL;
3518 switch (pImportSection->Type)
3519 {
3520 case CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD:
3521 wbRangeName = "ExternalMethod";
3522 break;
3523
3524#if 0
3525 case CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD:
3526 wbRangeName = "VirtualMethod";
3527 break;
3528
3529 case CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH:
3530 wbRangeName = "StubDispatch";
3531 break;
3532#endif
3533
3534 // This method is only ever called for targets of direct calls right now and so the only
3535 // import that can meaninfully show up here is external method thunk.
3536 default:
3537 return 0;
3538 }
3539
3540 TempBuffer fixupThunkBuf;
3541 fixupThunkBuf.AppendPrintf( W("%S (0x%p) for "), wbRangeName, addr );
3542 FixupThunkToString(pImportSection, (TADDR)addr, fixupThunkBuf);
3543
3544 _snwprintf_s(name, nameSize, _TRUNCATE, W("%s"), (const WCHAR *)fixupThunkBuf);
3545
3546 *offset = 0;
3547 return wcslen(name);
3548 }
3549 }
3550 else if( g_dacImpl->GetJitHelperFunctionName(addr,
3551 _countof(bigByteBuffer),
3552 (char*)bigByteBuffer,
3553 NULL ) == S_OK )
3554 {
3555 *offset = 0;
3556 _snwprintf_s( name, nameSize, _TRUNCATE, W("%S"), bigByteBuffer );
3557 return wcslen(name);
3558 }
3559 else
3560 {
3561 //check mscorwks
3562 if( m_mscorwksBase <= addr &&
3563 addr < (m_mscorwksBase + m_mscorwksSize) )
3564 {
3565 *offset = addr - m_mscorwksBase;
3566 _snwprintf_s( name, nameSize, _TRUNCATE, W("clr") );
3567 return wcslen(name);
3568 }
3569 for( COUNT_T i = 0; i < m_numDependencies; ++i )
3570 {
3571 const Dependency& dep = m_dependencies[i];
3572 if( dep.pLoadedAddress <= addr &&
3573 addr < (dep.pLoadedAddress + dep.size) )
3574 {
3575 *offset = addr - dep.pLoadedAddress;
3576 _snwprintf_s( name, nameSize, _TRUNCATE, W("%s.ni"), dep.name );
3577 return wcslen(name);
3578 }
3579 }
3580 }
3581
3582 return 0;
3583}
3584
3585BOOL NativeImageDumper::HandleFixupForMethodDump(PTR_CORCOMPILE_IMPORT_SECTION pSection, SIZE_T fixupIndex, SIZE_T *fixupCell)
3586{
3587 PTR_SIZE_T fixupPtr(TO_TADDR(fixupCell));
3588 m_display->StartElement( "Fixup" );
3589 m_display->WriteElementPointer( "Address",
3590 DataPtrToDisplay( TO_TADDR(fixupCell) ) );
3591 m_display->WriteElementUInt( "TaggedValue", (DWORD)*fixupPtr );
3592 WriteElementsFixupBlob(pSection, *fixupPtr);
3593 m_display->EndElement();
3594
3595 return TRUE;
3596}
3597
3598void NativeImageDumper::DumpMethodFixups(PTR_Module module,
3599 TADDR fixupList)
3600{
3601 _ASSERTE( CHECK_OPT(METHODS) );
3602
3603 COUNT_T nImportSections;
3604 PTR_CORCOMPILE_IMPORT_SECTION pImportSections = m_decoder.GetNativeImportSections(&nImportSections);
3605
3606 //create the first element outside of the callback. The callback creates
3607 //subsequent elements.
3608 module->FixupDelayListAux( fixupList, this,
3609 &NativeImageDumper::HandleFixupForMethodDump,
3610 pImportSections, nImportSections,
3611 &m_decoder );
3612}
3613
3614IMAGE_SECTION_HEADER * NativeImageDumper::FindSection( char const * name )
3615{
3616 COUNT_T numberOfSections = m_decoder.GetNumberOfSections();
3617 PTR_IMAGE_SECTION_HEADER curSection( m_decoder.FindFirstSection() );
3618
3619 for ( ; numberOfSections > 0; --numberOfSections, ++curSection )
3620 {
3621 if ( ! strncmp( reinterpret_cast< char * >( curSection->Name ), name, 8 ) )
3622 break;
3623 }
3624
3625 if ( ! numberOfSections )
3626 return NULL;
3627
3628 return curSection;
3629}
3630
3631NativeImageDumper::EnumMnemonics NativeImageDumper::s_ModulePersistedFlags[] =
3632{
3633#define MPF_ENTRY(f) NativeImageDumper::EnumMnemonics(Module::f, W(#f))
3634 MPF_ENTRY(COMPUTED_GLOBAL_CLASS),
3635
3636 MPF_ENTRY(COMPUTED_STRING_INTERNING),
3637 MPF_ENTRY(NO_STRING_INTERNING),
3638
3639 MPF_ENTRY(COMPUTED_WRAP_EXCEPTIONS),
3640 MPF_ENTRY(WRAP_EXCEPTIONS),
3641
3642 MPF_ENTRY(COMPUTED_RELIABILITY_CONTRACT),
3643
3644 MPF_ENTRY(COLLECTIBLE_MODULE),
3645 MPF_ENTRY(COMPUTED_IS_PRE_V4_ASSEMBLY),
3646 MPF_ENTRY(IS_PRE_V4_ASSEMBLY),
3647 MPF_ENTRY(DEFAULT_DLL_IMPORT_SEARCH_PATHS_IS_CACHED),
3648 MPF_ENTRY(DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS),
3649
3650 MPF_ENTRY(NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED),
3651 MPF_ENTRY(COMPUTED_METHODDEF_TO_PROPERTYINFO_MAP),
3652 MPF_ENTRY(LOW_LEVEL_SYSTEM_ASSEMBLY_BY_NAME),
3653#undef MPF_ENTRY
3654};
3655
3656//VirtualSectionTypes.
3657#define TEXTIFY(x) W(#x)
3658static const NativeImageDumper::EnumMnemonics s_virtualSectionFlags [] =
3659{
3660
3661#define CORCOMPILE_SECTION_IBCTYPE(ibcType, _value) NativeImageDumper::EnumMnemonics(_value, TEXTIFY(ibcType)),
3662 CORCOMPILE_SECTION_IBCTYPES()
3663#undef CORCOMPILE_SECTION_IBCTYPE
3664
3665#define CORCOMPILE_SECTION_RANGE_TYPE(rangeType, _value) NativeImageDumper::EnumMnemonics(_value, TEXTIFY(rangeType) W("Range")),
3666 CORCOMPILE_SECTION_RANGE_TYPES()
3667#undef CORCOMPILE_SECTION_RANGE_TYPE
3668};
3669const WCHAR * g_sectionNames[] =
3670{
3671 W("SECTION_DUMMY"), // the first section start at 0x1. Make the array 1 based.
3672#define CORCOMPILE_SECTION_TYPE(section) W("SECTION_") TEXTIFY(section),
3673 CORCOMPILE_SECTION_TYPES()
3674#undef CORCOMPILE_SECTION
3675
3676};
3677#undef TEXTIFY
3678
3679
3680#ifdef _PREFAST_
3681#pragma warning(push)
3682#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3683#endif
3684
3685void NativeImageDumper::DumpModule( PTR_Module module )
3686{
3687
3688 //the module is the fisrt thing in the .data section. We use this fact for
3689 //the sectionBases down below.
3690// _ASSERTE(m_decoder.GetDataRva(PTR_TO_TADDR(module))
3691// == FindSection(".data")->VirtualAddress );
3692
3693 DisplayStartStructure( "module", DPtrToPreferredAddr(module),
3694 sizeof(*module), MODULE );
3695 PTR_PEFile file = module->m_file;
3696 _ASSERTE(file == NULL);
3697 DisplayWriteFieldPointer( m_file, DPtrToPreferredAddr(file), Module,
3698 MODULE );
3699
3700 PTR_MethodDesc dllMain( TO_TADDR(module->m_pDllMain) );
3701 WriteFieldMethodDesc( m_pDllMain, dllMain, Module,
3702 MODULE );
3703
3704 _ASSERTE(module->m_dwTransientFlags == 0U);
3705 DisplayWriteFieldUInt(m_dwTransientFlags, module->m_dwTransientFlags,
3706 Module, MODULE );
3707
3708
3709
3710 DisplayWriteFieldEnumerated( m_dwPersistedFlags, module->m_dwPersistedFlags,
3711 Module, s_ModulePersistedFlags, W("|"), MODULE );
3712
3713 DisplayWriteFieldPointer( m_pAssembly,
3714 DPtrToPreferredAddr(module->m_pAssembly),
3715 Module, MODULE );
3716 _ASSERTE(module->m_pAssembly == NULL); //never appears in the image
3717
3718 DisplayWriteFieldUInt( m_moduleRef, module->m_moduleRef, Module, MODULE );
3719 DisplayWriteFieldInt( m_dwDebuggerJMCProbeCount,
3720 module->m_dwDebuggerJMCProbeCount, Module, MODULE );
3721 /* REVISIT_TODO Fri 10/14/2005
3722 * Dump the binder
3723 */
3724 PTR_MscorlibBinder binder = module->m_pBinder;
3725 if( NULL != binder )
3726 {
3727 DisplayStartStructureWithOffset( m_pBinder, DPtrToPreferredAddr(binder),
3728 sizeof(*binder), Module,
3729 MODULE );
3730
3731 //these four fields don't have anything useful in ngen images.
3732 DisplayWriteFieldPointer( m_classDescriptions,
3733 DPtrToPreferredAddr(binder->m_classDescriptions),
3734 MscorlibBinder, MODULE );
3735 DisplayWriteFieldPointer( m_methodDescriptions,
3736 DPtrToPreferredAddr(binder->m_methodDescriptions),
3737 MscorlibBinder, MODULE );
3738 DisplayWriteFieldPointer( m_fieldDescriptions,
3739 DPtrToPreferredAddr(binder->m_fieldDescriptions),
3740 MscorlibBinder, MODULE );
3741 DisplayWriteFieldPointer( m_pModule,
3742 DPtrToPreferredAddr(binder->m_pModule),
3743 MscorlibBinder, MODULE );
3744
3745 DisplayWriteFieldInt( m_cClasses, binder->m_cClasses, MscorlibBinder,
3746 MODULE );
3747 DisplayWriteFieldAddress( m_pClasses,
3748 DPtrToPreferredAddr(binder->m_pClasses),
3749 sizeof(*binder->m_pClasses)
3750 * binder->m_cClasses,
3751 MscorlibBinder, MODULE );
3752 DisplayWriteFieldInt( m_cFields, binder->m_cFields, MscorlibBinder,
3753 MODULE );
3754 DisplayWriteFieldAddress( m_pFields,
3755 DPtrToPreferredAddr(binder->m_pFields),
3756 sizeof(*binder->m_pFields)
3757 * binder->m_cFields,
3758 MscorlibBinder, MODULE );
3759 DisplayWriteFieldInt( m_cMethods, binder->m_cMethods, MscorlibBinder,
3760 MODULE );
3761 DisplayWriteFieldAddress( m_pMethods,
3762 DPtrToPreferredAddr(binder->m_pMethods),
3763 sizeof(*binder->m_pMethods)
3764 * binder->m_cMethods,
3765 MscorlibBinder, MODULE );
3766
3767 DisplayEndStructure( MODULE ); //m_pBinder
3768 }
3769 else
3770 {
3771 DisplayWriteFieldPointer( m_pBinder, NULL, Module, MODULE );
3772 }
3773
3774
3775 /* REVISIT_TODO Tue 10/25/2005
3776 * unconditional dependencies, activations, class dependencies, thunktable
3777 */
3778
3779
3780 //round trip the LookupMap back through the DAC so that we don't have an
3781 //interior host pointer.
3782 PTR_LookupMapBase lookupMap( PTR_TO_TADDR(module)
3783 + offsetof(Module, m_TypeDefToMethodTableMap) );
3784 TraverseMap( lookupMap, "m_TypeDefToMethodTableMap",
3785 offsetof(Module, m_TypeDefToMethodTableMap),
3786 fieldsize(Module, m_TypeDefToMethodTableMap),
3787 &NativeImageDumper::IterateTypeDefToMTCallback );
3788
3789 lookupMap = PTR_LookupMapBase( PTR_TO_TADDR(module)
3790 + offsetof(Module, m_TypeRefToMethodTableMap) );
3791
3792 TraverseMap( lookupMap, "m_TypeRefToMethodTableMap",
3793 offsetof(Module, m_TypeRefToMethodTableMap),
3794 fieldsize(Module, m_TypeRefToMethodTableMap),
3795 &NativeImageDumper::IterateTypeRefToMTCallback );
3796
3797 lookupMap = PTR_LookupMapBase( PTR_TO_TADDR(module)
3798 + offsetof(Module, m_MethodDefToDescMap) );
3799 TraverseMap( lookupMap, "m_MethodDefToDescMap",
3800 offsetof(Module, m_MethodDefToDescMap),
3801 fieldsize(Module, m_MethodDefToDescMap),
3802 &NativeImageDumper::IterateMethodDefToMDCallback);
3803
3804 lookupMap = PTR_LookupMapBase( PTR_TO_TADDR(module)
3805 + offsetof(Module, m_FieldDefToDescMap) );
3806 TraverseMap( lookupMap, "m_FieldDefToDescMap",
3807 offsetof(Module, m_FieldDefToDescMap),
3808 fieldsize(Module, m_FieldDefToDescMap),
3809 &NativeImageDumper::IterateFieldDefToFDCallback);
3810
3811 TraverseMemberRefToDescHash(module->m_pMemberRefToDescHashTable, "m_pMemberRefToDescHashTable",
3812 offsetof(Module, m_pMemberRefToDescHashTable),
3813 fieldsize(Module, m_pMemberRefToDescHashTable),
3814 FALSE);
3815
3816 lookupMap = PTR_LookupMapBase( PTR_TO_TADDR(module)
3817 + offsetof(Module, m_GenericParamToDescMap) );
3818
3819 TraverseMap( lookupMap, "m_GenericParamToDescMap",
3820 offsetof(Module, m_GenericParamToDescMap),
3821 fieldsize(Module, m_GenericParamToDescMap),
3822 &NativeImageDumper::IterateGenericParamToDescCallback);
3823
3824 lookupMap = PTR_LookupMapBase( PTR_TO_TADDR(module)
3825 + offsetof(Module, m_GenericTypeDefToCanonMethodTableMap) );
3826
3827 TraverseMap( lookupMap, "m_GenericTypeDefToCanonMethodTableMap",
3828 offsetof(Module, m_GenericTypeDefToCanonMethodTableMap),
3829 fieldsize(Module, m_GenericTypeDefToCanonMethodTableMap),
3830 &NativeImageDumper::IterateTypeDefToMTCallback );
3831
3832 lookupMap = PTR_LookupMapBase( PTR_TO_TADDR(module)
3833 + offsetof(Module, m_FileReferencesMap) );
3834 TraverseMap( lookupMap, "m_FileReferencesMap",
3835 offsetof(Module, m_FileReferencesMap),
3836 fieldsize(Module, m_FileReferencesMap),
3837 &NativeImageDumper::IterateMemberRefToDescCallback);
3838
3839 lookupMap = PTR_LookupMapBase(PTR_TO_TADDR(module)
3840 + offsetof(Module,m_ManifestModuleReferencesMap));
3841
3842 TraverseMap( lookupMap, "m_ManifestModuleReferencesMap",
3843 offsetof(Module, m_ManifestModuleReferencesMap),
3844 fieldsize(Module, m_ManifestModuleReferencesMap),
3845 &NativeImageDumper::IterateManifestModules);
3846
3847 TraverseClassHash( module->m_pAvailableClasses, "m_pAvailableClasses",
3848 offsetof(Module, m_pAvailableClasses),
3849 fieldsize(Module, m_pAvailableClasses), true );
3850
3851 TraverseTypeHash( module->m_pAvailableParamTypes, "m_pAvailableParamTypes",
3852 offsetof(Module, m_pAvailableParamTypes),
3853 fieldsize(Module, m_pAvailableParamTypes) );
3854 TraverseInstMethodHash( module->m_pInstMethodHashTable,
3855 "m_pInstMethodHashTable",
3856 offsetof(Module, m_pInstMethodHashTable),
3857 fieldsize(Module, m_pInstMethodHashTable),
3858 module );
3859 TraverseStubMethodHash( module->m_pStubMethodHashTable,
3860 "m_pStubMethodHashTable",
3861 offsetof(Module, m_pStubMethodHashTable),
3862 fieldsize(Module, m_pStubMethodHashTable),
3863 module );
3864
3865 IF_OPT(MODULE)
3866 {
3867 TraverseClassHash( module->m_pAvailableClassesCaseIns,
3868 "m_pAvailableClassesCaseIns",
3869 offsetof(Module, m_pAvailableClassesCaseIns),
3870 fieldsize(Module, m_pAvailableClassesCaseIns),
3871 false );
3872 }
3873
3874#ifdef FEATURE_COMINTEROP
3875 TraverseGuidToMethodTableHash( module->m_pGuidToTypeHash,
3876 "m_pGuidToTypeHash",
3877 offsetof(Module, m_pGuidToTypeHash),
3878 fieldsize(Module, m_pGuidToTypeHash),
3879 true);
3880
3881#endif // FEATURE_COMINTEROP
3882
3883 _ASSERTE(module->m_pProfilingBlobTable == NULL);
3884
3885 DisplayWriteFieldFlag( m_nativeImageProfiling,
3886 module->m_nativeImageProfiling, Module, MODULE );
3887
3888 DisplayWriteFieldPointer( m_methodProfileList,
3889 DataPtrToDisplay((TADDR)module->m_methodProfileList),
3890 Module, MODULE );
3891 _ASSERTE(module->m_methodProfileList == NULL);
3892
3893 /* REVISIT_TODO Tue 10/04/2005
3894 * Dump module->m_moduleCtorInfo
3895 */
3896 PTR_ModuleCtorInfo ctorInfo( PTR_HOST_MEMBER_TADDR(Module, module,
3897 m_ModuleCtorInfo) );
3898
3899 DisplayStartStructureWithOffset( m_ModuleCtorInfo,
3900 DPtrToPreferredAddr(ctorInfo),
3901 sizeof(*ctorInfo),
3902 Module, SLIM_MODULE_TBLS );
3903 DisplayWriteFieldInt( numElements, ctorInfo->numElements, ModuleCtorInfo,
3904 SLIM_MODULE_TBLS );
3905 DisplayWriteFieldInt( numLastAllocated, ctorInfo->numLastAllocated,
3906 ModuleCtorInfo, SLIM_MODULE_TBLS );
3907 DisplayWriteFieldInt( numElementsHot, ctorInfo->numElementsHot,
3908 ModuleCtorInfo, SLIM_MODULE_TBLS );
3909 DisplayWriteFieldAddress( ppMT, DPtrToPreferredAddr(ctorInfo->ppMT),
3910 ctorInfo->numElements * sizeof(RelativePointer<MethodTable*>),
3911 ModuleCtorInfo, SLIM_MODULE_TBLS );
3912 /* REVISIT_TODO Tue 03/21/2006
3913 * is cctorInfoHot and cctorInfoCold actually have anything interesting
3914 * inside of them?
3915 */
3916 DisplayWriteFieldAddress( cctorInfoHot,
3917 DPtrToPreferredAddr(ctorInfo->cctorInfoHot),
3918 sizeof(*ctorInfo->cctorInfoHot)
3919 * ctorInfo->numElementsHot,
3920 ModuleCtorInfo, SLIM_MODULE_TBLS );
3921 DisplayWriteFieldAddress( cctorInfoCold,
3922 DPtrToPreferredAddr(ctorInfo->cctorInfoCold),
3923 sizeof(*ctorInfo->cctorInfoCold)
3924 * (ctorInfo->numElements
3925 - ctorInfo->numElementsHot),
3926 ModuleCtorInfo, SLIM_MODULE_TBLS );
3927 /* XXX Thu 03/23/2006
3928 * See ModuleCtorInfo::Save for why these are +1.
3929 */
3930 DisplayWriteFieldAddress( hotHashOffsets,
3931 DPtrToPreferredAddr(ctorInfo->hotHashOffsets),
3932 (ctorInfo->numHotHashes + 1)
3933 * sizeof(*ctorInfo->hotHashOffsets),
3934 ModuleCtorInfo, SLIM_MODULE_TBLS );
3935 DisplayWriteFieldAddress( coldHashOffsets,
3936 DPtrToPreferredAddr(ctorInfo->coldHashOffsets),
3937 (ctorInfo->numColdHashes + 1)
3938 * sizeof(*ctorInfo->coldHashOffsets),
3939 ModuleCtorInfo, SLIM_MODULE_TBLS );
3940
3941 DisplayWriteFieldInt( numHotHashes, ctorInfo->numHotHashes, ModuleCtorInfo,
3942 SLIM_MODULE_TBLS );
3943 DisplayWriteFieldInt( numColdHashes, ctorInfo->numColdHashes,
3944 ModuleCtorInfo, SLIM_MODULE_TBLS );
3945
3946 DisplayWriteFieldAddress( ppHotGCStaticsMTs,
3947 DPtrToPreferredAddr(ctorInfo->ppHotGCStaticsMTs),
3948 ctorInfo->numHotGCStaticsMTs
3949 * sizeof(*ctorInfo->ppHotGCStaticsMTs),
3950 ModuleCtorInfo, SLIM_MODULE_TBLS );
3951 DisplayWriteFieldAddress( ppColdGCStaticsMTs,
3952 DPtrToPreferredAddr(ctorInfo->ppColdGCStaticsMTs),
3953 ctorInfo->numColdGCStaticsMTs
3954 * sizeof(*ctorInfo->ppColdGCStaticsMTs),
3955 ModuleCtorInfo, SLIM_MODULE_TBLS );
3956 DisplayWriteFieldInt( numHotGCStaticsMTs, ctorInfo->numHotGCStaticsMTs,
3957 ModuleCtorInfo, SLIM_MODULE_TBLS );
3958 DisplayWriteFieldInt( numColdGCStaticsMTs, ctorInfo->numColdGCStaticsMTs,
3959 ModuleCtorInfo, SLIM_MODULE_TBLS );
3960
3961 DisplayEndStructure( SLIM_MODULE_TBLS ); //m_ModuleCtorInfo
3962
3963 _ASSERTE(module->m_pNgenStats == NULL);
3964
3965 DisplayWriteFieldPointer( m_pNgenStats,
3966 DataPtrToDisplay((TADDR)module->m_pNgenStats),
3967 Module, MODULE );
3968
3969 DisplayWriteFieldAddress(m_propertyNameSet,
3970 DPtrToPreferredAddr(module->m_propertyNameSet),
3971 sizeof(module->m_propertyNameSet[0]) *
3972 module->m_nPropertyNameSet,
3973 Module, MODULE);
3974
3975 DisplayWriteFieldPointer( m_ModuleID,
3976 DataPtrToDisplay(dac_cast<TADDR>(module->m_ModuleID)),
3977 Module, MODULE );
3978 _ASSERTE(module->m_ModuleID == NULL);
3979
3980 /* XXX Tue 04/11/2006
3981 * Value is either -1 or 0, so no need to rebase.
3982 */
3983 DisplayWriteFieldPointer( m_pRegularStaticOffsets,
3984 PTR_TO_TADDR(module->m_pRegularStaticOffsets),
3985 Module, MODULE );
3986 _ASSERTE(module->m_pRegularStaticOffsets == (void*)-1
3987 || module->m_pRegularStaticOffsets == 0 );
3988
3989 DisplayWriteFieldInt( m_dwMaxGCRegularStaticHandles,
3990 module->m_dwMaxGCRegularStaticHandles, Module, MODULE );
3991 DisplayWriteFieldInt( m_dwRegularStaticsBlockSize, module->m_dwRegularStaticsBlockSize,
3992 Module, MODULE );
3993 DisplayWriteFieldAddress( m_pDynamicStaticsInfo,
3994 DataPtrToDisplay((TADDR)module->m_pDynamicStaticsInfo),
3995 module->m_maxDynamicEntries
3996 * sizeof(*(module->m_pDynamicStaticsInfo)),
3997 Module, MODULE );
3998
3999 DisplayWriteFieldInt( m_cDynamicEntries,
4000 (int)module->m_cDynamicEntries, Module, MODULE );
4001
4002 CoverageRead(TO_TADDR(module->m_pDynamicStaticsInfo),
4003 (int)(module->m_maxDynamicEntries
4004 * sizeof(*(module->m_pDynamicStaticsInfo))));
4005
4006
4007
4008 _ASSERTE(module->m_debuggerSpecificData.m_pDynamicILCrst == NULL);
4009 DisplayWriteFieldPointer( m_debuggerSpecificData.m_pDynamicILCrst,
4010 DataPtrToDisplay(dac_cast<TADDR>(module->m_debuggerSpecificData.m_pDynamicILCrst)),
4011 Module, MODULE );
4012
4013
4014 /* REVISIT_TODO Wed 09/21/2005
4015 * Get me in the debugger and look at the activations and module/class
4016 * dependencies.
4017 * As well as the thunks.
4018 */
4019
4020 /* REVISIT_TODO Wed 09/21/2005
4021 * Dump the following
4022 */
4023 //file
4024 //assembly
4025
4026 DisplayWriteFieldInt( m_DefaultDllImportSearchPathsAttributeValue,
4027 module->m_DefaultDllImportSearchPathsAttributeValue, Module, MODULE );
4028
4029
4030 DisplayEndStructure(MODULE); //Module
4031}
4032#ifdef _PREFAST_
4033#pragma warning(pop)
4034#endif
4035
4036bool NativeImageDumper::isPrecode(TADDR maybePrecode)
4037{
4038 PTR_Module module = (TADDR)m_decoder.GetPersistedModuleImage();
4039
4040 return !!module->IsZappedPrecode(maybePrecode);
4041}
4042
4043
4044void NativeImageDumper::IterateTypeDefToMTCallback( TADDR mtTarget,
4045 TADDR flags,
4046 PTR_LookupMapBase map,
4047 DWORD rid )
4048{
4049 DisplayStartElement( "Entry", MODULE_TABLES );
4050
4051 PTR_MethodTable mt(mtTarget);
4052
4053 DisplayWriteElementUInt( "Token", rid | mdtTypeDef, MODULE_TABLES );
4054 /* REVISIT_TODO Fri 10/21/2005
4055 * Can I use WriteElementMethodTable here?
4056 */
4057 DisplayWriteElementPointer( "MethodTable", DPtrToPreferredAddr(mt),
4058 MODULE_TABLES );
4059 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4060 /* REVISIT_TODO Fri 09/30/2005
4061 * This handles the extra entries in the type table that shouldn't be there.
4062 */
4063 if( rid == 0 || ((rid != 1) && (mtTarget == NULL)) )
4064 {
4065 DisplayWriteElementString( "Name", "mdTypeDefNil", MODULE_TABLES );
4066 }
4067 else
4068 {
4069 TempBuffer buf;
4070 MethodTableToString( mt, buf );
4071 DisplayWriteElementStringW( "Name", (const WCHAR*)buf, MODULE_TABLES );
4072 }
4073 DisplayWriteElementFlag( "hot", !!map->FindHotItemValuePtr(rid),
4074 MODULE_TABLES );
4075 DisplayEndElement( MODULE_TABLES );
4076
4077 if( isInRange(PTR_TO_TADDR(mt)) )
4078 {
4079 m_discoveredMTs.AppendEx(mt);
4080 PTR_EEClass clazz = GetClassFromMT(mt);
4081 if( isInRange(PTR_TO_TADDR(clazz)) )
4082 m_discoveredClasses.AppendEx(mt);
4083 }
4084}
4085
4086void NativeImageDumper::IterateTypeRefToMTCallback( TADDR mtTarget,
4087 TADDR flags,
4088 PTR_LookupMapBase map,
4089 DWORD rid )
4090{
4091 DisplayStartElement( "Entry", MODULE_TABLES );
4092
4093 mtTarget = ((FixupPointer<TADDR>&)mtTarget).GetValue();
4094
4095 PTR_MethodTable mt(mtTarget);
4096
4097#if 0
4098 RecordTypeRef(rid | mdtTypeRef, mt);
4099#endif
4100
4101 DisplayWriteElementUInt( "Token", rid | mdtTypeRef, MODULE_TABLES );
4102
4103 DisplayWriteElementPointer( "MethodTable", DPtrToPreferredAddr(mt),
4104 MODULE_TABLES );
4105
4106 if( rid == 0 )
4107 {
4108 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4109 DisplayWriteElementString( "Name", "mdtTypeRefNil", MODULE_TABLES );
4110 }
4111 else if( mt == NULL )
4112 {
4113 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4114 IF_OPT(MODULE_TABLES)
4115 WriteElementMDToken( "Name", mdtTypeRef | rid );
4116 }
4117 else if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)) )
4118 {
4119 RVA rva = CORCOMPILE_UNTAG_TOKEN(PTR_TO_TADDR(mt));
4120 //
4121 // This guy writes two things FixupTargetValue and FixupTargetName
4122 //
4123 WriteElementsFixupBlob( NULL,PTR_TO_TADDR(mt));
4124 }
4125 else
4126 {
4127 TempBuffer buf;
4128 MethodTableToString( mt, buf );
4129 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4130 DisplayWriteElementStringW( "Name", (const WCHAR*)buf, MODULE_TABLES );
4131 }
4132 DisplayWriteElementFlag( "hot", !!map->FindHotItemValuePtr(rid),
4133 MODULE_TABLES );
4134 DisplayEndElement( MODULE_TABLES );
4135 if( isInRange(mtTarget) )
4136 {
4137 m_discoveredMTs.AppendEx(mt);
4138 PTR_EEClass clazz = GetClassFromMT(mt);
4139 if( isInRange(PTR_TO_TADDR(clazz)) )
4140 m_discoveredClasses.AppendEx(mt);
4141 }
4142}
4143
4144void NativeImageDumper::IterateMethodDefToMDCallback( TADDR mdTarget,
4145 TADDR flags,
4146 PTR_LookupMapBase map,
4147 DWORD rid )
4148{
4149 DisplayStartElement( "Entry", MODULE_TABLES );
4150
4151 PTR_MethodDesc md(mdTarget);
4152
4153 DisplayWriteElementUInt( "Token", rid | mdtMethodDef, MODULE_TABLES );
4154
4155 DisplayWriteElementPointer( "MethodDesc", DPtrToPreferredAddr(md),
4156 MODULE_TABLES );
4157
4158 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4159 if( rid == 0 )
4160 {
4161 DisplayWriteElementString( "Name", "mdtMethodDefNil", MODULE_TABLES );
4162 }
4163 else
4164 {
4165 TempBuffer buf;
4166 MethodDescToString( md, buf );
4167 DisplayWriteElementStringW( "Name", (const WCHAR*)buf, MODULE_TABLES );
4168 }
4169 DisplayWriteElementFlag( "hot", !!map->FindHotItemValuePtr(rid),
4170 MODULE_TABLES );
4171 DisplayEndElement( MODULE_TABLES );
4172 //m_discoveredMDs.AppendEx(md);
4173}
4174
4175void NativeImageDumper::IterateFieldDefToFDCallback( TADDR fdTarget,
4176 TADDR flags,
4177 PTR_LookupMapBase map,
4178 DWORD rid )
4179{
4180 PTR_FieldDesc fd(fdTarget);
4181 DisplayStartElement( "Entry", MODULE_TABLES );
4182
4183
4184 DisplayWriteElementUInt( "Token", rid | mdtFieldDef, MODULE_TABLES );
4185
4186 DisplayWriteElementPointer( "FieldDef", DPtrToPreferredAddr(fd),
4187 MODULE_TABLES );
4188
4189 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4190 if( rid == 0 )
4191 {
4192 DisplayWriteElementString( "Name", "mdtFieldDefNil", MODULE_TABLES );
4193 }
4194 else
4195 {
4196 TempBuffer buf;
4197 FieldDescToString( fd, mdtFieldDef | rid, buf );
4198 DisplayWriteElementStringW( "Name", (const WCHAR*)buf, MODULE_TABLES );
4199 }
4200 DisplayWriteElementFlag( "hot", !!map->FindHotItemValuePtr(rid),
4201 MODULE_TABLES );
4202 DisplayEndElement( MODULE_TABLES );
4203 /* XXX Mon 10/17/2005
4204 * All FieldDescs are reachable from the EEClasses
4205 */
4206 //m_discoveredFDs.AppendEx(PTR_FieldDesc(fdTarget));
4207}
4208
4209void NativeImageDumper::IterateMemberRefToDescCallback( TADDR mrTarget,
4210 TADDR flags,
4211 PTR_LookupMapBase map,
4212 DWORD rid )
4213{
4214 DisplayStartElement( "Entry", MODULE_TABLES );
4215
4216
4217 bool isFieldRef = (flags & IS_FIELD_MEMBER_REF) != 0;
4218 mdToken targetToken = mdtMemberRef | rid;
4219 mrTarget = ((FixupPointer<TADDR>&)mrTarget).GetValue();
4220 DisplayWriteElementUInt( "Token", targetToken, MODULE_TABLES );
4221 DisplayWriteElementPointer( isFieldRef ? "FieldDesc" : "MethodDesc",
4222 DataPtrToDisplay(mrTarget), MODULE_TABLES );
4223
4224 TempBuffer buf;
4225 if( rid == 0 )
4226 {
4227 buf.Append( W("mdtMemberDefNil") );
4228 }
4229 else if( CORCOMPILE_IS_POINTER_TAGGED(mrTarget) )
4230 {
4231 WriteElementsFixupBlob( NULL, mrTarget );
4232 }
4233 else if( isFieldRef )
4234 {
4235 FieldDescToString( PTR_FieldDesc(mrTarget), buf );
4236 }
4237 else
4238 {
4239 MethodDescToString( PTR_MethodDesc(mrTarget), buf );
4240 }
4241 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4242 DisplayWriteElementStringW( "Name", (const WCHAR*)buf, MODULE_TABLES );
4243
4244 DisplayWriteElementFlag( "hot", !!map->FindHotItemValuePtr(rid),
4245 MODULE_TABLES );
4246 DisplayEndElement(MODULE_TABLES);
4247 //m_discoveredMTs.AppendEx(mt);
4248}
4249
4250void NativeImageDumper::IterateGenericParamToDescCallback( TADDR tdTarget,
4251 TADDR flags,
4252 PTR_LookupMapBase map,
4253 DWORD rid )
4254{
4255 PTR_TypeDesc td(tdTarget);
4256 DisplayStartElement( "Entry", MODULE_TABLES );
4257
4258
4259 DisplayWriteElementUInt( "Token", rid | mdtGenericParam, MODULE_TABLES );
4260
4261 DisplayWriteElementPointer( "GenericParam", DPtrToPreferredAddr(td),
4262 MODULE_TABLES );
4263
4264 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4265 if( rid == 0 || td == NULL )
4266 {
4267 DisplayWriteElementString( "Name", "mdtGenericParamNil", MODULE_TABLES );
4268 }
4269 else
4270 {
4271 TempBuffer buf;
4272 TypeDescToString( td, buf );
4273 DisplayWriteElementStringW( "Name", (const WCHAR*)buf, MODULE_TABLES );
4274 }
4275 DisplayWriteElementFlag( "hot", !!map->FindHotItemValuePtr(rid),
4276 MODULE_TABLES );
4277 DisplayEndElement( MODULE_TABLES );
4278}
4279
4280#if 0
4281void NativeImageDumper::IterateFileReferencesCallback(TADDR moduleTarget,
4282 TADDR flags,
4283 PTR_LookupMapBase map,
4284 DWORD rid)
4285{
4286 DisplayStartElement( "Entry", MODULE_TABLES );
4287
4288 PTR_Module module(moduleTarget);
4289
4290 DisplayWriteElementUInt( "Token", rid | mdtFile, MODULE_TABLES );
4291
4292 DisplayWriteElementPointer( "Module", DPtrToPreferredAddr(module),
4293 MODULE_TABLES );
4294
4295 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4296 if( rid == 0 || (module == NULL) )
4297 {
4298 DisplayWriteElementString( "Name", "mdtFileNil", MODULE_TABLES );
4299 }
4300 else
4301 {
4302 TempBuffer buf;
4303 AppendTokenName(mdtFile | rid, buf);
4304 DisplayWriteElementStringW( "Name", (const WCHAR*)buf, MODULE_TABLES );
4305 }
4306 DisplayWriteElementFlag( "hot", !!map->FindHotItemValuePtr(rid),
4307 MODULE_TABLES );
4308 DisplayEndElement( MODULE_TABLES );
4309 //m_discoveredFDs.AppendEx(mt);
4310}
4311#endif
4312
4313void NativeImageDumper::IterateManifestModules( TADDR moduleTarget,
4314 TADDR flags,
4315 PTR_LookupMapBase map,
4316 DWORD rid )
4317{
4318 DisplayStartElement( "Entry", MODULE_TABLES );
4319
4320 moduleTarget = ((FixupPointer<TADDR>&)moduleTarget).GetValue();
4321
4322 PTR_Module module(moduleTarget);
4323
4324 DisplayWriteElementUInt( "Token", rid | mdtAssemblyRef, MODULE_TABLES );
4325
4326 DisplayWriteElementPointer( "Module", DPtrToPreferredAddr(module),
4327 MODULE_TABLES );
4328 DisplayWriteElementFlag( "fake", false, MODULE_TABLES );
4329 if( rid == 0 || (module == NULL) )
4330 {
4331 DisplayWriteElementString( "Name", "mdtAssemblyRefNil", MODULE_TABLES );
4332 }
4333 else
4334 {
4335 TempBuffer buf;
4336 AppendTokenName(mdtAssemblyRef | rid, buf, m_import);
4337 DisplayWriteElementStringW( "Name", (const WCHAR*)buf, MODULE_TABLES );
4338 }
4339 DisplayWriteElementFlag( "hot", !!map->FindHotItemValuePtr(rid),
4340 MODULE_TABLES );
4341 DisplayEndElement( MODULE_TABLES );
4342 //m_discoveredFDs.AppendEx(mt);
4343}
4344
4345void NativeImageDumper::TraverseMap(PTR_LookupMapBase map, const char * name,
4346 unsigned offset, unsigned fieldSize,
4347 void(NativeImageDumper::*cb)(TADDR,
4348 TADDR,
4349 PTR_LookupMapBase,
4350 DWORD))
4351{
4352 if( map == NULL )
4353 {
4354 IF_OPT(MODULE)
4355 m_display->WriteFieldPointer( name, offset, fieldSize, NULL );
4356 return;
4357 }
4358 DisplayStartVStructure(name, MODULE);
4359
4360 DisplayStartArray( "Tables", W("%s"), MODULE );
4361 PTR_LookupMapBase current = map;
4362 do
4363 {
4364 DWORD cbTable = map->MapIsCompressed() ? map->cbTable : map->dwCount * sizeof(*map->pTable);
4365
4366 IF_OPT(MODULE)
4367 {
4368 DisplayWriteElementAddress( "Table",
4369 DPtrToPreferredAddr(map->pTable),
4370 cbTable,
4371 MODULE);
4372 }
4373
4374 CoverageRead( PTR_TO_TADDR(map->pTable), cbTable );
4375 _ASSERTE(current == map || current->hotItemList == NULL);
4376 current = current->pNext;
4377 }while( current != NULL );
4378
4379 DisplayEndArray( "Total Tables", MODULE ); //Tables
4380
4381 DisplayWriteFieldAddress( hotItemList,
4382 DPtrToPreferredAddr(map->hotItemList),
4383 map->dwNumHotItems * sizeof(*map->hotItemList),
4384 LookupMapBase, MODULE );
4385
4386 DisplayStartArray( "Map", W("[%s]: %s %s%s %s %s %s"), MODULE_TABLES );
4387
4388 IF_OPT_OR3(MODULE_TABLES, EECLASSES, METHODTABLES)
4389 {
4390 LookupMap<TADDR>::Iterator iter(dac_cast<DPTR(LookupMap<TADDR>)>(map));
4391 DWORD rid = 0;
4392 while(iter.Next())
4393 {
4394 TADDR flags = 0;
4395 TADDR element = iter.GetElementAndFlags(&flags);
4396 (this->*cb)( element, flags, map, rid );
4397 rid++;
4398 }
4399
4400 }
4401 CoverageRead( PTR_TO_TADDR(map->hotItemList),
4402 map->dwNumHotItems * sizeof(*map->hotItemList) );
4403 DisplayEndArray( "Total" , MODULE_TABLES );//Map
4404
4405 DisplayEndVStructure(MODULE); //name
4406}
4407
4408// Templated method containing the core code necessary to traverse hash tables based on NgenHash (see
4409// vm\NgenHash.h).
4410template<typename HASH_CLASS, typename HASH_ENTRY_CLASS>
4411void NativeImageDumper::TraverseNgenHash(DPTR(HASH_CLASS) pTable,
4412 const char * name,
4413 unsigned offset,
4414 unsigned fieldSize,
4415 bool saveClasses,
4416 void (NativeImageDumper::*DisplayEntryFunction)(void *, DPTR(HASH_ENTRY_CLASS), bool),
4417 void *pContext)
4418{
4419 if (pTable == NULL)
4420 {
4421 IF_OPT(MODULE)
4422 m_display->WriteFieldPointer(name, offset, fieldSize, NULL);
4423 return;
4424 }
4425 IF_OPT(MODULE)
4426 {
4427 m_display->StartStructureWithOffset(name, offset, fieldSize,
4428 DPtrToPreferredAddr(pTable),
4429 sizeof(HASH_CLASS));
4430 }
4431
4432 DisplayWriteFieldPointer(m_pModule,
4433 DPtrToPreferredAddr(pTable->GetModule()),
4434 HASH_CLASS, MODULE);
4435
4436 // Dump warm (volatile) entries.
4437 DisplayWriteFieldUInt(m_cWarmEntries, pTable->m_cWarmEntries, HASH_CLASS, MODULE);
4438 DisplayWriteFieldUInt(m_cWarmBuckets, pTable->m_cWarmBuckets, HASH_CLASS, MODULE);
4439 DisplayWriteFieldAddress(m_pWarmBuckets,
4440 DPtrToPreferredAddr(pTable->GetWarmBuckets()),
4441 sizeof(HASH_ENTRY_CLASS*) * pTable->m_cWarmBuckets,
4442 HASH_CLASS, MODULE);
4443
4444 // Dump hot (persisted) entries.
4445 DPTR(typename HASH_CLASS::PersistedEntries) pHotEntries(PTR_HOST_MEMBER_TADDR(HASH_CLASS, pTable, m_sHotEntries));
4446 DisplayStartStructureWithOffset(m_sHotEntries, DPtrToPreferredAddr(pHotEntries),
4447 sizeof(typename HASH_CLASS::PersistedEntries),
4448 HASH_CLASS, MODULE);
4449 TraverseNgenPersistedEntries<HASH_CLASS, HASH_ENTRY_CLASS>(pTable, pHotEntries, saveClasses, DisplayEntryFunction, pContext);
4450 DisplayEndStructure(MODULE); // Hot entries
4451
4452 // Dump cold (persisted) entries.
4453 DPTR(typename HASH_CLASS::PersistedEntries) pColdEntries(PTR_HOST_MEMBER_TADDR(HASH_CLASS, pTable, m_sColdEntries));
4454 DisplayStartStructureWithOffset(m_sColdEntries, DPtrToPreferredAddr(pColdEntries),
4455 sizeof(typename HASH_CLASS::PersistedEntries),
4456 HASH_CLASS, MODULE);
4457 TraverseNgenPersistedEntries<HASH_CLASS, HASH_ENTRY_CLASS>(pTable, pColdEntries, saveClasses, DisplayEntryFunction, pContext);
4458 DisplayEndStructure(MODULE); // Cold entries
4459
4460 DisplayEndStructure(MODULE); // pTable
4461}
4462
4463// Helper used by TraverseNgenHash above to traverse an ngen persisted section of a table (separated out here
4464// because NgenHash-based tables can have two such sections, one for hot and one for cold entries).
4465template<typename HASH_CLASS, typename HASH_ENTRY_CLASS>
4466void NativeImageDumper::TraverseNgenPersistedEntries(DPTR(HASH_CLASS) pTable,
4467 DPTR(typename HASH_CLASS::PersistedEntries) pEntries,
4468 bool saveClasses,
4469 void (NativeImageDumper::*DisplayEntryFunction)(void *, DPTR(HASH_ENTRY_CLASS), bool),
4470 void *pContext)
4471{
4472 // Display top-level fields.
4473 DisplayWriteFieldUInt(m_cEntries, pEntries->m_cEntries, typename HASH_CLASS::PersistedEntries, MODULE);
4474 DisplayWriteFieldUInt(m_cBuckets, pEntries->m_cBuckets, typename HASH_CLASS::PersistedEntries, MODULE);
4475 DisplayWriteFieldAddress(m_pBuckets,
4476 DPtrToPreferredAddr(pTable->GetPersistedBuckets(pEntries)),
4477 pEntries->m_cBuckets ? pTable->GetPersistedBuckets(pEntries)->GetSize(pEntries->m_cBuckets) : 0,
4478 typename HASH_CLASS::PersistedEntries, MODULE);
4479 DisplayWriteFieldAddress(m_pEntries,
4480 DPtrToPreferredAddr(pTable->GetPersistedEntries(pEntries)),
4481 sizeof(typename HASH_CLASS::PersistedEntry) * pEntries->m_cEntries,
4482 typename HASH_CLASS::PersistedEntries, MODULE);
4483
4484 // Display entries (or maybe just the classes referenced by those entries).
4485 DisplayStartArray("Entries", NULL, SLIM_MODULE_TBLS);
4486
4487 // Enumerate bucket list.
4488 for (DWORD i = 0; i < pEntries->m_cBuckets; ++i)
4489 {
4490 // Get index of the first entry and the count of entries in the bucket.
4491 DWORD dwEntryId, cEntries;
4492 pTable->GetPersistedBuckets(pEntries)->GetBucket(i, &dwEntryId, &cEntries);
4493
4494 // Loop over entries.
4495 while (cEntries && (CHECK_OPT(SLIM_MODULE_TBLS)
4496 || CHECK_OPT(EECLASSES)
4497 || CHECK_OPT(METHODTABLES)))
4498 {
4499 // Lookup entry in the array via the index we have.
4500 typename HASH_CLASS::PTR_PersistedEntry pEntry(PTR_TO_TADDR(pTable->GetPersistedEntries(pEntries)) +
4501 (dwEntryId * sizeof(typename HASH_CLASS::PersistedEntry)));
4502
4503 IF_OPT(SLIM_MODULE_TBLS)
4504 {
4505 DisplayStartStructure("PersistedEntry",
4506 DPtrToPreferredAddr(pEntry),
4507 sizeof(typename HASH_CLASS::PersistedEntry), SLIM_MODULE_TBLS);
4508 }
4509
4510 // Display entry via a member function specific to the type of hash table we're traversing. Each
4511 // sub-class of NgenHash hash its own entry structure that is embedded NgenHash's entry. The
4512 // helper function expects a pointer to this inner entry.
4513 DPTR(HASH_ENTRY_CLASS) pInnerEntry(PTR_TO_MEMBER_TADDR(typename HASH_CLASS::PersistedEntry, pEntry, m_sValue));
4514 (this->*DisplayEntryFunction)(pContext, pInnerEntry, saveClasses);
4515
4516 IF_OPT(SLIM_MODULE_TBLS)
4517 {
4518 DisplayWriteFieldUInt(m_iHashValue, pEntry->m_iHashValue,
4519 typename HASH_CLASS::PersistedEntry, SLIM_MODULE_TBLS);
4520
4521 DisplayEndStructure(SLIM_MODULE_TBLS); // Entry
4522 }
4523
4524 dwEntryId++;
4525 cEntries--;
4526 }
4527 }
4528
4529 DisplayEndArray("Total Entries", SLIM_MODULE_TBLS); // Entry array
4530}
4531
4532void NativeImageDumper::TraverseClassHashEntry(void *pContext, PTR_EEClassHashEntry pEntry, bool saveClasses)
4533{
4534 IF_OPT(SLIM_MODULE_TBLS)
4535 {
4536 DisplayStartStructure("EEClassHashEntry",
4537 DPtrToPreferredAddr(pEntry),
4538 sizeof(EEClassHashEntry), SLIM_MODULE_TBLS);
4539 }
4540
4541 size_t datum = size_t(PTR_TO_TADDR(pEntry->GetData()));
4542
4543 if (datum & EECLASSHASH_TYPEHANDLE_DISCR)
4544 {
4545 IF_OPT(SLIM_MODULE_TBLS)
4546 {
4547 /* REVISIT_TODO Tue 10/25/2005
4548 * Raw data with annotation?
4549 */
4550 mdTypeDef tk;
4551 tk = EEClassHashTable::UncompressModuleAndClassDef(pEntry->GetData());
4552 DoWriteFieldMDToken("Token",
4553 offsetof(EEClassHashEntry, m_Data),
4554 fieldsize(EEClassHashEntry, m_Data),
4555 tk);
4556 }
4557 }
4558 else
4559 {
4560 PTR_MethodTable pMT(TO_TADDR(datum));
4561 IF_OPT(SLIM_MODULE_TBLS)
4562 {
4563 DoWriteFieldMethodTable("MethodTable",
4564 offsetof(EEClassHashEntry, m_Data),
4565 fieldsize(EEClassHashEntry, m_Data),
4566 pMT);
4567 }
4568
4569 if (saveClasses)
4570 {
4571 // These are MethodTables. Get back to the EEClass from there.
4572 if (isInRange(PTR_TO_TADDR(pMT)))
4573 m_discoveredMTs.AppendEx(pMT);
4574 if (pMT != NULL)
4575 {
4576 PTR_EEClass pClass = GetClassFromMT(pMT);
4577 if (isInRange(PTR_TO_TADDR(pClass)))
4578 m_discoveredClasses.AppendEx(pMT);
4579 }
4580 }
4581 }
4582
4583 IF_OPT(SLIM_MODULE_TBLS)
4584 {
4585 DisplayWriteFieldPointer(m_pEncloser,
4586 DPtrToPreferredAddr(pEntry->GetEncloser()),
4587 EEClassHashEntry, SLIM_MODULE_TBLS);
4588 DisplayEndStructure(SLIM_MODULE_TBLS);
4589 }
4590}
4591
4592void NativeImageDumper::TraverseClassHash(PTR_EEClassHashTable pTable,
4593 const char * name,
4594 unsigned offset,
4595 unsigned fieldSize,
4596 bool saveClasses)
4597{
4598 TraverseNgenHash<EEClassHashTable, EEClassHashEntry>(pTable,
4599 name,
4600 offset,
4601 fieldSize,
4602 saveClasses,
4603 &NativeImageDumper::TraverseClassHashEntry,
4604 NULL);
4605}
4606
4607#ifdef FEATURE_COMINTEROP
4608
4609void NativeImageDumper::TraverseGuidToMethodTableEntry(void *pContext, PTR_GuidToMethodTableEntry pEntry, bool saveClasses)
4610{
4611 IF_OPT(SLIM_MODULE_TBLS)
4612 {
4613 DisplayStartStructure("GuidToMethodTableEntry",
4614 DPtrToPreferredAddr(pEntry),
4615 sizeof(GuidToMethodTableEntry), SLIM_MODULE_TBLS);
4616 }
4617
4618 WriteFieldMethodTable(m_pMT, pEntry->m_pMT, GuidToMethodTableEntry, ALWAYS);
4619
4620 TempBuffer buf;
4621 GuidToString( *(pEntry->m_Guid), buf );
4622 DisplayWriteFieldStringW( m_Guid, (const WCHAR *)buf, GuidToMethodTableEntry, ALWAYS );
4623
4624 DisplayEndStructure( SLIM_MODULE_TBLS );
4625}
4626
4627void NativeImageDumper::TraverseGuidToMethodTableHash(PTR_GuidToMethodTableHashTable pTable,
4628 const char * name,
4629 unsigned offset,
4630 unsigned fieldSize,
4631 bool saveClasses)
4632{
4633 TraverseNgenHash<GuidToMethodTableHashTable, GuidToMethodTableEntry>(pTable,
4634 name,
4635 offset,
4636 fieldSize,
4637 saveClasses,
4638 &NativeImageDumper::TraverseGuidToMethodTableEntry,
4639 NULL);
4640}
4641
4642#endif // FEATURE_COMINTEROP
4643
4644void NativeImageDumper::TraverseMemberRefToDescHashEntry(void *pContext, PTR_MemberRefToDescHashEntry pEntry, bool saveClasses)
4645{
4646 IF_OPT(SLIM_MODULE_TBLS)
4647 {
4648 DisplayStartStructure("MemberRefToDescHashEntry",
4649 DPtrToPreferredAddr(pEntry),
4650 sizeof(MemberRefToDescHashEntry), SLIM_MODULE_TBLS);
4651 }
4652
4653 if(pEntry->m_value & IS_FIELD_MEMBER_REF)
4654 WriteFieldFieldDesc(m_value, dac_cast<PTR_FieldDesc>(pEntry->m_value & (~MEMBER_REF_MAP_ALL_FLAGS)), MemberRefToDescHashEntry, MODULE_TABLES);
4655 else
4656 WriteFieldMethodDesc(m_value, dac_cast<PTR_MethodDesc>(pEntry->m_value), MemberRefToDescHashEntry, MODULE_TABLES);
4657
4658 DisplayEndStructure( SLIM_MODULE_TBLS );
4659}
4660
4661void NativeImageDumper::TraverseMemberRefToDescHash(PTR_MemberRefToDescHashTable pTable,
4662 const char * name,
4663 unsigned offset,
4664 unsigned fieldSize,
4665 bool saveClasses)
4666{
4667 TraverseNgenHash<MemberRefToDescHashTable, MemberRefToDescHashEntry>(pTable,
4668 name,
4669 offset,
4670 fieldSize,
4671 saveClasses,
4672 &NativeImageDumper::TraverseMemberRefToDescHashEntry,
4673 NULL);
4674}
4675
4676
4677void NativeImageDumper::TraverseTypeHashEntry(void *pContext, PTR_EETypeHashEntry pEntry, bool saveClasses)
4678{
4679 TypeHandle th = pEntry->GetTypeHandle();
4680 IF_OPT(SLIM_MODULE_TBLS)
4681 {
4682 DisplayStartStructure("EETypeHashEntry",
4683 DPtrToPreferredAddr(pEntry),
4684 sizeof(EETypeHashEntry), SLIM_MODULE_TBLS);
4685
4686 DoWriteFieldTypeHandle("TypeHandle",
4687 offsetof(EETypeHashEntry, m_data),
4688 fieldsize(EETypeHashEntry, m_data),
4689 th);
4690 }
4691
4692 if (!CORCOMPILE_IS_POINTER_TAGGED(th.AsTAddr()) && th.IsTypeDesc())
4693 {
4694 PTR_TypeDesc td(th.AsTypeDesc());
4695 if (isInRange(PTR_TO_TADDR(td)))
4696 m_discoveredTypeDescs.AppendEx(td);
4697 if (td->HasTypeParam())
4698 {
4699 PTR_ParamTypeDesc ptd(td);
4700
4701 /* REVISIT_TODO Thu 12/15/2005
4702 * Check OwnsTemplateMethodTable. However, this asserts in
4703 * this special completely unrestored and messed up state
4704 * (also, it chases through MT->GetClass()). There isn't
4705 * all that much harm here (bloats m_discoveredMTs though,
4706 * but not by a huge amount.
4707 */
4708 PTR_MethodTable mt(ptd->GetTemplateMethodTableInternal());
4709 if (isInRange(PTR_TO_TADDR(mt)))
4710 {
4711 m_discoveredMTs.AppendEx(mt);
4712 if (mt->IsClassPointerValid())
4713 {
4714 PTR_EEClass pClass = mt->GetClass();
4715 if (isInRange(PTR_TO_TADDR(pClass)))
4716 m_discoveredClasses.AppendEx(mt);
4717 }
4718 }
4719 }
4720 }
4721 else
4722 {
4723 PTR_MethodTable mt(th.AsTAddr());
4724
4725 if (isInRange( PTR_TO_TADDR(mt)))
4726 m_discoveredMTs.AppendEx(mt);
4727 //don't use GetClassFromMT here. mt->m_pEEClass might be a
4728 //fixup. In that case, just skip it.
4729 if (mt->IsClassPointerValid())
4730 {
4731 PTR_EEClass pClass = mt->GetClass();
4732 if (isInRange(PTR_TO_TADDR(pClass)))
4733 m_discoveredClasses.AppendEx(mt);
4734 }
4735 }
4736
4737 IF_OPT(SLIM_MODULE_TBLS)
4738 {
4739 DisplayEndStructure(SLIM_MODULE_TBLS);
4740 }
4741}
4742
4743void NativeImageDumper::TraverseTypeHash(PTR_EETypeHashTable pTable,
4744 const char * name,
4745 unsigned offset,
4746 unsigned fieldSize)
4747{
4748 TraverseNgenHash<EETypeHashTable, EETypeHashEntry>(pTable,
4749 name,
4750 offset,
4751 fieldSize,
4752 true,
4753 &NativeImageDumper::TraverseTypeHashEntry,
4754 NULL);
4755}
4756
4757void NativeImageDumper::TraverseInstMethodHashEntry(void *pContext, PTR_InstMethodHashEntry pEntry, bool saveClasses)
4758{
4759 PTR_Module pModule((TADDR)pContext);
4760
4761 IF_OPT(SLIM_MODULE_TBLS)
4762 {
4763 DisplayStartStructure("InstMethodHashEntry",
4764 DPtrToPreferredAddr(pEntry),
4765 sizeof(InstMethodHashEntry), SLIM_MODULE_TBLS);
4766 }
4767
4768 IF_OPT_OR(SLIM_MODULE_TBLS, METHODDESCS)
4769 {
4770 IF_OPT(METHODDESCS)
4771 {
4772 PTR_MethodDesc md = pEntry->GetMethod();
4773 _ASSERTE(md != NULL);
4774
4775 //if we want methoddescs, write the data field as a
4776 //structure with the whole contents of the method desc.
4777 m_display->StartVStructureWithOffset("data", offsetof(InstMethodHashEntry, data),
4778 sizeof(pEntry->data));
4779 DumpMethodDesc(md, pModule);
4780 DisplayEndVStructure(ALWAYS); //data
4781 }
4782 else
4783 {
4784 PTR_MethodDesc md = pEntry->GetMethod();
4785 WriteFieldMethodDesc(data, md,
4786 InstMethodHashEntry, ALWAYS);
4787 }
4788 }
4789 else
4790 CoverageRead(PTR_TO_TADDR(pEntry), sizeof(*pEntry));
4791
4792 IF_OPT(SLIM_MODULE_TBLS)
4793 {
4794 DisplayEndStructure(SLIM_MODULE_TBLS);
4795 }
4796}
4797
4798void NativeImageDumper::TraverseStubMethodHashEntry(void *pContext, PTR_StubMethodHashEntry pEntry, bool saveClasses)
4799{
4800 PTR_Module pModule((TADDR)pContext);
4801
4802 IF_OPT(SLIM_MODULE_TBLS)
4803 {
4804 DisplayStartStructure("StubMethodHashEntry",
4805 DPtrToPreferredAddr(pEntry),
4806 sizeof(StubMethodHashEntry), SLIM_MODULE_TBLS);
4807 }
4808
4809 IF_OPT_OR(SLIM_MODULE_TBLS, METHODDESCS)
4810 {
4811 PTR_MethodDesc md = pEntry->GetMethod();
4812 _ASSERTE(md != NULL);
4813
4814 PTR_MethodDesc stub = pEntry->GetStubMethod();
4815 _ASSERTE(stub != NULL);
4816
4817 IF_OPT(METHODDESCS)
4818 {
4819 //if we want methoddescs, write the data fields as a
4820 //structure with the whole contents of the method desc.
4821 m_display->StartVStructureWithOffset("pMD", offsetof(StubMethodHashEntry, pMD),
4822 sizeof(pEntry->pMD));
4823 DumpMethodDesc(md, pModule);
4824 DisplayEndVStructure(ALWAYS); //pMD
4825
4826 m_display->StartVStructureWithOffset("pStubMD", offsetof(StubMethodHashEntry, pStubMD),
4827 sizeof(pEntry->pStubMD));
4828 DumpMethodDesc(stub, pModule);
4829 DisplayEndVStructure(ALWAYS); //pStubMD
4830 }
4831 else
4832 {
4833 WriteFieldMethodDesc(pMD, md,
4834 StubMethodHashEntry, ALWAYS);
4835 WriteFieldMethodDesc(pStubMD, stub,
4836 StubMethodHashEntry, ALWAYS);
4837 }
4838 }
4839 else
4840 CoverageRead(PTR_TO_TADDR(pEntry), sizeof(*pEntry));
4841
4842 IF_OPT(SLIM_MODULE_TBLS)
4843 {
4844 DisplayEndStructure(SLIM_MODULE_TBLS);
4845 }
4846}
4847
4848void NativeImageDumper::TraverseInstMethodHash(PTR_InstMethodHashTable pTable,
4849 const char * name,
4850 unsigned fieldOffset,
4851 unsigned fieldSize,
4852 PTR_Module module)
4853{
4854 TraverseNgenHash<InstMethodHashTable, InstMethodHashEntry>(pTable,
4855 name,
4856 fieldOffset,
4857 fieldSize,
4858 true,
4859 &NativeImageDumper::TraverseInstMethodHashEntry,
4860 (void*)dac_cast<TADDR>(module));
4861}
4862
4863void NativeImageDumper::TraverseStubMethodHash(PTR_StubMethodHashTable pTable,
4864 const char * name,
4865 unsigned fieldOffset,
4866 unsigned fieldSize,
4867 PTR_Module module)
4868{
4869 TraverseNgenHash<StubMethodHashTable, StubMethodHashEntry>(pTable,
4870 name,
4871 fieldOffset,
4872 fieldSize,
4873 true,
4874 &NativeImageDumper::TraverseStubMethodHashEntry,
4875 (void*)dac_cast<TADDR>(module));
4876}
4877
4878const NativeImageDumper::Dependency *
4879NativeImageDumper::GetDependencyForModule( PTR_Module module )
4880{
4881 for( COUNT_T i = 0; i < m_numDependencies; ++i )
4882 {
4883 if( m_dependencies[i].pModule == module )
4884 return &m_dependencies[i];
4885 }
4886 return NULL;
4887}
4888
4889#if 0
4890const NativeImageDumper::Import *
4891NativeImageDumper::GetImportForPointer( TADDR ptr )
4892{
4893 for( int i = 0; i < m_numImports; ++i )
4894 {
4895 const Import * import = &m_imports[i];
4896 if( import->dependency->pPreferredBase == NULL )
4897 continue;
4898 if( import->dependency->pPreferredBase <= ptr
4899 && ((import->dependency->pPreferredBase
4900 + import->dependency->size) > ptr) )
4901 {
4902 //found the right target
4903 return import;
4904 }
4905 }
4906 return NULL;
4907}
4908#endif
4909const NativeImageDumper::Dependency *
4910NativeImageDumper::GetDependencyForPointer( TADDR ptr )
4911{
4912 for( COUNT_T i = 0; i < m_numDependencies; ++i )
4913 {
4914 const Dependency * dependency = &m_dependencies[i];
4915 if( dependency->pLoadedAddress == NULL )
4916 continue;
4917 if( dependency->pLoadedAddress <= ptr
4918 && ((dependency->pLoadedAddress + dependency->size) > ptr) )
4919 {
4920 //found the right target
4921 return dependency;
4922 }
4923 }
4924 return NULL;
4925}
4926
4927void NativeImageDumper::DictionaryToArgString( PTR_Dictionary dictionary, unsigned numArgs, SString& buf )
4928{
4929 //this can be called with numArgs == 0 for value type instantiations.
4930 buf.Append( W("<") );
4931
4932 for( unsigned i = 0; i < numArgs; ++i )
4933 {
4934 if( i > 0 )
4935 buf.Append( W(",") );
4936
4937 TypeHandle th = dictionary->GetInstantiation()[i].GetValue();
4938 if( CORCOMPILE_IS_POINTER_TAGGED(th.AsTAddr()) )
4939 {
4940 if (!isSelf(GetDependencyForPointer(PTR_TO_TADDR(dictionary))))
4941 {
4942 //this is an RVA from another hardbound dependency. We cannot decode it
4943 buf.Append(W("OUT_OF_MODULE_FIXUP"));
4944 }
4945 else
4946 {
4947 RVA rva = CORCOMPILE_UNTAG_TOKEN(th.AsTAddr());
4948 FixupBlobToString(rva, buf);
4949 }
4950 }
4951 else
4952 {
4953 TypeHandleToString( th, buf );
4954 }
4955 }
4956 buf.Append( W(">") );
4957}
4958
4959void NativeImageDumper::MethodTableToString( PTR_MethodTable mt, SString& buf )
4960{
4961 bool hasCompleteExtents = true;
4962 IF_OPT(DISABLE_NAMES)
4963 {
4964 buf.Append( W("Disabled") );
4965 return;
4966 }
4967 mdToken token = mdTokenNil;
4968 if( mt == NULL )
4969 buf.Append( W("mdTypeDefNil") );
4970 else
4971 {
4972 _ASSERTE(!CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)));
4973 const Dependency * dependency;
4974 if( !mt->IsClassPointerValid() )
4975 {
4976 if( isSelf(GetDependencyForPointer(PTR_TO_TADDR(mt))) )
4977 {
4978
4979 hasCompleteExtents = false;
4980 RVA rva = CORCOMPILE_UNTAG_TOKEN(mt->GetCanonicalMethodTableFixup());
4981 PTR_CCOR_SIGNATURE sig = (TADDR) m_decoder.GetRvaData(rva);
4982
4983 BYTE kind = *sig++;
4984
4985 if (kind & ENCODE_MODULE_OVERRIDE)
4986 {
4987 /* int moduleIndex = */ DacSigUncompressData(sig);
4988 kind &= ~ENCODE_MODULE_OVERRIDE;
4989 }
4990
4991 _ASSERTE(kind == ENCODE_TYPE_HANDLE);
4992 CorElementType et = DacSigUncompressElementType(sig);
4993 if( et == ELEMENT_TYPE_GENERICINST )
4994 {
4995 //generic instances have another element type
4996 et = DacSigUncompressElementType(sig);
4997 }
4998 if (et == ELEMENT_TYPE_VALUETYPE || et == ELEMENT_TYPE_CLASS)
4999 {
5000 token = DacSigUncompressToken(sig);
5001 }
5002 else
5003 {
5004 // Arrays, etc.
5005 token = mdtTypeDef;
5006 }
5007 dependency = GetDependencyForFixup(rva);
5008 }
5009 else
5010 {
5011 //this is an RVA from another hardbound dependency. We cannot decode it
5012 buf.Append(W("OUT_OF_MODULE_FIXUP"));
5013 return;
5014 }
5015 }
5016 else
5017 {
5018 token = mt->GetCl();
5019 dependency = GetDependencyFromMT(mt);
5020 }
5021
5022 if( !isSelf(dependency) )
5023 {
5024 AppendTokenName( dependency->entry->dwAssemblyRef, buf,
5025 m_manifestImport );
5026 buf.Append(W("!"));
5027 }
5028
5029 _ASSERTE(dependency->pImport);
5030 if( token == mdtTypeDef )
5031 buf.Append( W("No Token") );
5032 else
5033 AppendTokenName( token, buf, dependency->pImport );
5034
5035 if( mt->HasPerInstInfo() )
5036 {
5037 unsigned numDicts;
5038 if( hasCompleteExtents )
5039 {
5040 numDicts = mt->GetNumDicts();
5041 _ASSERTE(numDicts == CountDictionariesInClass(token, dependency->pImport));
5042 }
5043 else
5044 {
5045 numDicts = (DWORD)CountDictionariesInClass(token, dependency->pImport);
5046 }
5047
5048 TADDR base = dac_cast<TADDR>(&(mt->GetPerInstInfo()[numDicts-1]));
5049
5050 PTR_Dictionary dictionary( MethodTable::PerInstInfoElem_t::GetValueAtPtr(base) );
5051 unsigned numArgs = mt->GetNumGenericArgs();
5052
5053 DictionaryToArgString( dictionary, numArgs, buf );
5054 }
5055 }
5056}
5057
5058mdToken NativeImageDumper::ConvertToTypeDef( mdToken typeToken, IMetaDataImport2* (&pImport) )
5059{
5060 _ASSERTE( (TypeFromToken(typeToken) == mdtTypeDef) || (TypeFromToken(typeToken) == mdtTypeRef)
5061 || (TypeFromToken(typeToken) == mdtTypeSpec) );
5062 if( mdtTypeDef == TypeFromToken(typeToken) )
5063 return typeToken;
5064 if( mdtTypeRef == TypeFromToken(typeToken) )
5065 {
5066 //convert the ref to a def.
5067 mdToken scope;
5068 WCHAR trName[MAX_CLASS_NAME];
5069 ULONG trNameLen;
5070 IfFailThrow(pImport->GetTypeRefProps(typeToken, &scope, trName, _countof(trName), &trNameLen));
5071 _ASSERTE(trName[trNameLen-1] == 0);
5072
5073 //scope is now a moduleRef or assemblyRef. Find the IMetaData import for that Ref
5074 /* REVISIT_TODO Fri 10/6/2006
5075 * How do I handle moduleRefs?
5076 */
5077 _ASSERTE(TypeFromToken(scope) == mdtAssemblyRef);
5078 ReleaseHolder<IMetaDataAssemblyImport> pAssemblyImport;
5079 IfFailThrow(pImport->QueryInterface(IID_IMetaDataAssemblyImport,
5080 (void **)&pAssemblyImport));
5081 NativeImageDumper::Dependency * dep = GetDependency(scope, pAssemblyImport);
5082
5083 pImport = dep->pImport;
5084
5085 /* REVISIT_TODO Fri 10/6/2006
5086 * Does this work for inner types?
5087 */
5088 //now I have the correct MetaData. Find the typeDef
5089 HRESULT hr = pImport->FindTypeDefByName(trName, mdTypeDefNil, &typeToken);
5090 while (hr == CLDB_E_RECORD_NOTFOUND)
5091 {
5092 // No matching TypeDef, try ExportedType
5093 pAssemblyImport = NULL;
5094 IfFailThrow(pImport->QueryInterface(IID_IMetaDataAssemblyImport,
5095 (void **)&pAssemblyImport));
5096 mdExportedType tkExportedType = mdExportedTypeNil;
5097 IfFailThrow(pAssemblyImport->FindExportedTypeByName(trName, mdExportedTypeNil, &tkExportedType));
5098 mdToken tkImplementation;
5099 IfFailThrow(pAssemblyImport->GetExportedTypeProps(tkExportedType, NULL, 0, NULL, &tkImplementation, NULL, NULL));
5100 dep = GetDependency(tkImplementation, pAssemblyImport);
5101
5102 pImport = dep->pImport;
5103 hr = pImport->FindTypeDefByName(trName, mdTypeDefNil, &typeToken);
5104 }
5105 IfFailThrow(hr);
5106 }
5107 else
5108 {
5109 PCCOR_SIGNATURE pSig;
5110 ULONG cbSig;
5111 IfFailThrow(pImport->GetTypeSpecFromToken(typeToken, &pSig, &cbSig));
5112 //GENERICINST (CLASS|VALUETYPE) typeDefOrRef
5113 CorElementType et = CorSigUncompressElementType(pSig);
5114 _ASSERTE(et == ELEMENT_TYPE_GENERICINST);
5115 et = CorSigUncompressElementType(pSig);
5116 _ASSERTE((et == ELEMENT_TYPE_CLASS) || (et == ELEMENT_TYPE_VALUETYPE));
5117 typeToken = CorSigUncompressToken(pSig);
5118 }
5119
5120 //we just removed one level of indirection. We still might have a ref or spec.
5121 typeToken = ConvertToTypeDef(typeToken, pImport);
5122 _ASSERTE(TypeFromToken(typeToken) == mdtTypeDef);
5123 return typeToken;
5124}
5125
5126SIZE_T NativeImageDumper::CountDictionariesInClass( mdToken typeToken, IMetaDataImport2 * pImport )
5127{
5128 SIZE_T myDicts; //either 0 or 1
5129
5130 _ASSERTE((TypeFromToken(typeToken) == mdtTypeDef) || (TypeFromToken(typeToken) == mdtTypeRef)
5131 || (TypeFromToken(typeToken) == mdtTypeSpec));
5132
5133
5134 //for refs and specs, convert to a def. This is a nop for defs.
5135 typeToken = ConvertToTypeDef(typeToken, pImport);
5136
5137 _ASSERTE(TypeFromToken(typeToken) == mdtTypeDef);
5138
5139
5140 //count the number of generic arguments. If there are any, then we have a dictionary.
5141 HCORENUM hEnum = NULL;
5142 mdGenericParam params[2];
5143 ULONG numParams = 0;
5144 IfFailThrow(pImport->EnumGenericParams(&hEnum, typeToken, params, _countof(params), &numParams));
5145 myDicts = (numParams > 0) ? 1 : 0;
5146
5147 pImport->CloseEnum(hEnum);
5148
5149 //get my parent for the recursive call.
5150 mdToken parent;
5151 IfFailThrow(pImport->GetTypeDefProps(typeToken, NULL, 0, NULL, NULL, &parent));
5152 return myDicts + (IsNilToken(parent) ? 0 : CountDictionariesInClass(parent, pImport));
5153}
5154
5155const NativeImageDumper::EnumMnemonics s_Subsystems[] =
5156{
5157#define S_ENTRY(f,v) NativeImageDumper::EnumMnemonics(f, 0, v)
5158 S_ENTRY(IMAGE_SUBSYSTEM_UNKNOWN, W("Unknown")),
5159 S_ENTRY(IMAGE_SUBSYSTEM_NATIVE, W("Native")),
5160 S_ENTRY(IMAGE_SUBSYSTEM_WINDOWS_CUI, W("Windows CUI")),
5161 S_ENTRY(IMAGE_SUBSYSTEM_WINDOWS_GUI, W("Windows GUI")),
5162 S_ENTRY(IMAGE_SUBSYSTEM_OS2_CUI, W("OS/2 CUI")),
5163 S_ENTRY(IMAGE_SUBSYSTEM_POSIX_CUI, W("POSIX CUI")),
5164 S_ENTRY(IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, W("WinCE GUI")),
5165 S_ENTRY(IMAGE_SUBSYSTEM_XBOX, W("XBox"))
5166#undef S_ENTRY
5167};
5168
5169const NativeImageDumper::EnumMnemonics s_CorCompileHdrFlags[] =
5170{
5171#define CCHF_ENTRY(f) NativeImageDumper::EnumMnemonics(f, W(#f))
5172 CCHF_ENTRY(CORCOMPILE_HEADER_HAS_SECURITY_DIRECTORY),
5173 CCHF_ENTRY(CORCOMPILE_HEADER_IS_IBC_OPTIMIZED),
5174 CCHF_ENTRY(CORCOMPILE_HEADER_IS_READY_TO_RUN),
5175#undef CCHF_ENTRY
5176};
5177
5178const NativeImageDumper::EnumMnemonics s_CorPEKind[] =
5179{
5180#define CPEK_ENTRY(f) NativeImageDumper::EnumMnemonics(f, W(#f))
5181 CPEK_ENTRY(peNot),
5182 CPEK_ENTRY(peILonly),
5183 CPEK_ENTRY(pe32BitRequired),
5184 CPEK_ENTRY(pe32Plus),
5185 CPEK_ENTRY(pe32Unmanaged),
5186 CPEK_ENTRY(pe32BitPreferred)
5187#undef CPEK_ENTRY
5188};
5189const NativeImageDumper::EnumMnemonics s_IFH_Machine[] =
5190{
5191#define IFH_ENTRY(f) NativeImageDumper::EnumMnemonics(f, 0, W(#f))
5192 IFH_ENTRY(IMAGE_FILE_MACHINE_UNKNOWN),
5193 IFH_ENTRY(IMAGE_FILE_MACHINE_I386),
5194 IFH_ENTRY(IMAGE_FILE_MACHINE_AMD64),
5195 IFH_ENTRY(IMAGE_FILE_MACHINE_ARMNT),
5196#undef IFH_ENTRY
5197};
5198
5199const NativeImageDumper::EnumMnemonics s_IFH_Characteristics[] =
5200{
5201#define IFH_ENTRY(f) NativeImageDumper::EnumMnemonics(f, W(#f))
5202 IFH_ENTRY(IMAGE_FILE_RELOCS_STRIPPED),
5203 IFH_ENTRY(IMAGE_FILE_EXECUTABLE_IMAGE),
5204 IFH_ENTRY(IMAGE_FILE_LINE_NUMS_STRIPPED),
5205 IFH_ENTRY(IMAGE_FILE_LOCAL_SYMS_STRIPPED),
5206 IFH_ENTRY(IMAGE_FILE_AGGRESIVE_WS_TRIM),
5207 IFH_ENTRY(IMAGE_FILE_LARGE_ADDRESS_AWARE),
5208 IFH_ENTRY(IMAGE_FILE_BYTES_REVERSED_LO),
5209 IFH_ENTRY(IMAGE_FILE_32BIT_MACHINE),
5210 IFH_ENTRY(IMAGE_FILE_DEBUG_STRIPPED),
5211 IFH_ENTRY(IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
5212 IFH_ENTRY(IMAGE_FILE_NET_RUN_FROM_SWAP),
5213 IFH_ENTRY(IMAGE_FILE_SYSTEM),
5214 IFH_ENTRY(IMAGE_FILE_DLL),
5215 IFH_ENTRY(IMAGE_FILE_UP_SYSTEM_ONLY),
5216 IFH_ENTRY(IMAGE_FILE_BYTES_REVERSED_HI),
5217#undef IFH_ENTRY
5218};
5219
5220const NativeImageDumper::EnumMnemonics s_ImportSectionType[] =
5221{
5222#define IST_ENTRY(f) NativeImageDumper::EnumMnemonics(f, 0, W(#f))
5223 IST_ENTRY(CORCOMPILE_IMPORT_TYPE_UNKNOWN),
5224 IST_ENTRY(CORCOMPILE_IMPORT_TYPE_EXTERNAL_METHOD),
5225 IST_ENTRY(CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH),
5226 IST_ENTRY(CORCOMPILE_IMPORT_TYPE_STRING_HANDLE),
5227 IST_ENTRY(CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE),
5228 IST_ENTRY(CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE),
5229 IST_ENTRY(CORCOMPILE_IMPORT_TYPE_VIRTUAL_METHOD),
5230#undef IST_ENTRY
5231};
5232
5233const NativeImageDumper::EnumMnemonics s_ImportSectionFlags[] =
5234{
5235#define IST_FLAGS(f) NativeImageDumper::EnumMnemonics(f, W(#f))
5236 IST_FLAGS(CORCOMPILE_IMPORT_FLAGS_EAGER),
5237 IST_FLAGS(CORCOMPILE_IMPORT_FLAGS_CODE),
5238 IST_FLAGS(CORCOMPILE_IMPORT_FLAGS_PCODE),
5239#undef IST_FLAGS
5240};
5241
5242void NativeImageDumper::DumpNativeHeader()
5243{
5244 PTR_CORCOMPILE_HEADER nativeHeader(m_decoder.GetNativeHeader());
5245
5246 IF_OPT(NATIVE_INFO)
5247 {
5248
5249#define WRITE_NATIVE_FIELD( name ) m_display->WriteFieldAddress(\
5250 # name, offsetof(CORCOMPILE_HEADER, name), \
5251 fieldsize(CORCOMPILE_HEADER, name), \
5252 RvaToDisplay( nativeHeader-> name . VirtualAddress ), \
5253 nativeHeader-> name . Size )
5254
5255 m_display->StartStructure( "CORCOMPILE_HEADER",
5256 DPtrToPreferredAddr(nativeHeader),
5257 sizeof(*nativeHeader) );
5258
5259 DisplayWriteFieldUInt( Signature, nativeHeader->Signature, CORCOMPILE_HEADER, ALWAYS );
5260 DisplayWriteFieldUInt( MajorVersion, nativeHeader->MajorVersion, CORCOMPILE_HEADER, ALWAYS );
5261 DisplayWriteFieldUInt( MinorVersion, nativeHeader->MinorVersion, CORCOMPILE_HEADER, ALWAYS );
5262
5263 WRITE_NATIVE_FIELD(HelperTable);
5264
5265 WRITE_NATIVE_FIELD(ImportSections);
5266 PTR_CORCOMPILE_IMPORT_SECTION pImportSections =
5267 nativeHeader->ImportSections.VirtualAddress
5268 + PTR_TO_TADDR(m_decoder.GetBase());
5269 DisplayStartArray( "ImportSections", NULL, ALWAYS );
5270 for( COUNT_T i = 0; i < nativeHeader->ImportSections.Size
5271 / sizeof(*pImportSections); ++i )
5272 {
5273 DisplayStartStructure( "CORCOMPILE_IMPORT_SECTION",
5274 DPtrToPreferredAddr(pImportSections + i),
5275 sizeof(pImportSections[i]), ALWAYS );
5276 DisplayWriteElementAddress( "Section",
5277 RvaToDisplay(pImportSections[i].Section.VirtualAddress),
5278 pImportSections[i].Section.Size, ALWAYS );
5279
5280 DisplayWriteFieldEnumerated( Flags, pImportSections[i].Flags,
5281 CORCOMPILE_IMPORT_SECTION, s_ImportSectionFlags, W(", "), ALWAYS );
5282 DisplayWriteFieldEnumerated( Type, pImportSections[i].Type,
5283 CORCOMPILE_IMPORT_SECTION, s_ImportSectionType, W(""), ALWAYS );
5284
5285 DisplayWriteFieldUInt( EntrySize, pImportSections[i].EntrySize,
5286 CORCOMPILE_IMPORT_SECTION, ALWAYS );
5287 DisplayWriteFieldUInt( Signatures, pImportSections[i].Signatures,
5288 CORCOMPILE_IMPORT_SECTION, ALWAYS );
5289 DisplayWriteFieldUInt( AuxiliaryData, pImportSections[i].AuxiliaryData,
5290 CORCOMPILE_IMPORT_SECTION, ALWAYS );
5291 DisplayEndStructure( ALWAYS ); //PTR_CORCOMPILE_IMPORT_SECTION
5292
5293 }
5294 DisplayEndArray( NULL, ALWAYS ); //delayLoads
5295
5296 WRITE_NATIVE_FIELD(VersionInfo);
5297 WRITE_NATIVE_FIELD(DebugMap);
5298 WRITE_NATIVE_FIELD(ModuleImage);
5299 WRITE_NATIVE_FIELD(CodeManagerTable);
5300 WRITE_NATIVE_FIELD(ProfileDataList);
5301 WRITE_NATIVE_FIELD(ManifestMetaData);
5302
5303 WRITE_NATIVE_FIELD(VirtualSectionsTable);
5304 DisplayStartArray( "VirtualSections", W("%-48s%s"), SLIM_MODULE_TBLS );
5305 PTR_CORCOMPILE_VIRTUAL_SECTION_INFO sects( nativeHeader->VirtualSectionsTable.VirtualAddress + PTR_TO_TADDR(m_decoder.GetBase()) );
5306 COUNT_T numVirtualSections = nativeHeader->VirtualSectionsTable.Size / sizeof (CORCOMPILE_VIRTUAL_SECTION_INFO);
5307
5308 for( COUNT_T i = 0; i < numVirtualSections; ++i )
5309 {
5310 TempBuffer sectionNameBuf;
5311 TempBuffer sectionFlags;
5312 StackScratchBuffer scratch;
5313
5314 sectionNameBuf.Append(g_sectionNames[VirtualSectionData::VirtualSectionType(sects[i].SectionType)]);
5315
5316 EnumFlagsToString( sects[i].SectionType, s_virtualSectionFlags, dim(s_virtualSectionFlags),
5317 W(" | "), sectionFlags);
5318
5319 sectionNameBuf.Append(W(" ["));
5320 sectionNameBuf.Append(sectionFlags);
5321 sectionNameBuf.Append(W("]"));
5322
5323 DisplayStartElement( "Section", SLIM_MODULE_TBLS );
5324 DisplayWriteElementString("Name", sectionNameBuf.GetANSI(scratch), SLIM_MODULE_TBLS);
5325
5326 DisplayWriteElementAddress( "Address",
5327 RvaToDisplay(sects[i].VirtualAddress),
5328 sects[i].Size,
5329 SLIM_MODULE_TBLS );
5330 DisplayEndElement( SLIM_MODULE_TBLS ); //Section
5331 }
5332 DisplayEndArray( "Total VirtualSections", SLIM_MODULE_TBLS );
5333
5334 WRITE_NATIVE_FIELD(EEInfoTable);
5335
5336#undef WRITE_NATIVE_FIELD
5337 DisplayWriteFieldEnumerated( Flags, nativeHeader->Flags,
5338 CORCOMPILE_HEADER, s_CorCompileHdrFlags, W(", "),
5339 NATIVE_INFO );
5340
5341 DisplayWriteFieldEnumerated( PEKind, nativeHeader->PEKind,
5342 CORCOMPILE_HEADER, s_CorPEKind, W(", "),
5343 NATIVE_INFO );
5344
5345 DisplayWriteFieldEnumerated( COR20Flags, nativeHeader->COR20Flags,
5346 CORCOMPILE_HEADER, s_CorHdrFlags, W(", "),
5347 NATIVE_INFO );
5348
5349 DisplayWriteFieldEnumerated( Machine, nativeHeader->Machine,
5350 CORCOMPILE_HEADER, s_IFH_Machine,
5351 W(""), NATIVE_INFO );
5352 DisplayWriteFieldEnumerated( Characteristics,
5353 nativeHeader->Characteristics,
5354 CORCOMPILE_HEADER, s_IFH_Characteristics,
5355 W(", "), NATIVE_INFO );
5356
5357 m_display->EndStructure(); //CORCOMPILE_HEADER
5358 }
5359}
5360
5361const NativeImageDumper::EnumMnemonics s_RelocType[] =
5362{
5363#define REL_ENTRY(x) NativeImageDumper::EnumMnemonics( x, 0, W(#x))
5364 REL_ENTRY(IMAGE_REL_BASED_ABSOLUTE),
5365 REL_ENTRY(IMAGE_REL_BASED_HIGHLOW),
5366 REL_ENTRY(IMAGE_REL_BASED_DIR64),
5367 REL_ENTRY(IMAGE_REL_BASED_THUMB_MOV32),
5368#undef REL_ENTRY
5369};
5370
5371void NativeImageDumper::DumpBaseRelocs()
5372{
5373 COUNT_T size;
5374 TADDR data;
5375
5376 data = m_decoder.GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_BASERELOC, &size);
5377
5378 if (size != 0)
5379 {
5380 DisplayStartStructure( "Relocations", DataPtrToDisplay(data), size,
5381 ALWAYS );
5382
5383 while (size != 0)
5384 {
5385 IMAGE_BASE_RELOCATION * pBaseRelocation = dac_cast<DPTR(IMAGE_BASE_RELOCATION)>(data);
5386 _ASSERTE(size >= pBaseRelocation->SizeOfBlock);
5387
5388 SIZE_T rel = sizeof(IMAGE_BASE_RELOCATION);
5389 while (rel < pBaseRelocation->SizeOfBlock)
5390 {
5391 USHORT typeOffset = *PTR_USHORT(data + rel);
5392
5393 DisplayStartElement( "Entry", ALWAYS );
5394
5395 DisplayWriteElementPointer( "Address", RvaToDisplay(pBaseRelocation->VirtualAddress + (typeOffset & 0xFFF)), ALWAYS );
5396
5397 DisplayWriteElementEnumerated( "Type", (typeOffset >> 12),
5398 s_RelocType, W(", "), ALWAYS );
5399
5400 DisplayEndElement( ALWAYS ); //Entry
5401
5402 rel += sizeof(USHORT);
5403 }
5404
5405 data += pBaseRelocation->SizeOfBlock;
5406 size -= pBaseRelocation->SizeOfBlock;
5407 }
5408
5409 DisplayEndStructure( ALWAYS ); //Relocations
5410 }
5411}
5412
5413void NativeImageDumper::DumpHelperTable()
5414{
5415 COUNT_T size;
5416 TADDR data;
5417
5418 data = TO_TADDR(m_decoder.GetNativeHelperTable(&size));
5419 if( size != 0 )
5420 {
5421 DisplayStartStructure( "HelperTable", DataPtrToDisplay(data), size,
5422 ALWAYS );
5423
5424 TADDR curEntry = data;
5425 TADDR tableEnd = data + size;
5426
5427 while (curEntry < tableEnd)
5428 {
5429 DWORD dwHelper = *PTR_DWORD(curEntry);
5430
5431 int iHelper = (USHORT)dwHelper;
5432 _ASSERTE(iHelper < CORINFO_HELP_COUNT);
5433
5434 DisplayStartStructure( "Helper",
5435 DataPtrToDisplay(curEntry), (dwHelper & CORCOMPILE_HELPER_PTR) ? sizeof(TADDR) : HELPER_TABLE_ENTRY_LEN,
5436 ALWAYS );
5437
5438 DisplayWriteElementUInt( "dwHelper", dwHelper, ALWAYS );
5439 DisplayWriteElementString( "Name", g_helperNames[iHelper], ALWAYS );
5440
5441 DisplayEndStructure( ALWAYS ); //Helper
5442
5443 curEntry += (dwHelper & CORCOMPILE_HELPER_PTR) ? sizeof(TADDR) : HELPER_TABLE_ENTRY_LEN;
5444 }
5445
5446 DisplayEndStructure( ALWAYS ); //HelperTable
5447 }
5448}
5449
5450// TODO: fix these to work with the updated flags in MethodTable, AND to understand
5451// the new overloading of component size...
5452
5453NativeImageDumper::EnumMnemonics s_MTFlagsLow[] =
5454{
5455#define MTFLAG_ENTRY(x) \
5456 NativeImageDumper::EnumMnemonics(MethodTable::enum_flag_ ## x, W(#x))
5457
5458 MTFLAG_ENTRY(UNUSED_ComponentSize_1),
5459 MTFLAG_ENTRY(StaticsMask),
5460 MTFLAG_ENTRY(StaticsMask_NonDynamic),
5461 MTFLAG_ENTRY(StaticsMask_Dynamic),
5462 MTFLAG_ENTRY(StaticsMask_Generics),
5463 MTFLAG_ENTRY(StaticsMask_CrossModuleGenerics),
5464 MTFLAG_ENTRY(NotInPZM),
5465 MTFLAG_ENTRY(GenericsMask),
5466 MTFLAG_ENTRY(GenericsMask_NonGeneric),
5467 MTFLAG_ENTRY(GenericsMask_GenericInst),
5468 MTFLAG_ENTRY(GenericsMask_SharedInst),
5469 MTFLAG_ENTRY(GenericsMask_TypicalInst),
5470 MTFLAG_ENTRY(HasVariance),
5471 MTFLAG_ENTRY(HasDefaultCtor),
5472 MTFLAG_ENTRY(HasPreciseInitCctors),
5473#if defined(FEATURE_HFA)
5474 MTFLAG_ENTRY(IsHFA),
5475#endif // FEATURE_HFA
5476#if defined(UNIX_AMD64_ABI)
5477 MTFLAG_ENTRY(IsRegStructPassed),
5478#endif // UNIX_AMD64_ABI
5479 MTFLAG_ENTRY(IsByRefLike),
5480 MTFLAG_ENTRY(UNUSED_ComponentSize_5),
5481 MTFLAG_ENTRY(UNUSED_ComponentSize_6),
5482 MTFLAG_ENTRY(UNUSED_ComponentSize_7),
5483#undef MTFLAG_ENTRY
5484};
5485
5486NativeImageDumper::EnumMnemonics s_MTFlagsHigh[] =
5487{
5488#define MTFLAG_ENTRY(x) \
5489 NativeImageDumper::EnumMnemonics(MethodTable::enum_flag_ ## x, W(#x))
5490
5491#define MTFLAG_CATEGORY_ENTRY(x) \
5492 NativeImageDumper::EnumMnemonics(MethodTable::enum_flag_Category_ ## x, MethodTable::enum_flag_Category_Mask, W("Category_") W(#x))
5493
5494#define MTFLAG_CATEGORY_ENTRY_WITH_MASK(x, m) \
5495 NativeImageDumper::EnumMnemonics(MethodTable::enum_flag_Category_ ## x, MethodTable::enum_flag_Category_ ## m, W("Category_") W(#x))
5496
5497 MTFLAG_CATEGORY_ENTRY(Class),
5498 MTFLAG_CATEGORY_ENTRY(Unused_1),
5499 MTFLAG_CATEGORY_ENTRY(Unused_2),
5500 MTFLAG_CATEGORY_ENTRY(Unused_3),
5501 MTFLAG_CATEGORY_ENTRY(ValueType),
5502 MTFLAG_CATEGORY_ENTRY(Nullable),
5503 MTFLAG_CATEGORY_ENTRY(PrimitiveValueType),
5504 MTFLAG_CATEGORY_ENTRY(TruePrimitive),
5505
5506 MTFLAG_CATEGORY_ENTRY(Interface),
5507 MTFLAG_CATEGORY_ENTRY(Unused_4),
5508 MTFLAG_CATEGORY_ENTRY(Unused_5),
5509 MTFLAG_CATEGORY_ENTRY(Unused_6),
5510
5511 MTFLAG_CATEGORY_ENTRY_WITH_MASK(Array, Array_Mask),
5512 MTFLAG_CATEGORY_ENTRY_WITH_MASK(IfArrayThenSzArray, IfArrayThenSzArray),
5513
5514#undef MTFLAG_CATEGORY_ENTRY_WITH_MASK
5515#undef MTFLAG_CATEGORY_ENTRY
5516
5517 MTFLAG_ENTRY(HasFinalizer),
5518 MTFLAG_ENTRY(IfNotInterfaceThenMarshalable),
5519#if defined(FEATURE_COMINTEROP)
5520 MTFLAG_ENTRY(IfInterfaceThenHasGuidInfo),
5521#endif
5522#if defined(FEATURE_ICASTABLE)
5523 MTFLAG_ENTRY(ICastable),
5524#endif
5525 MTFLAG_ENTRY(HasIndirectParent),
5526 MTFLAG_ENTRY(ContainsPointers),
5527 MTFLAG_ENTRY(HasTypeEquivalence),
5528#if defined(FEATURE_COMINTEROP)
5529 MTFLAG_ENTRY(HasRCWPerTypeData),
5530#endif
5531 MTFLAG_ENTRY(HasCriticalFinalizer),
5532 MTFLAG_ENTRY(Collectible),
5533 MTFLAG_ENTRY(ContainsGenericVariables),
5534#if defined(FEATURE_COMINTEROP)
5535 MTFLAG_ENTRY(ComObject),
5536#endif
5537 MTFLAG_ENTRY(HasComponentSize),
5538#undef MTFLAG_ENTRY
5539};
5540
5541
5542NativeImageDumper::EnumMnemonics s_MTFlags2[] =
5543{
5544#define MTFLAG2_ENTRY(x) \
5545 NativeImageDumper::EnumMnemonics(MethodTable::enum_flag_ ## x, W(#x))
5546 MTFLAG2_ENTRY(HasPerInstInfo),
5547 MTFLAG2_ENTRY(HasInterfaceMap),
5548 MTFLAG2_ENTRY(HasDispatchMapSlot),
5549 MTFLAG2_ENTRY(HasNonVirtualSlots),
5550 MTFLAG2_ENTRY(HasModuleOverride),
5551 MTFLAG2_ENTRY(IsZapped),
5552 MTFLAG2_ENTRY(IsPreRestored),
5553 MTFLAG2_ENTRY(HasModuleDependencies),
5554 MTFLAG2_ENTRY(IsIntrinsicType),
5555 MTFLAG2_ENTRY(RequiresDispatchTokenFat),
5556 MTFLAG2_ENTRY(HasCctor),
5557 MTFLAG2_ENTRY(HasCCWTemplate),
5558#ifdef FEATURE_64BIT_ALIGNMENT
5559 MTFLAG2_ENTRY(RequiresAlign8),
5560#endif
5561 MTFLAG2_ENTRY(HasBoxedRegularStatics),
5562 MTFLAG2_ENTRY(HasSingleNonVirtualSlot),
5563 MTFLAG2_ENTRY(DependsOnEquivalentOrForwardedStructs),
5564#undef MTFLAG2_ENTRY
5565};
5566
5567NativeImageDumper::EnumMnemonics s_WriteableMTFlags[] =
5568{
5569#define WMTFLAG_ENTRY(x) \
5570 NativeImageDumper::EnumMnemonics(MethodTableWriteableData::enum_flag_ ## x,\
5571 W(#x))
5572
5573 WMTFLAG_ENTRY(Unrestored),
5574 WMTFLAG_ENTRY(HasApproxParent),
5575 WMTFLAG_ENTRY(UnrestoredTypeKey),
5576 WMTFLAG_ENTRY(IsNotFullyLoaded),
5577 WMTFLAG_ENTRY(DependenciesLoaded),
5578
5579#ifdef _DEBUG
5580 WMTFLAG_ENTRY(ParentMethodTablePointerValid),
5581#endif
5582
5583 WMTFLAG_ENTRY(NGEN_IsFixedUp),
5584 WMTFLAG_ENTRY(NGEN_IsNeedsRestoreCached),
5585 WMTFLAG_ENTRY(NGEN_CachedNeedsRestore),
5586#undef WMTFLAG_ENTRY
5587};
5588
5589static NativeImageDumper::EnumMnemonics s_CorElementType[] =
5590{
5591#define CET_ENTRY(x) NativeImageDumper::EnumMnemonics(ELEMENT_TYPE_ ## x, 0, W("ELEMENT_TYPE_") W(#x))
5592 CET_ENTRY(END),
5593 CET_ENTRY(VOID),
5594 CET_ENTRY(BOOLEAN),
5595 CET_ENTRY(CHAR),
5596 CET_ENTRY(I1),
5597 CET_ENTRY(U1),
5598 CET_ENTRY(I2),
5599 CET_ENTRY(U2),
5600 CET_ENTRY(I4),
5601 CET_ENTRY(U4),
5602 CET_ENTRY(I8),
5603 CET_ENTRY(U8),
5604 CET_ENTRY(R4),
5605 CET_ENTRY(R8),
5606 CET_ENTRY(STRING),
5607 CET_ENTRY(PTR),
5608 CET_ENTRY(BYREF),
5609 CET_ENTRY(VALUETYPE),
5610 CET_ENTRY(CLASS),
5611 CET_ENTRY(VAR),
5612 CET_ENTRY(ARRAY),
5613 CET_ENTRY(GENERICINST),
5614 CET_ENTRY(TYPEDBYREF),
5615 CET_ENTRY(VALUEARRAY_UNSUPPORTED),
5616 CET_ENTRY(I),
5617 CET_ENTRY(U),
5618 CET_ENTRY(R_UNSUPPORTED),
5619 CET_ENTRY(FNPTR),
5620 CET_ENTRY(OBJECT),
5621 CET_ENTRY(SZARRAY),
5622 CET_ENTRY(MVAR),
5623 CET_ENTRY(CMOD_REQD),
5624 CET_ENTRY(CMOD_OPT),
5625 CET_ENTRY(INTERNAL),
5626
5627 CET_ENTRY(SENTINEL),
5628 CET_ENTRY(PINNED),
5629#undef CET_ENTRY
5630};
5631
5632void NativeImageDumper::DoWriteFieldCorElementType( const char * name,
5633 unsigned offset,
5634 unsigned fieldSize,
5635 CorElementType type )
5636{
5637 TempBuffer buf;
5638 EnumFlagsToString( (int)type, s_CorElementType, dim(s_CorElementType),
5639 W(""), buf );
5640 m_display->WriteFieldEnumerated( name, offset, fieldSize, (unsigned)type,
5641 (const WCHAR *) buf );
5642
5643}
5644
5645static NativeImageDumper::EnumMnemonics s_CorTypeAttr[] =
5646{
5647#define CTA_ENTRY(x) NativeImageDumper::EnumMnemonics( x, W(#x) )
5648
5649#define CTA_VISIBILITY_ENTRY(x) NativeImageDumper::EnumMnemonics( x, tdVisibilityMask, W(#x) )
5650 CTA_VISIBILITY_ENTRY(tdNotPublic),
5651 CTA_VISIBILITY_ENTRY(tdPublic),
5652 CTA_VISIBILITY_ENTRY(tdNestedPublic),
5653 CTA_VISIBILITY_ENTRY(tdNestedPrivate),
5654 CTA_VISIBILITY_ENTRY(tdNestedFamily),
5655 CTA_VISIBILITY_ENTRY(tdNestedAssembly),
5656 CTA_VISIBILITY_ENTRY(tdNestedFamANDAssem),
5657 CTA_VISIBILITY_ENTRY(tdNestedFamORAssem),
5658#undef CTA_VISIBILITY_ENTRY
5659
5660 CTA_ENTRY(tdSequentialLayout),
5661 CTA_ENTRY(tdExplicitLayout),
5662
5663 CTA_ENTRY(tdInterface),
5664
5665 CTA_ENTRY(tdAbstract),
5666 CTA_ENTRY(tdSealed),
5667 CTA_ENTRY(tdSpecialName),
5668
5669 CTA_ENTRY(tdImport),
5670 CTA_ENTRY(tdSerializable),
5671
5672 CTA_ENTRY(tdUnicodeClass),
5673 CTA_ENTRY(tdAutoClass),
5674 CTA_ENTRY(tdCustomFormatClass),
5675 CTA_ENTRY(tdCustomFormatMask),
5676
5677 CTA_ENTRY(tdBeforeFieldInit),
5678 CTA_ENTRY(tdForwarder),
5679
5680 CTA_ENTRY(tdRTSpecialName),
5681 CTA_ENTRY(tdHasSecurity)
5682#undef CTA_ENTRY
5683};
5684static NativeImageDumper::EnumMnemonics s_VMFlags[] =
5685{
5686#define VMF_ENTRY(x) NativeImageDumper::EnumMnemonics( EEClass::VMFLAG_ ## x, W(#x) )
5687
5688#ifdef FEATURE_READYTORUN
5689 VMF_ENTRY(LAYOUT_DEPENDS_ON_OTHER_MODULES),
5690#endif
5691 VMF_ENTRY(DELEGATE),
5692 VMF_ENTRY(FIXED_ADDRESS_VT_STATICS),
5693 VMF_ENTRY(HASLAYOUT),
5694 VMF_ENTRY(ISNESTED),
5695 VMF_ENTRY(IS_EQUIVALENT_TYPE),
5696
5697 VMF_ENTRY(HASOVERLAYEDFIELDS),
5698 VMF_ENTRY(HAS_FIELDS_WHICH_MUST_BE_INITED),
5699 VMF_ENTRY(UNSAFEVALUETYPE),
5700
5701 VMF_ENTRY(BESTFITMAPPING_INITED),
5702 VMF_ENTRY(BESTFITMAPPING),
5703 VMF_ENTRY(THROWONUNMAPPABLECHAR),
5704
5705 VMF_ENTRY(NO_GUID),
5706 VMF_ENTRY(HASNONPUBLICFIELDS),
5707 VMF_ENTRY(PREFER_ALIGN8),
5708
5709#ifdef FEATURE_COMINTEROP
5710 VMF_ENTRY(SPARSE_FOR_COMINTEROP),
5711 VMF_ENTRY(HASCOCLASSATTRIB),
5712 VMF_ENTRY(COMEVENTITFMASK),
5713 VMF_ENTRY(PROJECTED_FROM_WINRT),
5714 VMF_ENTRY(EXPORTED_TO_WINRT),
5715#endif // FEATURE_COMINTEROP
5716
5717 VMF_ENTRY(NOT_TIGHTLY_PACKED),
5718 VMF_ENTRY(CONTAINS_METHODIMPLS),
5719#ifdef FEATURE_COMINTEROP
5720 VMF_ENTRY(MARSHALINGTYPE_MASK),
5721 VMF_ENTRY(MARSHALINGTYPE_INHIBIT),
5722 VMF_ENTRY(MARSHALINGTYPE_FREETHREADED),
5723 VMF_ENTRY(MARSHALINGTYPE_STANDARD),
5724#endif
5725#undef VMF_ENTRY
5726};
5727static NativeImageDumper::EnumMnemonics s_CorFieldAttr[] =
5728{
5729#define CFA_ENTRY(x) NativeImageDumper::EnumMnemonics( x, W(#x) )
5730
5731#define CFA_ACCESS_ENTRY(x) NativeImageDumper::EnumMnemonics( x, fdFieldAccessMask, W(#x) )
5732 CFA_ENTRY(fdPrivateScope),
5733 CFA_ENTRY(fdPrivate),
5734 CFA_ENTRY(fdFamANDAssem),
5735 CFA_ENTRY(fdAssembly),
5736 CFA_ENTRY(fdFamily),
5737 CFA_ENTRY(fdFamORAssem),
5738 CFA_ENTRY(fdPublic),
5739#undef CFA_ACCESS_ENTRY
5740
5741 CFA_ENTRY(fdStatic),
5742 CFA_ENTRY(fdInitOnly),
5743 CFA_ENTRY(fdLiteral),
5744 CFA_ENTRY(fdNotSerialized),
5745
5746 CFA_ENTRY(fdSpecialName),
5747
5748 CFA_ENTRY(fdPinvokeImpl),
5749
5750 CFA_ENTRY(fdRTSpecialName),
5751 CFA_ENTRY(fdHasFieldMarshal),
5752 CFA_ENTRY(fdHasDefault),
5753 CFA_ENTRY(fdHasFieldRVA),
5754#undef CFA_ENTRY
5755};
5756
5757NativeImageDumper::EnumMnemonics NativeImageDumper::s_MDFlag2[] =
5758{
5759#define MDF2_ENTRY(x) NativeImageDumper::EnumMnemonics( MethodDesc::enum_flag2_ ## x, W("enum_flag2_") W(#x) )
5760 MDF2_ENTRY(HasStableEntryPoint),
5761 MDF2_ENTRY(HasPrecode),
5762 MDF2_ENTRY(IsUnboxingStub),
5763 MDF2_ENTRY(HasNativeCodeSlot),
5764#undef MDF2_ENTRY
5765};
5766
5767NativeImageDumper::EnumMnemonics NativeImageDumper::s_MDC[] =
5768{
5769#define MDC_ENTRY(x) NativeImageDumper::EnumMnemonics( x, W(#x) )
5770
5771#define MDC_ENTRY_CLASSIFICATION(x) NativeImageDumper::EnumMnemonics( x, mdcClassification, W(#x) )
5772 MDC_ENTRY_CLASSIFICATION(mcIL),
5773 MDC_ENTRY_CLASSIFICATION(mcFCall),
5774 MDC_ENTRY_CLASSIFICATION(mcNDirect),
5775 MDC_ENTRY_CLASSIFICATION(mcEEImpl),
5776 MDC_ENTRY_CLASSIFICATION(mcArray),
5777 MDC_ENTRY_CLASSIFICATION(mcInstantiated),
5778#ifdef FEATURE_COMINTEROP
5779 MDC_ENTRY_CLASSIFICATION(mcComInterop),
5780#endif // FEATURE_COMINTEROP
5781 MDC_ENTRY_CLASSIFICATION(mcDynamic),
5782#undef MDC_ENTRY_CLASSIFICATION
5783
5784 MDC_ENTRY(mdcHasNonVtableSlot),
5785 MDC_ENTRY(mdcMethodImpl),
5786
5787 // Method is static
5788 MDC_ENTRY(mdcStatic),
5789
5790 MDC_ENTRY(mdcDuplicate),
5791 MDC_ENTRY(mdcVerifiedState),
5792 MDC_ENTRY(mdcVerifiable),
5793 MDC_ENTRY(mdcNotInline),
5794 MDC_ENTRY(mdcSynchronized),
5795 MDC_ENTRY(mdcRequiresFullSlotNumber),
5796#undef MDC_ENTRY
5797};
5798
5799
5800
5801void NativeImageDumper::DumpTypes(PTR_Module module)
5802{
5803 _ASSERTE(CHECK_OPT(EECLASSES) || CHECK_OPT(METHODTABLES)
5804 || CHECK_OPT(TYPEDESCS));
5805
5806 IF_OPT_OR3(METHODTABLES, EECLASSES, TYPEDESCS)
5807 m_display->StartCategory( "Types" );
5808 IF_OPT(METHODTABLES)
5809 {
5810 //there may be duplicates in the list. Remove them before moving on.
5811 COUNT_T mtCount = m_discoveredMTs.GetCount();
5812
5813#if !defined(FEATURE_CORESYSTEM) // no STL right now
5814 std::sort(&*m_discoveredMTs.Begin(),
5815 (&*m_discoveredMTs.Begin())
5816 + (m_discoveredMTs.End() - m_discoveredMTs.Begin()));
5817 PTR_MethodTable* newEnd = std::unique(&*m_discoveredMTs.Begin(),
5818 (&*m_discoveredMTs.Begin())
5819 + (m_discoveredMTs.End()
5820 - m_discoveredMTs.Begin()));
5821 mtCount = (COUNT_T)(newEnd - &*m_discoveredMTs.Begin());
5822#endif
5823
5824 DisplayStartArray( "MethodTables", NULL, METHODTABLES );
5825 for(COUNT_T i = 0; i < mtCount; ++i )
5826 {
5827 PTR_MethodTable mt = m_discoveredMTs[i];
5828 if( mt == NULL )
5829 continue;
5830 DumpMethodTable( mt, "MethodTable", module );
5831 }
5832
5833 DisplayEndArray( "Total MethodTables", METHODTABLES );
5834
5835 DisplayStartArray( "MethodTableSlotChunks", NULL, METHODTABLES );
5836 {
5837 COUNT_T slotChunkCount = m_discoveredSlotChunks.GetCount();
5838#if !defined(FEATURE_CORESYSTEM) // no STL right now
5839 std::sort(&*m_discoveredSlotChunks.Begin(),
5840 (&*m_discoveredSlotChunks.Begin())
5841 + (m_discoveredSlotChunks.End() - m_discoveredSlotChunks.Begin()));
5842 SlotChunk *newEndChunks = std::unique(&*m_discoveredSlotChunks.Begin(),
5843 (&*m_discoveredSlotChunks.Begin())
5844 + (m_discoveredSlotChunks.End() - m_discoveredSlotChunks.Begin()));
5845 slotChunkCount = (COUNT_T)(newEndChunks - &*m_discoveredSlotChunks.Begin());
5846#endif
5847
5848 for (COUNT_T i = 0; i < slotChunkCount; ++i)
5849 {
5850 DumpMethodTableSlotChunk(m_discoveredSlotChunks[i].addr,
5851 m_discoveredSlotChunks[i].nSlots,
5852 m_discoveredSlotChunks[i].isRelative);
5853 }
5854 }
5855 DisplayEndArray( "Total MethodTableSlotChunks", METHODTABLES );
5856 }
5857 IF_OPT(EECLASSES)
5858 {
5859 DisplayStartArray( "EEClasses", NULL, EECLASSES );
5860
5861 //there may be duplicates in the list. Remove them before moving on.
5862 COUNT_T clazzCount = m_discoveredClasses.GetCount();
5863#if !defined(FEATURE_CORESYSTEM) // no STL right now
5864 std::sort(&*m_discoveredClasses.Begin(),
5865 (&*m_discoveredClasses.Begin())
5866 + (m_discoveredClasses.End() - m_discoveredClasses.Begin()));
5867 PTR_MethodTable * newEndClazz = std::unique(&*m_discoveredClasses.Begin(),
5868 (&*m_discoveredClasses.Begin())
5869 +(m_discoveredClasses.End()
5870 -m_discoveredClasses.Begin()));
5871 clazzCount = (COUNT_T)(newEndClazz - &*m_discoveredClasses.Begin());
5872#endif
5873
5874 for(COUNT_T i = 0; i < clazzCount; ++i )
5875 {
5876 PTR_MethodTable mt = m_discoveredClasses[i];
5877 if( mt == NULL )
5878 continue;
5879 DumpEEClassForMethodTable( mt );
5880 }
5881
5882 DisplayEndArray( "Total EEClasses", EECLASSES ); //EEClasses
5883
5884 }
5885 IF_OPT(TYPEDESCS)
5886 {
5887 DisplayStartArray( "TypeDescs", NULL, TYPEDESCS );
5888
5889 //there may be duplicates in the list. Remove them before moving on.
5890 COUNT_T tdCount = m_discoveredTypeDescs.GetCount();
5891#if !defined(FEATURE_CORESYSTEM) // no STL right now
5892 std::sort(&*m_discoveredTypeDescs.Begin(),
5893 (&*m_discoveredTypeDescs.Begin())
5894 + (m_discoveredTypeDescs.End()
5895 - m_discoveredTypeDescs.Begin()));
5896 PTR_TypeDesc* newEndTD = std::unique(&*m_discoveredTypeDescs.Begin(),
5897 (&*m_discoveredTypeDescs.Begin())
5898 +(m_discoveredTypeDescs.End()
5899 -m_discoveredTypeDescs.Begin()));
5900 tdCount = (COUNT_T)(newEndTD - &*m_discoveredTypeDescs.Begin());
5901#endif
5902
5903 for(COUNT_T i = 0; i < tdCount; ++i )
5904 {
5905 PTR_TypeDesc td = m_discoveredTypeDescs[i];
5906 if( td == NULL )
5907 continue;
5908 DumpTypeDesc( td );
5909 }
5910
5911 DisplayEndArray( "Total TypeDescs", TYPEDESCS ); //EEClasses
5912
5913 }
5914 IF_OPT_OR3(EECLASSES, METHODTABLES, TYPEDESCS)
5915 m_display->EndCategory(); //Types
5916}
5917
5918PTR_EEClass NativeImageDumper::GetClassFromMT( PTR_MethodTable mt )
5919{
5920 /* REVISIT_TODO Tue 10/11/2005
5921 * Handle fixups
5922 */
5923 _ASSERTE( mt->IsClassPointerValid() );
5924 PTR_EEClass clazz( mt->GetClass() );
5925 return clazz;
5926}
5927PTR_MethodTable NativeImageDumper::GetParent( PTR_MethodTable mt )
5928{
5929 /* REVISIT_TODO Thu 12/01/2005
5930 * Handle fixups
5931 */
5932 PTR_MethodTable parent( ReadPointerMaybeNull((MethodTable*) mt, &MethodTable::m_pParentMethodTable, mt->GetFlagHasIndirectParent()) );
5933 _ASSERTE(!CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(parent)));
5934 return parent;
5935}
5936
5937//Counts the FieldDescs in a class. This is all of the non-static and static
5938//non-literal fields.
5939SIZE_T NativeImageDumper::CountFields( PTR_MethodTable mt )
5940{
5941 SIZE_T fieldCount = 0;
5942
5943 HCORENUM hEnum = NULL;
5944
5945 const Dependency * dep = GetDependencyFromMT(mt);
5946 mdToken classToken = mt->GetCl();
5947
5948 _ASSERTE(dep);
5949 _ASSERTE(dep->pImport);
5950
5951 //Arrays have no token.
5952 if( RidFromToken(classToken) == 0 )
5953 return 0;
5954
5955 for (;;)
5956 {
5957 mdToken fields[1];
5958 ULONG numFields;
5959
5960 IfFailThrow(dep->pImport->EnumFields( &hEnum, classToken, fields,
5961 1, &numFields));
5962
5963 if (numFields == 0)
5964 break;
5965
5966 DWORD dwAttr;
5967 IfFailThrow(dep->pImport->GetFieldProps( fields[0], NULL, NULL, 0,
5968 NULL, & dwAttr, NULL, NULL,
5969 NULL, NULL, NULL ) );
5970 if( !IsFdStatic(dwAttr) || !IsFdLiteral(dwAttr) )
5971 ++fieldCount;
5972 }
5973 dep->pImport->CloseEnum(hEnum);
5974 return fieldCount;
5975}
5976const NativeImageDumper::Dependency*
5977NativeImageDumper::GetDependencyFromMT( PTR_MethodTable mt )
5978{
5979 if( !mt->IsClassPointerValid() )
5980 {
5981 //This code will not work for out of module dependencies.
5982 _ASSERTE(isSelf(GetDependencyForPointer(PTR_TO_TADDR(mt))));
5983
5984 //the EEClass is a fixup. The home for that fixup tells us the
5985 //home for the metadata.
5986 unsigned rva = CORCOMPILE_UNTAG_TOKEN(mt->GetCanonicalMethodTableFixup());
5987 return GetDependencyForFixup(rva);
5988 }
5989 PTR_Module module = mt->GetModule();
5990 if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(module)) )
5991 {
5992 unsigned rva = CORCOMPILE_UNTAG_TOKEN(PTR_TO_TADDR(module));
5993 return GetDependencyForFixup(rva);
5994 }
5995 return GetDependencyForModule(module);
5996}
5997const NativeImageDumper::Dependency*
5998NativeImageDumper::GetDependencyFromFD( PTR_FieldDesc fd )
5999{
6000 PTR_MethodTable mt = fd->GetApproxEnclosingMethodTable();
6001 if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)) )
6002 {
6003 //This code will not work for out of module dependencies.
6004 _ASSERTE(isSelf(GetDependencyForPointer(PTR_TO_TADDR(fd))));
6005
6006 //the MethodTable has a fixup. The home for that fixup tells us the
6007 //home for the metadata.
6008 unsigned rva = CORCOMPILE_UNTAG_TOKEN(PTR_TO_TADDR(mt));
6009 return GetDependencyForFixup(rva);
6010 }
6011 return GetDependencyFromMT(mt);
6012}
6013const NativeImageDumper::Dependency*
6014NativeImageDumper::GetDependencyFromMD( PTR_MethodDesc md )
6015{
6016 PTR_MethodDescChunk chunk( md->GetMethodDescChunk() );
6017 PTR_MethodTable mt = chunk->GetMethodTable();
6018 if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)) )
6019 {
6020 //This code will not work for out of module dependencies.
6021 _ASSERTE(isSelf(GetDependencyForPointer(PTR_TO_TADDR(md))));
6022
6023 //the MethodTable has a fixup. The home for that fixup tells us the
6024 //home for the metadata.
6025 unsigned rva = CORCOMPILE_UNTAG_TOKEN(PTR_TO_TADDR(mt));
6026 return GetDependencyForFixup(rva);
6027 }
6028 return GetDependencyFromMT(mt);
6029}
6030
6031BOOL NativeImageDumper::DoWriteFieldAsFixup( const char * name,
6032 unsigned offset,
6033 unsigned fieldSize, TADDR fixup)
6034{
6035 if( !CORCOMPILE_IS_POINTER_TAGGED(fixup) )
6036 return FALSE;
6037 if( UINT_MAX == offset )
6038 m_display->StartVStructure( name );
6039 else
6040 m_display->StartVStructureWithOffset( name, offset, fieldSize );
6041
6042 WriteElementsFixupBlob( NULL, fixup );
6043 m_display->EndVStructure(); //name
6044 return TRUE;
6045}
6046
6047void AppendTypeQualifier( CorElementType kind, DWORD rank, SString& buf )
6048{
6049 switch( kind )
6050 {
6051 case ELEMENT_TYPE_BYREF :
6052 buf.Append( W("&") );
6053 break;
6054 case ELEMENT_TYPE_PTR :
6055 buf.Append( W("*") );
6056 break;
6057 case ELEMENT_TYPE_SZARRAY :
6058 buf.Append( W("[]") );
6059 break;
6060 case ELEMENT_TYPE_ARRAY :
6061 if( rank == 1 )
6062 {
6063 buf.Append( W("[*]") );
6064 }
6065 else
6066 {
6067 buf.Append( W("[") );
6068 for( COUNT_T i = 0; i < rank; ++i )
6069 buf.Append( W(","));
6070 buf.Append( W("]") );
6071 }
6072 break;
6073 default :
6074 break;
6075 }
6076}
6077void NativeImageDumper::TypeDescToString( PTR_TypeDesc td, SString& buf )
6078{
6079 _ASSERTE(!(PTR_TO_TADDR(td) & 0x2));
6080 if( td->IsGenericVariable() )
6081 {
6082 PTR_TypeVarTypeDesc tvtd( PTR_TO_TADDR(td) );
6083 //From code:TypeString::AppendType
6084 mdGenericParam token = tvtd->GetToken();
6085 PTR_Module module(tvtd->GetModule());
6086 IMetaDataImport2 * pImport;
6087 if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(module)) )
6088 {
6089 if (!isSelf(GetDependencyForPointer(PTR_TO_TADDR(td))))
6090 {
6091 //this is an RVA from another hardbound dependency. We cannot decode it
6092 buf.Append(W("OUT_OF_MODULE_FIXUP"));
6093 return;
6094 }
6095 else
6096 {
6097 RVA rva = CORCOMPILE_UNTAG_TOKEN(PTR_TO_TADDR(module));
6098 pImport = GetDependencyForFixup(rva)->pImport;
6099 }
6100 }
6101 else
6102 {
6103 pImport = GetDependencyForModule(module)->pImport;
6104 }
6105 AppendTokenName(token, buf, pImport);
6106 }
6107 else if( ELEMENT_TYPE_FNPTR == td->GetInternalCorElementType() )
6108 {
6109 PTR_FnPtrTypeDesc fptd( PTR_TO_TADDR(td) );
6110 buf.Append( W("(fnptr)") );
6111 }
6112 else if( td->HasTypeParam() || td->IsArray() )
6113 {
6114 //either a Parameter or an Array.
6115 PTR_ParamTypeDesc ptd(PTR_TO_TADDR(td));
6116 TypeHandle elemType;
6117 /* REVISIT_TODO Thu 10/5/2006
6118 * Do I need to find a rank somewhere in the TypeDesc?
6119 */
6120 unsigned rank;
6121 if( td->IsArray() )
6122 {
6123 //td->HasTypeParam() may also be true.
6124 PTR_MethodTable mt = ptd->GetTemplateMethodTableInternal();
6125 _ASSERTE( PTR_TO_TADDR(mt) );
6126 if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)) )
6127 {
6128 if (!isSelf(GetDependencyForPointer(PTR_TO_TADDR(ptd))))
6129 {
6130 //this is an RVA from another hardbound dependency. We cannot decode it
6131 buf.Append(W("OUT_OF_MODULE_FIXUP"));
6132 }
6133 else
6134 {
6135 RVA rva = CORCOMPILE_UNTAG_TOKEN(PTR_TO_TADDR(mt));
6136 FixupBlobToString(rva, buf);
6137 }
6138 return;
6139 }
6140 else
6141 {
6142 _ASSERTE( !CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)) );
6143 MethodTableToString( mt, buf );
6144 rank = PTR_ArrayTypeDesc(PTR_TO_TADDR(ptd))->GetRank();
6145 }
6146 }
6147 else
6148 {
6149 _ASSERTE(td->HasTypeParam());
6150 TypeHandle th(ptd->GetTypeParam());
6151 _ASSERTE( !CORCOMPILE_IS_POINTER_TAGGED(th.AsTAddr()) );
6152 _ASSERTE( th.AsTAddr() );
6153 TypeHandleToString(th, buf);
6154 rank = 0;
6155 }
6156 AppendTypeQualifier( td->GetInternalCorElementType(), rank, buf );
6157 }
6158 else
6159 {
6160 //generic typedesc?
6161 EnumFlagsToString( (int)td->GetInternalCorElementType(), s_CorElementType, dim(s_CorElementType),
6162 W(""), buf );
6163 }
6164}
6165void NativeImageDumper::TypeHandleToString( TypeHandle th, SString& buf )
6166{
6167 TADDR arg = th.AsTAddr();
6168 /* REVISIT_TODO Thu 10/5/2006
6169 * Is this constant somewhere?
6170 */
6171 //0x2 is the subtle hint that this is a typedesc. code:TypeHandle::AsTypeDesc
6172 if( arg & 0x2 )
6173 {
6174 PTR_TypeDesc argTD( arg & ~0x2 );
6175 TypeDescToString( argTD, buf );
6176 }
6177 else
6178 {
6179 PTR_MethodTable argMT( th.AsTAddr() );
6180 MethodTableToString( argMT, buf );
6181 }
6182}
6183
6184void NativeImageDumper::DoWriteFieldTypeHandle( const char * name,
6185 unsigned offset,
6186 unsigned fieldSize,
6187 TypeHandle th )
6188{
6189 TempBuffer buf;
6190 TADDR ptr = th.AsTAddr();
6191 if( DoWriteFieldAsFixup(name, offset, fieldSize, th.AsTAddr() ) )
6192 return;
6193 else
6194 {
6195 TypeHandleToString(th, buf);
6196
6197 buf.Append( W(" (from TypeHandle)") );
6198 /* REVISIT_TODO Fri 10/14/2005
6199 * Do a better job of this
6200 */
6201 if( offset == UINT_MAX )
6202 {
6203 m_display->WriteElementPointerAnnotated( name,
6204 DataPtrToDisplay(ptr),
6205 (const WCHAR*) buf );
6206 }
6207 else
6208 {
6209 m_display->WriteFieldPointerAnnotated( name, offset, fieldSize,
6210 DataPtrToDisplay(ptr),
6211 (const WCHAR*) buf );
6212 }
6213 }
6214}
6215void NativeImageDumper::WriteElementTypeHandle( const char * name,
6216 TypeHandle th )
6217{
6218 DoWriteFieldTypeHandle( name, UINT_MAX, UINT_MAX, th );
6219}
6220
6221void NativeImageDumper::DoDumpFieldStub( PTR_Stub stub, unsigned offset,
6222 unsigned fieldSize, const char * name )
6223{
6224 _ASSERTE(CHECK_OPT(EECLASSES));
6225 if( stub == NULL )
6226 {
6227 m_display->WriteFieldPointer( name, offset, fieldSize, NULL );
6228 }
6229 else
6230 {
6231 m_display->StartStructureWithOffset( name, offset, fieldSize,
6232 DPtrToPreferredAddr(stub),
6233 sizeof(*stub) );
6234 /* REVISIT_TODO Fri 10/14/2005
6235 * Dump stub
6236 */
6237 m_display->EndStructure();
6238 }
6239}
6240
6241#ifdef FEATURE_COMINTEROP
6242void NativeImageDumper::DoDumpComPlusCallInfo( PTR_ComPlusCallInfo compluscall )
6243{
6244 m_display->StartStructure( "ComPlusCallInfo",
6245 DPtrToPreferredAddr(compluscall),
6246 sizeof(*compluscall) );
6247
6248 DisplayWriteFieldPointer( m_pILStub, compluscall->m_pILStub,
6249 ComPlusCallInfo, ALWAYS);
6250 /* REVISIT_TODO Fri 12/16/2005
6251 * Coverage read stub?
6252 */
6253 WriteFieldMethodTable(m_pInterfaceMT,
6254 compluscall->m_pInterfaceMT,
6255 ComPlusCallInfo, ALWAYS);
6256
6257 PTR_MethodDesc pEventProviderMD = PTR_MethodDesc((TADDR)compluscall->m_pEventProviderMD);
6258 WriteFieldMethodDesc(m_pEventProviderMD,
6259 pEventProviderMD,
6260 ComPlusCallInfo, ALWAYS);
6261 DisplayWriteFieldInt( m_cachedComSlot, compluscall->m_cachedComSlot,
6262 ComPlusCallInfo, ALWAYS );
6263
6264 /* REVISIT_TODO Fri 12/16/2005
6265 * Dump these as mnemonics
6266 */
6267 DisplayWriteFieldInt( m_flags, compluscall->m_flags,
6268 ComPlusCallInfo, ALWAYS );
6269 WriteFieldMethodDesc( m_pStubMD,
6270 compluscall->m_pStubMD.GetValueMaybeNull(PTR_HOST_MEMBER_TADDR(ComPlusCallInfo, compluscall, m_pStubMD)),
6271 ComPlusCallInfo, ALWAYS );
6272
6273#ifdef _TARGET_X86_
6274 DisplayWriteFieldInt( m_cbStackArgumentSize, compluscall->m_cbStackArgumentSize,
6275 ComPlusCallInfo, ALWAYS );
6276
6277 DisplayWriteFieldPointer( m_pRetThunk,
6278 DataPtrToDisplay((TADDR)compluscall->m_pRetThunk),
6279 ComPlusCallInfo, ALWAYS );
6280#endif
6281 m_display->EndStructure(); //ComPlusCallInfo
6282}
6283#endif // FEATURE_COMINTEROP
6284
6285void NativeImageDumper::DoWriteFieldStr( PTR_BYTE ptr, const char * name,
6286 unsigned offset, unsigned fieldSize )
6287{
6288 if( ptr == NULL )
6289 {
6290 if( UINT_MAX == offset )
6291 m_display->WriteElementPointer( name, NULL );
6292 else
6293 m_display->WriteFieldPointer( name, offset, fieldSize, NULL );
6294 }
6295 else
6296 {
6297 /* REVISIT_TODO Wed 03/22/2006
6298 * Obviously this does the wrong thing for UTF-8.
6299 */
6300 TempBuffer buf;
6301 BYTE b;
6302 TADDR taddr = DPtrToPreferredAddr(ptr);
6303 PTR_BYTE current = ptr;
6304 /* REVISIT_TODO Mon 03/27/2006
6305 * Actually handle UTF-8 properly
6306 */
6307 while( (b = *current++) != 0 )
6308 buf.Append( (WCHAR)b );
6309 /* REVISIT_TODO Wed 03/22/2006
6310 * This seems way way way more verbose than it needs to be.
6311 */
6312 if( UINT_MAX == offset )
6313 {
6314 m_display->StartStructure( name, DataPtrToDisplay(taddr),
6315 current - ptr );
6316 }
6317 else
6318 {
6319 m_display->StartStructureWithOffset( name, offset, fieldSize,
6320 DataPtrToDisplay(taddr),
6321 current - ptr );
6322 }
6323 DisplayWriteElementStringW( "Value", (const WCHAR *)buf, ALWAYS );
6324 m_display->EndStructure();
6325 /*
6326 m_display->WriteFieldPointerAnnotated( name, offset, fieldSize,
6327 taddr, (const WCHAR *)buf );
6328 */
6329 }
6330}
6331void NativeImageDumper::WriteFieldDictionaryLayout(const char * name,
6332 unsigned offset,
6333 unsigned fieldSize,
6334 PTR_DictionaryLayout layout,
6335 IMetaDataImport2 * import)
6336{
6337 if( layout == NULL )
6338 {
6339 m_display->WriteFieldPointer(name, NULL, offset, fieldSize);
6340 return;
6341 }
6342 m_display->StartVStructureWithOffset( name, offset, fieldSize );
6343 DisplayStartArray( "DictionaryLayouts", NULL, ALWAYS );
6344 do
6345 {
6346 DisplayStartStructure( "DictionaryLayout", DPtrToPreferredAddr(layout),
6347 sizeof(DictionaryLayout)
6348 + sizeof(DictionaryEntryLayout)
6349 * (layout->m_numSlots - 1), ALWAYS );
6350
6351
6352 DisplayWriteFieldPointer( m_pNext, DataPtrToDisplay((TADDR)layout->m_pNext),
6353 DictionaryLayout, ALWAYS );
6354 DisplayWriteFieldInt( m_numSlots, layout->m_numSlots,
6355 DictionaryLayout, ALWAYS );
6356 DisplayStartArrayWithOffset( m_slots, NULL, DictionaryLayout, ALWAYS );
6357 for( unsigned i = 0; i < layout->m_numSlots; ++i )
6358 {
6359 PTR_DictionaryEntryLayout entry( PTR_HOST_MEMBER_TADDR(DictionaryLayout, layout, m_slots) + (i * sizeof(DictionaryEntryLayout)) );
6360 DisplayStartStructure( "DictionaryEntryLayout",
6361 DPtrToPreferredAddr(entry), sizeof(*entry),
6362 ALWAYS );
6363 const char * kind = NULL;
6364 switch( entry->GetKind() )
6365 {
6366#define KIND_ENTRY(x) case x : kind = # x ; break
6367 KIND_ENTRY(EmptySlot);
6368 KIND_ENTRY(TypeHandleSlot);
6369 KIND_ENTRY(MethodDescSlot);
6370 KIND_ENTRY(MethodEntrySlot);
6371 KIND_ENTRY(ConstrainedMethodEntrySlot);
6372 KIND_ENTRY(DispatchStubAddrSlot);
6373 KIND_ENTRY(FieldDescSlot);
6374#undef KIND_ENTRY
6375 default:
6376 _ASSERTE( !"unreachable" );
6377 }
6378 DisplayWriteElementString( "Kind", kind, ALWAYS );
6379 DisplayWriteElementPointer( "Signature", DPtrToPreferredAddr(entry->m_signature), ALWAYS );
6380 DisplayEndStructure( ALWAYS ); //DictionaryEntryLayout
6381 }
6382 DisplayEndArray( "Total Dictionary Entries", ALWAYS ); //m_slots
6383 DisplayEndStructure( ALWAYS ); //Layout
6384 layout = PTR_DictionaryLayout(TO_TADDR(layout->m_pNext));
6385 }while( layout != NULL );
6386 DisplayEndArray( "Total Dictionary Layouts", ALWAYS ); //DictionaryLayouts
6387
6388
6389 DisplayEndVStructure( ALWAYS ); // name
6390}
6391void NativeImageDumper::DoWriteFieldFieldDesc( const char * name,
6392 unsigned offset,
6393 unsigned fieldSize,
6394 PTR_FieldDesc fd )
6395{
6396 if( fd == NULL )
6397 {
6398 m_display->WriteFieldPointer( name, offset, fieldSize, NULL );
6399 }
6400 else
6401 {
6402 TempBuffer buf;
6403 FieldDescToString( fd, buf );
6404 m_display->WriteFieldPointerAnnotated( name, offset, fieldSize,
6405 DPtrToPreferredAddr(fd),
6406 (const WCHAR*) buf );
6407 }
6408
6409}
6410void NativeImageDumper::DoWriteFieldMethodDesc( const char * name,
6411 unsigned offset,
6412 unsigned fieldSize,
6413 PTR_MethodDesc md )
6414{
6415 if( md == NULL )
6416 {
6417 m_display->WriteFieldPointer( name, offset, fieldSize, NULL );
6418 }
6419 else if( DoWriteFieldAsFixup(name, offset, fieldSize, PTR_TO_TADDR(md)) )
6420 {
6421 return;
6422 }
6423 else
6424 {
6425 TempBuffer buf;
6426 MethodDescToString( md, buf );
6427 m_display->WriteFieldPointerAnnotated( name, offset, fieldSize,
6428 DPtrToPreferredAddr(md),
6429 (const WCHAR*) buf );
6430 }
6431}
6432
6433void NativeImageDumper::EntryPointToString( TADDR pEntryPoint,
6434 SString& buf )
6435{
6436 const Dependency * dependency = GetDependencyForPointer(pEntryPoint);
6437
6438 PTR_MethodDesc md;
6439 if (dependency->pModule->IsZappedPrecode(pEntryPoint))
6440 {
6441 md = dac_cast<PTR_MethodDesc>(Precode::GetPrecodeFromEntryPoint(pEntryPoint)->GetMethodDesc());
6442 }
6443 else
6444 {
6445 PTR_Module module = (TADDR)m_decoder.GetPersistedModuleImage();
6446 PTR_NGenLayoutInfo pNgenLayout = module->GetNGenLayoutInfo();
6447 DWORD rva = (DWORD)(pEntryPoint - PTR_TO_TADDR(m_decoder.GetBase()));
6448
6449 for (int iRange = 0; iRange < 2; iRange++)
6450 {
6451 if (pNgenLayout->m_CodeSections[iRange].IsInRange(pEntryPoint))
6452 {
6453 int MethodIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod(rva, pNgenLayout->m_pRuntimeFunctions[iRange], 0, pNgenLayout->m_nRuntimeFunctions[iRange] - 1);
6454 if (MethodIndex >= 0)
6455 {
6456#ifdef WIN64EXCEPTIONS
6457 while (pNgenLayout->m_MethodDescs[iRange][MethodIndex] == 0)
6458 MethodIndex--;
6459#endif
6460
6461 PTR_RUNTIME_FUNCTION pRuntimeFunction = pNgenLayout->m_pRuntimeFunctions[iRange] + MethodIndex;
6462
6463 md = NativeUnwindInfoLookupTable::GetMethodDesc(pNgenLayout, pRuntimeFunction, PTR_TO_TADDR(m_decoder.GetBase()));
6464 break;
6465 }
6466 }
6467 }
6468 }
6469
6470 MethodDescToString(md, buf);
6471}
6472
6473void NativeImageDumper::MethodDescToString( PTR_MethodDesc md,
6474 SString& buf )
6475{
6476 if( md == NULL )
6477 buf.Append( W("mdMethodDefNil") );
6478 else if( md->IsILStub() )
6479 buf.AppendUTF8(md->AsDynamicMethodDesc()->GetName());
6480 else
6481 {
6482 //write the name to a temporary location, since I'm going to insert it
6483 //into the middle of a signature.
6484 TempBuffer tempName;
6485
6486 _ASSERTE(!CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(md)));
6487 //work back to the EEClass. That gives us the context for the token.
6488 PTR_MethodDescChunk chunk(md->GetMethodDescChunk());
6489 //chunk is implicitly remapped because it's calculated from the pointer
6490 //to MD.
6491 PTR_MethodTable mt = chunk->GetMethodTable();
6492 const Dependency * dependency;
6493 if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)) )
6494 {
6495 //This code will not work for out of module dependencies.
6496 _ASSERTE(isSelf(GetDependencyForPointer(PTR_TO_TADDR(md))));
6497
6498 RVA rva = CORCOMPILE_UNTAG_TOKEN(PTR_TO_TADDR(mt));
6499 dependency = GetDependencyForFixup(rva);
6500 mt = NULL; //make sure we don't use this for anything.
6501 }
6502 else
6503 dependency = GetDependencyFromMT(mt);
6504
6505 _ASSERTE(dependency);
6506
6507
6508 /* REVISIT_TODO Fri 10/13/2006
6509 * Don't I need the array type name here?
6510 */
6511 _ASSERTE(dependency->pImport);
6512 if( md->GetClassification() == mcArray )
6513 {
6514
6515 //We don't need to append the dependency all the time.
6516 //MethodTableToString() already appends it to the MethodTable.
6517 //Only do it in cases where we don't call MethodTableToString.
6518 if( !isSelf(dependency) )
6519 {
6520 AppendTokenName( dependency->entry->dwAssemblyRef, tempName,
6521 m_manifestImport );
6522 tempName.Append(W("!"));
6523 }
6524
6525 _ASSERTE(PTR_TO_TADDR(mt));
6526 MethodTableToString( mt, tempName );
6527 tempName.Append( W("::") );
6528
6529 //there are four hard coded names for array method descs, use these
6530 //instead of the token.
6531 PTR_ArrayMethodDesc amd(PTR_TO_TADDR(md));
6532 tempName.AppendUTF8( amd->GetMethodName() );
6533 }
6534 else
6535 {
6536 //if we have a MethodTable, use that and compose the name
6537 //ourselves. That way we can get generic arguments.
6538 if( mt )
6539 {
6540 ULONG size;
6541 MethodTableToString( mt, tempName );
6542 tempName.Append( W("::") );
6543 IfFailThrow(dependency->pImport->GetMethodProps(md->GetMemberDef(), NULL, bigBuffer,
6544 bigBufferSize, &size, NULL, NULL, NULL, NULL,
6545 NULL));
6546 tempName.Append(bigBuffer);
6547 }
6548 else
6549 {
6550 //We don't need to append the dependency all the time.
6551 //MethodTableToString() already appends it to the MethodTable.
6552 //Only do it in cases where we don't call MethodTableToString.
6553 if( !isSelf(dependency) )
6554 {
6555 AppendTokenName( dependency->entry->dwAssemblyRef, tempName,
6556 m_manifestImport );
6557 tempName.Append(W("!"));
6558 }
6559 AppendTokenName( md->GetMemberDef(), tempName, dependency->pImport );
6560 }
6561
6562 if( mcInstantiated == md->GetClassification() )
6563 {
6564 PTR_InstantiatedMethodDesc imd(PTR_TO_TADDR(md));
6565 unsigned numArgs = imd->m_wNumGenericArgs;
6566 PTR_Dictionary dict(imd->IMD_GetMethodDictionary());
6567 if( dict != NULL )
6568 {
6569 DictionaryToArgString( dict, numArgs, tempName );
6570 }
6571 }
6572
6573 PCCOR_SIGNATURE pvSigBlob;
6574 ULONG cbSigBlob;
6575 IfFailThrow(dependency->pImport->GetMethodProps(md->GetMemberDef(),
6576 NULL,
6577 NULL,
6578 0,
6579 NULL,
6580 NULL,
6581 &pvSigBlob,
6582 &cbSigBlob,
6583 NULL,
6584 NULL));
6585
6586
6587 CQuickBytes prettySig;
6588 ReleaseHolder<IMDInternalImport> pInternal;
6589 IfFailThrow(GetMDInternalInterfaceFromPublic(dependency->pImport, IID_IMDInternalImport,
6590 (void**)&pInternal));
6591 StackScratchBuffer buffer;
6592 const ANSI * ansi = tempName.GetANSI(buffer);
6593 ansi = PrettyPrintSig(pvSigBlob, cbSigBlob, ansi, &prettySig, pInternal, NULL);
6594 tempName.SetANSI( ansi );
6595 }
6596 buf.Append(tempName);
6597 }
6598}
6599void NativeImageDumper::WriteElementMethodDesc( const char * name,
6600 PTR_MethodDesc md )
6601{
6602 if( md == NULL )
6603 {
6604 m_display->WriteElementPointer( name, NULL );
6605 }
6606 else
6607 {
6608 TempBuffer buf;
6609 MethodDescToString( md, buf );
6610 m_display->WriteElementPointerAnnotated( name, DPtrToPreferredAddr(md),
6611 (const WCHAR*) buf );
6612 }
6613}
6614void NativeImageDumper::FieldDescToString( PTR_FieldDesc fd, SString& buf )
6615{
6616 FieldDescToString( fd, mdFieldDefNil, buf );
6617}
6618void NativeImageDumper::FieldDescToString( PTR_FieldDesc fd, mdFieldDef tok,
6619 SString& buf )
6620{
6621 IF_OPT(DISABLE_NAMES)
6622 {
6623 buf.Append( W("Disabled") );
6624 return;
6625 }
6626 if( fd == NULL )
6627 {
6628 if( tok == mdFieldDefNil )
6629 buf.Append( W("mdFieldDefNil") );
6630 else
6631 AppendTokenName( tok, buf );
6632 }
6633 else
6634 {
6635 _ASSERTE(!CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(fd)));
6636 IMetaDataImport2 * importMD = NULL;
6637 if( !isInRange(PTR_TO_TADDR(fd)) )
6638 {
6639 const Dependency * dependency = GetDependencyFromFD(fd);
6640 _ASSERTE(dependency);
6641 AppendTokenName( dependency->entry->dwAssemblyRef, buf,
6642 m_manifestImport );
6643 buf.Append(W("!"));
6644 importMD = dependency->pImport;
6645 _ASSERTE(importMD);
6646
6647 }
6648 else
6649 {
6650 importMD = m_import;
6651 }
6652 AppendTokenName( fd->GetMemberDef(), buf, importMD );
6653 }
6654}
6655
6656void NativeImageDumper::DoWriteFieldAsHex( const char * name, unsigned offset,
6657 unsigned fieldSize, PTR_BYTE ptr,
6658 unsigned dataLen )
6659{
6660 TempBuffer buffer;
6661 for( unsigned i = 0; i < dataLen; ++i )
6662 {
6663 unsigned char b = ptr[i];
6664 buffer.AppendPrintf( W("%02x%02x"), (b & 0xf0) >> 4, b & 0xf );
6665 }
6666 if( offset == UINT_MAX )
6667 {
6668 m_display->WriteElementStringW( name, (const WCHAR *)buffer );
6669 }
6670 else
6671 {
6672 m_display->WriteFieldStringW( name, offset, fieldSize,
6673 (const WCHAR *)buffer );
6674 }
6675}
6676void NativeImageDumper::WriteElementMDToken( const char * name, mdToken token )
6677{
6678 DoWriteFieldMDToken( name, UINT_MAX, UINT_MAX, token );
6679}
6680void NativeImageDumper::DoWriteFieldMDToken( const char * name, unsigned offset,
6681 unsigned fieldSize, mdToken token,
6682 IMetaDataImport2 * import )
6683{
6684 TempBuffer buf;
6685 if( RidFromToken(token) == mdTokenNil )
6686 {
6687 AppendNilToken( token, buf );
6688 }
6689 else
6690 {
6691 AppendToken( token, buf, import );
6692 }
6693 if( UINT_MAX == offset )
6694 m_display->WriteElementEnumerated( name, token, (const WCHAR *)buf );
6695 else
6696 {
6697 m_display->WriteFieldEnumerated(name, offset, fieldSize, token,
6698 (const WCHAR*)buf);
6699 }
6700}
6701
6702void NativeImageDumper::WriteElementMethodTable( const char * name,
6703 PTR_MethodTable mt )
6704{
6705 DoWriteFieldMethodTable( name, UINT_MAX, UINT_MAX, mt );
6706}
6707void NativeImageDumper::DoWriteFieldMethodTable( const char * name,
6708 unsigned offset,
6709 unsigned fieldSize,
6710 PTR_MethodTable mt )
6711{
6712 if( mt == NULL )
6713 {
6714 if( UINT_MAX == offset )
6715 m_display->WriteElementPointer( name, NULL );
6716 else
6717 m_display->WriteFieldPointer( name, offset, fieldSize, NULL );
6718 }
6719 else if( DoWriteFieldAsFixup( name, offset, fieldSize, PTR_TO_TADDR(mt) ) )
6720 {
6721 return;
6722 }
6723 else
6724 {
6725 TempBuffer buf;
6726 MethodTableToString( mt, buf );
6727 if( UINT_MAX == offset )
6728 {
6729
6730 m_display->WriteElementPointerAnnotated( name,
6731 DPtrToPreferredAddr(mt),
6732 (const WCHAR*) buf );
6733 }
6734 else
6735 {
6736 m_display->WriteFieldPointerAnnotated( name, offset, fieldSize,
6737 DPtrToPreferredAddr(mt),
6738 (const WCHAR*) buf );
6739 }
6740 }
6741}
6742
6743const char * s_VTSCallbackNames[] =
6744{
6745#define VTSCB_ENTRY(x) # x
6746 VTSCB_ENTRY(VTS_CALLBACK_ON_SERIALIZING),
6747 VTSCB_ENTRY(VTS_CALLBACK_ON_SERIALIZED),
6748 VTSCB_ENTRY(VTS_CALLBACK_ON_DESERIALIZING),
6749 VTSCB_ENTRY(VTS_CALLBACK_ON_DESERIALIZED),
6750#undef VTSCB_ENTRY
6751};
6752void NativeImageDumper::DumpFieldDesc( PTR_FieldDesc fd, const char * name )
6753{
6754 DisplayStartStructure( name, DPtrToPreferredAddr(fd), sizeof(*fd),
6755 ALWAYS );
6756 WriteFieldMethodTable( m_pMTOfEnclosingClass,
6757 fd->GetApproxEnclosingMethodTable(), FieldDesc, ALWAYS );
6758 m_display->WriteFieldUInt( "m_mb", offsetof(FieldDesc, m_dword1),
6759 fieldsize(FieldDesc, m_dword1),
6760 fd->GetMemberDef() );
6761 m_display->WriteFieldFlag( "m_isStatic",
6762 offsetof(FieldDesc, m_dword1),
6763 fieldsize(FieldDesc, m_dword1),
6764 fd->m_isStatic );
6765 m_display->WriteFieldFlag( "m_isThreadLocal",
6766 offsetof(FieldDesc, m_dword1),
6767 fieldsize(FieldDesc, m_dword1),
6768 fd->m_isThreadLocal );
6769 m_display->WriteFieldFlag( "m_isRVA", offsetof(FieldDesc, m_dword1),
6770 fieldsize(FieldDesc, m_dword1),
6771 fd->m_isRVA );
6772
6773 {
6774 TempBuffer buf;
6775 EnumFlagsToString( fd->m_prot, s_CorFieldAttr,
6776 _countof(s_CorFieldAttr), W(" "), buf );
6777 m_display->WriteFieldEnumerated( "m_prot",
6778 offsetof(FieldDesc, m_dword1),
6779 fieldsize(FieldDesc, m_dword1),
6780 fd->m_prot, (const WCHAR *)buf );
6781 }
6782 m_display->WriteFieldFlag( "m_requiresFullMbValue",
6783 offsetof(FieldDesc, m_dword1),
6784 fieldsize(FieldDesc, m_dword1),
6785 fd->m_requiresFullMbValue );
6786 m_display->WriteFieldInt( "m_dwOffset",
6787 offsetof(FieldDesc, m_dword2),
6788 fieldsize(FieldDesc, m_dword2),
6789 fd->m_dwOffset );
6790 DoWriteFieldCorElementType( "m_type",
6791 offsetof(FieldDesc, m_dword2),
6792 fieldsize(FieldDesc, m_dword2),
6793 (CorElementType)fd->m_type );
6794#ifdef _DEBUG
6795 WriteFieldStr( m_debugName, PTR_BYTE(TO_TADDR(fd->m_debugName)),
6796 FieldDesc, ALWAYS );
6797#endif
6798 DisplayEndStructure( ALWAYS ); //name
6799}
6800
6801#ifdef _PREFAST_
6802#pragma warning(push)
6803#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
6804#endif
6805void
6806NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
6807 PTR_Module module )
6808{
6809 _ASSERTE(NULL != mt);
6810 TADDR start, end;
6811 bool haveCompleteExtents = true;
6812 PTR_EEClass clazz = NULL;
6813 if( !mt->IsCanonicalMethodTable() && CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt->GetCanonicalMethodTable())) )
6814 {
6815 /* REVISIT_TODO Wed 02/01/2006
6816 * GetExtent requires the class in order to compute GetInstAndDictSize.
6817 * If the EEClass isn't present, I cannot compute the size. If we are
6818 * in this case, skip all of the generic dictionaries.
6819 */
6820 haveCompleteExtents = false;
6821 TempBuffer buf;
6822 MethodTableToString( mt, buf );
6823 m_display->ErrorPrintF( "WARNING! MethodTable %S is generic but is not hard bound to its EEClass. Cannot compute generic dictionary sizes.\n", (const WCHAR *)buf );
6824 }
6825 else if( !m_isMscorlibHardBound )
6826 {
6827 /* REVISIT_TODO Mon 8/20/2007
6828 * If we're not hard bound to mscorlib, most things don't work. They depend on knowing what
6829 * g_pObjectClass is. Without the hard binding to mscorlib, I can't figure that out.
6830 */
6831 haveCompleteExtents = false;
6832 }
6833 if( haveCompleteExtents )
6834 {
6835 mt->GetSavedExtent(&start, &end);
6836 clazz = mt->GetClass();
6837 }
6838 else
6839 {
6840 start = PTR_TO_TADDR(mt);
6841 end = start + sizeof(*mt);
6842 }
6843 IF_OPT(METHODTABLES)
6844 {
6845 m_display->StartStructureWithNegSpace( name, DPtrToPreferredAddr(mt),
6846 DataPtrToDisplay(start), end - start );
6847 }
6848
6849 IF_OPT(METHODTABLES)
6850 {
6851 {
6852 TempBuffer buf;
6853 MethodTableToString( mt, buf );
6854 DisplayWriteElementStringW( "Name", (const WCHAR *)buf, ALWAYS );
6855 }
6856 if( mt->ContainsPointers() )
6857 {
6858 PTR_CGCDesc cgc = CGCDesc::GetCGCDescFromMT(mt);
6859 unsigned size = (unsigned)cgc->GetSize();
6860 /* REVISIT_TODO Tue 12/13/2005
6861 * Does anyone actually care about what's inside here?
6862 */
6863 m_display->WriteFieldEmpty( "CGCDesc", ~size + 1, size );
6864 }
6865 }
6866
6867 /* XXX Mon 10/24/2005
6868 * The MT might have a component size as the low WORD of the m_dwFlags
6869 * field, if it doesn't then that field instead represents a number of
6870 * flags, which we know as the "low flags"
6871 */
6872 if (mt->HasComponentSize())
6873 {
6874 DisplayWriteElementInt( "ComponentSize", mt->RawGetComponentSize(),
6875 METHODTABLES );
6876 }
6877 else
6878 {
6879 DisplayWriteFieldEnumerated( m_dwFlags, mt->m_dwFlags & 0xFFFF, MethodTable,
6880 s_MTFlagsLow, W(", "), METHODTABLES );
6881 }
6882
6883 /* XXX Fri 10/07/2005
6884 * The low WORD of the flags is used for either a component size or flags
6885 * (see above), the high WORD is always flags. If this changes then this
6886 * might be busted.
6887 */
6888 DisplayWriteFieldEnumerated( m_dwFlags, mt->m_dwFlags & ~0xFFFF, MethodTable,
6889 s_MTFlagsHigh, W(", "), METHODTABLES );
6890
6891 DisplayWriteFieldInt( m_BaseSize, mt->m_BaseSize, MethodTable,
6892 METHODTABLES );
6893
6894 DisplayWriteFieldEnumerated( m_wFlags2, mt->m_wFlags2, MethodTable,
6895 s_MTFlags2, W(", "), METHODTABLES );
6896
6897 DisplayWriteFieldInt( m_wToken, mt->m_wToken, MethodTable,
6898 METHODTABLES );
6899 DisplayWriteFieldInt( m_wNumVirtuals, mt->m_wNumVirtuals, MethodTable,
6900 METHODTABLES );
6901 DisplayWriteFieldInt( m_wNumInterfaces, mt->m_wNumInterfaces, MethodTable,
6902 METHODTABLES );
6903
6904
6905
6906 PTR_MethodTable parent = ReadPointerMaybeNull((MethodTable*) mt, &MethodTable::m_pParentMethodTable, mt->GetFlagHasIndirectParent());
6907 if( parent == NULL )
6908 {
6909 DisplayWriteFieldPointer( m_pParentMethodTable, NULL, MethodTable,
6910 METHODTABLES );
6911 }
6912 else
6913 {
6914 IF_OPT(METHODTABLES)
6915 {
6916 DoWriteFieldMethodTable( "m_pParentMethodTable",
6917 offsetof(MethodTable, m_pParentMethodTable),
6918 fieldsize(MethodTable, m_pParentMethodTable),
6919 mt->GetParentMethodTable() );
6920 }
6921 }
6922 DisplayWriteFieldPointer( m_pLoaderModule,
6923 DPtrToPreferredAddr(mt->GetLoaderModule()),
6924 MethodTable, METHODTABLES );
6925
6926 PTR_MethodTableWriteableData wd = ReadPointer((MethodTable *)mt, &MethodTable::m_pWriteableData);
6927 _ASSERTE(wd != NULL);
6928 DisplayStartStructureWithOffset( m_pWriteableData, DPtrToPreferredAddr(wd),
6929 sizeof(*wd), MethodTable, METHODTABLES );
6930 DisplayWriteFieldEnumerated( m_dwFlags, wd->m_dwFlags,
6931 MethodTableWriteableData, s_WriteableMTFlags,
6932 W(", "), METHODTABLES );
6933 DisplayWriteFieldPointer( m_hExposedClassObject,
6934 DataPtrToDisplay(wd->m_hExposedClassObject),
6935 MethodTableWriteableData, METHODTABLES );
6936 _ASSERTE(wd->m_hExposedClassObject == 0);
6937 DisplayEndStructure( METHODTABLES ); //m_pWriteableData
6938
6939 if( !mt->IsCanonicalMethodTable() )
6940 {
6941 WriteFieldMethodTable( m_pCanonMT, mt->GetCanonicalMethodTable(),
6942 MethodTable, METHODTABLES );
6943 }
6944 else
6945 {
6946 DisplayWriteFieldPointer( m_pEEClass, DPtrToPreferredAddr(mt->GetClass()),
6947 MethodTable, METHODTABLES );
6948 }
6949
6950 if( mt->IsArray() )
6951 {
6952 WriteFieldTypeHandle( m_ElementTypeHnd,
6953 mt->GetApproxArrayElementTypeHandle(),
6954 MethodTable, METHODTABLES );
6955 }
6956
6957 if( mt->HasPerInstInfo() && haveCompleteExtents )
6958 {
6959 //print out the generics dictionary info, and then print out
6960 //the contents of those dictionaries.
6961 PTR_GenericsDictInfo di = mt->GetGenericsDictInfo();
6962 _ASSERTE(NULL != di);
6963
6964 DisplayStartStructure("GenericsDictInfo", DPtrToPreferredAddr(di), sizeof(*di), METHODTABLES);
6965
6966 DisplayWriteFieldInt( m_wNumDicts, di->m_wNumDicts, GenericsDictInfo,
6967 METHODTABLES );
6968 DisplayWriteFieldInt( m_wNumTyPars, di->m_wNumTyPars,
6969 GenericsDictInfo, METHODTABLES);
6970 DisplayEndStructure( METHODTABLES ); //GenericsDictInfo
6971
6972 DPTR(MethodTable::PerInstInfoElem_t) perInstInfo = mt->GetPerInstInfo();
6973
6974 DisplayStartStructure( "PerInstInfo",
6975 DPtrToPreferredAddr(perInstInfo),
6976 mt->GetPerInstInfoSize(),
6977 METHODTABLES );
6978 /* XXX Tue 10/11/2005
6979 * Only dump this type's dictionary, rather than the inherited
6980 * dictionaries. (there are multiple entries in m_pPerInstInfo, but
6981 * only print the last one, which is the one for this class).
6982 * cloned from Genericdict.cpp
6983 */
6984 PTR_Dictionary currentDictionary(mt->GetDictionary());
6985 if( currentDictionary != NULL )
6986 {
6987 PTR_DictionaryEntry entry(currentDictionary->EntryAddr(0));
6988
6989 PTR_DictionaryLayout layout( clazz->GetDictionaryLayout() );
6990
6991 DisplayStartStructure( "Dictionary",
6992 DPtrToPreferredAddr(currentDictionary),
6993 //if there is a layout, use it to compute
6994 //the size, otherwise there is just the one
6995 //entry.
6996 DictionaryLayout::GetFirstDictionaryBucketSize(mt->GetNumGenericArgs(), layout),
6997 METHODTABLES );
6998
6999 DisplayStartArrayWithOffset( m_pEntries, NULL, Dictionary,
7000 METHODTABLES );
7001
7002 /* REVISIT_TODO Thu 12/15/2005
7003 * use VERBOSE_TYPES here.
7004 */
7005 _ASSERTE(CHECK_OPT(METHODTABLES));
7006
7007 //for each generic arg, there is a type handle slot
7008 for( unsigned i = 0; i < mt->GetNumGenericArgs(); ++i )
7009 DumpDictionaryEntry("Entry", TypeHandleSlot, entry + i);
7010
7011 //now check for a layout. If it is present, then there are more
7012 //entries.
7013 if( layout != NULL && (layout->GetNumUsedSlots() > 0) )
7014 {
7015 unsigned numUsedSlots = layout->GetNumUsedSlots();
7016 for( unsigned i = 0; i < numUsedSlots; ++i )
7017 {
7018 //DictionaryLayout::GetEntryLayout
7019 PTR_DictionaryEntryLayout entryLayout(layout->GetEntryLayout(i));
7020
7021 //Dictionary::GetSlotAddr
7022 PTR_DictionaryEntry ent(currentDictionary->EntryAddr(mt->GetNumGenericArgs() + i));
7023
7024 DumpDictionaryEntry( "Entry", entryLayout->GetKind(), ent );
7025 }
7026 }
7027 if( layout != NULL )
7028 {
7029 /* REVISIT_TODO Thu 12/15/2005
7030 * Where is this data?
7031 */
7032 }
7033 DisplayEndArray( "Total Per instance Info",
7034 METHODTABLES ); //m_pEntries
7035 DisplayEndStructure( METHODTABLES ); //Dictionary
7036 }
7037 DisplayEndStructure( METHODTABLES ); //m_pPerInstInfo
7038 }
7039
7040#ifdef _DEBUG
7041 WriteFieldStr( debug_m_szClassName,
7042 PTR_BYTE(TO_TADDR(mt->debug_m_szClassName)), MethodTable,
7043 METHODTABLES );
7044#if 0 //already dumping the optional member
7045 PTR_InterfaceInfo imap( TO_TADDR(mt->m_pIMapDEBUG) );
7046 /* REVISIT_TODO Mon 10/24/2005
7047 * Dump interface map
7048 */
7049 DisplayStartArrayWithOffset( m_pIMapDEBUG, NULL, MethodTable,
7050 METHODTABLES );
7051 DisplayEndArray( "Total Interfaces", METHODTABLES );
7052#endif
7053#endif
7054
7055 if( mt->HasDispatchMapSlot() )
7056 {
7057 PTR_DispatchMap dispatchMap(mt->GetDispatchMap());
7058
7059 DisplayStartStructure( "DispatchMap",
7060 DPtrToPreferredAddr(dispatchMap),
7061 DispatchMap::GetObjectSize(dispatchMap->GetMapSize()),
7062 METHODTABLES );
7063
7064 IF_OPT(VERBOSE_TYPES )
7065 {
7066 DispatchMap::Iterator iter(mt);
7067 DisplayStartArray( "DispatchMap", NULL, VERBOSE_TYPES );
7068 while( iter.Next() )
7069 {
7070 DispatchMapEntry * ent = iter.Entry();
7071
7072 DisplayStartElement( "Entry", METHODTABLES );
7073 DisplayStartVStructure( "TypeID", METHODTABLES );
7074 DispatchMapTypeID typeID = ent->GetTypeID();
7075 if( typeID.IsThisClass() )
7076 DisplayWriteElementFlag("IsThisClass", true, METHODTABLES );
7077 else if( typeID.IsImplementedInterface() )
7078 {
7079 DisplayWriteElementFlag( "IsImplementedInterface",
7080 true, METHODTABLES );
7081 DisplayWriteElementInt( "GetInterfaceNum",
7082 typeID.GetInterfaceNum(), METHODTABLES );
7083 }
7084 DisplayEndStructure( METHODTABLES ); //TypeID
7085 m_display->WriteElementInt( "SlotNumber",
7086 ent->GetSlotNumber() );
7087 DisplayWriteElementInt( "TargetSlotNumber",
7088 ent->GetSlotNumber(), METHODTABLES );
7089
7090 m_display->EndElement(); //Entry
7091 }
7092 //DispatchMap
7093 DisplayEndArray("Total Dispatch Map Entries", METHODTABLES );
7094 }
7095 else
7096 {
7097 CoverageRead(PTR_TO_TADDR(dispatchMap),
7098 DispatchMap::GetObjectSize(dispatchMap->GetMapSize()));
7099 }
7100
7101 DisplayEndStructure( METHODTABLES ); //DispatchMap
7102 }
7103
7104 IF_OPT( METHODTABLES )
7105 {
7106 m_display->StartStructureWithOffset("Vtable",
7107 mt->GetVtableOffset(),
7108 mt->GetNumVtableIndirections() * sizeof(MethodTable::VTableIndir_t),
7109 DataPtrToDisplay(PTR_TO_TADDR(mt) + mt->GetVtableOffset()),
7110 mt->GetNumVtableIndirections() * sizeof(MethodTable::VTableIndir_t));
7111
7112
7113 MethodTable::VtableIndirectionSlotIterator itIndirect = mt->IterateVtableIndirectionSlots();
7114 while (itIndirect.Next())
7115 {
7116 SlotChunk sc;
7117 sc.addr = dac_cast<TADDR>(itIndirect.GetIndirectionSlot());
7118 sc.nSlots = (WORD)itIndirect.GetNumSlots();
7119 sc.isRelative = MethodTable::VTableIndir2_t::isRelative;
7120 m_discoveredSlotChunks.AppendEx(sc);
7121 }
7122
7123 IF_OPT(VERBOSE_TYPES)
7124 {
7125 DisplayStartList( W("[%-4s]: %s (%s)"), ALWAYS );
7126 for( unsigned i = 0; i < mt->GetNumVtableIndirections(); ++i )
7127 {
7128 DisplayStartElement( "Slot", ALWAYS );
7129 DisplayWriteElementInt( "Index", i, ALWAYS );
7130 TADDR base = dac_cast<TADDR>(&(mt->GetVtableIndirections()[i]));
7131 DPTR(MethodTable::VTableIndir2_t) tgt = MethodTable::VTableIndir_t::GetValueMaybeNullAtPtr(base);
7132 DisplayWriteElementPointer( "Pointer",
7133 DataPtrToDisplay(dac_cast<TADDR>(tgt)),
7134 ALWAYS );
7135 DisplayWriteElementString( "Type", "chunk indirection",
7136 ALWAYS );
7137 DisplayEndElement( ALWAYS ); //Slot
7138 }
7139
7140 if (mt->HasNonVirtualSlotsArray())
7141 {
7142 DisplayStartElement( "Slot", ALWAYS );
7143 DisplayWriteElementInt( "Index", -1, ALWAYS );
7144 PTR_PCODE tgt = mt->GetNonVirtualSlotsArray();
7145 DisplayWriteElementPointer( "Pointer",
7146 DataPtrToDisplay(dac_cast<TADDR>(tgt)),
7147 ALWAYS );
7148 DisplayWriteElementString( "Type", "non-virtual chunk indirection",
7149 ALWAYS );
7150 DisplayEndElement( ALWAYS ); //Slot
7151
7152 SlotChunk sc;
7153 sc.addr = dac_cast<TADDR>(tgt);
7154 sc.nSlots = (mt->GetNumVtableSlots() - mt->GetNumVirtuals());
7155 sc.isRelative = false;
7156 m_discoveredSlotChunks.AppendEx(sc);
7157 }
7158 else if (mt->HasSingleNonVirtualSlot())
7159 {
7160 DumpSlot((unsigned)-1, mt->GetSlot(mt->GetNumVirtuals()));
7161 }
7162
7163 DisplayEndList( ALWAYS ); //vtable
7164 }
7165 else
7166 {
7167 CoverageRead( PTR_TO_TADDR(mt) + mt->GetVtableOffset(),
7168 mt->GetNumVtableIndirections() * sizeof(MethodTable::VTableIndir_t) );
7169
7170 if (mt->HasNonVirtualSlotsArray())
7171 {
7172 CoverageRead( PTR_TO_TADDR(mt->GetNonVirtualSlotsArray()),
7173 mt->GetNonVirtualSlotsArraySize() );
7174 }
7175
7176 }
7177 DisplayEndStructure(ALWAYS); //Vtable
7178 }
7179
7180 if( mt->HasInterfaceMap() && CHECK_OPT(METHODTABLES) )
7181 {
7182 PTR_InterfaceInfo ifMap = mt->GetInterfaceMap();
7183 m_display->StartArrayWithOffset( "InterfaceMap",
7184 offsetof(MethodTable, m_pInterfaceMap),
7185 sizeof(void*),
7186 NULL );
7187 for( unsigned i = 0; i < mt->GetNumInterfaces(); ++i )
7188 {
7189 PTR_InterfaceInfo info = ifMap + i;
7190 DisplayStartStructure( "InterfaceInfo_t", DPtrToPreferredAddr(info),
7191 sizeof(*info), METHODTABLES );
7192 WriteFieldMethodTable( m_pMethodTable,
7193 info->GetMethodTable(),
7194 InterfaceInfo_t, METHODTABLES );
7195 DisplayEndStructure( METHODTABLES ); //InterfaceInfo_t
7196 }
7197 DisplayEndArray( "Total InterfaceInfos",
7198 METHODTABLES ); //InterfaceMap
7199 }
7200
7201 //rest of the optional members
7202
7203 //GenericStatics comes after the generic dictionaries. So if I
7204 //don't have extents, I can't print them.
7205 if( haveCompleteExtents &&
7206 mt->HasGenericsStaticsInfo() &&
7207 CHECK_OPT(METHODTABLES)
7208 )
7209 {
7210 PTR_GenericsStaticsInfo genStatics = mt->GetGenericsStaticsInfo();
7211 m_display->StartStructureWithOffset( "OptionalMember_"
7212 "GenericsStaticsInfo",
7213 mt->GetOffsetOfOptionalMember(MethodTable::OptionalMember_GenericsStaticsInfo),
7214 sizeof(*genStatics),
7215 DPtrToPreferredAddr(genStatics),
7216 sizeof(*genStatics) );
7217
7218 PTR_FieldDesc fieldDescs = ReadPointerMaybeNull((GenericsStaticsInfo *) genStatics, &GenericsStaticsInfo::m_pFieldDescs);
7219 if( fieldDescs == NULL )
7220 {
7221 DisplayWriteFieldPointer( m_pFieldDescs, NULL, GenericsStaticsInfo,
7222 ALWAYS );
7223 }
7224 else
7225 {
7226 DisplayStartArrayWithOffset( m_pFieldDescs, NULL,
7227 GenericsStaticsInfo, ALWAYS );
7228 _ASSERTE(clazz == GetClassFromMT(mt));
7229 for( int i = 0; i < clazz->GetNumStaticFields(); ++i )
7230 {
7231 PTR_FieldDesc fd = fieldDescs + i;
7232 DumpFieldDesc( fd, "FieldDesc" );
7233 }
7234 DisplayEndArray( "Total Static Fields", ALWAYS ); // m_pFieldDescs
7235 }
7236 DisplayWriteFieldUInt( m_DynamicTypeID, (DWORD)genStatics->m_DynamicTypeID,
7237 GenericsStaticsInfo, METHODTABLES );
7238
7239 DisplayEndStructure( METHODTABLES );//OptionalMember_GenericsStaticsInfo
7240
7241 }
7242
7243#ifdef FEATURE_COMINTEROP
7244 if (haveCompleteExtents &&
7245 mt->HasGuidInfo() &&
7246 CHECK_OPT(METHODTABLES)
7247 )
7248 {
7249 PTR_GuidInfo guidInfo(*mt->GetGuidInfoPtr());
7250
7251 if (guidInfo != NULL)
7252 {
7253 m_display->StartStructureWithOffset( "OptionalMember_GuidInfo",
7254 mt->GetOffsetOfOptionalMember(MethodTable::OptionalMember_GuidInfo),
7255 sizeof(void*),
7256 DPtrToPreferredAddr(guidInfo),
7257 sizeof(GuidInfo)
7258 );
7259 TempBuffer buf;
7260 GuidToString( guidInfo->m_Guid, buf );
7261 DisplayWriteFieldStringW( m_Guid, (const WCHAR *)buf, GuidInfo,
7262 ALWAYS );
7263 DisplayWriteFieldFlag( m_bGeneratedFromName,
7264 guidInfo->m_bGeneratedFromName,
7265 GuidInfo, ALWAYS );
7266 DisplayEndStructure( ALWAYS ); // OptionalMember_GuidInfo
7267 }
7268 }
7269
7270 if (haveCompleteExtents &&
7271 mt->HasCCWTemplate()
7272 && CHECK_OPT(METHODTABLES)
7273 )
7274 {
7275 PTR_ComCallWrapperTemplate ccwTemplate(TO_TADDR(*mt->GetCCWTemplatePtr()));
7276 m_display->WriteFieldPointer( "OptionalMember_CCWTemplate",
7277 mt->GetOffsetOfOptionalMember(MethodTable::OptionalMember_CCWTemplate),
7278 sizeof(void *),
7279 DPtrToPreferredAddr(ccwTemplate)
7280 );
7281 }
7282#endif // FEATURE_COMINTEROP
7283
7284 DisplayEndStructure( METHODTABLES ); //MethodTable
7285} // NativeImageDumper::DumpMethodTable
7286#ifdef _PREFAST_
7287#pragma warning(pop)
7288#endif
7289
7290void
7291NativeImageDumper::DumpMethodTableSlotChunk( TADDR slotChunk, COUNT_T numSlots, bool isRelative )
7292{
7293 IF_OPT( METHODTABLES )
7294 {
7295 COUNT_T slotsSize;
7296 if (isRelative)
7297 {
7298 slotsSize = numSlots * sizeof(RelativePointer<PCODE>);
7299 }
7300 else
7301 {
7302 slotsSize = numSlots * sizeof(PCODE);
7303 }
7304 DisplayStartStructure( "MethodTableSlotChunk", DataPtrToDisplay(slotChunk), slotsSize, METHODTABLES );
7305
7306 IF_OPT(VERBOSE_TYPES)
7307 {
7308 DisplayStartList( W("[%-4s]: %s (%s)"), ALWAYS );
7309 for( unsigned i = 0; i < numSlots; ++i )
7310 {
7311 PCODE target;
7312 if (isRelative)
7313 {
7314 target = RelativePointer<PCODE>::GetValueMaybeNullAtPtr(slotChunk + i * sizeof(RelativePointer<PCODE>));
7315 }
7316 else
7317 {
7318 target = dac_cast<PTR_PCODE>(slotChunk)[i];
7319 }
7320
7321 DumpSlot(i, target);
7322 }
7323 DisplayEndList( ALWAYS ); //Slot list
7324 }
7325 else
7326 CoverageRead( slotChunk, slotsSize );
7327 DisplayEndStructure(ALWAYS); //Slot chunk
7328 }
7329}
7330
7331
7332void
7333NativeImageDumper::DumpSlot( unsigned index, PCODE tgt )
7334{
7335 IF_OPT(VERBOSE_TYPES)
7336 {
7337 DisplayStartElement( "Slot", ALWAYS );
7338 DisplayWriteElementInt( "Index", index, ALWAYS );
7339 DisplayWriteElementPointer( "Pointer",
7340 DataPtrToDisplay(tgt),
7341 ALWAYS );
7342 if( !isInRange(TO_TADDR(tgt)) )
7343 {
7344 DisplayWriteElementString( "Type", "external",
7345 ALWAYS );
7346 }
7347 else if( isPrecode(TO_TADDR(tgt))
7348 && Precode::IsValidType(PTR_Precode(TO_TADDR(tgt))->GetType()) )
7349 {
7350 PTR_Precode precode(TO_TADDR(tgt));
7351 DisplayWriteElementString( "Type", "precode",
7352 ALWAYS );
7353 //DumpPrecode( precode, module );
7354 }
7355 else
7356 {
7357 DisplayWriteElementString( "Type", "code pointer",
7358 ALWAYS );
7359 }
7360 DisplayEndElement( ALWAYS ); //Slot
7361 }
7362}
7363
7364NativeImageDumper::EnumMnemonics NativeImageDumper::s_SSMDExtendedFlags[] =
7365{
7366#define SSMD_ENTRY(x) NativeImageDumper::EnumMnemonics( x, W(#x) )
7367
7368#define SSMD_ACCESS_ENTRY(x) NativeImageDumper::EnumMnemonics( x, mdMemberAccessMask, W(#x) )
7369 SSMD_ACCESS_ENTRY(mdPrivateScope),
7370 SSMD_ACCESS_ENTRY(mdPrivate),
7371 SSMD_ACCESS_ENTRY(mdFamANDAssem),
7372 SSMD_ACCESS_ENTRY(mdAssem),
7373 SSMD_ACCESS_ENTRY(mdFamily),
7374 SSMD_ACCESS_ENTRY(mdFamORAssem),
7375 SSMD_ACCESS_ENTRY(mdPublic),
7376#undef SSMD_ACCESS_ENTRY
7377
7378 SSMD_ENTRY(mdStatic),
7379 SSMD_ENTRY(mdFinal),
7380 SSMD_ENTRY(mdVirtual),
7381 SSMD_ENTRY(mdHideBySig),
7382
7383 SSMD_ENTRY(mdVtableLayoutMask),
7384 SSMD_ENTRY(mdNewSlot),
7385
7386 SSMD_ENTRY(mdCheckAccessOnOverride),
7387 SSMD_ENTRY(mdAbstract),
7388 SSMD_ENTRY(mdSpecialName),
7389
7390 SSMD_ENTRY(mdPinvokeImpl),
7391 SSMD_ENTRY(mdUnmanagedExport),
7392
7393 SSMD_ENTRY(mdRTSpecialName),
7394 SSMD_ENTRY(mdHasSecurity),
7395 SSMD_ENTRY(mdRequireSecObject),
7396
7397 NativeImageDumper::EnumMnemonics( DynamicMethodDesc::nomdILStub,
7398 W("nomdILStub") ),
7399 NativeImageDumper::EnumMnemonics( DynamicMethodDesc::nomdLCGMethod,
7400 W("nomdLCGMethod") ),
7401#undef SSMD_ENTRY
7402};
7403
7404//maps MethodClassification to a name for a MethodDesc
7405const char * const s_MDTypeName[] =
7406{
7407 "MethodDesc", //mcIL
7408 "FCallMethodDesc", //mcFCall
7409 "NDirectMethodDesc", //mcNDirect
7410 "EEImplMethodDesc", //mcEEImpl - //public StoredSigMethodDesc
7411 "ArrayMethodDesc", //mcArray - //public StoredSigMethodDesc
7412 "InstantiatedMethodDesc", //mcInstantiated
7413#if defined(FEATURE_COMINTEROP)
7414 "ComPlusCallMethodDesc", //mcComInterop
7415#else
7416 "",
7417#endif
7418 "DynamicMethodDesc", //mcDynamic -- //public StoredSigMethodDesc
7419};
7420
7421unsigned s_MDSizes[] =
7422{
7423 sizeof(MethodDesc), //mcIL
7424 sizeof(FCallMethodDesc), //mcFCall
7425 sizeof(NDirectMethodDesc), //mcNDirect
7426 sizeof(EEImplMethodDesc), //mcEEImpl
7427 sizeof(ArrayMethodDesc), //mcArray
7428 sizeof(InstantiatedMethodDesc), //mcInstantiated
7429#if defined(FEATURE_COMINTEROP)
7430 sizeof(ComPlusCallMethodDesc), //mcComInterop
7431#else
7432 0,
7433#endif
7434 sizeof(DynamicMethodDesc), //mcDynamic
7435};
7436
7437static NativeImageDumper::EnumMnemonics g_NDirectFlags[] =
7438{
7439#define NDF_ENTRY(x) NativeImageDumper::EnumMnemonics( NDirectMethodDesc:: x, W(#x) )
7440 NDF_ENTRY(kEarlyBound),
7441 NDF_ENTRY(kHasSuppressUnmanagedCodeAccess),
7442 NDF_ENTRY(kIsMarshalingRequiredCached),
7443 NDF_ENTRY(kCachedMarshalingRequired),
7444 NDF_ENTRY(kNativeAnsi),
7445 NDF_ENTRY(kLastError),
7446 NDF_ENTRY(kNativeNoMangle),
7447 NDF_ENTRY(kVarArgs),
7448 NDF_ENTRY(kStdCall),
7449 NDF_ENTRY(kThisCall),
7450 NDF_ENTRY(kIsQCall),
7451 NDF_ENTRY(kHasCopyCtorArgs),
7452 NDF_ENTRY(kStdCallWithRetBuf),
7453#undef NDF_ENTRY
7454};
7455NativeImageDumper::EnumMnemonics NativeImageDumper::s_IMDFlags[] =
7456{
7457#define IMD_ENTRY(x) NativeImageDumper::EnumMnemonics( InstantiatedMethodDesc:: x, W(#x) )
7458
7459#define IMD_KIND_ENTRY(x) NativeImageDumper::EnumMnemonics( InstantiatedMethodDesc:: x, InstantiatedMethodDesc::KindMask, W(#x) )
7460 IMD_KIND_ENTRY(GenericMethodDefinition),
7461 IMD_KIND_ENTRY(UnsharedMethodInstantiation),
7462 IMD_KIND_ENTRY(SharedMethodInstantiation),
7463 IMD_KIND_ENTRY(WrapperStubWithInstantiations),
7464#undef IMD_KIND_ENTRY
7465
7466#ifdef EnC_SUPPORTED
7467 // Method is a new virtual function added through EditAndContinue.
7468 IMD_ENTRY(EnCAddedMethod),
7469#endif // EnC_SUPPORTED
7470
7471 IMD_ENTRY(Unrestored),
7472
7473#ifdef FEATURE_COMINTEROP
7474 IMD_ENTRY(HasComPlusCallInfo),
7475#endif // FEATURE_COMINTEROP
7476
7477#undef IMD_ENTRY
7478};
7479
7480void NativeImageDumper::DumpPrecode( PTR_Precode precode, PTR_Module module )
7481{
7482 _ASSERTE(isPrecode(PTR_TO_TADDR(precode)));
7483
7484 PrecodeType pType = precode->GetType();
7485 switch(pType)
7486 {
7487#define DISPLAY_PRECODE(type) \
7488 IF_OPT_AND(PRECODES, METHODDESCS) \
7489 { \
7490 PTR_ ## type p( precode->As ## type () ); \
7491 DisplayStartStructure( # type, \
7492 DPtrToPreferredAddr(p), \
7493 sizeof(*p), ALWAYS ); \
7494 WriteFieldMethodDesc( m_pMethodDesc, \
7495 p->m_pMethodDesc, \
7496 type, ALWAYS ); \
7497 TADDR target = p->GetTarget(); \
7498 DisplayWriteElementPointer("Target",\
7499 DataPtrToDisplay(target),\
7500 ALWAYS );\
7501 DisplayEndStructure( ALWAYS ); \
7502 }
7503
7504 case PRECODE_STUB:
7505 DISPLAY_PRECODE(StubPrecode); break;
7506#ifdef HAS_NDIRECT_IMPORT_PRECODE
7507 case PRECODE_NDIRECT_IMPORT:
7508 DISPLAY_PRECODE(NDirectImportPrecode); break;
7509#endif
7510#ifdef HAS_FIXUP_PRECODE
7511 case PRECODE_FIXUP:
7512 IF_OPT_AND(PRECODES, METHODDESCS)
7513 {
7514 PTR_FixupPrecode p( precode->AsFixupPrecode() );
7515 DisplayStartStructure( "FixupPrecode",
7516 DPtrToPreferredAddr(p),
7517 sizeof(*p),
7518 ALWAYS );
7519 PTR_MethodDesc precodeMD(p->GetMethodDesc());
7520#ifdef HAS_FIXUP_PRECODE_CHUNKS
7521 {
7522 DisplayWriteFieldInt( m_MethodDescChunkIndex,
7523 p->m_MethodDescChunkIndex, FixupPrecode,
7524 ALWAYS );
7525 DisplayWriteFieldInt( m_PrecodeChunkIndex,
7526 p->m_PrecodeChunkIndex, FixupPrecode,
7527 ALWAYS );
7528 if( p->m_PrecodeChunkIndex == 0 )
7529 {
7530 //dump the location of the Base
7531 DisplayWriteElementAddress( "PrecodeChunkBase",
7532 DataPtrToDisplay(p->GetBase()),
7533 sizeof(void*), ALWAYS );
7534 }
7535 //Make sure I align up if there is no code slot to make
7536 //sure that I get the padding
7537 TADDR mdPtrStart = p->GetBase()
7538 + (p->m_MethodDescChunkIndex * MethodDesc::ALIGNMENT);
7539 TADDR mdPtrEnd = ALIGN_UP( mdPtrStart + sizeof(MethodDesc*),
7540 8 );
7541 CoverageRead( mdPtrStart, (ULONG32)(mdPtrEnd - mdPtrStart) );
7542 TADDR precodeMDSlot = p->GetBase()
7543 + p->m_MethodDescChunkIndex * MethodDesc::ALIGNMENT;
7544 DoWriteFieldMethodDesc( "MethodDesc",
7545 (DWORD)(precodeMDSlot - PTR_TO_TADDR(p)),
7546 sizeof(TADDR), precodeMD );
7547 }
7548#else //HAS_FIXUP_PRECODE_CHUNKS
7549 WriteFieldMethodDesc( m_pMethodDesc,
7550 p->m_pMethodDesc,
7551 FixupPrecode, ALWAYS );
7552#endif //HAS_FIXUP_PRECODE_CHUNKS
7553 TADDR target = p->GetTarget();
7554 DisplayWriteElementPointer("Target",
7555 DataPtrToDisplay(target),
7556 ALWAYS );
7557 /* REVISIT_TODO Thu 01/05/2006
7558 * dump slot with offset if it is here
7559 */
7560 DisplayEndStructure( ALWAYS ); //FixupPrecode
7561 }
7562 break;
7563#endif
7564#ifdef HAS_THISPTR_RETBUF_PRECODE
7565 case PRECODE_THISPTR_RETBUF:
7566 DISPLAY_PRECODE(ThisPtrRetBufPrecode); break;
7567#endif
7568 default:
7569 _ASSERTE( !"Unsupported precode type" );
7570#undef DISPLAY_PRECODE
7571#undef PrecodeMDWrite
7572 }
7573}
7574
7575#ifdef _PREFAST_
7576#pragma warning(push)
7577#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
7578#endif
7579void NativeImageDumper::DumpMethodDesc( PTR_MethodDesc md, PTR_Module module )
7580{
7581 //StoredSigMethodDesc
7582
7583 MethodClassification mc =
7584 (MethodClassification)md->GetClassification();
7585 _ASSERTE(mc >= 0 && mc < mcCount);
7586 const char * mdTypeName = s_MDTypeName[mc];
7587 unsigned mdSize = (unsigned)md->SizeOf();
7588
7589 DisplayStartStructure( mdTypeName, DPtrToPreferredAddr(md),
7590 mdSize, METHODDESCS );
7591 IF_OPT(METHODDESCS)
7592 {
7593 TempBuffer buf;
7594 MethodDescToString( md, buf );
7595 DisplayWriteElementStringW( "Name", (const WCHAR *)buf, METHODDESCS );
7596 }
7597#ifdef _DEBUG
7598 IF_OPT(METHODDESCS)
7599 {
7600 WriteFieldStr(m_pszDebugMethodName,
7601 PTR_BYTE(TO_TADDR(md->m_pszDebugMethodName)),
7602 MethodDesc, METHODDESCS);
7603 WriteFieldStr(m_pszDebugClassName,
7604 PTR_BYTE(TO_TADDR(md->m_pszDebugClassName)),
7605 MethodDesc, METHODDESCS);
7606 WriteFieldStr(m_pszDebugMethodSignature,
7607 PTR_BYTE(TO_TADDR(md->m_pszDebugMethodSignature)),
7608 MethodDesc, METHODDESCS);
7609 }
7610 else
7611 {
7612 CoverageReadString(TO_TADDR(md->m_pszDebugMethodName));
7613 CoverageReadString(TO_TADDR(md->m_pszDebugClassName));
7614 CoverageReadString(TO_TADDR(md->m_pszDebugMethodSignature));
7615 }
7616#endif
7617
7618 DisplayWriteFieldInt( m_wFlags3AndTokenRemainder, md->m_wFlags3AndTokenRemainder,
7619 MethodDesc, METHODDESCS );
7620
7621 DisplayWriteFieldInt( m_chunkIndex, md->m_chunkIndex,
7622 MethodDesc, METHODDESCS );
7623
7624 /* XXX Fri 03/24/2006
7625 * This is a workaround. The InstantiatedMethodDescs are in chunks, but there's
7626 * no obvious place to display the chunk, so display the bounds here.
7627 */
7628 if( mc == mcInstantiated && md->m_chunkIndex == 0 )
7629 {
7630 PTR_MethodDescChunk chunk( md->GetMethodDescChunk() );
7631 DisplayWriteElementAddress( "MethodDescChunk", DPtrToPreferredAddr(chunk),
7632 chunk->SizeOf(), METHODDESCS );
7633 }
7634
7635 DisplayWriteFieldEnumerated( m_bFlags2, md->m_bFlags2, MethodDesc,
7636 s_MDFlag2, W(", "), METHODDESCS );
7637
7638 DisplayWriteFieldInt( m_wSlotNumber, md->GetSlot(), MethodDesc,
7639 METHODDESCS );
7640 DisplayWriteFieldEnumerated( m_wFlags, md->m_wFlags, MethodDesc,
7641 s_MDC, W(", "), METHODDESCS );
7642
7643 IF_OPT(IL)
7644 {
7645 if( md->IsIL() )
7646 {
7647 PTR_MethodDescChunk chunk(md->GetMethodDescChunk());
7648 //chunk is implicitly remapped because it's calculated from the pointer
7649 //to MD.
7650 PTR_MethodTable mt = chunk->GetMethodTable();
7651 if( !CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)) )
7652 {
7653 if ( md->IsTypicalMethodDefinition() )
7654 {
7655 DWORD dwRVA = 0;
7656 m_import->GetMethodProps(md->GetMemberDef(), NULL, NULL, NULL, 0,
7657 NULL, NULL, NULL, &dwRVA, NULL);
7658
7659 if (dwRVA != 0)
7660 {
7661 _ASSERTE(m_ILHostCopy);
7662 _ASSERTE(m_ILSectionStart);
7663 _ASSERTE(dwRVA >= m_ILSectionStart);
7664 _ASSERTE(dwRVA < (m_ILSectionStart + m_ILSectionSize));
7665 //The RVA is from the start of the file, so convert it
7666 //to an RVA to the start of the .text section.
7667 TADDR pILTarget = (TADDR)m_decoder.GetRvaData(dwRVA);
7668 COR_ILMETHOD * pILHeader = (COR_ILMETHOD*)(m_ILHostCopy + dwRVA - m_ILSectionStart);
7669
7670 COR_ILMETHOD_DECODER decoder(pILHeader);
7671
7672 DisplayStartStructure( "IL",
7673 DataPtrToDisplay(pILTarget),
7674 PEDecoder::ComputeILMethodSize(pILTarget),
7675 ALWAYS );
7676
7677 DisplayWriteElementInt( "CodeSize", decoder.GetCodeSize(), ALWAYS );
7678
7679 // Dump the disassembled IL code?
7680
7681 DisplayEndStructure( ALWAYS );
7682 }
7683 }
7684 }
7685 }
7686 }
7687 if( md->HasPrecode() )
7688 {
7689 PTR_Precode precode( md->GetPrecode() );
7690
7691 DumpPrecode( precode, module );
7692 }
7693 if ( md->HasNonVtableSlot() )
7694 {
7695 DisplayWriteElementInt( "Slot", (DWORD)(md->GetAddrOfSlot() - PTR_TO_TADDR(md)), ALWAYS);
7696 }
7697 if (md->HasNativeCodeSlot())
7698 {
7699 DisplayWriteElementInt( "NativeCode", DWORD(md->GetAddrOfNativeCodeSlot() - PTR_TO_TADDR(md)), ALWAYS);
7700 //m_display->WriteFieldPointer( "NativeCode",
7701 // DWORD(md->GetAddrOfNativeCodeSlot() - PTR_TO_TADDR(md)),
7702 // sizeof(TADDR),
7703 // md->GetNativeCode() );
7704 }
7705 if (md->HasMethodImplSlot())
7706 {
7707 DisplayStartVStructure( "MethodImpl", METHODDESCS );
7708 PTR_MethodImpl impl(md->GetMethodImpl());
7709 PTR_DWORD slots = impl->GetSlots() - 1; // GetSlots returns the address of the first real slot (past the size)
7710 unsigned numSlots = impl->GetSize();
7711 _ASSERTE(!numSlots || numSlots == slots[0]);
7712 _ASSERTE(slots == NULL || isInRange(PTR_TO_TADDR(slots)));
7713 if ((slots != NULL) && isInRange(PTR_TO_TADDR(slots)))
7714 {
7715 DisplayWriteFieldAddress(pdwSlots, DataPtrToDisplay(dac_cast<TADDR>(slots)),
7716 (numSlots + 1) * sizeof(*slots),
7717 MethodImpl, METHODDESCS);
7718 }
7719 else
7720 {
7721 DisplayWriteFieldPointer(pdwSlots, DataPtrToDisplay(dac_cast<TADDR>(slots)),
7722 MethodImpl, METHODDESCS);
7723
7724 }
7725 _ASSERTE(impl->pImplementedMD.IsNull()
7726 || isInRange(PTR_TO_TADDR(impl->GetImpMDsNonNull())));
7727 if (!impl->pImplementedMD.IsNull() &&
7728 isInRange(PTR_TO_TADDR(impl->GetImpMDsNonNull())))
7729 {
7730 DisplayWriteFieldAddress( pImplementedMD,
7731 DataPtrToDisplay(dac_cast<TADDR>(impl->GetImpMDsNonNull())),
7732 numSlots * sizeof(RelativePointer <MethodDesc*>),
7733 MethodImpl, METHODDESCS );
7734 }
7735 else
7736 {
7737 DisplayWriteFieldPointer( pImplementedMD,
7738 DataPtrToDisplay(dac_cast<TADDR>(impl->GetImpMDs())),
7739 MethodImpl, METHODDESCS );
7740 }
7741 DisplayEndVStructure( METHODDESCS );
7742 }
7743 if (md->HasStoredSig())
7744 {
7745 DisplayStartVStructure( "StoredSigMethodDesc", METHODDESCS );
7746 PTR_StoredSigMethodDesc ssmd(md);
7747 //display signature information.
7748 if( isInRange(ssmd->GetSigRVA()) )
7749 {
7750 DisplayWriteFieldAddress(m_pSig, DataPtrToDisplay(ssmd->GetSigRVA()),
7751 ssmd->m_cSig, StoredSigMethodDesc,
7752 METHODDESCS);
7753 }
7754 else
7755 {
7756 DisplayWriteFieldPointer(m_pSig, DataPtrToDisplay(ssmd->GetSigRVA()),
7757 StoredSigMethodDesc, METHODDESCS);
7758
7759 }
7760 CoverageRead(TO_TADDR(ssmd->GetSigRVA()), ssmd->m_cSig);
7761 DisplayWriteFieldInt( m_cSig, ssmd->m_cSig,
7762 StoredSigMethodDesc, METHODDESCS );
7763#ifdef _WIN64
7764 DisplayWriteFieldEnumerated( m_dwExtendedFlags,
7765 ssmd->m_dwExtendedFlags,
7766 StoredSigMethodDesc,
7767 s_SSMDExtendedFlags, W(", "),
7768 METHODDESCS );
7769#endif
7770 DisplayEndVStructure( METHODDESCS ); //StoredSigMethodDesc
7771 }
7772 if( mc == mcDynamic )
7773 {
7774 PTR_DynamicMethodDesc dmd(md);
7775 DisplayStartVStructure( "DynamicMethodDesc", METHODDESCS );
7776 WriteFieldStr( m_pszMethodName, PTR_BYTE(dmd->GetMethodName()),
7777 DynamicMethodDesc, METHODDESCS );
7778 if( !CHECK_OPT(METHODDESCS) )
7779 CoverageReadString( PTR_TO_TADDR(dmd->GetMethodName()) );
7780 DisplayWriteFieldPointer( m_pResolver,
7781 DPtrToPreferredAddr(dmd->m_pResolver),
7782 DynamicMethodDesc, METHODDESCS );
7783#ifndef _WIN64
7784 DisplayWriteFieldEnumerated( m_dwExtendedFlags,
7785 dmd->m_dwExtendedFlags,
7786 DynamicMethodDesc,
7787 s_SSMDExtendedFlags, W(", "),
7788 METHODDESCS );
7789#endif
7790 DisplayEndVStructure( METHODDESCS );
7791 }
7792 if (mc == mcFCall )
7793 {
7794 PTR_FCallMethodDesc fcmd(md);
7795 DisplayStartVStructure( "FCallMethodDesc", METHODDESCS );
7796
7797 DisplayWriteFieldInt( m_dwECallID,
7798 fcmd->m_dwECallID,
7799 FCallMethodDesc,
7800 METHODDESCS );
7801
7802 DisplayEndVStructure( METHODDESCS ); //NDirectMethodDesc
7803 }
7804 if( mc == mcNDirect )
7805 {
7806 PTR_NDirectMethodDesc ndmd(md);
7807 DisplayStartVStructure( "NDirectMethodDesc", METHODDESCS );
7808 DPTR(NDirectMethodDesc::temp1) nd( PTR_HOST_MEMBER_TADDR(NDirectMethodDesc, ndmd, ndirect) );
7809 DisplayStartStructureWithOffset( ndirect,
7810 DPtrToPreferredAddr(nd),
7811 sizeof(*nd), NDirectMethodDesc,
7812 METHODDESCS );
7813 DisplayWriteFieldPointer( m_pNativeNDirectTarget,
7814 DataPtrToDisplay((TADDR)nd->m_pNativeNDirectTarget),
7815 NDirectMethodDesc::temp1,
7816 METHODDESCS );
7817 DisplayWriteFieldEnumerated( m_wFlags, nd->m_wFlags,
7818 NDirectMethodDesc::temp1,
7819 g_NDirectFlags, W(", "),
7820 METHODDESCS );
7821
7822 WriteFieldStr( m_pszEntrypointName,
7823 PTR_BYTE(dac_cast<TADDR>(ndmd->GetEntrypointName())),
7824 NDirectMethodDesc::temp1, METHODDESCS );
7825 if( !CHECK_OPT(METHODDESCS) )
7826 CoverageReadString(dac_cast<TADDR>(ndmd->GetEntrypointName()));
7827 if (md->IsQCall())
7828 {
7829 DisplayWriteFieldInt( m_dwECallID,
7830 nd->m_dwECallID,
7831 NDirectMethodDesc::temp1,
7832 METHODDESCS );
7833 }
7834 else
7835 {
7836 WriteFieldStr( m_pszLibName,
7837 PTR_BYTE(dac_cast<TADDR>(ndmd->GetLibNameRaw())),
7838 NDirectMethodDesc::temp1, METHODDESCS );
7839 }
7840 if( !CHECK_OPT(METHODDESCS) )
7841 CoverageReadString( dac_cast<TADDR>(ndmd->GetLibNameRaw()) );
7842
7843 PTR_NDirectWriteableData wnd( ndmd->GetWriteableData() );
7844 DisplayStartStructureWithOffset( m_pWriteableData,
7845 DPtrToPreferredAddr(wnd),
7846 sizeof(*wnd),
7847 NDirectMethodDesc::temp1,
7848 METHODDESCS );
7849 DisplayWriteFieldPointer( m_pNDirectTarget,
7850 DataPtrToDisplay((TADDR)wnd->m_pNDirectTarget), NDirectWriteableData, METHODDESCS );
7851 if( !CHECK_OPT(METHODDESCS) )
7852 CoverageRead( PTR_TO_TADDR(wnd), sizeof(*wnd) );
7853 DisplayEndStructure( METHODDESCS ); //m_pWriteableData
7854
7855 PTR_NDirectImportThunkGlue glue(ndmd->GetNDirectImportThunkGlue());
7856
7857#ifdef HAS_NDIRECT_IMPORT_PRECODE
7858 if (glue == NULL)
7859 {
7860 // import thunk glue is not needed for P/Invoke that is not inlinable
7861 DisplayWriteFieldPointer( m_pImportThunkGlue,
7862 NULL,
7863 NDirectMethodDesc::temp1,
7864 METHODDESCS );
7865 }
7866 else
7867 {
7868 DisplayStartStructureWithOffset( m_pImportThunkGlue,
7869 DPtrToPreferredAddr(glue),
7870 sizeof(*glue),
7871 NDirectMethodDesc::temp1,
7872 METHODDESCS);
7873#else
7874 DisplayStartStructureWithOffset( m_ImportThunkGlue,
7875 DPtrToPreferredAddr(glue),
7876 sizeof(*glue),
7877 NDirectMethodDesc::temp1,
7878 METHODDESCS);
7879#endif
7880#ifdef HAS_NDIRECT_IMPORT_PRECODE
7881 /* REVISIT_TODO Thu 01/05/2006
7882 * Dump this properly as a precode
7883 */
7884 WriteFieldMethodDesc( m_pMethodDesc, glue->m_pMethodDesc,
7885 NDirectImportThunkGlue, METHODDESCS );
7886 {
7887 PTR_Precode p(glue);
7888 DumpPrecode( p, module );
7889 }
7890 if( !CHECK_OPT(METHODDESCS) )
7891 CoverageRead(PTR_TO_TADDR(glue), sizeof(*glue));
7892 /* REVISIT_TODO Fri 12/16/2005
7893 * Factor out this code into some shared precode dumping code
7894 */
7895#else //!HAS_NDIRECT_IMPORT_PRECODE
7896 /* REVISIT_TODO Fri 10/27/2006
7897 * For Whidbey AMD64 (!HAS_NDIRECT_IMPORT_PRECODE), I don't have this data structure in the output.
7898 */
7899#endif //HAS_NDIRECT_IMPORT_PRECODE
7900
7901 DisplayEndStructure( METHODDESCS ); //m_pImportThunkGlue
7902#ifdef HAS_NDIRECT_IMPORT_PRECODE
7903 }
7904#endif
7905
7906#ifdef _TARGET_X86_
7907 DisplayWriteFieldInt( m_cbStackArgumentSize,
7908 nd->m_cbStackArgumentSize,
7909 NDirectMethodDesc::temp1, METHODDESCS );
7910#endif
7911
7912 WriteFieldMethodDesc( m_pStubMD,
7913 nd->m_pStubMD.GetValueMaybeNull(PTR_HOST_MEMBER_TADDR(NDirectMethodDesc::temp1, nd, m_pStubMD)),
7914 NDirectMethodDesc::temp1, METHODDESCS );
7915
7916 DisplayEndStructure( METHODDESCS ); //ndirect
7917
7918
7919 DisplayEndVStructure( METHODDESCS ); //NDirectMethodDesc
7920 }
7921 if( mc == mcEEImpl )
7922 {
7923 DisplayStartVStructure( "EEImplMethodDesc", METHODDESCS );
7924 DisplayEndVStructure( METHODDESCS );
7925 }
7926#if defined(FEATURE_COMINTEROP)
7927 if( mc == mcComInterop )
7928 {
7929 PTR_ComPlusCallMethodDesc cpmd(md);
7930 DisplayStartVStructure( "ComPlusCallMethodDesc", METHODDESCS );
7931 PTR_ComPlusCallInfo compluscall((TADDR)cpmd->m_pComPlusCallInfo);
7932
7933 if (compluscall == NULL)
7934 {
7935 DisplayWriteFieldPointer( m_pComPlusCallInfo,
7936 NULL,
7937 ComPlusCallMethodDesc,
7938 METHODDESCS );
7939 }
7940 else
7941 {
7942 DumpComPlusCallInfo( compluscall, METHODDESCS );
7943 }
7944
7945 DisplayEndVStructure( METHODDESCS ); //ComPlusCallMethodDesc
7946 }
7947#endif
7948 if( mc == mcInstantiated )
7949 {
7950 PTR_InstantiatedMethodDesc imd(md);
7951 DisplayStartVStructure( "InstantiatedMethodDesc", METHODDESCS );
7952 unsigned kind = imd->m_wFlags2
7953 & InstantiatedMethodDesc::KindMask;
7954 if( kind == InstantiatedMethodDesc::SharedMethodInstantiation )
7955 {
7956 PTR_DictionaryLayout layout(dac_cast<TADDR>(imd->GetDictLayoutRaw()));
7957 IF_OPT(METHODDESCS)
7958 {
7959 WriteFieldDictionaryLayout( "m_pDictLayout",
7960 offsetof(InstantiatedMethodDesc, m_pDictLayout ),
7961 fieldsize(InstantiatedMethodDesc, m_pDictLayout),
7962 layout,
7963 GetDependencyFromMD(md)->pImport );
7964 }
7965 else
7966 {
7967 while( layout != NULL )
7968 {
7969 CoverageRead( PTR_TO_TADDR(layout),
7970 sizeof(DictionaryLayout)
7971 + sizeof(DictionaryEntryLayout)
7972 * (layout->m_numSlots - 1) );
7973 layout = PTR_DictionaryLayout(TO_TADDR(layout->m_pNext));
7974 }
7975 }
7976 }
7977 else if( kind ==
7978 InstantiatedMethodDesc::WrapperStubWithInstantiations )
7979 {
7980 PTR_MethodDesc wimd(imd->IMD_GetWrappedMethodDesc());
7981 if( wimd == NULL || !DoWriteFieldAsFixup( "m_pWrappedMethodDesc",
7982 offsetof(InstantiatedMethodDesc, m_pWrappedMethodDesc),
7983 fieldsize(InstantiatedMethodDesc, m_pWrappedMethodDesc),
7984 PTR_TO_TADDR(wimd) ) )
7985 {
7986 WriteFieldMethodDesc( m_pWrappedMethodDesc, wimd,
7987 InstantiatedMethodDesc, METHODDESCS );
7988 }
7989 }
7990 else
7991 {
7992 _ASSERTE(imd->m_pDictLayout.IsNull());
7993 DisplayWriteFieldPointer( m_pDictLayout, NULL,
7994 InstantiatedMethodDesc,
7995 METHODDESCS );
7996 }
7997 //now handle the contents of the m_pMethInst/m_pPerInstInfo union.
7998 unsigned numSlots = imd->m_wNumGenericArgs;
7999 PTR_Dictionary inst(imd->IMD_GetMethodDictionary());
8000 unsigned dictSize;
8001 if( kind == InstantiatedMethodDesc::SharedMethodInstantiation )
8002 {
8003 dictSize = sizeof(TypeHandle);
8004 }
8005 else if( kind == InstantiatedMethodDesc::WrapperStubWithInstantiations )
8006 {
8007 PTR_InstantiatedMethodDesc wrapped =
8008 PTR_InstantiatedMethodDesc(imd->IMD_GetWrappedMethodDesc());
8009 if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(wrapped)) )
8010 {
8011 /* XXX Mon 03/27/2006
8012 * Note that 4 is the correct answer for all IMDs at this time.
8013 */
8014 TempBuffer buf;
8015 MethodDescToString( md, buf );
8016 //m_display->ErrorPrintF( "WARNING! InstantiatedMethodDesc %S wraps a MethodDesc that is a fixup. I cannot accurately determine the size of the associated generic dictionary. Assuming 4.\n", (const WCHAR *)buf );
8017 dictSize = (imd->GetNumGenericMethodArgs() + 4) * sizeof(void*);
8018 }
8019 else
8020 {
8021 PTR_DictionaryLayout layout(wrapped->IsSharedByGenericMethodInstantiations()
8022 ? dac_cast<TADDR>(wrapped->GetDictLayoutRaw()) : NULL );
8023 dictSize = DictionaryLayout::GetFirstDictionaryBucketSize(imd->GetNumGenericMethodArgs(),
8024 layout);
8025 }
8026 }
8027 else
8028 {
8029 dictSize = sizeof(TypeHandle);
8030 }
8031 //instantiations has the number of slots of
8032 //GetNumGenericMethodArgs.
8033 if( inst == NULL )
8034 {
8035 m_display->WriteFieldPointer( "m_pPerInstInfo",
8036 offsetof(InstantiatedMethodDesc, m_pPerInstInfo),
8037 fieldsize(InstantiatedMethodDesc, m_pPerInstInfo),
8038 NULL );
8039 }
8040 else
8041 {
8042 IF_OPT(METHODDESCS)
8043 {
8044
8045 m_display->StartStructureWithOffset( "m_pPerInstInfo",
8046 offsetof(InstantiatedMethodDesc, m_pPerInstInfo),
8047 fieldsize(InstantiatedMethodDesc, m_pPerInstInfo),
8048 DPtrToPreferredAddr(inst),
8049 dictSize );
8050 }
8051 DisplayStartArray( "InstantiationInfo", W("[%-2s]: %s"),
8052 METHODDESCS );
8053 /* REVISIT_TODO Thu 03/23/2006
8054 * This doesn't dump the contents of the dictionary which are
8055 * hanging around after the real slots. Get around to doing that.
8056 */
8057 for( unsigned i = 0; i < numSlots
8058 && CHECK_OPT(METHODDESCS); ++i )
8059 {
8060 DisplayStartElement( "Handle", METHODDESCS );
8061 DisplayWriteElementInt( "Index", i, METHODDESCS );
8062
8063 TypeHandle thArg = inst->GetInstantiation()[i].GetValue();
8064 IF_OPT(METHODDESCS)
8065 WriteElementTypeHandle( "TypeHandle", thArg);
8066
8067 /* XXX Fri 03/24/2006
8068 * There is no really good home for TypeDescs, so I gotta check
8069 * lots of places for them.
8070 */
8071 if( !CORCOMPILE_IS_POINTER_TAGGED(thArg.AsTAddr()) &&
8072 thArg.IsTypeDesc() )
8073 {
8074 PTR_TypeDesc td(thArg.AsTypeDesc());
8075 if( isInRange(PTR_TO_TADDR(td)) )
8076 {
8077 m_discoveredTypeDescs.AppendEx(td);
8078 }
8079 }
8080 DisplayEndElement( METHODDESCS ); //Handle
8081 }
8082 //Instantiation Info
8083 DisplayEndArray( "Total TypeHandles", METHODDESCS );
8084
8085 DisplayEndVStructure(METHODDESCS); //m_pPerInstInfo;
8086 if( !CHECK_OPT(METHODDESCS) )
8087 CoverageRead(PTR_TO_TADDR(inst), numSlots * sizeof(*inst));
8088 }
8089
8090 DisplayWriteFieldEnumerated( m_wFlags2, imd->m_wFlags2,
8091 InstantiatedMethodDesc, s_IMDFlags,
8092 W(", "), METHODDESCS );
8093 DisplayWriteFieldInt( m_wNumGenericArgs, imd->m_wNumGenericArgs,
8094 InstantiatedMethodDesc, METHODDESCS );
8095
8096#ifdef FEATURE_COMINTEROP
8097 if (imd->IMD_HasComPlusCallInfo())
8098 {
8099 PTR_ComPlusCallInfo compluscall = imd->IMD_GetComPlusCallInfo();
8100 DumpComPlusCallInfo( compluscall, METHODDESCS );
8101 }
8102#endif // FEATURE_COMINTEROP
8103
8104 DisplayEndStructure( METHODDESCS );
8105 }
8106
8107 DisplayEndStructure( METHODDESCS ); //MethodDesc (mdTypeName)
8108 if( !CHECK_OPT(METHODDESCS) )
8109 CoverageRead( PTR_TO_TADDR(md), mdSize );
8110
8111}
8112#ifdef _PREFAST_
8113#pragma warning(pop)
8114#endif
8115
8116NativeImageDumper::EnumMnemonics NativeImageDumper::s_EECLIFlags[] =
8117{
8118#define EECLI_FLAGS_ENTRY(x) NativeImageDumper::EnumMnemonics( EEClassLayoutInfo:: x, W(#x) )
8119 EECLI_FLAGS_ENTRY(e_BLITTABLE),
8120 EECLI_FLAGS_ENTRY(e_MANAGED_SEQUENTIAL),
8121 EECLI_FLAGS_ENTRY(e_ZERO_SIZED),
8122 EECLI_FLAGS_ENTRY(e_HAS_EXPLICIT_SIZE),
8123#undef EECLI_FLAGS_ENTRY
8124};
8125
8126
8127#ifdef _PREFAST_
8128#pragma warning(push)
8129#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
8130#endif
8131void
8132NativeImageDumper::DumpEEClassForMethodTable( PTR_MethodTable mt )
8133{
8134 PTR_EEClass clazz = mt->GetClass();
8135
8136 _ASSERTE(CHECK_OPT(EECLASSES));
8137 _ASSERTE(clazz != NULL);
8138 _ASSERTE(isInRange(PTR_TO_TADDR(clazz)));
8139
8140 const char * eeClassType;
8141
8142 if( clazz->HasLayout() )
8143 eeClassType = "LayoutEEClass";
8144 else if( mt->IsArray() )
8145 eeClassType = "ArrayClass";
8146 else if( clazz->IsDelegate() )
8147 eeClassType = "DelegateEEClass";
8148 else
8149 eeClassType = "EEClass";
8150
8151 DisplayStartStructure( eeClassType, DPtrToPreferredAddr(clazz), clazz->GetSize(),
8152 EECLASSES );
8153 {
8154 TempBuffer buf;
8155 MethodTableToString( mt, buf );
8156 DisplayWriteElementStringW( "Name", (const WCHAR *)buf, EECLASSES );
8157 }
8158
8159 PTR_GuidInfo guidInfo = clazz->GetGuidInfo();
8160 if(guidInfo != NULL)
8161 {
8162 DisplayStartStructureWithOffset( m_pGuidInfo,
8163 DPtrToPreferredAddr(guidInfo),
8164 sizeof(*guidInfo), EEClass,
8165 EECLASSES );
8166 TempBuffer buf;
8167 GuidToString( guidInfo->m_Guid, buf );
8168 DisplayWriteFieldStringW( m_Guid, (const WCHAR *)buf, GuidInfo,
8169 EECLASSES );
8170 DisplayWriteFieldFlag( m_bGeneratedFromName,
8171 guidInfo->m_bGeneratedFromName,
8172 GuidInfo, EECLASSES );
8173 DisplayEndStructure( EECLASSES ); //guidinfo
8174 }
8175 else
8176 {
8177 /* XXX Fri 10/14/2005
8178 * if Clazz isn't an interface, m_pGuidInfo is undefined.
8179 */
8180 DisplayWriteFieldPointerAnnotated( m_pGuidInfo, PTR_TO_TADDR(guidInfo),
8181 W("Invalid"), EEClass, EECLASSES );
8182 }
8183
8184
8185#ifdef _DEBUG
8186 WriteFieldStr( m_szDebugClassName,
8187 PTR_BYTE(TO_TADDR(clazz->m_szDebugClassName)),
8188 EEClass, EECLASSES );
8189 DisplayWriteFieldFlag( m_fDebuggingClass, clazz->m_fDebuggingClass,
8190 EEClass, EECLASSES );
8191#endif
8192
8193 WriteFieldMethodTable( m_pMethodTable, clazz->GetMethodTable(), EEClass,
8194 EECLASSES );
8195
8196 WriteFieldCorElementType( m_NormType, (CorElementType)clazz->m_NormType,
8197 EEClass, EECLASSES );
8198
8199 PTR_FieldDesc fdList = clazz->GetFieldDescList();
8200
8201 ULONG fieldCount = (ULONG)CountFields(mt);
8202 _ASSERTE((fdList == NULL) == (fieldCount == 0));
8203
8204 IF_OPT(EECLASSES)
8205 {
8206 m_display->StartStructureWithOffset( "m_pFieldDescList",
8207 offsetof(EEClass, m_pFieldDescList),
8208 fieldsize(EEClass, m_pFieldDescList),
8209 DPtrToPreferredAddr(fdList),
8210 fdList != NULL ?
8211 sizeof(*fdList) * fieldCount :
8212 0 );
8213 }
8214 IF_OPT(VERBOSE_TYPES)
8215 {
8216 if( fdList != NULL )
8217 {
8218 DisplayStartArray( "FieldDescs", NULL, EECLASSES );
8219 for( SIZE_T i = 0; i < fieldCount; ++i )
8220 {
8221 PTR_FieldDesc fd = fdList + i;
8222 IF_OPT(EECLASSES)
8223 DumpFieldDesc( fd, "FieldDesc" );
8224 }
8225 DisplayEndArray( "Total FieldDescs", EECLASSES ); //FieldDescs
8226 }
8227 }
8228 else if( (fdList != NULL) && CHECK_OPT(DEBUG_COVERAGE) )
8229 {
8230 for( SIZE_T i = 0; i < fieldCount; ++i )
8231 {
8232 PTR_FieldDesc fd = fdList + i;
8233#ifdef _DEBUG
8234 if( fd != NULL && fd->m_debugName != NULL )
8235 CoverageReadString( fd->m_debugName );
8236#endif
8237 }
8238 CoverageRead( PTR_TO_TADDR(fdList), sizeof(*fdList) * fieldCount );
8239 }
8240
8241 DisplayEndStructure( EECLASSES ); //FieldDescList
8242
8243 DisplayWriteFieldEnumerated( m_dwAttrClass, clazz->GetAttrClass(),
8244 EEClass, s_CorTypeAttr, W(" "), EECLASSES );
8245 DisplayWriteFieldEnumerated( m_VMFlags, clazz->m_VMFlags, EEClass,
8246 s_VMFlags, W(", "), EECLASSES );
8247
8248 PTR_MethodDescChunk chunk = clazz->GetChunks();
8249
8250 DisplayStartArrayWithOffset( m_pChunks, NULL, EEClass, EECLASSES );
8251 while( chunk != NULL )
8252 {
8253 DisplayStartStructure( "MethodDescChunk",
8254 DPtrToPreferredAddr(chunk),
8255 chunk->SizeOf(), EECLASSES );
8256 _ASSERTE(!CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(chunk->GetMethodTable())));
8257 PTR_MethodTable chunkMT = chunk->GetMethodTable();
8258 DisplayWriteFieldPointer( m_methodTable,
8259 DPtrToPreferredAddr(chunkMT),
8260 MethodDescChunk, EECLASSES );
8261 PTR_MethodDescChunk chunkNext = chunk->GetNextChunk();
8262 DisplayWriteFieldPointer( m_next,
8263 DPtrToPreferredAddr(chunkNext),
8264 MethodDescChunk, EECLASSES );
8265 DisplayWriteFieldInt( m_size, chunk->m_size, MethodDescChunk,
8266 EECLASSES );
8267 DisplayWriteFieldInt( m_count, chunk->m_count, MethodDescChunk,
8268 EECLASSES );
8269 DisplayWriteFieldInt( m_flagsAndTokenRange, chunk->m_flagsAndTokenRange, MethodDescChunk,
8270 EECLASSES );
8271 /* XXX Wed 12/14/2005
8272 * Don't skip walking this array. I need to make sure I touch the
8273 * precodes.
8274 */
8275 DisplayStartArray( "MethodDescs", NULL, METHODDESCS );
8276 PTR_MethodDesc md(chunk->GetFirstMethodDesc());
8277 while (md != NULL)
8278 {
8279 IF_OPT_OR(METHODDESCS, DEBUG_COVERAGE)
8280 {
8281 PTR_Module module = mt->GetModule();
8282 if(CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(module) ))
8283 DumpMethodDesc( md, PTR_Module((TADDR)0) );
8284 else
8285 DumpMethodDesc( md, module );
8286 }
8287
8288 // Check whether the next MethodDesc is within the bounds of the current chunks
8289 TADDR pNext = PTR_HOST_TO_TADDR(md) + md->SizeOf();
8290 TADDR pEnd = PTR_HOST_TO_TADDR(chunk) + chunk->SizeOf();
8291
8292 md = (pNext < pEnd) ? PTR_MethodDesc(pNext) : NULL;
8293 }
8294
8295 DisplayEndArray( "Total MethodDescs", METHODDESCS); //MethodDescs
8296
8297 chunk = chunk->GetNextChunk();
8298
8299 DisplayEndStructure( EECLASSES ); //MethodDescChunk
8300 }
8301
8302 DisplayEndArray( "Total MethodDescChunks", EECLASSES );
8303 /* REVISIT_TODO Fri 10/14/2005
8304 * Dump the class dependencies
8305 */
8306 //_ASSERTE(!clazz->m_classDependencies.TestAnyBit());
8307
8308 /* REVISIT_TODO Mon 10/24/2005
8309 * Create vstructure for union?
8310 */
8311 //decode union here
8312#ifdef FEATURE_COMINTEROP
8313 if( clazz->IsBlittable() || clazz->HasLayout() )
8314 {
8315 DisplayWriteFieldInt(m_cbNativeSize, clazz->m_cbNativeSize, EEClass,
8316 EECLASSES );
8317 }
8318 else if( clazz->IsInterface() )
8319 {
8320 DisplayWriteFieldPointer( m_ohDelegate,
8321 DataPtrToDisplay(clazz->m_ohDelegate),
8322 EEClass, EECLASSES );
8323 }
8324 else
8325 {
8326 static const WCHAR * ifnames[] ={W("Dual"),W("Vtable"),W("Dispatch")};
8327 m_display->WriteFieldEnumerated( "ComInterfaceType",
8328 offsetof(EEClass,
8329 m_ComInterfaceType),
8330 fieldsize(EEClass,
8331 m_ComInterfaceType),
8332 (int)clazz->m_ComInterfaceType,
8333 ifnames[(int)clazz->m_ComInterfaceType] );
8334 }
8335#else
8336 DisplayWriteFieldInt( m_cbNativeSize, clazz->m_cbNativeSize,
8337 EEClass, EECLASSES );
8338#endif
8339
8340#if defined(FEATURE_COMINTEROP)
8341 PTR_ComCallWrapperTemplate ccwTemplate(TO_TADDR(clazz->m_pccwTemplate));
8342 if( ccwTemplate != NULL )
8343 {
8344 DisplayWriteFieldPointer( m_pccwTemplate, NULL, EEClass,
8345 EECLASSES );
8346 }
8347 else
8348 {
8349 /* REVISIT_TODO Fri 10/14/2005
8350 * Dump CcwTemplate
8351 */
8352 DisplayWriteFieldPointer( m_pccwTemplate,
8353 DPtrToPreferredAddr(ccwTemplate), EEClass,
8354 EECLASSES );
8355 }
8356#endif // defined(FEATURE_COMINTEROP)
8357
8358 //fields for classes that aren't just EEClasses.
8359 if( clazz->HasLayout() )
8360 {
8361 PTR_LayoutEEClass layoutClass(PTR_TO_TADDR(clazz));
8362 DisplayStartVStructure("LayoutEEClass", EECLASSES );
8363
8364 PTR_EEClassLayoutInfo eecli( PTR_HOST_MEMBER_TADDR( LayoutEEClass,
8365 layoutClass,
8366 m_LayoutInfo ) );
8367 DisplayStartStructureWithOffset( m_LayoutInfo,
8368 DPtrToPreferredAddr(eecli),
8369 sizeof(EEClassLayoutInfo),
8370 LayoutEEClass, EECLASSES );
8371 /* REVISIT_TODO Fri 10/14/2005
8372 * Dump EEClassLayoutInfo
8373 */
8374 DisplayWriteFieldInt( m_cbNativeSize, eecli->m_cbNativeSize,
8375 EEClassLayoutInfo, VERBOSE_TYPES );
8376 DisplayWriteFieldInt( m_cbManagedSize, eecli->m_cbManagedSize,
8377 EEClassLayoutInfo, VERBOSE_TYPES );
8378 DisplayWriteFieldInt( m_LargestAlignmentRequirementOfAllMembers,
8379 eecli->m_LargestAlignmentRequirementOfAllMembers,
8380 EEClassLayoutInfo, VERBOSE_TYPES );
8381 DisplayWriteFieldInt( m_ManagedLargestAlignmentRequirementOfAllMembers,
8382 eecli->m_ManagedLargestAlignmentRequirementOfAllMembers,
8383 EEClassLayoutInfo, VERBOSE_TYPES );
8384 DisplayWriteFieldEnumerated( m_bFlags, eecli->m_bFlags,
8385 EEClassLayoutInfo, s_EECLIFlags, W(", "),
8386 VERBOSE_TYPES );
8387 DisplayWriteFieldInt( m_numCTMFields, eecli->m_numCTMFields,
8388 EEClassLayoutInfo, VERBOSE_TYPES );
8389 PTR_FieldMarshaler fmArray = eecli->GetFieldMarshalers();
8390 DisplayWriteFieldAddress( m_pFieldMarshalers,
8391 DPtrToPreferredAddr(fmArray),
8392 eecli->m_numCTMFields
8393 * MAXFIELDMARSHALERSIZE,
8394 EEClassLayoutInfo, VERBOSE_TYPES );
8395 /* REVISIT_TODO Wed 03/22/2006
8396 * Dump the various types of FieldMarshalers.
8397 */
8398#if 0
8399 DisplayStartArrayWithOffset( m_pFieldMarshalers, NULL,
8400 EEClassLayoutInfo, VERBOSE_TYPES );
8401 for( unsigned i = 0; i < eecli->m_numCTMFields; ++i )
8402 {
8403 /* REVISIT_TODO Wed 03/22/2006
8404 * Try to display the type of the field marshaler in the future.
8405 */
8406 PTR_FieldMarshaler current = fmArray + i;
8407 DisplayStartStructure( "FieldMarshaler",
8408 DPtrToPreferredAddr(current),
8409 sizeof(*current), VERBOSE_TYPES );
8410 WriteFieldFieldDesc( m_pFD, PTR_FieldDesc(TO_TADDR(current->m_pFD)),
8411 FieldMarshaler, VERBOSE_TYPES );
8412 DisplayWriteFieldInt( m_dwExternalOffset,
8413 current->m_dwExternalOffset, FieldMarshaler,
8414 VERBOSE_TYPES );
8415 DisplayEndStructure( VERBOSE_TYPES ); //FieldMarshaler
8416 }
8417
8418 DisplayEndArray( "Number of FieldMarshalers", VERBOSE_TYPES ); //m_pFieldMarshalers
8419#endif
8420
8421 DisplayEndStructure( EECLASSES ); //LayoutInfo
8422
8423 DisplayEndVStructure( EECLASSES ); //LayoutEEClass
8424 }
8425 else if( mt->IsArray() )
8426 {
8427 PTR_ArrayClass arrayClass(PTR_TO_TADDR(clazz));
8428 DisplayStartVStructure( "ArrayClass", EECLASSES);
8429 IF_OPT(EECLASSES)
8430 {
8431 m_display->WriteFieldInt( "m_rank", offsetof(ArrayClass, m_rank),
8432 fieldsize(ArrayClass, m_rank),
8433 arrayClass->GetRank() );
8434 }
8435 DoWriteFieldCorElementType( "m_ElementType",
8436 offsetof(ArrayClass, m_ElementType),
8437 fieldsize(ArrayClass, m_ElementType),
8438 arrayClass->GetArrayElementType() );
8439
8440 DisplayEndVStructure( EECLASSES ); //ArrayClass
8441 }
8442 else if( clazz->IsDelegate() )
8443 {
8444 PTR_DelegateEEClass delegateClass(PTR_TO_TADDR(clazz));
8445 DisplayStartVStructure( "DelegateEEClass", EECLASSES );
8446
8447 DumpFieldStub( m_pStaticCallStub, delegateClass->m_pStaticCallStub,
8448 DelegateEEClass, EECLASSES );
8449 DumpFieldStub( m_pInstRetBuffCallStub,
8450 delegateClass->m_pInstRetBuffCallStub,
8451 DelegateEEClass, EECLASSES );
8452
8453 WriteFieldMethodDesc( m_pInvokeMethod,
8454 delegateClass->GetInvokeMethod(),
8455 DelegateEEClass, EECLASSES );
8456 DumpFieldStub( m_pMultiCastInvokeStub,
8457 delegateClass->m_pMultiCastInvokeStub,
8458 DelegateEEClass, EECLASSES );
8459
8460 DPTR(UMThunkMarshInfo)
8461 umInfo(TO_TADDR(delegateClass->m_pUMThunkMarshInfo));
8462
8463 if( umInfo == NULL )
8464 {
8465 DisplayWriteFieldPointer( m_pUMThunkMarshInfo, NULL,
8466 DelegateEEClass, EECLASSES );
8467 }
8468 else
8469 {
8470 DisplayStartStructureWithOffset( m_pUMThunkMarshInfo,
8471 DPtrToPreferredAddr(umInfo),
8472 sizeof(*umInfo),
8473 DelegateEEClass, EECLASSES );
8474 /* REVISIT_TODO Fri 10/14/2005
8475 * DumpUMThunkMarshInfo
8476 */
8477 DisplayEndStructure( EECLASSES ); //UMThunkMarshInfo
8478 }
8479
8480 WriteFieldMethodDesc( m_pBeginInvokeMethod,
8481 delegateClass->GetBeginInvokeMethod(),
8482 DelegateEEClass, EECLASSES );
8483 WriteFieldMethodDesc( m_pEndInvokeMethod,
8484 delegateClass->GetEndInvokeMethod(),
8485 DelegateEEClass, EECLASSES );
8486 DisplayWriteFieldPointer( m_pMarshalStub, delegateClass->m_pMarshalStub,
8487 DelegateEEClass, EECLASSES );
8488
8489 WriteFieldMethodDesc( m_pForwardStubMD,
8490 PTR_MethodDesc(TO_TADDR(delegateClass->m_pForwardStubMD)),
8491 DelegateEEClass, EECLASSES );
8492 WriteFieldMethodDesc( m_pReverseStubMD,
8493 PTR_MethodDesc(TO_TADDR(delegateClass->m_pReverseStubMD)),
8494 DelegateEEClass, EECLASSES );
8495
8496#ifdef FEATURE_COMINTEROP
8497 DPTR(ComPlusCallInfo) compluscall((TADDR)delegateClass->m_pComPlusCallInfo);
8498 if (compluscall == NULL)
8499 {
8500 DisplayWriteFieldPointer( m_pComPlusCallInfo,
8501 NULL,
8502 DelegateEEClass,
8503 EECLASSES );
8504 }
8505 else
8506 {
8507 DumpComPlusCallInfo( compluscall, EECLASSES );
8508 }
8509#endif // FEATURE_COMINTEROP
8510
8511 DisplayEndVStructure( EECLASSES ); //DelegateEEClass
8512 }
8513
8514 DisplayEndStructure( EECLASSES ); //eeClassType
8515
8516 PTR_EEClassOptionalFields pClassOptional = clazz->GetOptionalFields();
8517 if (pClassOptional)
8518 {
8519 DisplayStartStructure( "EEClassOptionalFields", DPtrToPreferredAddr(pClassOptional), sizeof(EEClassOptionalFields),
8520 EECLASSES );
8521
8522#ifdef FEATURE_COMINTEROP
8523 PTR_SparseVTableMap sparseVTMap(TO_TADDR(pClassOptional->m_pSparseVTableMap));
8524 if( sparseVTMap == NULL )
8525 {
8526 DisplayWriteFieldPointer( m_pSparseVTableMap, NULL, EEClassOptionalFields,
8527 EECLASSES );
8528 }
8529 else
8530 {
8531 _ASSERTE( !"Untested code" );
8532 IF_OPT(EECLASSES)
8533 {
8534 m_display->StartStructure( "m_SparseVTableMap",
8535 DPtrToPreferredAddr(sparseVTMap),
8536 sizeof(*sparseVTMap) );
8537 }
8538 _ASSERTE(sparseVTMap->m_MapList != NULL);
8539 PTR_SparseVTableMap_Entry mapList(TO_TADDR(sparseVTMap->m_MapList));
8540 DisplayStartArray( "m_MapList", NULL, EECLASSES );
8541 for( WORD i = 0; i < sparseVTMap->m_MapEntries; ++i )
8542 {
8543 DisplayWriteFieldInt( m_Start, mapList[i].m_Start,
8544 SparseVTableMap::Entry, EECLASSES );
8545 DisplayWriteFieldInt( m_Span, mapList[i].m_Span,
8546 SparseVTableMap::Entry, EECLASSES );
8547 DisplayWriteFieldInt( m_Span, mapList[i].m_MapTo,
8548 SparseVTableMap::Entry, EECLASSES );
8549 }
8550
8551 DisplayEndArray( "Total Entries", EECLASSES ); //m_MapList
8552
8553 DisplayWriteFieldInt( m_MapEntries, sparseVTMap->m_MapEntries,
8554 SparseVTableMap, EECLASSES );
8555 DisplayWriteFieldInt( m_Allocated, sparseVTMap->m_Allocated,
8556 SparseVTableMap, EECLASSES );
8557 DisplayWriteFieldInt( m_LastUsed, sparseVTMap->m_LastUsed,
8558 SparseVTableMap, EECLASSES );
8559 DisplayWriteFieldInt( m_VTSlot, sparseVTMap->m_VTSlot,
8560 SparseVTableMap, EECLASSES );
8561 DisplayWriteFieldInt( m_MTSlot, sparseVTMap->m_MTSlot,
8562 SparseVTableMap, EECLASSES );
8563
8564 DisplayEndStructure( EECLASSES ); //SparseVTableMap
8565 }
8566
8567 WriteFieldTypeHandle( m_pCoClassForIntf, pClassOptional->m_pCoClassForIntf,
8568 EEClassOptionalFields, EECLASSES );
8569
8570 PTR_ClassFactoryBase classFactory(TO_TADDR(pClassOptional->m_pClassFactory));
8571 if( classFactory != NULL )
8572 {
8573 DisplayWriteFieldPointer( m_pClassFactory, NULL, EEClassOptionalFields,
8574 EECLASSES );
8575 }
8576 else
8577 {
8578 /* REVISIT_TODO Fri 10/14/2005
8579 * Dump ComClassFactory
8580 */
8581 DisplayWriteFieldPointer( m_pClassFactory,
8582 DPtrToPreferredAddr(classFactory),
8583 EEClassOptionalFields, EECLASSES );
8584 }
8585#endif // FEATURE_COMINTEROP
8586
8587 PTR_DictionaryLayout layout = pClassOptional->m_pDictLayout;
8588 if( layout == NULL )
8589 {
8590 DisplayWriteFieldPointer( m_pDictLayout, NULL, EEClassOptionalFields, EECLASSES );
8591 }
8592 else
8593 {
8594 IF_OPT(VERBOSE_TYPES)
8595 {
8596 WriteFieldDictionaryLayout( "m_pDictLayout",
8597 offsetof(EEClassOptionalFields, m_pDictLayout),
8598 fieldsize(EEClassOptionalFields, m_pDictLayout),
8599 layout, GetDependencyFromMT(mt)->pImport );
8600 }
8601 else
8602 {
8603 while( layout != NULL )
8604 {
8605 CoverageRead( PTR_TO_TADDR(layout),
8606 sizeof(DictionaryLayout)
8607 + sizeof(DictionaryEntryLayout)
8608 * (layout->m_numSlots - 1) );
8609 layout = PTR_DictionaryLayout(TO_TADDR(layout->m_pNext));
8610 }
8611 }
8612 }
8613 PTR_BYTE varianceInfo = pClassOptional->GetVarianceInfo();
8614 if( varianceInfo == NULL )
8615 {
8616 DisplayWriteFieldPointer( m_pVarianceInfo, NULL,
8617 EEClassOptionalFields, EECLASSES );
8618 }
8619 else
8620 {
8621 /* REVISIT_TODO Fri 10/14/2005
8622 * Dump variance info
8623 */
8624 DisplayWriteFieldPointer( m_pVarianceInfo,
8625 DPtrToPreferredAddr(varianceInfo), EEClassOptionalFields,
8626 EECLASSES );
8627 }
8628
8629 DisplayWriteFieldInt( m_cbModuleDynamicID, pClassOptional->m_cbModuleDynamicID,
8630 EEClassOptionalFields, EECLASSES );
8631
8632 DisplayEndStructure( EECLASSES ); // EEClassOptionalFields
8633 }
8634} // NativeImageDumper::DumpEEClassForMethodTable
8635#ifdef _PREFAST_
8636#pragma warning(pop)
8637#endif
8638
8639enum TypeDescType
8640{
8641 TDT_IsTypeDesc,
8642 TDT_IsParamTypeDesc,
8643 TDT_IsArrayTypeDesc,
8644 TDT_IsTypeVarTypeDesc,
8645 TDT_IsFnPtrTypeDesc
8646};
8647const char * const g_typeDescTypeNames[] =
8648{
8649 "TypeDesc",
8650 "ParamTypeDesc",
8651 "ArrayTypeDesc",
8652 "TypeVarTypeDesc",
8653 "FnPtrTypeDesc"
8654};
8655int g_typeDescSizes[] =
8656{
8657 sizeof(TypeDesc),
8658 sizeof(ParamTypeDesc),
8659 sizeof(ArrayTypeDesc),
8660 sizeof(TypeVarTypeDesc),
8661 -1//sizeof(FnPtrTypeDesc) -- variable size
8662};
8663TypeDescType getTypeDescType( PTR_TypeDesc td )
8664{
8665 _ASSERTE(td != NULL);
8666 if( td->IsArray() )
8667 return TDT_IsArrayTypeDesc;
8668 if( td->HasTypeParam() )
8669 return TDT_IsParamTypeDesc;
8670 if( td->IsGenericVariable() )
8671 return TDT_IsTypeVarTypeDesc;
8672 if( td->GetInternalCorElementType() == ELEMENT_TYPE_FNPTR )
8673 return TDT_IsFnPtrTypeDesc;
8674 return TDT_IsTypeDesc;
8675}
8676NativeImageDumper::EnumMnemonics NativeImageDumper::s_TDFlags[] =
8677{
8678
8679#define TDF_ENTRY(x) NativeImageDumper::EnumMnemonics(TypeDesc:: x, W(#x) )
8680 TDF_ENTRY(enum_flag_NeedsRestore),
8681 TDF_ENTRY(enum_flag_PreRestored),
8682 TDF_ENTRY(enum_flag_Unrestored),
8683 TDF_ENTRY(enum_flag_UnrestoredTypeKey),
8684 TDF_ENTRY(enum_flag_IsNotFullyLoaded),
8685 TDF_ENTRY(enum_flag_DependenciesLoaded),
8686#undef TDF_ENTRY
8687};
8688
8689NativeImageDumper::EnumMnemonics s_CConv[] =
8690{
8691#define CC_ENTRY(x) NativeImageDumper::EnumMnemonics( x, W(#x) )
8692
8693#define CC_CALLCONV_ENTRY(x) NativeImageDumper::EnumMnemonics( x, IMAGE_CEE_CS_CALLCONV_MASK, W(#x) )
8694 CC_CALLCONV_ENTRY(IMAGE_CEE_CS_CALLCONV_VARARG),
8695 CC_CALLCONV_ENTRY(IMAGE_CEE_CS_CALLCONV_FIELD),
8696 CC_CALLCONV_ENTRY(IMAGE_CEE_CS_CALLCONV_LOCAL_SIG),
8697 CC_CALLCONV_ENTRY(IMAGE_CEE_CS_CALLCONV_PROPERTY),
8698 CC_CALLCONV_ENTRY(IMAGE_CEE_CS_CALLCONV_UNMGD),
8699 CC_CALLCONV_ENTRY(IMAGE_CEE_CS_CALLCONV_GENERICINST),
8700 CC_CALLCONV_ENTRY(IMAGE_CEE_CS_CALLCONV_NATIVEVARARG),
8701#undef CC_CALLCONV_ENTRY
8702
8703 CC_ENTRY(IMAGE_CEE_CS_CALLCONV_HASTHIS),
8704 CC_ENTRY(IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS),
8705 CC_ENTRY(IMAGE_CEE_CS_CALLCONV_GENERIC)
8706};
8707
8708
8709void NativeImageDumper::DumpTypeDesc( PTR_TypeDesc td )
8710{
8711 _ASSERTE(CHECK_OPT(TYPEDESCS));
8712 TypeDescType tdt = getTypeDescType(td);
8713 int size = g_typeDescSizes[(int)tdt];
8714 if( size == -1 )
8715 {
8716 _ASSERTE(tdt == TDT_IsFnPtrTypeDesc);
8717 size = FnPtrTypeDesc::DacSize(PTR_TO_TADDR(td));
8718 }
8719 DisplayStartStructure( g_typeDescTypeNames[(int)tdt],
8720 DPtrToPreferredAddr(td), size, TYPEDESCS );
8721
8722 //first handle the fields of typedesc
8723 WriteFieldCorElementType( m_typeAndFlags, td->GetInternalCorElementType(),
8724 TypeDesc, TYPEDESCS );
8725 DisplayWriteFieldEnumerated( m_typeAndFlags, td->m_typeAndFlags, TypeDesc,
8726 s_TDFlags, W(", "), TYPEDESCS );
8727 if( tdt == TDT_IsParamTypeDesc || tdt == TDT_IsArrayTypeDesc )
8728 {
8729 PTR_ParamTypeDesc ptd(td);
8730 DisplayStartVStructure( "ParamTypeDesc", TYPEDESCS );
8731 WriteFieldMethodTable( m_TemplateMT, ptd->GetTemplateMethodTableInternal(),
8732 ParamTypeDesc, TYPEDESCS );
8733 WriteFieldTypeHandle( m_Arg, ptd->m_Arg,
8734 ParamTypeDesc, TYPEDESCS );
8735 DisplayWriteFieldPointer( m_hExposedClassObject,
8736 DataPtrToDisplay(ptd->m_hExposedClassObject),
8737 ParamTypeDesc, TYPEDESCS );
8738
8739 DisplayEndVStructure( TYPEDESCS ); //ParamTypeDesc
8740 }
8741 else if( tdt == TDT_IsFnPtrTypeDesc )
8742 {
8743 PTR_FnPtrTypeDesc ftd(td);
8744 DisplayStartVStructure( "FnPtrTypeDesc", TYPEDESCS );
8745 DisplayWriteFieldInt( m_NumArgs, ftd->m_NumArgs, FnPtrTypeDesc,
8746 TYPEDESCS );
8747 DisplayWriteFieldEnumerated( m_CallConv, ftd->m_CallConv,
8748 FnPtrTypeDesc, s_CConv, W(", "),
8749 TYPEDESCS );
8750 DisplayStartArrayWithOffset( m_RetAndArgTypes, W("[%-4s]: %s"),
8751 FnPtrTypeDesc, TYPEDESCS );
8752 PTR_TypeHandle args( PTR_HOST_MEMBER_TADDR(FnPtrTypeDesc, ftd,
8753 m_RetAndArgTypes) );
8754 for( unsigned i = 0; i < ftd->m_NumArgs; ++i )
8755 {
8756 DisplayStartElement( "Argument", TYPEDESCS );
8757 DisplayWriteElementInt( "Index", i, TYPEDESCS );
8758 IF_OPT( TYPEDESCS )
8759 WriteElementTypeHandle( "TypeHandle", args[i] );
8760 DisplayEndElement( TYPEDESCS );
8761 }
8762 DisplayEndArray( "Total Arguments", TYPEDESCS );
8763 DisplayEndVStructure( TYPEDESCS );
8764 }
8765 else if( tdt == TDT_IsTypeVarTypeDesc )
8766 {
8767 PTR_TypeVarTypeDesc tvtd(td);
8768 DisplayStartVStructure( "TypeVarTypeDesc", TYPEDESCS );
8769 DisplayWriteFieldPointer( m_pModule,
8770 DPtrToPreferredAddr(tvtd->GetModule()),
8771 TypeVarTypeDesc, TYPEDESCS );
8772 DisplayWriteFieldUInt( m_typeOrMethodDef,
8773 tvtd->m_typeOrMethodDef,
8774 TypeVarTypeDesc, TYPEDESCS );
8775 DisplayWriteFieldInt( m_numConstraints, tvtd->m_numConstraints,
8776 TypeVarTypeDesc, TYPEDESCS );
8777 if( tvtd->m_constraints == NULL )
8778 {
8779 DisplayWriteFieldPointer( m_constraints, NULL, TypeVarTypeDesc,
8780 TYPEDESCS );
8781 }
8782 else
8783 {
8784 DisplayStartStructureWithOffset( m_constraints,
8785 DPtrToPreferredAddr(tvtd->m_constraints),
8786 sizeof(*tvtd->m_constraints) *
8787 tvtd->m_numConstraints,
8788 TypeVarTypeDesc, TYPEDESCS );
8789 DisplayStartArray( "Constraints", NULL, TYPEDESCS );
8790 for( unsigned i = 0; i < tvtd->m_numConstraints; ++i )
8791 {
8792 WriteElementTypeHandle( "TypeHandle", tvtd->m_constraints[i] );
8793 }
8794 DisplayEndArray( "Total Constraints", TYPEDESCS ); //Constraints
8795 DisplayEndStructure( TYPEDESCS ); //m_constraints
8796 }
8797 DisplayWriteFieldPointer( m_hExposedClassObject,
8798 DataPtrToDisplay(tvtd->m_hExposedClassObject),
8799 TypeVarTypeDesc, TYPEDESCS );
8800 DisplayWriteFieldUInt( m_token, tvtd->m_token, TypeVarTypeDesc,
8801 TYPEDESCS );
8802 DisplayWriteFieldInt( m_index, tvtd->m_index, TypeVarTypeDesc,
8803 TYPEDESCS );
8804
8805 DisplayEndVStructure( TYPEDESCS ); //TypeVarTypeDesc
8806 }
8807
8808
8809 DisplayEndStructure( TYPEDESCS ); // g_typeDescTypeNames
8810
8811}
8812
8813void NativeImageDumper::DumpDictionaryEntry( const char * elementName,
8814 DictionaryEntryKind kind,
8815 PTR_DictionaryEntry entry )
8816{
8817 m_display->StartElement( elementName );
8818 const char * name = NULL;
8819 switch(kind)
8820 {
8821 case EmptySlot:
8822 m_display->WriteEmptyElement("EmptySlot");
8823 break;
8824 case TypeHandleSlot:
8825 {
8826 TypeHandle th = dac_cast<DPTR(FixupPointer<TypeHandle>)>(entry)->GetValue();
8827 WriteElementTypeHandle( "TypeHandle", th );
8828 /* XXX Fri 03/24/2006
8829 * There is no straightforward home for these, so make sure to
8830 * record them
8831 */
8832 if( !CORCOMPILE_IS_POINTER_TAGGED(th.AsTAddr()) && th.IsTypeDesc() )
8833 {
8834 PTR_TypeDesc td(th.AsTypeDesc());
8835 if( isInRange(PTR_TO_TADDR(td)) )
8836 {
8837 m_discoveredTypeDescs.AppendEx(td);
8838 }
8839 }
8840 }
8841 break;
8842 case MethodDescSlot:
8843 {
8844 TempBuffer buf;
8845 PTR_MethodDesc md(TO_TADDR(*entry));
8846 WriteElementMethodDesc( "MethodDesc", md );
8847 }
8848 break;
8849 case MethodEntrySlot:
8850 name = "MethodEntry";
8851 goto StandardEntryDisplay;
8852 case ConstrainedMethodEntrySlot:
8853 name = "ConstrainedMethodEntry";
8854 goto StandardEntryDisplay;
8855 case DispatchStubAddrSlot:
8856 name = "DispatchStubAddr";
8857 goto StandardEntryDisplay;
8858 /* REVISIT_TODO Tue 10/11/2005
8859 * Print out name information here
8860 */
8861 case FieldDescSlot:
8862 name = "FieldDescSlot";
8863StandardEntryDisplay:
8864 m_display->WriteElementPointer(name, DataPtrToDisplay((TADDR)*entry));
8865 break;
8866 default:
8867 _ASSERTE( !"unreachable" );
8868 }
8869 m_display->EndElement(); //elementName
8870}
8871
8872#ifdef FEATURE_READYTORUN
8873IMAGE_DATA_DIRECTORY * NativeImageDumper::FindReadyToRunSection(DWORD type)
8874{
8875 PTR_READYTORUN_SECTION pSections = dac_cast<PTR_READYTORUN_SECTION>(dac_cast<TADDR>(m_pReadyToRunHeader) + sizeof(READYTORUN_HEADER));
8876 for (DWORD i = 0; i < m_pReadyToRunHeader->NumberOfSections; i++)
8877 {
8878 // Verify that section types are sorted
8879 _ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type));
8880
8881 READYTORUN_SECTION * pSection = pSections + i;
8882 if (pSection->Type == type)
8883 return &pSection->Section;
8884 }
8885 return NULL;
8886}
8887
8888//
8889// Ready to Run specific dumping methods
8890//
8891void NativeImageDumper::DumpReadyToRun()
8892{
8893 m_pReadyToRunHeader = m_decoder.GetReadyToRunHeader();
8894
8895 m_nativeReader = NativeFormat::NativeReader(dac_cast<PTR_BYTE>(m_decoder.GetBase()), m_decoder.GetVirtualSize());
8896
8897 IMAGE_DATA_DIRECTORY * pRuntimeFunctionsDir = FindReadyToRunSection(READYTORUN_SECTION_RUNTIME_FUNCTIONS);
8898 if (pRuntimeFunctionsDir != NULL)
8899 {
8900 m_pRuntimeFunctions = dac_cast<PTR_RUNTIME_FUNCTION>(m_decoder.GetDirectoryData(pRuntimeFunctionsDir));
8901 m_nRuntimeFunctions = pRuntimeFunctionsDir->Size / sizeof(T_RUNTIME_FUNCTION);
8902 }
8903 else
8904 {
8905 m_nRuntimeFunctions = 0;
8906 }
8907
8908 IMAGE_DATA_DIRECTORY * pEntryPointsDir = FindReadyToRunSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS);
8909 if (pEntryPointsDir != NULL)
8910 m_methodDefEntryPoints = NativeFormat::NativeArray((TADDR)&m_nativeReader, pEntryPointsDir->VirtualAddress);
8911
8912 DisplayStartCategory("NativeInfo", NATIVE_INFO);
8913
8914 IF_OPT(NATIVE_INFO)
8915 DumpReadyToRunHeader();
8916
8917 DisplayEndCategory(NATIVE_INFO); //NativeInfo
8918
8919 IF_OPT_OR3(METHODS, GC_INFO, DISASSEMBLE_CODE)
8920 DumpReadyToRunMethods();
8921
8922 IF_OPT(RELOCATIONS)
8923 DumpBaseRelocs();
8924}
8925
8926const NativeImageDumper::EnumMnemonics s_ReadyToRunFlags[] =
8927{
8928#define RTR_FLAGS(f) NativeImageDumper::EnumMnemonics(f, W(#f))
8929 RTR_FLAGS(READYTORUN_FLAG_PLATFORM_NEUTRAL_SOURCE),
8930#undef RTR_FLAGS
8931};
8932
8933void NativeImageDumper::DumpReadyToRunHeader()
8934{
8935 IF_OPT(NATIVE_INFO)
8936 {
8937 m_display->StartStructure( "READYTORUN_HEADER",
8938 DPtrToPreferredAddr(dac_cast<PTR_READYTORUN_HEADER>(m_pReadyToRunHeader)),
8939 sizeof(*m_pReadyToRunHeader) );
8940
8941 DisplayWriteFieldUInt( Signature, m_pReadyToRunHeader->Signature, READYTORUN_HEADER, ALWAYS );
8942 DisplayWriteFieldUInt( MajorVersion, m_pReadyToRunHeader->MajorVersion, READYTORUN_HEADER, ALWAYS );
8943 DisplayWriteFieldUInt( MinorVersion, m_pReadyToRunHeader->MinorVersion, READYTORUN_HEADER, ALWAYS );
8944
8945 DisplayWriteFieldEnumerated( Flags, m_pReadyToRunHeader->Flags,
8946 READYTORUN_HEADER, s_ReadyToRunFlags, W(", "),
8947 NATIVE_INFO );
8948
8949 m_display->EndStructure(); //READYTORUN_HEADER
8950 }
8951}
8952
8953void NativeImageDumper::DumpReadyToRunMethods()
8954{
8955 DisplayStartArray("Methods", NULL, METHODS);
8956
8957 for (uint rid = 1; rid <= m_methodDefEntryPoints.GetCount(); rid++)
8958 {
8959 uint offset;
8960 if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset))
8961 continue;
8962
8963 uint id;
8964 offset = m_nativeReader.DecodeUnsigned(offset, &id);
8965
8966 if (id & 1)
8967 {
8968 if (id & 2)
8969 {
8970 uint val;
8971 m_nativeReader.DecodeUnsigned(offset, &val);
8972 offset -= val;
8973 }
8974
8975 // TODO: Dump fixups from dac_cast<TADDR>(m_pLayout->GetBase()) + offset
8976
8977 id >>= 2;
8978 }
8979 else
8980 {
8981 id >>= 1;
8982 }
8983
8984 _ASSERTE(id < m_nRuntimeFunctions);
8985 PTR_RUNTIME_FUNCTION pRuntimeFunction = m_pRuntimeFunctions + id;
8986 PCODE pEntryPoint = dac_cast<TADDR>(m_decoder.GetBase()) + pRuntimeFunction->BeginAddress;
8987
8988 SString buf;
8989 AppendTokenName(TokenFromRid(rid, mdtMethodDef), buf, m_import);
8990
8991 DumpReadyToRunMethod(pEntryPoint, pRuntimeFunction, buf);
8992 }
8993
8994 DisplayEndArray("Total Methods", METHODS); //Methods
8995}
8996
8997extern PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFunction, /* out */ SIZE_T * pSize);
8998
8999void NativeImageDumper::DumpReadyToRunMethod(PCODE pEntryPoint, PTR_RUNTIME_FUNCTION pRuntimeFunction, SString& name)
9000{
9001 //Read the GCInfo to get the total method size.
9002 unsigned methodSize = 0;
9003 unsigned gcInfoSize = UINT_MAX;
9004
9005 SIZE_T nUnwindDataSize;
9006 PTR_VOID pUnwindData = GetUnwindDataBlob(dac_cast<TADDR>(m_decoder.GetBase()), pRuntimeFunction, &nUnwindDataSize);
9007
9008 // GCInfo immediatelly follows unwind data
9009 PTR_CBYTE gcInfo = dac_cast<PTR_CBYTE>(pUnwindData) + nUnwindDataSize;
9010
9011 void(*stringOutFn)(const char *, ...);
9012 IF_OPT(GC_INFO)
9013 {
9014 stringOutFn = stringOut;
9015 }
9016 else
9017 {
9018 stringOutFn = nullStringOut;
9019 }
9020 if (gcInfo != NULL)
9021 {
9022 PTR_CBYTE curGCInfoPtr = gcInfo;
9023 g_holdStringOutData.Clear();
9024 GCDump gcDump(GCINFO_VERSION);
9025 gcDump.gcPrintf = stringOutFn;
9026 UINT32 r2rversion = m_pReadyToRunHeader->MajorVersion;
9027 UINT32 gcInfoVersion = GCInfoToken::ReadyToRunVersionToGcInfoVersion(r2rversion);
9028 GCInfoToken gcInfoToken = { curGCInfoPtr, gcInfoVersion };
9029
9030#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
9031 GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_CODE_LENGTH);
9032 methodSize = gcInfoDecoder.GetCodeLength();
9033#endif
9034
9035 //dump the data to a string first so we can get the gcinfo size.
9036#ifdef _TARGET_X86_
9037 InfoHdr hdr;
9038 stringOutFn("method info Block:\n");
9039 curGCInfoPtr += gcDump.DumpInfoHdr(curGCInfoPtr, &hdr, &methodSize, 0);
9040 stringOutFn("\n");
9041#endif
9042
9043 IF_OPT(METHODS)
9044 {
9045#ifdef _TARGET_X86_
9046 stringOutFn("PointerTable:\n");
9047 curGCInfoPtr += gcDump.DumpGCTable(curGCInfoPtr,
9048 hdr,
9049 methodSize, 0);
9050 gcInfoSize = curGCInfoPtr - gcInfo;
9051#elif defined(USE_GC_INFO_DECODER)
9052 stringOutFn("PointerTable:\n");
9053 curGCInfoPtr += gcDump.DumpGCTable(curGCInfoPtr,
9054 methodSize, 0);
9055 gcInfoSize = (unsigned)(curGCInfoPtr - gcInfo);
9056#endif
9057 }
9058
9059 //data is output below.
9060 }
9061
9062 DisplayStartElement("Method", METHODS);
9063 DisplayWriteElementStringW("Name", (const WCHAR *)name, METHODS);
9064
9065 DisplayStartStructure("GCInfo",
9066 DPtrToPreferredAddr(gcInfo),
9067 gcInfoSize,
9068 METHODS);
9069
9070 DisplayStartTextElement("Contents", GC_INFO);
9071 DisplayWriteXmlTextBlock(("%S", (const WCHAR *)g_holdStringOutData), GC_INFO);
9072 DisplayEndTextElement(GC_INFO); //Contents
9073
9074 DisplayEndStructure(METHODS); //GCInfo
9075
9076 DisplayStartStructure("Code", DataPtrToDisplay(pEntryPoint), methodSize,
9077 METHODS);
9078
9079 IF_OPT(DISASSEMBLE_CODE)
9080 {
9081 // Disassemble hot code. Read the code into the host process.
9082 /* REVISIT_TODO Mon 10/24/2005
9083 * Is this align up right?
9084 */
9085 BYTE * codeStartHost =
9086 reinterpret_cast<BYTE*>(PTR_READ(pEntryPoint,
9087 (ULONG32)ALIGN_UP(methodSize,
9088 CODE_SIZE_ALIGN)));
9089 DisassembleMethod(codeStartHost, methodSize);
9090 }
9091
9092 DisplayEndStructure(METHODS); //Code
9093
9094 DisplayEndElement(METHODS); //Method
9095}
9096#endif // FEATURE_READYTORUN
9097
9098#if 0
9099void NativeImageDumper::RecordTypeRef( mdTypeRef token, PTR_MethodTable mt )
9100{
9101 if( mt != NULL )
9102 m_mtToTypeRefMap.Add( mt, token );
9103}
9104mdTypeRef NativeImageDumper::FindTypeRefForMT( PTR_MethodTable mt )
9105{
9106 return m_mtToTypeRefMap.Find(mt);
9107}
9108#endif
9109
9110
9111/* REVISIT_TODO Mon 10/10/2005
9112 * Here is where it gets bad. There is no DAC build of gcdump, so instead
9113 * build it directly into the the dac. That's what all these ugly defines
9114 * are all about.
9115 */
9116#ifdef __MSC_VER
9117#pragma warning(disable:4244) // conversion from 'unsigned int' to 'unsigned short', possible loss of data
9118#pragma warning(disable:4189) // local variable is initialized but not referenced
9119#endif // __MSC_VER
9120
9121#undef assert
9122#define assert(a)
9123#define NOTHROW
9124#define GC_NOTRIGGER
9125#include <gcdecoder.cpp>
9126#undef NOTHROW
9127#undef GC_NOTRIGGER
9128
9129#if defined _DEBUG && defined _TARGET_X86_
9130#ifdef _MSC_VER
9131// disable FPO for checked build
9132#pragma optimize("y", off)
9133#endif // _MSC_VER
9134#endif
9135
9136#undef _ASSERTE
9137#define _ASSERTE(a) do {} while (0)
9138#ifdef _TARGET_X86_
9139#include <gcdump.cpp>
9140#endif
9141
9142#undef LIMITED_METHOD_CONTRACT
9143#undef WRAPPER_NO_CONTRACT
9144#ifdef _TARGET_X86_
9145#include <i386/gcdumpx86.cpp>
9146#else // !_TARGET_X86_
9147#undef PREGDISPLAY
9148#include <gcdumpnonx86.cpp>
9149#endif // !_TARGET_X86_
9150
9151#ifdef __MSC_VER
9152#pragma warning(default:4244)
9153#pragma warning(default:4189)
9154#endif // __MSC_VER
9155
9156
9157#else //!FEATURE_PREJIT
9158//dummy implementation for dac
9159HRESULT ClrDataAccess::DumpNativeImage(CLRDATA_ADDRESS loadedBase,
9160 LPCWSTR name,
9161 IXCLRDataDisplay * display,
9162 IXCLRLibrarySupport * support,
9163 IXCLRDisassemblySupport * dis)
9164{
9165 return E_FAIL;
9166}
9167#endif //FEATURE_PREJIT
9168