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

Initial checkin

This commit is contained in:
Brian Fiete 2019-08-23 11:56:54 -07:00
parent c74712dad9
commit 078564ac9e
3242 changed files with 1616395 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,463 @@
#pragma once
#include "../Beef/BfCommon.h"
#include "BeefySysLib/FileStream.h"
#include "BeefySysLib/MemStream.h"
#include "BeefySysLib/util/BumpAllocator.h"
#include "BeefySysLib/util/ChunkedDataBuffer.h"
#include "BeefySysLib/util/Array.h"
#include "BeefySysLib/util/String.h"
#include "BeefySysLib/util/Hash.h"
#include "BeefySysLib/util/CritSect.h"
#include "BeefySysLib/util/WorkThread.h"
#include "BeefySysLib/util/PerfTimer.h"
#include "../Compiler/BfUtil.h"
#include "BlMsf.h"
#include <unordered_map>
#include <unordered_set>
#include "BlPdbParser.h"
//#include "Hash.h"
#include "BlCvTypeSource.h"
#include "BlContext.h"
#include <queue>
//#define BL_USE_DENSEMAP_CV
#ifdef BL_USE_DENSEMAP_CV
#include <sparsehash/dense_hash_map>
#include <sparsehash/dense_hash_set>
#endif
NS_BF_BEGIN
struct PE_SymInfo;
struct COFFRelocation;
class BlContext;
class BlObjectData;
class BlCvTypeSource;
class BlCVStream
{
public:
String mName;
Array<int> mBlocks;
int mSize;
public:
BlCVStream()
{
mSize = 0;
}
};
class BlCvFileInfo
{
public:
int mStrTableIdx;
int mChksumOfs;
int8 mHashType;
uint8 mHash[16];
};
class BlCvLine
{
public:
int mOffset;
int mLineNumStart;
};
class BlCvLineInfoBlock
{
public:
int mFileInfoIdx;
std::vector<BlCvLine> mLines;
std::vector<int16> mColumns;
};
class BlCvLineInfo
{
public:
int mStartSegmentIdx;
int mStartSegmentOffset;
int mContribBytes;
std::vector<BlCvLineInfoBlock> mLineInfoBlocks;
BlCvLineInfo()
{
mStartSegmentIdx = -1;
mStartSegmentOffset = 0;
mContribBytes = 0;
}
};
struct BlCvSymDataBlock
{
void* mData;
int mSize;
int mOutSize;
int mSourceSectOffset;
COFFRelocation* mRelocStart;
COFFRelocation* mRelocEnd;
FILE* mFP;
int mFPOfs;
};
enum BlSectInfoState : intptr
{
BlSectInfoState_QueuedData = -1,
BlSectInfoState_QueuedDebugT = -2,
BlSectInfoState_QueuedDebugS = -3
};
struct BlObjectDataSectInfo
{
int mSegmentIdx;
int mSegmentOffset;
void* mRelocData;
union
{
void* mChunkData;
BlSectInfoState mState;
};
uint16 mSelectNum;
int8 mSelection;
bool IsUsed()
{
return (intptr)mChunkData >= 0;
}
};
struct BlObjectDataSectInfo;
class BlCvModuleContrib
{
public:
int mBlSectionIdx;
int mBlSectionOfs;
int mSize;
int mCharacteristics;
public:
BlCvModuleContrib()
{
mBlSectionIdx = 0;
mBlSectionOfs = 0;
mSize = 0;
mCharacteristics = 0;
}
};
class BlCvModuleInfo
{
public:
int mIdx;
String mName;
const char* mStrTab;
BlObjectData* mObjectData;
int mSymStreamIdx;
BlCvTypeSource* mTypeSource;
PE_SymInfo* mObjSyms;
BfSizedVector<BlObjectDataSymInfo, 0> mSymInfo;
BfSizedVector<BlCvSymDataBlock, 1> mSymData;
int mLineInfoSize;
//BfSizedVector<BlCvContrib, 1> mContribs;
BlCvModuleContrib mContrib;
std::vector<BlCvFileInfo> mFileInfos;
OwnedVector<BlCvLineInfo> mLineInfo;
BfSizedVector<BlCvSymDataBlock, 1> mInlineData;
BfSizedVector<BlObjectDataSectInfo, 1> mSectInfos;
int mDeferredSegOfsStart;
int mDeferredSegOfsLen;
public:
BlCvModuleInfo()
{
mIdx = -1;
mStrTab = NULL;
//mObjSyms = NULL;
mObjectData = NULL;
mSymStreamIdx = -1;
mLineInfoSize = 0;
mTypeSource = NULL;
mDeferredSegOfsStart = 0;
mDeferredSegOfsLen = 0;
mObjSyms = NULL;
}
~BlCvModuleInfo()
{
}
};
class BlTypeInfo
{
public:
#ifdef BL_USE_DENSEMAP_CV
google::dense_hash_map<Val128, int, Val128::Hash, Val128::Equals> mTypeMap;
#else
std::unordered_map<Val128, int, Val128::Hash, Val128::Equals> mTypeMap;
#endif
ChunkedDataBuffer mData;
int mCurTagId;
public:
BlTypeInfo()
{
mCurTagId = 0x1000;
#ifdef BL_USE_DENSEMAP_CV
mTypeMap.set_empty_key(Val128(-1));
mTypeMap.min_load_factor(0);
mTypeMap.resize(100000);
#endif
}
};
class BlCvRecordEntry
{
public:
Val128 mKey;
int mRecordIndex;
BlCvRecordEntry* mNext;
};
class BlCvRecordMap
{
public:
#ifdef BL_USE_DENSEMAP_CV
google::dense_hash_set<Val128, Val128::Hash, Val128::Equals> mKeySet;
#else
std::unordered_set<Val128, Val128::Hash, Val128::Equals> mKeySet;
#endif
BlCodeView* mCodeView;
BlCvRecordEntry* mBuckets[4096];
BumpAllocator mAlloc;
int mNumEntries;
public:
BlCvRecordMap()
{
mCodeView = NULL;
memset(&mBuckets, 0, sizeof(mBuckets));
mNumEntries = 0;
#ifdef BL_USE_DENSEMAP_CV
mKeySet.set_empty_key(Val128(-1));
mKeySet.min_load_factor(0);
mKeySet.resize(100000);
#endif
}
void Insert(const char* name, int symIdx);
int TryInsert(const char* name, const Val128& key);
};
class BlCvContrib
{
public:
int mModuleIdx;
int mBlSectionOfs;
int mSize;
int mCharacteristics;
};
class BlCvContributionSeg
{
public:
std::vector<BlCvContrib> mContribs;
};
class BlCvContributionMap
{
public:
OwnedVector<BlCvContributionSeg> mSegments;
};
class BlCvTypeWorkThread : public WorkThread
{
public:
std::deque<BlCvTypeSource*> mTypeSourceWorkQueue;
BlCodeView* mCodeView;
CritSect mCritSect;
SyncEvent mWorkEvent;
volatile bool mTypesDone;
volatile bool mThreadDone;
public:
BlCvTypeWorkThread();
~BlCvTypeWorkThread();
virtual void Stop() override;
virtual void Run() override;
void Add(BlCvTypeSource* typeSource);
};
class BlCvModuleWorkThread : public WorkThread
{
public:
std::deque<BlCvModuleInfo*> mModuleWorkQueue;
BlCodeView* mCodeView;
CritSect mCritSect;
SyncEvent mWorkEvent;
volatile bool mModulesDone;
public:
BlCvModuleWorkThread();
~BlCvModuleWorkThread();
virtual void Stop() override;
virtual void Run() override;
void Add(BlCvModuleInfo* module);
};
class BlCvStreamWriter
{
public:
BlMsf* mMsf;
BlCVStream* mCurStream;
uint8* mCurBlockPos;
uint8* mCurBlockEnd;
public:
BlCvStreamWriter();
void Start(BlCVStream* stream);
void Continue(BlCVStream* stream);
void End(bool flush = true);
void Write(const void* data, int size);
template <typename T>
void WriteT(const T& val)
{
Write(&val, sizeof(T));
}
void Write(ChunkedDataBuffer& buffer);
int GetStreamPos();
void StreamAlign(int align);
void* GetStreamPtr(int pos);
};
class BlCvStreamReader
{
public:
BlMsf* mMsf;
int mBlockIdx;
BlCVStream* mCurStream;
uint8* mCurBlockPos;
uint8* mCurBlockEnd;
public:
BlCvStreamReader();
void Open(BlCVStream* stream);
void* ReadFast(void* data, int size);
void Seek(int size);
int GetStreamPos();
};
class BlCodeView
{
public:
BlContext* mContext;
BumpAllocator mAlloc;
BlMsf mMsf;
int mStat_TypeMapInserts;
int mStat_ParseTagFuncs;
OwnedVector<BlCVStream> mStreams;
OwnedVector<BlCvModuleInfo> mModuleInfo;
int mSectStartFilePos;
BlTypeInfo mTPI;
BlTypeInfo mIPI;
int8 mSignature[16];
int mAge;
DynMemStream mSectionHeaders;
ChunkedVector<int> mSymRecordDeferredPositions;
int mSymRecordsStream;
//ChunkedDataBuffer mSymRecords;
BlCvRecordMap mGlobals;
std::unordered_map<String, BlCvTypeSource*> mTypeServerFiles;
std::unordered_map<String, int> mStrTabMap;
String mStrTab;
BlCvContributionMap mContribMap;
BlCvTypeWorkThread mTypeWorkThread;
BlCvModuleWorkThread mModuleWorkThread;
ChunkedVector<int> mDeferedSegOffsets;
BlCvStreamWriter mWriter;
BlCvStreamWriter mSymRecordsWriter;
public:
void NotImpl();
void Fail(const StringImpl& err);
char* StrDup(const char* str);
void FixSymAddress(void* oldDataStart, void* oldDataPos, void* outDataPos, BlCvModuleInfo* module, BlCvSymDataBlock* dataBlock, COFFRelocation*& nextReloc);
int StartStream(int streamIdx = -1);
void StartUnnamedStream(BlCVStream& stream);
void EndStream(bool flush = true);
void FlushStream(BlCVStream* stream);
void CvEncodeString(const StringImpl& str);
int AddToStringTable(const StringImpl& str);
void WriteStringTable(const StringImpl& strTable, std::unordered_map<String, int>& strTabMap);
void GetOutSectionAddr(int segIdx, int segOfs, uint16& cvSectIdx, long& cvSectOfs);
bool FixTPITag(BlCvModuleInfo* module, unsigned long& typeId);
bool FixIPITag(BlCvModuleInfo* module, unsigned long& typeId);
bool FixIPITag_Member(BlCvModuleInfo* module, unsigned long& typeId);
bool OnlyHasSimpleRelocs(BlCvModuleInfo * module);
void StartSection(int sectionNum);
int EndSection();
void FlushMemStream();
void CreatePDBInfoStream();
void WriteTypeData(int streamId, BlTypeInfo& typeInfo);
void CreateTypeStream();
void CreateIPIStream();
void WriteRecordMap(BlCvRecordMap * recordMap);
int CreateGlobalStream();
int CreatePublicStream();
void FinishSymRecords();
int CreateSymRecordStream();
int CreateSectionHeaderStream();
void CreateDBIStream();
void CreateLinkInfoStream();
void CreateHeaderBlockStream();
void CreateNamesStream();
void CreateModuleStreamSyms(BlCvModuleInfo* module, BlCvSymDataBlock* dataBlock, int dataOfs);
void CreateLinkerSymStream();
void CreateModuleStream(BlCvModuleInfo* module);
void FinishModuleStream(BlCvModuleInfo* module);
void CreateLinkerModule();
void DoFinish();
public:
BlCodeView();
~BlCodeView();
bool Create(const StringImpl& fileName);
void StartWorkThreads();
void StopWorkThreads();
void Finish();
};
NS_BF_END

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,572 @@
#pragma once
#include "../Beef/BfCommon.h"
#include "../Compiler/BfUtil.h"
#include "BeefySysLib/util/Hash.h"
#include "BeefySysLib/util/BumpAllocator.h"
#include "BeefySysLib/util/ChunkedDataBuffer.h"
#include "BlSymTable.h"
#include "BeefySysLib/MemStream.h"
#include "BeefySysLib/util/ChunkedVector.h"
#include "BeefySysLib/util/CritSect.h"
#include "BeefySysLib/util/MappedFile.h"
#include <map>
#include <set>
NS_BF_BEGIN
//#define BL_PERFTIME
#ifdef BL_PERFTIME
#define BL_AUTOPERF(name) AutoPerf autoPerf##__LINE__(name);
#else
#define BL_AUTOPERF(name)
#endif
struct BlSymHash
{
public:
const char* mName;
};
enum BlSymKind
{
BlSymKind_Undefined = -1,
BlSymKind_LibSymbolRef = -2,
BlSymKind_LibSymbolGroupRef = -3,
BlSymKind_WeakSymbol = -4,
BlSymKind_ImageBaseRel = -5,
BlSymKind_Import = -6,
BlSymKind_ImportImp = -7,
BlSymKind_Absolute = -8,
};
class BlCodeView;
class BlSymbol
{
public:
const char* mName;
union
{
// If mSectionIdx is negative, then we're not a resolved symbol and the mKind member is used instead
int mSegmentIdx;
BlSymKind mKind;
};
union
{
int mSegmentOffset;
int mParam;
};
int mObjectDataIdx;
};
class BlLib
{
public:
String mFileName;
char* mStrTable;
public:
BlLib()
{
mStrTable = NULL;
}
};
// From lowest priority to highest
enum BlObjectDataKind
{
BlObjectDataKind_DirectiveLib,
BlObjectDataKind_DefaultLib,
BlObjectDataKind_SpecifiedLib,
BlObjectDataKind_SpecifiedObj,
};
struct BlObjectDataSymInfo
{
BlSymbol* mSym;
enum Kind
{
Kind_None = -1,
Kind_Section = -2
};
union
{
int mSegmentIdx;
Kind mKind;
};
union
{
int mSegmentOffset;
int mSectionNum;
};
BlObjectDataSymInfo()
{
mSym = NULL;
mSegmentIdx = Kind_None;
mSegmentOffset = 0;
}
};
enum BlObjectDataLoadState
{
BlObjectDataLoadState_UnloadedLib = -1,
BlObjectDataLoadState_UnloadedThinLib = -2,
BlObjectDataLoadState_ImportObject = -3,
};
class BlObjectData
{
public:
BlObjectDataKind mKind;
int mIdx;
BlLib* mLib;
char* mName;
union
{
void* mData;
BlSymbol* mImportSym;
};
union
{
int mSize;
BlObjectDataLoadState mLoadState;
};
FILE* mFP;
int mFPOfs;
public:
BlObjectData()
{
mKind = BlObjectDataKind_DefaultLib;
mIdx = -1;
mLib = NULL;
mName = NULL;
mData = NULL;
mSize = 0;
mFP = NULL;
mFPOfs = 0;
}
};
struct BlLibMemberHeader
{
char mName[16];
char mDate[12];
char mUserId[6];
char mGroupId[6];
char mMode[8];
char mSize[10];
char mEnd[2];
void Init()
{
char* spaces = " ";
memcpy(mName, spaces, 16);
memcpy(mDate, spaces, 12);
memcpy(mUserId, spaces, 6);
memcpy(mGroupId, spaces, 6);
memcpy(mMode, spaces, 8);
memcpy(mSize, spaces, 10);
mEnd[0] = '`';
mEnd[1] = '\n';
}
};
class BlChunk
{
public:
int mOffset;
int mAlignPad; // Before data
void* mData;
int mSize;
int mObjectDataIdx;
};
enum BlRelocKind : uint8
{
BlRelocKind_ADDR32NB,
BlRelocKind_ADDR64,
BlRelocKind_REL32,
BlRelocKind_REL32_1,
BlRelocKind_REL32_4,
BlRelocKind_SECREL,
BlRelocKind_SECTION,
};
enum BeRelocFlags : uint8
{
//BeRelocFlags_SymName = 1,
BeRelocFlags_Sym = 2,
BeRelocFlags_SymIsNew = 4,
BeRelocFlags_Loc = 8,
BeRelocFlags_Func = 0x10
};
class BlReloc
{
public:
BlRelocKind mKind;
BeRelocFlags mFlags;
int32 mOutOffset;
union
{
struct
{
int32 mSegmentIdx;
int32 mSegmentOffset;
};
const char* mSymName;
BlSymbol* mSym;
};
};
class BlContext;
class BlSegmentInfo
{
public:
String mName;
};
// Segments are almost like sections, but segments like ".text" and ".text$mn" get
// combined together into BlOutSection objects so there's not a one-to-one correspondence.
class BlSegment : public BlSegmentInfo
{
public:
int mOutSectionIdx;
int mCharacteristics;
BumpAllocator mAlloc;
BlContext* mContext;
std::vector<BlChunk> mChunks;
std::vector<BlReloc> mRelocs;
int mResolvedRelocIdx;
int mCurSize;
int mSegmentIdx;
int mAlign;
int mRVA;
public:
BlSegment()
{
mOutSectionIdx = -1;
mCharacteristics = 0;
mContext = NULL;
mCurSize = 0;
mSegmentIdx = -1;
mAlign = 1;
mRVA = 0;
mResolvedRelocIdx = 0;
}
BlChunk* AddChunk(void* data, int size, int characteristics, int& offset);
};
class BlOutSection
{
public:
int mIdx;
String mName;
std::vector<BlSegment*> mSegments;
int mCharacteristics;
int mAlign;
int mRVA;
int mRawDataPos;
int mRawSize;
int mVirtualSize;
public:
BlOutSection()
{
mIdx = 0;
mCharacteristics = 0;
mAlign = 1;
mRawDataPos = 0;
mRVA = 0;
mRawSize = 0;
mVirtualSize = 0;
}
};
class BlPendingComdat
{
public:
};
class BlImportLookup
{
public:
String mName;
int mHint;
int mThunkIdx;
int mIDataIdx;
public:
BlImportLookup()
{
mHint = 0;
mThunkIdx = -1;
mIDataIdx = -1;
}
};
class BlImportFile
{
public:
OwnedVector<BlImportLookup> mLookups;
};
struct BlResIdLess
{
bool operator()(const char16_t* lhs, const char16_t* rhs) const
{
bool lhsIsID = ((uintptr)lhs < 0x10000);
bool rhsIsID = ((uintptr)rhs < 0x10000);
// Strings before IDs
if (lhsIsID && !rhsIsID)
return false;
if (!lhsIsID && rhsIsID)
return true;
if (lhsIsID && rhsIsID)
return (uintptr)lhs < (uintptr)rhs;
return wcscmp((wchar_t*)lhs, (wchar_t*)rhs) < 0;
}
};
class BlResEntry
{
public:
bool mIsDir;
virtual ~BlResEntry()
{
}
};
class BlResData : public BlResEntry
{
public:
BlResData()
{
mIsDir = false;
}
void* mData;
int mSize;
};
class BlResDirectory : public BlResEntry
{
public:
BlResDirectory()
{
mIsDir = true;
}
std::map<const char16_t*, BlResEntry*, BlResIdLess> mEntries;
};
class BlPeRelocs
{
public:
ChunkedDataBuffer mData;
uint32 mBlockAddr;
int32* mLenPtr;
public:
BlPeRelocs()
{
mBlockAddr = 0;
mLenPtr = NULL;
}
void Add(uint32 addr, int fixupType);
};
class BlExport
{
public:
String mSrcName;
int mOrdinal;
bool mNoName;
bool mIsPrivate;
bool mIsData;
bool mOrdinalSpecified;
public:
BlExport()
{
mOrdinal = -1;
mNoName = false;
mIsPrivate = false;
mIsData = false;
mOrdinalSpecified = false;
}
};
class BlImportGroup
{
public:
std::vector<int> mObjectDatas;
};
class BlSymNotFound
{
public:
BlSymbol* mSym;
int mSegmentIdx;
int mOutOffset;
};
class BlContext
{
public:
CritSect mCritSect;
String mOutName;
String mPDBPath;
String mImpLibName;
int mDebugKind;
bool mVerbose;
bool mNoDefaultLib;
std::set<String> mNoDefaultLibs;
std::vector<String> mDefaultLibs;
bool mHasFixedBase;
bool mHasDynamicBase;
bool mHighEntropyVA;
bool mIsNXCompat;
bool mIsTerminalServerAware;
int mPeSubsystem;
int mHeapReserve;
int mHeapCommit;
int mStackReserve;
int mStackCommit;
int mPeVersionMajor;
int mPeVersionMinor;
int mProcessingSegIdx;
int mDbgSymSectsFound;
int mDbgSymSectsUsed;
bool mIsDLL;
String mEntryPoint;
uint32 mTimestamp;
int mNumObjFiles;
int mNumLibs;
int mNumImportedObjs;
int mNumWeakSymbols;
BumpAllocator mAlloc;
bool mFailed;
int mErrorCount;
std::vector<String> mSearchPaths;
OwnedVector<MappedFile> mMappedFiles;
OwnedVector<BlObjectData> mObjectDatas;
std::vector<BlObjectData*> mObjectDataWorkQueue;
//std::vector<BlChunk*> mChunks;
std::vector<BlSegment*> mSegments;
std::vector<BlSegment*> mOrderedSegments;
std::map<String, String> mSectionMerges;
OwnedVector<BlSegment> mDynSegments;
OwnedVector<BlLib> mLibs;
BlSymTable mSymTable;
std::vector<String> mRemapStrs;
OwnedVector<BlOutSection> mOutSections;
std::map<String, BlImportFile> mImportFiles;
std::vector<BlImportLookup*> mImportLookups;
std::map<String, BlExport> mExports;
std::vector<String> mForcedSyms;
OwnedVector<BlImportGroup> mImportGroups;
std::vector<BlSymNotFound> mSymNotFounds;
BlResDirectory mRootResDirectory;
OwnedVector<BlResEntry> mResEntries;
DynMemStream mImportStream;
DynMemStream mThunkStream;
DynMemStream mDebugDirStream;
DynMemStream mCvInfoStream;
DynMemStream mResDataStream;
DynMemStream mLoadConfigStream;
DynMemStream mExportStream;
BlCodeView* mCodeView;
BlSegment* mIDataSeg;
BlSegment* mTextSeg;
BlSegment* mRDataSeg;
BlSegment* mDataSeg;
BlSegment* mBSSSeg;
int mNumFixedSegs;
String mManifestUAC;
String mManifestData;
BlPeRelocs mPeRelocs;
int64 mImageBase;
/*BlSection mTextSect;
BlSection mRDataSect;
BlSection mBSSSect; */
std::set<String> mSeenLibs;
public:
BlSymHash Hash(const char* symName);
String ObjectDataIdxToString(int objectDataIdx);
String GetSymDisp(const StringImpl& name);
String FixFilePath(const StringImpl& path, const StringImpl& actualFileName);
void Fail(const StringImpl& error);
void Warn(const StringImpl& error);
void Fail(BlObjectData* objectData, const StringImpl& error);
void AssertFailed();
void NotImpl();
void PrintStats();
void AddSegment(BlSegment* section);
void LoadFiles();
bool HandleLibSymbolRef(BlSymbol* sym, int objectDataIds);
BlSymbol* ProcessSymbol(BlSymbol* sym);
BlSymbol* ResolveSym(const char* name, bool throwError = true);
uint64 GetSymAddr(BlSymbol* sym);
void AddAbsoluteSym(const char* name, int val);
BlSegment* CreateSegment(const StringImpl& name, int characteristics, int align);
void PlaceSections();
void ResolveRelocs();
void LoadResourceData(BlObjectData* objectData);
void LoadDefData(BlObjectData* objectData);
void WriteDLLLib(const StringImpl& libName);
void PopulateIData_LookupTable(BlSegment* iDataSect, int& hintNameTableSize);
void PopulateIData(BlSegment* iDataSeg);
BlSegment* CreateIData();
void PopulateThunkData(BlSegment* thunkSeg, BlSegment* iDataSeg);
BlSegment* CreateThunkData();
void PopulateExportData(BlSegment * exportSeg);
BlSegment * CreateExportData();
void PopulateCvInfoData(BlSegment* cvInfoSeg);
BlSegment* CreateCvInfoData();
void PopulateDebugDirData(BlSegment* debugDirSeg, BlSegment* cvInfoSeg);
BlSegment* CreateDebugDirData();
void PopulateResData(BlSegment* resSeg);
void GetResDataStats(BlResDirectory* resDir, int& dirCount, int& dataCount, int& symsStrsSize, int& dataSize);
void CreateResData(BlSegment* resSeg, BlResDirectory* resDir, int resDirSize, int symsStrSize, DynMemStream& symStrsStream, DynMemStream& dataEntryStream);
BlSegment* CreateResData();
void WriteOutSection(BlOutSection * outSection, DataStream * st);
public:
BlContext();
~BlContext();
void Init(bool is64Bit, bool isDebug);
void AddSearchPath(const StringImpl& directory);
bool DoAddFile(const StringImpl& path, BlObjectDataKind objectDataKind);
bool AddFile(const StringImpl& fileName, BlObjectDataKind objectDataKind);
void Link();
};
NS_BF_END

