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 | |
8 | // |
9 | // ==--== |
10 | #include "strike.h" |
11 | #include "util.h" |
12 | #include "genericstackprobe.h" |
13 | |
14 | /**********************************************************************\ |
15 | * Routine Description: * |
16 | * * |
17 | * This function is called to find the name of a TypeDef using * |
18 | * metadata API. * |
19 | * * |
20 | \**********************************************************************/ |
21 | // Caller should guard against exception |
22 | // !!! mdName should have at least mdNameLen WCHAR |
23 | static HRESULT NameForTypeDef_s(mdTypeDef tkTypeDef, IMetaDataImport *pImport, |
24 | __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName) |
25 | { |
26 | DWORD flags; |
27 | ULONG nameLen; |
28 | |
29 | HRESULT hr = pImport->GetTypeDefProps(tkTypeDef, mdName, |
30 | mdNameLen, &nameLen, |
31 | &flags, NULL); |
32 | if (hr != S_OK) { |
33 | return hr; |
34 | } |
35 | |
36 | if (!IsTdNested(flags)) { |
37 | return hr; |
38 | } |
39 | mdTypeDef tkEnclosingClass; |
40 | hr = pImport->GetNestedClassProps(tkTypeDef, &tkEnclosingClass); |
41 | if (hr != S_OK) { |
42 | return hr; |
43 | } |
44 | WCHAR *name = (WCHAR*)_alloca((nameLen+1)*sizeof(WCHAR)); |
45 | wcscpy_s (name, nameLen+1, mdName); |
46 | hr = NameForTypeDef_s(tkEnclosingClass,pImport,mdName, capacity_mdName); |
47 | if (hr != S_OK) { |
48 | return hr; |
49 | } |
50 | size_t Len = _wcslen (mdName); |
51 | if (Len < mdNameLen-2) { |
52 | mdName[Len++] = L'+'; |
53 | mdName[Len] = L'\0'; |
54 | } |
55 | Len = mdNameLen-1 - Len; |
56 | if (Len > nameLen) { |
57 | Len = nameLen; |
58 | } |
59 | wcsncat_s (mdName,capacity_mdName,name,Len); |
60 | return hr; |
61 | } |
62 | |
63 | /**********************************************************************\ |
64 | * Routine Description: * |
65 | * * |
66 | * This function is called to find the name of a TypeDef using * |
67 | * metadata API. * |
68 | * * |
69 | \**********************************************************************/ |
70 | // Caller should guard against exception |
71 | // !!! mdName should have at least mdNameLen WCHAR |
72 | /* |
73 | static HRESULT NameForTypeDefNew(mdTypeDef tkTypeDef, IMDInternalImport *pImport, |
74 | WCHAR *mdName) |
75 | { |
76 | DWORD flags; |
77 | ULONG nameLen; |
78 | char *name = (char *)_alloca((mdNameLen+1)*sizeof(char)); |
79 | char *namesp = (char *)_alloca((mdNameLen+1)*sizeof(char)); |
80 | |
81 | HRESULT hr = pImport->GetNameOfTypeDef(tkTypeDef, name, namesp); |
82 | if (FAILED(hr)) |
83 | { |
84 | return hr; |
85 | } |
86 | |
87 | strcpy (namesp, "."); |
88 | strcpy (namesp, name); |
89 | MultiByteToWideChar (CP_ACP,0,namesp,-1,mdName,mdNameLen); |
90 | return hr; |
91 | } |
92 | */ |
93 | |
94 | /**********************************************************************\ |
95 | * Routine Description: * |
96 | * * |
97 | * Find the Module MD Importer given the name of the Module. * |
98 | * * |
99 | \**********************************************************************/ |
100 | IMetaDataImport* MDImportForModule(DacpModuleData* pModule) |
101 | { |
102 | IMetaDataImport *pRet = NULL; |
103 | ToRelease<IXCLRDataModule> module; |
104 | HRESULT hr = g_sos->GetModule(pModule->Address, &module); |
105 | |
106 | if (SUCCEEDED(hr)) |
107 | hr = module->QueryInterface(IID_IMetaDataImport, (LPVOID *) &pRet); |
108 | |
109 | if (SUCCEEDED(hr)) |
110 | return pRet; |
111 | |
112 | return NULL; |
113 | } |
114 | |
115 | IMetaDataImport* MDImportForModule(DWORD_PTR pModule) |
116 | { |
117 | DacpModuleData moduleData; |
118 | if(moduleData.Request(g_sos, TO_CDADDR(pModule))==S_OK) |
119 | return MDImportForModule(&moduleData); |
120 | else |
121 | return NULL; |
122 | } |
123 | |
124 | /**********************************************************************\ |
125 | * Routine Description: * |
126 | * * |
127 | * Find the name for a metadata token given an importer. * |
128 | * * |
129 | \**********************************************************************/ |
130 | HRESULT NameForToken_s(mdTypeDef mb, IMetaDataImport *pImport, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName, |
131 | bool bClassName) |
132 | { |
133 | mdName[0] = L'\0'; |
134 | if ((mb & 0xff000000) != mdtTypeDef |
135 | && (mb & 0xff000000) != mdtFieldDef |
136 | && (mb & 0xff000000) != mdtMethodDef) |
137 | { |
138 | //ExtOut("unsupported\n"); |
139 | return E_FAIL; |
140 | } |
141 | |
142 | HRESULT hr = E_FAIL; |
143 | |
144 | PAL_CPP_TRY |
145 | { |
146 | static WCHAR name[MAX_CLASSNAME_LENGTH]; |
147 | if ((mb & 0xff000000) == mdtTypeDef) |
148 | { |
149 | hr = NameForTypeDef_s (mb, pImport, mdName, capacity_mdName); |
150 | } |
151 | else if ((mb & 0xff000000) == mdtFieldDef) |
152 | { |
153 | mdTypeDef mdClass; |
154 | ULONG size; |
155 | hr = pImport->GetMemberProps(mb, &mdClass, |
156 | name, sizeof(name)/sizeof(WCHAR)-1, &size, |
157 | NULL, NULL, NULL, NULL, |
158 | NULL, NULL, NULL, NULL); |
159 | if (SUCCEEDED (hr)) |
160 | { |
161 | if (mdClass != mdTypeDefNil && bClassName) |
162 | { |
163 | hr = NameForTypeDef_s (mdClass, pImport, mdName, capacity_mdName); |
164 | wcscat_s (mdName, capacity_mdName, W("." )); |
165 | } |
166 | name[size] = L'\0'; |
167 | wcscat_s (mdName, capacity_mdName, name); |
168 | } |
169 | } |
170 | else if ((mb & 0xff000000) == mdtMethodDef) |
171 | { |
172 | mdTypeDef mdClass; |
173 | ULONG size; |
174 | hr = pImport->GetMethodProps(mb, &mdClass, |
175 | name, sizeof(name)/sizeof(WCHAR)-1, &size, |
176 | NULL, NULL, NULL, NULL, NULL); |
177 | if (SUCCEEDED (hr)) |
178 | { |
179 | if (mdClass != mdTypeDefNil && bClassName) |
180 | { |
181 | hr = NameForTypeDef_s (mdClass, pImport, mdName, capacity_mdName); |
182 | wcscat_s (mdName, capacity_mdName, W("." )); |
183 | } |
184 | name[size] = L'\0'; |
185 | wcscat_s (mdName, capacity_mdName, name); |
186 | } |
187 | } |
188 | else |
189 | { |
190 | ExtOut ("Unsupported token type\n" ); |
191 | hr = E_FAIL; |
192 | } |
193 | } |
194 | PAL_CPP_CATCH_ALL |
195 | { |
196 | hr = E_FAIL; |
197 | } |
198 | PAL_CPP_ENDTRY |
199 | return hr; |
200 | } |
201 | |
202 | /**********************************************************************\ |
203 | * Routine Description: * |
204 | * * |
205 | * Find the name for a metadata token given an importer. * |
206 | * * |
207 | \**********************************************************************/ |
208 | /* |
209 | HRESULT NameForTokenNew(mdTypeDef mb, IMDInternalImport *pImport, WCHAR *mdName, size_t capacity_mdName, |
210 | bool bClassName) |
211 | { |
212 | |
213 | // TODO: Change calls to use the secure versions (string as well as to functions defined here) |
214 | // Simply uncommenting this function will not result in a clean compile |
215 | // --chirayuk @ 11/23/2004 |
216 | |
217 | mdName[0] = L'\0'; |
218 | if ((mb & 0xff000000) != mdtTypeDef |
219 | && (mb & 0xff000000) != mdtFieldDef |
220 | && (mb & 0xff000000) != mdtMethodDef) |
221 | { |
222 | //ExtOut("unsupported\n"); |
223 | return E_FAIL; |
224 | } |
225 | |
226 | HRESULT hr; |
227 | |
228 | __try |
229 | { |
230 | static WCHAR name[MAX_CLASSNAME_LENGTH]; |
231 | if (TypeFromToken(mb) == mdtTypeDef) |
232 | { |
233 | hr = NameForTypeDefNew (mb, pImport, mdName); |
234 | } |
235 | else if (TypeFromToken(mb) == mdtFieldDef) |
236 | { |
237 | mdTypeDef mdClass; |
238 | ULONG size; |
239 | MultiByteToWideChar (CP_ACP,0,pImport->GetNameOfFieldDef(mb),-1,name,MAX_CLASSNAME_LENGTH); |
240 | |
241 | hr = pImport->GetParentToken (mb, &mdClass); |
242 | if (SUCCEEDED (hr)) |
243 | { |
244 | if (mdClass != mdTypeDefNil && bClassName) |
245 | { |
246 | hr = NameForTypeDefNew (mdClass, pImport, mdName); |
247 | _wcscat (mdName, W(".")); |
248 | } |
249 | name[size] = L'\0'; |
250 | _wcscat (mdName, name); |
251 | } |
252 | } |
253 | else if (TypeFromToken(mb) == mdtMethodDef) |
254 | { |
255 | mdTypeDef mdClass; |
256 | ULONG size; |
257 | |
258 | MultiByteToWideChar (CP_ACP,0,pImport->GetNameOfMethodDef(mb),-1,name,MAX_CLASSNAME_LENGTH); |
259 | hr = pImport->GetParentToken (mb, &mdClass); |
260 | if (SUCCEEDED (hr)) |
261 | { |
262 | if (mdClass != mdTypeDefNil && bClassName) |
263 | { |
264 | hr = NameForTypeDefNew (mdClass, pImport, mdName); |
265 | _wcscat (mdName, W(".")); |
266 | } |
267 | name[size] = L'\0'; |
268 | _wcscat (mdName, name); |
269 | } |
270 | } |
271 | else |
272 | { |
273 | ExtOut ("Unsupported token type\n"); |
274 | hr = E_FAIL; |
275 | } |
276 | } |
277 | __except (EXCEPTION_EXECUTE_HANDLER) |
278 | { |
279 | //ExtOut("Metadata operation failure\n"); |
280 | hr = E_FAIL; |
281 | } |
282 | return hr; |
283 | } |
284 | */ |
285 | |
286 | /**********************************************************************\ |
287 | * Routine Description: * |
288 | * * |
289 | * This function is called to find the name of a metadata token * |
290 | * using metadata API. * |
291 | * * |
292 | \**********************************************************************/ |
293 | void NameForToken_s(DWORD_PTR ModuleAddr, mdTypeDef mb, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName, |
294 | bool bClassName) |
295 | { |
296 | DacpModuleData ModuleData; |
297 | mdName[0] = L'\0'; |
298 | if(ModuleData.Request(g_sos, TO_CDADDR(ModuleAddr))==S_OK) |
299 | NameForToken_s(&ModuleData,mb,mdName,capacity_mdName,bClassName); |
300 | } |
301 | |
302 | BOOL IsValidToken(DWORD_PTR ModuleAddr, mdTypeDef mb) |
303 | { |
304 | DacpModuleData ModuleData; |
305 | if(ModuleData.Request(g_sos, TO_CDADDR(ModuleAddr))==S_OK) |
306 | { |
307 | ToRelease<IMetaDataImport> pImport = MDImportForModule(&ModuleData); |
308 | if (pImport) |
309 | { |
310 | if (pImport->IsValidToken (mb)) |
311 | return TRUE; |
312 | } |
313 | } |
314 | return FALSE; |
315 | } |
316 | |
317 | void NameForToken_s(DacpModuleData *pModule, mdTypeDef mb, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName, |
318 | bool bClassName) |
319 | { |
320 | mdName[0] = L'\0'; |
321 | HRESULT hr = 0; |
322 | ToRelease<IMetaDataImport> pImport = MDImportForModule(pModule); |
323 | if (pImport) |
324 | { |
325 | hr = NameForToken_s (mb, pImport, mdName, capacity_mdName, bClassName); |
326 | } |
327 | |
328 | if (!pImport || !SUCCEEDED (hr)) |
329 | { |
330 | const SIZE_T capacity_moduleName = mdNameLen+19; |
331 | LPWSTR moduleName = (LPWSTR)alloca(capacity_moduleName * sizeof(WCHAR)); // for the "Dynamic Module In " below |
332 | FileNameForModule(pModule,moduleName); |
333 | if (moduleName[0] == L'\0') { |
334 | DacpAssemblyData assembly; |
335 | assembly.Request(g_sos,pModule->Assembly); |
336 | if (assembly.isDynamic) { |
337 | wcscpy_s(moduleName, capacity_moduleName, W("Dynamic " )); |
338 | } |
339 | wcscat_s (moduleName, capacity_moduleName, W("Module in " )); |
340 | if(g_sos->GetAssemblyName(pModule->Assembly, mdNameLen, g_mdName, NULL)==S_OK) |
341 | { |
342 | wcscat_s(moduleName, capacity_moduleName, g_mdName); |
343 | } |
344 | } |
345 | swprintf_s (mdName, capacity_mdName, |
346 | W(" mdToken: %08x (%ws)" ), |
347 | mb, |
348 | moduleName[0] ? moduleName : W("Unknown Module" ) ); |
349 | } |
350 | } |
351 | |
352 | #define STRING_BUFFER_LEN 1024 |
353 | |
354 | class MDInfo |
355 | { |
356 | public: |
357 | MDInfo (DWORD_PTR ModuleAddr) |
358 | { |
359 | m_pImport = MDImportForModule(ModuleAddr); |
360 | if (!m_pImport) |
361 | ExtOut("Unable to get IMetaDataImport for module %p\n" , ModuleAddr); |
362 | m_pSigBuf = NULL; |
363 | } |
364 | |
365 | MDInfo (IMetaDataImport * pImport) |
366 | { |
367 | m_pImport = pImport; |
368 | m_pImport->AddRef(); |
369 | m_pSigBuf = NULL; |
370 | } |
371 | |
372 | void GetMethodName(mdTypeDef token, CQuickBytes *fullName); |
373 | GetSignatureStringResults GetMethodSignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, CQuickBytes *fullName); |
374 | GetSignatureStringResults GetSignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, CQuickBytes *fullName); |
375 | |
376 | LPCWSTR TypeDefName(mdTypeDef inTypeDef); |
377 | LPCWSTR TypeRefName(mdTypeRef tr); |
378 | LPCWSTR TypeDeforRefName(mdToken inToken); |
379 | private: |
380 | // helper to init signature buffer |
381 | void InitSigBuffer() |
382 | { |
383 | ((LPWSTR)m_pSigBuf->Ptr())[0] = L'\0'; |
384 | } |
385 | |
386 | HRESULT AddToSigBuffer(LPCWSTR string); |
387 | |
388 | HRESULT GetFullNameForMD(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, LONG *plSigBlobRemaining OPTIONAL); |
389 | HRESULT GetOneElementType(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, ULONG *pcb); |
390 | |
391 | ToRelease<IMetaDataImport> m_pImport; |
392 | // Signature buffer. |
393 | CQuickBytes *m_pSigBuf; |
394 | |
395 | // temporary buffer for TypeDef or TypeRef name. Consume immediately |
396 | // because other functions may overwrite it. |
397 | static WCHAR m_szTempBuf[MAX_CLASSNAME_LENGTH]; |
398 | |
399 | static WCHAR m_szName[MAX_CLASSNAME_LENGTH]; |
400 | }; |
401 | |
402 | WCHAR MDInfo::m_szTempBuf[MAX_CLASSNAME_LENGTH]; |
403 | WCHAR MDInfo::m_szName[MAX_CLASSNAME_LENGTH]; |
404 | |
405 | GetSignatureStringResults GetMethodSignatureString (PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, DWORD_PTR dwModuleAddr, CQuickBytes *sigString) |
406 | { |
407 | MDInfo mdInfo(dwModuleAddr); |
408 | |
409 | return mdInfo.GetMethodSignature(pbSigBlob, ulSigBlob, sigString); |
410 | } |
411 | |
412 | |
413 | GetSignatureStringResults GetSignatureString (PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, DWORD_PTR dwModuleAddr, CQuickBytes *sigString) |
414 | { |
415 | MDInfo mdInfo(dwModuleAddr); |
416 | |
417 | return mdInfo.GetSignature(pbSigBlob, ulSigBlob, sigString); |
418 | } |
419 | |
420 | void GetMethodName(mdMethodDef methodDef, IMetaDataImport * pImport, CQuickBytes *fullName) |
421 | { |
422 | MDInfo mdInfo(pImport); |
423 | |
424 | mdInfo.GetMethodName(methodDef, fullName); |
425 | } |
426 | |
427 | |
428 | // Tables for mapping element type to text |
429 | const WCHAR *g_wszMapElementType[] = |
430 | { |
431 | W("End" ), // 0x0 |
432 | W("Void" ), // 0x1 |
433 | W("Boolean" ), |
434 | W("Char" ), |
435 | W("I1" ), |
436 | W("UI1" ), |
437 | W("I2" ), // 0x6 |
438 | W("UI2" ), |
439 | W("I4" ), |
440 | W("UI4" ), |
441 | W("I8" ), |
442 | W("UI8" ), |
443 | W("R4" ), |
444 | W("R8" ), |
445 | W("String" ), |
446 | W("Ptr" ), // 0xf |
447 | W("ByRef" ), // 0x10 |
448 | W("ValueClass" ), |
449 | W("Class" ), |
450 | W("CopyCtor" ), |
451 | W("MDArray" ), // 0x14 |
452 | W("GENArray" ), |
453 | W("TypedByRef" ), |
454 | W("VALUEARRAY" ), |
455 | W("I" ), |
456 | W("U" ), |
457 | W("R" ), // 0x1a |
458 | W("FNPTR" ), |
459 | W("Object" ), |
460 | W("SZArray" ), |
461 | W("GENERICArray" ), |
462 | W("CMOD_REQD" ), |
463 | W("CMOD_OPT" ), |
464 | W("INTERNAL" ), |
465 | }; |
466 | |
467 | const WCHAR *g_wszCalling[] = |
468 | { |
469 | W("[DEFAULT]" ), |
470 | W("[C]" ), |
471 | W("[STDCALL]" ), |
472 | W("[THISCALL]" ), |
473 | W("[FASTCALL]" ), |
474 | W("[VARARG]" ), |
475 | W("[FIELD]" ), |
476 | W("[LOCALSIG]" ), |
477 | W("[PROPERTY]" ), |
478 | W("[UNMANAGED]" ), |
479 | }; |
480 | |
481 | void MDInfo::GetMethodName(mdTypeDef token, CQuickBytes *fullName) |
482 | { |
483 | if (m_pImport == NULL) { |
484 | return; |
485 | } |
486 | |
487 | HRESULT hr; |
488 | mdTypeDef memTypeDef; |
489 | ULONG nameLen; |
490 | DWORD flags; |
491 | PCCOR_SIGNATURE pbSigBlob; |
492 | ULONG ulSigBlob; |
493 | ULONG ulCodeRVA; |
494 | ULONG ulImplFlags; |
495 | |
496 | m_pSigBuf = fullName; |
497 | InitSigBuffer(); |
498 | |
499 | WCHAR szFunctionName[1024]; |
500 | |
501 | hr = m_pImport->GetMethodProps(token, &memTypeDef, |
502 | szFunctionName, _countof(szFunctionName), &nameLen, |
503 | &flags, &pbSigBlob, &ulSigBlob, &ulCodeRVA, &ulImplFlags); |
504 | if (FAILED (hr)) |
505 | { |
506 | return; |
507 | } |
508 | |
509 | szFunctionName[nameLen] = L'\0'; |
510 | m_szName[0] = L'\0'; |
511 | if (memTypeDef != mdTypeDefNil) |
512 | { |
513 | hr = NameForTypeDef_s (memTypeDef, m_pImport, m_szName, _countof(m_szName)); |
514 | if (SUCCEEDED (hr)) { |
515 | wcscat_s (m_szName, _countof(m_szName), W("." )); |
516 | } |
517 | } |
518 | wcscat_s (m_szName, _countof(m_szName), szFunctionName); |
519 | |
520 | LONG lSigBlobRemaining; |
521 | hr = GetFullNameForMD(pbSigBlob, ulSigBlob, &lSigBlobRemaining); |
522 | |
523 | // We should have consumed all signature blob. If not, dump the sig in hex. |
524 | // Also dump in hex if so requested. |
525 | if (lSigBlobRemaining != 0) |
526 | { |
527 | // Did we not consume enough, or try to consume too much? |
528 | if (lSigBlobRemaining < 0) |
529 | ExtOut("ERROR IN SIGNATURE: Signature should be larger.\n" ); |
530 | else |
531 | ExtOut("ERROR IN SIGNATURE: Not all of signature blob was consumed. %d byte(s) remain\n" , lSigBlobRemaining); |
532 | } |
533 | |
534 | if (FAILED(hr)) |
535 | ExtOut("ERROR!! Bad signature blob value!" ); |
536 | } |
537 | |
538 | |
539 | GetSignatureStringResults MDInfo::GetMethodSignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, CQuickBytes *fullName) |
540 | { |
541 | if (!m_pImport) |
542 | return GSS_ERROR; |
543 | |
544 | m_pSigBuf = fullName; |
545 | InitSigBuffer(); |
546 | |
547 | m_szName[0] = '\0'; |
548 | |
549 | LONG lSigBlobRemaining; |
550 | if (FAILED(GetFullNameForMD(pbSigBlob, ulSigBlob, &lSigBlobRemaining))) |
551 | return GSS_ERROR; |
552 | |
553 | if (lSigBlobRemaining < 0) |
554 | return GSS_INSUFFICIENT_DATA; |
555 | |
556 | return GSS_SUCCESS; |
557 | } |
558 | |
559 | |
560 | GetSignatureStringResults MDInfo::GetSignature(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, CQuickBytes *fullName) |
561 | { |
562 | if (!m_pImport) |
563 | return GSS_ERROR; |
564 | |
565 | m_pSigBuf = fullName; |
566 | InitSigBuffer(); |
567 | |
568 | m_szName[0] = '\0'; |
569 | |
570 | ULONG cb; |
571 | if (FAILED(GetOneElementType(pbSigBlob, ulSigBlob, &cb))) |
572 | { |
573 | if (cb > ulSigBlob) |
574 | return GSS_INSUFFICIENT_DATA; |
575 | else |
576 | return GSS_ERROR; |
577 | } |
578 | |
579 | return GSS_SUCCESS; |
580 | } |
581 | |
582 | |
583 | inline bool isCallConv(unsigned sigByte, CorCallingConvention conv) |
584 | { |
585 | return ((sigByte & IMAGE_CEE_CS_CALLCONV_MASK) == (unsigned) conv); |
586 | } |
587 | |
588 | #ifndef IfFailGoto |
589 | #define IfFailGoto(EXPR, LABEL) \ |
590 | do { hr = (EXPR); if(FAILED(hr)) { goto LABEL; } } while (0) |
591 | #endif |
592 | |
593 | #ifndef IfFailGo |
594 | #define IfFailGo(EXPR) IfFailGoto(EXPR, ErrExit) |
595 | #endif |
596 | |
597 | #ifndef IfFailRet |
598 | #define IfFailRet(EXPR) do { hr = (EXPR); if(FAILED(hr)) { return (hr); } } while (0) |
599 | #endif |
600 | |
601 | #ifndef _ASSERTE |
602 | #define _ASSERTE(expr) |
603 | #endif |
604 | |
605 | HRESULT MDInfo::GetFullNameForMD(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, LONG *plSigBlobRemaining) |
606 | { |
607 | ULONG cbCur = 0; |
608 | ULONG cb; |
609 | ULONG ulData = NULL; |
610 | ULONG ulArgs; |
611 | HRESULT hr = NOERROR; |
612 | |
613 | cb = CorSigUncompressData(pbSigBlob, &ulData); |
614 | |
615 | // 0 is a valid calling convention byte (IMAGE_CEE_CS_CALLCONV_DEFAULT w/ no flags) |
616 | //if (ulData == NULL) |
617 | // goto ErrExit; |
618 | |
619 | AddToSigBuffer (g_wszCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK]); |
620 | if (cb>ulSigBlob) |
621 | goto ErrExit; |
622 | cbCur += cb; |
623 | ulSigBlob -= cb; |
624 | |
625 | if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS) |
626 | AddToSigBuffer ( W(" [hasThis]" )); |
627 | if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS) |
628 | AddToSigBuffer ( W(" [explicit]" )); |
629 | |
630 | AddToSigBuffer (W(" " )); |
631 | if ( isCallConv(ulData,IMAGE_CEE_CS_CALLCONV_FIELD) ) |
632 | { |
633 | // display field type |
634 | if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb))) |
635 | goto ErrExit; |
636 | AddToSigBuffer ( W(" " )); |
637 | AddToSigBuffer ( m_szName); |
638 | if (cb>ulSigBlob) |
639 | goto ErrExit; |
640 | cbCur += cb; |
641 | ulSigBlob -= cb; |
642 | } |
643 | else |
644 | { |
645 | cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulArgs); |
646 | if (cb>ulSigBlob) |
647 | goto ErrExit; |
648 | cbCur += cb; |
649 | ulSigBlob -= cb; |
650 | |
651 | if (ulData != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) |
652 | { |
653 | // display return type when it is not a local varsig |
654 | if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb))) |
655 | goto ErrExit; |
656 | AddToSigBuffer (W(" " )); |
657 | AddToSigBuffer (m_szName); |
658 | AddToSigBuffer ( W("(" )); |
659 | if (cb>ulSigBlob) |
660 | goto ErrExit; |
661 | cbCur += cb; |
662 | ulSigBlob -= cb; |
663 | } |
664 | |
665 | ULONG i = 0; |
666 | while (i < ulArgs && ulSigBlob > 0) |
667 | { |
668 | ULONG ulDataUncompress; |
669 | |
670 | // Handle the sentinal for varargs because it isn't counted in the args. |
671 | CorSigUncompressData(&pbSigBlob[cbCur], &ulDataUncompress); |
672 | ++i; |
673 | |
674 | if (FAILED(hr = GetOneElementType(&pbSigBlob[cbCur], ulSigBlob, &cb))) |
675 | goto ErrExit; |
676 | if (i != ulArgs) { |
677 | AddToSigBuffer ( W("," )); |
678 | } |
679 | if (cb>ulSigBlob) |
680 | goto ErrExit; |
681 | |
682 | cbCur += cb; |
683 | ulSigBlob -= cb; |
684 | } |
685 | AddToSigBuffer ( W(")" )); |
686 | } |
687 | |
688 | // Nothing consumed but not yet counted. |
689 | cb = 0; |
690 | |
691 | ErrExit: |
692 | |
693 | if (plSigBlobRemaining) |
694 | *plSigBlobRemaining = (ulSigBlob - cb); |
695 | |
696 | return hr; |
697 | } |
698 | |
699 | LPCWSTR MDInfo::TypeDefName(mdTypeDef inTypeDef) |
700 | { |
701 | if (m_pImport == NULL) { |
702 | return W("" ); |
703 | } |
704 | |
705 | HRESULT hr; |
706 | |
707 | hr = m_pImport->GetTypeDefProps( |
708 | // [IN] The import scope. |
709 | inTypeDef, // [IN] TypeDef token for inquiry. |
710 | m_szTempBuf, // [OUT] Put name here. |
711 | MAX_CLASSNAME_LENGTH , // [IN] size of name buffer in wide chars. |
712 | NULL, // [OUT] put size of name (wide chars) here. |
713 | NULL, // [OUT] Put flags here. |
714 | NULL); // [OUT] Put base class TypeDef/TypeRef here. |
715 | |
716 | if (FAILED(hr)) return (W("NoName" )); |
717 | return (m_szTempBuf); |
718 | } // LPCWSTR MDInfo::TypeDefName() |
719 | LPCWSTR MDInfo::TypeRefName(mdTypeRef tr) |
720 | { |
721 | if (m_pImport == NULL) { |
722 | return W("" ); |
723 | } |
724 | |
725 | HRESULT hr; |
726 | |
727 | hr = m_pImport->GetTypeRefProps( |
728 | tr, // The class ref token. |
729 | NULL, // Resolution scope. |
730 | m_szTempBuf, // Put the name here. |
731 | MAX_CLASSNAME_LENGTH, // Size of the name buffer, wide chars. |
732 | NULL); // Put actual size of name here. |
733 | if (FAILED(hr)) return (W("NoName" )); |
734 | |
735 | return (m_szTempBuf); |
736 | } // LPCWSTR MDInfo::TypeRefName() |
737 | |
738 | LPCWSTR MDInfo::TypeDeforRefName(mdToken inToken) |
739 | { |
740 | if (RidFromToken(inToken)) |
741 | { |
742 | if (TypeFromToken(inToken) == mdtTypeDef) |
743 | return (TypeDefName((mdTypeDef) inToken)); |
744 | else if (TypeFromToken(inToken) == mdtTypeRef) |
745 | return (TypeRefName((mdTypeRef) inToken)); |
746 | else |
747 | return (W("[InvalidReference]" )); |
748 | } |
749 | else |
750 | return (W("" )); |
751 | } // LPCWSTR MDInfo::TypeDeforRefName() |
752 | |
753 | |
754 | HRESULT MDInfo::AddToSigBuffer(LPCWSTR string) |
755 | { |
756 | HRESULT hr; |
757 | IfFailRet(m_pSigBuf->ReSize((_wcslen((LPWSTR)m_pSigBuf->Ptr()) + _wcslen(string) + 1) * sizeof(WCHAR))); |
758 | wcscat_s((LPWSTR)m_pSigBuf->Ptr(), m_pSigBuf->Size()/sizeof(WCHAR),string); |
759 | return NOERROR; |
760 | } |
761 | |
762 | HRESULT MDInfo::GetOneElementType(PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, ULONG *pcb) |
763 | { |
764 | HRESULT hr = S_OK; // A result. |
765 | ULONG cbCur = 0; |
766 | ULONG cb; |
767 | ULONG ulData; |
768 | ULONG ulTemp; |
769 | int iTemp = 0; |
770 | mdToken tk; |
771 | const size_t capacity_buffer = 9; |
772 | |
773 | cb = CorSigUncompressData(pbSigBlob, &ulData); |
774 | |
775 | if (cb == ULONG(-1)) { |
776 | hr = E_FAIL; |
777 | goto ErrExit; |
778 | } |
779 | |
780 | cbCur += cb; |
781 | |
782 | // Handle the modifiers. |
783 | if (ulData & ELEMENT_TYPE_MODIFIER) |
784 | { |
785 | if (ulData == ELEMENT_TYPE_SENTINEL) |
786 | IfFailGo(AddToSigBuffer(W("<ELEMENT_TYPE_SENTINEL> " ))); |
787 | else if (ulData == ELEMENT_TYPE_PINNED) |
788 | IfFailGo(AddToSigBuffer(W("PINNED " ))); |
789 | else |
790 | { |
791 | hr = E_FAIL; |
792 | goto ErrExit; |
793 | } |
794 | if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) |
795 | goto ErrExit; |
796 | cbCur += cb; |
797 | goto ErrExit; |
798 | } |
799 | |
800 | // Handle the underlying element types. |
801 | if (ulData >= ELEMENT_TYPE_MAX) |
802 | { |
803 | hr = E_FAIL; |
804 | goto ErrExit; |
805 | } |
806 | while (ulData == ELEMENT_TYPE_PTR || ulData == ELEMENT_TYPE_BYREF) |
807 | { |
808 | IfFailGo(AddToSigBuffer(g_wszMapElementType[ulData])); |
809 | IfFailGo(AddToSigBuffer(W(" " ))); |
810 | cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); |
811 | cbCur += cb; |
812 | } |
813 | |
814 | // Generics |
815 | if (ulData == ELEMENT_TYPE_VAR) |
816 | { |
817 | IfFailGo(AddToSigBuffer(W("__Canon" ))); |
818 | |
819 | // The next byte represents which generic parameter is referred to. We |
820 | // do not currently use this information, so just bypass this byte. |
821 | cbCur++; |
822 | |
823 | goto ErrExit; |
824 | } |
825 | |
826 | // A generic instance, e.g. IEnumerable<String> |
827 | if (ulData == ELEMENT_TYPE_GENERICINST) |
828 | { |
829 | // Print out the base type. |
830 | IfFailGo(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)); |
831 | cbCur += cb; |
832 | |
833 | // Get the number of generic arguments. |
834 | ULONG numParams = 0; |
835 | IfFailGo(CorSigUncompressData(&pbSigBlob[cbCur], 1, &numParams, &cb)); |
836 | cbCur += cb; |
837 | |
838 | // Print out the list of arguments |
839 | IfFailGo(AddToSigBuffer(W("<" ))); |
840 | for (ULONG i = 0; i < numParams; i++) |
841 | { |
842 | if (i > 0) |
843 | IfFailGo(AddToSigBuffer(W("," ))); |
844 | |
845 | IfFailGo(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb)); |
846 | cbCur += cb; |
847 | } |
848 | IfFailGo(AddToSigBuffer(W(">" ))); |
849 | goto ErrExit; |
850 | } |
851 | |
852 | // Past this point we must have something which directly maps to a value in g_wszMapElementType. |
853 | IfFailGo(AddToSigBuffer(g_wszMapElementType[ulData])); |
854 | if (CorIsPrimitiveType((CorElementType)ulData) || |
855 | ulData == ELEMENT_TYPE_TYPEDBYREF || |
856 | ulData == ELEMENT_TYPE_OBJECT || |
857 | ulData == ELEMENT_TYPE_I || |
858 | ulData == ELEMENT_TYPE_U) |
859 | { |
860 | // If this is a primitive type, we are done |
861 | goto ErrExit; |
862 | } |
863 | |
864 | AddToSigBuffer(W(" " )); |
865 | if (ulData == ELEMENT_TYPE_VALUETYPE || |
866 | ulData == ELEMENT_TYPE_CLASS || |
867 | ulData == ELEMENT_TYPE_CMOD_REQD || |
868 | ulData == ELEMENT_TYPE_CMOD_OPT) |
869 | { |
870 | cb = CorSigUncompressToken(&pbSigBlob[cbCur], &tk); |
871 | cbCur += cb; |
872 | |
873 | // get the name of type ref. Don't care if truncated |
874 | if (TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtTypeRef) |
875 | { |
876 | IfFailGo(AddToSigBuffer(TypeDeforRefName(tk))); |
877 | } |
878 | else |
879 | { |
880 | _ASSERTE(TypeFromToken(tk) == mdtTypeSpec); |
881 | WCHAR buffer[capacity_buffer]; |
882 | _itow_s (tk, buffer, capacity_buffer, 16); |
883 | IfFailGo(AddToSigBuffer(buffer)); |
884 | } |
885 | if (ulData == ELEMENT_TYPE_CMOD_REQD || |
886 | ulData == ELEMENT_TYPE_CMOD_OPT) |
887 | { |
888 | IfFailGo(AddToSigBuffer(W(" " ))); |
889 | if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) |
890 | goto ErrExit; |
891 | cbCur += cb; |
892 | } |
893 | |
894 | goto ErrExit; |
895 | } |
896 | if (ulData == ELEMENT_TYPE_SZARRAY) |
897 | { |
898 | // display the base type of SZARRAY or GENERICARRAY |
899 | if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) |
900 | goto ErrExit; |
901 | cbCur += cb; |
902 | goto ErrExit; |
903 | } |
904 | if (ulData == ELEMENT_TYPE_FNPTR) |
905 | { |
906 | cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); |
907 | cbCur += cb; |
908 | if (ulData & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS) |
909 | IfFailGo(AddToSigBuffer(W("[explicit] " ))); |
910 | if (ulData & IMAGE_CEE_CS_CALLCONV_HASTHIS) |
911 | IfFailGo(AddToSigBuffer(W("[hasThis] " ))); |
912 | |
913 | IfFailGo(AddToSigBuffer(g_wszCalling[ulData & IMAGE_CEE_CS_CALLCONV_MASK])); |
914 | |
915 | // Get number of args |
916 | ULONG numArgs; |
917 | cb = CorSigUncompressData(&pbSigBlob[cbCur], &numArgs); |
918 | cbCur += cb; |
919 | |
920 | // do return type |
921 | if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) |
922 | goto ErrExit; |
923 | cbCur += cb; |
924 | |
925 | IfFailGo(AddToSigBuffer(W("(" ))); |
926 | while (numArgs > 0) |
927 | { |
928 | if (cbCur > ulSigBlob) |
929 | goto ErrExit; |
930 | if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) |
931 | goto ErrExit; |
932 | cbCur += cb; |
933 | --numArgs; |
934 | if (numArgs > 0) |
935 | IfFailGo(AddToSigBuffer(W("," ))); |
936 | } |
937 | IfFailGo(AddToSigBuffer(W(")" ))); |
938 | goto ErrExit; |
939 | } |
940 | |
941 | if (ulData == ELEMENT_TYPE_INTERNAL) |
942 | { |
943 | IfFailGo(AddToSigBuffer(W("MT " ))); |
944 | |
945 | void *pvMethodTable; |
946 | cb = CorSigUncompressPointer(&pbSigBlob[cbCur], (void**)&pvMethodTable); |
947 | cbCur += cb; |
948 | |
949 | const size_t capacity_szMethodTableValue = 10; |
950 | WCHAR szMethodTableValue[10]; |
951 | itow_s_ptr((INT_PTR)pvMethodTable, szMethodTableValue, capacity_szMethodTableValue, 16); |
952 | |
953 | IfFailGo(AddToSigBuffer(szMethodTableValue)); |
954 | IfFailGo(AddToSigBuffer(W(" " ))); |
955 | |
956 | IfFailGo(g_sos->GetMethodTableName(TO_CDADDR(pvMethodTable), mdNameLen, g_mdName, NULL)); |
957 | IfFailGo(AddToSigBuffer(g_mdName)); |
958 | |
959 | goto ErrExit; |
960 | } |
961 | |
962 | |
963 | if(ulData != ELEMENT_TYPE_ARRAY) return E_FAIL; |
964 | |
965 | // display the base type of SDARRAY |
966 | if (FAILED(GetOneElementType(&pbSigBlob[cbCur], ulSigBlob-cbCur, &cb))) |
967 | goto ErrExit; |
968 | cbCur += cb; |
969 | |
970 | IfFailGo(AddToSigBuffer(W(" " ))); |
971 | // display the rank of MDARRAY |
972 | cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); |
973 | cbCur += cb; |
974 | WCHAR buffer[capacity_buffer]; |
975 | _itow_s (ulData, buffer, capacity_buffer, 10); |
976 | IfFailGo(AddToSigBuffer(buffer)); |
977 | if (ulData == 0) |
978 | // we are done if no rank specified |
979 | goto ErrExit; |
980 | |
981 | IfFailGo(AddToSigBuffer(W(" " ))); |
982 | // how many dimensions have size specified? |
983 | cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); |
984 | cbCur += cb; |
985 | _itow_s (ulData, buffer, capacity_buffer, 10); |
986 | IfFailGo(AddToSigBuffer(buffer)); |
987 | if (ulData == 0) { |
988 | IfFailGo(AddToSigBuffer(W(" " ))); |
989 | } |
990 | while (ulData) |
991 | { |
992 | |
993 | cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulTemp); |
994 | _itow_s (ulTemp, buffer, capacity_buffer, 10); |
995 | IfFailGo(AddToSigBuffer(buffer)); |
996 | IfFailGo(AddToSigBuffer(W(" " ))); |
997 | cbCur += cb; |
998 | ulData--; |
999 | } |
1000 | // how many dimensions have lower bounds specified? |
1001 | cb = CorSigUncompressData(&pbSigBlob[cbCur], &ulData); |
1002 | cbCur += cb; |
1003 | _itow_s (ulData, buffer, capacity_buffer, 10); |
1004 | IfFailGo(AddToSigBuffer(buffer)); |
1005 | while (ulData) |
1006 | { |
1007 | |
1008 | cb = CorSigUncompressSignedInt(&pbSigBlob[cbCur], &iTemp); |
1009 | _itow_s (iTemp, buffer, capacity_buffer, 10); |
1010 | IfFailGo(AddToSigBuffer(buffer)); |
1011 | IfFailGo(AddToSigBuffer(W(" " ))); |
1012 | cbCur += cb; |
1013 | ulData--; |
1014 | } |
1015 | |
1016 | ErrExit: |
1017 | if (cbCur > ulSigBlob) |
1018 | hr = E_FAIL; |
1019 | *pcb = cbCur; |
1020 | return hr; |
1021 | } |
1022 | |
1023 | //***************************************************************************** |
1024 | // Used when the method is tiny (< 64 bytes), and there are no local vars |
1025 | //***************************************************************************** |
1026 | typedef struct tagCOR_ILMETHOD_TINY : IMAGE_COR_ILMETHOD_TINY |
1027 | { |
1028 | bool IsTiny() const { return((Flags_CodeSize & (CorILMethod_FormatMask >> 1)) == CorILMethod_TinyFormat); } |
1029 | DWORD GetLocalVarSigTok() const { return(0); } |
1030 | } COR_ILMETHOD_TINY; |
1031 | |
1032 | |
1033 | //***************************************************************************** |
1034 | // This strucuture is the 'fat' layout, where no compression is attempted. |
1035 | // Note that this structure can be added on at the end, thus making it extensible |
1036 | //***************************************************************************** |
1037 | typedef struct tagCOR_ILMETHOD_FAT : IMAGE_COR_ILMETHOD_FAT |
1038 | { |
1039 | bool IsFat() const { return((Flags & CorILMethod_FormatMask) == CorILMethod_FatFormat); } |
1040 | mdToken GetLocalVarSigTok() const { return(LocalVarSigTok); } |
1041 | } COR_ILMETHOD_FAT; |
1042 | |