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//
11// disasm.cpp : Defines the entry point for the console application.
12//
13#ifndef FEATURE_PAL
14#include <tchar.h>
15#endif
16#include "strike.h"
17#include "util.h"
18#include "strsafe.h"
19//#ifndef FEATURE_PAL
20//#include "gcinfo.h"
21//#endif
22#include "disasm.h"
23#include <dbghelp.h>
24
25#include "corhdr.h"
26
27#include "cor.h"
28#include "dacprivate.h"
29
30#include "openum.h"
31
32#include "sos_md.h"
33
34#define SOS_INCLUDE 1
35#include "corhlpr.h"
36#include "corhlpr.cpp"
37
38//////////////////////////////////////////////////////////////////////////////////////////////////////////
39#undef printf
40#define printf ExtOut
41
42// typedef unsigned char BYTE;
43struct OpCode
44{
45 int code;
46 const char *name;
47 int args;
48 BYTE b1;
49 BYTE b2;
50
51 unsigned int getCode() {
52 if (b1==0xFF) return b2;
53 else return (0xFE00 | b2);
54 }
55};
56
57#define OPCODES_LENGTH 0x122
58
59#undef OPDEF
60#define OPDEF(c,s,pop,push,args,type,l,s1,s2,ctrl) {c, s, args, s1, s2},
61static OpCode opcodes[] =
62{
63#include "opcode.def"
64};
65
66static ULONG position = 0;
67static BYTE *pBuffer = NULL;
68
69// The UNALIGNED is because on IA64 alignment rules would prevent
70// us from reading a pointer from an unaligned source.
71template <typename T>
72T readData ( ) {
73 T val = *((T UNALIGNED*)(pBuffer+position));
74 position += sizeof(T);
75 return val;
76}
77
78unsigned int readOpcode()
79{
80 unsigned int c = readData<BYTE>();
81 if (c == 0xFE)
82 {
83 c = readData<BYTE>();
84 c |= 0x100;
85 }
86 return c;
87}
88
89void DisassembleToken(IMetaDataImport *i,
90 DWORD token)
91{
92 HRESULT hr;
93
94 switch (TypeFromToken(token))
95 {
96 default:
97 printf("<unknown token type %08x>", TypeFromToken(token));
98 break;
99
100 case mdtTypeDef:
101 {
102 ULONG cLen;
103 WCHAR szName[50];
104
105 hr = i->GetTypeDefProps(token, szName, 49, &cLen, NULL, NULL);
106
107 if (FAILED(hr))
108 StringCchCopyW(szName, COUNTOF(szName), W("<unknown type def>"));
109
110 printf("%S", szName);
111 }
112 break;
113
114 case mdtTypeRef:
115 {
116 ULONG cLen;
117 WCHAR szName[50];
118
119 hr = i->GetTypeRefProps(token, NULL, szName, 49, &cLen);
120
121 if (FAILED(hr))
122 StringCchCopyW(szName, COUNTOF(szName), W("<unknown type ref>"));
123
124 printf("%S", szName);
125 }
126 break;
127
128 case mdtFieldDef:
129 {
130 ULONG cLen;
131 WCHAR szFieldName[50];
132 WCHAR szClassName[50];
133 mdTypeDef mdClass;
134
135 hr = i->GetFieldProps(token, &mdClass, szFieldName, 49, &cLen,
136 NULL, NULL, NULL, NULL, NULL, NULL);
137
138 if (FAILED(hr))
139 StringCchCopyW(szFieldName, COUNTOF(szFieldName), W("<unknown field def>"));
140
141 hr = i->GetTypeDefProps(mdClass, szClassName, 49, &cLen,
142 NULL, NULL);
143
144 if (FAILED(hr))
145 StringCchCopyW(szClassName, COUNTOF(szClassName), W("<unknown type def>"));
146
147 printf("%S::%S", szClassName, szFieldName);
148 }
149 break;
150
151 case mdtMethodDef:
152 {
153 ULONG cLen;
154 WCHAR szFieldName[50];
155 WCHAR szClassName[50];
156 mdTypeDef mdClass;
157
158 hr = i->GetMethodProps(token, &mdClass, szFieldName, 49, &cLen,
159 NULL, NULL, NULL, NULL, NULL);
160
161 if (FAILED(hr))
162 StringCchCopyW(szFieldName, COUNTOF(szFieldName), W("<unknown method def>"));
163
164 hr = i->GetTypeDefProps(mdClass, szClassName, 49, &cLen,
165 NULL, NULL);
166
167 if (FAILED(hr))
168 StringCchCopyW(szClassName, COUNTOF(szClassName), W("<unknown type def>"));
169
170 printf("%S::%S", szClassName, szFieldName);
171 }
172 break;
173
174 case mdtMemberRef:
175 {
176 mdTypeRef cr = mdTypeRefNil;
177 LPCWSTR pMemberName;
178 WCHAR memberName[50];
179 ULONG memberNameLen;
180
181 hr = i->GetMemberRefProps(token, &cr, memberName, 49,
182 &memberNameLen, NULL, NULL);
183
184 if (FAILED(hr))
185 {
186 pMemberName = W("<unknown member ref>");
187 }
188 else
189 pMemberName = memberName;
190
191 ULONG cLen;
192 WCHAR szName[50];
193
194 if(TypeFromToken(cr) == mdtTypeRef)
195 {
196 if (FAILED(i->GetTypeRefProps(cr, NULL, szName, 50, &cLen)))
197 {
198 StringCchCopyW(szName, COUNTOF(szName), W("<unknown type ref>"));
199 }
200 }
201 else if(TypeFromToken(cr) == mdtTypeDef)
202 {
203 if (FAILED(i->GetTypeDefProps(cr, szName, 49, &cLen,
204 NULL, NULL)))
205 {
206 StringCchCopyW(szName, COUNTOF(szName), W("<unknown type def>"));
207 }
208 }
209 else if(TypeFromToken(cr) == mdtTypeSpec)
210 {
211 IMDInternalImport *pIMDI = NULL;
212 if (SUCCEEDED(GetMDInternalFromImport(i, &pIMDI)))
213 {
214 CQuickBytes out;
215 ULONG cSig;
216 PCCOR_SIGNATURE sig;
217 if (FAILED(pIMDI->GetSigFromToken(cr, &cSig, &sig)))
218 {
219 StringCchCopyW(szName, COUNTOF(szName), W("<Invalid record>"));
220 }
221 else
222 {
223 PrettyPrintType(sig, &out, pIMDI);
224 MultiByteToWideChar (CP_ACP, 0, asString(&out), -1, szName, 50);
225 }
226
227 pIMDI->Release();
228 }
229 else
230 {
231 StringCchCopyW(szName, COUNTOF(szName), W("<unknown type spec>"));
232 }
233 }
234 else
235 {
236 StringCchCopyW(szName, COUNTOF(szName), W("<unknown type token>"));
237 }
238
239 printf("%S::%S ", szName, pMemberName);
240 }
241 break;
242 }
243}
244
245ULONG GetILSize(DWORD_PTR ilAddr)
246{
247 ULONG uRet = 0;
248
249 // workaround: read enough bytes at ilAddr to presumably get the entire header.
250 // Could be error prone.
251
252 static BYTE headerArray[1024];
253 HRESULT Status = g_ExtData->ReadVirtual(TO_CDADDR(ilAddr), headerArray, sizeof(headerArray), NULL);
254 if (SUCCEEDED(Status))
255 {
256 COR_ILMETHOD_DECODER header((COR_ILMETHOD *)headerArray);
257 // uRet = header.GetHeaderSize();
258 uRet = header.GetOnDiskSize((COR_ILMETHOD *)headerArray);
259 }
260
261 return uRet;
262}
263
264HRESULT DecodeILFromAddress(IMetaDataImport *pImport, TADDR ilAddr)
265{
266 HRESULT Status = S_OK;
267
268 ULONG Size = GetILSize(ilAddr);
269 if (Size == 0)
270 {
271 ExtOut("error decoding IL\n");
272 return Status;
273 }
274
275 ExtOut("ilAddr = %p\n", SOS_PTR(ilAddr));
276
277 // Read the memory into a local buffer
278 ArrayHolder<BYTE> pArray = new BYTE[Size];
279 Status = g_ExtData->ReadVirtual(TO_CDADDR(ilAddr), pArray, Size, NULL);
280 if (Status != S_OK)
281 {
282 ExtOut("Failed to read memory\n");
283 return Status;
284 }
285
286 DecodeIL(pImport, pArray, Size);
287
288 return Status;
289}
290
291void DecodeIL(IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize)
292{
293 // First decode the header
294 COR_ILMETHOD *pHeader = (COR_ILMETHOD *) buffer;
295 COR_ILMETHOD_DECODER header(pHeader);
296
297 // Set globals
298 position = 0;
299 pBuffer = (BYTE *) header.Code;
300
301 UINT indentCount = 0;
302 ULONG endCodePosition = header.GetCodeSize();
303 while(position < endCodePosition)
304 {
305 for (unsigned e=0;e<header.EHCount();e++)
306 {
307 IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehBuff;
308 const IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
309
310 ehInfo = header.EH->EHClause(e,&ehBuff);
311 if (ehInfo->TryOffset == position)
312 {
313 printf ("%*s.try\n%*s{\n", indentCount, "", indentCount, "");
314 indentCount+=2;
315 }
316 else if ((ehInfo->TryOffset + ehInfo->TryLength) == position)
317 {
318 indentCount-=2;
319 printf("%*s} // end .try\n", indentCount, "");
320 }
321
322 if (ehInfo->HandlerOffset == position)
323 {
324 if (ehInfo->Flags == COR_ILEXCEPTION_CLAUSE_FINALLY)
325 printf("%*s.finally\n%*s{\n", indentCount, "", indentCount, "");
326 else
327 printf("%*s.catch\n%*s{\n", indentCount, "", indentCount, "");
328
329 indentCount+=2;
330 }
331 else if ((ehInfo->HandlerOffset + ehInfo->HandlerLength) == position)
332 {
333 indentCount-=2;
334
335 if (ehInfo->Flags == COR_ILEXCEPTION_CLAUSE_FINALLY)
336 printf("%*s} // end .finally\n", indentCount, "");
337 else
338 printf("%*s} // end .catch\n", indentCount, "");
339 }
340 }
341
342 printf("%*sIL_%04x: ", indentCount, "", position);
343 unsigned int c = readOpcode();
344 OpCode opcode = opcodes[c];
345 printf("%s ", opcode.name);
346
347 switch(opcode.args)
348 {
349 case InlineNone: break;
350
351 case ShortInlineVar:
352 printf("VAR OR ARG %d",readData<BYTE>()); break;
353 case InlineVar:
354 printf("VAR OR ARG %d",readData<WORD>()); break;
355 case InlineI:
356 printf("%d",readData<LONG>());
357 break;
358 case InlineR:
359 printf("%f",readData<double>());
360 break;
361 case InlineBrTarget:
362 printf("IL_%04x",readData<LONG>() + position); break;
363 case ShortInlineBrTarget:
364 printf("IL_%04x",readData<BYTE>() + position); break;
365 case InlineI8:
366 printf("%ld", readData<__int64>()); break;
367
368 case InlineMethod:
369 case InlineField:
370 case InlineType:
371 case InlineTok:
372 case InlineSig:
373 {
374 LONG l = readData<LONG>();
375 if (pImport != NULL)
376 {
377 DisassembleToken(pImport, l);
378 }
379 else
380 {
381 printf("TOKEN %x", l);
382 }
383 break;
384 }
385
386 case InlineString:
387 {
388 LONG l = readData<LONG>();
389
390 ULONG numChars;
391 WCHAR str[84];
392
393 if ((pImport != NULL) && (pImport->GetUserString((mdString) l, str, 80, &numChars) == S_OK))
394 {
395 if (numChars < 80)
396 str[numChars] = 0;
397 wcscpy_s(&str[79], 4, W("..."));
398 WCHAR* ptr = str;
399 while(*ptr != 0) {
400 if (*ptr < 0x20 || * ptr >= 0x80) {
401 *ptr = '.';
402 }
403 ptr++;
404 }
405
406 printf("\"%S\"", str);
407 }
408 else
409 {
410 printf("STRING %x", l);
411 }
412 break;
413 }
414
415 case InlineSwitch:
416 {
417 LONG cases = readData<LONG>();
418 LONG *pArray = new LONG[cases];
419 LONG i=0;
420 for(i=0;i<cases;i++)
421 {
422 pArray[i] = readData<LONG>();
423 }
424 printf("(");
425 for(i=0;i<cases;i++)
426 {
427 if (i != 0)
428 printf(", ");
429 printf("IL_%04x",pArray[i] + position);
430 }
431 printf(")");
432 delete [] pArray;
433 break;
434 }
435 case ShortInlineI:
436 printf("%d", readData<BYTE>()); break;
437 case ShortInlineR:
438 printf("%f", readData<float>()); break;
439 default: printf("Error, unexpected opcode type\n"); break;
440 }
441
442 printf("\n");
443 }
444}
445
446DWORD_PTR GetObj(DacpObjectData& tokenArray, UINT item)
447{
448 if (item < tokenArray.dwNumComponents)
449 {
450 DWORD_PTR dwAddr = (DWORD_PTR) (tokenArray.ArrayDataPtr + tokenArray.dwComponentSize*item);
451 DWORD_PTR objPtr;
452 if (SUCCEEDED(MOVE(objPtr, dwAddr)))
453 {
454 return objPtr;
455 }
456 }
457 return NULL;
458}
459
460
461void DisassembleToken(DacpObjectData& tokenArray,
462 DWORD token)
463{
464 switch (TypeFromToken(token))
465 {
466 default:
467 printf("<unknown token type (token=%08x)>", token);
468 break;
469
470 case mdtTypeDef:
471 {
472 DWORD_PTR runtimeTypeHandle = GetObj(tokenArray, RidFromToken(token));
473
474 DWORD_PTR runtimeType = NULL;
475 MOVE(runtimeType, runtimeTypeHandle + sizeof(DWORD_PTR));
476
477 int offset = GetObjFieldOffset(runtimeType, W("m_handle"));
478
479 DWORD_PTR methodTable = NULL;
480 MOVE(methodTable, runtimeType + offset);
481
482 if (NameForMT_s(methodTable, g_mdName,mdNameLen))
483 {
484 printf("%x \"%S\"", token, g_mdName);
485 }
486 else
487 {
488 printf("<invalid MethodTable>");
489 }
490 }
491 break;
492
493 case mdtSignature:
494 case mdtTypeRef:
495 {
496 printf ("%x (%p)", token, SOS_PTR(GetObj(tokenArray, RidFromToken(token))));
497 }
498 break;
499
500 case mdtFieldDef:
501 {
502 printf ("%x (%p)", token, SOS_PTR(GetObj(tokenArray, RidFromToken(token))));
503 }
504 break;
505
506 case mdtMethodDef:
507 {
508 CLRDATA_ADDRESS runtimeMethodHandle = GetObj(tokenArray, RidFromToken(token));
509 int offset = GetObjFieldOffset(runtimeMethodHandle, W("m_value"));
510
511 TADDR runtimeMethodInfo = NULL;
512 MOVE(runtimeMethodInfo, runtimeMethodHandle+offset);
513
514 offset = GetObjFieldOffset(runtimeMethodInfo, W("m_handle"));
515
516 TADDR methodDesc = NULL;
517 MOVE(methodDesc, runtimeMethodInfo+offset);
518
519 NameForMD_s((DWORD_PTR)methodDesc, g_mdName, mdNameLen);
520 printf ("%x %S", token, g_mdName);
521 }
522 break;
523
524 case mdtMemberRef:
525 {
526 printf ("%x (%p)", token, SOS_PTR(GetObj(tokenArray, RidFromToken(token))));
527 }
528 break;
529 case mdtString:
530 {
531 DWORD_PTR strObj = GetObj(tokenArray, RidFromToken(token));
532 printf ("%x \"", token);
533 StringObjectContent (strObj, FALSE, 40);
534 printf ("\"");
535 }
536 break;
537 }
538}
539
540// Similar to the function above. TODO: factor them together before checkin.
541void DecodeDynamicIL(BYTE *data, ULONG Size, DacpObjectData& tokenArray)
542{
543 // There is no header for this dynamic guy.
544 // Set globals
545 position = 0;
546 pBuffer = data;
547
548 // At this time no exception information will be displayed (fix soon)
549 UINT indentCount = 0;
550 ULONG endCodePosition = Size;
551 while(position < endCodePosition)
552 {
553 printf("%*sIL_%04x: ", indentCount, "", position);
554 unsigned int c = readOpcode();
555 OpCode opcode = opcodes[c];
556 printf("%s ", opcode.name);
557
558 switch(opcode.args)
559 {
560 case InlineNone: break;
561
562 case ShortInlineVar:
563 printf("VAR OR ARG %d",readData<BYTE>()); break;
564 case InlineVar:
565 printf("VAR OR ARG %d",readData<WORD>()); break;
566 case InlineI:
567 printf("%d",readData<LONG>());
568 break;
569 case InlineR:
570 printf("%f",readData<double>());
571 break;
572 case InlineBrTarget:
573 printf("IL_%04x",readData<LONG>() + position); break;
574 case ShortInlineBrTarget:
575 printf("IL_%04x",readData<BYTE>() + position); break;
576 case InlineI8:
577 printf("%ld", readData<__int64>()); break;
578
579 case InlineMethod:
580 case InlineField:
581 case InlineType:
582 case InlineTok:
583 case InlineSig:
584 case InlineString:
585 {
586 LONG l = readData<LONG>();
587 DisassembleToken(tokenArray, l);
588 break;
589 }
590
591 case InlineSwitch:
592 {
593 LONG cases = readData<LONG>();
594 LONG *pArray = new LONG[cases];
595 LONG i=0;
596 for(i=0;i<cases;i++)
597 {
598 pArray[i] = readData<LONG>();
599 }
600 printf("(");
601 for(i=0;i<cases;i++)
602 {
603 if (i != 0)
604 printf(", ");
605 printf("IL_%04x",pArray[i] + position);
606 }
607 printf(")");
608 delete [] pArray;
609 break;
610 }
611 case ShortInlineI:
612 printf("%d", readData<BYTE>()); break;
613 case ShortInlineR:
614 printf("%f", readData<float>()); break;
615 default: printf("Error, unexpected opcode type\n"); break;
616 }
617
618 printf("\n");
619 }
620}
621
622
623
624/******************************************************************************/
625// CQuickBytes utilities
626static char* asString(CQuickBytes *out) {
627 SIZE_T oldSize = out->Size();
628 out->ReSize(oldSize + 1);
629 char* cur = &((char*) out->Ptr())[oldSize];
630 *cur = 0;
631 out->ReSize(oldSize); // Don't count the null character
632 return((char*) out->Ptr());
633}
634
635static void appendStr(CQuickBytes *out, const char* str, unsigned len=-1) {
636 if(len == (unsigned)(-1)) len = (unsigned)strlen(str);
637 SIZE_T oldSize = out->Size();
638 out->ReSize(oldSize + len);
639 char* cur = &((char*) out->Ptr())[oldSize];
640 memcpy(cur, str, len);
641 // Note no trailing null!
642}
643
644static void appendChar(CQuickBytes *out, char chr) {
645 SIZE_T oldSize = out->Size();
646 out->ReSize(oldSize + 1);
647 ((char*) out->Ptr())[oldSize] = chr;
648 // Note no trailing null!
649}
650
651static void insertStr(CQuickBytes *out, const char* str) {
652 unsigned len = (unsigned)strlen(str);
653 SIZE_T oldSize = out->Size();
654 out->ReSize(oldSize + len);
655 char* cur = &((char*) out->Ptr())[len];
656 memmove(cur,out->Ptr(),oldSize);
657 memcpy(out->Ptr(), str, len);
658 // Note no trailing null!
659}
660
661static void appendStrNum(CQuickBytes *out, int num) {
662 char buff[16];
663 sprintf_s(buff, COUNTOF(buff), "%d", num);
664 appendStr(out, buff);
665}
666
667
668//PrettyPrinting type names
669PCCOR_SIGNATURE PrettyPrintType(
670 PCCOR_SIGNATURE typePtr, // type to convert,
671 CQuickBytes *out, // where to put the pretty printed string
672 IMDInternalImport *pIMDI, // ptr to IMDInternal class with ComSig
673 DWORD formatFlags /*= formatILDasm*/)
674{
675 mdToken tk;
676 const char* str;
677 int typ;
678 CQuickBytes tmp;
679 CQuickBytes Appendix;
680 BOOL Reiterate;
681 int n;
682
683 do {
684 Reiterate = FALSE;
685 switch(typ = *typePtr++) {
686 case ELEMENT_TYPE_VOID :
687 str = "void"; goto APPEND;
688 case ELEMENT_TYPE_BOOLEAN :
689 str = "bool"; goto APPEND;
690 case ELEMENT_TYPE_CHAR :
691 str = "char"; goto APPEND;
692 case ELEMENT_TYPE_I1 :
693 str = "int8"; goto APPEND;
694 case ELEMENT_TYPE_U1 :
695 str = "uint8"; goto APPEND;
696 case ELEMENT_TYPE_I2 :
697 str = "int16"; goto APPEND;
698 case ELEMENT_TYPE_U2 :
699 str = "uint16"; goto APPEND;
700 case ELEMENT_TYPE_I4 :
701 str = "int32"; goto APPEND;
702 case ELEMENT_TYPE_U4 :
703 str = "uint32"; goto APPEND;
704 case ELEMENT_TYPE_I8 :
705 str = "int64"; goto APPEND;
706 case ELEMENT_TYPE_U8 :
707 str = "uint64"; goto APPEND;
708 case ELEMENT_TYPE_R4 :
709 str = "float32"; goto APPEND;
710 case ELEMENT_TYPE_R8 :
711 str = "float64"; goto APPEND;
712 case ELEMENT_TYPE_U :
713 str = "native uint"; goto APPEND;
714 case ELEMENT_TYPE_I :
715 str = "native int"; goto APPEND;
716 case ELEMENT_TYPE_OBJECT :
717 str = "object"; goto APPEND;
718 case ELEMENT_TYPE_STRING :
719 str = "string"; goto APPEND;
720 case ELEMENT_TYPE_TYPEDBYREF :
721 str = "typedref"; goto APPEND;
722 APPEND:
723 appendStr(out, (char*)str);
724 break;
725
726 case ELEMENT_TYPE_VALUETYPE :
727 if ((formatFlags & FormatKwInNames) != 0)
728 str = "valuetype ";
729 else str = "";
730 goto DO_CLASS;
731 case ELEMENT_TYPE_CLASS :
732 if ((formatFlags & FormatKwInNames) != 0)
733 str = "class ";
734 else str = "";
735 goto DO_CLASS;
736
737 DO_CLASS:
738 appendStr(out, (char*)str);
739 typePtr += CorSigUncompressToken(typePtr, &tk);
740 if(IsNilToken(tk))
741 {
742 appendStr(out, "[ERROR! NIL TOKEN]");
743 }
744 else PrettyPrintClass(out, tk, pIMDI, formatFlags);
745 break;
746
747 case ELEMENT_TYPE_SZARRAY :
748 insertStr(&Appendix,"[]");
749 Reiterate = TRUE;
750 break;
751
752 case ELEMENT_TYPE_ARRAY :
753 {
754 typePtr = PrettyPrintType(typePtr, out, pIMDI, formatFlags);
755 unsigned rank = CorSigUncompressData(typePtr);
756 // <TODO> what is the syntax for the rank 0 case? </TODO>
757 if (rank == 0) {
758 appendStr(out, "[BAD: RANK == 0!]");
759 }
760 else {
761 _ASSERTE(rank != 0);
762#ifdef _PREFAST_
763#pragma warning(push)
764#pragma warning(disable:22009) // "Suppress PREfast warnings about integer overflow"
765// PREFAST warns about using _alloca in a loop. However when we're in this switch case we do NOT
766// set Reiterate to true, so we only execute through the loop once!
767#pragma warning(disable:6263) // "Suppress PREfast warnings about stack overflow due to _alloca in a loop."
768#endif
769 int* lowerBounds = (int*) _alloca(sizeof(int)*2*rank);
770 int* sizes = &lowerBounds[rank];
771 memset(lowerBounds, 0, sizeof(int)*2*rank);
772
773 unsigned numSizes = CorSigUncompressData(typePtr);
774 _ASSERTE(numSizes <= rank);
775 unsigned i;
776 for(i =0; i < numSizes; i++)
777 sizes[i] = CorSigUncompressData(typePtr);
778
779 unsigned numLowBounds = CorSigUncompressData(typePtr);
780 _ASSERTE(numLowBounds <= rank);
781 for(i = 0; i < numLowBounds; i++)
782 typePtr+=CorSigUncompressSignedInt(typePtr,&lowerBounds[i]);
783
784 appendChar(out, '[');
785 if (rank == 1 && numSizes == 0 && numLowBounds == 0)
786 appendStr(out, "...");
787 else {
788 for(i = 0; i < rank; i++)
789 {
790 //if (sizes[i] != 0 || lowerBounds[i] != 0)
791 {
792 if (i < numSizes && lowerBounds[i] == 0)
793 appendStrNum(out, sizes[i]);
794 else
795 {
796 if(i < numLowBounds)
797 {
798 appendStrNum(out, lowerBounds[i]);
799 appendStr(out, "...");
800 if (/*sizes[i] != 0 && */i < numSizes)
801 appendStrNum(out, lowerBounds[i] + sizes[i] - 1);
802 }
803 }
804 }
805 if (i < rank-1)
806 appendChar(out, ',');
807 }
808 }
809 appendChar(out, ']');
810#ifdef _PREFAST_
811#pragma warning(pop)
812#endif
813 }
814 } break;
815
816 case ELEMENT_TYPE_VAR :
817 appendChar(out, '!');
818 n = CorSigUncompressData(typePtr);
819 appendStrNum(out, n);
820 break;
821
822 case ELEMENT_TYPE_MVAR :
823 appendChar(out, '!');
824 appendChar(out, '!');
825 n = CorSigUncompressData(typePtr);
826 appendStrNum(out, n);
827 break;
828
829 case ELEMENT_TYPE_FNPTR :
830 appendStr(out, "method ");
831 appendStr(out, "METHOD"); // was: typePtr = PrettyPrintSignature(typePtr, 0x7FFF, "*", out, pIMDI, NULL);
832 break;
833
834 case ELEMENT_TYPE_GENERICINST :
835 {
836 typePtr = PrettyPrintType(typePtr, out, pIMDI, formatFlags);
837 if ((formatFlags & FormatSignature) == 0)
838 break;
839
840 if ((formatFlags & FormatAngleBrackets) != 0)
841 appendStr(out, "<");
842 else
843 appendStr(out,"[");
844 unsigned numArgs = CorSigUncompressData(typePtr);
845 bool needComma = false;
846 while(numArgs--)
847 {
848 if (needComma)
849 appendChar(out, ',');
850 typePtr = PrettyPrintType(typePtr, out, pIMDI, formatFlags);
851 needComma = true;
852 }
853 if ((formatFlags & FormatAngleBrackets) != 0)
854 appendStr(out, ">");
855 else
856 appendStr(out,"]");
857 break;
858 }
859
860 case ELEMENT_TYPE_PINNED :
861 str = " pinned"; goto MODIFIER;
862 case ELEMENT_TYPE_PTR :
863 str = "*"; goto MODIFIER;
864 case ELEMENT_TYPE_BYREF :
865 str = "&"; goto MODIFIER;
866 MODIFIER:
867 insertStr(&Appendix, str);
868 Reiterate = TRUE;
869 break;
870
871 default:
872 case ELEMENT_TYPE_SENTINEL :
873 case ELEMENT_TYPE_END :
874 //_ASSERTE(!"Unknown Type");
875 if(typ)
876 {
877 char sz[64];
878 sprintf_s(sz,COUNTOF(sz),"/* UNKNOWN TYPE (0x%X)*/",typ);
879 appendStr(out, sz);
880 }
881 break;
882 } // end switch
883 } while(Reiterate);
884 if (Appendix.Size() > 0)
885 appendStr(out,asString(&Appendix));
886
887 return(typePtr);
888}
889
890// Protection against null names, used by ILDASM/SOS
891const char *const szStdNamePrefix[] = {"MO","TR","TD","","FD","","MD","","PA","II","MR","","CA","","PE","","","SG","","","EV",
892"","","PR","","","MOR","TS","","","","","AS","","","AR","","","FL","ET","MAR"};
893
894#define MAKE_NAME_IF_NONE(psz, tk) { if(!(psz && *psz)) { char* sz = (char*)_alloca(16); \
895sprintf_s(sz,16,"$%s$%X",szStdNamePrefix[tk>>24],tk&0x00FFFFFF); psz = sz; } }
896
897const char* PrettyPrintClass(
898 CQuickBytes *out, // where to put the pretty printed string
899 mdToken tk, // The class token to look up
900 IMDInternalImport *pIMDI, // ptr to IMDInternalImport class with ComSig
901 DWORD formatFlags /*= formatILDasm*/)
902{
903 if(tk == mdTokenNil) // Zero resolution scope for "somewhere here" TypeRefs
904 {
905 appendStr(out,"[*]");
906 return(asString(out));
907 }
908 if (!pIMDI->IsValidToken(tk))
909 {
910 char str[1024];
911 sprintf_s(str,COUNTOF(str)," [ERROR: INVALID TOKEN 0x%8.8X] ",tk);
912 appendStr(out, str);
913 return(asString(out));
914 }
915 switch (TypeFromToken(tk))
916 {
917 case mdtTypeRef:
918 case mdtTypeDef:
919 {
920 const char *nameSpace = 0;
921 const char *name = 0;
922 mdToken tkEncloser = mdTokenNil;
923
924 if (TypeFromToken(tk) == mdtTypeRef)
925 {
926 if (((formatFlags & FormatAssembly) && FAILED(pIMDI->GetResolutionScopeOfTypeRef(tk, &tkEncloser))) ||
927 FAILED(pIMDI->GetNameOfTypeRef(tk, &nameSpace, &name)))
928 {
929 char str[1024];
930 sprintf_s(str, COUNTOF(str), " [ERROR: Invalid TypeRef record 0x%8.8X] ", tk);
931 appendStr(out, str);
932 return asString(out);
933 }
934 }
935 else
936 {
937 if (((formatFlags & FormatNamespace) == 0) || FAILED(pIMDI->GetNestedClassProps(tk,&tkEncloser)))
938 {
939 tkEncloser = mdTypeDefNil;
940 }
941 if (FAILED(pIMDI->GetNameOfTypeDef(tk, &name, &nameSpace)))
942 {
943 char str[1024];
944 sprintf_s(str, COUNTOF(str), " [ERROR: Invalid TypeDef record 0x%8.8X] ", tk);
945 appendStr(out, str);
946 return asString(out);
947 }
948 }
949 MAKE_NAME_IF_NONE(name,tk);
950 if((tkEncloser == mdTokenNil) || RidFromToken(tkEncloser))
951 {
952 if (TypeFromToken(tkEncloser) == mdtTypeRef || TypeFromToken(tkEncloser) == mdtTypeDef)
953 {
954 PrettyPrintClass(out,tkEncloser,pIMDI, formatFlags);
955 if (formatFlags & FormatSlashSep)
956 appendChar(out, '/');
957 else
958 appendChar(out, '+');
959 //nameSpace = ""; //don't print namespaces for nested classes!
960 }
961 else if (formatFlags & FormatAssembly)
962 {
963 PrettyPrintClass(out,tkEncloser,pIMDI, formatFlags);
964 }
965 }
966 if(TypeFromToken(tk)==mdtTypeDef)
967 {
968 unsigned L = (unsigned)strlen(name)+1;
969 char* szFN = NULL;
970 if(((formatFlags & FormatNamespace) != 0) && nameSpace && *nameSpace)
971 {
972 const char* sz = nameSpace;
973 L+= (unsigned)strlen(sz)+1;
974 szFN = new char[L];
975 sprintf_s(szFN,L,"%s.",sz);
976 }
977 else
978 {
979 szFN = new char[L];
980 *szFN = 0;
981 }
982 strcat_s(szFN,L, name);
983 appendStr(out, szFN);
984 if (szFN) delete[] (szFN);
985 }
986 else
987 {
988 if (((formatFlags & FormatNamespace) != 0) && nameSpace && *nameSpace) {
989 appendStr(out, nameSpace);
990 appendChar(out, '.');
991 }
992
993 appendStr(out, name);
994 }
995 }
996 break;
997
998 case mdtAssemblyRef:
999 {
1000 LPCSTR szName = NULL;
1001 pIMDI->GetAssemblyRefProps(tk,NULL,NULL,&szName,NULL,NULL,NULL,NULL);
1002 if(szName && *szName)
1003 {
1004 appendChar(out, '[');
1005 appendStr(out, szName);
1006 appendChar(out, ']');
1007 }
1008 }
1009 break;
1010 case mdtAssembly:
1011 {
1012 LPCSTR szName = NULL;
1013 pIMDI->GetAssemblyProps(tk,NULL,NULL,NULL,&szName,NULL,NULL);
1014 if(szName && *szName)
1015 {
1016 appendChar(out, '[');
1017 appendStr(out, szName);
1018 appendChar(out, ']');
1019 }
1020 }
1021 break;
1022 case mdtModuleRef:
1023 {
1024 LPCSTR szName = NULL;
1025 pIMDI->GetModuleRefProps(tk,&szName);
1026 if(szName && *szName)
1027 {
1028 appendChar(out, '[');
1029 appendStr(out, ".module ");
1030 appendStr(out, szName);
1031 appendChar(out, ']');
1032 }
1033 }
1034 break;
1035
1036 case mdtTypeSpec:
1037 {
1038 ULONG cSig;
1039 PCCOR_SIGNATURE sig;
1040 if (FAILED(pIMDI->GetSigFromToken(tk, &cSig, &sig)))
1041 {
1042 char str[128];
1043 sprintf_s(str, COUNTOF(str), " [ERROR: Invalid token 0x%8.8X] ", tk);
1044 appendStr(out, str);
1045 }
1046 else
1047 {
1048 PrettyPrintType(sig, out, pIMDI, formatFlags);
1049 }
1050 }
1051 break;
1052
1053 case mdtModule:
1054 break;
1055
1056 default:
1057 {
1058 char str[128];
1059 sprintf_s(str,COUNTOF(str)," [ERROR: INVALID TOKEN TYPE 0x%8.8X] ",tk);
1060 appendStr(out, str);
1061 }
1062 }
1063 return(asString(out));
1064}
1065
1066// This function takes a module and a token and prints the representation in the mdName buffer.
1067void PrettyPrintClassFromToken(
1068 TADDR moduleAddr, // the module containing the token
1069 mdToken tok, // the class token to look up
1070 __out_ecount(cbName) WCHAR* mdName, // where to put the pretty printed string
1071 size_t cbName, // the capacity of the buffer
1072 DWORD formatFlags /*= FormatCSharp*/)
1073{
1074 // set the default value
1075 swprintf_s(mdName, cbName, W("token_0x%8.8X"), tok);
1076
1077 DacpModuleData dmd;
1078 if (dmd.Request(g_sos, TO_CDADDR(moduleAddr)) != S_OK)
1079 return;
1080
1081 ToRelease<IMetaDataImport> pImport(MDImportForModule(&dmd));
1082 ToRelease<IMDInternalImport> pIMDI = NULL;
1083
1084 if ((pImport == NULL) || FAILED(GetMDInternalFromImport(pImport, &pIMDI)))
1085 return;
1086
1087 CQuickBytes qb;
1088 PrettyPrintClass(&qb, tok, pIMDI, formatFlags);
1089 MultiByteToWideChar (CP_ACP, 0, asString(&qb), -1, mdName, (int) cbName);
1090}
1091