View file

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

View file

@ -0,0 +1,57 @@
#pragma once
#include "../Beef/BfCommon.h"
#include "BeefySysLib/FileStream.h"
#include "BeefySysLib/util/BumpAllocator.h"
#include "../Compiler/BfUtil.h"
#include <unordered_map>
NS_BF_BEGIN
struct PESectionHeader;
struct PE_SymInfo;
class BlContext;
class BlObjectData;
class BlCodeView;
class BlCvModuleInfo;
class BlReloc;
struct BlObjectDataSectInfo;
struct BlObjectDataSymInfo;
struct COFFRelocation;
class BlCvParser
{
public:
BlContext* mContext;
BlCodeView* mCodeView;
BlCvModuleInfo* mCurModule;
const BfSizedVectorRef<BlObjectDataSymInfo>* mSyms;
BfSizedVector<PESectionHeader*, 1> mTypeSects;
BfSizedVector<PESectionHeader*, 1> mSymSects;
std::vector<int16> mChksumOfsToFileIdx;
public:
void NotImpl();
void Fail(const StringImpl& err);
static int64 CvParseConstant(uint16 constVal, uint8*& data);
static int64 CvParseConstant(uint8*& data);
static const char* CvParseString(uint8*& data);
bool MapAddress(void* symbolData, void* cvLoc, BlReloc& outReloc, COFFRelocation*& nextReloc);
bool TryReloc(void* symbolData, void* cvLoc, int32* outVal, COFFRelocation*& nextReloc);
void ParseSymbolData(void* symbolData, int size, void* relocData, int numRelocs);
public:
BlCvParser(BlContext* context);
void AddModule(BlObjectData* objectData, const char* strTab);
void AddTypeData(PESectionHeader* sect);
void AddSymbolData(PESectionHeader* sects);
void ParseTypeData(void * typeData, int size);
void AddContribution(int blSectionIdx, int blSectionOfs, int size, int characteristics);
void FinishModule(PESectionHeader* sectHeaderArr, const BfSizedVectorRef<BlObjectDataSectInfo>& sectInfos, PE_SymInfo* symInfo, const BfSizedVectorRef<BlObjectDataSymInfo>& syms);
};
NS_BF_END

