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 | */ |
64 | inline 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 | } |
87 | FORCEINLINE 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 |
98 | inline 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 |
110 | FORCEINLINE CorElementType DacSigUncompressElementType(//Element type |
111 | PTR_CCOR_SIGNATURE &pData) // [IN,OUT] compressed data |
112 | { |
113 | return (CorElementType)*pData++; |
114 | } |
115 | |
116 | |
117 | |
118 | const 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 | |
129 | void 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 | |
156 | const 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 | }; |
167 | inline int CheckFlags( DWORD source, DWORD flags ) |
168 | { |
169 | return (source & flags) == flags; |
170 | } |
171 | |
172 | HRESULT 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 | |
191 | static ULONG bigBufferSize = 8192; |
192 | static WCHAR bigBuffer[8192]; |
193 | static BYTE bigByteBuffer[1024]; |
194 | |
195 | //---------------------------------------------------------------------------- |
196 | // |
197 | // NativeImageDumper |
198 | // |
199 | //---------------------------------------------------------------------------- |
200 | template<typename T> |
201 | inline T combine(T a, T b) |
202 | { |
203 | return (T)(((DWORD)a) | ((DWORD)b)); |
204 | } |
205 | template<typename T> |
206 | inline 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 | |
360 | void 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 | } |
400 | void 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 | |
412 | struct 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 | |
424 | static 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. |
450 | STDAPI 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 | |
461 | NativeImageDumper::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 | |
512 | void 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 | |
523 | NativeImageDumper::~NativeImageDumper() |
524 | { |
525 | } |
526 | |
527 | inline 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. |
533 | template<typename T> |
534 | inline 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 | |
539 | template<typename T> |
540 | inline const DPTR(T) dptr_sub(T* ptr, COUNT_T offset) |
541 | { |
542 | return DPTR(T)(PTR_HOST_TO_TADDR(ptr) - (offset * sizeof(T))); |
543 | } |
544 | template<typename T> |
545 | inline 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 | |
550 | struct 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 | |
557 | static 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 | |
593 | const 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 | |
606 | void 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? |
624 | void |
625 | NativeImageDumper::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 = |
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 (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 = 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 (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 = 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 | |
1211 | void 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 | |
1262 | void 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 | |
1279 | void 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 ( 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 | } |
1377 | void 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 | } |
1425 | void |
1426 | NativeImageDumper::AppendTokenName(mdToken token, SString& buf) |
1427 | { |
1428 | AppendTokenName(token, buf, NULL); |
1429 | } |
1430 | void |
1431 | NativeImageDumper::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 | } |
1553 | void NativeImageDumper::PrintManifestTokenName(mdToken token, SString& str) |
1554 | { |
1555 | PrintManifestTokenName(token, str, NULL); |
1556 | } |
1557 | void |
1558 | NativeImageDumper::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 | |
1627 | BOOL 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 | |
1649 | void 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 | |
1720 | void 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 | |
1833 | void 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 | |
1861 | void 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 | |
1889 | const 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 | |
1902 | void 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; |
2116 | DataToTokenCore: |
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 | |
2223 | void 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 | |
2244 | NativeImageDumper::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 | |
2277 | mdAssemblyRef 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, ¤tRef, 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 | |
2428 | NativeImageDumper::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 | |
2458 | const 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 | |
2473 | void NativeImageDumper::AppendToken(mdToken token, SString& buf) |
2474 | { |
2475 | return NativeImageDumper::AppendToken(token, buf, NULL); |
2476 | } |
2477 | void 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 | |
2534 | NativeImageDumper::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 | |
2714 | IMetaDataImport2* NativeImageDumper::TypeToString(PTR_CCOR_SIGNATURE &sig, SString& buf) |
2715 | { |
2716 | return TypeToString(sig, buf, NULL); |
2717 | } |
2718 | #if 0 |
2719 | void 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 | |
2733 | IMetaDataImport2 * 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 | |
2922 | void 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 | |
3001 | static SString g_holdStringOutData; |
3002 | |
3003 | static 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 | |
3011 | static void nullStringOut( const char * fmt, ... ) { } |
3012 | |
3013 | const 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 | |
3024 | void 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 | |
3238 | void 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 | |
3285 | NEXT_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 | |
3316 | SIZE_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 | } |
3337 | SIZE_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 | |
3381 | size_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 | |
3585 | BOOL 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 | |
3598 | void 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 | |
3614 | IMAGE_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 | |
3631 | NativeImageDumper::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) |
3658 | static 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 | }; |
3669 | const 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 | |
3685 | void 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 | |
4036 | bool NativeImageDumper::isPrecode(TADDR maybePrecode) |
4037 | { |
4038 | PTR_Module module = (TADDR)m_decoder.GetPersistedModuleImage(); |
4039 | |
4040 | return !!module->IsZappedPrecode(maybePrecode); |
4041 | } |
4042 | |
4043 | |
4044 | void 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 | |
4086 | void 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 | |
4144 | void 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 | |
4175 | void 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 | |
4209 | void 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 | |
4250 | void 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 |
4281 | void 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 | |
4313 | void 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 | |
4345 | void 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). |
4410 | template<typename HASH_CLASS, typename HASH_ENTRY_CLASS> |
4411 | void 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). |
4465 | template<typename HASH_CLASS, typename HASH_ENTRY_CLASS> |
4466 | void 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 | |
4532 | void 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 | |
4592 | void 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 | |
4609 | void 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 | |
4627 | void 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 | |
4644 | void 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 | |
4661 | void 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 | |
4677 | void 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 | |
4743 | void 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 | |
4757 | void 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 | |
4798 | void 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 | |
4848 | void 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 | |
4863 | void 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 | |
4878 | const NativeImageDumper::Dependency * |
4879 | NativeImageDumper::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 |
4890 | const NativeImageDumper::Import * |
4891 | NativeImageDumper::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 |
4909 | const NativeImageDumper::Dependency * |
4910 | NativeImageDumper::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 | |
4927 | void 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 | |
4959 | void 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 | |
5058 | mdToken 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 | |
5126 | SIZE_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 | |
5155 | const 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 | |
5169 | const 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 | |
5178 | const 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 | }; |
5189 | const 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 | |
5199 | const 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 | |
5220 | const 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 | |
5233 | const 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 | |
5242 | void NativeImageDumper::() |
5243 | { |
5244 | PTR_CORCOMPILE_HEADER (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 | |
5361 | const 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 | |
5371 | void 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 | |
5413 | void 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 | |
5453 | NativeImageDumper::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 | |
5486 | NativeImageDumper::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 | |
5542 | NativeImageDumper::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 | |
5567 | NativeImageDumper::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 | |
5589 | static 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 | |
5632 | void 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 | |
5645 | static 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 | }; |
5684 | static 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 | }; |
5727 | static 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 | |
5757 | NativeImageDumper::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 | |
5767 | NativeImageDumper::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 | |
5801 | void 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 | |
5918 | PTR_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 | } |
5927 | PTR_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. |
5939 | SIZE_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 | } |
5976 | const NativeImageDumper::Dependency* |
5977 | NativeImageDumper::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 | } |
5997 | const NativeImageDumper::Dependency* |
5998 | NativeImageDumper::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 | } |
6013 | const NativeImageDumper::Dependency* |
6014 | NativeImageDumper::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 | |
6031 | BOOL 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 | |
6047 | void 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 | } |
6077 | void 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 | } |
6165 | void 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 | |
6184 | void 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 | } |
6215 | void NativeImageDumper::WriteElementTypeHandle( const char * name, |
6216 | TypeHandle th ) |
6217 | { |
6218 | DoWriteFieldTypeHandle( name, UINT_MAX, UINT_MAX, th ); |
6219 | } |
6220 | |
6221 | void 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 |
6242 | void 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 | |
6285 | void 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 | } |
6331 | void 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 | } |
6391 | void 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 | } |
6410 | void 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 | |
6433 | void 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 | |
6473 | void 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 | } |
6599 | void 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 | } |
6614 | void NativeImageDumper::FieldDescToString( PTR_FieldDesc fd, SString& buf ) |
6615 | { |
6616 | FieldDescToString( fd, mdFieldDefNil, buf ); |
6617 | } |
6618 | void 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 | |
6656 | void 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 | } |
6676 | void NativeImageDumper::WriteElementMDToken( const char * name, mdToken token ) |
6677 | { |
6678 | DoWriteFieldMDToken( name, UINT_MAX, UINT_MAX, token ); |
6679 | } |
6680 | void 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 | |
6702 | void NativeImageDumper::WriteElementMethodTable( const char * name, |
6703 | PTR_MethodTable mt ) |
6704 | { |
6705 | DoWriteFieldMethodTable( name, UINT_MAX, UINT_MAX, mt ); |
6706 | } |
6707 | void 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 | |
6743 | const 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 | }; |
6752 | void 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 |
6805 | void |
6806 | NativeImageDumper::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 | |
7290 | void |
7291 | NativeImageDumper::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 | |
7332 | void |
7333 | NativeImageDumper::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 | |
7364 | NativeImageDumper::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 |
7405 | const 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 | |
7421 | unsigned 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 | |
7437 | static 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 | }; |
7455 | NativeImageDumper::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 | |
7480 | void 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 |
7579 | void 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 * = (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 | |
8116 | NativeImageDumper::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 |
8131 | void |
8132 | NativeImageDumper::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 | |
8639 | enum TypeDescType |
8640 | { |
8641 | TDT_IsTypeDesc, |
8642 | TDT_IsParamTypeDesc, |
8643 | TDT_IsArrayTypeDesc, |
8644 | TDT_IsTypeVarTypeDesc, |
8645 | TDT_IsFnPtrTypeDesc |
8646 | }; |
8647 | const char * const g_typeDescTypeNames[] = |
8648 | { |
8649 | "TypeDesc" , |
8650 | "ParamTypeDesc" , |
8651 | "ArrayTypeDesc" , |
8652 | "TypeVarTypeDesc" , |
8653 | "FnPtrTypeDesc" |
8654 | }; |
8655 | int g_typeDescSizes[] = |
8656 | { |
8657 | sizeof(TypeDesc), |
8658 | sizeof(ParamTypeDesc), |
8659 | sizeof(ArrayTypeDesc), |
8660 | sizeof(TypeVarTypeDesc), |
8661 | -1//sizeof(FnPtrTypeDesc) -- variable size |
8662 | }; |
8663 | TypeDescType 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 | } |
8676 | NativeImageDumper::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 | |
8689 | NativeImageDumper::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 | |
8709 | void 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 | |
8813 | void 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" ; |
8863 | StandardEntryDisplay: |
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 |
8873 | IMAGE_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 | // |
8891 | void 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 | |
8926 | const 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 | |
8933 | void NativeImageDumper::() |
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 | |
8953 | void 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 | |
8997 | extern PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFunction, /* out */ SIZE_T * pSize); |
8998 | |
8999 | void 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 |
9099 | void NativeImageDumper::RecordTypeRef( mdTypeRef token, PTR_MethodTable mt ) |
9100 | { |
9101 | if( mt != NULL ) |
9102 | m_mtToTypeRefMap.Add( mt, token ); |
9103 | } |
9104 | mdTypeRef 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 |
9159 | HRESULT 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 | |