mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00

Changed some string internals related to StringViewsma Added an "incompatible capture" error for lambdas when the captures change
2481 lines
61 KiB
C++
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();
|
|
}
|