View file

@ -0,0 +1,913 @@
#include "BlCvTypeSource.h"
#include "BlContext.h"
#include "codeview/cvinfo.h"
#include "BlCvParser.h"
#include "BlPdbParser.h"
#include "BlCodeView.h"
#define GET(T) *((T*)(data += sizeof(T)) - 1)
#define GET_INTO(T, name) T name = GET(T)
#define PTR_ALIGN(ptr, origPtr, alignSize) ptr = ( (origPtr)+( ((ptr - origPtr) + (alignSize - 1)) & ~(alignSize - 1) ) )
USING_NS_BF;
static int sIdx = 0;
BlCvTypeContainer::BlCvTypeContainer()
{
mSectionData = NULL;
mSectionSize = 0;
mCvMinTag = -1;
mCvMaxTag = -1;
mCodeView = NULL;
mOutTypeInfo = NULL;
mIdx = sIdx++;
}
BlCvTypeContainer::~BlCvTypeContainer()
{
}
void BlCvTypeContainer::Fail(const StringImpl& err)
{
BF_FATAL("Err");
}
const char* BlCvTypeContainer::CvParseAndDupString(uint8*& data, bool hasUniqueName)
{
const char* strStart = (const char*)data;
int strLen = (int)strlen((const char*)data);
if (strLen == 0)
return NULL;
data += strLen + 1;
if (hasUniqueName)
{
strLen = (int)strlen((const char*)data);
data += strLen + 1;
}
char* retVal = (char*)mCodeView->mAlloc.AllocBytes((int)(data - (uint8*)strStart));
memcpy(retVal, strStart, data - (uint8*)strStart);
return retVal;
}
int BlCvTypeContainer::CreateMasterTag(int tagId, BlTypeInfo* outTypeInfo)
{
#define DECL_LEAF(leafType, leafName) \
leafType& leafName = *(leafType*)&outBuffer[2];
#define FIXTPI(varName) \
varName = GetMasterTPITag(varName);
#define FIXIPI(varName) \
varName = GetMasterIPITag(varName);
uint8* sectionData = mSectionData; //mCvTypeSectionData;
uint8* srcDataStart = sectionData + mCvTagStartMap[tagId - mCvMinTag];
int16 tagLen = *(int16*)(srcDataStart - 2);
uint8* srcDataEnd = srcDataStart + tagLen;
int outSize = (int)(srcDataEnd - srcDataStart) + 2;
uint8 outBuffer[0x10000];
memcpy(outBuffer, srcDataStart - 2, outSize);
uint8* data = (uint8*)outBuffer + 2;
uint8* dataEnd = data + tagLen;
int16 trLeafType = GET(uint16);
BF_ASSERT(((intptr)data) % 4 == 0);
switch (trLeafType)
{
case LF_VTSHAPE:
break;
case LF_LABEL:
break;
case LF_STRUCTURE:
case LF_CLASS:
{
DECL_LEAF(lfClass, classInfo);
FIXTPI(classInfo.derived);
FIXTPI(classInfo.field);
FIXTPI(classInfo.vshape);
}
break;
case LF_ENUM:
{
DECL_LEAF(lfEnum, enumInfo);
FIXTPI(enumInfo.field);
}
break;
case LF_UNION:
{
DECL_LEAF(lfUnion, unionInfo);
FIXTPI(unionInfo.field);
}
break;
case LF_ARRAY:
{
DECL_LEAF(lfArray, arrayInfo);
FIXTPI(arrayInfo.elemtype);
FIXTPI(arrayInfo.idxtype);
}
break;
case LF_POINTER:
{
DECL_LEAF(lfPointer, pointerInfo);
FIXTPI(pointerInfo.utype);
if ((pointerInfo.attr.ptrmode == CV_PTR_MODE_PMEM) || (pointerInfo.attr.ptrmode == CV_PTR_MODE_PMFUNC))
{
FIXTPI(pointerInfo.pbase.pm.pmclass);
}
else if (pointerInfo.attr.ptrmode == CV_PTR_BASE_TYPE)
{
FIXTPI(pointerInfo.pbase.btype.index);
}
}
break;
case LF_MODIFIER:
{
DECL_LEAF(lfModifier, modifierInfo);
FIXTPI(modifierInfo.type);
}
break;
case LF_MFUNCTION:
{
DECL_LEAF(lfMFunc, func);
FIXTPI(func.rvtype);
FIXTPI(func.classtype);
FIXTPI(func.thistype);
FIXTPI(func.arglist);
}
break;
case LF_PROCEDURE:
{
DECL_LEAF(lfProc, proc);
FIXTPI(proc.rvtype);
FIXTPI(proc.arglist);
}
break;
case LF_FIELDLIST:
{
while (data < dataEnd)
{
static int itrIdx = 0;
itrIdx++;
uint8* leafDataStart = data;
int leafType = (int)GET(uint16);
switch (leafType)
{
case LF_VFUNCTAB:
{
lfVFuncTab& vfuncTab = *(lfVFuncTab*)leafDataStart;
FIXTPI(vfuncTab.type);
data = (uint8*)(&vfuncTab + 1);
}
break;
case LF_BCLASS:
{
lfBClass& baseClassInfo = *(lfBClass*)leafDataStart;
data = (uint8*)&baseClassInfo.offset;
int thisOffset = (int)BlCvParser::CvParseConstant(data);
FIXTPI(baseClassInfo.index);
}
break;
case LF_VBCLASS:
case LF_IVBCLASS:
{
lfVBClass& baseClassInfo = *(lfVBClass*)leafDataStart;
data = (uint8*)&baseClassInfo.vbpoff;
int thisOffset = (int)BlCvParser::CvParseConstant(data);
int vTableOffset = (int)BlCvParser::CvParseConstant(data);
FIXTPI(baseClassInfo.index);
FIXTPI(baseClassInfo.vbptr);
}
break;
case LF_ENUMERATE:
{
CV_fldattr_t fieldAttr = GET(CV_fldattr_t);
int64 fieldVal = BlCvParser::CvParseConstant(data);
const char* fieldName = BlCvParser::CvParseString(data);
}
break;
case LF_NESTTYPE:
{
lfNestType& nestType = *(lfNestType*)leafDataStart;
FIXTPI(nestType.index);
data = (uint8*)&nestType.Name;
const char* typeName = BlCvParser::CvParseString(data);
}
break;
case LF_ONEMETHOD:
{
lfOneMethod& oneMethod = *(lfOneMethod*)leafDataStart;
FIXTPI(oneMethod.index);
data = (uint8*)&oneMethod.vbaseoff;
int virtOffset = -1;
if ((oneMethod.attr.mprop == CV_MTintro) || (oneMethod.attr.mprop == CV_MTpureintro))
{
virtOffset = GET(int32);
}
const char* methodName = BlCvParser::CvParseString(data);
}
break;
case LF_METHOD:
{
lfMethod& method = *(lfMethod*)leafDataStart;
FIXTPI(method.mList);
data = (uint8*)&method.Name;
const char* methodName = BlCvParser::CvParseString(data);
}
break;
case LF_MEMBER:
case LF_STMEMBER:
{
lfMember& member = *(lfMember*)leafDataStart;
FIXTPI(member.index);
bool isStatic = leafType == LF_STMEMBER;
data = (uint8*)&member.offset;
int memberOffset = -1;
if (!isStatic)
{
memberOffset = (int)BlCvParser::CvParseConstant(data);
//
}
char* fieldName = (char*)BlCvParser::CvParseString(data);
}
break;
default:
BF_FATAL("Unhandled");
}
PTR_ALIGN(data, outBuffer, 4);
//BF_ASSERT(((intptr)data) % 4 == 0);
}
}
break;
case LF_ARGLIST:
{
int argCount = GET(int32);
for (int argIdx = 0; argIdx < argCount; argIdx++)
{
CV_typ_t& argTypeId = GET(CV_typ_t);
FIXTPI(argTypeId);
}
}
break;
case LF_METHODLIST:
{
while (data < dataEnd)
{
mlMethod& method = *(mlMethod*)data;
FIXTPI(method.index);
data = (uint8*)method.vbaseoff;
if ((method.attr.mprop == CV_MTintro) || (method.attr.mprop == CV_MTpureintro))
{
int virtOffset = GET(int32);
}
}
}
break;
case LF_STRING_ID:
break;
case LF_SUBSTR_LIST:
{
DECL_LEAF(lfArgList, argList);
data = (uint8*)&argList.arg;
for (int idx = 0; idx < (int)argList.count; idx++)
{
CV_ItemId& itemId = GET(CV_ItemId);
FIXIPI(itemId);
}
}
break;
case LF_UDT_SRC_LINE:
{
DECL_LEAF(lfUdtSrcLine, udtSrcLine);
udtSrcLine.leaf = LF_UDT_MOD_SRC_LINE;
FIXTPI(udtSrcLine.type);
FIXIPI(udtSrcLine.src);
lfUdtModSrcLine& udtModSrcLine = *(lfUdtModSrcLine*)&udtSrcLine;
udtModSrcLine.imod = 1;
outSize += 4;
*(int16*)(outBuffer) += 4;
}
break;
case LF_FUNC_ID:
{
DECL_LEAF(lfFuncId, funcId);
FIXIPI(funcId.scopeId);
FIXTPI(funcId.type);
}
break;
case LF_MFUNC_ID:
{
DECL_LEAF(lfMFuncId, mfuncId);
FIXTPI(mfuncId.parentType);
FIXTPI(mfuncId.type);
}
break;
case LF_BUILDINFO:
{
DECL_LEAF(lfBuildInfo, buildInfo);
data = (uint8*)&buildInfo.arg;
for (int idx = 0; idx < buildInfo.count; idx++)
{
CV_ItemId& itemId = GET(CV_ItemId);
FIXIPI(itemId);
}
}
break;
case LF_BITFIELD:
{
DECL_LEAF(lfBitfield, bitfield);
FIXTPI(bitfield.type);
}
break;
case LF_VFTABLE:
{
DECL_LEAF(lfVftable, vtTable);
FIXTPI(vtTable.type);
FIXTPI(vtTable.baseVftable);
}
break;
default:
NotImpl();
break;
}
BF_ASSERT(*(int16*)(outBuffer) == outSize - 2);
outTypeInfo->mData.Write(outBuffer, outSize);
return outTypeInfo->mCurTagId++;
}
void BlCvTypeContainer::HashName(const char* namePtr, bool hasMangledName, HashContext& hashContext)
{
int hashSize = (int)strlen(namePtr);
if (hasMangledName)
hashSize += 1 + (int)strlen(namePtr + hashSize + 1);
hashContext.Mixin(namePtr, hashSize);
}
int BlCvTypeContainer::GetMasterTPITag(int tagId)
{
if (tagId == 0)
return 0;
if (tagId < mCvMinTag)
return tagId;
int masterTag = (*mTPIMap)[tagId - mCvMinTag];
if (masterTag == -1)
{
// Ensure we're TPI
BF_ASSERT(&mTagMap == mTPIMap);
ParseTag(tagId);
masterTag = (*mTPIMap)[tagId - mCvMinTag];
BF_ASSERT(masterTag != -1);
return masterTag;
}
BF_ASSERT(masterTag != -1);
return masterTag;
}
int BlCvTypeContainer::GetMasterIPITag(int tagId)
{
if (tagId == 0)
return 0;
// Ensure we're IPI
BF_ASSERT(&mTagMap == mIPIMap);
if (tagId < mCvMinTag)
return tagId;
int typeIdx = mTagMap[tagId - mCvMinTag];
BF_ASSERT(typeIdx != -1);
return typeIdx;
}
void BlCvTypeContainer::NotImpl()
{
BF_FATAL("NotImpl");
}
void BlCvTypeContainer::ScanTypeData()
{
uint8* sectionData = mSectionData;
int sectionSize = mSectionSize;
uint8* data = (uint8*)sectionData;
uint8* dataEnd = data + sectionSize;
if (mCvMinTag == -1)
{
mCvMinTag = 0x1000;
int tagCountGuess = sectionSize / 128;
mCvTagStartMap.reserve(tagCountGuess);
int tagIdx = mCvMinTag;
while (data < dataEnd)
{
int tagLen = GET(uint16);
uint8* dataStart = data;
uint8* dataTagEnd = data + tagLen;
mCvTagStartMap.push_back((int)(data - sectionData));
data = dataTagEnd;
tagIdx++;
}
mCvMaxTag = tagIdx;
}
else
{
int tagIdx = mCvMinTag;
while (data < dataEnd)
{
int tagLen = GET(uint16);
uint8* dataStart = data;
uint8* dataTagEnd = data + tagLen;
mCvTagStartMap[tagIdx - mCvMinTag] = (int)(data - sectionData);
data = dataTagEnd;
tagIdx++;
}
}
}
void BlCvTypeContainer::HashTPITag(int tagId, HashContext& hashContext)
{
int masterTagId = GetMasterTPITag(tagId);
hashContext.Mixin(masterTagId);
}
void BlCvTypeContainer::HashIPITag(int tagId, HashContext& hashContext)
{
int masterTagId = GetMasterIPITag(tagId);
hashContext.Mixin(masterTagId);
}
void BlCvTypeContainer::HashTagContent(int tagId, HashContext& hashContext, bool& isIPI)
{
uint8* sectionData = mSectionData; //mCvTypeSectionData;
uint8* data = sectionData + mCvTagStartMap[tagId - mCvMinTag];
uint8* dataStart = data;
int16 tagLen = *(int16*)(data - 2);
uint8* dataEnd = data + tagLen;
int16 trLeafType = GET(uint16);
hashContext.Mixin(trLeafType);
switch (trLeafType)
{
case LF_VTSHAPE:
{
lfVTShape& vtShape = *(lfVTShape*)dataStart;
data = (uint8*)&vtShape.desc;
int shapeBytes = (vtShape.count + 1) / 2;
hashContext.Mixin(data, shapeBytes);
}
break;
case LF_LABEL:
{
lfLabel& label = *(lfLabel*)dataStart;
hashContext.Mixin(label.mode);
}
break;
case LF_ARGLIST:
{
int argCount = (int)GET(int32);
hashContext.Mixin(argCount);
for (int argIdx = 0; argIdx < (int)argCount; argIdx++)
{
HashTPITag(GET(CV_typ_t), hashContext);
}
}
break;
case LF_FIELDLIST:
{
while (data < dataEnd)
{
uint8* leafDataStart = data;
int leafType = (int)GET(uint16);
hashContext.Mixin(leafType);
switch (leafType)
{
case LF_VFUNCTAB:
{
lfVFuncTab& vfuncTab = *(lfVFuncTab*)leafDataStart;
HashTPITag(vfuncTab.type, hashContext);
data = (uint8*)(&vfuncTab + 1);
}
break;
case LF_BCLASS:
{
lfBClass& baseClassInfo = *(lfBClass*)leafDataStart;
data = (uint8*)&baseClassInfo.offset;
int thisOffset = (int)BlCvParser::CvParseConstant(data);
hashContext.Mixin(thisOffset);
HashTPITag(baseClassInfo.index, hashContext);
}
break;
case LF_VBCLASS:
case LF_IVBCLASS:
{
lfVBClass& baseClassInfo = *(lfVBClass*)leafDataStart;
data = (uint8*)&baseClassInfo.vbpoff;
int thisOffset = (int)BlCvParser::CvParseConstant(data);
int vTableOffset = (int)BlCvParser::CvParseConstant(data);
hashContext.Mixin(baseClassInfo.attr);
HashTPITag(baseClassInfo.index, hashContext);
HashTPITag(baseClassInfo.vbptr, hashContext);
HashTPITag(thisOffset, hashContext);
HashTPITag(vTableOffset, hashContext);
}
break;
case LF_ENUMERATE:
{
CV_fldattr_t fieldAttr = GET(CV_fldattr_t);
int64 fieldVal = BlCvParser::CvParseConstant(data);
const char* fieldName = BlCvParser::CvParseString(data);
hashContext.Mixin(fieldAttr);
hashContext.Mixin(fieldVal);
hashContext.MixinStr(fieldName);
}
break;
case LF_NESTTYPE:
{
int16 pad = GET(int16);
int32 nestedTypeId = GET(int32);
//int64 nestedSize = BlCvParser::CvParseConstant(data);
const char* typeName = BlCvParser::CvParseString(data);
HashTPITag(nestedTypeId, hashContext);
}
break;
case LF_ONEMETHOD:
{
CV_fldattr_t attr = GET(CV_fldattr_t);
CV_typ_t methodTypeId = GET(CV_typ_t);
hashContext.Mixin(attr);
HashTPITag(methodTypeId, hashContext);
int virtOffset = -1;
if ((attr.mprop == CV_MTintro) || (attr.mprop == CV_MTpureintro))
{
virtOffset = GET(int32);
hashContext.Mixin(virtOffset);
}
const char* name = BlCvParser::CvParseString(data);
hashContext.MixinStr(name);
}
break;
case LF_METHOD:
{
int count = (int)GET(uint16);
int32 methodList = GET(int32);
const char* name = BlCvParser::CvParseString(data);
hashContext.MixinStr(name);
}
break;
case LF_MEMBER:
case LF_STMEMBER:
{
bool isStatic = leafType == LF_STMEMBER;
bool isConst = false;
CV_fldattr_t attr = GET(CV_fldattr_t);
CV_typ_t fieldTypeId = GET(CV_typ_t);
hashContext.Mixin(attr);
int memberOffset = -1;
if (!isStatic)
{
memberOffset = (int)BlCvParser::CvParseConstant(data);
hashContext.Mixin(memberOffset);
}
const char* name = BlCvParser::CvParseString(data);
hashContext.MixinStr(name);
HashTPITag(fieldTypeId, hashContext);
}
break;
default:
BF_FATAL("Unhandled");
}
PTR_ALIGN(data, sectionData, 4);
}
}
break;
case LF_METHODLIST:
{
while (data < dataEnd)
{
mlMethod& method = *(mlMethod*)data;
bool tempBool = false;
HashTagContent(method.index, hashContext, tempBool);
data = (uint8*)method.vbaseoff;
if ((method.attr.mprop == CV_MTintro) || (method.attr.mprop == CV_MTpureintro))
{
int virtOffset = GET(int32);
hashContext.Mixin(virtOffset);
}
}
}
break;
case LF_STRUCTURE:
case LF_CLASS:
{
lfClass& classInfo = *(lfClass*)dataStart;
data = (uint8*)&classInfo.data;
int dataSize = (int)BlCvParser::CvParseConstant(data);
HashName((char*)data, classInfo.property.hasuniquename, hashContext);
hashContext.Mixin(dataSize);
hashContext.Mixin(classInfo.property);
HashTPITag(classInfo.field, hashContext);
HashTPITag(classInfo.derived, hashContext);
HashTPITag(classInfo.vshape, hashContext);
}
break;
case LF_ENUM:
{
lfEnum& enumInfo = *(lfEnum*)dataStart;
data = (uint8*)enumInfo.Name;
HashName((char*)data, enumInfo.property.hasuniquename, hashContext);
hashContext.Mixin(enumInfo.property);
HashTPITag(enumInfo.utype, hashContext);
HashTPITag(enumInfo.field, hashContext);
}
break;
case LF_UNION:
{
lfUnion& unionInfo = *(lfUnion*)dataStart;
data = (uint8*)unionInfo.data;
int dataSize = (int)BlCvParser::CvParseConstant(data);
HashName((char*)data, unionInfo.property.hasuniquename, hashContext);
hashContext.Mixin(dataSize);
hashContext.Mixin(unionInfo.property);
HashTPITag(unionInfo.field, hashContext);
}
break;
case LF_ARRAY:
{
lfArray& arrayInfo = *(lfArray*)dataStart;
data = (uint8*)arrayInfo.data;
int dataSize = (int)BlCvParser::CvParseConstant(data);
HashName((char*)data, false, hashContext);
HashTPITag(arrayInfo.elemtype, hashContext);
HashTPITag(arrayInfo.idxtype, hashContext);
}
break;
case LF_MFUNCTION:
{
lfMFunc& func = *(lfMFunc*)dataStart;
HashTPITag(func.thistype, hashContext);
HashTPITag(func.classtype, hashContext);
HashTPITag(func.rvtype, hashContext);
HashTPITag(func.arglist, hashContext);
hashContext.Mixin(func.funcattr);
hashContext.Mixin(func.calltype);
hashContext.Mixin(func.parmcount);
hashContext.Mixin(func.thisadjust);
}
break;
case LF_PROCEDURE:
{
lfProc& proc = *(lfProc*)dataStart;
HashTPITag(proc.rvtype, hashContext);
HashTPITag(proc.arglist, hashContext);
hashContext.Mixin(proc.funcattr);
hashContext.Mixin(proc.calltype);
hashContext.Mixin(proc.parmcount);
}
break;
case LF_POINTER:
{
lfPointer& pointerInfo = *(lfPointer*)dataStart;
HashTPITag(pointerInfo.utype, hashContext);
hashContext.Mixin(pointerInfo.attr);
}
break;
case LF_MODIFIER:
{
lfModifier& modifierInfo = *(lfModifier*)dataStart;
HashTPITag(modifierInfo.type, hashContext);
hashContext.Mixin(modifierInfo.attr);
}
break;
case LF_STRING_ID:
{
isIPI = true;
lfStringId& stringId = *(lfStringId*)dataStart;
HashIPITag(stringId.id, hashContext);
HashName((char*)stringId.name, false, hashContext);
}
break;
case LF_SUBSTR_LIST:
{
lfArgList& argList = *(lfArgList*)dataStart;
data = (uint8*)&argList.arg;
for (int idx = 0; idx < (int)argList.count; idx++)
{
CV_ItemId& itemId = GET(CV_ItemId);
HashIPITag(itemId, hashContext);
}
}
break;
case LF_UDT_SRC_LINE:
{
lfUdtSrcLine& srcLine = *(lfUdtSrcLine*)dataStart;
HashTPITag(srcLine.type, hashContext);
HashIPITag(srcLine.src, hashContext);
}
break;
case LF_FUNC_ID:
{
isIPI = true;
lfFuncId& funcId = *(lfFuncId*)dataStart;
HashIPITag(funcId.scopeId, hashContext);
HashTPITag(funcId.type, hashContext);
HashName((char*)funcId.name, false, hashContext);
}
break;
case LF_MFUNC_ID:
{
isIPI = true;
lfMFuncId& mfuncId = *(lfMFuncId*)dataStart;
HashTPITag(mfuncId.parentType, hashContext);
HashTPITag(mfuncId.type, hashContext);
HashName((char*)mfuncId.name, false, hashContext);
}
break;
case LF_BUILDINFO:
{
lfBuildInfo& buildInfo = *(lfBuildInfo*)dataStart;
data = (uint8*)&buildInfo.arg;
for (int idx = 0; idx < (int)buildInfo.count; idx++)
{
CV_ItemId& itemId = GET(CV_ItemId);
HashIPITag(itemId, hashContext);
}
}
break;
case LF_BITFIELD:
{
lfBitfield& bitfield = *(lfBitfield*)dataStart;
HashTPITag(bitfield.type, hashContext);
hashContext.Mixin(bitfield.length);
hashContext.Mixin(bitfield.position);
}
break;
case LF_VFTABLE:
{
lfVftable& vtTable = *(lfVftable*)dataStart;
HashTPITag(vtTable.type, hashContext);
HashTPITag(vtTable.baseVftable, hashContext);
hashContext.Mixin(vtTable.offsetInObjectLayout);
data = (uint8*)&vtTable.Names;
hashContext.Mixin(data, vtTable.len);
}
break;
default:
NotImpl();
break;
}
}
void BlCvTypeContainer::ParseTag(int tagId, bool forceFull)
{
uint8* data = mSectionData + mCvTagStartMap[tagId - mCvMinTag];
uint8* dataStart = data;
int16 tagLen = *(int16*)(data - 2);
uint8* dataEnd = data + tagLen;
int16 trLeafType = GET(uint16);
//TODO: Bad? Good?
//forceFull = true;
bool wantsExt = false;
int memberMasterTag = 0;
switch (trLeafType)
{
case LF_FUNC_ID:
{
mCodeView->mStat_ParseTagFuncs++;
wantsExt = true;
lfFuncId& funcId = *(lfFuncId*)dataStart;
int memberTagId = GetMasterTPITag(funcId.type);
mElementMap[tagId - mCvMinTag] = memberTagId;
/*if (!forceFull)
{
mTagMap[tagId - mCvMinTag] = memberMasterTag | BlTypeMapFlag_InfoExt_ProcId_TypeOnly;
return;
}*/
//return;
}
break;
case LF_MFUNC_ID:
{
mCodeView->mStat_ParseTagFuncs++;
wantsExt = true;
lfMFuncId& funcId = *(lfMFuncId*)dataStart;
int memberTagId = GetMasterTPITag(funcId.type);
mElementMap[tagId - mCvMinTag] = memberTagId;
/*if (!forceFull)
{
mTagMap[tagId - mCvMinTag] = memberMasterTag | BlTypeMapFlag_InfoExt_ProcId_TypeOnly;
return;
}*/
//return;
}
break;
}
HashContext hashContext;
bool isIPI = false;
HashTagContent(tagId, hashContext, isIPI);
auto outTypeInfo = mOutTypeInfo;
if (isIPI)
outTypeInfo = &mCodeView->mIPI;
mCodeView->mStat_TypeMapInserts++;
Val128 hashVal = hashContext.Finish128();
int masterTagId;
auto insertPair = outTypeInfo->mTypeMap.insert(std::make_pair(hashVal, -1));
if (insertPair.second)
{
masterTagId = CreateMasterTag(tagId, outTypeInfo);
insertPair.first->second = masterTagId;
}
else
{
masterTagId = insertPair.first->second;
}
/*if (wantsExt)
{
mTagMap[tagId - mCvMinTag] = (int)mInfoExts.size() | BlTypeMapFlag_InfoExt_ProcId_Resolved;
BlCvTypeInfoExt infoExt;
infoExt.mMasterTag = masterTagId;
infoExt.mMemberMasterTag = memberMasterTag;
mInfoExts.push_back(infoExt);
}
else*/
mTagMap[tagId - mCvMinTag] = masterTagId;
}
void BlCvTypeContainer::ParseTypeData()
{
mTagMap.insert(mTagMap.begin(), mCvTagStartMap.size(), -1);
mElementMap.insert(mElementMap.begin(), mCvTagStartMap.size(), -1);
for (int tagId = mCvMinTag; tagId < mCvMaxTag; tagId++)
{
if (mTagMap[tagId - mCvMinTag] == -1)
ParseTag(tagId);
}
}
//////////////////////////////////////////////////////////////////////////
BlCvTypeSource::BlCvTypeSource()
{
mTypeServerLib = NULL;
mIPI = NULL;
mIsDone = false;
mObjectData = NULL;
}
BlCvTypeSource::~BlCvTypeSource()
{
delete mTypeServerLib;
if (mIPI != &mTPI)
delete mIPI;
}
void BlCvTypeSource::CreateIPI()
{
auto codeView = mTPI.mCodeView;
BF_ASSERT(mIPI == &mTPI);
mIPI = new BlCvTypeContainer();
mIPI->mCodeView = codeView;
mIPI->mOutTypeInfo = &codeView->mIPI;
mIPI->mTPIMap = &mTPI.mTagMap;
mIPI->mIPIMap = &mIPI->mTagMap;
}
void BlCvTypeSource::Init(BlCodeView* codeView)
{
mTPI.mCodeView = codeView;
mTPI.mOutTypeInfo = &codeView->mTPI;
mTPI.mTPIMap = &mTPI.mTagMap;
mTPI.mIPIMap = &mTPI.mTagMap;
mIPI = &mTPI;
}

