#include "BlCvParser.h" #include "BlContext.h" #include "BlCodeView.h" #include "codeview/cvinfo.h" #include "../COFFData.h" #include "BeefySysLib/util/PerfTimer.h" USING_NS_BF; #define CV_BLOCK_SIZE 0x1000 #define MSF_SIGNATURE_700 "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0" #define GET(T) *((T*)(data += sizeof(T)) - 1) #define PTR_ALIGN(ptr, origPtr, alignSize) ptr = ( (origPtr)+( ((ptr - origPtr) + (alignSize - 1)) & ~(alignSize - 1) ) ) BlCvParser::BlCvParser(BlContext* context) { mContext = context; mCodeView = context->mCodeView; mCurModule = NULL; mSyms = NULL; } void BlCvParser::NotImpl() { } void BlCvParser::Fail(const StringImpl& err) { mContext->Fail(StrFormat("%s in %s", err.c_str(), mContext->ObjectDataIdxToString(mCurModule->mObjectData->mIdx).c_str())); } int64 BlCvParser::CvParseConstant(uint16 constVal, uint8*& data) { if (constVal < LF_NUMERIC) // 0x8000 return constVal; switch (constVal) { case LF_CHAR: return GET(int8); case LF_SHORT: return GET(int16); case LF_USHORT: return GET(uint16); case LF_LONG: return GET(int32); case LF_ULONG: return GET(uint32); case LF_QUADWORD: return GET(int64); case LF_UQUADWORD: return (int64)GET(uint64); default: BF_FATAL("Not handled"); } return 0; } int64 BlCvParser::CvParseConstant(uint8*& data) { uint16 val = GET(uint16); return CvParseConstant(val, data); } const char* BlCvParser::CvParseString(uint8*& data) { const char* strStart = (const char*)data; int strLen = (int)strlen((const char*)data); data += strLen + 1; if (strLen == 0) return NULL; return strStart; } bool BlCvParser::MapAddress(void* symbolData, void* cvLoc, BlReloc& outReloc, COFFRelocation*& nextReloc) { int posOfs = (int)((uint8*)cvLoc - (uint8*)symbolData); int posSect = (int)((uint8*)cvLoc + 4 - (uint8*)symbolData); if (nextReloc->mVirtualAddress != posOfs) { outReloc.mFlags = (BeRelocFlags)0; outReloc.mSymName = NULL; return false; } auto sym = &(*mSyms)[nextReloc->mSymbolTableIndex]; if (sym->mSym != NULL) { outReloc.mFlags = BeRelocFlags_Sym; outReloc.mSym = sym->mSym; } else { outReloc.mFlags = BeRelocFlags_Loc; outReloc.mSegmentIdx = sym->mSegmentIdx; outReloc.mSegmentOffset = sym->mSegmentOffset; } nextReloc++; if (nextReloc->mVirtualAddress != posSect) return false; // It MUST be the same sym nextReloc++; return true; } bool BlCvParser::TryReloc(void* symbolData, void* cvLoc, int32* outVal, COFFRelocation*& nextReloc) { int posOfs = (int)((uint8*)cvLoc - (uint8*)symbolData); if (nextReloc->mVirtualAddress != posOfs) return true; return false; } void BlCvParser::AddModule(BlObjectData* objectData, const char* strTab) { //const char* invalidStrs[] = { "delete_scalar", "new_scalar", "throw_bad_alloc", "std_type_info_static", "delete_scalar_size", "main2" }; //const char* invalidStrs[] = { "delete_scalar", "new_scalar" }; /*const char* invalidStrs[] = { "delete_scalar" }; for (const char* invalidStr : invalidStrs) { //TODO: if (strstr(objectData->mName, invalidStr) != NULL) { return; } } if (strstr(objectData->mName, "new_scalar") != NULL) { mTEMP_Testing = true; }*/ mCurModule = mCodeView->mModuleInfo.Alloc(); mCurModule->mObjectData = objectData; mCurModule->mIdx = (int)mCodeView->mModuleInfo.size() - 1; mCurModule->mStrTab = strTab; } void BlCvParser::AddTypeData(PESectionHeader* sect) { mTypeSects.push_back(sect); } void BlCvParser::AddSymbolData(PESectionHeader* sect) { mSymSects.push_back(sect); } void BlCvParser::ParseTypeData(void* typeData, int size) { uint8* data = (uint8*)typeData; uint8* dataEnd = data + size; int sig = GET(int32); if (sig != CV_SIGNATURE_C13) { Fail("Invalid debug signature"); return; } bool useWorkList = true; if (*(int16*)(data + 2) == LF_TYPESERVER2) { lfTypeServer2& typeServer = *(lfTypeServer2*)(data + 2); String filePath = (char*)typeServer.name; String fixedFilePath = FixPathAndCase(filePath); auto itr = mCodeView->mTypeServerFiles.find(fixedFilePath); if (itr == mCodeView->mTypeServerFiles.end()) { auto itrPair = mCodeView->mTypeServerFiles.insert(std::make_pair(fixedFilePath, (BlCvTypeSource*)NULL)); BlPdbParser* pdbParser = new BlPdbParser(); pdbParser->mTypeSource = new BlCvTypeSource; itrPair.first->second = pdbParser->mTypeSource; pdbParser->mTypeSource->mTypeServerLib = pdbParser; pdbParser->mTypeSource->Init(mCodeView); if (FileExists(filePath)) { pdbParser->mFileName = filePath; } else { String fileName = GetFileName(filePath); String checkFilePath; if (mCurModule->mObjectData->mLib != NULL) checkFilePath = GetFileDir(mCurModule->mObjectData->mLib->mFileName); else checkFilePath = GetFileDir(mCurModule->mObjectData->mName); checkFilePath += fileName; pdbParser->mFileName = checkFilePath; } if (useWorkList) { mCodeView->mTypeWorkThread.Add(pdbParser->mTypeSource); } else { pdbParser->Load(pdbParser->mFileName); } mCurModule->mTypeSource = pdbParser->mTypeSource; } else { mCurModule->mTypeSource = itr->second; } return; } auto typeSource = new BlCvTypeSource(); typeSource->Init(mCodeView); mCurModule->mTypeSource = typeSource; typeSource->mTPI.mSectionData = data; typeSource->mTPI.mSectionSize = size - 4; typeSource->mObjectData = mCurModule->mObjectData; if (useWorkList) { mCodeView->mTypeWorkThread.Add(typeSource); } else { typeSource->mTPI.ScanTypeData(); typeSource->mTPI.ParseTypeData(); } } void BlCvParser::ParseSymbolData(void* symbolData, int size, void* relocData, int numRelocs) { // static int itrCount = 0; // itrCount++; // // if (itrCount == 0x32) // { // NOP; // } uint8* data = (uint8*)symbolData; uint8* symDataEnd = data + size; int sig = GET(int32); if (sig != CV_SIGNATURE_C13) { Fail("Invalid debug signature"); return; } bool relocFailed = false; uint8* fileChecksumStart = NULL; uint8* fileChecksumEnd = NULL; COFFRelocation* nextReloc = (COFFRelocation*)relocData; COFFRelocation* relocEnd = nextReloc + numRelocs; const char* strTable = NULL; while (data < symDataEnd) { int sectionNum = GET(int32); int sectionLen = GET(int32); uint8* sectionStart = data; uint8* sectionEnd = data + sectionLen; if (sectionNum == DEBUG_S_STRINGTABLE) { //BF_ASSERT(mCurModule->mStrTab.size() == 0); //mCurModule->mStrTab.insert(mCurModule->mStrTab.begin(), (char*)sectionStart, (char*)sectionEnd); strTable = (char*)sectionStart; } else if (sectionNum == DEBUG_S_FILECHKSMS) { fileChecksumStart = sectionStart; fileChecksumEnd = sectionEnd; } data = sectionEnd; PTR_ALIGN(data, (uint8*)symbolData, 4); } //int bytesPerFile = 24; // Handle DEBUG_S_FILECHKSMS if (fileChecksumStart != NULL) { data = fileChecksumStart; uint8* sectionStart = data; uint8* sectionEnd = fileChecksumEnd; // Always at least 8 bytes per file info mChksumOfsToFileIdx.resize((sectionEnd - data) / 8); mCurModule->mFileInfos.reserve((sectionEnd - data) / 24); while (data < sectionEnd) { int dataOfs = (int)(data - sectionStart); uint32 fileTableOfs = GET(uint32); const char* fileName = strTable + fileTableOfs; uint8 hashLen = GET(uint8); uint8 hashType = GET(uint8); BlCvFileInfo fileInfo; fileInfo.mChksumOfs = dataOfs; fileInfo.mStrTableIdx = mCodeView->AddToStringTable(fileName); if (hashLen > 0) { BF_ASSERT(hashType == 1); fileInfo.mHashType = 1; memcpy(fileInfo.mHash, data, 16); data += hashLen; } else { fileInfo.mHashType = 0; } mChksumOfsToFileIdx[dataOfs / 8] = (int)mCurModule->mFileInfos.size(); mCurModule->mFileInfos.push_back(fileInfo); PTR_ALIGN(data, sectionStart, 4); } } data = (uint8*)symbolData + 4; while (data < symDataEnd) { int sectionNum = GET(int32); int sectionLen = GET(int32); uint8* sectionStart = data; uint8* sectionEnd = data + sectionLen; if ((sectionNum == DEBUG_S_SYMBOLS) || (sectionNum == DEBUG_S_INLINEELINES)) { //BL_AUTOPERF("DEBUG_S_SYMBOLS"); BlCvSymDataBlock dataBlock; dataBlock.mSize = (int)(sectionEnd - sectionStart); dataBlock.mData = sectionStart; dataBlock.mSourceSectOffset = (int)((uint8*)sectionStart - (uint8*)symbolData); dataBlock.mRelocStart = nextReloc; dataBlock.mOutSize = -1; WIN32_MEMORY_RANGE_ENTRY vAddrs = { dataBlock.mData, (SIZE_T)dataBlock.mSize }; //TODO: This was causing link errors on Win7 #if 0 PrefetchVirtualMemory(GetCurrentProcess(), 1, &vAddrs, 0); #endif data = sectionEnd; while ((nextReloc < relocEnd) && ((int)nextReloc->mVirtualAddress < (int)(sectionEnd - (uint8*)symbolData))) nextReloc++; dataBlock.mRelocEnd = nextReloc; if (sectionNum == DEBUG_S_SYMBOLS) mCurModule->mSymData.push_back(dataBlock); else mCurModule->mInlineData.push_back(dataBlock); PTR_ALIGN(data, (uint8*)symbolData, 4); continue; } if ((sectionNum & DEBUG_S_IGNORE) != 0) { data = sectionEnd; while ((nextReloc < relocEnd) && ((int)nextReloc->mVirtualAddress < (int)(sectionEnd - (uint8*)symbolData))) nextReloc++; PTR_ALIGN(data, (uint8*)symbolData, 4); continue; } switch (sectionNum) { case DEBUG_S_LINES: { //BL_AUTOPERF("DEBUG_S_LINES"); CV_DebugSLinesHeader_t& lineSec = GET(CV_DebugSLinesHeader_t); BlReloc reloc; MapAddress(symbolData, &lineSec.offCon, reloc, nextReloc); auto lineInfo = mCurModule->mLineInfo.Alloc(); /*if ((reloc.mFlags & BeRelocFlags_Sym) != 0) { auto sym = mContext->ProcessSymbol(reloc.mSym); if (sym->mSegmentIdx >= 0) { lineInfo->mStartSegmentIdx = sym->mSegmentIdx; lineInfo->mStartSegmentOffset = sym->mSegmentOffset; } else relocFailed = true; } else*/ if ((reloc.mFlags & BeRelocFlags_Loc) != 0) { lineInfo->mStartSegmentIdx = reloc.mSegmentIdx; lineInfo->mStartSegmentOffset = reloc.mSegmentOffset; } else { relocFailed = true; } lineInfo->mContribBytes = lineSec.cbCon; while (data < sectionEnd) { CV_DebugSLinesFileBlockHeader_t& linesFileHeader = GET(CV_DebugSLinesFileBlockHeader_t); lineInfo->mLineInfoBlocks.emplace_back(BlCvLineInfoBlock()); auto& lineInfoBlock = lineInfo->mLineInfoBlocks.back(); lineInfoBlock.mLines.reserve(linesFileHeader.nLines); if ((lineSec.flags & CV_LINES_HAVE_COLUMNS) != 0) lineInfoBlock.mColumns.reserve(linesFileHeader.nLines); //BF_ASSERT(linesFileHeader.offFile % bytesPerFile == 0); //lineInfoBlock.mFileInfoIdx = linesFileHeader.offFile / bytesPerFile; lineInfoBlock.mFileInfoIdx = mChksumOfsToFileIdx[linesFileHeader.offFile / 8]; for (int lineIdx = 0; lineIdx < linesFileHeader.nLines; lineIdx++) { CV_Line_t& srcLineData = GET(CV_Line_t); BlCvLine cvLine; cvLine.mLineNumStart = srcLineData.linenumStart; cvLine.mOffset = srcLineData.offset; lineInfoBlock.mLines.push_back(cvLine); } if ((lineSec.flags & CV_LINES_HAVE_COLUMNS) != 0) { for (int lineIdx = 0; lineIdx < linesFileHeader.nLines; lineIdx++) { CV_Column_t& srcColumnData = GET(CV_Column_t); lineInfoBlock.mColumns.push_back(srcColumnData.offColumnStart); } } } } break; case DEBUG_S_INLINEELINES: { // Already handled } break; case DEBUG_S_STRINGTABLE: { // Already handled } break; case DEBUG_S_FILECHKSMS: { // Already handled } break; default: NotImpl(); } data = sectionEnd; PTR_ALIGN(data, (uint8*)symbolData, 4); } if (nextReloc != (COFFRelocation*)relocData + numRelocs) relocFailed = true; if (relocFailed) Fail("Failed to apply relocations to debug symbol data"); } void BlCvParser::AddContribution(int blSectionIdx, int blSectionOfs, int size, int characteristics) { if (mCurModule == NULL) return; if ((characteristics & IMAGE_SCN_MEM_EXECUTE) != 0) { if (mCurModule->mContrib.mCharacteristics == 0) { mCurModule->mContrib.mBlSectionIdx = blSectionIdx; mCurModule->mContrib.mBlSectionOfs = blSectionOfs; mCurModule->mContrib.mSize = size; mCurModule->mContrib.mCharacteristics = characteristics; } } BlCvContrib contrib; contrib.mModuleIdx = mCurModule->mIdx; contrib.mBlSectionOfs = blSectionOfs; contrib.mSize = size; contrib.mCharacteristics = characteristics; while (blSectionIdx >= (int)mCodeView->mContribMap.mSegments.size()) mCodeView->mContribMap.mSegments.Alloc(); auto contribMapSeg = mCodeView->mContribMap.mSegments[blSectionIdx]; contribMapSeg->mContribs.push_back(contrib); } void BlCvParser::FinishModule(PESectionHeader* sectHeaderArr, const BfSizedVectorRef& sectInfos, PE_SymInfo* objSyms, const BfSizedVectorRef& syms) { if (mCurModule == NULL) return; mCurModule->mObjSyms = objSyms; if (!syms.empty()) mCurModule->mSymInfo.insert(mCurModule->mSymInfo.begin(), syms.begin(), syms.end()); for (auto sectInfo : sectInfos) mCurModule->mSectInfos.push_back(sectInfo); mSyms = &syms; // { BL_AUTOPERF("BlCvParser::FinishModule ParseTypeData"); for (auto sect : mTypeSects) { ParseTypeData((uint8*)mCurModule->mObjectData->mData + sect->mPointerToRawData, sect->mSizeOfRawData); } } // { BL_AUTOPERF("BlCvParser::FinishModule ParseSymbolData"); for (auto sect : mSymSects) { ParseSymbolData( (uint8*)mCurModule->mObjectData->mData + sect->mPointerToRawData, sect->mSizeOfRawData, (uint8*)mCurModule->mObjectData->mData + sect->mPointerToRelocations, sect->mNumberOfRelocations); } } mCodeView->mModuleWorkThread.Add(mCurModule); }