#include "MSVCMapFileParser.h" #include "MSVCSectionParser.h" #include "MSVCSymbolParser.h" #include #include #include #include #include #include namespace mapfileparser { static size_t GetSectionIndexForSymbol(int64_t absoluteSymbolAddress, const std::vector
& sections) { for (size_t index = 0; index < sections.size(); ++index) { if (absoluteSymbolAddress >= sections[index].start && absoluteSymbolAddress <= (sections[index].start + sections[index].length)) return index; } throw std::runtime_error(std::string("Unable to find section for symbol")); } static void CalculateLengthsAndSegmentTypesForAllSymbols(MapFile& mapFile) { bool processedImageBase = false; // iterate all symbols and calculate length based on difference between start and start of next symbol for (size_t index = 0; index < mapFile.symbols.size(); ++index) { if (!processedImageBase) { if (mapFile.symbols[index].name == "___ImageBase" || mapFile.symbols[index].name == "__ImageBase") processedImageBase = true; continue; } size_t currentSectionIndex = GetSectionIndexForSymbol(mapFile.symbols[index].start, mapFile.sections); mapFile.symbols[index].segmentType = mapFile.sections[currentSectionIndex].segmentType; if (index == mapFile.symbols.size() - 1 || mapFile.sections[currentSectionIndex].segmentName != mapFile.sections[GetSectionIndexForSymbol(mapFile.symbols[index + 1].start, mapFile.sections)].segmentName) mapFile.symbols[index].length = mapFile.sections[currentSectionIndex].start + mapFile.sections[currentSectionIndex].length - mapFile.symbols[index].start; else mapFile.symbols[index].length = mapFile.symbols[index + 1].start - mapFile.symbols[index].start; } } static std::string ReadUntilDelimiter(std::istream& is, const char* delimiter) { const size_t delimiterLength = strlen(delimiter); std::string line; std::getline(is, line); while (!is.eof() && strncmp(line.c_str(), delimiter, delimiterLength) != 0) std::getline(is, line); return line; } static int64_t ParseBaseAddress(std::istream& is) { const char* preferredLoadAddressDelimiter = " Preferred load address is "; const size_t preferredLoadAddressDelimiterLength = strlen(preferredLoadAddressDelimiter); std::string line = ReadUntilDelimiter(is, preferredLoadAddressDelimiter); std::string imageBaseString = line.substr(preferredLoadAddressDelimiterLength); int64_t imageBaseOffset = 0; int fieldsParsed = sscanf(imageBaseString.c_str(), "%llX", &imageBaseOffset); if (fieldsParsed != 1) throw std::runtime_error("Unable to parse base address."); return imageBaseOffset; } static void ParseSections(std::istream& is, std::vector
& sections) { std::string line; std::getline(is, line); int64_t segmentOffset = 0x1000; std::string currentSegmentName; while (!is.eof() && line.length() > 0) { Section section = MSVCSectionParser::Parse(line); if (currentSegmentName.length() == 0) currentSegmentName = section.segmentName; else if (currentSegmentName != section.segmentName) { Section prevSection = sections[sections.size() - 1]; const int32_t kSectionBoundarySize = 0x1000; segmentOffset = prevSection.start + prevSection.length; if ((segmentOffset % kSectionBoundarySize) != 0) segmentOffset = (segmentOffset + kSectionBoundarySize) / kSectionBoundarySize * kSectionBoundarySize; currentSegmentName = section.segmentName; } section.start += segmentOffset; sections.push_back(section); std::getline(is, line); } } static void ParseSymbols(std::istream& is, std::vector& symbols, int64_t imageBaseOffset) { std::string line; std::getline(is, line); while (!is.eof()) { std::getline(is, line); if (line.length() == 0) break; symbols.push_back(MSVCSymbolParser::Parse(line, imageBaseOffset)); } } MapFile MSVCMapFileParser::Parse(std::istream& is) { MapFile mapFile; int64_t imageBaseOffset = ParseBaseAddress(is); ReadUntilDelimiter(is, " Start "); ParseSections(is, mapFile.sections); ReadUntilDelimiter(is, " Address "); ParseSymbols(is, mapFile.symbols, imageBaseOffset); CalculateLengthsAndSegmentTypesForAllSymbols(mapFile); return mapFile; } }