View file

@ -0,0 +1,94 @@
#pragma once
#include "../Beef/BfCommon.h"
#include "BeefySysLib/FileStream.h"
#include "BeefySysLib/util/BumpAllocator.h"
#include "BeefySysLib/util/Hash.h"
#include "BeefySysLib/util/CritSect.h"
#include "../Compiler/BfUtil.h"
#include <unordered_map>
NS_BF_BEGIN
class BlPdbParser;
class BlTypeInfo;
class BlCompositeType;
class BlCodeView;
class BlType;
class BlStructType;
class BlProcType;
class BlCvTypeInfoExt
{
public:
int mMasterTag;
int mMemberMasterTag;
};
enum BlTypeMapFlag
{
BlTypeMapFlag_InfoExt_ProcId_TypeOnly = 0x80000000,
BlTypeMapFlag_InfoExt_ProcId_Resolved = 0x40000000,
BlTypeMapFlag_InfoExt_MASK = 0x0FFFFFFF
};
class BlCvTypeContainer
{
public:
int mCvMinTag;
int mCvMaxTag;
// Negative values in mTagMap are contextual:
// For LF_FUNC_ID, refers to embedded FunctionType
std::vector<int> mTagMap;
std::vector<int> mElementMap; // From FUNC_ID to FuncType, for example
std::vector<int> mCvTagStartMap;
uint8* mSectionData;
int mSectionSize;
BlCodeView* mCodeView;
BlTypeInfo* mOutTypeInfo;
std::vector<int>* mTPIMap;
std::vector<int>* mIPIMap;
int mIdx;
//std::vector<BlCvTypeInfoExt> mInfoExts;
public:
void NotImpl();
void Fail(const StringImpl& err);
const char* CvParseAndDupString(uint8 *& data, bool hasUniqueName = false);
int CreateMasterTag(int tagId, BlTypeInfo* outTypeInfo);
void HashName(const char* namePtr, bool hasMangledName, HashContext& hashContext);
void HashTPITag(int tagId, HashContext& hashContext);
void HashIPITag(int tagId, HashContext& hashContext);
void HashTagContent(int tagId, HashContext& hashContext, bool& isIPI);
void ParseTag(int tagId, bool forceFull = false);
public:
BlCvTypeContainer();
~BlCvTypeContainer();
int GetMasterTPITag(int tagId);
int GetMasterIPITag(int tagId);
void ScanTypeData();
void ParseTypeData();
};
class BlObjectData;
class BlCvTypeSource
{
public:
BlPdbParser* mTypeServerLib;
BlObjectData* mObjectData;
BlCvTypeContainer mTPI;
BlCvTypeContainer* mIPI;
volatile bool mIsDone;
public:
BlCvTypeSource();
~BlCvTypeSource();
void CreateIPI();
void Init(BlCodeView* codeView);
};
NS_BF_END

