#include #include #include #include "Driver.h" #include "MSVC/MSVCMapFileParser.h" #include "Clang/ClangMapFileParser.h" #include "SNC/SNCMapFileParser.h" #include "GCC/GCCMapFileParser.h" #include "SymbolInfoWriter.h" #include "Statistics.h" #ifdef _WINDOWS #include #endif namespace mapfileparser { enum MapFileFormat { kMapFileFormatUnknown, kMapFileFormatMSVC, kMapFileFormatClang, kMapFileFormatSNC, kMapFileFormatGCC, }; static MapFileParser* GetParser(MapFileFormat mapFileFormat) { switch (mapFileFormat) { case kMapFileFormatMSVC: return new MSVCMapFileParser(); case kMapFileFormatClang: return new ClangMapFileParser(); case kMapFileFormatSNC: return new SNCMapFileParser(); case kMapFileFormatGCC: return new GCCMapFileParser(); default: throw new std::runtime_error(std::string("Invalid map file format specified")); } } static const char* GetUsage() { return "Usage: MapFileParser -format= mapFile <-stats|outputFile>"; } static std::string NativeStringToUtf8(const NativeChar* str) { #if !_WINDOWS return str; #else size_t strLength = wcslen(str); std::string result; result.resize(4 * strLength); int resultLength = WideCharToMultiByte(CP_UTF8, 0, str, static_cast(strLength), &result[0], static_cast(4 * strLength), NULL, NULL); result.resize(resultLength); return result; #endif } static void ParseInputAndWriteOutput(MapFileFormat mapFileFormat, std::ifstream& inputFile, std::ofstream& outputFile) { MapFileParser* parser = GetParser(mapFileFormat); MapFile mapFile = parser->Parse(inputFile); SymbolInfoWriter::Write(outputFile, mapFile); } static void ParseInputAndGenerateStatistics(MapFileFormat mapFileFormat, std::ifstream& inputFile, std::ostream& output) { MapFileParser* parser = GetParser(mapFileFormat); MapFile mapFile = parser->Parse(inputFile); Statistics::Generate(mapFile, output); } int Driver::Run(int argc, const NativeChar* const argv[], std::ostream& out) { if (argc != 4) { out << GetUsage() << std::endl; return 1; } MapFileFormat mapFileFormat = kMapFileFormatUnknown; if (!NativeStrCmp(argv[1], NativeText("-format=MSVC"))) mapFileFormat = kMapFileFormatMSVC; else if (!NativeStrCmp(argv[1], NativeText("-format=Clang"))) mapFileFormat = kMapFileFormatClang; else if (!NativeStrCmp(argv[1], NativeText("-format=SNC"))) mapFileFormat = kMapFileFormatSNC; else if (!NativeStrCmp(argv[1], NativeText("-format=GCC"))) mapFileFormat = kMapFileFormatGCC; if (mapFileFormat == kMapFileFormatUnknown) { out << "Unknown map file format.\n"; out << GetUsage() << std::endl; return 1; } // If we have a runtime error, like a file failing to open or an error parsing, // we want to return 0, so that the build will succeed. Since map-file based // stack traces are not required to execute, we won't fail the build if // we can't generate the output file. const NativeChar* mapFileName = argv[2]; std::ifstream inputFile; inputFile.open(mapFileName, std::ifstream::in); if (!inputFile.is_open()) { out << "Map file " << NativeStringToUtf8(argv[2]) << " cannot be opened.\n"; return 1; } if (NativeStrCmp(argv[3], NativeText("-stats")) == 0) { if (mapFileFormat != kMapFileFormatClang) { out << "Statistics are only supported for Clang map files now.\n"; out << GetUsage() << std::endl; return 1; } try { ParseInputAndGenerateStatistics(mapFileFormat, inputFile, out); } catch (const std::exception& e) { out << e.what() << std::endl; } } else { const NativeChar* outputFileName = argv[3]; std::ofstream outputFile; outputFile.open(outputFileName, std::ios::binary | std::ios::out); if (!outputFile.is_open()) { out << "Output file " << NativeStringToUtf8(argv[3]) << " cannot be opened.\n"; return 0; } try { ParseInputAndWriteOutput(mapFileFormat, inputFile, outputFile); } catch (const std::exception& e) { out << e.what() << std::endl; } } return 0; } }