mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
323 lines
7.9 KiB
C++
323 lines
7.9 KiB
C++
![]() |
#include "BlPdbParser.h"
|
||
|
#include "BlContext.h"
|
||
|
#include "codeview/cvinfo.h"
|
||
|
#include "BlCvParser.h"
|
||
|
#include "BlCvTypeSource.h"
|
||
|
|
||
|
USING_NS_BF;
|
||
|
|
||
|
#define MSF_SIGNATURE_700 "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"
|
||
|
#define GET(T) *((T*)(data += sizeof(T)) - 1)
|
||
|
#define GET_INTO(T, name) T name = GET(T)
|
||
|
#define PTR_ALIGN(ptr, origPtr, alignSize) ptr = ( (origPtr)+( ((ptr - origPtr) + (alignSize - 1)) & ~(alignSize - 1) ) )
|
||
|
|
||
|
void BlPdbParser::Fail(const StringImpl& err)
|
||
|
{
|
||
|
BF_FATAL("Err");
|
||
|
}
|
||
|
|
||
|
void BlPdbParser::NotImpl()
|
||
|
{
|
||
|
BF_FATAL("NotImpl");
|
||
|
}
|
||
|
|
||
|
BlPdbParser::BlPdbParser()
|
||
|
{
|
||
|
mCvHeaderData = NULL;
|
||
|
mCvTypeSectionData = NULL;
|
||
|
mCvIPIData = NULL;
|
||
|
mMappedFile = NULL;
|
||
|
}
|
||
|
|
||
|
BlPdbParser::~BlPdbParser()
|
||
|
{
|
||
|
delete mCvHeaderData;
|
||
|
delete mCvTypeSectionData;
|
||
|
delete mCvIPIData;
|
||
|
delete mMappedFile;
|
||
|
}
|
||
|
|
||
|
bool BlPdbParser::Load(const StringImpl& fileName)
|
||
|
{
|
||
|
mMappedFile = new MappedFile();
|
||
|
if (!mMappedFile->Open(fileName))
|
||
|
return false;
|
||
|
mData = (uint8*)mMappedFile->mData;
|
||
|
|
||
|
uint8* data = (uint8*)mMappedFile->mData;
|
||
|
if (memcmp(data, MSF_SIGNATURE_700, 32) != 0)
|
||
|
{
|
||
|
Fail("PDB signature error");
|
||
|
return false;
|
||
|
}
|
||
|
data += 32;
|
||
|
|
||
|
int pageSize = GET(int32);
|
||
|
int fpmPageNum = GET(int32);
|
||
|
int totalPageCount = GET(int32);
|
||
|
int rootDirSize = GET(int32);
|
||
|
int unknown = GET(int32);
|
||
|
int rootDirPtr = GET(int32);
|
||
|
|
||
|
bool failed = false;
|
||
|
|
||
|
mCvPageSize = pageSize;
|
||
|
|
||
|
int rootPageCount = (rootDirSize + pageSize - 1) / pageSize;
|
||
|
int rootPointersPages = (rootPageCount * sizeof(int32) + pageSize - 1) / pageSize;
|
||
|
int rootPageIdx = 0;
|
||
|
|
||
|
std::vector<uint8> rootDirData;
|
||
|
rootDirData.resize(rootPageCount * pageSize);
|
||
|
data = mData + (rootDirPtr * pageSize);
|
||
|
|
||
|
int32* rootPages = (int32*)data;
|
||
|
for (int subRootPageIdx = 0; subRootPageIdx < pageSize / 4; subRootPageIdx++, rootPageIdx++)
|
||
|
{
|
||
|
if (rootPageIdx >= rootPageCount)
|
||
|
break;
|
||
|
|
||
|
int rootPagePtr = rootPages[subRootPageIdx];
|
||
|
if (rootPagePtr == 0)
|
||
|
break;
|
||
|
data = mData + (rootPagePtr * pageSize);
|
||
|
memcpy(&rootDirData[rootPageIdx * pageSize], data, pageSize);
|
||
|
data += pageSize;
|
||
|
}
|
||
|
|
||
|
if (!ParseCv(&rootDirData[0]))
|
||
|
{
|
||
|
Fail("Failed to parse PDB");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool BlPdbParser::CvParseHeader()
|
||
|
{
|
||
|
uint8* data = CvReadStream(1);
|
||
|
mCvHeaderData = data;
|
||
|
|
||
|
int32 pdbVersion = GET(int32);
|
||
|
int32 timestamp = GET(int32);
|
||
|
int32 pdbAge = GET(int32);
|
||
|
int8 pdbGuid[16];
|
||
|
for (int i = 0; i < 16; i++)
|
||
|
pdbGuid[i] = GET(int8);
|
||
|
|
||
|
/*if ((wantAge != -1) &&
|
||
|
((pdbAge != wantAge) || (memcmp(pdbGuid, wantGuid, 16) != 0)))
|
||
|
{
|
||
|
String msg = "PDB version did not match requested version\n";
|
||
|
|
||
|
msg += StrFormat(" Age: %d Module GUID: ", wantAge);
|
||
|
for (int i = 0; i < 16; i++)
|
||
|
msg += StrFormat("%02X", (uint8)wantGuid[i]);
|
||
|
msg += "\n";
|
||
|
|
||
|
msg += StrFormat(" Age: %d PDB GUID : ", pdbAge);
|
||
|
for (int i = 0; i < 16; i++)
|
||
|
msg += StrFormat("%02X", (uint8)pdbGuid[i]);
|
||
|
msg += "\n";
|
||
|
|
||
|
mDebugger->OutputMessage(msg);
|
||
|
return false;
|
||
|
}*/
|
||
|
|
||
|
int nameTableIdx = -1;
|
||
|
|
||
|
GET_INTO(int32, strTabLen);
|
||
|
const char* strTab = (const char*)data;
|
||
|
data += strTabLen;
|
||
|
|
||
|
GET_INTO(int32, numStrItems);
|
||
|
GET_INTO(int32, strItemMax);
|
||
|
|
||
|
GET_INTO(int32, usedLen);
|
||
|
data += usedLen * sizeof(int32);
|
||
|
GET_INTO(int32, deletedLen);
|
||
|
data += deletedLen * sizeof(int32);
|
||
|
|
||
|
for (int tableIdx = 0; tableIdx < numStrItems; tableIdx++)
|
||
|
{
|
||
|
GET_INTO(int32, strOfs);
|
||
|
GET_INTO(int32, streamNum);
|
||
|
|
||
|
const char* tableName = strTab + strOfs;
|
||
|
if (strcmp(tableName, "/names") == 0)
|
||
|
mStringTable.mStream = streamNum;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
uint8* BlPdbParser::CvReadStream(int streamIdx, int* outSize)
|
||
|
{
|
||
|
int streamSize = mCvStreamSizes[streamIdx];
|
||
|
if (outSize != NULL)
|
||
|
*outSize = streamSize;
|
||
|
if (streamSize <= 0)
|
||
|
return NULL;
|
||
|
int streamPageCount = (streamSize + mCvPageSize - 1) / mCvPageSize;
|
||
|
|
||
|
uint8* sectionData = new uint8[streamSize];
|
||
|
bool deferDeleteSectionData = false;
|
||
|
|
||
|
int streamPtrIdx = mCvStreamPtrStartIdxs[streamIdx];
|
||
|
for (int streamPageIdx = 0; streamPageIdx < streamPageCount; streamPageIdx++)
|
||
|
{
|
||
|
uint8* data = mData + (mCvStreamPtrs[streamPtrIdx] * mCvPageSize);
|
||
|
memcpy(sectionData + streamPageIdx * mCvPageSize, data, std::min(streamSize - (streamPageIdx * mCvPageSize), mCvPageSize));
|
||
|
streamPtrIdx++;
|
||
|
}
|
||
|
|
||
|
return sectionData;
|
||
|
}
|
||
|
|
||
|
bool BlPdbParser::ParseCv(uint8* rootDirData)
|
||
|
{
|
||
|
uint8* data = rootDirData;
|
||
|
|
||
|
bool failed = false;
|
||
|
int numStreams = GET(int32);
|
||
|
if (numStreams == 0)
|
||
|
return true;
|
||
|
|
||
|
mCvStreamSizes.resize(numStreams);
|
||
|
mCvStreamPtrStartIdxs.resize(numStreams);
|
||
|
|
||
|
int streamPages = 0;
|
||
|
for (int i = 0; i < (int)mCvStreamSizes.size(); i++)
|
||
|
mCvStreamSizes[i] = GET(int32);
|
||
|
for (int streamIdx = 0; streamIdx < numStreams; streamIdx++)
|
||
|
{
|
||
|
mCvStreamPtrStartIdxs[streamIdx] = streamPages;
|
||
|
if (mCvStreamSizes[streamIdx] > 0)
|
||
|
streamPages += (mCvStreamSizes[streamIdx] + mCvPageSize - 1) / mCvPageSize;
|
||
|
}
|
||
|
mCvStreamPtrs.resize(streamPages);
|
||
|
for (int i = 0; i < (int)mCvStreamPtrs.size(); i++)
|
||
|
mCvStreamPtrs[i] = GET(int32);
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
if (!CvParseHeader())
|
||
|
return false;
|
||
|
|
||
|
ParseTypeData();
|
||
|
ParseIPIData();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void BlPdbParser::ParseTypeData()
|
||
|
{
|
||
|
int sectionSize = 0;
|
||
|
mCvTypeSectionData = CvReadStream(2, §ionSize);
|
||
|
uint8* data = mCvTypeSectionData;
|
||
|
uint8* sectionData = mCvTypeSectionData;
|
||
|
|
||
|
int32 ver = GET(int32);
|
||
|
int32 headerSize = GET(int32);
|
||
|
int32 minVal = GET(int32);
|
||
|
int32 maxVal = GET(int32);
|
||
|
int32 followSize = GET(int32);
|
||
|
|
||
|
int16 hashStream = GET(int16);
|
||
|
int16 hashStreamPadding = GET(int16);
|
||
|
int32 hashKey = GET(int32);
|
||
|
int32 hashBucketsSize = GET(int32);
|
||
|
int32 hashValsOffset = GET(int32);
|
||
|
int32 hashValsSize = GET(int32);
|
||
|
int32 hashTypeInfoOffset = GET(int32);
|
||
|
int32 hashTypeInfoSize = GET(int32);
|
||
|
int32 hashAdjOffset = GET(int32);
|
||
|
int32 hashAdjSize = GET(int32);
|
||
|
|
||
|
mTypeSource->mTPI.mCvMinTag = minVal;
|
||
|
mTypeSource->mTPI.mCvMaxTag = maxVal;
|
||
|
//mCvTypeMap.clear();
|
||
|
//mTypeSource->mTPI.mCvTagStartMap.clear();
|
||
|
//mCvTypeMap.resize(maxVal - minVal);
|
||
|
mTypeSource->mTPI.mCvTagStartMap.resize(maxVal - minVal);
|
||
|
|
||
|
//DbgDataMap dataMap(minVal, maxVal);
|
||
|
|
||
|
mTypeSource->mTPI.mSectionData = data;
|
||
|
mTypeSource->mTPI.mSectionSize = sectionSize - (int)(data - sectionData);
|
||
|
mTypeSource->mTPI.ScanTypeData();
|
||
|
mTypeSource->mTPI.ParseTypeData();
|
||
|
|
||
|
if (hashAdjSize > 0)
|
||
|
{
|
||
|
int sectionSize = 0;
|
||
|
uint8* data = CvReadStream(hashStream, §ionSize);
|
||
|
uint8* sectionData = data;
|
||
|
|
||
|
data = sectionData + hashAdjOffset;
|
||
|
|
||
|
GET_INTO(int32, adjustCount);
|
||
|
GET_INTO(int32, unk0);
|
||
|
GET_INTO(int32, unkCount);
|
||
|
for (int i = 0; i < unkCount; i++)
|
||
|
{
|
||
|
GET_INTO(int32, unk2);
|
||
|
}
|
||
|
GET_INTO(int32, unkCount2);
|
||
|
for (int i = 0; i < unkCount2; i++)
|
||
|
{
|
||
|
GET_INTO(int32, unk3);
|
||
|
}
|
||
|
|
||
|
// Types listed in the adjustment table are always primary types,
|
||
|
// they should override any "old types" with the same name
|
||
|
for (int adjIdx = 0; adjIdx < adjustCount; adjIdx++)
|
||
|
{
|
||
|
GET_INTO(int32, adjVal);
|
||
|
GET_INTO(CV_typ_t, typeId);
|
||
|
}
|
||
|
|
||
|
delete[] sectionData;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BlPdbParser::ParseIPIData()
|
||
|
{
|
||
|
int sectionSize = 0;
|
||
|
mCvIPIData = CvReadStream(4, §ionSize);
|
||
|
uint8* data = mCvIPIData;
|
||
|
uint8* sectionData = data;
|
||
|
|
||
|
int32 ver = GET(int32);
|
||
|
int32 headerSize = GET(int32);
|
||
|
int32 minVal = GET(int32);
|
||
|
int32 maxVal = GET(int32);
|
||
|
int32 followSize = GET(int32);
|
||
|
|
||
|
int16 hashStream = GET(int16);
|
||
|
int16 hashStreamPadding = GET(int16);
|
||
|
int32 hashKey = GET(int32);
|
||
|
int32 hashBucketsSize = GET(int32);
|
||
|
int32 hashValsOffset = GET(int32);
|
||
|
int32 hashValsSize = GET(int32);
|
||
|
int32 hashTypeInfoOffset = GET(int32);
|
||
|
int32 hashTypeInfoSize = GET(int32);
|
||
|
int32 hashAdjOffset = GET(int32);
|
||
|
int32 hashAdjSize = GET(int32);
|
||
|
|
||
|
mTypeSource->CreateIPI();
|
||
|
mTypeSource->mIPI->mCvMinTag = minVal;
|
||
|
mTypeSource->mIPI->mCvMaxTag = maxVal;
|
||
|
int recordCount = maxVal - minVal;
|
||
|
mTypeSource->mIPI->mCvTagStartMap.resize(recordCount);
|
||
|
|
||
|
int typeDataSize = sectionSize - (int)(data - sectionData);
|
||
|
mTypeSource->mIPI->mSectionData = data;
|
||
|
mTypeSource->mIPI->mSectionSize = typeDataSize;
|
||
|
mTypeSource->mIPI->ScanTypeData();
|
||
|
mTypeSource->mIPI->ParseTypeData();
|
||
|
}
|
||
|
|