209
IDEHelper/Linker/BlHash.cpp Normal file
View file

@ -0,0 +1,209 @@
#include "BlHash.h"
#include "codeview/cvinfo.h"
#include "BlCvParser.h"
USING_NS_BF;
#define GET(T) *((T*)(data += sizeof(T)) - 1)
// These are derived from
// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/include/misc.h
// and
// https://github.com/Microsoft/microsoft-pdb/blob/master/langapi/shared/crc32.h
uint32 BlHash::HashStr_PdbV1(const char* str, int len)
{
uint8* ptr = (uint8*)str;
uint8* end;
if (len != -1)
end = (uint8*)ptr + len;
else
end = (uint8*)ptr + strlen(str);
uint32 hash = 0;
while (ptr <= end - 4)
{
hash ^= *(uint32*)ptr;
ptr += 4;
}
while (ptr <= end - 2)
{
hash ^= *(uint16*)ptr;
ptr += 2;
}
while (ptr < end)
hash ^= *(ptr++);
hash |= 0x20202020;
hash ^= hash >> 11;
return hash ^ (hash >> 16);
}
uint32 BlHash::HashStr_PdbV2(const char* str)
{
uint8* ptr = (uint8*)str;
uint8* end = (uint8*)ptr + strlen(str);
uint32 hash = 0xb170a1bf;
while (ptr <= end - 4)
{
hash += *(uint32*)ptr;
ptr += 4;
hash += hash << 10;
hash ^= hash >> 6;
}
while (ptr < end)
{
hash += *(uint8*)(ptr++);
hash += hash << 10;
hash ^= hash >> 6;
}
return hash * 1664525 + 1013904223;
}
uint32 BlHash::GetSig_Pdb(void* data, int len)
{
static const uint32 crcTab[] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
uint8* ptr = (uint8*)data;
uint8* end = ptr + len;
uint32 crc = 0;
while (ptr < end)
crc = (crc >> 8) ^ crcTab[(crc & 0xff) ^ *ptr++];
return crc;
}
static bool IsUnnamed(const char* name)
{
if (strcmp(name, "<unnamed-tag>") == 0)
return true;
if (strcmp(name, "__unnamed") == 0)
return true;
int nameLen = (int)strlen(name);
if ((nameLen > 15) && (strcmp(name + nameLen - 15, "::<unnamed-tag>") == 0))
return true;
if ((nameLen > 11) && (strcmp(name + nameLen - 15, "::__unnamed") == 0))
return true;
return false;
}
uint32 BlHash::GetTypeHash(uint8*& data)
{
uint16 trLength = GET(uint16);
uint8* dataStart = data;
uint16 trLeafType = GET(uint16);
uint8* dataEnd = dataStart + trLength;
bool didHash = false;
const char* name = NULL;
switch (trLeafType)
{
case LF_STRUCTURE:
case LF_CLASS:
{
lfClass& classInfo = *(lfClass*)dataStart;
data = (uint8*)&classInfo.data;
int dataSize = (int)BlCvParser::CvParseConstant(data);
name = (const char*)data;
break;
}
break;
case LF_ENUM:
{
lfEnum& enumInfo = *(lfEnum*)dataStart;
name = (const char*)enumInfo.Name;
}
break;
case LF_UNION:
{
lfUnion& unionInfo = *(lfUnion*)dataStart;
data = (uint8*)&unionInfo.data;
int dataSize = (int)BlCvParser::CvParseConstant(data);
name = (const char*)data;
}
break;
case LF_UDT_MOD_SRC_LINE:
{
lfUdtModSrcLine& modSrcLine = *(lfUdtModSrcLine*)dataStart;
// Weird, but this is what's required
data = dataEnd;
return BlHash::HashStr_PdbV1((const char*)&modSrcLine.type, 4);
}
break;
}
data = dataEnd;
if (name != NULL)
{
lfClass& classInfo = *(lfClass*)dataStart;
if (!classInfo.property.fwdref)
{
if (classInfo.property.scoped)
{
if (!classInfo.property.hasuniquename)
name = NULL;
else
name = name + strlen(name) + 1;
}
if ((name != NULL) && (!IsUnnamed(name)))
{
return BlHash::HashStr_PdbV1(name);
}
}
}
return BlHash::GetSig_Pdb(dataStart - 2, trLength + 2);
}

