diff options
author | Jiyoung Yun <jy910.yun@samsung.com> | 2016-11-23 19:09:09 +0900 |
---|---|---|
committer | Jiyoung Yun <jy910.yun@samsung.com> | 2016-11-23 19:09:09 +0900 |
commit | 4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (patch) | |
tree | 98110734c91668dfdbb126fcc0e15ddbd93738ca /src/ToolBox/superpmi/mcs | |
parent | fa45f57ed55137c75ac870356a1b8f76c84b229c (diff) | |
download | coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.gz coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.bz2 coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.zip |
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src/ToolBox/superpmi/mcs')
34 files changed, 3194 insertions, 0 deletions
diff --git a/src/ToolBox/superpmi/mcs/.gitmirror b/src/ToolBox/superpmi/mcs/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/ToolBox/superpmi/mcs/CMakeLists.txt b/src/ToolBox/superpmi/mcs/CMakeLists.txt new file mode 100644 index 0000000000..7e6ff70471 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/CMakeLists.txt @@ -0,0 +1,76 @@ +project(mcs) + +remove_definitions(-DUNICODE) +remove_definitions(-D_UNICODE) + +add_definitions(-DFEATURE_NO_HOST) +add_definitions(-DSELF_NO_HOST) + +if(WIN32) + #use static crt + add_definitions(-MT) +endif(WIN32) + +include_directories(.) +include_directories(../superpmi-shared) + +set(MCS_SOURCES + commandline.cpp + mcs.cpp + verbasmdump.cpp + verbconcat.cpp + verbdump.cpp + verbdumpmap.cpp + verbdumptoc.cpp + verbfracture.cpp + verbildump.cpp + verbinteg.cpp + verbmerge.cpp + verbremovedup.cpp + verbsmarty.cpp + verbstat.cpp + verbstrip.cpp + verbtoc.cpp + ../superpmi-shared/asmdumper.cpp + ../superpmi-shared/callutils.cpp + ../superpmi-shared/compileresult.cpp + ../superpmi-shared/errorhandling.cpp + ../superpmi-shared/logging.cpp + ../superpmi-shared/mclist.cpp + ../superpmi-shared/methodcontext.cpp + ../superpmi-shared/methodcontextiterator.cpp + ../superpmi-shared/methodcontextreader.cpp + ../superpmi-shared/simpletimer.cpp + ../superpmi-shared/spmiutil.cpp + ../superpmi-shared/tocfile.cpp + ../superpmi-shared/typeutils.cpp +) + +add_precompiled_header( + standardpch.h + ../superpmi-shared/standardpch.cpp + MCS_SOURCES +) + +add_executable(mcs + ${MCS_SOURCES} +) + +if(CLR_CMAKE_PLATFORM_UNIX) + target_link_libraries(mcs + utilcodestaticnohost + mscorrc_debug + coreclrpal + palrt + ) +else() + target_link_libraries(mcs + advapi32.lib + ${STATIC_MT_CRT_LIB} + ${STATIC_MT_CPP_LIB} + ) + + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/mcs.pdb DESTINATION PDB) +endif(CLR_CMAKE_PLATFORM_UNIX) + +install (TARGETS mcs DESTINATION .) diff --git a/src/ToolBox/superpmi/mcs/commandline.cpp b/src/ToolBox/superpmi/mcs/commandline.cpp new file mode 100644 index 0000000000..ea6a4a3e72 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/commandline.cpp @@ -0,0 +1,581 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// CommandLine.cpp - tiny very specific command line parser +//---------------------------------------------------------- + +#include "standardpch.h" +#include "commandline.h" +#include "logging.h" +#include "mclist.h" + +void CommandLine::DumpHelp(const char* program) +{ + printf("MCS is a utility for examining and manipulating SuperPMI MC files.\n"); + printf("\n"); + printf("Usage: %s [options] {verb} {verb options}", program); + printf("\n"); + printf("Options:\n"); + printf("\n"); + printf(" -v[erbosity] messagetypes\n"); + printf(" Controls which types of messages MCS logs. Specify a string of\n"); + printf(" characters representing message categories to enable, where:\n"); + printf(" e - errors (internal fatal errors that are non-recoverable)\n"); + printf(" w - warnings (internal conditions that are unusual, but not serious)\n"); + printf(" m - missing (failures due to missing JIT-EE interface details)\n"); + printf(" n - information (notifications/summaries, e.g. 'Loaded 42, Saved 23')\n"); + printf(" v - verbose (status messages, e.g. 'Jit startup took 151.12ms')\n"); + printf(" d - debug (lots of detailed output)\n"); + printf(" a - all (enable all message types; overrides other enable message types)\n"); + printf(" q - quiet (disable all output; overrides all others)\n"); + printf(" e.g. '-v ew' only writes error and warning messages to the console.\n"); + printf(" 'q' takes precedence over any other message type specified.\n"); + printf(" Default set of messages enabled is 'ewmnv'.\n"); + printf("\n"); + printf(" -writeLogFile logfile\n"); + printf(" Write log messages to the specified file.\n"); + printf("\n"); + printf("Verbs:\n"); + printf("\n"); + printf(" -ASMDump {optional range} inputfile outputfile\n"); + printf(" Dump out the asm file for each input methodContext.\n"); + printf(" inputfile is read and output is written to outputfile.\n"); + printf(" e.g. -ASMDump a.mc a.asm\n"); + printf("\n"); + printf(" -concat file1 file2\n"); + printf(" Concatenate two files without regard to internal formatting.\n"); + printf(" file2 is appended to file1.\n"); + printf(" e.g. -concat a.mch b.mch\n"); + printf("\n"); + printf(" -copy range file1 file2\n"); + printf(" Copy methodContext numbers in range from file1 to file2.\n"); + printf(" file1 is read and file2 is written\n"); + printf(" e.g. -copy a.mch b.mch\n"); + printf("\n"); + printf(" -dump {optional range} inputfile\n"); + printf(" Dump details for each methodContext\n"); + printf(" e.g. -dump a.mc\n"); + printf("\n"); + printf(" -dumpMap inputfile\n"); + printf(" Dump a map from MC index to function name to the console, in CSV format\n"); + printf(" e.g. -dumpMap a.mc\n"); + printf("\n"); + printf(" -dumpToc inputfile\n"); + printf(" Dump a TOC file\n"); + printf(" e.g. -dumpToc a.mct\n"); + printf("\n"); + printf(" -fracture range inputfile outputfile\n"); + printf(" Break the input file into chunks sized by range.\n"); + printf(" If '-thin' is also passed, CompileResults are stripped from the input file when written.\n"); + printf(" e.g. '-fracture 3 a.mch b-' leads to b-0.mch, b-1.mch, etc., with 3 mc's in each file.\n"); + printf("\n"); + printf(" -ildump {optional range} inputfile\n"); + printf(" Dump raw IL for each methodContext\n"); + printf(" e.g. -ildump a.mc\n"); + printf("\n"); + printf(" -integ inputfile\n"); + printf(" Check the integrity of each methodContext\n"); + printf(" e.g. -integ a.mc\n"); + printf("\n"); + printf(" -merge outputfile pattern\n"); + printf(" Merge all the input files matching the pattern.\n"); + printf(" e.g. -merge a.mch *.mc\n"); + printf(" e.g. -merge a.mch c:\\foo\\bar\\*.mc\n"); + printf(" e.g. -merge a.mch relpath\\*.mc\n"); + printf(" e.g. -merge a.mch .\n"); + printf(" e.g. -merge a.mch onedir\n"); + printf("\n"); + printf(" -merge outputfile pattern -recursive\n"); + printf(" Merge all the input files matching the pattern, in the specified and all child directories.\n"); + printf(" e.g. -merge a.mch *.mc -recursive\n"); + printf("\n"); + printf(" -removeDup inputfile outputfile\n"); + printf(" Copy methodContexts from inputfile to outputfile, skipping duplicates.\n"); + printf(" e.g. -removeDup a.mc b.mc\n"); + printf("\n"); + printf(" -removeDup -legacy inputfile outputfile\n"); + printf(" Copy methodContexts from inputfile to outputfile, skipping duplicates.\n"); + printf(" Comparisons are performed using the legacy method and may take much longer\n"); + printf(" e.g. -removeDup -legacy a.mc b.mc\n"); + printf("\n"); + printf(" -removeDup -thin inputfile outputfile\n"); + printf(" Copy methodContexts from inputfile to outputfile, skipping duplicates.\n"); + printf(" CompileResults are stripped from the input file when written.\n"); + printf(" e.g. -removeDup -thin a.mc b.mc\n"); + printf(" e.g. -removeDup -legacy -thin a.mc b.mc\n"); + printf("\n"); + printf(" -smarty range inputfile outputfile\n"); + printf(" Write smarty Test IDs of the range from inputfile to outputfile.\n"); + printf(" e.g. -smarty 2 a.mc b.mc\n"); + printf("\n"); + printf(" -stat {optional range} inputfile outputfile\n"); + printf(" Report various statistics per method context.\n"); + printf(" inputfile is read and statistics are written into outputfile\n"); + printf(" e.g. -stat a.mc a.csv\n"); + printf("\n"); + printf(" -strip range inputfile outputfile\n"); + printf(" Copy method contexts from one file to another, skipping ranged items.\n"); + printf(" inputfile is read and records not in range are written to outputfile.\n"); + printf(" e.g. -strip 2 a.mc b.mc\n"); + printf("\n"); + printf(" -toc inputfile\n"); + printf(" Create a Table of Contents file for inputfile to allow better random access\n"); + printf(" to the mch file.\n"); + printf(" e.g. '-toc a.mch' creates a.mch.mct\n"); + printf("\n"); + printf("Range descriptions are either a single number, or a text file with .mcl extension\n"); + printf("containing a sorted list of line delimited numbers.\n"); + printf(" e.g. -strip 2 a.mc b.mc\n"); + printf(" e.g. -strip list.mcl a.mc b.mc\n"); + printf("\n"); + printf("Note: Inputs are case insensitive.\n"); +} + +//Assumption: All inputs are initialized to default or real value. we'll just set the stuff in what we see on the command line. +//Assumption: Single byte names are passed in.. mb stuff doesnt cause an obvious problem... but it might have issues... +//Assumption: Values larger than 2^31 aren't expressible from the commandline.... (atoi) Unless you pass in negatives.. :-| +bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o) +{ + size_t argLen = 0; + size_t tempLen = 0; + + bool foundVerb = false; + bool foundFile1 = false; + bool foundFile2 = false; + + if (argc == 1) //Print help when no args are passed + { + DumpHelp(argv[0]); + return false; + } + + for (int i = 1; i<argc; i++) + { + bool isASwitch = (argv[i][0] == '-'); +#ifndef FEATURE_PAL + if (argv[i][0] == '/') // Also accept "/" on Windows + { + isASwitch = true; + } +#endif // !FEATURE_PAL + + //Process a switch + if (isASwitch) + { + argLen = strlen(argv[i]); + + if (argLen >1) + argLen--; //adjust for leading switch + else + { + DumpHelp(argv[0]); + return false; + } + + if ((_strnicmp(&argv[i][1], "help", argLen) == 0) || + (_strnicmp(&argv[i][1], "?", argLen) == 0)) + { + DumpHelp(argv[0]); + return false; + } + else if ((_strnicmp(&argv[i][1], "ASMDump", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionASMDump = true; + if (i + 1 < argc) //Peek to see if we have an mcl file or an integer next + goto processMCL; + } + else if ((_strnicmp(&argv[i][1], "concat", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionConcat = true; + } + else if ((_strnicmp(&argv[i][1], "copy", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionCopy = true; + if (i + 1 < argc) //Peek to see if we have an mcl file or an integer next + goto processMCL; + } + else if ((_strnicmp(&argv[i][1], "dump", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionDump = true; + if (i + 1 < argc) //Peek to see if we have an mcl file or an integer next + goto processMCL; + } + else if ((_strnicmp(&argv[i][1], "fracture", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionFracture = true; + if (i + 1 < argc) //Peek to see if we have an mcl file or an integer next + goto processMCL; + } + else if ((_strnicmp(&argv[i][1], "dumpmap", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionDumpMap = true; + } + else if ((_strnicmp(&argv[i][1], "dumptoc", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionDumpToc = true; + } + else if ((_strnicmp(&argv[i][1], "ildump", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionILDump = true; + if (i + 1 < argc) //Peek to see if we have an mcl file or an integer next + goto processMCL; + } + else if ((_strnicmp(&argv[i][1], "merge", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionMerge = true; + } + else if ((_strnicmp(&argv[i][1], "recursive", argLen) == 0)) + { + tempLen = strlen(argv[i]); + o->recursive = true; + } + else if ((_strnicmp(&argv[i][1], "toc", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionTOC = true; + } + else if ((_strnicmp(&argv[i][1], "input", argLen) == 0)) + { + if (++i >= argc) + { + DumpHelp(argv[0]); + return false; + } + + processInput: + + tempLen = strlen(argv[i]); + if (tempLen == 0) + { + printf("ERROR: CommandLine::Parse() Arg '%s' is invalid, name of file missing.\n", argv[i]); + DumpHelp(argv[0]); + return false; + } + if (foundFile1 == false) + { + o->nameOfFile1 = new char[tempLen + 1]; + strcpy_s(o->nameOfFile1, tempLen + 1, argv[i]); + foundFile1 = true; + } + else if (foundFile2 == false) + { + o->nameOfFile2 = new char[tempLen + 1]; + strcpy_s(o->nameOfFile2, tempLen + 1, argv[i]); + foundFile2 = true; + } + else + { + printf("ERROR: CommandLine::Parse() Arg '%s' is invalid, too many files given.\n", argv[i]); + DumpHelp(argv[0]); + return false; + } + } + else if ((_strnicmp(&argv[i][1], "integ", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionInteg = true; + } + else if ((_strnicmp(&argv[i][1], "mcl", argLen) == 0)) + { + if (i + 1 >= argc) + { + DumpHelp(argv[0]); + return false; + } + + processMCL: + i++; + processMCL2: + + bool isValidList = MCList::processArgAsMCL(argv[i], &o->indexCount, &o->indexes); + if (!isValidList) + i--; + } + else if ((_strnicmp(&argv[i][1], "removeDup", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionRemoveDup = true; + } + else if ((_strnicmp(&argv[i][1], "stat", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionStat = true; + if (i + 1 < argc) //Peek to see if we have an mcl file or an integer next + goto processMCL; + } + else if ((_strnicmp(&argv[i][1], "strip", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionStrip = true; + if (i + 1 < argc) //Peek to see if we have an mcl file or an integer next + goto processMCL; + } + else if ((_strnicmp(&argv[i][1], "thin", argLen) == 0)) + { + o->stripCR = true; + } + else if ((_strnicmp(&argv[i][1], "legacy", argLen) == 0)) + { + o->legacyCompare = true; + } + else if ((_strnicmp(&argv[i][1], "smarty", argLen) == 0)) + { + tempLen = strlen(argv[i]); + o->actionSmarty = true; + foundVerb = true; + if (i + 1 < argc) //Peek to see if we have an mcl file or an integer next + goto processMCL; + } + else if ((_strnicmp(&argv[i][1], "verbosity", argLen) == 0)) + { + if (++i >= argc) + { + DumpHelp(argv[0]); + return false; + } + + Logger::SetLogLevel(Logger::ParseLogLevelString(argv[i])); + } + else if ((_strnicmp(&argv[i][1], "writeLogFile", argLen) == 0)) + { + if (++i >= argc) + { + DumpHelp(argv[0]); + return false; + } + + Logger::OpenLogFile(argv[i]); + } + else + { + LogError("CommandLine::Parse() - Unknown verb '%s'", argv[i]); + DumpHelp(argv[0]); + return false; + } + + } + //Process an input filename + else + { + char *lastdot = strrchr(argv[i], '.'); + if (lastdot != nullptr) + { + if (_stricmp(lastdot, ".mcl") == 0) + goto processMCL2; + } + goto processInput; + } + } + + if (o->recursive) + { + if (!o->actionMerge) + { + LogError("CommandLine::Parse() '-recursive' requires -merge."); + DumpHelp(argv[0]); + return false; + } + } + + if (o->actionASMDump) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() -ASMDump needs one input file and one output file."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionConcat) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() '-concat' needs two input files (second will be used as output)."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionMerge) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() '-merge' needs an output file (the first) and a file pattern (the second)."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionCopy) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() '-copy' needs one input and one output."); + DumpHelp(argv[0]); + return false; + } + if (o->indexCount == 0) + { + LogError("CommandLine::Parse() -copy requires a range."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionDump) + { + if (!foundFile1) + { + LogError("CommandLine::Parse() '-dump' needs one input file, but didn't see one."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionFracture) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() '-fracture' needs one input and one output."); + DumpHelp(argv[0]); + return false; + } + if (o->indexCount == 0) + { + LogError("CommandLine::Parse() -fracture requires a range."); + DumpHelp(argv[0]); + return false; + } + if (o->indexCount > 1) + { + LogWarning("CommandLine::Parse() -fracture found multiple ranges, we'll use the first one."); + } + return true; + } + if (o->actionDumpMap) + { + if (!foundFile1) + { + LogError("CommandLine::Parse() '-dumpMap' needs one input."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionDumpToc) + { + if (!foundFile1) + { + LogError("CommandLine::Parse() '-dumpToc' needs one input."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionILDump) + { + if (!foundFile1) + { + LogError("CommandLine::Parse() '-ildump' needs one input."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionTOC) + { + if (!foundFile1) + { + LogError("CommandLine::Parse() '-toc' needs one input."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionInteg) + { + if (!foundFile1) + { + LogError("CommandLine::Parse() '-integ' needs one input file, but didn't see one."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionRemoveDup) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() -removeDup needs one input file and one output file."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionStat) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() '-stat' needs one input file and one output file."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionStrip) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() -strip needs one input file and one output file."); + DumpHelp(argv[0]); + return false; + } + if (o->indexCount == 0) + { + LogError("CommandLine::Parse() -strip requires a range."); + DumpHelp(argv[0]); + return false; + } + return true; + } + if (o->actionSmarty) + { + if ((!foundFile1) || (!foundFile2)) + { + LogError("CommandLine::Parse() '-smarty' needs one input file and one output file."); + DumpHelp(argv[0]); + return false; + } + return true; + } + + DumpHelp(argv[0]); + return false; +} diff --git a/src/ToolBox/superpmi/mcs/commandline.h b/src/ToolBox/superpmi/mcs/commandline.h new file mode 100644 index 0000000000..a04969696b --- /dev/null +++ b/src/ToolBox/superpmi/mcs/commandline.h @@ -0,0 +1,76 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// CommandLine.h - tiny very specific command line parser +//---------------------------------------------------------- +#ifndef _CommandLine +#define _CommandLine + +class CommandLine +{ +public: + + class Options + { + public: + Options() : + actionASMDump(false), + actionConcat(false), + actionCopy(false), + actionDump(false), + actionDumpMap(false), + actionDumpToc(false), + actionFracture(false), + actionILDump(false), + actionInteg(false), + actionMerge(false), + actionRemoveDup(false), + actionSmarty(false), + actionStat(false), + actionStrip(false), + actionTOC(false), + legacyCompare(false), + recursive(false), + stripCR(false), + nameOfFile1(nullptr), + nameOfFile2(nullptr), + nameOfFile3(nullptr), + indexCount(-1), + indexes(nullptr) + { + } + + bool actionASMDump; + bool actionConcat; + bool actionCopy; + bool actionDump; + bool actionDumpMap; + bool actionDumpToc; + bool actionFracture; + bool actionILDump; + bool actionInteg; + bool actionMerge; + bool actionRemoveDup; + bool actionSmarty; + bool actionStat; + bool actionStrip; + bool actionTOC; + bool legacyCompare; + bool recursive; + bool stripCR; + char* nameOfFile1; + char* nameOfFile2; + char* nameOfFile3; + int indexCount; + int* indexes; + }; + + static bool Parse(int argc, char* argv[], /* OUT */ Options* o); + +private: + static void DumpHelp(const char* program); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/mcs.cpp b/src/ToolBox/superpmi/mcs/mcs.cpp new file mode 100644 index 0000000000..d2debdd90f --- /dev/null +++ b/src/ToolBox/superpmi/mcs/mcs.cpp @@ -0,0 +1,108 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "mcs.h" +#include "commandline.h" +#include "verbasmdump.h" +#include "verbinteg.h" +#include "verbdump.h" +#include "verbfracture.h" +#include "verbdumpmap.h" +#include "verbdumptoc.h" +#include "verbildump.h" +#include "verbtoc.h" +#include "verbremovedup.h" +#include "verbstat.h" +#include "verbconcat.h" +#include "verbmerge.h" +#include "verbstrip.h" +#include "verbsmarty.h" +#include "logging.h" + +int __cdecl main(int argc, char* argv[]) +{ +#ifdef FEATURE_PAL + if (0 != PAL_Initialize(argc, argv)) + { + fprintf(stderr, "Error: Fail to PAL_Initialize\n"); + exit(1); + } +#endif // FEATURE_PAL + + Logger::Initialize(); + + CommandLine::Options o; + if(!CommandLine::Parse(argc, argv, &o)) + { + return -1; + } + + //execute the chosen command. + int exitCode = 0; + if (o.actionASMDump) + { + exitCode = verbASMDump::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes); + } + if (o.actionConcat) + { + exitCode = verbConcat::DoWork(o.nameOfFile1, o.nameOfFile2); + } + if (o.actionMerge) + { + exitCode = verbMerge::DoWork(o.nameOfFile1, o.nameOfFile2, o.recursive); + } + if (o.actionCopy) + { + exitCode = verbStrip::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes, false, o.stripCR); + } + if (o.actionDump) + { + exitCode = verbDump::DoWork(o.nameOfFile1, o.indexCount, o.indexes); + } + if (o.actionFracture) + { + exitCode = verbFracture::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes, o.stripCR); + } + if (o.actionDumpMap) + { + exitCode = verbDumpMap::DoWork(o.nameOfFile1); + } + if (o.actionDumpToc) + { + exitCode = verbDumpToc::DoWork(o.nameOfFile1); + } + if (o.actionILDump) + { + exitCode = verbILDump::DoWork(o.nameOfFile1, o.indexCount, o.indexes); + } + if (o.actionInteg) + { + exitCode = verbInteg::DoWork(o.nameOfFile1); + } + if (o.actionRemoveDup) + { + exitCode = verbRemoveDup::DoWork(o.nameOfFile1, o.nameOfFile2, o.stripCR, o.legacyCompare); + } + if (o.actionStat) + { + exitCode = verbStat::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes); + } + if (o.actionStrip) + { + exitCode = verbStrip::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes, true, o.stripCR); + } + if (o.actionTOC) + { + exitCode = verbTOC::DoWork(o.nameOfFile1); + } + if (o.actionSmarty) + { + exitCode = verbSmarty::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes); + } + + Logger::Shutdown(); + return exitCode; +} diff --git a/src/ToolBox/superpmi/mcs/mcs.h b/src/ToolBox/superpmi/mcs/mcs.h new file mode 100644 index 0000000000..3eb19502db --- /dev/null +++ b/src/ToolBox/superpmi/mcs/mcs.h @@ -0,0 +1,9 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _MCS +#define _MCS + +#endif diff --git a/src/ToolBox/superpmi/mcs/verbasmdump.cpp b/src/ToolBox/superpmi/mcs/verbasmdump.cpp new file mode 100644 index 0000000000..3f018b3a45 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbasmdump.cpp @@ -0,0 +1,68 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbasmdump.h" +#include "simpletimer.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" +#include "asmdumper.h" +#include "errorhandling.h" + +#define BUFFER_SIZE 0xFFFFFF + +int verbASMDump::DoWork(const char *nameOfInput, const char *nameOfOutput, int indexCount, const int *indexes) +{ + LogVerbose("Loading from '%s' and writing ASM output into '%s-MC#.asm'", nameOfInput, nameOfOutput); + + MethodContextIterator mci(indexCount, indexes, true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + + char buff[500]; + sprintf_s(buff, 500, "%s-%d.asm", nameOfOutput, mci.MethodContextNumber()); + + HANDLE hFileOut = CreateFileA(buff, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open output '%s'. GetLastError()=%u", buff, GetLastError()); + return -1; + } + + if (mc->cr->IsEmpty()) + { + const size_t bufflen = 4096; + DWORD bytesWritten; + char buff[bufflen]; + ZeroMemory(buff, bufflen * sizeof(char)); + int buff_offset = sprintf_s(buff, bufflen, ";;Method context has no compile result"); + WriteFile(hFileOut, buff, buff_offset * sizeof(char), &bytesWritten, nullptr); + } + else + { + ASMDumper::DumpToFile(hFileOut, mc, mc->cr); + } + + if (!CloseHandle(hFileOut)) + { + LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + savedCount++; + } + + LogInfo("Asm'd %d", savedCount); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbasmdump.h b/src/ToolBox/superpmi/mcs/verbasmdump.h new file mode 100644 index 0000000000..693366ef91 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbasmdump.h @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbASMDump.h - verb that +//---------------------------------------------------------- +#ifndef _verbASMDump +#define _verbASMDump + +class verbASMDump +{ +public: + static int DoWork(const char *nameOfInput1, const char *nameOfOutput, int indexCount, const int *indexes); +}; +#endif + + diff --git a/src/ToolBox/superpmi/mcs/verbconcat.cpp b/src/ToolBox/superpmi/mcs/verbconcat.cpp new file mode 100644 index 0000000000..36620f11b2 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbconcat.cpp @@ -0,0 +1,99 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbconcat.h" +#include "simpletimer.h" +#include "logging.h" + +#define BUFFER_SIZE 0xFFFFFF + +int verbConcat::DoWork(const char *nameOfFile1, const char *nameOfFile2) +{ + SimpleTimer st1; + + LogVerbose("Concatenating '%s'+'%s' into %s", nameOfFile1, nameOfFile2, nameOfFile1); + + LARGE_INTEGER DataTemp1; + LARGE_INTEGER DataTemp2; + + HANDLE hFileIn1 = CreateFileA(nameOfFile1, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(hFileIn1 == INVALID_HANDLE_VALUE) + { + LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfFile1, GetLastError()); + return -1; + } + if(GetFileSizeEx(hFileIn1, &DataTemp1)==0) + { + LogError("GetFileSizeEx failed. GetLastError()=%u", GetLastError()); + return -1; + } + + LONG highDWORD = 0; + DWORD dwPtr = SetFilePointer(hFileIn1, 0, &highDWORD, FILE_END); + if (dwPtr == INVALID_SET_FILE_POINTER) + { + LogError("Failed to SetFilePointer on input 1 '%s'. GetLastError()=%u", nameOfFile1, GetLastError()); + return -1; + } + + HANDLE hFileIn2 = CreateFileA(nameOfFile2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(hFileIn2 == INVALID_HANDLE_VALUE) + { + LogError("Failed to open input 2 '%s'. GetLastError()=%u", nameOfFile2, GetLastError()); + return -1; + } + if(GetFileSizeEx(hFileIn2, &DataTemp2)==0) + { + LogError("2nd GetFileSizeEx failed. GetLastError()=%u", GetLastError()); + return -1; + } + + unsigned char* buffer = new unsigned char[BUFFER_SIZE]; + + st1.Start(); + for(LONGLONG offset = 0; offset < DataTemp2.QuadPart; offset += BUFFER_SIZE) + { + DWORD bytesRead = -1; + BOOL res = ReadFile(hFileIn2, buffer, BUFFER_SIZE, &bytesRead, nullptr); + if(res == 0) + { + LogError("Failed to read '%s' from offset %lld. GetLastError()=%u", nameOfFile2, offset, GetLastError()); + return -1; + } + DWORD bytesWritten = -1; + BOOL res2 = WriteFile(hFileIn1, buffer, bytesRead, &bytesWritten, nullptr); + if(res2 == 0) + { + LogError("Failed to write '%s' at offset %lld. GetLastError()=%u", nameOfFile1, offset, GetLastError()); + return -1; + } + if(bytesRead!=bytesWritten) + { + LogError("Failed to read/write matching bytes %u!=%u", bytesRead, bytesWritten); + return -1; + } + } + st1.Stop(); + + delete[] buffer; + + if(CloseHandle(hFileIn1)==0) + { + LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + if(CloseHandle(hFileIn2)==0) + { + LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + + LogInfo("Read/Wrote %lld MB @ %4.2f MB/s.\n", + DataTemp2.QuadPart/(1000*1000), + (((double)DataTemp2.QuadPart)/(1000*1000))/st1.GetSeconds()); //yes yes.. http://en.wikipedia.org/wiki/Megabyte_per_second#Megabyte_per_second + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbconcat.h b/src/ToolBox/superpmi/mcs/verbconcat.h new file mode 100644 index 0000000000..26e55857bd --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbconcat.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbConcat.h - verb that concatenates two files +//---------------------------------------------------------- +#ifndef _verbConcat +#define _verbConcat + +class verbConcat +{ +public: + static int DoWork(const char *nameOfFile1, const char *nameOfFile2); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbdump.cpp b/src/ToolBox/superpmi/mcs/verbdump.cpp new file mode 100644 index 0000000000..290cbdbac5 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbdump.cpp @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbdump.h" +#include "logging.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" +#include "errorhandling.h" + +int verbDump::DoWork(const char *nameOfInput, int indexCount, const int *indexes) +{ + LogVerbose("Dumping '%s' to console", nameOfInput); + + MethodContextIterator mci(indexCount, indexes); + if (!mci.Initialize(nameOfInput)) + return -1; + + int dumpedCount = 0; + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + mc->dumpToConsole(mci.MethodContextNumber()); + dumpedCount++; + } + + LogVerbose("Dumped %d methodContexts", dumpedCount); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbdump.h b/src/ToolBox/superpmi/mcs/verbdump.h new file mode 100644 index 0000000000..32f4b0d661 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbdump.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbDump.h - verb that Dumps a MC file +//---------------------------------------------------------- +#ifndef _verbDump +#define _verbDump + +class verbDump +{ +public: + static int DoWork(const char *nameofInput, int indexCount, const int *indexes); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbdumpmap.cpp b/src/ToolBox/superpmi/mcs/verbdumpmap.cpp new file mode 100644 index 0000000000..3fc8268f5f --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbdumpmap.cpp @@ -0,0 +1,64 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "simpletimer.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" +#include "verbdumpmap.h" +#include "verbildump.h" + +// Dump the CSV format header for all the columns we're going to dump. +void DumpMapHeader() +{ + printf("index,"); + // printf("process name,"); + printf("method name,"); + printf("full signature\n"); +} + +void DumpMap(int index, MethodContext *mc) +{ + CORINFO_METHOD_INFO cmi; + unsigned int flags = 0; + + mc->repCompileMethod(&cmi, &flags); + + const char *moduleName = nullptr; + const char *methodName = mc->repGetMethodName(cmi.ftn, &moduleName); + const char *className = mc->repGetClassName(mc->repGetMethodClass(cmi.ftn)); + + printf("%d,", index); + // printf("\"%s\",", mc->cr->repProcessName()); + printf("%s:%s,", className, methodName); + + // Also, dump the full method signature + printf("\""); + DumpAttributeToConsoleBare(mc->repGetMethodAttribs(cmi.ftn)); + DumpPrimToConsoleBare(mc, cmi.args.retType, (DWORDLONG)cmi.args.retTypeClass); + printf(" %s(", methodName); + DumpSigToConsoleBare(mc, &cmi.args); + printf(")\"\n"); +} + +int verbDumpMap::DoWork(const char *nameOfInput) +{ + MethodContextIterator mci; + if (!mci.Initialize(nameOfInput)) + return -1; + + DumpMapHeader(); + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + DumpMap(mci.MethodContextNumber(), mc); + } + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbdumpmap.h b/src/ToolBox/superpmi/mcs/verbdumpmap.h new file mode 100644 index 0000000000..129b8d8440 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbdumpmap.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbDumpMap.h - verb that dumps a map of index to function name for an MC file +//---------------------------------------------------------- +#ifndef _verbDumpMap +#define _verbDumpMap + +class verbDumpMap +{ +public: + static int DoWork(const char *nameofInput); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbdumptoc.cpp b/src/ToolBox/superpmi/mcs/verbdumptoc.cpp new file mode 100644 index 0000000000..2837f0bf3e --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbdumptoc.cpp @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbdumptoc.h" +#include "methodcontext.h" +#include "tocfile.h" +#include "runtimedetails.h" + +int verbDumpToc::DoWork(const char *nameOfInput) +{ + TOCFile tf; + + tf.LoadToc(nameOfInput, false); + + for (size_t i = 0; i < tf.GetTocCount(); i++) + { + const TOCElement* te = tf.GetElementPtr(i); + printf("%4u: %016llX ", te->Number, te->Offset); + + for (int j = 0; j < sizeof(te->Hash); j++) + { + printf("%02x ", te->Hash[j]); + } + + printf("\n"); + } + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbdumptoc.h b/src/ToolBox/superpmi/mcs/verbdumptoc.h new file mode 100644 index 0000000000..c2ea880b52 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbdumptoc.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbDumpToc.h - verb that dumps a MCH Table of Context file +//---------------------------------------------------------- +#ifndef _verbDumpToc +#define _verbDumpToc + +class verbDumpToc +{ +public: + static int DoWork(const char *nameOfInput1); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbfracture.cpp b/src/ToolBox/superpmi/mcs/verbfracture.cpp new file mode 100644 index 0000000000..bcc6d04e1d --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbfracture.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbfracture.h" +#include "simpletimer.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" +#include "errorhandling.h" +#include "logging.h" + +int verbFracture::DoWork(const char *nameOfInput, const char *nameOfOutput, int indexCount, const int *indexes, bool stripCR) +{ + int rangeSize = indexes[0]; + + LogVerbose("Reading from '%s' copying %d MethodContexts files into each output file of '%s'", nameOfInput, rangeSize, nameOfOutput); + + MethodContextIterator mci(true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int fileCount = 0; + char fileName[512]; + + HANDLE hFileOut = INVALID_HANDLE_VALUE; + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + + if ((hFileOut == INVALID_HANDLE_VALUE) || (((mci.MethodContextNumber() - 1) % rangeSize) == 0)) + { + if (hFileOut != INVALID_HANDLE_VALUE) + { + if (!CloseHandle(hFileOut)) + { + LogError("1st CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + hFileOut = INVALID_HANDLE_VALUE; + } + sprintf_s(fileName, 512, "%s-%0*d.mch", nameOfOutput, 5, fileCount++); + hFileOut = CreateFileA(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open output file '%s'. GetLastError()=%u", fileName, GetLastError()); + return -1; + } + } + if (stripCR) + { + delete mc->cr; + mc->cr = new CompileResult(); + } + mc->saveToFile(hFileOut); + } + + if (hFileOut != INVALID_HANDLE_VALUE) + { + if (!CloseHandle(hFileOut)) + { + LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + } + + LogInfo("Output fileCount %d", fileCount); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbfracture.h b/src/ToolBox/superpmi/mcs/verbfracture.h new file mode 100644 index 0000000000..feddbe1908 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbfracture.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbFracture.h - verb that copies N items into each child file. +//---------------------------------------------------------- +#ifndef _verbFracture +#define _verbFracture + +class verbFracture +{ +public: + static int DoWork(const char *nameOfInput1, const char *nameOfOutput, int indexCount, const int *indexes, bool stripCR); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbildump.cpp b/src/ToolBox/superpmi/mcs/verbildump.cpp new file mode 100644 index 0000000000..23b68da003 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbildump.cpp @@ -0,0 +1,625 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "simpletimer.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" +#include "verbildump.h" + +void DumpPrimToConsoleBare(MethodContext *mc, CorInfoType prim, DWORDLONG classHandle) +{ + switch(prim) + { + case CORINFO_TYPE_VOID: printf("void"); return; + case CORINFO_TYPE_BOOL: printf("bool"); return; + case CORINFO_TYPE_CHAR: printf("char"); return; + case CORINFO_TYPE_BYTE: printf("int8"); return; + case CORINFO_TYPE_UBYTE: printf("unsigned int8"); return; + case CORINFO_TYPE_SHORT: printf("int16"); return; + case CORINFO_TYPE_USHORT: printf("unsigned int16"); return; + case CORINFO_TYPE_INT: printf("int32"); return; + case CORINFO_TYPE_UINT: printf("unsigned int32"); return; + case CORINFO_TYPE_LONG: printf("int64"); return; + case CORINFO_TYPE_ULONG: printf("unsigned int64"); return; + case CORINFO_TYPE_NATIVEINT: printf("native int"); return; + case CORINFO_TYPE_NATIVEUINT: printf("native unsigned int"); return; + case CORINFO_TYPE_FLOAT: printf("float32"); return; + case CORINFO_TYPE_DOUBLE: printf("float64"); return; +// case CORINFO_TYPE_STRING: printf("string"); return; + case CORINFO_TYPE_PTR: printf("ptr"); return; + case CORINFO_TYPE_BYREF: printf("byref"); return; + case CORINFO_TYPE_VALUECLASS: printf("valueclass %s", mc->repGetClassName((CORINFO_CLASS_HANDLE)classHandle)); return; + case CORINFO_TYPE_CLASS: printf("class %s", mc->repGetClassName((CORINFO_CLASS_HANDLE)classHandle)); return; + case CORINFO_TYPE_REFANY: printf("refany"); return; + case CORINFO_TYPE_VAR: printf("var"); return; + default: + LogWarning("unknown type in PrimToString(0x%x)",prim); + __debugbreak(); + return; + } +} +void DumpSigToConsoleBare(MethodContext *mc, CORINFO_SIG_INFO *pSig) +{ + CORINFO_ARG_LIST_HANDLE currentItem = pSig->args; + DWORD exceptionCode; + + for(int i=0; i < (int)pSig->numArgs; i++) + { + DWORDLONG dl; + CorInfoTypeWithMod type = mc->repGetArgType(pSig, currentItem, (CORINFO_CLASS_HANDLE *)&dl, &exceptionCode); + CorInfoType cit = strip(type); + if (cit == CORINFO_TYPE_CLASS) + dl = (DWORDLONG)mc->repGetArgClass(pSig, currentItem, &exceptionCode); + if ((type & CORINFO_TYPE_MOD_PINNED) == CORINFO_TYPE_MOD_PINNED) + printf("pinned "); + DumpPrimToConsoleBare(mc, cit, dl); + currentItem = mc->repGetArgNext(currentItem); + if (i + 1 < (int)pSig->numArgs) + printf(", "); + } +} + + +void DumpILToConsoleBare(unsigned char *ilCode, int len) +{ + int i,j,k; + for(i=0;i<len;i++) + { + printf("IL_%04x: ",i); + switch(ilCode[i]) + { + case 0x00:printf("nop");continue; + case 0x01:printf("break");continue; + case 0x02:printf("ldarg.0");continue; + case 0x03:printf("ldarg.1");continue; + case 0x04:printf("ldarg.2");continue; + case 0x05:printf("ldarg.3");continue; + case 0x06:printf("ldloc.0");continue; + case 0x07:printf("ldloc.1");continue; + case 0x08:printf("ldloc.2");continue; + case 0x09:printf("ldloc.3");continue; + case 0x0a:printf("stloc.0");continue; + case 0x0b:printf("stloc.1");continue; + case 0x0c:printf("stloc.2");continue; + case 0x0d:printf("stloc.3");continue; + case 0x0e: //ldarg.s X + printf("ldarg.s 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0x0f: //ldarga.s X + printf("ldarga.s 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0x10: //starg.s X + printf("starg.s 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0x11: //ldloc.s X + printf("ldloc.s 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0x12: //ldloca.s X + printf("ldloca.s 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0x13: //stloc.s X + printf("stloc.s 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0x14:printf("ldnull");continue; + case 0x15:printf("ldc.i4.m1");continue; + case 0x16:printf("ldc.i4.0");continue; + case 0x17:printf("ldc.i4.1");continue; + case 0x18:printf("ldc.i4.2");continue; + case 0x19:printf("ldc.i4.3");continue; + case 0x1a:printf("ldc.i4.4");continue; + case 0x1b:printf("ldc.i4.5");continue; + case 0x1c:printf("ldc.i4.6");continue; + case 0x1d:printf("ldc.i4.7");continue; + case 0x1e:printf("ldc.i4.8");continue; + case 0x1f: //ldc.i4.s X + printf("ldc.i4.s 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0x20: //ldc.i4 XXXX + printf("ldc.i4 0x%02x%02x%02x%02x", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x21: //ldc.i8 XXXXXXXX + printf("ldc.i8 0x%02x%02x%02x%02x%02x%02x%02x%02x", ilCode[i+8], ilCode[i+7], ilCode[i+6], ilCode[i+5], ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=8; + continue; + case 0x22: //ldc.r4 XXXX + printf("ldc.r4 float32(0x%02x%02x%02x%02x)", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x23: //ldc.r8 XXXXXXXX + printf("ldc.r8 float64(0x%02x%02x%02x%02x%02x%02x%02x%02x)", ilCode[i+8], ilCode[i+7], ilCode[i+6], ilCode[i+5], ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=8; + continue; + case 0x25:printf("dup");continue; + case 0x26:printf("pop");continue; + case 0x27: //JMP <T> + printf("jmp <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x28: //call <T> + printf("call <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x29: //calli <T> + printf("calli <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x2a:printf("ret");continue; + case 0x2b: //br.s X + printf("br.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x2c: //brfalse.s X + printf("brfalse.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x2d: //brtrue.s X + printf("brtrue.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x2e: //beq.s X + printf("beq.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x2f: //bgt.s X + printf("bgt.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x30: //bgt.s X + printf("bgt.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x31: //ble.s X + printf("ble.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x32: //blt.s X + printf("blt.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x33: //bne.un.s X + printf("bne.un.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x34: //bge.un.s X + printf("bge.un.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x35: //bgt.un.s X + printf("bgt.un.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x36: //ble.un.s X + printf("ble.un.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x37: //blt.un.s X + printf("blt.un.s IL_%04x", i+2+ilCode[i+1]);; + i+=1; + continue; + case 0x38: //br XXXX + printf("br IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x39: //brfalse XXXX + printf("brfalse IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x3a: //brtrue XXXX + printf("brtrue IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x3b: //beq XXXX + printf("beq IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x3c: //bgt XXXX + printf("bgt IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x3d: //bgt XXXX + printf("bgt IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x3e: //ble XXXX + printf("ble IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x3f: //blt XXXX + printf("blt IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x40: //bne.un XXXX + printf("bne.un IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x41: //bge.un XXXX + printf("bge.un IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x42: //bgt.un XXXX + printf("bgt.un IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x43: //ble.un XXXX + printf("ble.un IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x44: //blt.un XXXX + printf("blt.un IL_%04x", i+5+(ilCode[i+4]<<24|ilCode[i+3]<<16|ilCode[i+2]<<8|ilCode[i+1])); + i+=4; + continue; + case 0x45: //switch NNNN NNNN*XXXX + printf("switch (0x%02x%02x%02x%02x)", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + k = (ilCode[i+4]<<24)|(ilCode[i+3]<<16)|(ilCode[i+2]<<8)|(ilCode[i+1]<<0); + i+=4; + for(j=0;j<k;j++) + { + printf(" <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + } + continue; + case 0x46:printf("ldind.i1");continue; + case 0x47:printf("ldind.u1");continue; + case 0x48:printf("ldind.i2");continue; + case 0x49:printf("ldind.u2");continue; + case 0x4a:printf("ldind.i4");continue; + case 0x4b:printf("ldind.u4");continue; + case 0x4c:printf("ldind.i8");continue; + case 0x4d:printf("ldind.u8");continue; + case 0x4e:printf("ldind.r4");continue; + case 0x4f:printf("ldind.r8");continue; + case 0x50:printf("ldind.ref");continue; + case 0x51:printf("stind.ref");continue; + case 0x52:printf("stind.i1");continue; + case 0x53:printf("stind.i2");continue; + case 0x54:printf("stind.i4");continue; + case 0x55:printf("stind.i8");continue; + case 0x56:printf("stind.r4");continue; + case 0x57:printf("stind.r8");continue; + case 0x58:printf("add");continue; + case 0x59:printf("sub");continue; + case 0x5a:printf("mul");continue; + case 0x5b:printf("div");continue; + case 0x5c:printf("div.un");continue; + case 0x5d:printf("rem");continue; + case 0x5e:printf("rem.un");continue; + case 0x5f:printf("and");continue; + case 0x60:printf("or");continue; + case 0x61:printf("xor");continue; + case 0x62:printf("shl");continue; + case 0x63:printf("shr");continue; + case 0x64:printf("shr.un");continue; + case 0x65:printf("neg");continue; + case 0x66:printf("not");continue; + case 0x67:printf("conv.i1");continue; + case 0x68:printf("conv.i2");continue; + case 0x69:printf("conv.i4");continue; + case 0x6a:printf("conv.i8");continue; + case 0x6b:printf("conv.r4");continue; + case 0x6c:printf("conv.r8");continue; + case 0x6d:printf("conv.u4");continue; + case 0x6e:printf("conv.u8");continue; + case 0x6f: //callvirt <T> + printf("callvirt <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x70: //cpobj <T> + printf("cpobj <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x71: //ldobj <T> + printf("ldobj <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x72: //ldstr <T> + printf("ldstr <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x73: //newobj <T> + printf("newobj <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x74: //castclass <T> + printf("castclass <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x75: //isinst <T> + printf("isinst <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x76:printf("conv.r.un");continue; + case 0x79: //unbox <T> + printf("unbox <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x7a:printf("throw");continue; + case 0x7b: //ldfld <T> + printf("ldfld <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x7c: //ldflda <T> + printf("ldflda <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x7d: //stfld <T> + printf("stfld <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x7e: //ldsfld <T> + printf("ldsfld <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x7f: //ldsflda <T> + printf("ldsflda <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x80: //stsfld <T> + printf("stsfld <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x81: //stobj <T> + printf("stobj <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x82:printf("conv.ovf.i1.un");continue; + case 0x83:printf("conv.ovf.i2.un");continue; + case 0x84:printf("conv.ovf.i4.un");continue; + case 0x85:printf("conv.ovf.i8.un");continue; + case 0x86:printf("conv.ovf.u1.un");continue; + case 0x87:printf("conv.ovf.u2.un");continue; + case 0x88:printf("conv.ovf.u4.un");continue; + case 0x89:printf("conv.ovf.u8.un");continue; + case 0x8a:printf("conv.ovf.i.un");continue; + case 0x8b:printf("conv.ovf.u.un");continue; + case 0x8c: //box <T> + printf("box <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x8d: //newarr <T> + printf("newarr <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x8e:printf("ldlen");continue; + case 0x8f:printf("ldelema <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x90:printf("ldelem.i1");continue; + case 0x91:printf("ldelem.u1");continue; + case 0x92:printf("ldelem.i2");continue; + case 0x93:printf("ldelem.u2");continue; + case 0x94:printf("ldelem.i4");continue; + case 0x95:printf("ldelem.u4");continue; + case 0x96:printf("ldelem.i8");continue; + case 0x97:printf("ldelem.i");continue; + case 0x98:printf("ldelem.r4");continue; + case 0x99:printf("ldelem.r8");continue; + case 0x9a:printf("ldelem.ref");continue; + case 0x9b:printf("stelem.i");continue; + case 0x9c:printf("stelem.i1");continue; + case 0x9d:printf("stelem.i2");continue; + case 0x9e:printf("stelem.i4");continue; + case 0x9f:printf("stelem.i8");continue; + case 0xa0:printf("stelem.r4");continue; + case 0xa1:printf("stelem.r8");continue; + case 0xa2:printf("stelem.ref");continue; + case 0xa3:printf("stelem <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0xa4:printf("stelem <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0xa5:printf("unbox.any <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0xb3:printf("conv.ovf.i1");continue; + case 0xb4:printf("conv.ovf.u1");continue; + case 0xb5:printf("conv.ovf.i2");continue; + case 0xb6:printf("conv.ovf.u2");continue; + case 0xb7:printf("conv.ovf.i4");continue; + case 0xb8:printf("conv.ovf.u4");continue; + case 0xb9:printf("conv.ovf.i8");continue; + case 0xba:printf("conv.ovf.u8");continue; + case 0xc2: //refanyval <T> + printf("refanyval <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0xc3:printf("ckfinite");continue; + case 0xc6: //mkrefany <T> + printf("mkrefany <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0xd0: //ldtoken <T> + printf("ldtoken <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0xd1:printf("conv.u2");continue; + case 0xd2:printf("conv.u1");continue; + case 0xd3:printf("conv.i");continue; + case 0xd4:printf("conv.ovf.i");continue; + case 0xd5:printf("conv.ovf.u");continue; + case 0xd6:printf("add.ovf");continue; + case 0xd7:printf("add.ovf.un");continue; + case 0xd8:printf("mul.ovf");continue; + case 0xd9:printf("mul.ovf.un");continue; + case 0xda:printf("sub.ovf");continue; + case 0xdb:printf("sub.ovf.un");continue; + case 0xdc:printf("endfinally");continue; + case 0xdd: //leave XXXX + printf("leave 0x%02x%02x%02x%02x", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0xde: //leave.s X + printf("leave 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0xdf:printf("stind.i");continue; + case 0xe0:printf("conv.u");continue; + case 0xfe: + i++; + switch(ilCode[i]) + { + case 0x00:printf("arglist");continue; + case 0x01:printf("ceq");continue; + case 0x02:printf("cgt");continue; + case 0x03:printf("cgt.un");continue; + case 0x04:printf("clt");continue; + case 0x05:printf("clt.un");continue; + case 0x06: //ldftn <T> + printf("ldftn <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x07: //ldvirtftn <T> + printf("ldvirtftn <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x09: //ldarg XX + printf("ldarg 0x%02x%02x", ilCode[i+2], ilCode[i+1]); + i+=2; + continue; + case 0x0a: //ldarga XX + printf("ldarga 0x%02x%02x", ilCode[i+2], ilCode[i+1]); + i+=2; + continue; + case 0x0b: //starg XX + printf("starg 0x%02x%02x", ilCode[i+2], ilCode[i+1]); + i+=2; + continue; + case 0x0c: //ldloc XX + printf("ldloc 0x%02x%02x", ilCode[i+2], ilCode[i+1]); + i+=2; + continue; + case 0x0d: //ldloca XX + printf("ldloca 0x%02x%02x", ilCode[i+2], ilCode[i+1]); + i+=2; + continue; + case 0x0e: //stloc XX + printf("stloc 0x%02x%02x", ilCode[i+2], ilCode[i+1]); + i+=2; + continue; + case 0x0f:printf("localloc");continue; + case 0x11:printf("endfilter");continue; + case 0x12: //unaligned X + printf("unaligned. 0x%02x", ilCode[i+1]); + i+=1; + continue; + case 0x13:printf("volatile.");continue; + case 0x14:printf("tail.");continue; + case 0x15: //initobj <T> + printf("initobj <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x16://incomplete? + printf("constrained. <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x17:printf("cpblk");continue; + case 0x18:printf("initblk");continue; + case 0x19:printf("no.");continue; //incomplete? + case 0x1a:printf("rethrow");continue; + case 0x1c: //sizeof <T> + printf("sizeof <0x%02x%02x%02x%02x>", ilCode[i+4], ilCode[i+3], ilCode[i+2], ilCode[i+1]); + i+=4; + continue; + case 0x1d:printf("refanytype");continue; + default: + LogError("unknown ilCode 0xfe%2x at offset %d in MethodGen::PrettyPrint", ilCode[i], i); + break; + } + default: + LogError("unknown ilCode 0x%02x at offset %d in MethodGen::PrettyPrint", ilCode[i], i); + break; + } + printf("\n"); + } +} +char * DumpAttributeToConsoleBare(DWORD attribute) +{ + const char *s_static = "static"; + const char *s_dontInline = "$dontInline "; + const char *s_constructor = "$constructor"; + const char *s_cfnw = "$noSecurityWrap"; + +#define ifPrint(s,t) else if((s&attribute)==s) {printf(t); printf(" ");} + + if(0); + ifPrint(CORINFO_FLG_STATIC, s_static) + ifPrint(CORINFO_FLG_DONT_INLINE, s_dontInline) + ifPrint(CORINFO_FLG_CONSTRUCTOR, s_constructor) + ifPrint(CORINFO_FLG_NOSECURITYWRAP, s_cfnw) + else + { + LogError("unknown attribute %x", attribute); + __debugbreak(); + } + return nullptr; + +#undef ifPrint +} + +void DumpIL(MethodContext *mc) +{ + CORINFO_METHOD_INFO cmi; + unsigned int flags = 0; + + mc->repCompileMethod(&cmi, &flags); + + const char *moduleName = nullptr; + const char *methodName = mc->repGetMethodName(cmi.ftn, &moduleName); + const char *className = mc->repGetClassName(mc->repGetMethodClass(cmi.ftn)); + + printf("// ProcessName - '%s'\n", mc->cr->repProcessName()); + printf(".assembly extern mscorlib{}\n"); + printf(".assembly %s{}\n", moduleName); + printf(".class %s\n", className); + printf("{\n"); + printf(" .method "); + DumpAttributeToConsoleBare(mc->repGetMethodAttribs(cmi.ftn)); + DumpPrimToConsoleBare(mc, cmi.args.retType, (DWORDLONG)cmi.args.retTypeClass); + printf(" %s(", methodName); + DumpSigToConsoleBare(mc, &cmi.args); + printf(")\n"); + printf(" {\n"); + printf(" .maxstack %u\n", cmi.maxStack); + printf(" .locals%s(", (((cmi.options&CORINFO_OPT_INIT_LOCALS)==CORINFO_OPT_INIT_LOCALS)?" init ":" ")); + DumpSigToConsoleBare(mc, &cmi.locals); + printf(")\n"); + DumpILToConsoleBare(cmi.ILCode, cmi.ILCodeSize); + printf(" }\n"); + printf("}\n"); +} + +int verbILDump::DoWork(const char *nameOfInput, int indexCount, const int *indexes) +{ + LogVerbose("// Reading from '%s' dumping raw IL for MC Indexes to console", nameOfInput); + + MethodContextIterator mci(indexCount, indexes); + if (!mci.Initialize(nameOfInput)) + return -1; + + int dumpedCount = 0; + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + DumpIL(mc); + dumpedCount++; + } + + LogInfo("// Dumped %d", dumpedCount); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbildump.h b/src/ToolBox/superpmi/mcs/verbildump.h new file mode 100644 index 0000000000..e947fcf40c --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbildump.h @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbILDump.h - verb that attempts to dump the raw IL for a MC +//---------------------------------------------------------- +#ifndef _verbILDump +#define _verbILDump + +#include "methodcontext.h" + +class verbILDump +{ +public: + static int DoWork(const char *nameOfInput1, int indexCount, const int *indexes); +}; + +void DumpPrimToConsoleBare(MethodContext *mc, CorInfoType prim, DWORDLONG classHandle); +void DumpSigToConsoleBare(MethodContext *mc, CORINFO_SIG_INFO *pSig); +char * DumpAttributeToConsoleBare(DWORD attribute); + +#endif diff --git a/src/ToolBox/superpmi/mcs/verbinteg.cpp b/src/ToolBox/superpmi/mcs/verbinteg.cpp new file mode 100644 index 0000000000..9b1057769a --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbinteg.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbinteg.h" +#include "simpletimer.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" + +int verbInteg::DoWork(const char *nameOfInput) +{ + LogVerbose("Checking the integrity of '%s'", nameOfInput); + + SimpleTimer st2; + st2.Start(); + + MethodContextIterator mci(true); + if (!mci.Initialize(nameOfInput)) + return -1; + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + // Nothing to do except load the current one. + } + + st2.Stop(); + LogInfo("Checked the integrity of %d methodContexts at %d per second", + mci.MethodContextNumber(), (int)((double)mci.MethodContextNumber() / st2.GetSeconds())); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbinteg.h b/src/ToolBox/superpmi/mcs/verbinteg.h new file mode 100644 index 0000000000..d45ea15307 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbinteg.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbInteg.h - verb that checks the integrity of a MC file +//---------------------------------------------------------- +#ifndef _verbInteg +#define _verbInteg + +class verbInteg +{ +public: + static int DoWork(const char *nameofInput); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbmerge.cpp b/src/ToolBox/superpmi/mcs/verbmerge.cpp new file mode 100644 index 0000000000..c4acfd8769 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbmerge.cpp @@ -0,0 +1,470 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbmerge.h" +#include "simpletimer.h" +#include "logging.h" + +// Do reads/writes in large 256MB chunks. +#define BUFFER_SIZE 0x10000000 + +// MergePathStrings: take two file system path components, compose them together, and return the merged pathname string. +// The caller must delete the returned string with delete[]. +// +// static +char* verbMerge::MergePathStrings(const char* dir, const char* file) +{ + size_t dirlen = strlen(dir); + size_t filelen = strlen(file); + size_t newlen = dirlen + 1 /* slash */ + filelen + 1 /* null */; + char* newpath = new char[newlen]; + strcpy(newpath, dir); + strcat(newpath, DIRECTORY_SEPARATOR_STR_A); + strcat(newpath, file); + return newpath; +} + +// AppendFile: append the file named by 'fileName' to the output file referred to by 'hFileOut'. The 'hFileOut' +// handle is assumed to be open, and the file position is assumed to be at the correct spot for writing, to append. +// +// 'buffer' is memory that can be used to do reading/buffering. +// +// static +int verbMerge::AppendFile(HANDLE hFileOut, const char* fileName, unsigned char* buffer, size_t bufferSize) +{ + int result = 0; // default to zero == success + + LogInfo("Appending file '%s'", fileName); + + HANDLE hFileIn = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFileIn == INVALID_HANDLE_VALUE) + { + LogError("Failed to open input file '%s'. GetLastError()=%u", fileName, GetLastError()); + return -1; + } + + LARGE_INTEGER fileSize; + if (GetFileSizeEx(hFileIn, &fileSize) == 0) + { + LogError("GetFileSizeEx on '%s' failed. GetLastError()=%u", fileName, GetLastError()); + result = -1; + goto CLEAN_UP; + } + + for (LONGLONG offset = 0; offset < fileSize.QuadPart; offset += bufferSize) + { + DWORD bytesRead = -1; + BOOL res = ReadFile(hFileIn, buffer, (DWORD)bufferSize, &bytesRead, nullptr); + if (!res) + { + LogError("Failed to read '%s' from offset %lld. GetLastError()=%u", fileName, offset, GetLastError()); + result = -1; + goto CLEAN_UP; + } + DWORD bytesWritten = -1; + BOOL res2 = WriteFile(hFileOut, buffer, bytesRead, &bytesWritten, nullptr); + if (!res2) + { + LogError("Failed to write output file at offset %lld. GetLastError()=%u", offset, GetLastError()); + result = -1; + goto CLEAN_UP; + } + if (bytesRead != bytesWritten) + { + LogError("Failed to read/write matching bytes %u!=%u", bytesRead, bytesWritten); + result = -1; + goto CLEAN_UP; + } + } + +CLEAN_UP: + + if (CloseHandle(hFileIn) == 0) + { + LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); + result = -1; + } + + return result; +} + +// Return true if this is a directory +// +// static +bool verbMerge::DirectoryFilterDirectories(WIN32_FIND_DATAA* findData) +{ + if ((findData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + // It's a directory. See if we want to exclude it because of other reasons, such as: + // 1. reparse points: avoid the possibility of loops + // 2. system directories + // 3. hidden directories + // 4. "." or ".." + +#ifndef FEATURE_PAL // FILE_ATTRIBUTE_REPARSE_POINT is not defined in the PAL + if ((findData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) + return false; +#endif // !FEATURE_PAL + if ((findData->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) != 0) + return false; + if ((findData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0) + return false; + + if (strcmp(findData->cFileName, ".") == 0) + return false; + if (strcmp(findData->cFileName, "..") == 0) + return false; + + return true; + } + + return false; +} + +// Return true if this is a file. +// +// static +bool verbMerge::DirectoryFilterFile(WIN32_FIND_DATAA* findData) +{ + if ((findData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) + { + // This is not a directory, so it must be a file. + return true; + } + + return false; +} + +// static +int __cdecl verbMerge::WIN32_FIND_DATAA_qsort_helper(const void* p1, const void* p2) +{ + const WIN32_FIND_DATAA* file1 = (WIN32_FIND_DATAA*)p1; + const WIN32_FIND_DATAA* file2 = (WIN32_FIND_DATAA*)p2; + return strcmp(file1->cFileName, file2->cFileName); +} + +// Enumerate a directory for the files specified by "searchPattern". For each element in the directory, +// pass it to the filter function. If the filter returns true, we keep it, otherwise we ignore it. Return +// an array of information for the files that we kept, sorted by filename. +// +// Returns 0 on success, non-zero on failure. +// If success, fileArray and elemCount are set. +// +// static +int verbMerge::FilterDirectory(const char* searchPattern, DirectoryFilterFunction_t filter, /* out */ WIN32_FIND_DATAA** ppFileArray, int* pElemCount) +{ + // First, build up a list, then create an array and sort it after we know how many elements there are. + struct findDataList + { + findDataList(WIN32_FIND_DATAA* newFindData, findDataList* newNext) + : findData(*newFindData) + , next(newNext) + { + } + + static void DeleteList(findDataList* root) + { + for (findDataList* loop = root; loop != nullptr; ) + { + findDataList* tmp = loop; + loop = loop->next; + delete tmp; + } + } + + WIN32_FIND_DATAA findData; + findDataList* next; + }; + + WIN32_FIND_DATAA* retArray = nullptr; + findDataList* first = nullptr; + + int result = 0; // default to zero == success + int elemCount = 0; + + // NOTE: this function only works on Windows 7 and later. + WIN32_FIND_DATAA findData; + HANDLE hSearch; +#ifdef FEATURE_PAL + // PAL doesn't have FindFirstFileEx(). So just use FindFirstFile(). The only reason we use + // the Ex version is potentially better performance (don't populate short name; use large fetch), + // not functionality. + hSearch = FindFirstFileA(searchPattern, &findData); +#else // !FEATURE_PAL + hSearch = FindFirstFileExA(searchPattern, + FindExInfoBasic, // We don't care about the short names + &findData, + FindExSearchNameMatch, // standard name matching + NULL, + FIND_FIRST_EX_LARGE_FETCH); +#endif // !FEATURE_PAL + + if (hSearch == INVALID_HANDLE_VALUE) + { + DWORD lastErr = GetLastError(); + if (lastErr == ERROR_FILE_NOT_FOUND) + { + // This is ok; there was just nothing matching the pattern. + } + else + { + LogError("Failed to find pattern '%s'. GetLastError()=%u", searchPattern, GetLastError()); + } + goto CLEAN_UP; + } + + while (true) + { + // Do something with findData... + + if (filter(&findData)) + { + // Prepend it to the list. + first = new findDataList(&findData, first); + ++elemCount; + } + + BOOL ok = FindNextFileA(hSearch, &findData); + if (!ok) + { + DWORD err = GetLastError(); + if (err != ERROR_NO_MORE_FILES) + { + LogError("Failed to find next file. GetLastError()=%u", GetLastError()); + result = -1; + goto CLEAN_UP; + } + break; + } + } + + // Now sort the list. Create an array to put everything in. + + int i; + + retArray = new WIN32_FIND_DATAA[elemCount]; + i = 0; + for (findDataList* tmp = first; tmp != nullptr; tmp = tmp->next) + { + retArray[i++] = tmp->findData; + } + + qsort(retArray, elemCount, sizeof(retArray[0]), WIN32_FIND_DATAA_qsort_helper); + +CLEAN_UP: + + findDataList::DeleteList(first); + + if ((hSearch != INVALID_HANDLE_VALUE) && !FindClose(hSearch)) + { + LogError("Failed to close search handle. GetLastError()=%u", GetLastError()); + delete[] retArray; + return -1; + } + + *ppFileArray = retArray; + *pElemCount = elemCount; + return result; +} + +// Append all files in the given directory matching the file pattern. +// +// static +int verbMerge::AppendAllInDir(HANDLE hFileOut, const char* dir, const char* file, unsigned char* buffer, size_t bufferSize, bool recursive, /* out */ LONGLONG* size) +{ + int result = 0; // default to zero == success + LONGLONG totalSize = 0; + + char* searchPattern = MergePathStrings(dir, file); + + WIN32_FIND_DATAA* fileArray = nullptr; + int elemCount = 0; + result = FilterDirectory(searchPattern, DirectoryFilterFile, &fileArray, &elemCount); + if (result != 0) + { + goto CLEAN_UP; + } + + for (int i = 0; i < elemCount; i++) + { + const WIN32_FIND_DATAA& findData = fileArray[i]; + char* fileFullPath = MergePathStrings(dir, findData.cFileName); + + // Is it zero length? If so, skip it. + if ((findData.nFileSizeLow == 0) && (findData.nFileSizeHigh == 0)) + { + LogInfo("Skipping zero-length file '%s'", fileFullPath); + } + else + { + result = AppendFile(hFileOut, fileFullPath, buffer, bufferSize); + if (result != 0) + { + // Error was already logged. + delete[] fileFullPath; + goto CLEAN_UP; + } + } + + delete[] fileFullPath; + totalSize += ((LONGLONG)findData.nFileSizeHigh << 32) + (LONGLONG)findData.nFileSizeLow; + } + + // If we need to recurse, then search the directory again for directories, and recursively search each one. + if (recursive) + { + delete[] searchPattern; + delete[] fileArray; + + searchPattern = MergePathStrings(dir, "*"); + fileArray = nullptr; + elemCount = 0; + result = FilterDirectory(searchPattern, DirectoryFilterDirectories, &fileArray, &elemCount); + if (result != 0) + { + goto CLEAN_UP; + } + + LONGLONG dirSize = 0; + for (int i = 0; i < elemCount; i++) + { + const WIN32_FIND_DATAA& findData = fileArray[i]; + + char* fileFullPath = MergePathStrings(dir, findData.cFileName); + result = AppendAllInDir(hFileOut, fileFullPath, file, buffer, bufferSize, recursive, &dirSize); + delete[] fileFullPath; + if (result != 0) + { + // Error was already logged. + goto CLEAN_UP; + } + + totalSize += dirSize; + } + } + +CLEAN_UP: + + delete[] searchPattern; + delete[] fileArray; + + if (result == 0) + { + *size = totalSize; + } + + return result; +} + +// Merge a set of .MC files into an output .MCH file. The .MC files to merge are given as a pattern, one of: +// 1. *.mc -- simple pattern. Assumes current directory. +// 2. foo\bar\*.mc -- simple pattern with relative directory. +// 3. c:\foo\bar\baz\*.mc -- simple pattern with full path. +// If no pattern is given, then the last component of the path is expected to be a directory name, and the pattern is assumed to be "*" (that is, all files). +// +// If "recursive" is true, then the pattern is searched for in the specified directory (or implicit current directory) and +// all sub-directories, recursively. +// +// static +int verbMerge::DoWork(const char* nameOfOutputFile, const char* pattern, bool recursive) +{ + int result = 0; // default to zero == success + SimpleTimer st1; + + LogInfo("Merging files matching '%s' into '%s'", pattern, nameOfOutputFile); + + HANDLE hFileOut = CreateFileA(nameOfOutputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open output file '%s'. GetLastError()=%u", nameOfOutputFile, GetLastError()); + return -1; + } + + // Create a buffer we can use for all the copies. + unsigned char* buffer = new unsigned char[BUFFER_SIZE]; + char* dir = nullptr; + const char* file = nullptr; + + dir = _strdup(pattern); + char* lastSlash = strrchr(dir, DIRECTORY_SEPARATOR_CHAR_A); + if (lastSlash == NULL) + { + // The user may have passed a relative path without a slash, or the current directory. + // If there is a wildcard, we use it as the file pattern. If there isn't, we assume it's a relative directory name + // and use it as a directory, with "*" as the file pattern. + const char* wildcard = strchr(dir, '*'); + if (wildcard == NULL) + { + file = "*"; + } + else + { + file = dir; + dir = _strdup("."); + } + } + else + { + const char* wildcard = strchr(lastSlash, '*'); + if (wildcard == NULL) + { + file = "*"; + + // Minor canonicalization: if there is a trailing last slash, strip it (probably should do this in a loop...) + if (*(lastSlash + 1) == '\0') + { + *lastSlash = '\0'; + } + } + else + { + // ok, we found a wildcard after the last slash, so assume there is a pattern. Strip it at the last slash. + *lastSlash = '\0'; + file = lastSlash + 1; + } + } + + LONGLONG totalSize = 0; + LONGLONG dirSize = 0; + + st1.Start(); + + result = AppendAllInDir(hFileOut, dir, file, buffer, BUFFER_SIZE, recursive, &dirSize); + if (result != 0) + { + goto CLEAN_UP; + } + totalSize += dirSize; + + st1.Stop(); + + LogInfo("Read/Wrote %lld MB @ %4.2f MB/s.", + totalSize/(1000*1000), + (((double)totalSize)/(1000*1000))/st1.GetSeconds()); //yes yes.. http://en.wikipedia.org/wiki/Megabyte_per_second#Megabyte_per_second + +CLEAN_UP: + + free((void*)dir); + delete[] buffer; + + if (CloseHandle(hFileOut) == 0) + { + LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); + result = -1; + } + + if (result != 0) + { + // There was a failure. Delete the output file, to avoid leaving some half-created file. + BOOL ok = DeleteFileA(nameOfOutputFile); + if (!ok) + { + LogError("Failed to delete file after MCS /merge failed. GetLastError()=%u", GetLastError()); + } + } + + return result; +} diff --git a/src/ToolBox/superpmi/mcs/verbmerge.h b/src/ToolBox/superpmi/mcs/verbmerge.h new file mode 100644 index 0000000000..1d612426f3 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbmerge.h @@ -0,0 +1,29 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbMerge.h - verb that merges multiple .MC into one .MCH file +//---------------------------------------------------------- +#ifndef _verbMerge +#define _verbMerge + +class verbMerge +{ +public: + static int DoWork(const char* nameOfOutputFile, const char* pattern, bool recursive); + +private: + typedef bool (*DirectoryFilterFunction_t)(WIN32_FIND_DATAA*); + static bool DirectoryFilterDirectories(WIN32_FIND_DATAA* findData); + static bool DirectoryFilterFile(WIN32_FIND_DATAA* findData); + static int __cdecl WIN32_FIND_DATAA_qsort_helper(const void* p1, const void* p2); + static int FilterDirectory(const char* searchPattern, DirectoryFilterFunction_t filter, /* out */ WIN32_FIND_DATAA** ppFileArray, int* pElemCount); + + static char* MergePathStrings(const char* dir, const char* file); + + static int AppendFile(HANDLE hFileOut, const char* fileName, unsigned char* buffer, size_t bufferSize); + static int AppendAllInDir(HANDLE hFileOut, const char* dir, const char* file, unsigned char* buffer, size_t bufferSize, bool recursive, /* out */ LONGLONG* size); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbremovedup.cpp b/src/ToolBox/superpmi/mcs/verbremovedup.cpp new file mode 100644 index 0000000000..eca5dc1b09 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbremovedup.cpp @@ -0,0 +1,145 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbremovedup.h" +#include "simpletimer.h" +#include "lightweightmap.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" + +//We use a hash to limit the number of comparisons we need to do. +//The first level key to our hash map is ILCodeSize and the second +//level map key is just an index and the value is an existing MC Hash. + +LightWeightMap<int, DenseLightWeightMap<char *> *> *inFile = nullptr; + +bool unique(MethodContext *mc) +{ + if (inFile == nullptr) + inFile = new LightWeightMap<int, DenseLightWeightMap<char *> *>(); + + CORINFO_METHOD_INFO newInfo; + unsigned newFlags = 0; + mc->repCompileMethod(&newInfo, &newFlags); + + char *md5Buff = new char[MD5_HASH_BUFFER_SIZE]; + mc->dumpMethodMD5HashToBuffer(md5Buff, MD5_HASH_BUFFER_SIZE); + + if (inFile->GetIndex(newInfo.ILCodeSize) == -1) + inFile->Add(newInfo.ILCodeSize, new DenseLightWeightMap<char *>()); + + DenseLightWeightMap<char *> *ourRank = inFile->Get(newInfo.ILCodeSize); + + for (int i = 0; i < (int)ourRank->GetCount(); i++) + { + char *md5Buff2 = ourRank->Get(i); + + if (strncmp(md5Buff, md5Buff2, MD5_HASH_BUFFER_SIZE) == 0) + { + delete[] md5Buff; + return false; + } + } + + ourRank->Append(md5Buff); + return true; +} + +LightWeightMap<int, DenseLightWeightMap<MethodContext *> *> *inFileLegacy = nullptr; + +bool uniqueLegacy(MethodContext *mc) +{ + if (inFileLegacy == nullptr) + inFileLegacy = new LightWeightMap<int, DenseLightWeightMap<MethodContext *> *>(); + + CORINFO_METHOD_INFO newInfo; + unsigned newFlags = 0; + mc->repCompileMethod(&newInfo, &newFlags); + + if (inFileLegacy->GetIndex(newInfo.ILCodeSize) == -1) + inFileLegacy->Add(newInfo.ILCodeSize, new DenseLightWeightMap<MethodContext *>()); + + DenseLightWeightMap<MethodContext *> *ourRank = inFileLegacy->Get(newInfo.ILCodeSize); + + for (int i = 0; i < (int)ourRank->GetCount(); i++) + { + MethodContext *scratch = ourRank->Get(i); + if (mc->Equal(scratch)) + { + return false; + } + } + + // We store the MethodContext in our map. + ourRank->Append(mc); + return true; +} + +int verbRemoveDup::DoWork(const char *nameOfInput, const char *nameOfOutput, bool stripCR, bool legacyCompare) +{ + LogVerbose("Removing duplicates from '%s', writing to '%s'", nameOfInput, nameOfOutput); + + MethodContextIterator mci(true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + + HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open output '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); + return -1; + } + + while (mci.MoveNext()) + { + MethodContext* mc = mci.CurrentTakeOwnership(); + if (stripCR) + { + delete mc->cr; + mc->cr = new CompileResult(); + } + if (legacyCompare) + { + if (uniqueLegacy(mc)) + { + mc->saveToFile(hFileOut); + savedCount++; + + // In this case, for the legacy comparer, it has placed the 'mc' in the 'inFileLegacy' table, so we can't delete it. + } + else + { + delete mc; // we no longer need this + } + } + else + { + if (unique(mc)) + { + mc->saveToFile(hFileOut); + savedCount++; + } + delete mc; // we no longer need this + } + } + + // We're leaking 'inFile' or 'inFileLegacy', but the process is going away, so it shouldn't matter. + + if (CloseHandle(hFileOut) == 0) + { + LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + + LogInfo("Loaded %d, Saved %d", mci.MethodContextNumber(), savedCount); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbremovedup.h b/src/ToolBox/superpmi/mcs/verbremovedup.h new file mode 100644 index 0000000000..ab0cb98692 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbremovedup.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbRemoveDup.h - verb that attempts to remove dups +//---------------------------------------------------------- +#ifndef _verbRemoveDup +#define _verbRemoveDup + +class verbRemoveDup +{ +public: + static int DoWork(const char *nameOfInput1, const char *nameOfOutput, bool stripCR, bool legacyCompare); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbsmarty.cpp b/src/ToolBox/superpmi/mcs/verbsmarty.cpp new file mode 100644 index 0000000000..9b881cdcbf --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbsmarty.cpp @@ -0,0 +1,96 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbsmarty.h" +#include "simpletimer.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" + +// +// Constructs a new verbSmarty. +// +// Arguments: +// hFile - A handle to the output file that we are writing the Smarty Test IDs +// +// Assumptions: +// hFile refers to an open and writeable file handle. +// +verbSmarty::verbSmarty(HANDLE hFile) +{ + m_hFile=hFile; +} + +// +// Dumps the Smarty TestID to file +// +// Arguments: +// testID - Smarty Test ID +// +void verbSmarty::DumpTestInfo(int testID) +{ + #define bufflen 4096 + DWORD bytesWritten; + + char buff[bufflen]; + int buff_offset = 0; + ZeroMemory(buff, bufflen * sizeof(char)); + + buff_offset+=sprintf_s(&buff[buff_offset], bufflen-buff_offset, "%i\r\n", testID); + WriteFile(m_hFile, buff, buff_offset * sizeof(char), &bytesWritten, nullptr); +} + + +int verbSmarty::DoWork(const char *nameOfInput, const char *nameOfOutput, int indexCount, const int *indexes) +{ + LogVerbose("Reading from '%s' reading Smarty ID for the Mc Indexes and writing into '%s'", nameOfInput, nameOfOutput); + + MethodContextIterator mci(indexCount, indexes); + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + + HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); + return -1; + } + + verbSmarty *verbList = new verbSmarty(hFileOut); + + //TODO-Cleanup: look to use toc for this + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + + int testID = mc->repGetTestID(); + if (testID != -1) + { + //write to the file + verbList->DumpTestInfo(testID); + } + else + { + LogError("Smarty ID not found for '%s'", mc->cr->repProcessName()); + } + } + + delete verbList; + + if (!CloseHandle(hFileOut)) + { + LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + + LogInfo("Loaded %d, Saved %d", mci.MethodContextNumber(), savedCount); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbsmarty.h b/src/ToolBox/superpmi/mcs/verbsmarty.h new file mode 100644 index 0000000000..994695da79 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbsmarty.h @@ -0,0 +1,22 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbSmarty.h - verb that outputs Smarty test ID for mc +//---------------------------------------------------------- +#ifndef _verbSmarty +#define _verbSmarty + +class verbSmarty +{ +public: + verbSmarty(HANDLE hFile); + void DumpTestInfo(int testID); + static int DoWork(const char *nameOfInput, const char *nameofOutput, int indexCount, const int *indexes); + +private: + HANDLE m_hFile; +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbstat.cpp b/src/ToolBox/superpmi/mcs/verbstat.cpp new file mode 100644 index 0000000000..473f452f96 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbstat.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbstat.h" +#include "simpletimer.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" +#include "errorhandling.h" + +int verbStat::DoWork(const char *nameOfInput, const char *nameOfOutput, int indexCount, const int *indexes) +{ + LogVerbose("Stat'ing from '%s' and writing output into '%s'", nameOfInput, nameOfOutput); + + MethodContextIterator mci(indexCount, indexes, true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + + HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); + return -1; + } + + #define bufflen 50000 + DWORD bytesWritten; + char buff[bufflen]; + int offset = 0; + ZeroMemory(&buff[0], bufflen); + offset += sprintf_s(buff, bufflen, "Title,MC#,"); + offset += MethodContext::dumpStatTitleToBuffer(&buff[offset], bufflen - offset); + buff[offset++] = 0x0d; + buff[offset++] = 0x0a; + WriteFile(hFileOut, &buff[0], offset, &bytesWritten, nullptr); + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + + offset = 0; + ZeroMemory(&buff[0], bufflen); + if ((mc->cr->ProcessName != nullptr) && (mc->cr->ProcessName->GetCount() > 0)) + { + const char *procname = mc->cr->repProcessName(); + strcpy_s(&buff[offset], bufflen, procname); + offset += (int)strlen(procname); + } + buff[offset++] = ','; + offset += sprintf_s(&buff[offset], bufflen - offset, "%d,", mci.MethodContextNumber()); + offset += mc->dumpStatToBuffer(&buff[offset], bufflen - offset); + buff[offset++] = 0x0d; + buff[offset++] = 0x0a; + WriteFile(hFileOut, &buff[0], offset, &bytesWritten, nullptr); + savedCount++; + } + + if (!CloseHandle(hFileOut)) + { + LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + + LogInfo("Loaded %d, Stat'd %d", mci.MethodContextNumber(), savedCount); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbstat.h b/src/ToolBox/superpmi/mcs/verbstat.h new file mode 100644 index 0000000000..53a3a78d6f --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbstat.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbStat.h - verb that +//---------------------------------------------------------- +#ifndef _verbStat +#define _verbStat + +class verbStat +{ +public: + static int DoWork(const char *nameOfInput1, const char *nameOfOutput, int indexCount, const int *indexes); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbstrip.cpp b/src/ToolBox/superpmi/mcs/verbstrip.cpp new file mode 100644 index 0000000000..8783b1a767 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbstrip.cpp @@ -0,0 +1,150 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbstrip.h" +#include "simpletimer.h" +#include "methodcontext.h" +#include "errorhandling.h" +#include "methodcontextreader.h" +#include "methodcontextiterator.h" + +// verbStrip::DoWork handles both "-copy" and "-strip". These both copy from input file to output file, +// but treat the passed-in indexes in opposite ways. +int verbStrip::DoWork(const char *nameOfInput, const char *nameOfOutput, int indexCount, const int *indexes, bool strip, bool stripCR) +{ + if (strip) + return DoWorkTheOldWay(nameOfInput, nameOfOutput, indexCount, indexes, stripCR); + SimpleTimer *st1 = new SimpleTimer(); + + LogVerbose("Reading from '%s' removing Mc Indexes and writing into '%s'", nameOfInput, nameOfOutput); + + int loadedCount = 0; + MethodContext *mc = nullptr; + int savedCount = 0; + int index = 0; + + // The method context reader handles skipping any unrequested method contexts + // Used in conjunction with an MCI file, it does a lot less work... + MethodContextReader *reader = new MethodContextReader(nameOfInput, indexes, indexCount); + if (!reader->isValid()) + { + return -1; + } + + HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); + return -1; + } + + if(indexCount == -1) + strip = true; //Copy command with no indexes listed should copy all the inputs... + while(true) + { + MethodContextBuffer mcb = reader->GetNextMethodContext(); + if (mcb.Error()) + { + return -1; + } + else if (mcb.allDone()) + { + break; + } + + loadedCount++; + if((loadedCount%500==0)&&(loadedCount>0)) + { + st1->Stop(); + LogVerbose("%2.1f%% - Loaded %d at %d per second", reader->PercentComplete(), loadedCount, (int)((double)500 / st1->GetSeconds())); + st1->Start(); + } + + if (!MethodContext::Initialize(loadedCount, mcb.buff, mcb.size, &mc)) + return -1; + + if(stripCR) + { + delete mc->cr; + mc->cr = new CompileResult(); + } + mc->saveToFile(hFileOut); + savedCount++; + delete mc; + } + if(CloseHandle(hFileOut)==0) + { + LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + LogInfo("Loaded %d, Saved %d", loadedCount, savedCount); + + return 0; +} + + +// This is only used for "-strip". +int verbStrip::DoWorkTheOldWay(const char *nameOfInput, const char *nameOfOutput, int indexCount, const int *indexes, bool stripCR) +{ + LogVerbose("Reading from '%s' removing MC Indexes and writing into '%s'", nameOfInput, nameOfOutput); + + MethodContextIterator mci(true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + bool write; + int index = 0; // Can't use MethodContextIterator indexing, since we want the opposite of that. + + HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); + return -1; + } + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + + write = true; // assume we'll write it + if (index < indexCount) + { + if (indexes[index] == mci.MethodContextNumber()) + { + index++; + write = false; + } + } + + if (write) + { + if (stripCR) + { + delete mc->cr; + mc->cr = new CompileResult(); + } + mc->saveToFile(hFileOut); + savedCount++; + } + } + + if (CloseHandle(hFileOut) == 0) + { + LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + + if (index < indexCount) + LogWarning("Didn't use all of index count input %d < %d (i.e. didn't see MC #%d)", index, indexCount, indexes[index]); + + LogInfo("Loaded %d, Saved %d", mci.MethodContextNumber(), savedCount); + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbstrip.h b/src/ToolBox/superpmi/mcs/verbstrip.h new file mode 100644 index 0000000000..9db77736a8 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbstrip.h @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbStrip.h - verb that removes a list of mc's from an MCH file +//---------------------------------------------------------- +#ifndef _verbStrip +#define _verbStrip + +class verbStrip +{ +public: + static int DoWork(const char *nameOfInput1, const char *nameOfOutput, int indexCount, const int *indexes, bool strip, bool stripCR); + static int DoWorkTheOldWay(const char *nameOfInput, const char *nameOfOutput, int indexCount, const int *indexes, bool stripCR); +}; +#endif diff --git a/src/ToolBox/superpmi/mcs/verbtoc.cpp b/src/ToolBox/superpmi/mcs/verbtoc.cpp new file mode 100644 index 0000000000..a99fbf0183 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbtoc.cpp @@ -0,0 +1,108 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbtoc.h" +#include "methodcontext.h" +#include "methodcontextreader.h" +#include "methodcontextiterator.h" +#include "simpletimer.h" + +class TOCElementNode +{ +public: + TOCElementNode *Next; + TOCElement tocElement; + + TOCElementNode(int number, __int64 offset) + : Next(nullptr) + , tocElement(number, offset) + { + } +}; + +int verbTOC::DoWork(const char *nameOfInput) +{ + LogVerbose("Indexing from '%s' into '%s.mct'", nameOfInput, nameOfInput); + + MethodContextIterator mci; + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + + TOCElementNode *head = nullptr; + TOCElementNode *curElem = nullptr; + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + + TOCElementNode *nxt = new TOCElementNode(mci.MethodContextNumber(), mci.CurrentPos()); + mc->dumpMethodMD5HashToBuffer(nxt->tocElement.Hash, MD5_HASH_BUFFER_SIZE); + + if (curElem != nullptr) + { + curElem->Next = nxt; + } + else + { + head = nxt; + } + curElem = nxt; + savedCount++; + } + + size_t maxLen = strlen(nameOfInput) + 5; + char *nameOfOutput = (char*)_alloca(maxLen); + strcpy_s(nameOfOutput, maxLen, nameOfInput); + strcat_s(nameOfOutput, maxLen, ".mct"); + HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFileOut == INVALID_HANDLE_VALUE) + { + LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); + return -1; + } + + DWORD written; + // Write out the signature "INDX" and then the element count + LARGE_INTEGER token; + token.u.LowPart = *(const int*)"INDX"; // cuz Type Safety is for languages that have good IO facilities + token.u.HighPart = savedCount; + if (!WriteFile(hFileOut, &token, sizeof(token), &written, nullptr) || written != sizeof(token)) + { + LogError("Failed to write index header. GetLastError()=%u", GetLastError()); + } + + // Now just dump sizeof(TOCElement) byte chunks into the file. + // I could probably do this more efficiently, but I don't think it matters + DWORD chunkSize = sizeof(TOCElement); + for (curElem = head; curElem != nullptr; curElem = curElem->Next) + { + if (!WriteFile(hFileOut, &curElem->tocElement, chunkSize, &written, nullptr) || written != chunkSize) + { + LogError("Failed to write index element '%d'. GetLastError()=%u", curElem->tocElement.Number, GetLastError()); + return -1; + } + } + // Now write out a final "INDX" to flag the end of the file... + if (!WriteFile(hFileOut, &token.u.LowPart, sizeof(token.u.LowPart), &written, nullptr) || (written != sizeof(token.u.LowPart))) + { + LogError("Failed to write index terminal. GetLastError()=%u", GetLastError()); + } + + LogInfo("Loaded %d, added %d to Table of Contents", mci.MethodContextNumber(), savedCount); + + if (CloseHandle(hFileOut) == 0) + { + LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); + return -1; + } + + if (!mci.Destroy()) + return -1; + + return 0; +} diff --git a/src/ToolBox/superpmi/mcs/verbtoc.h b/src/ToolBox/superpmi/mcs/verbtoc.h new file mode 100644 index 0000000000..7eea371191 --- /dev/null +++ b/src/ToolBox/superpmi/mcs/verbtoc.h @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// verbTOC.h - verb that creates a Table of Context for a MCH file +//---------------------------------------------------------- +#ifndef _verbTOC +#define _verbTOC + +class verbTOC +{ +public: + static int DoWork(const char *nameOfInput1); +}; +#endif |