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 * File: winmain.cpp *
8 * *
9 * Purpose: Main program for graphic COM+ 2.0 disassembler ILDASM.exe *
10 * *
11 ************************************************************************************************/
12#include "ildasmpch.h"
13
14#include "dynamicarray.h"
15
16#include "dasmenum.hpp"
17#include "dis.h"
18#include <ndpversion.h>
19#include "resource.h"
20
21#include "new.hpp"
22
23#define MODE_DUMP_ALL 0
24#define MODE_DUMP_CLASS 1
25#define MODE_DUMP_CLASS_METHOD 2
26#define MODE_DUMP_CLASS_METHOD_SIG 3
27
28// All externs are defined in DASM.CPP
29extern BOOL g_fDumpIL;
30extern BOOL g_fDumpHeader;
31extern BOOL g_fDumpAsmCode;
32extern BOOL g_fDumpTokens;
33extern BOOL g_fDumpStats;
34extern BOOL g_fDumpClassList;
35extern BOOL g_fDumpTypeList;
36extern BOOL g_fDumpSummary;
37extern BOOL g_fDecompile; // still in progress
38extern BOOL g_fShowRefs;
39
40extern BOOL g_fDumpToPerfWriter;
41
42extern BOOL g_fShowBytes;
43extern BOOL g_fShowSource;
44extern BOOL g_fInsertSourceLines;
45extern BOOL g_fTryInCode;
46extern BOOL g_fQuoteAllNames;
47extern BOOL g_fTDC;
48extern BOOL g_fShowCA;
49extern BOOL g_fCAVerbal;
50
51extern char g_pszClassToDump[];
52extern char g_pszMethodToDump[];
53extern char g_pszSigToDump[];
54
55extern char g_szAsmCodeIndent[];
56
57extern DWORD g_Mode;
58
59extern char* g_pszExeFile;
60extern char g_szInputFile[]; // in UTF-8
61extern WCHAR g_wszFullInputFile[]; // in UTF-16
62extern char g_szOutputFile[]; // in UTF-8
63extern char* g_pszObjFileName;
64extern FILE* g_pFile;
65
66extern BOOL g_fLimitedVisibility;
67#if defined(_DEBUG) && defined(FEATURE_PREJIT)
68extern BOOL g_fNGenNativeMetadata;
69#endif
70extern BOOL g_fHidePub;
71extern BOOL g_fHidePriv;
72extern BOOL g_fHideFam;
73extern BOOL g_fHideAsm;
74extern BOOL g_fHideFAA;
75extern BOOL g_fHideFOA;
76extern BOOL g_fHidePrivScope;
77extern BOOL g_fProject;
78
79extern unsigned g_uCodePage;
80extern unsigned g_uConsoleCP;
81extern BOOL g_fForwardDecl;
82extern BOOL g_fUseProperName;
83
84#include "../tools/metainfo/mdinfo.h"
85extern BOOL g_fDumpMetaInfo;
86extern ULONG g_ulMetaInfoFilter;
87HINSTANCE g_hInstance;
88HINSTANCE g_hResources;
89HANDLE hConsoleOut=NULL;
90HANDLE hConsoleErr=NULL;
91// These are implemented in DASM.CPP:
92BOOL Init();
93void Uninit();
94void Cleanup();
95void DumpMetaInfo(__in __nullterminated const WCHAR* pszFileName, __in __nullterminated const char* pszObjFileName, void* GUICookie);
96FILE* OpenOutput(__in __nullterminated const char* szFileName);
97
98void PrintLogo()
99{
100 printf("Microsoft (R) .NET Framework IL Disassembler. Version " VER_FILEVERSION_STR);
101 printf("\n%S\n\n", VER_LEGALCOPYRIGHT_LOGO_STR_L);
102}
103
104void SyntaxCon()
105{
106 DWORD l;
107
108 for(l=IDS_USAGE_01; l<= IDS_USAGE_23; l++) printf(RstrANSI(l));
109 if(g_fTDC)
110 {
111 for(l=IDS_USAGE_24; l<= IDS_USAGE_32; l++) printf(RstrANSI(l));
112 for(l=IDS_USAGE_34; l<= IDS_USAGE_36; l++) printf(RstrANSI(l));
113 for(l=IDS_USAGE_37; l<= IDS_USAGE_39; l++) printf(RstrANSI(l));
114 }
115 else printf(RstrANSI(IDS_USAGE_40));
116 for(l=IDS_USAGE_41; l<= IDS_USAGE_42; l++) printf(RstrANSI(l));
117
118}
119
120char* CheckForDQuotes(__inout __nullterminated char* sz)
121{
122 char* ret = sz;
123 if(*sz == '"')
124 {
125 ret++;
126 sz[strlen(sz)-1] = 0;
127 }
128 return ret;
129}
130
131char* EqualOrColon(__in __nullterminated char* szArg)
132{
133 char* pchE = strchr(szArg,'=');
134 char* pchC = strchr(szArg,':');
135 char* ret;
136 if(pchE == NULL) ret = pchC;
137 else if(pchC == NULL) ret = pchE;
138 else ret = (pchE < pchC)? pchE : pchC;
139 return ret;
140}
141
142void GetInputFileFullPath()
143{
144 // We need the input file's full path to make uses of it later, despite changing CurrentDirectory
145
146 // First, convert back up to UTF16
147 DWORD len = (DWORD) strlen(g_szInputFile) + 16;
148 WCHAR* wzArg = new WCHAR[len];
149 memset(wzArg, 0, len * sizeof(WCHAR));
150 WszMultiByteToWideChar(g_uConsoleCP, 0, g_szInputFile, -1, wzArg, len);
151
152 // Get the full path
153 len = WszGetFullPathName(wzArg, MAX_PATH, g_wszFullInputFile, NULL);
154 VDELETE(wzArg);
155}
156
157int ProcessOneArg(__in __nullterminated char* szArg, __out char** ppszObjFileName)
158{
159 char szOpt[128];
160 if(strlen(szArg) == 0) return 0;
161 if ((strcmp(szArg, "/?") == 0) || (strcmp(szArg, "-?") == 0)) return 1;
162
163#ifdef FEATURE_PAL
164 if(szArg[0] == '-')
165#else
166 if((szArg[0] == '/') || (szArg[0] == '-'))
167#endif
168 {
169 strncpy_s(szOpt,128, &szArg[1],10);
170 szOpt[3] = 0;
171 if (_stricmp(szOpt, "dec") == 0)
172 {
173 g_fDecompile = TRUE;
174 }
175 else if (_stricmp(szOpt, "hea") == 0)
176 {
177 g_fDumpHeader = TRUE;
178 }
179 else if (_stricmp(szOpt, "adv") == 0)
180 {
181 g_fTDC = TRUE;
182 }
183 else if (_stricmp(szOpt, "tok") == 0)
184 {
185 g_fDumpTokens = TRUE;
186 }
187 else if (_stricmp(szOpt, "noi") == 0)
188 {
189 g_fDumpAsmCode = FALSE;
190 }
191 else if (_stricmp(szOpt, "noc") == 0)
192 {
193 g_fShowCA = FALSE;
194 }
195 else if (_stricmp(szOpt, "cav") == 0)
196 {
197 g_fCAVerbal = TRUE;
198 }
199 else if (_stricmp(szOpt, "not") == 0)
200 {
201 g_fTryInCode = FALSE;
202 }
203 else if (_stricmp(szOpt, "raw") == 0)
204 {
205 g_fTryInCode = FALSE;
206 }
207 else if (_stricmp(szOpt, "byt") == 0)
208 {
209 g_fShowBytes = TRUE;
210 }
211 else if (_stricmp(szOpt, "sou") == 0)
212 {
213 printf("Warning: 'SOURCE' option is ignored for ildasm on CoreCLR.\n");
214 }
215 else if (_stricmp(szOpt, "lin") == 0)
216 {
217 g_fInsertSourceLines = TRUE;
218 }
219 else if ((_stricmp(szOpt, "sta") == 0)&&g_fTDC)
220 {
221 g_fDumpStats = g_fTDC;
222 }
223 else if ((_stricmp(szOpt, "cla") == 0)&&g_fTDC)
224 {
225 g_fDumpClassList = g_fTDC;
226 }
227 else if (_stricmp(szOpt, "typ") == 0)
228 {
229 g_fDumpTypeList = TRUE;
230 }
231 else if (_stricmp(szOpt, "sum") == 0)
232 {
233 g_fDumpSummary = TRUE;
234 }
235 else if (_stricmp(szOpt, "per") == 0)
236 {
237 g_fDumpToPerfWriter = TRUE;
238 }
239 else if (_stricmp(szOpt, "for") == 0)
240 {
241 g_fForwardDecl = TRUE;
242 }
243 else if (_stricmp(szOpt, "ref") == 0)
244 {
245 g_fShowRefs = TRUE;
246 }
247 else if (_stricmp(szOpt, "pub") == 0)
248 {
249 g_fLimitedVisibility = TRUE;
250 g_fHidePub = FALSE;
251 }
252#if defined(_DEBUG) && defined(FEATURE_PREJIT)
253 else if (_stricmp(szOpt, "nat") == 0)
254 {
255 g_fNGenNativeMetadata = TRUE;
256 }
257#endif
258 else if (_stricmp(szOpt, "pre") == 0)
259 {
260 //g_fPrettyPrint = TRUE;
261 }
262 else if (_stricmp(szOpt, "pro") == 0)
263 {
264 g_fProject = TRUE;
265 }
266 else if (_stricmp(szOpt, "vis") == 0)
267 {
268 char *pc = EqualOrColon(szArg);
269 char *pStr;
270 if(pc == NULL) return -1;
271 do {
272 pStr = pc+1;
273 pStr = CheckForDQuotes(pStr);
274 if((pc = strchr(pStr,'+'))) *pc=0;
275 if (!_stricmp(pStr,"pub")) g_fHidePub = FALSE;
276 else if(!_stricmp(pStr,"pri")) g_fHidePriv = FALSE;
277 else if(!_stricmp(pStr,"fam")) g_fHideFam = FALSE;
278 else if(!_stricmp(pStr,"asm")) g_fHideAsm = FALSE;
279 else if(!_stricmp(pStr,"faa")) g_fHideFAA = FALSE;
280 else if(!_stricmp(pStr,"foa")) g_fHideFOA = FALSE;
281 else if(!_stricmp(pStr,"psc")) g_fHidePrivScope = FALSE;
282 } while(pc);
283 g_fLimitedVisibility = g_fHidePub ||
284 g_fHidePriv ||
285 g_fHideFam ||
286 g_fHideAsm ||
287 g_fHideFAA ||
288 g_fHideFOA ||
289 g_fHidePrivScope;
290 }
291 else if (_stricmp(szOpt, "quo") == 0)
292 {
293 g_fQuoteAllNames = TRUE;
294 }
295 else if (_stricmp(szOpt, "utf") == 0)
296 {
297 g_uCodePage = CP_UTF8;
298 }
299 else if (_stricmp(szOpt, "uni") == 0)
300 {
301 g_uCodePage = 0xFFFFFFFF;
302 }
303 else if (_stricmp(szOpt, "rtf") == 0)
304 {
305 g_fDumpRTF = TRUE;
306 g_fDumpHTML = FALSE;
307 }
308 else if (_stricmp(szOpt, "htm") == 0)
309 {
310 g_fDumpRTF = FALSE;
311 g_fDumpHTML = TRUE;
312 }
313 else if (_stricmp(szOpt, "all") == 0)
314 {
315 g_fDumpStats = g_fTDC;
316 g_fDumpHeader = TRUE;
317 g_fShowBytes = TRUE;
318 g_fDumpClassList = g_fTDC;
319 g_fDumpTokens = TRUE;
320 }
321 else if (_stricmp(szOpt, "ite") == 0)
322 {
323 char *pStr = EqualOrColon(szArg);
324 char *p, *q;
325 if(pStr == NULL) return -1;
326 pStr++;
327 pStr = CheckForDQuotes(pStr);
328 // treat it as meaning "dump only class X" or "class X method Y"
329 p = strchr(pStr, ':');
330
331 if (p == NULL)
332 {
333 // dump one class
334 g_Mode = MODE_DUMP_CLASS;
335 strcpy_s(g_pszClassToDump, MAX_CLASSNAME_LENGTH, pStr);
336 }
337 else
338 {
339 *p++ = '\0';
340 if (*p != ':') return -1;
341
342 strcpy_s(g_pszClassToDump, MAX_CLASSNAME_LENGTH, pStr);
343
344 p++;
345
346 q = strchr(p, '(');
347 if (q == NULL)
348 {
349 // dump class::method
350 g_Mode = MODE_DUMP_CLASS_METHOD;
351 strcpy_s(g_pszMethodToDump, MAX_MEMBER_LENGTH, p);
352 }
353 else
354 {
355 // dump class::method(sig)
356 g_Mode = MODE_DUMP_CLASS_METHOD_SIG;
357 *q = '\0';
358 strcpy_s(g_pszMethodToDump, MAX_MEMBER_LENGTH, p);
359 // get rid of external parentheses:
360 q++;
361 strcpy_s(g_pszSigToDump, MAX_SIGNATURE_LENGTH, q);
362 }
363 }
364 }
365 else if ((_stricmp(szOpt, "met") == 0)&&g_fTDC)
366 {
367 printf("Warning: 'METADATA' option is ignored for ildasm on CoreCLR.\n");
368 }
369 else if (_stricmp(szOpt, "obj") == 0)
370 {
371 char *pStr = EqualOrColon(szArg);
372 if(pStr == NULL) return -1;
373 pStr++;
374 pStr = CheckForDQuotes(pStr);
375 *ppszObjFileName = new char[strlen(pStr)+1];
376 strcpy_s(*ppszObjFileName,strlen(pStr)+1,pStr);
377 }
378 else if (_stricmp(szOpt, "out") == 0)
379 {
380 char *pStr = EqualOrColon(szArg);
381 if(pStr == NULL) return -1;
382 pStr++;
383 pStr = CheckForDQuotes(pStr);
384 if(*pStr == 0) return -1;
385 if(_stricmp(pStr,"con"))
386 {
387 strncpy_s(g_szOutputFile, MAX_FILENAME_LENGTH, pStr,MAX_FILENAME_LENGTH-1);
388 g_szOutputFile[MAX_FILENAME_LENGTH-1] = 0;
389 }
390 }
391 else
392 {
393 PrintLogo();
394 printf(RstrANSI(IDS_E_INVALIDOPTION),szArg); //"INVALID COMMAND LINE OPTION: %s\n\n",szArg);
395 return -1;
396 }
397 }
398 else
399 {
400 if(g_szInputFile[0])
401 {
402 PrintLogo();
403 printf(RstrANSI(IDS_E_MULTIPLEINPUT)); //"MULTIPLE INPUT FILES SPECIFIED\n\n");
404 return -1; // check if it was already specified
405 }
406 szArg = CheckForDQuotes(szArg);
407 strncpy_s(g_szInputFile, MAX_FILENAME_LENGTH,szArg,MAX_FILENAME_LENGTH-1);
408 g_szInputFile[MAX_FILENAME_LENGTH-1] = 0;
409 GetInputFileFullPath();
410 }
411 return 0;
412}
413
414char* UTF8toANSI(__in __nullterminated char* szUTF)
415{
416 ULONG32 L = (ULONG32) strlen(szUTF)+16;
417 WCHAR* wzUnicode = new WCHAR[L];
418 memset(wzUnicode,0,L*sizeof(WCHAR));
419 WszMultiByteToWideChar(CP_UTF8,0,szUTF,-1,wzUnicode,L);
420 L <<= 2;
421 char* szANSI = new char[L];
422 memset(szANSI,0,L);
423 WszWideCharToMultiByte(g_uConsoleCP,0,wzUnicode,-1,szANSI,L,NULL,NULL);
424 VDELETE(wzUnicode);
425 return szANSI;
426}
427char* ANSItoUTF8(__in __nullterminated char* szANSI)
428{
429 ULONG32 L = (ULONG32) strlen(szANSI)+16;
430 WCHAR* wzUnicode = new WCHAR[L];
431 memset(wzUnicode,0,L*sizeof(WCHAR));
432 WszMultiByteToWideChar(g_uConsoleCP,0,szANSI,-1,wzUnicode,L);
433 L *= 3;
434 char* szUTF = new char[L];
435 memset(szUTF,0,L);
436 WszWideCharToMultiByte(CP_UTF8,0,wzUnicode,-1,szUTF,L,NULL,NULL);
437 VDELETE(wzUnicode);
438 return szUTF;
439}
440
441int ParseCmdLineW(__in __nullterminated WCHAR* wzCmdLine, __out char** ppszObjFileName)
442{
443 int argc,ret=0;
444 LPWSTR* argv= SegmentCommandLine(wzCmdLine, (DWORD*)&argc);
445 char* szArg = new char[2048];
446 for(int i=1; i < argc; i++)
447 {
448 memset(szArg,0,2048);
449 WszWideCharToMultiByte(CP_UTF8,0,argv[i],-1,szArg,2048,NULL,NULL);
450 if((ret = ProcessOneArg(szArg,ppszObjFileName)) != 0) break;
451 }
452 VDELETE(szArg);
453 return ret;
454}
455
456int ParseCmdLineA(__in __nullterminated char* szCmdLine, __out char** ppszObjFileName)
457{
458 if((szCmdLine == NULL)||(*szCmdLine == 0)) return 0;
459
460 // ANSI to UTF-8
461 char* szCmdLineUTF = ANSItoUTF8(szCmdLine);
462
463 // Split into argv[]
464 int argc=0, ret = 0;
465 DynamicArray<char*> argv;
466 char* pch;
467 char* pchend;
468 bool bUnquoted = true;
469
470 pch = szCmdLineUTF;
471 pchend = pch+strlen(szCmdLineUTF);
472 while(pch)
473 {
474 for(; *pch == ' '; pch++); // skip the blanks
475 argv[argc++] = pch;
476 for(; pch < pchend; pch++)
477 {
478 if(*pch == '"') bUnquoted = !bUnquoted;
479 else if((*pch == ' ')&&bUnquoted) break;
480 }
481
482 if(pch < pchend) *pch++ = 0;
483 else break;
484 }
485
486 for(int i=1; i < argc; i++)
487 {
488 if((ret = ProcessOneArg(argv[i],ppszObjFileName)) != 0) break;
489 }
490 VDELETE(szCmdLineUTF);
491 return ret;
492}
493
494int __cdecl main(int nCmdShow, char* lpCmdLine[])
495{
496#if defined(FEATURE_PAL)
497 if (0 != PAL_Initialize(nCmdShow, lpCmdLine))
498 {
499 printError(g_pFile, "Error: Fail to PAL_Initialize\n");
500 exit(1);
501 }
502 g_pszExeFile = lpCmdLine[0];
503#endif
504
505 // ildasm does not need to be SO-robust.
506 SO_NOT_MAINLINE_FUNCTION;
507
508 // SWI has requested that the exact form of the function call below be used. For details see http://swi/SWI%20Docs/Detecting%20Heap%20Corruption.doc
509 (void)HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
510
511#ifdef _DEBUG
512 DisableThrowCheck();
513#endif
514
515 int iCommandLineParsed = 0;
516 WCHAR* wzCommandLine = NULL;
517 char* szCommandLine = NULL;
518
519 g_fUseProperName = TRUE;
520
521 g_pszClassToDump[0]=0;
522 g_pszMethodToDump[0]=0;
523 g_pszSigToDump[0]=0;
524 memset(g_szInputFile,0,MAX_FILENAME_LENGTH);
525 memset(g_szOutputFile,0,MAX_FILENAME_LENGTH);
526#if defined(_DEBUG)
527 g_fTDC = TRUE;
528#endif
529
530#undef GetCommandLineW
531#undef CreateProcessW
532 g_pszObjFileName = NULL;
533
534 g_szAsmCodeIndent[0] = 0;
535 hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
536 hConsoleErr = GetStdHandle(STD_ERROR_HANDLE);
537
538#ifndef FEATURE_PAL
539 // Dev11 #5320 - pull the localized resource loader up so if ParseCmdLineW need resources, they're already loaded
540 g_hResources = LoadLocalizedResourceDLLForSDK(L"ildasmrc.dll");
541#endif
542
543 iCommandLineParsed = ParseCmdLineW((wzCommandLine = GetCommandLineW()),&g_pszObjFileName);
544
545 if(!g_fLimitedVisibility)
546 {
547 g_fHidePub = FALSE;
548 g_fHidePriv = FALSE;
549 g_fHideFam = FALSE;
550 g_fHideAsm = FALSE;
551 g_fHideFAA = FALSE;
552 g_fHideFOA = FALSE;
553 g_fHidePrivScope = FALSE;
554 }
555 if(hConsoleOut != INVALID_HANDLE_VALUE) //First pass: console
556 {
557 g_uConsoleCP = GetConsoleOutputCP();
558
559 if(iCommandLineParsed)
560 {
561 if(iCommandLineParsed > 0) PrintLogo();
562 SyntaxCon();
563 exit((iCommandLineParsed == 1) ? 0 : 1);
564 }
565
566 {
567 DWORD exitCode = 1;
568 if(g_szInputFile[0] == 0)
569 {
570 SyntaxCon();
571 exit(1);
572 }
573 g_pFile = NULL;
574 if(g_szOutputFile[0])
575 {
576 g_pFile = OpenOutput(g_szOutputFile);
577 if(g_pFile == NULL)
578 {
579 char sz[4096];
580 sprintf_s(sz,4096,RstrUTF(IDS_E_CANTOPENOUT)/*"Unable to open '%s' for output."*/, g_szOutputFile);
581 g_uCodePage = CP_ACP;
582 printError(NULL,sz);
583 exit(1);
584 }
585 }
586 else // console output -- force the code page to ANSI
587 {
588 g_uCodePage = g_uConsoleCP;
589 g_fDumpRTF = FALSE;
590 g_fDumpHTML = FALSE;
591 }
592 if (Init() == TRUE)
593 {
594 exitCode = DumpFile() ? 0 : 1;
595 Cleanup();
596 }
597 Uninit();
598 exit(exitCode);
599 }
600 }
601 return 0;
602}
603
604