16
IDEHelper/Linker/BlHash.h Normal file
View file

@ -0,0 +1,16 @@
#pragma once
#include "../Beef/BfCommon.h"
NS_BF_BEGIN
class BlHash
{
public:
static uint32 HashStr_PdbV1(const char* str, int len = -1);
static uint32 HashStr_PdbV2(const char* str);
static uint32 GetSig_Pdb(void* data, int len);
static uint32 GetTypeHash(uint8*& data);
};
NS_BF_END

228
IDEHelper/Linker/BlMsf.cpp Normal file
View file

@ -0,0 +1,228 @@
#include "BlMsf.h"
#include "BeefySysLib/MemStream.h"
#include "../Compiler/BfAstAllocator.h"
USING_NS_BF;
#define MSF_SIGNATURE_700 "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"
#define CV_BLOCK_SIZE 0x1000
#define PTR_ALIGN(ptr, origPtr, alignSize) ptr = ( (origPtr)+( ((ptr - origPtr) + (alignSize - 1)) & ~(alignSize - 1) ) )
//////////////////////////////////////////////////////////////////////////
BlMsfWorkThread::BlMsfWorkThread()
{
mMsf = NULL;
mDone = false;
mSortDirty = false;
}
BlMsfWorkThread::~BlMsfWorkThread()
{
Stop();
}
void BlMsfWorkThread::Stop()
{
mDone = true;
mWorkEvent.Set();
WorkThread::Stop();
}
void BlMsfWorkThread::Run()
{
while (!mDone)
{
if (mSortedWriteBlockWorkQueue.empty())
{
// Only fill in new entries when our queue is empty. This is not a strong ordering guarantee.
bool sortDirty = false;
mCritSect.Lock();
if (!mWriteBlockWorkQueue.empty())
{
sortDirty = true;
mSortedWriteBlockWorkQueue.insert(mSortedWriteBlockWorkQueue.begin(), mWriteBlockWorkQueue.begin(), mWriteBlockWorkQueue.end());
mWriteBlockWorkQueue.clear();
}
mCritSect.Unlock();
BlMsfBlock* block = NULL;
if (sortDirty)
{
std::sort(mSortedWriteBlockWorkQueue.begin(), mSortedWriteBlockWorkQueue.end(), [](BlMsfBlock* lhs, BlMsfBlock* rhs)
{
return lhs->mIdx < rhs->mIdx;
});
}
}
BlMsfBlock* block = NULL;
if (!mSortedWriteBlockWorkQueue.empty())
{
block = mSortedWriteBlockWorkQueue.front();
mSortedWriteBlockWorkQueue.pop_front();
}
if (block == NULL)
{
mWorkEvent.WaitFor();
continue;
}
mMsf->WriteBlock(block);
}
}
void BlMsfWorkThread::Add(BlMsfBlock* block)
{
AutoCrit autoCrit(mCritSect);
mWriteBlockWorkQueue.push_back(block);
mWorkEvent.Set();
mSortDirty = true;
}
//////////////////////////////////////////////////////////////////////////
BlMsf::BlMsf()
{
mCodeView = NULL;
mBlockSize = 0x1000;
mFreePageBitmapIdx = 1;
mFileSize = 0;
mAllocatedFileSize = 0;
mWorkThread.mMsf = this;
}
BlMsf::~BlMsf()
{
for (auto block : mBlocks)
delete block->mData;
}
void BlMsf::WriteBlock(BlMsfBlock* block)
{
if (mAllocatedFileSize > mFileSize)
{
mFS.SetSizeFast(mAllocatedFileSize);
mFileSize = mAllocatedFileSize;
}
int wantPos = block->mIdx * CV_BLOCK_SIZE;
if (wantPos > mFileSize)
{
mFS.SetSizeFast(wantPos);
mFileSize = wantPos;
}
if (mFileSize == wantPos)
mFileSize = wantPos + CV_BLOCK_SIZE;
mFS.SetPos(block->mIdx * CV_BLOCK_SIZE);
mFS.Write(block->mData, CV_BLOCK_SIZE);
delete block->mData;
block->mData = NULL;
}
bool BlMsf::Create(const StringImpl& fileName)
{
mFileName = fileName;
//if (!mFS.Open(fileName, GENERIC_WRITE | GENERIC_READ))
//return false;
if (!mFS.Open(fileName, BfpFileCreateKind_CreateAlways, (BfpFileCreateFlags)(BfpFileCreateFlag_Write | BfpFileCreateFlag_Read)))
return false;
// Header
Alloc(true, false);
// First FPM block
Alloc(true, false);
// 'Old' FPM block
Alloc(true, false);
return true;
}
int BlMsf::Alloc(bool clear, bool skipFPMBlock)
{
int blockIdx = (int)mBlocks.size();
BlMsfBlock* msfBlock = mBlocks.Alloc();
msfBlock->mData = new uint8[CV_BLOCK_SIZE];
if (clear)
memset(msfBlock->mData, 0, CV_BLOCK_SIZE);
msfBlock->mIdx = blockIdx;
if ((skipFPMBlock) && ((blockIdx % CV_BLOCK_SIZE) == mFreePageBitmapIdx))
{
// We need this page as a Free Page Bitmap. This will be triggered once for
// every 16MB of PDB. It should be once every 128MB but isn't because of a
// Microsoft bug in their initial implementation.
return Alloc();
}
mAllocatedFileSize = (int)(mBlocks.size() * CV_BLOCK_SIZE);
return blockIdx;
}
void BlMsf::FlushBlock(int blockIdx)
{
if (mWorkThread.mThread == NULL)
mWorkThread.Start();
mWorkThread.Add(mBlocks[blockIdx]);
}
void BlMsf::Finish(int rootBlockNum, int streamDirLen)
{
mWorkThread.Stop();
int numBlocks = (int)mBlocks.size();
MemStream headerStream(mBlocks[0]->mData, CV_BLOCK_SIZE, false);
headerStream.Write(MSF_SIGNATURE_700, 32);
headerStream.Write((int32)CV_BLOCK_SIZE); // Page size
headerStream.Write((int32)mFreePageBitmapIdx); // FreeBlockMapBlock - always use page 1. It's allowed to flip between 1 and 2.
headerStream.Write((int32)numBlocks); // Total page count
headerStream.Write((int32)streamDirLen);
headerStream.Write((int32)0); // Unknown
headerStream.Write((int32)rootBlockNum);
// Create Free Page Bitmap
BfBitSet bitset;
bitset.Init(numBlocks);
int numBytes = (numBlocks + 7) / 8;
memset(bitset.mBits, 0xFF, numBytes);
for (int i = 0; i < numBlocks; i++)
bitset.Clear(i);
// Bits are written in blocks at block nums (mFreePageBitmapIdx + k*CV_BLOCK_SIZE)
// This is a little strange, but the actual mFreePageBitmapIdx block can only hold enough bits for
// 128MB of pages, so PSBs over that size get spread at 'CV_BLOCK_SIZE' intervals. This is technically
// wrong, as it should be 'CV_BLOCK_SIZE*8', but that's an Microsoft bug that can't be fixed now.
uint8* data = (uint8*)bitset.mBits;
int bytesLeft = numBytes;
int curBlockNum = mFreePageBitmapIdx;
while (bytesLeft > 0)
{
int writeBytes = std::min(bytesLeft, CV_BLOCK_SIZE);
uint8* dataDest = (uint8*)mBlocks[curBlockNum]->mData;
memcpy(dataDest, data, writeBytes);
bytesLeft -= writeBytes;
data += writeBytes;
curBlockNum += CV_BLOCK_SIZE;
}
// Do actual write
for (auto block : mBlocks)
{
if (block->mData != NULL)
WriteBlock(block);
}
mFS.Close();
}

