1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28:20 +02:00
Beef/IDEHelper/Linker/BlCodeView.cpp
Brian Fiete 2f01cc14dd Beefy::String changes, lambda hotswap fixes
Changed some string internals related to StringViewsma
Added an "incompatible capture" error for lambdas when the captures change
2019-09-03 11:17:13 -07:00

2481 lines
61 KiB
C++

#include "BlCodeView.h"
#include "codeview/cvinfo.h"
#include "BlContext.h"
#include "BlHash.h"
#include "../COFFData.h"
#include "../Compiler/BfAstAllocator.h"
#include "BeefySysLib/util/BeefPerf.h"
#include <direct.h>
#include <time.h>
//#define BL_AUTOPERF_CV(name) AutoPerf autoPerf##__LINE__(name);
#define BL_AUTOPERF_CV(name)
USING_NS_BF;
#define CV_BLOCK_SIZE 0x1000
#define GET(T) *((T*)(data += sizeof(T)) - 1)
#define PTR_ALIGN(ptr, origPtr, alignSize) ptr = ( (origPtr)+( ((ptr - (origPtr)) + (alignSize - 1)) & ~(alignSize - 1) ) )
//////////////////////////////////////////////////////////////////////////
void BlCvRecordMap::Insert(const char* name, int symIdx)
{
int hashKey = BlHash::HashStr_PdbV1(name) % 4096;
auto entry = mAlloc.Alloc<BlCvRecordEntry>();
entry->mRecordIndex = symIdx;
entry->mNext = mBuckets[hashKey];
mBuckets[hashKey] = entry;
mNumEntries++;
}
int BlCvRecordMap::TryInsert(const char* name, const Val128& key)
{
auto pair = mKeySet.insert(key);
if (!pair.second)
return -1;
//BL_AUTOPERF_CV("BlCvRecordMap::TryInsert insert");
int hashKey = BlHash::HashStr_PdbV1(name) % 4096;
/*auto checkEntry = mBuckets[hashKey];
while (checkEntry != NULL)
{
if (checkEntry->mKey == key)
return -1;
checkEntry = checkEntry->mNext;
}*/
auto entry = mAlloc.Alloc<BlCvRecordEntry>();
entry->mKey = key;
entry->mNext = mBuckets[hashKey];
mBuckets[hashKey] = entry;
mNumEntries++;
entry->mRecordIndex = mCodeView->mSymRecordsWriter.GetStreamPos();
return entry->mRecordIndex;
}
//////////////////////////////////////////////////////////////////////////
BlCvTypeWorkThread::BlCvTypeWorkThread()
{
mTypesDone = false;
mThreadDone = false;
}
BlCvTypeWorkThread::~BlCvTypeWorkThread()
{
Stop();
}
void BlCvTypeWorkThread::Stop()
{
mTypesDone = true;
mWorkEvent.Set();
WorkThread::Stop();
}
void BlCvTypeWorkThread::Run()
{
// Any failure is instant-abort
while (!mCodeView->mContext->mFailed)
{
BlCvTypeSource* typeSource = NULL;
mCritSect.Lock();
if (!mTypeSourceWorkQueue.empty())
{
typeSource = mTypeSourceWorkQueue.front();
mTypeSourceWorkQueue.pop_front();
}
mCritSect.Unlock();
if (typeSource == NULL)
{
if (mTypesDone)
break;
BP_ZONE("Waiting");
mWorkEvent.WaitFor();
continue;
}
BF_ASSERT(!typeSource->mIsDone);
if (typeSource->mTypeServerLib != NULL)
{
BP_ZONE("Load TypeServerLib");
if (!typeSource->mTypeServerLib->Load(typeSource->mTypeServerLib->mFileName))
{
mCodeView->mContext->Fail(StrFormat("Failed to load: %s", typeSource->mTypeServerLib->mFileName.c_str()));
}
}
else
{
BP_ZONE("Load Obj");
typeSource->mTPI.ScanTypeData();
typeSource->mTPI.ParseTypeData();
}
typeSource->mIsDone = true;
//typeSource->mDoneSignal.Set();
// The module work thread may be waiting for this type source
mCodeView->mModuleWorkThread.mWorkEvent.Set();
}
// Wake up module work thread
mThreadDone = true;
mCodeView->mModuleWorkThread.mWorkEvent.Set();
}
void BlCvTypeWorkThread::Add(BlCvTypeSource* typeSource)
{
AutoCrit autoCrit(mCritSect);
mTypeSourceWorkQueue.push_back(typeSource);
mWorkEvent.Set();
}
//////////////////////////////////////////////////////////////////////////
BlCvModuleWorkThread::BlCvModuleWorkThread()
{
mModulesDone = false;
}
BlCvModuleWorkThread::~BlCvModuleWorkThread()
{
Stop();
}
void BlCvModuleWorkThread::Stop()
{
mModulesDone = true;
mWorkEvent.Set();
WorkThread::Stop();
}
void BlCvModuleWorkThread::Run()
{
{
BP_ZONE("Initial Waiting");
//mCodeView->mTypeWorkThread.WaitForFinish();
}
// Any failure is instant-abort
while (!mCodeView->mContext->mFailed)
{
BlCvModuleInfo* module = NULL;
mCritSect.Lock();
if (!mModuleWorkQueue.empty())
{
module = mModuleWorkQueue.front();
if ((module->mTypeSource == NULL) || (module->mTypeSource->mIsDone))
{
mModuleWorkQueue.pop_front();
}
else
{
module = NULL;
}
}
mCritSect.Unlock();
if (module == NULL)
{
if ((mModulesDone) && (mCodeView->mTypeWorkThread.mThreadDone))
break;
BP_ZONE("Waiting");
mWorkEvent.WaitFor();
continue;
}
BF_ASSERT(module->mSymStreamIdx == -1);
mCodeView->CreateModuleStream(module);
}
//
{
BP_ZONE("Waiting for TypeThread");
mCodeView->mTypeWorkThread.WaitForFinish();
}
if (!mCodeView->mContext->mFailed)
{
BP_ZONE("DoFinish");
mCodeView->DoFinish();
}
}
void BlCvModuleWorkThread::Add(BlCvModuleInfo* module)
{
AutoCrit autoCrit(mCritSect);
mModuleWorkQueue.push_back(module);
mWorkEvent.Set();
}
//////////////////////////////////////////////////////////////////////////
BlCvStreamWriter::BlCvStreamWriter()
{
mCurStream = NULL;
mCurStream = NULL;
mCurBlockPos = NULL;
mCurBlockEnd = NULL;
}
void BlCvStreamWriter::Start(BlCVStream * stream)
{
mCurStream = stream;
BF_ASSERT(mCurStream->mBlocks.empty());
}
void BlCvStreamWriter::Continue(BlCVStream * stream)
{
mCurStream = stream;
if (!stream->mBlocks.empty())
{
mCurBlockPos = (uint8*)mMsf->mBlocks[mCurStream->mBlocks.back()]->mData;
mCurBlockEnd = mCurBlockPos + CV_BLOCK_SIZE;
mCurBlockPos += stream->mSize % CV_BLOCK_SIZE;
}
}
void BlCvStreamWriter::End(bool flush)
{
if (flush)
{
for (auto block : mCurStream->mBlocks)
mMsf->FlushBlock(block);
}
mCurStream->mSize = GetStreamPos();
mCurBlockPos = NULL;
mCurBlockEnd = NULL;
mCurStream = NULL;
}
void BlCvStreamWriter::Write(const void* data, int size)
{
while (mCurBlockPos + size > mCurBlockEnd)
{
int writeBytes = (int)(mCurBlockEnd - mCurBlockPos);
if (writeBytes > 0)
{
memcpy(mCurBlockPos, data, writeBytes);
data = (uint8*)data + writeBytes;
size -= writeBytes;
}
int newBlock = mMsf->Alloc();
mCurStream->mBlocks.Add(newBlock);
mCurBlockPos = (uint8*)mMsf->mBlocks[newBlock]->mData;
mCurBlockEnd = mCurBlockPos + CV_BLOCK_SIZE;
}
if (size > 0)
{
memcpy(mCurBlockPos, data, size);
mCurBlockPos += size;
}
}
void BlCvStreamWriter::Write(ChunkedDataBuffer& buffer)
{
int size = buffer.GetSize();
buffer.SetReadPos(0);
while (buffer.mReadCurPtr + size > buffer.mReadNextAlloc)
{
int curSize = (int)(buffer.mReadNextAlloc - buffer.mReadCurPtr);
if (curSize > 0)
Write(buffer.mReadCurPtr, curSize);
buffer.NextReadPool();
size -= curSize;
}
Write(buffer.mReadCurPtr, size);
buffer.mReadCurPtr += size;
}
int BlCvStreamWriter::GetStreamPos()
{
return (int)((mCurStream->mBlocks.size() - 1)*CV_BLOCK_SIZE + (mCurBlockPos - (mCurBlockEnd - CV_BLOCK_SIZE)));
}
void BlCvStreamWriter::StreamAlign(int align)
{
PTR_ALIGN(mCurBlockPos, mCurBlockEnd - CV_BLOCK_SIZE, align);
}
void* BlCvStreamWriter::GetStreamPtr(int pos)
{
int blockNum = mCurStream->mBlocks[pos / CV_BLOCK_SIZE];
auto data = (uint8*)mMsf->mBlocks[blockNum]->mData;
return (uint8*)data + (pos % CV_BLOCK_SIZE);
}
//////////////////////////////////////////////////////////////////////////
BlCvStreamReader::BlCvStreamReader()
{
mMsf = NULL;
mBlockIdx = -1;
mCurBlockPos = NULL;
mCurBlockEnd = NULL;
}
void BlCvStreamReader::Open(BlCVStream* stream)
{
mCurStream = stream;
if (!mCurStream->mBlocks.empty())
{
mBlockIdx = 0;
mCurBlockPos = (uint8*)mMsf->mBlocks[stream->mBlocks[mBlockIdx]]->mData;
mCurBlockEnd = mCurBlockPos + CV_BLOCK_SIZE;
}
else
{
mBlockIdx = -1;
mCurBlockPos = NULL;
mCurBlockEnd = NULL;
}
}
// Pass NULL to data to make sure we have a mutable pointer into the stream. This can
// only work if we know the alignment of a stream and we are reading an aligned member
// with a size less than or equal to the stream's alignment
void* BlCvStreamReader::ReadFast(void* data, int size)
{
if (mCurBlockPos + size <= mCurBlockEnd)
{
// The FAST case, just return a pointer
void* ptr = mCurBlockPos;
mCurBlockPos += size;
return ptr;
}
void* ptr = data;
while (mCurBlockPos + size > mCurBlockEnd)
{
int readBytes = (int)(mCurBlockEnd - mCurBlockPos);
if (readBytes > 0)
{
memcpy(data, mCurBlockPos, readBytes);
data = (uint8*)data + readBytes;
size -= readBytes;
}
mBlockIdx++;
mCurBlockPos = (uint8*)mMsf->mBlocks[mCurStream->mBlocks[mBlockIdx]]->mData;
mCurBlockEnd = mCurBlockPos + CV_BLOCK_SIZE;
}
// We had to load new data but nothing got read in yet
if (ptr == data)
{
void* ptr = mCurBlockPos;
mCurBlockPos += size;
return ptr;
}
if (size > 0)
{
memcpy(data, mCurBlockPos, size);
mCurBlockPos += size;
}
return ptr;
}
void BlCvStreamReader::Seek(int size)
{
while (mCurBlockPos + size > mCurBlockEnd)
{
int readBytes = (int)(mCurBlockEnd - mCurBlockPos);
size -= readBytes;
mBlockIdx++;
mCurBlockPos = (uint8*)mMsf->mBlocks[mCurStream->mBlocks[mBlockIdx]]->mData;
mCurBlockEnd = mCurBlockPos + CV_BLOCK_SIZE;
}
mCurBlockPos += size;
}
int BlCvStreamReader::GetStreamPos()
{
return (int)(mBlockIdx*CV_BLOCK_SIZE + (mCurBlockPos - (mCurBlockEnd - CV_BLOCK_SIZE)));
}
//////////////////////////////////////////////////////////////////////////
#pragma comment(lib, "rpcrt4.lib")
BlCodeView::BlCodeView()
{
//mTagBufPtr = NULL;
mSymRecordsStream = -1;
mStat_TypeMapInserts = 0;
mStat_ParseTagFuncs = 0;
mSectStartFilePos = -1;
for (int i = 0; i < 5; i++)
mStreams.Alloc();
memset(mSignature, 0, sizeof(mSignature));
//uint32 sig[] = { 0x8BB4B1E6, 0x32C63441, 0xB5BD0FDC, 0x8206881A };
//uint32 sig[] = { 0x00000000, 0x00000001, 0x00000000, 0x00000000 };
//memcpy(mSignature, sig, 16);
UuidCreate((UUID*)&mSignature);
mAge = 1;
mGlobals.mCodeView = this;
mTypeWorkThread.mCodeView = this;
mModuleWorkThread.mCodeView = this;
mWriter.mMsf = &mMsf;
mSymRecordsWriter.mMsf = &mMsf;
AddToStringTable("");
}
BlCodeView::~BlCodeView()
{
for (auto pair : mTypeServerFiles)
delete pair.second;
}
void BlCodeView::Fail(const StringImpl& err)
{
mContext->Fail(err);
}
char* BlCodeView::StrDup(const char* str)
{
int len = (int)strlen(str);
char* newStr = (char*)mAlloc.AllocBytes(len + 1);
memcpy(newStr, str, len + 1);
return newStr;
}
void BlCodeView::NotImpl()
{
BF_FATAL("NotImpl");
}
void BlCodeView::FixSymAddress(void* oldDataStart, void* oldDataPos, void* outDataPos, BlCvModuleInfo* module, BlCvSymDataBlock* dataBlock, COFFRelocation*& nextReloc)
{
//BL_AUTOPERF_CV("BlCodeView::FixSymAddress");
int posOfs = (int)((uint8*)oldDataPos - (uint8*)oldDataStart) + dataBlock->mSourceSectOffset;
int posSect = posOfs + 4;
if ((nextReloc->mVirtualAddress != posOfs) || (nextReloc == dataBlock->mRelocEnd))
return;
auto objSym = &module->mSymInfo[nextReloc->mSymbolTableIndex];
int segmentIdx = -1;
int segmentOffset = -1;
if (objSym->mSym == NULL)
{
segmentIdx = objSym->mSegmentIdx;
segmentOffset = objSym->mSegmentOffset;
}
else
{
auto sym = objSym->mSym;
BF_ASSERT(sym != NULL);
if (sym != NULL)
{
if (sym->mKind == BlSymKind_WeakSymbol)
sym = mContext->ProcessSymbol(sym);
if (sym->mSegmentIdx >= 0)
{
segmentIdx = sym->mSegmentIdx;
segmentOffset = sym->mSegmentOffset;
}
else if (sym->mKind == BlSymKind_ImageBaseRel)
{
// Leave zeros
}
else if (sym->mKind == BlSymKind_Absolute)
{
*(int32*)(outDataPos) += sym->mParam;
*((int16*)outDataPos + 2) += (int)mContext->mOutSections.size(); // One past end is 'Abs' section
}
else if (sym->mKind == BlSymKind_ImportImp)
{
int segmentIdx = mContext->mIDataSeg->mSegmentIdx;
auto lookup = mContext->mImportLookups[sym->mParam];
int segmentOffset = lookup->mIDataIdx * 8;
/*auto segment = mContext->mSegments[segmentIdx];
auto outSection = mContext->mOutSections[segment->mOutSectionIdx];
*(int32*)(outDataPos) += (segment->mRVA - outSection->mRVA) + segmentOffset;
*((int16*)outDataPos + 2) += outSection->mIdx + 1;*/
}
else
{
// Invalid address
BF_FATAL("Invalid address");
}
}
}
if (segmentIdx != -1)
{
auto segment = mContext->mSegments[segmentIdx];
auto outSection = mContext->mOutSections[segment->mOutSectionIdx];
*(int32*)(outDataPos) += (segment->mRVA - outSection->mRVA) + segmentOffset;
*((int16*)outDataPos + 2) += outSection->mIdx + 1;
}
nextReloc++;
if (nextReloc->mVirtualAddress != posSect)
Fail("Symbol remap failure");
// It MUST be the same sym
nextReloc++;
}
int BlCodeView::StartStream(int streamIdx)
{
BF_ASSERT(mWriter.mCurStream == NULL);
BF_ASSERT(streamIdx <= 5);
if (streamIdx == -1)
{
streamIdx = (int)mStreams.size();
mStreams.Alloc();
}
mWriter.Start(mStreams[streamIdx]);
return streamIdx;
}
void BlCodeView::StartUnnamedStream(BlCVStream& stream)
{
mWriter.Start(&stream);
}
void BlCodeView::EndStream(bool flush)
{
mWriter.End(flush);
}
void BlCodeView::FlushStream(BlCVStream* stream)
{
for (auto block : stream->mBlocks)
mMsf.FlushBlock(block);
}
void BlCodeView::CvEncodeString(const StringImpl& str)
{
mWriter.Write((void*)str.c_str(), (int)str.length() + 1);
}
int BlCodeView::AddToStringTable(const StringImpl&str)
{
auto pairVal = mStrTabMap.insert(std::make_pair(str, -1));
if (pairVal.second)
{
pairVal.first->second = (int)mStrTab.length();
mStrTab.Append(str.c_str(), str.length());
}
return pairVal.first->second;
}
void BlCodeView::WriteStringTable(const StringImpl&strTab, std::unordered_map<String, int>& strTabMap)
{
mWriter.WriteT((int32)0xEFFEEFFE);
mWriter.WriteT(1); // Version
mWriter.WriteT((int32)strTab.length() + 1);
mWriter.Write((char*)strTab.c_str(), (int)strTab.length() + 1);
int bucketCount = (int)(strTabMap.size() * 1.25) + 1;
std::vector<uint32> buckets;
buckets.resize(bucketCount);
mWriter.WriteT(bucketCount);
for (auto pair : mStrTabMap)
{
int idx = pair.second;
uint32 hash = BlHash::HashStr_PdbV1(pair.first.c_str());
for (int ofs = 0; ofs < bucketCount; ofs++)
{
int slot = (hash + ofs) % bucketCount;
if (slot == 0)
continue; // 0 is reserved
if (buckets[slot] != 0)
continue;
buckets[slot] = idx;
break;
}
}
mWriter.Write((void*)&buckets[0], (int)buckets.size() * 4);
mWriter.WriteT((int)strTabMap.size());
}
void BlCodeView::GetOutSectionAddr(int segIdx, int segOfs, uint16& cvSectIdx, long& cvSectOfs)
{
auto segment = mContext->mSegments[segIdx];
auto outSect = mContext->mOutSections[segment->mOutSectionIdx];
cvSectIdx = outSect->mIdx + 1;
cvSectOfs = (segment->mRVA - outSect->mRVA) + segOfs;
}
void BlCodeView::StartSection(int sectionNum)
{
mSectStartFilePos = mWriter.GetStreamPos();
BF_ASSERT((mSectStartFilePos % 4) == 0);
mWriter.WriteT((int32)sectionNum);
mWriter.WriteT((int32)0); // Temporary - size
}
int BlCodeView::EndSection()
{
int totalLen = mWriter.GetStreamPos() - mSectStartFilePos - 8;
*((int32*)mWriter.GetStreamPtr(mSectStartFilePos + 4)) = totalLen;
return totalLen + 8;
}
bool BlCodeView::Create(const StringImpl& fileName)
{
if (!mMsf.Create(fileName))
return false;
mSymRecordsStream = StartStream();
mSymRecordsWriter.Start(mWriter.mCurStream);
EndStream(false);
CreateLinkerModule();
return true;
}
void BlCodeView::StartWorkThreads()
{
mTypeWorkThread.Start();
mModuleWorkThread.Start();
}
void BlCodeView::StopWorkThreads()
{
BL_AUTOPERF_CV("BlCodeView::StopWorkThread");
mTypeWorkThread.Stop();
mModuleWorkThread.Stop();
}
void BlCodeView::CreatePDBInfoStream()
{
//PDB Info Stream
StartStream(1);
mWriter.WriteT((int32)20000404); //VC70
mWriter.WriteT((int32)mContext->mTimestamp);
mWriter.WriteT((int32)mAge);
mWriter.WriteT(mSignature);
int strCount = 0;
String namesStr;
for (auto& stream : mStreams)
{
if (!stream->mName.empty())
{
namesStr += stream->mName;
namesStr.Append((char)0);
strCount++;
}
}
// Named string table
mWriter.WriteT((int32)namesStr.length());
mWriter.Write(namesStr.c_str(), (int)namesStr.length());
mWriter.WriteT((int32)strCount); // actual item count
mWriter.WriteT((int32)strCount * 2); // max item count. What should this be?
mWriter.WriteT((int32)1); // usedLength
int32 usedBits = 0;
// This is supposed to be hashed but we just fill in the correct number of bits.
for (int i = 0; i < strCount; i++)
usedBits |= 1 << i;
mWriter.WriteT((int32)usedBits);
mWriter.WriteT((int32)0); // deletedLength
int strTabIdx = 0;
for (int streamIdx = 0; streamIdx < (int)mStreams.size(); streamIdx++)
{
auto& stream = mStreams[streamIdx];
if (!stream->mName.empty())
{
mWriter.WriteT((int32)strTabIdx);
mWriter.WriteT((int32)streamIdx);
strTabIdx += (int)stream->mName.length() + 1;
}
}
// Features info
mWriter.WriteT((int32)0);
mWriter.WriteT((int32)20140508); // PdbImplVC140
EndStream();
}
void BlCodeView::WriteTypeData(int streamId, BlTypeInfo& typeInfo)
{
int hashStream = StartStream();
int pos = 0;
uint8 tempData[0x10002];
int hashBucketsSize = 0x3FFFF;
int numTags = typeInfo.mCurTagId - 0x1000;
struct _JumpEntry
{
int mTypeIdx;
int mOfs;
};
Array<_JumpEntry> indexEntries;
uint8* curChunk = NULL;
typeInfo.mData.SetReadPos(0);
for (int tagId = 0x1000; tagId < typeInfo.mCurTagId; tagId++)
{
// Align
typeInfo.mData.mReadCurPtr = (uint8*)(((intptr)typeInfo.mData.mReadCurPtr + 3) & ~3);
// Chunks are every 8k, which is perfect for the jump table
if (curChunk != typeInfo.mData.mReadCurAlloc)
{
indexEntries.Add({ tagId, typeInfo.mData.GetReadPos() });
curChunk = typeInfo.mData.mReadCurAlloc;
}
uint8* dataHead = (uint8*)typeInfo.mData.FastRead(tempData, 4);
// Pointer not valid
uint8* data = dataHead;
int trLength = GET(uint16);
if (dataHead == tempData)
{
typeInfo.mData.Read(tempData + 4, trLength - 2);
}
else
{
uint8* leafData = (uint8*)typeInfo.mData.FastRead(tempData + 4, trLength - 2);
if (leafData != dataHead + 4)
{
memcpy(tempData, dataHead, 4);
dataHead = tempData;
}
}
data = dataHead;
int32 hashVal = BlHash::GetTypeHash(data) % hashBucketsSize;
mWriter.WriteT(hashVal);
//typeInfo.mData.TryGetPtr
}
mWriter.Write(&indexEntries[0], (int)indexEntries.size() * 8);
// Adjuster
/*mWriter.WriteT(0); // Adjust count
mWriter.WriteT(0); // Adjust capacity
mWriter.WriteT(0); // Used len
mWriter.WriteT(0); // Deleted len*/
EndStream();
int hashValsSize = numTags * 4;
int hashTypeInfoSize = (int)indexEntries.size() * 8;
int adjusterSize = 0;
StartStream(streamId);
mWriter.WriteT(0x0131ca0b); // ver
mWriter.WriteT(56); // headerSize
mWriter.WriteT(0x1000); // minVal
mWriter.WriteT(typeInfo.mCurTagId); // maxVal
mWriter.WriteT(typeInfo.mData.GetSize()); // followSize - should be total section size - headerSize(56)
mWriter.WriteT((int16)hashStream); // hashStream
mWriter.WriteT((int16)-1); // hashStreamPadding
mWriter.WriteT(4); // hashKeySize
mWriter.WriteT(hashBucketsSize); // hashBucketsSize
mWriter.WriteT(0); // hashValsOffset
mWriter.WriteT(hashValsSize); // hashValsSize
mWriter.WriteT(hashValsSize); // hashTypeInfoOffset
mWriter.WriteT(hashTypeInfoSize); // hashTypeInfoSize
mWriter.WriteT(hashValsSize + hashTypeInfoSize); // hashAdjOffset
mWriter.WriteT(adjusterSize); // hashAdjSize
typeInfo.mData.SetReadPos(0);
mWriter.Write(typeInfo.mData);
EndStream();
}
void BlCodeView::CreateTypeStream()
{
//BL_AUTOPERF_CV("BlCodeView::CreateTypeStream");
BP_ZONE("BlCodeView::CreateTypeStream");
WriteTypeData(2, mTPI);
}
void BlCodeView::CreateIPIStream()
{
//BL_AUTOPERF_CV("BlCodeView::CreateIPIStream");
BP_ZONE("BlCodeView::CreateIPIStream");
WriteTypeData(4, mIPI);
}
void BlCodeView::WriteRecordMap(BlCvRecordMap* recordMap)
{
mWriter.WriteT((int32)-1); // verSig
mWriter.WriteT((int32)0xf12f091a); // verHdr
mWriter.WriteT((int32)(recordMap->mNumEntries * 4 * 2)); // sizeHr
int bucketsCount = 0;
for (int hashKey = 0; hashKey < 4096; hashKey++)
if (recordMap->mBuckets[hashKey] != NULL)
bucketsCount++;
mWriter.WriteT((int32)(0x81 * 4 + bucketsCount * 4)); // sizeBuckets
uint32 bucketBits[0x80] = { 0 };
int32 buckets[4096];
int bucketIdx = 0;
// HR
int hrIdx = 0;
for (int hashKey = 0; hashKey < 4096; hashKey++)
{
auto checkEntry = recordMap->mBuckets[hashKey];
if (checkEntry == NULL)
continue;
bucketBits[hashKey / 32] |= 1 << (hashKey % 32);
buckets[bucketIdx++] = hrIdx;
while (checkEntry != NULL)
{
mWriter.WriteT(checkEntry->mRecordIndex + 1);
mWriter.WriteT(1);
checkEntry = checkEntry->mNext;
hrIdx++;
}
}
for (int i = 0; i < 0x80; i++)
mWriter.WriteT((int32)bucketBits[i]);
mWriter.WriteT(0);
for (int i = 0; i < bucketIdx; i++)
mWriter.WriteT(buckets[i] * 12);
}
int BlCodeView::CreateGlobalStream()
{
BP_ZONE("BlCodeView::CreateGlobalStream");
int globalStreamIdx = StartStream();
WriteRecordMap(&mGlobals);
EndStream();
return globalStreamIdx;
}
int BlCodeView::CreatePublicStream()
{
BP_ZONE("BlCodeView::CreatePublicStream");
int publicStreamIdx = StartStream();
BlCvRecordMap publics;
struct _SortEntry
{
uint64 mAddr;
int mRecordIdx;
};
Array<_SortEntry> addrMap;
addrMap.Reserve(mContext->mSymTable.mMap.size());
for (auto symPair : mContext->mSymTable.mMap)
{
auto sym = symPair.second;
if ((sym->mSegmentIdx >= 0) || (sym->mKind == BlSymKind_Absolute))
{
bool isAbs = sym->mKind == BlSymKind_Absolute;
#define ADDR_FLAG_ABS 0x8000000000000000L
auto segment = (isAbs) ? (BlSegment*)NULL : mContext->mSegments[sym->mSegmentIdx];
int pubSymLen = (int)offsetof(PUBSYM32, name);
int nameSize = (int)strlen(sym->mName) + 1;
PUBSYM32 pubSym = { 0 };
pubSym.reclen = pubSymLen + nameSize - 2;
pubSym.rectyp = S_PUB32;
if (isAbs)
{
pubSym.seg = (int)mContext->mOutSections.size(); // One past end is 'Abs' section
pubSym.off = sym->mSegmentOffset;
}
else
{
auto outSection = mContext->mOutSections[segment->mOutSectionIdx];
if ((outSection->mCharacteristics & IMAGE_SCN_MEM_EXECUTE) != 0)
{
pubSym.pubsymflags.fFunction = 1;
pubSym.pubsymflags.fCode = 1;
}
pubSym.off = (segment->mRVA - outSection->mRVA) + sym->mSegmentOffset;
pubSym.seg = outSection->mIdx + 1;
}
int addBytes = ((nameSize + 2 + 3) & ~3) - (nameSize + 2);
pubSym.reclen += addBytes;
int idx = mSymRecordsWriter.GetStreamPos();
if (isAbs)
addrMap.Add({ ADDR_FLAG_ABS + sym->mSegmentOffset, idx});
else
addrMap.Add({ (uint64)(segment->mRVA + sym->mSegmentOffset), idx });
mSymRecordsWriter.Write(&pubSym, pubSymLen);
mSymRecordsWriter.Write(sym->mName, nameSize);
if (addBytes > 0)
{
int zero = 0;
mSymRecordsWriter.Write(&zero, addBytes);
}
publics.Insert(sym->mName, idx);
}
}
std::sort(addrMap.begin(), addrMap.end(), [](const _SortEntry& lhs, const _SortEntry& rhs) { return lhs.mAddr < rhs.mAddr; });
int bucketsCount = 0;
for (int hashKey = 0; hashKey < 4096; hashKey++)
if (publics.mBuckets[hashKey] != NULL)
bucketsCount++;
int symHashSize = 16 + (int32)(publics.mNumEntries * 4 * 2) + (int32)(0x81 * 4 + bucketsCount * 4);
int addrHashSize = (int)addrMap.size() * 4;
mWriter.WriteT(symHashSize); // symHashSize
mWriter.WriteT(addrHashSize); // addrMapSize
mWriter.WriteT(0); // thunkCount
mWriter.WriteT(0); // thunkSize
mWriter.WriteT(0); // thunkTableStream
mWriter.WriteT(0); // thunkTableOfs
mWriter.WriteT(0); // thunkSectCount
int symHashPos = mWriter.GetStreamPos();
WriteRecordMap(&publics);
BF_ASSERT(mWriter.GetStreamPos() - symHashPos == symHashSize);
for (auto& addrMapEntry : addrMap)
{
mWriter.WriteT(addrMapEntry.mRecordIdx);
}
EndStream();
return publicStreamIdx;
}
void BlCodeView::FinishSymRecords()
{
BP_ZONE("BlCodeView::FinishSymRecords");
BlCvStreamReader reader;
reader.mMsf = &mMsf;
reader.Open(mStreams[mSymRecordsStream]);
auto itr = mSymRecordDeferredPositions.begin();
auto endItr = mSymRecordDeferredPositions.end();
int wantPos = mSymRecordsWriter.GetStreamPos();
int curPos = 0;
while (itr != endItr)
{
int wantOfs = *itr;
reader.Seek(wantOfs - curPos);
curPos = wantOfs;
int16 hdrBuf[2];
int16* hdr = (int16*)reader.ReadFast(&hdrBuf, 4);
int16 symLen = hdr[0];
int16 symType = hdr[1];
int wantSeekBytes = symLen - 2;
int addrOfs;
switch (symType)
{
case S_LPROC32:
case S_GPROC32:
addrOfs = offsetof(PROCSYM32, off);
break;
case S_LTHREAD32:
case S_GTHREAD32:
addrOfs = offsetof(THREADSYM32, off);
break;
case S_LDATA32:
case S_GDATA32:
addrOfs = offsetof(DATASYM32, off);
break;
default:
NotImpl();
break;
}
reader.Seek(addrOfs - 4);
int32* ofsPtr = (int32*)reader.ReadFast(NULL, 4);
int16* segPtr = (int16*)reader.ReadFast(NULL, 2);
auto segment = mContext->mSegments[*segPtr];
auto outSection = mContext->mOutSections[segment->mOutSectionIdx];
*ofsPtr += segment->mRVA - outSection->mRVA;
*segPtr = outSection->mIdx + 1;
reader.Seek(wantSeekBytes - addrOfs - 2);
curPos += 2 + symLen;
BF_ASSERT(curPos == reader.GetStreamPos());
++itr;
}
mSymRecordsWriter.End();
}
/*int BlCodeView::CreateSymRecordStream()
{
int symRecordStreamIdx = StartStream();
//mSymRecords.Read(mFS, mSymRecords.GetSize());
//mWriter.Write(mSymRecords);
EndStream();
return symRecordStreamIdx;
}*/
int BlCodeView::CreateSectionHeaderStream()
{
int symRecordStreamIdx = StartStream();
mWriter.Write(mSectionHeaders.GetPtr(), mSectionHeaders.GetSize());
EndStream();
return symRecordStreamIdx;
}
void BlCodeView::CreateDBIStream()
{
int globalStreamIdx = CreateGlobalStream();
int publicStreamIdx = CreatePublicStream();
//int symRecordStreamIdx = CreateSymRecordStream();
int symRecordStreamIdx = mSymRecordsStream;
int sectionHeaderStreamIdx = CreateSectionHeaderStream();
StartStream(3);
mWriter.WriteT((int32)-1); // VersionSignature
mWriter.WriteT((int32)19990903); // VersionHeader V70
mWriter.WriteT((int32)mAge);
mWriter.WriteT((int16)globalStreamIdx);
//int buildNum = (1 << 15) | (12 << 8) | (0); // Fake as 'NewVersionFormat' 12.0 (MSVC 2013)
mWriter.WriteT((int16)0x8e00);
mWriter.WriteT((int16)publicStreamIdx);
mWriter.WriteT((int16)0x5e92); // PdbDllVersion
mWriter.WriteT((int16)symRecordStreamIdx);
mWriter.WriteT((int16)0); // PdbDllRbld
int substreamSizesPos = mWriter.GetStreamPos();
int32* sizePtrs = (int32*)mWriter.mCurBlockPos;
mWriter.WriteT((int32)0); // ModInfoSize
mWriter.WriteT((int32)0); // SectionContributionSize
mWriter.WriteT((int32)0); // SectionMapSize
mWriter.WriteT((int32)0); // SourceInfoSize
mWriter.WriteT((int32)0); // TypeServerSize
mWriter.WriteT((int32)0); // MFCTypeServerIndex
mWriter.WriteT((int32)0); // OptionalDbgHeaderSize
mWriter.WriteT((int32)0); // ECSubstreamSize
int16 flags = 0; // WasIncrementallyLinked, ArePrivateSymbolsStripped, HasConfictingTypes (?)
mWriter.WriteT((int16)flags);
mWriter.WriteT((int16)0x8664); // Machine type
mWriter.WriteT((int32)0); // Padding
struct _SectionContribEntry
{
uint32 mSectionIdx;
int32 mOffset;
int32 mSize;
uint32 mCharacteristics;
uint32 mModuleIdx;
uint32 mDataCrc;
uint32 mRelocCrc;
};
//////////////////////////////////////////////////////////////////////////
// ModuleInfo
int curPos = mWriter.GetStreamPos();
for (auto moduleInfo : mModuleInfo)
{
mWriter.WriteT((int32)0); // Unused
_SectionContribEntry contribEntry = { 0 };
if (!moduleInfo->mContrib.mCharacteristics != 0)
{
auto& contrib = moduleInfo->mContrib;
auto blSection = mContext->mSegments[contrib.mBlSectionIdx];
auto outSection = mContext->mOutSections[blSection->mOutSectionIdx];
contribEntry.mCharacteristics = contrib.mCharacteristics;
contribEntry.mSectionIdx = outSection->mIdx + 1;
contribEntry.mOffset = (blSection->mRVA - outSection->mRVA) + contrib.mBlSectionOfs;
contribEntry.mSize = contrib.mSize;
contribEntry.mModuleIdx = moduleInfo->mIdx;
//TODO: DataCRC, RelocCRC
}
mWriter.WriteT(contribEntry);
int16 flags = 0; //
mWriter.WriteT(flags);
mWriter.WriteT((int16)moduleInfo->mSymStreamIdx);
int symSize = 4;
for (auto& block : moduleInfo->mSymData)
{
BF_ASSERT(block.mOutSize >= 0);
symSize += block.mOutSize;
}
BF_ASSERT(symSize % 4 == 0);
mWriter.WriteT(symSize);
mWriter.WriteT(0); // C11-style LineInfo size
mWriter.WriteT(moduleInfo->mLineInfoSize); //C13-style LineInfo size
mWriter.WriteT((int32)moduleInfo->mFileInfos.size()); // Source file count
mWriter.WriteT((int32)0); // Unusued
mWriter.WriteT((int32)0); // SourceFileNameIndex
// What about special "* Linker *" module? The only case this should be non-zero?
mWriter.WriteT((int32)0); // PdbFilePathNameIndex
if (!moduleInfo->mName.empty())
CvEncodeString(moduleInfo->mName);
else
CvEncodeString(moduleInfo->mObjectData->mName);
if (moduleInfo->mObjectData != NULL)
CvEncodeString(moduleInfo->mObjectData->mName);
else
mWriter.WriteT((uint8)0);
mWriter.StreamAlign(4);
}
int32 modInfoSize = mWriter.GetStreamPos() - curPos;
//////////////////////////////////////////////////////////////////////////
// SectionContributionSize
curPos = mWriter.GetStreamPos();
mWriter.WriteT((int32)(0xeffe0000 + 19970605)); // Ver60
for (auto& outSection : mContext->mOutSections)
{
for (auto& segment : outSection->mSegments)
{
if (segment->mSegmentIdx >= mContribMap.mSegments.size())
continue;
for (auto& contrib : mContribMap.mSegments[segment->mSegmentIdx]->mContribs)
{
_SectionContribEntry contribEntry = { 0 };
contribEntry.mCharacteristics = contrib.mCharacteristics;
contribEntry.mSectionIdx = outSection->mIdx + 1;
contribEntry.mOffset = (segment->mRVA - outSection->mRVA) + contrib.mBlSectionOfs;
contribEntry.mSize = contrib.mSize;
contribEntry.mModuleIdx = contrib.mModuleIdx;
mWriter.WriteT(contribEntry);
}
}
}
int32 sectionContributionSize = mWriter.GetStreamPos() - curPos;
//////////////////////////////////////////////////////////////////////////
// SectionMap
curPos = mWriter.GetStreamPos();
mWriter.WriteT((int16)mContext->mOutSections.size()); // Section count
mWriter.WriteT((int16)mContext->mOutSections.size()); // Log section count
for (auto outSection : mContext->mOutSections)
{
int16 flags = (1 << 3) | (1 << 8); // AddressIs32Bit, IsSelector
if ((outSection->mCharacteristics & IMAGE_SCN_MEM_READ) != 0)
flags |= (1 << 0);
if ((outSection->mCharacteristics & IMAGE_SCN_MEM_WRITE) != 0)
flags |= (1 << 1);
if ((outSection->mCharacteristics & IMAGE_SCN_MEM_EXECUTE) != 0)
flags |= (1 << 2);
mWriter.WriteT(flags);
mWriter.WriteT((int16)0); // Logical overlay number - ?
mWriter.WriteT((int16)0); // Group
mWriter.WriteT((int16)(outSection->mIdx + 1)); // Frame
mWriter.WriteT((int16)-1); // Section name string idx
mWriter.WriteT((int16)-1); // Class name string idx
mWriter.WriteT((int32)0); // Offset
mWriter.WriteT((int32)outSection->mVirtualSize); // SectionLength
}
int32 sectionMapSize = mWriter.GetStreamPos() - curPos;
//////////////////////////////////////////////////////////////////////////
// FileInfo
curPos = mWriter.GetStreamPos();
mWriter.WriteT((int16)mModuleInfo.size());
int numSourceFiles = 0;
for (auto module : mModuleInfo)
numSourceFiles += (int)module->mFileInfos.size();
mWriter.WriteT((int16)numSourceFiles); // NumSourceFiles - this is ignored now since it would only allow 64k files
// ModIndices
int curFileIdx = 0;
for (auto module : mModuleInfo)
{
mWriter.WriteT((int16)curFileIdx);
curFileIdx += (int)module->mFileInfos.size();
}
// ModFileCounts
for (auto module : mModuleInfo)
mWriter.WriteT((int16)module->mFileInfos.size());
int strIdx = 0;
for (auto module : mModuleInfo)
{
for (auto& cvFileInfo : module->mFileInfos)
{
char* str = (char*)mStrTab.c_str() + cvFileInfo.mStrTableIdx;
mWriter.WriteT((int32)strIdx);
strIdx += (int)strlen(str) + 1;
}
}
for (auto module : mModuleInfo)
{
for (auto& cvFileInfo : module->mFileInfos)
{
char* str = (char*)mStrTab.c_str() + cvFileInfo.mStrTableIdx;
mWriter.Write(str, (int)strlen(str) + 1);
}
}
mWriter.StreamAlign(4);
int32 fileInfoSize = mWriter.GetStreamPos() - curPos;
//////////////////////////////////////////////////////////////////////////
// Type Server
curPos = mWriter.GetStreamPos();
int typeServerSize = mWriter.GetStreamPos() - curPos;
//////////////////////////////////////////////////////////////////////////
// EC
curPos = mWriter.GetStreamPos();
String ecStrTab;
std::unordered_map<String, int> ecStrTabMap;
WriteStringTable(ecStrTab, ecStrTabMap);
int ecSize = mWriter.GetStreamPos() - curPos;
//////////////////////////////////////////////////////////////////////////
// Optional debug header
curPos = mWriter.GetStreamPos();
mWriter.WriteT((int16)-1); // fpo
mWriter.WriteT((int16)-1); // exception
mWriter.WriteT((int16)-1); // fixup
mWriter.WriteT((int16)-1); // omap_to_src
mWriter.WriteT((int16)-1); // omap_from_src
mWriter.WriteT((int16)sectionHeaderStreamIdx); // section_header
mWriter.WriteT((int16)-1); // token_rid_map
mWriter.WriteT((int16)-1); // x_data
mWriter.WriteT((int16)-1); // p_data
mWriter.WriteT((int16)-1); // new_fpo
mWriter.WriteT((int16)-1); // section_header_origin
int optionalDbgHeaderSize = mWriter.GetStreamPos() - curPos;
// Go back and fill in substream sizes
sizePtrs[0] = modInfoSize;
sizePtrs[1] = sectionContributionSize;
sizePtrs[2] = sectionMapSize;
sizePtrs[3] = fileInfoSize;
sizePtrs[4] = typeServerSize;
sizePtrs[5] = 0; // MFCTypeServerIndex
// Note: the position of the optionalDbgHeader and ecSize seem reversed, but this is correct
sizePtrs[6] = optionalDbgHeaderSize;
sizePtrs[7] = ecSize;
EndStream();
}
void BlCodeView::CreateNamesStream()
{
StartStream();
mWriter.mCurStream->mName = "/names";
WriteStringTable(mStrTab, mStrTabMap);
EndStream();
}
void BlCodeView::CreateLinkInfoStream()
{
StartStream();
mWriter.mCurStream->mName = "/LinkInfo";
EndStream();
}
void BlCodeView::CreateHeaderBlockStream()
{
StartStream();
mWriter.mCurStream->mName = "/src/headerblock";
EndStream();
}
bool BlCodeView::FixTPITag(BlCvModuleInfo* module, unsigned long& typeId)
{
if (typeId < 0x1000)
return true;
//BL_AUTOPERF_CV("BlCodeView::FixTPITag");
auto& tpi = module->mTypeSource->mTPI;
if (tpi.mCvMinTag == -1)
{
typeId = 0;
return false;
}
typeId = tpi.GetMasterTPITag(typeId);
return true;
}
bool BlCodeView::FixIPITag(BlCvModuleInfo* module, unsigned long& typeId)
{
if (typeId < 0x1000)
return true;
//BL_AUTOPERF_CV("BlCodeView::FixTPITag");
auto ipi = module->mTypeSource->mIPI;
int masterTag = ipi->GetMasterIPITag(typeId);
/*if ((masterTag & BlTypeMapFlag_InfoExt_ProcId_TypeOnly) != 0)
{
// Force loading of whole type now
module->mTypeSource->mIPI->ParseTag(typeId, true);
masterTag = ipi->GetMasterIPITag(typeId);
}
if ((masterTag & BlTypeMapFlag_InfoExt_ProcId_Resolved) != 0)
{
int extId = masterTag & BlTypeMapFlag_InfoExt_MASK;
masterTag = module->mTypeSource->mIPI->mInfoExts[extId].mMasterTag;
}*/
typeId = masterTag;
return true;
}
bool BlCodeView::FixIPITag_Member(BlCvModuleInfo* module, unsigned long& typeId)
{
if (typeId == 0)
return true;
//BL_AUTOPERF_CV("BlCodeView::FixIPITag");
auto ipi = module->mTypeSource->mIPI;
int memberTag = ipi->mElementMap[typeId - ipi->mCvMinTag];
BF_ASSERT(memberTag != -1);
typeId = memberTag;
/*typeId = ipi->GetMasterIPITag(typeId);
if ((typeId & BlTypeMapFlag_InfoExt_ProcId_TypeOnly) != 0)
typeId = typeId & BlTypeMapFlag_InfoExt_MASK;
else if ((typeId & BlTypeMapFlag_InfoExt_ProcId_Resolved) != 0)
{
int extId = typeId & BlTypeMapFlag_InfoExt_MASK;
typeId = module->mTypeSource->mIPI->mInfoExts[extId].mMemberMasterTag;
}
else
{
BF_FATAL("No member found");
}*/
return true;
}
void BlCodeView::CreateModuleStreamSyms(BlCvModuleInfo* module, BlCvSymDataBlock* dataBlock, int dataOfs)
{
//BL_AUTOPERF_CV("BlCodeView::CreateModuleStreamSyms");
int streamStartPos = mWriter.GetStreamPos();
#define DECL_SYM(symType, symName) \
symType& old_##symName = *(symType*)dataStart; \
symType& symName = *((symType*)(dataOut += sizeof(symType)) - 1); \
symName = old_##symName;
#define _FIX_SYM_ADDRESS(ofsName) \
FixSymAddress(sectionStart, &old_##ofsName, &ofsName, module, dataBlock, nextReloc)
#define FIX_SYM_ADDRESS(ofsName) \
_FixSymAddress(&old_##ofsName, &ofsName)
#define FIXTPI(typeVal) \
FixTPITag(module, typeVal)
#define FIXIPI(typeVal) \
FixIPITag(module, typeVal)
// For FIXTPI, if we fail to lookup type then we just don't include this symbol.
// This can happen when we have a TYPESERVER but don't have the referenced PDB
/*#define FIXTPI(typeVal) \
if (!FixType(module, typeVal)) \
{ \
dataOut = dataOutStart; \
data = dataEnd; \
continue; \
}*/
COFFRelocation* nextReloc = dataBlock->mRelocStart;
int dataOutMaxSize = dataBlock->mSize * 2; // Alignment may add size
//uint8* dataOut = new uint8[dataOutMaxSize];
//uint8* dataOutHead = dataOut;
//uint8* dataOutMax = dataOut + dataOutMaxSize;
const static int MAX_BLOCK_DEPTH = 256;
int blockIdx = 0;
//int blockPositions[MAX_BLOCK_DEPTH];
int blockPtrs[MAX_BLOCK_DEPTH];
const char* lastProcName = NULL;
int curStreamPos = streamStartPos;
int streamDataOfs = -streamStartPos + dataOfs;
static int procId = 0;
uint8* data = (uint8*)dataBlock->mData;
uint8* sectionStart = data;
uint8* sectionEnd = data + dataBlock->mSize;
uint8 dataChunk[0x10000];
auto _SkipSymAddress = [&](void* oldDataPos, void* outDataPos)
{
int posOfs = (int)((uint8*)oldDataPos - (uint8*)sectionStart) + dataBlock->mSourceSectOffset;
int posSect = posOfs + 4;
if ((nextReloc->mVirtualAddress != posOfs) || (nextReloc == dataBlock->mRelocEnd))
return;
nextReloc++;
if (nextReloc->mVirtualAddress != posSect)
Fail("Symbol remap failure");
// It MUST be the same sym
nextReloc++;
};
int deferredOutIdx = -1;
bool addrIsInvalid = false;
auto _FixSymAddress = [&](void* oldDataPos, void* outDataPos)
{
int posOfs = (int)((uint8*)oldDataPos - (uint8*)sectionStart) + dataBlock->mSourceSectOffset;
int posSect = posOfs + 4;
if ((nextReloc->mVirtualAddress != posOfs) || (nextReloc == dataBlock->mRelocEnd))
return;
auto objSym = &module->mSymInfo[nextReloc->mSymbolTableIndex];
int segmentIdx = -1;
int segmentOffset = -1;
if (objSym->mKind == BlObjectDataSymInfo::Kind_Section)
{
auto& sectInfo = module->mSectInfos[objSym->mSectionNum - 1];
segmentIdx = sectInfo.mSegmentIdx;
segmentOffset = sectInfo.mSegmentOffset;
}
else
{
segmentIdx = objSym->mSegmentIdx;
segmentOffset = objSym->mSegmentOffset;
}
if (segmentIdx != -1)
{
auto segment = mContext->mSegments[segmentIdx];
bool deferAddr = true;
if (deferAddr)
{
int outOfs = (int)((uint8*)outDataPos - dataChunk);
deferredOutIdx = curStreamPos + outOfs;
*(int32*)(outDataPos) += segmentOffset;
*((int16*)outDataPos + 2) += segmentIdx;
}
else
{
auto outSection = mContext->mOutSections[segment->mOutSectionIdx];
*(int32*)(outDataPos) += (segment->mRVA - outSection->mRVA) + segmentOffset;
*((int16*)outDataPos + 2) += outSection->mIdx + 1;
}
}
else
{
addrIsInvalid = true;
}
nextReloc++;
if (nextReloc->mVirtualAddress != posSect)
Fail("Symbol remap failure");
// It MUST be the same sym
nextReloc++;
};
while (data < sectionEnd)
{
int symLen;
int symType;
uint8* dataOut = dataChunk;
uint8* dataStart = data;
uint8* dataOutStart = dataChunk;
uint8* dataEnd;
uint8* dataOutEnd;
symLen = GET(uint16);
dataEnd = data + symLen;
dataOutEnd = dataChunk + symLen + 2;
symType = GET(uint16);
bool skipEntry = false;
const char* globalsName = NULL;
bool isProcRef = false;
deferredOutIdx = -1;
addrIsInvalid = false;
switch (symType)
{
case S_OBJNAME:
{
DECL_SYM(OBJNAMESYM, objNameSym);
}
break;
case S_COMPILE3:
{
DECL_SYM(COMPILESYM3, compileSym);
}
break;
case S_ENVBLOCK:
{
DECL_SYM(ENVBLOCKSYM, envBlock);
}
break;
case S_BUILDINFO:
{
BUILDINFOSYM& buildInfoSym = *(BUILDINFOSYM*)dataStart;
skipEntry = true;
}
break;
case S_CONSTANT:
{
struct _ConstSymShort
{
unsigned short reclen; // Record length
unsigned short rectyp; // S_CONSTANT or S_MANCONSTANT
CV_typ_t typind; // Type index (containing enum if enumerate) or metadata token
};
CONSTSYM& oldConstSym = *(CONSTSYM*)dataStart;
globalsName = (char*)oldConstSym.name;
DECL_SYM(_ConstSymShort, constSym);
FIXTPI(constSym.typind);
skipEntry = true;
}
break;
case S_UDT:
{
DECL_SYM(UDTSYM, udtSym);
FIXTPI(udtSym.typind);
//TODO: JUST TESTING!
//udtSym.typind = 0x0074;
globalsName = (const char*)udtSym.name;
skipEntry = true;
}
break;
case S_LDATA32:
case S_GDATA32:
{
DECL_SYM(DATASYM32, dataSym);
FIX_SYM_ADDRESS(dataSym.off);
FIXTPI(dataSym.typind);
globalsName = (char*)old_dataSym.name;
skipEntry = true;
}
break;
case S_GTHREAD32:
case S_LTHREAD32:
{
DECL_SYM(THREADSYM32, threadSym);
FIX_SYM_ADDRESS(threadSym.off);
FIXTPI(threadSym.typind);
globalsName = (char*)old_threadSym.name;
skipEntry = true;
}
break;
case S_EXPORT:
{
EXPORTSYM& exportSym = *(EXPORTSYM*)dataStart;
}
break;
case S_LPROC32:
case S_GPROC32:
{
DECL_SYM(PROCSYM32, procSym);
FIX_SYM_ADDRESS(procSym.off);
FIXTPI(procSym.typind);
blockPtrs[blockIdx++] = curStreamPos;
globalsName = (const char*)old_procSym.name;
isProcRef = true;
}
break;
case S_LPROC32_ID:
case S_GPROC32_ID:
{
DECL_SYM(PROCSYM32, procSym);
FIX_SYM_ADDRESS(procSym.off);
lastProcName = (char*)old_procSym.name;
FixIPITag_Member(module, procSym.typind);
if (!addrIsInvalid)
blockPtrs[blockIdx++] = curStreamPos;
globalsName = (const char*)old_procSym.name;
isProcRef = true;
if (symType == S_LPROC32_ID)
procSym.rectyp = S_LPROC32;
else
procSym.rectyp = S_GPROC32;
}
break;
case S_FRAMEPROC:
{
//DECL_SYM(FRAMEPROCSYM, frameProc);
//FixSymAddress(&frameProc.);
}
break;
case S_THUNK32:
{
DECL_SYM(THUNKSYM32, thunkSym);
FIX_SYM_ADDRESS(thunkSym.off);
lastProcName = (char*)old_thunkSym.name;
blockPtrs[blockIdx++] = curStreamPos;
}
break;
case S_BLOCK32:
{
DECL_SYM(BLOCKSYM32, blockSym);
FIX_SYM_ADDRESS(blockSym.off);
if (blockIdx > 0)
blockSym.pParent = blockPtrs[blockIdx - 1] + streamDataOfs;
blockPtrs[blockIdx++] = curStreamPos;
}
break;
case S_LOCAL:
{
DECL_SYM(LOCALSYM, localSym);
FIXTPI(localSym.typind);
}
break;
case S_BPREL32:
{
DECL_SYM(BPRELSYM32, bpRel32);
FIXTPI(bpRel32.typind);
}
break;
case S_REGISTER:
{
DECL_SYM(REGSYM, regSym);
FIXTPI(regSym.typind);
}
break;
case S_REGREL32:
{
DECL_SYM(REGREL32, regRel32);
FIXTPI(regRel32.typind);
}
break;
case S_DEFRANGE_REGISTER:
{
DECL_SYM(DEFRANGESYMREGISTER, defRangeReg);
FIX_SYM_ADDRESS(defRangeReg.range.offStart);
}
break;
case S_DEFRANGE_FRAMEPOINTER_REL:
{
DECL_SYM(DEFRANGESYMFRAMEPOINTERREL, defRangeFPRel);
FIX_SYM_ADDRESS(defRangeFPRel.range.offStart);
}
break;
case S_DEFRANGE_SUBFIELD_REGISTER:
{
DECL_SYM(DEFRANGESYMSUBFIELDREGISTER, defRangeSubFieldReg);
FIX_SYM_ADDRESS(defRangeSubFieldReg.range.offStart);
}
break;
case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
{
DECL_SYM(DEFRANGESYMFRAMEPOINTERREL_FULL_SCOPE, defRangeFPRel);
}
break;
case S_DEFRANGE_REGISTER_REL:
{
DECL_SYM(DEFRANGESYMREGISTERREL, defRangeRegRel);
FIX_SYM_ADDRESS(defRangeRegRel.range.offStart);
}
break;
case S_ENDARG:
//BF_ASSERT(curParam == NULL);
break;
case S_PROC_ID_END:
{
struct _ENDSYM
{
unsigned short reclen;
unsigned short rectyp;
};
DECL_SYM(_ENDSYM, endSym);
endSym.rectyp = S_END;
}
// Fall through
case S_INLINESITE_END:
// Fall through
case S_END:
{
if (blockIdx == 0)
{
// Parent was omitted
skipEntry = true;
}
else
{
/*struct _SRCSYM // Either a BLOCKSYM32, PROCSYM32, WITHSYM32...
{
unsigned short reclen; // Record length
unsigned short rectyp; // S_BLOCK32
unsigned long pParent; // pointer to the parent
unsigned long pEnd; // pointer to this blocks end
};*/
long* pEnd = (long*)mWriter.GetStreamPtr(blockPtrs[--blockIdx] + 8);
BF_ASSERT(*pEnd == 0);
*pEnd = curStreamPos + streamDataOfs;
}
}
break;
case S_FRAMECOOKIE:
{
FRAMECOOKIE& frameCookie = *(FRAMECOOKIE*)dataStart;
}
break;
case S_LABEL32:
{
DECL_SYM(LABELSYM32, labelSym);
FIX_SYM_ADDRESS(labelSym.off);
}
break;
case S_CALLSITEINFO:
{
DECL_SYM(CALLSITEINFO, callSiteInfo);
FIX_SYM_ADDRESS(callSiteInfo.off);
FIXTPI(callSiteInfo.typind);
}
break;
case S_HEAPALLOCSITE:
{
DECL_SYM(HEAPALLOCSITE, heapAllocSite);
FIX_SYM_ADDRESS(heapAllocSite.off);
FIXTPI(heapAllocSite.typind);
}
break;
case S_FILESTATIC:
{
DECL_SYM(FILESTATICSYM, fileStaticSym);
FIXTPI(fileStaticSym.typind);
}
break;
case S_CALLEES:
{
DECL_SYM(FUNCTIONLIST, calleeList);
for (int i = 0; i < (int)calleeList.count; i++)
{
calleeList.funcs[i] = old_calleeList.funcs[i];
FIXTPI(calleeList.funcs[i]);
}
dataOut = (uint8*)(&calleeList.funcs[calleeList.count]);
}
break;
case S_CALLERS:
{
DECL_SYM(FUNCTIONLIST, callerList);
for (int i = 0; i < (int)callerList.count; i++)
{
callerList.funcs[i] = old_callerList.funcs[i];
FIXTPI(callerList.funcs[i]);
}
dataOut = (uint8*)(&callerList.funcs[callerList.count]);
}
break;
case S_POGODATA:
{
DECL_SYM(POGOINFO, pogoInfo);
}
break;
case S_INLINESITE:
{
DECL_SYM(INLINESITESYM, inlineSite);
FIXIPI(inlineSite.inlinee);
if (blockIdx > 0)
inlineSite.pParent = blockPtrs[blockIdx - 1] + streamDataOfs;
blockPtrs[blockIdx++] = curStreamPos;
}
break;
case S_ANNOTATION:
{
DECL_SYM(ANNOTATIONSYM, annotation);
FIX_SYM_ADDRESS(annotation.off);
}
break;
case S_TRAMPOLINE:
break;
case S_COFFGROUP:
{
DECL_SYM(COFFGROUPSYM, coffGroup);
FIX_SYM_ADDRESS(coffGroup.off);
}
break;
case S_SECTION:
NotImpl();
break;
case S_SSEARCH:
{
SEARCHSYM* searchSym = (SEARCHSYM*)dataStart;
}
break;
default:
NotImpl();
break;
}
data = dataEnd;
if (addrIsInvalid)
{
dataOut = dataOutStart;
continue;
}
if (dataOut < dataOutEnd)
{
//BL_AUTOPERF_CV("BlCodeView::CreateModuleStreamSyms EndCopy");
int copyBytes = (int)(dataOutEnd - dataOut);
memcpy(dataOut, data - copyBytes, copyBytes);
dataOut = dataOutEnd;
}
bool writeToSymRecord = false;
if (globalsName != NULL)
{
// We only include the first instance of each name
int idx;
Val128 hashVal;
hashVal = Hash128(globalsName, (int)strlen(globalsName));
idx = mGlobals.TryInsert(globalsName, hashVal);
//idx = -1;
if (idx >= 0)
{
if (isProcRef)
{
//BL_AUTOPERF_CV("BlCodeView::CreateModuleStreamSyms ProcRef");
int nameSize = (int)strlen(globalsName) + 1;
REFSYM2 refSym = { 0 };
refSym.reclen = (int)offsetof(REFSYM2, name) + nameSize - 2;
refSym.rectyp = S_PROCREF;
refSym.imod = module->mIdx + 1;
refSym.ibSym = curStreamPos + streamDataOfs;
int addBytes = ((nameSize + 2 + 3) & ~3) - (nameSize + 2);
refSym.reclen += addBytes;
//if (deferredOutIdx >= 0)
//mSymRecordDeferredPositions.Append((int)mSymRecordsWriter.GetStreamPos());
mSymRecordsWriter.Write(&refSym, (int)offsetof(REFSYM2, name));
mSymRecordsWriter.Write(globalsName, nameSize);
if (addBytes > 0)
{
int zero = 0;
mSymRecordsWriter.Write(&zero, addBytes);
}
}
else
{
writeToSymRecord = true;
}
}
/*auto pair = mGlobals.mMap.insert(hashVal);
if (pair.second)
{
int idx = mSymRecords.GetSize();
mGlobals.mRecordIndices.Append(idx);
mSymRecords.Write(dataOutStart, (int)(dataOutEnd - dataOutStart));
}*/
}
if ((skipEntry) && (!writeToSymRecord))
{
dataOut = dataOutStart;
continue;
}
// Align
if ((intptr)dataOut % 4 != 0)
{
//BL_AUTOPERF_CV("BlCodeView::CreateModuleStreamSyms Finish");
dataOutEnd = (uint8*)(((intptr)dataOut + 3) & ~3);
int addBytes = (int)(dataOutEnd - dataOut);
if (addBytes > 0)
{
*(int32*)(dataOut) = 0;
// Add to length
*(int16*)dataOutStart += (int16)addBytes;
}
dataOut = dataOutEnd;
}
if (writeToSymRecord)
{
//BL_AUTOPERF_CV("BlCodeView::CreateModuleStreamSyms WriteToSymRecord");
if (deferredOutIdx >= 0)
mSymRecordDeferredPositions.push_back((int)mSymRecordsWriter.GetStreamPos());
mSymRecordsWriter.Write(dataOutStart, (int)(dataOutEnd - dataOutStart));
}
if (skipEntry)
{
//dataOut = dataOutStart;
continue;
}
if (deferredOutIdx != -1)
{
mDeferedSegOffsets.push_back(deferredOutIdx);
module->mDeferredSegOfsLen++;
}
int dataSize = (int)(dataOutEnd - dataOutStart);
mWriter.Write(dataOutStart, dataSize);
curStreamPos += dataSize;
BF_ASSERT(curStreamPos == mWriter.GetStreamPos());
//BF_ASSERT(dataOut < dataOutMax);
}
BF_ASSERT(nextReloc == dataBlock->mRelocEnd);
BF_ASSERT(blockIdx == 0);
//int outSize = (int)(dataOut - dataOutHead);
dataBlock->mOutSize = mWriter.GetStreamPos() - streamStartPos;
{
//BL_AUTOPERF_CV("BlCodeView::CreateModuleStreamSyms Write");
//mWriter.Write(dataOutHead, outSize);
}
//delete [] dataOutHead;
}
void BlCodeView::CreateLinkerSymStream()
{
#define SALIGN(recLen) recLen = ((recLen + 2 + 3) & ~3) - 2;
#define OUT_WITH_STR(typeName, recName, nameMember) \
symLen = (int)offsetof(typeName, nameMember); \
recName.reclen = (symLen - 2) + (int)str.length() + 1; \
SALIGN(recName.reclen); \
mWriter.Write(&recName, symLen); \
mWriter.Write((void*)str.c_str(), (int)str.length() + 1); \
mWriter.StreamAlign(4);
String str;
int symLen;
OBJNAMESYM objNameSym = { 0 };
objNameSym.rectyp = S_OBJNAME;
str = "* Linker *";
OUT_WITH_STR(OBJNAMESYM, objNameSym, name);
COMPILESYM3 compileSym = { 0 };
compileSym.rectyp = S_COMPILE3;
compileSym.flags.iLanguage = 7; // Link
compileSym.machine = 0xD0;
compileSym.verMajor = 14;
compileSym.verMinor = 0;
compileSym.verFEBuild = 24215;
compileSym.verQFE = 1;
str = "Microsoft (R) Link";
OUT_WITH_STR(COMPILESYM3, compileSym, verSz);
char cwd[MAX_PATH];
_getcwd(cwd, MAX_PATH);
char moduleFileName[MAX_PATH];
GetModuleFileNameA(NULL, moduleFileName, MAX_PATH);
ENVBLOCKSYM envBlock = { 0 };
envBlock.rectyp = S_ENVBLOCK;
str = "cwd"; str.Append('\0');
str += cwd; str.Append('\0');
str += "exe"; str.Append('\0');
str += moduleFileName; str.Append('\0');
str += "pdb"; str.Append('\0');
str += mMsf.mFileName; str.Append('\0');
str += "cmd"; str.Append('\0');
str += GetCommandLineA(); str.Append('\0');
OUT_WITH_STR(ENVBLOCKSYM, envBlock, rgsz);
for (auto segment : mContext->mSegments)
{
auto outSection = mContext->mOutSections[segment->mOutSectionIdx];
COFFGROUPSYM coffGroupSym = { 0 };
coffGroupSym.rectyp = S_COFFGROUP;
coffGroupSym.seg = segment->mOutSectionIdx + 1;
coffGroupSym.off = (int)(segment->mRVA - outSection->mRVA);
coffGroupSym.characteristics = segment->mCharacteristics;
coffGroupSym.cb = segment->mCurSize;
str = segment->mName;
OUT_WITH_STR(COFFGROUPSYM, coffGroupSym, name);
}
for (auto outSection : mContext->mOutSections)
{
SECTIONSYM sectionSym = { 0 };
sectionSym.rectyp = S_SECTION;
sectionSym.rva = outSection->mRVA;
sectionSym.align = outSection->mAlign;
sectionSym.isec = outSection->mIdx + 1;
sectionSym.characteristics = outSection->mCharacteristics;
sectionSym.cb = outSection->mRawSize;
str = outSection->mName;
OUT_WITH_STR(SECTIONSYM, sectionSym, name);
}
}
bool BlCodeView::OnlyHasSimpleRelocs(BlCvModuleInfo* module)
{
/*for (auto& block : module->mSymData)
{
for (COFFRelocation* coffReloc = block.mRelocStart; coffReloc < block.mRelocEnd; coffReloc++)
{
auto& symInfo = module->mSymInfo[coffReloc->mSymbolTableIndex];
if (symInfo.mSegmentIdx < 0)
return false;
if (symInfo.mSegmentIdx >= mContext->mNumFixedSegs)
{
auto seg = mContext->mSegments[symInfo.mSegmentIdx];
OutputDebugStrF("Failed on: %s in %s\n", seg->mName.c_str(), module->mObjectData->mName);
return false;
}
}
}*/
return true;
}
void BlCodeView::CreateModuleStream(BlCvModuleInfo* module)
{
BP_ZONE("BlCodeView::CreateModuleStream");
//BL_AUTOPERF_CV("BlCodeView::CreateModuleStream");
//OutputDebugStrF("CreateModuleStream %d\n", module->mIdx);
//
{
BP_ZONE("BlCodeView::CreateModuleStream WaitForDoneSignal");
/*if (module->mTypeSource != NULL)
module->mTypeSource->mDoneSignal.WaitFor();*/
}
if (mContext->mFailed)
return;
module->mSymStreamIdx = StartStream();
mWriter.WriteT((int32)CV_SIGNATURE_C13);
//int startPos = mWriter.GetStreamPos();
if (module->mObjectData == NULL)
{
int startSize = mWriter.GetStreamPos();
if (module->mName == "* Linker *")
CreateLinkerSymStream();
BlCvSymDataBlock data = { 0 };
data.mOutSize = mWriter.GetStreamPos() - startSize;
module->mSymData.push_back(data);
}
else
{
int dataOfs = 4;
/*const char* invalidStrs[] = { "delete_scalar", "new_scalar" };
for (const char* invalidStr : invalidStrs)
{
//TODO:
if (strstr(module->mObjectData->mName, invalidStr) != NULL)
{
module->mSymData.clear();
module->mLineInfo.clear();
module->mFileInfos.clear();
break;
}
}*/
{
BL_AUTOPERF_CV("BlCodeView::CreateModuleStream CreateModuleStreamSyms");
module->mDeferredSegOfsStart = (int)mDeferedSegOffsets.size();
for (auto& block : module->mSymData)
{
CreateModuleStreamSyms(module, &block, dataOfs);
dataOfs += block.mOutSize;
}
}
}
//mFS.Align(4);
// TODO: Write symbol data...
//module->mSymSize = mWriter.GetStreamPos() - startPos;
if (!module->mFileInfos.empty())
{
int sectStart = mWriter.GetStreamPos();
StartSection(DEBUG_S_FILECHKSMS);
for (auto& fileInfo : module->mFileInfos)
{
struct _CVFileInfo
{
int32 mFileTabOfs;
int8 mHashLen;
int8 mHashType;
uint8 mHash[16];
uint16 mPadding;
};
BF_ASSERT(fileInfo.mChksumOfs == (mWriter.GetStreamPos() - sectStart) - 8);
_CVFileInfo cvFileInfo;
cvFileInfo.mFileTabOfs = fileInfo.mStrTableIdx;
if (fileInfo.mHashType == 1)
{
cvFileInfo.mHashLen = 16;
cvFileInfo.mHashType = 1; //MD5
memcpy(cvFileInfo.mHash, fileInfo.mHash, 16);
mWriter.WriteT(cvFileInfo);
}
else
{
cvFileInfo.mHashLen = 0;
cvFileInfo.mHashType = 0;
cvFileInfo.mHash[0] = 0; // Padding
cvFileInfo.mHash[1] = 0;
mWriter.Write(&cvFileInfo, 8);
}
}
module->mLineInfoSize += EndSection();
}
for (auto lineInfo : module->mLineInfo)
{
StartSection(DEBUG_S_LINES);
CV_DebugSLinesHeader_t lineSect = { 0 };
lineSect.flags = 0;
if (!lineInfo->mLineInfoBlocks.empty())
{
if (!lineInfo->mLineInfoBlocks[0].mColumns.empty())
lineSect.flags |= CV_LINES_HAVE_COLUMNS;
}
//GetOutSectionAddr(lineInfo->mStartSegmentIdx, lineInfo->mStartSegmentOffset, lineSect.segCon, lineSect.offCon);
lineSect.segCon = lineInfo->mStartSegmentIdx;
lineSect.offCon = lineInfo->mStartSegmentOffset;
mDeferedSegOffsets.push_back(mWriter.GetStreamPos());
module->mDeferredSegOfsLen++;
lineSect.cbCon = lineInfo->mContribBytes;
mWriter.WriteT(lineSect);
for (auto& lineBlocks : lineInfo->mLineInfoBlocks)
{
//TODO: Ensure cbBlock is correct
CV_DebugSLinesFileBlockHeader_t lineBlockHeader = { 0 };
lineBlockHeader.cbBlock = (int)sizeof(CV_DebugSLinesFileBlockHeader_t) + (int)(lineBlocks.mLines.size() * sizeof(CV_Line_t));
lineBlockHeader.cbBlock += (int)(lineBlocks.mColumns.size() * sizeof(int16) * 2);
lineBlockHeader.nLines = (int)lineBlocks.mLines.size();
//int bytesPerFile = 24;
//lineBlockHeader.offFile = lineBlocks.mFileInfoIdx * bytesPerFile;
auto fileInfo = module->mFileInfos[lineBlocks.mFileInfoIdx];
lineBlockHeader.offFile = fileInfo.mChksumOfs;
mWriter.WriteT(lineBlockHeader);
for (auto& line : lineBlocks.mLines)
{
CV_Line_t cvLineData;
cvLineData.offset = line.mOffset;
cvLineData.linenumStart = line.mLineNumStart;
cvLineData.fStatement = 0;
cvLineData.deltaLineEnd = 0;
mWriter.WriteT(cvLineData);
}
for (auto column : lineBlocks.mColumns)
{
int16 colVals[2] = { column, column };
mWriter.WriteT(colVals);
}
}
module->mLineInfoSize += EndSection();
}
for (auto& inlineData : module->mInlineData)
{
StartSection(DEBUG_S_INLINEELINES);
uint8* data = (uint8*)inlineData.mData;
uint8* dataEnd = data + inlineData.mSize;
int linesType = GET(int);
mWriter.WriteT(linesType);
BF_ASSERT(linesType == 0);
while (data < dataEnd)
{
CodeViewInfo::InlineeSourceLine lineInfo = GET(CodeViewInfo::InlineeSourceLine);
FixIPITag(module, lineInfo.inlinee);
mWriter.WriteT(lineInfo);
}
module->mLineInfoSize += EndSection();
}
mWriter.WriteT(0); // GlobalRefsSize
bool flushNow = module->mDeferredSegOfsLen == 0;
EndStream(flushNow);
}
void BlCodeView::FinishModuleStream(BlCvModuleInfo* module)
{
BP_ZONE("BlCodeView::FinishModuleStream");
auto streamInfo = mStreams[module->mSymStreamIdx];
auto fixItr = mDeferedSegOffsets.GetIterator(module->mDeferredSegOfsStart);
for (int deferIdx = 0; deferIdx < module->mDeferredSegOfsLen; deferIdx++)
{
int deferredIdx = *fixItr;
int dataIdx = deferredIdx;
int blockIdx = streamInfo->mBlocks[dataIdx / CV_BLOCK_SIZE];
uint8* data = (uint8*)mMsf.mBlocks[blockIdx]->mData + (dataIdx % CV_BLOCK_SIZE);
int32* ofsPtr = (int32*)data;
dataIdx = deferredIdx + 4;
blockIdx = streamInfo->mBlocks[dataIdx / CV_BLOCK_SIZE];
data = (uint8*)mMsf.mBlocks[blockIdx]->mData + (dataIdx % CV_BLOCK_SIZE);
int16* segPtr = (int16*)data;
auto segment = mContext->mSegments[*segPtr];
auto outSection = mContext->mOutSections[segment->mOutSectionIdx];
*ofsPtr += segment->mRVA - outSection->mRVA;
*segPtr = outSection->mIdx + 1;
++fixItr;
}
FlushStream(streamInfo);
}
void BlCodeView::CreateLinkerModule()
{
auto module = mModuleInfo.Alloc();
module->mName = "* Linker *";
module->mIdx = (int)mModuleInfo.size() - 1;
}
void BlCodeView::DoFinish()
{
//TODO:
//StopWorkThread();
int simpleRelocCount = 0;
for (auto module : mModuleInfo)
{
if (module->mSymStreamIdx == -1)
{
//simpleRelocCount += OnlyHasSimpleRelocs(module);
CreateModuleStream(module);
}
if (module->mDeferredSegOfsLen > 0)
{
FinishModuleStream(module);
}
}
/*for (auto module : mModuleInfo)
{
String dbgStr = StrFormat("Module #%d:", module->mIdx);
for (auto block : mStreams[module->mSymStreamIdx]->mBlocks)
{
dbgStr += StrFormat(" %d", block);
}
dbgStr += "\n";
OutputDebugStringA(dbgStr.c_str());
}*/
//StopWorkThread();
if (mContext->mFailed)
{
// We can't continue if any types may have failed
return;
}
CreateDBIStream();
// CreateDBIStream does CreateGlobalsStream/CreatePublicsStream, so the symRecords
// aren't done until after that
FinishSymRecords();
CreateTypeStream();
CreateIPIStream();
CreateNamesStream();
CreateLinkInfoStream();
CreateHeaderBlockStream();
CreatePDBInfoStream();
// Stream dir
//int streamDirLoc = mMSF.Alloc();
BlCVStream dirStream;
StartUnnamedStream(dirStream);
mWriter.WriteT((int32)mStreams.size());
for (auto& stream : mStreams)
{
BF_ASSERT(stream->mSize >= 0);
mWriter.WriteT((int32)stream->mSize);
}
std::vector<int> streamBlocks;
uint8* streamDataPos = NULL;
uint8* streamDataEnd = NULL;
for (auto& stream : mStreams)
{
//int numBlocks = (stream.mSize + CV_BLOCK_SIZE - 1) / CV_BLOCK_SIZE;
//for (int blockIdx = stream.mBlockStart; blockIdx < stream.mBlockStart + numBlocks; blockIdx++)
//mWriter.WriteT(blockIdx);
for (auto blockIdx : stream->mBlocks)
mWriter.WriteT((int32)blockIdx);
}
//int streamDirLen = mWriter.GetStreamPos() - (streamDirLoc * CV_BLOCK_SIZE);
//int numStreamDirBlocks = (streamDirLen + CV_BLOCK_SIZE - 1) / CV_BLOCK_SIZE;
//EndBlock();
EndStream();
// Root block
//int rootBlockNum = mMSF.Alloc();
BlCVStream rootStream;
StartUnnamedStream(rootStream);
for (auto block : dirStream.mBlocks)
mWriter.WriteT((int32)block);
EndStream();
//for (int streamDirBlockIdx = streamDirLoc; streamDirBlockIdx < streamDirLoc + numStreamDirBlocks; streamDirBlockIdx++)
//mWriter.WriteT((int32)streamDirBlockIdx);
//EndBlock();
// Fix header
/*MemStream headerStream(mMSF.mBlocks[0]->mData, CV_BLOCK_SIZE, false);
int headerStart = 32;
headerStream.SetPos(headerStart + 8);
headerStream.Write((int32)mNumBlocks);
headerStream.Write((int32)streamDirLen);
headerStream.Write((int32)0); // Unknown
headerStream.Write((int32)rootBlockNum);*/
// Fix bitmap
/*mFS.SetPos(CV_BLOCK_SIZE);
BfBitSet bitset;
bitset.Init(mNumBlocks);
int numBytes = (mNumBlocks + 7) / 8;
memset(bitset.mBits, 0xFF, numBytes);
for (int i = 1; i < mNumBlocks; i++)
bitset.Clear(i);
mWriter.WriteT(bitset.mBits, numBytes);
BF_ASSERT(mFS.GetSize() == mNumBlocks * CV_BLOCK_SIZE);
mFS.Close();*/
BF_ASSERT(rootStream.mBlocks.size() == 1);
//AutoPerf autoPerf("Write", &gCVThreadPerfManager);
BP_ZONE("BlCodeView::DoFinish Write");
{
BP_ZONE("BlCodeView::DoFinish Write Wait");
mMsf.mWorkThread.Stop();
}
mMsf.Finish(rootStream.mBlocks[0], dirStream.mSize);
}
void BlCodeView::Finish()
{
/*if (mWorkThread == NULL)
{
DoFinish();
}
else
{
mWorkDone = true;
mWorkEvent.Set();
}*/
mTypeWorkThread.mTypesDone = true;
mTypeWorkThread.mWorkEvent.Set();
mModuleWorkThread.mModulesDone = true;
mModuleWorkThread.mWorkEvent.Set();
}