85
IDEHelper/Linker/BlMsf.h Normal file
View file

@ -0,0 +1,85 @@
#pragma once
#include "../Beef/BfCommon.h"
#include "BeefySysLib/FileStream.h"
#include "BeefySysLib/util/CritSect.h"
#include "BeefySysLib/util/WorkThread.h"
#include "../Compiler/BfUtil.h"
#include <queue>
NS_BF_BEGIN
struct BlMsfBlock
{
public:
int mIdx;
bool mIsUsed;
void* mData;
public:
BlMsfBlock()
{
mIdx = -1;
mIsUsed = true;
mData = NULL;
}
};
class BlCodeView;
class BlMsf;
class BlMsfWorkThread : public WorkThread
{
public:
BlMsf* mMsf;
bool mDone;
CritSect mCritSect;
SyncEvent mWorkEvent;
std::deque<BlMsfBlock*> mSortedWriteBlockWorkQueue;
std::deque<BlMsfBlock*> mWriteBlockWorkQueue;
bool mSortDirty;
public:
BlMsfWorkThread();
~BlMsfWorkThread();
virtual void Stop() override;
virtual void Run() override;
void Add(BlMsfBlock* block);
};
class BlMsf
{
public:
SysFileStream mFS;
String mFileName;
int mFileSize;
int mAllocatedFileSize;
BlCodeView* mCodeView;
int mBlockSize;
int mFreePageBitmapIdx; // Either 1 or 2
OwnedVector<BlMsfBlock> mBlocks;
BlMsfWorkThread mWorkThread;
public:
void WriteBlock(BlMsfBlock* block);
public:
BlMsf();
~BlMsf();
bool Create(const StringImpl& fileName);
int Alloc(bool clear = true, bool skipFPMBlocks = true);
void FlushBlock(int blockIdx);
void Finish(int rootBlockNum, int streamDirLen);
};
NS_BF_END

View file

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

View file

@ -0,0 +1,65 @@
#pragma once
#include "../Beef/BfCommon.h"
#include "BeefySysLib/FileStream.h"
#include "BeefySysLib/util/BumpAllocator.h"
#include "BeefySysLib/util/Hash.h"
#include "../Compiler/BfUtil.h"
#include <unordered_map>
NS_BF_BEGIN
struct BlCvStringTable
{
int mStream;
int mStreamOffset;
const char* mStrTable;
BlCvStringTable()
{
mStream = -1;
mStreamOffset = 0;
mStrTable = NULL;
}
};
class MappedFile;
class BlCvTypeSource;
class BlPdbParser
{
public:
String mFileName;
MappedFile* mMappedFile;
uint8* mData;
int mCvPageSize;
BlCvStringTable mStringTable;
std::vector<int32> mCvStreamSizes;
std::vector<int32> mCvStreamPtrStartIdxs;
std::vector<int32> mCvStreamPtrs;
std::vector<int> mCvIPITagStartMap;
uint8* mCvHeaderData;
uint8* mCvTypeSectionData;
uint8* mCvIPIData;
BlCvTypeSource* mTypeSource;
public:
void Fail(const StringImpl& err);
void NotImpl();
uint8* CvReadStream(int streamIdx, int* outSize = NULL);
bool CvParseHeader();
void ParseTypeData();
void ParseIPIData();
public:
BlPdbParser();
~BlPdbParser();
bool Load(const StringImpl& fileName);
bool ParseCv(uint8 * rootDirData);
};
NS_BF_END

View file

@ -0,0 +1,36 @@
#include "BlSymTable.h"
#include "BlContext.h"
USING_NS_BF;
BlSymTable::BlSymTable()
{
#ifdef BL_USE_DENSEMAP_SYMTAB
mMap.set_empty_key(Val128(-1));
//mMap.set_empty_key("");
mMap.min_load_factor(0);
mMap.resize(100000);
#endif
}
BlSymbol* BlSymTable::Add(const char* name, bool* isNew)
{
Val128 val128 = Hash128(name, (int)strlen(name));
auto itr = mMap.insert(std::make_pair(val128, (BlSymbol*)NULL));
if (!itr.second)
{
if (isNew != NULL)
*isNew = false;
return itr.first->second;
}
if (isNew != NULL)
*isNew = true;
auto blSymbol = new BlSymbol();
itr.first->second = blSymbol;
blSymbol->mName = name;
blSymbol->mKind = BlSymKind_Undefined;
blSymbol->mObjectDataIdx = -1;
return blSymbol;
}

View file

@ -0,0 +1,36 @@
#pragma once
#include "../Beef/BfCommon.h"
#include <unordered_map>
#include "BeefySysLib/util/Hash.h"
//#define BL_USE_DENSEMAP_SYMTAB
#ifdef BL_USE_DENSEMAP_SYMTAB
#include <sparsehash/dense_hash_map>
#include <sparsehash/dense_hash_set>
#endif
NS_BF_BEGIN
class BlContext;
class BlSymbol;
class BlSymTable
{
public:
BlContext* mContext;
#ifdef BL_USE_DENSEMAP_SYMTAB
google::dense_hash_map<Val128, BlSymbol*, Val128::Hash, Val128::Equals> mMap;
#else
std::unordered_map<Val128, BlSymbol*, Val128::Hash, Val128::Equals> mMap;
#endif
public:
BlSymTable();
BlSymbol* Add(const char* name, bool* isNew = NULL);
};
NS_BF_END