mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 03:28:20 +02:00

Throwing error on member references with ".." cascade token outside invocations (ie: "ts..mA = 123") Fixed 'Thread.ModuleTLSIndex' error - which caused us TLS lookup failures in Beef DLLs Fixed some hotswap errors Made BeefPerf shut down properly Fixed an 'int literal' FixIntUnknown issue where rhs was System.Object which caused an illegal boxing Fixed COFF::LocateSymbol issues with Win32 and also with linking to static libraries - showed up with hot-linking in fmod when hot-adding a floating point mod Fixed a couple memory leaks Fixed alignment issue in COFF::ParseCompileUnit
1298 lines
No EOL
28 KiB
C++
1298 lines
No EOL
28 KiB
C++
#pragma once
|
|
|
|
#include "DebugCommon.h"
|
|
#include "CPU.h"
|
|
#include "BeefySysLib/Common.h"
|
|
#include "BeefySysLib/util/SLIList.h"
|
|
#include "BeefySysLib/util/BumpAllocator.h"
|
|
#include "BeefySysLib/util/HashSet.h"
|
|
#include "BeefySysLib/util/MappedFile.h"
|
|
#include "BeefySysLib/DataStream.h"
|
|
#include "Compiler/BfAst.h"
|
|
#include "Compiler/BfUtil.h"
|
|
#include "BumpList.h"
|
|
#include "RadixMap.h"
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <functional>
|
|
#include "Debugger.h"
|
|
#include "StrHashMap.h"
|
|
#include "DbgTypeMap.h"
|
|
#include "COFFData.h"
|
|
#include "X86Target.h"
|
|
|
|
NS_BF_DBG_BEGIN
|
|
|
|
using namespace Beefy;
|
|
|
|
class DbgModule;
|
|
|
|
enum DbgTypeCode : uint8
|
|
{
|
|
DbgType_Void,
|
|
DbgType_Root,
|
|
DbgType_Null,
|
|
DbgType_i8,
|
|
DbgType_u8,
|
|
DbgType_i16,
|
|
DbgType_u16,
|
|
DbgType_i32,
|
|
DbgType_u32,
|
|
DbgType_i64,
|
|
DbgType_u64,
|
|
DbgType_i128,
|
|
DbgType_u128,
|
|
DbgType_Single,
|
|
DbgType_Double,
|
|
DbgType_Float96,
|
|
DbgType_Float128,
|
|
DbgType_ComplexFloat,
|
|
DbgType_ComplexDouble,
|
|
DbgType_ComplexDouble96,
|
|
DbgType_ComplexDouble128,
|
|
DbgType_SChar,
|
|
DbgType_SChar16,
|
|
DbgType_SChar32,
|
|
DbgType_UChar,
|
|
DbgType_UChar16,
|
|
DbgType_UChar32,
|
|
DbgType_Utf8,
|
|
DbgType_Utf16,
|
|
DbgType_Utf32,
|
|
DbgType_Bool,
|
|
DbgType_Namespace,
|
|
DbgType_Enum,
|
|
DbgType_VTable,
|
|
DbgType_Bitfield,
|
|
DbgType_Class,
|
|
DbgType_Struct,
|
|
DbgType_Union,
|
|
DbgType_TypeDef,
|
|
|
|
#ifdef BF_DBG_32
|
|
DbgType_IntPtr_Alias = DbgType_i32,
|
|
DbgType_UIntPtr_Alias = DbgType_u32,
|
|
#else
|
|
DbgType_IntPtr_Alias = DbgType_i64,
|
|
DbgType_UIntPtr_Alias = DbgType_u64,
|
|
#endif
|
|
DbgType_DefinitionEnd = DbgType_TypeDef,
|
|
|
|
DbgType_Ptr,
|
|
DbgType_PtrToMember,
|
|
DbgType_SizedArray,
|
|
DbgType_Ref,
|
|
DbgType_RValueReference,
|
|
DbgType_Const,
|
|
DbgType_Volatile,
|
|
DbgType_Unaligned,
|
|
DbgType_Restrict,
|
|
DbgType_Subroutine,
|
|
DbgType_Unspecified,
|
|
DbgType_RawText,
|
|
|
|
DbgType_RegGroup,
|
|
|
|
DbgType_COUNT,
|
|
};
|
|
|
|
class DebugTarget;
|
|
class WinDebugger;
|
|
class DbgType;
|
|
class DbgBlock;
|
|
|
|
enum DbgClassType : uint8
|
|
{
|
|
DbgClassType_None,
|
|
DbgClassType_CompileUnit,
|
|
DbgClassType_Subprogram,
|
|
DbgClassType_Type,
|
|
DbgClassType_Member,
|
|
DbgClassType_Block,
|
|
DbgClassType_Variable,
|
|
};
|
|
|
|
enum DbgFileExistKind : uint8
|
|
{
|
|
DbgFileExistKind_NotChecked,
|
|
DbgFileExistKind_NotFound,
|
|
DbgFileExistKind_HasOldSourceCommand,
|
|
DbgFileExistKind_Found
|
|
};
|
|
|
|
class DbgCompileUnit;
|
|
|
|
struct DbgSectionData
|
|
{
|
|
uint8* mData;
|
|
int mSize;
|
|
};
|
|
|
|
class DbgDebugData
|
|
{
|
|
public:
|
|
DbgCompileUnit* mCompileUnit;
|
|
int mTagIdx;
|
|
|
|
public:
|
|
DbgDebugData()
|
|
{
|
|
mCompileUnit = NULL;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
virtual ~DbgDebugData()
|
|
{
|
|
}
|
|
#endif
|
|
};
|
|
|
|
enum DbgLocationLenKind
|
|
{
|
|
DbgLocationLenKind_SegPlusOffset = -0x80
|
|
};
|
|
|
|
class DbgVariable : public DbgDebugData
|
|
{
|
|
public:
|
|
static const DbgClassType ClassType = DbgClassType_Variable;
|
|
|
|
const char* mName;
|
|
const char* mLinkName;
|
|
addr_target mRangeStart;
|
|
int64 mConstValue;
|
|
DbgType* mType;
|
|
const uint8* mLocationData;
|
|
int mRangeLen;
|
|
int mMemberOffset;
|
|
int8 mLocationLen;
|
|
uint8 mBitSize;
|
|
uint8 mBitOffset;
|
|
bool mIsExtern;
|
|
bool mIsParam;
|
|
bool mIsMember;
|
|
bool mIsStatic;
|
|
bool mIsConst;
|
|
bool mInAutoStaticMap;
|
|
bool mSigNoPointer; // Signature was without pointer, mType has pointer
|
|
|
|
addr_target mStaticCachedAddr;
|
|
DbgVariable* mNext;
|
|
|
|
public:
|
|
DbgVariable()
|
|
{
|
|
mBitSize = 0;
|
|
mBitOffset = 0;
|
|
mIsParam = false;
|
|
mLocationData = NULL;
|
|
mLocationLen = 0;
|
|
mIsStatic = false;
|
|
mIsConst = false;
|
|
mConstValue = 0;
|
|
mMemberOffset = 0;
|
|
mInAutoStaticMap = false;
|
|
mStaticCachedAddr = 0;
|
|
}
|
|
|
|
const char* GetMappedName()
|
|
{
|
|
if (mLinkName != NULL)
|
|
return mLinkName;
|
|
return mName;
|
|
}
|
|
};
|
|
|
|
class DbgType;
|
|
class DbgDataMap;
|
|
|
|
typedef std::map<int, Array<int> > DwAsmDebugLineMap;
|
|
|
|
class DbgBlock : public DbgDebugData
|
|
{
|
|
public:
|
|
static const DbgClassType ClassType = DbgClassType_Block;
|
|
|
|
addr_target mLowPC; // If LowPC is -1 then mHighPC is index into debugRanges
|
|
addr_target mHighPC;
|
|
|
|
SLIList<DbgVariable*> mVariables;
|
|
SLIList<DbgBlock*> mSubBlocks;
|
|
|
|
DwAsmDebugLineMap* mAsmDebugLineMap; // empty unless inline asm is used
|
|
|
|
DbgBlock* mNext;
|
|
|
|
bool mAutoStaticVariablesProcessed;
|
|
|
|
public:
|
|
DbgBlock()
|
|
{
|
|
mLowPC = 0;
|
|
mHighPC = 0;
|
|
mAutoStaticVariablesProcessed = false;
|
|
}
|
|
|
|
bool IsEmpty()
|
|
{
|
|
return mLowPC == mHighPC;
|
|
}
|
|
};
|
|
|
|
enum DbgMethodType
|
|
{
|
|
DbgMethodType_Ctor,
|
|
DbgMethodType_Normal,
|
|
};
|
|
|
|
class DbgModule;
|
|
class DbgSrcFile;
|
|
class DbgSrcFileReference;
|
|
class DbgSubprogram;
|
|
|
|
class DbgLineData
|
|
{
|
|
public:
|
|
uint32 mRelAddress;
|
|
int32 mLine;
|
|
int16 mColumn;
|
|
uint16 mContribSize;
|
|
uint16 mCtxIdx;
|
|
|
|
bool IsStackFrameSetup()
|
|
{
|
|
return mColumn != -2;
|
|
}
|
|
};
|
|
|
|
struct DbgLineDataEx
|
|
{
|
|
public:
|
|
DbgLineData* mLineData;
|
|
DbgSubprogram* mSubprogram;
|
|
|
|
DbgLineDataEx()
|
|
{
|
|
mLineData = NULL;
|
|
mSubprogram = NULL;
|
|
}
|
|
|
|
DbgLineDataEx(DbgLineData* lineData, DbgSubprogram* subprogram)
|
|
{
|
|
mLineData = lineData;
|
|
mSubprogram = subprogram;
|
|
}
|
|
|
|
addr_target GetAddress();
|
|
DbgSrcFile* GetSrcFile();
|
|
|
|
bool operator==(DbgLineData* lineData)
|
|
{
|
|
return lineData == mLineData;
|
|
}
|
|
|
|
bool IsNull()
|
|
{
|
|
return mLineData == NULL;
|
|
}
|
|
};
|
|
|
|
class DbgLineInfoCtx
|
|
{
|
|
public:
|
|
DbgSubprogram* mInlinee;
|
|
DbgSrcFile* mSrcFile;
|
|
};
|
|
|
|
class DbgLineInfo
|
|
{
|
|
public:
|
|
DbgLineInfoCtx* mContexts;
|
|
BfSizedArray<DbgLineData> mLines;
|
|
bool mHasInlinees;
|
|
};
|
|
|
|
class HotReplacedLineInfo
|
|
{
|
|
public:
|
|
struct Entry
|
|
{
|
|
DbgLineInfo* mLineInfo;
|
|
DbgSubprogram* mSubprogram;
|
|
};
|
|
|
|
Array<Entry> mEntries;
|
|
};
|
|
|
|
class DbgInlineeInfo
|
|
{
|
|
public:
|
|
DbgSubprogram* mInlineParent;
|
|
DbgSubprogram* mRootInliner;
|
|
DbgLineData mFirstLineData;
|
|
DbgLineData mLastLineData;
|
|
uint32 mInlineeId;
|
|
int mInlineDepth;
|
|
};
|
|
|
|
class DbgSubprogram : public DbgDebugData
|
|
{
|
|
public:
|
|
static const DbgClassType ClassType = DbgClassType_Subprogram;
|
|
|
|
#ifdef BF_DBG_32
|
|
enum LocalBaseRegKind : uint8
|
|
{
|
|
LocalBaseRegKind_None,
|
|
LocalBaseRegKind_ESP,
|
|
LocalBaseRegKind_EBP,
|
|
LocalBaseRegKind_EBX
|
|
};
|
|
#else
|
|
enum LocalBaseRegKind : uint8
|
|
{
|
|
LocalBaseRegKind_None,
|
|
LocalBaseRegKind_RSP,
|
|
LocalBaseRegKind_RBP,
|
|
LocalBaseRegKind_R13
|
|
};
|
|
#endif
|
|
|
|
const char* mName;
|
|
const char* mLinkName;
|
|
int mTemplateNameIdx;
|
|
int mDeclLine;
|
|
int mFrameBaseLen;
|
|
int mPrologueSize;
|
|
const uint8* mFrameBaseData;
|
|
DbgBlock mBlock;
|
|
int mDeferredInternalsSize;
|
|
int mVTableLoc;
|
|
int mStepFilterVersion;
|
|
LocalBaseRegKind mLocalBaseReg;
|
|
bool mHasQualifiedName;
|
|
bool mIsStepFiltered;
|
|
bool mIsStepFilteredDefault;
|
|
bool mVirtual;
|
|
bool mHasThis;
|
|
bool mNeedLineDataFixup;
|
|
bool mWasHotReplaced;
|
|
bool mWasModuleHotReplaced; // Module was hot replaced but a new version of the subprogram wasn't found
|
|
bool mIsOptimized;
|
|
bool mHasLineAddrGaps; // There are gaps of addresses which are not covered by lineinfo
|
|
DbgLineInfo* mLineInfo;
|
|
DbgInlineeInfo* mInlineeInfo;
|
|
DbgType* mParentType;
|
|
DbgType* mReturnType;
|
|
DbgMethodType mMethodType;
|
|
BfProtection mProtection;
|
|
SLIList<DbgVariable*> mParams;
|
|
|
|
DbgSubprogram* mNext;
|
|
|
|
public:
|
|
DbgSubprogram()
|
|
{
|
|
mName = NULL;
|
|
mLinkName = NULL;
|
|
mHasThis = false;
|
|
mNeedLineDataFixup = true;
|
|
mWasHotReplaced = false;
|
|
mWasModuleHotReplaced = false;
|
|
mHasLineAddrGaps = false;
|
|
mPrologueSize = -1;
|
|
mParentType = NULL;
|
|
mDeclLine = 0;
|
|
//mInlinerData = NULL;
|
|
mInlineeInfo = NULL;
|
|
mFrameBaseData = NULL;
|
|
mFrameBaseLen = 0;
|
|
mReturnType = NULL;
|
|
mNext = NULL;
|
|
mMethodType = DbgMethodType_Normal;
|
|
mProtection = BfProtection_Public;
|
|
mVTableLoc = -1;
|
|
mStepFilterVersion = -1;
|
|
}
|
|
|
|
~DbgSubprogram();
|
|
|
|
String ToString();
|
|
DbgLineData* FindClosestLine(addr_target addr, DbgSubprogram** inlinedSubprogram = NULL, DbgSrcFile** srcFile = NULL, int* outLineIdx = NULL);
|
|
DbgType* GetParent();
|
|
DbgType* GetTargetType(); // usually mParentType except for closures
|
|
DbgLanguage GetLanguage();
|
|
bool Equals(DbgSubprogram* checkMethod);
|
|
int GetParamCount();
|
|
String GetParamName(int paramIdx);
|
|
bool IsGenericMethod();
|
|
bool ThisIsSplat();
|
|
|
|
DbgSubprogram* GetRootInlineParent()
|
|
{
|
|
if (mInlineeInfo == NULL)
|
|
return this;
|
|
return mInlineeInfo->mRootInliner;
|
|
}
|
|
|
|
int GetInlineDepth()
|
|
{
|
|
int inlineDepth = 0;
|
|
auto checkSubprogram = this;
|
|
while (checkSubprogram->mInlineeInfo != NULL)
|
|
{
|
|
checkSubprogram = checkSubprogram->mInlineeInfo->mInlineParent;
|
|
inlineDepth++;
|
|
}
|
|
if (mInlineeInfo != NULL)
|
|
BF_ASSERT(inlineDepth == mInlineeInfo->mInlineDepth);
|
|
return inlineDepth;
|
|
}
|
|
|
|
addr_target GetLineAddr(const DbgLineData& lineData);
|
|
DbgSubprogram* GetLineInlinee(const DbgLineData& lineData);
|
|
DbgSrcFile* GetLineSrcFile(const DbgLineData& lineData);
|
|
void PopulateSubprogram();
|
|
};
|
|
|
|
class DbgSubprogramMapEntry
|
|
{
|
|
public:
|
|
addr_target mAddress;
|
|
DbgSubprogram* mEntry;
|
|
DbgSubprogramMapEntry* mNext;
|
|
};
|
|
|
|
class DbgExceptionDirectoryEntry
|
|
{
|
|
public:
|
|
DbgExceptionDirectoryEntry* mNext;
|
|
DbgModule* mDbgModule;
|
|
addr_target mAddress;
|
|
int mOrigAddressOffset;
|
|
int mAddressLength;
|
|
int mExceptionPos;
|
|
};
|
|
|
|
class DbgBaseTypeEntry
|
|
{
|
|
public:
|
|
DbgType* mBaseType;
|
|
DbgBaseTypeEntry* mNext;
|
|
int mThisOffset;
|
|
int mVTableOffset;
|
|
|
|
public:
|
|
DbgBaseTypeEntry()
|
|
{
|
|
mVTableOffset = -1;
|
|
}
|
|
};
|
|
|
|
enum DbgTypePriority
|
|
{
|
|
DbgTypePriority_Normal,
|
|
DbgTypePriority_Unique,
|
|
DbgTypePriority_Primary_Implicit,
|
|
DbgTypePriority_Primary_Explicit
|
|
};
|
|
|
|
struct DbgMethodNameEntry
|
|
{
|
|
const char* mName;
|
|
int mCompileUnitId;
|
|
DbgMethodNameEntry* mNext;
|
|
};
|
|
|
|
enum DbgExtType : int8
|
|
{
|
|
DbgExtType_Unknown,
|
|
DbgExtType_Normal,
|
|
DbgExtType_BfObject,
|
|
DbgExtType_BfPayloadEnum,
|
|
DbgExtType_BfUnion,
|
|
DbgExtType_Interface
|
|
};
|
|
|
|
class DbgType : public DbgDebugData
|
|
{
|
|
public:
|
|
static const DbgClassType ClassType = DbgClassType_Type;
|
|
DbgType* mParent;
|
|
BumpList<DbgType*> mAlternates; // From other compile units
|
|
DbgType* mPrimaryType;
|
|
|
|
DbgTypeCode mTypeCode;
|
|
SLIList<DbgBaseTypeEntry*> mBaseTypes;
|
|
DbgType* mTypeParam;
|
|
SLIList<DbgVariable*> mMemberList;
|
|
|
|
DbgType* mPtrType;
|
|
|
|
DbgBlock* mBlockParam;
|
|
SLIList<DbgMethodNameEntry*> mMethodNameList;
|
|
SLIList<DbgSubprogram*> mMethodList;
|
|
SLIList<DbgType*> mSubTypeList;
|
|
BumpList<DbgType*> mUsingNamespaces;
|
|
SLIList<DbgSubprogram*> mHotReplacedMethodList; // Old methods
|
|
DbgType* mHotNewType; // Only non-null during actual hotloading
|
|
|
|
const char* mName;
|
|
const char* mTypeName;
|
|
int mTemplateNameIdx;
|
|
int mSize; // In bytes
|
|
int mAlign;
|
|
int mDeclFileIdx;
|
|
int mDeclLine;
|
|
int mTypeIdx;
|
|
uint16 mDefinedMembersCount; // For static members
|
|
uint16 mMethodsWithParamsCount;
|
|
bool mIsIncomplete; // Not fully loaded
|
|
bool mIsPacked;
|
|
bool mNeedsGlobalsPopulated;
|
|
bool mHasGlobalsPopulated;
|
|
bool mIsDeclaration;
|
|
bool mHasStaticMembers;
|
|
bool mHasVTable;
|
|
bool mFixedName;
|
|
DbgLanguage mLanguage;
|
|
DbgExtType mExtType;
|
|
DbgTypePriority mPriority; // Is the one stored in the type map
|
|
bool mSizeCalculated;
|
|
|
|
DbgType* mNext;
|
|
|
|
public:
|
|
DbgType();
|
|
~DbgType();
|
|
|
|
//uint64 GetHash();
|
|
DbgType* ResolveTypeDef();
|
|
bool Equals(DbgType* dbgType);
|
|
|
|
bool IsRoot();
|
|
bool IsNull();
|
|
bool IsVoid();
|
|
bool IsValuelessType();
|
|
bool IsPrimitiveType();
|
|
bool IsStruct();
|
|
bool IsValueType();
|
|
bool IsTypedPrimitive();
|
|
bool IsBoolean();
|
|
bool IsInteger();
|
|
bool IsIntegral();
|
|
bool IsChar();
|
|
bool IsChar(DbgLanguage language);
|
|
bool IsNamespace();
|
|
bool IsFloat();
|
|
bool IsCompositeType();
|
|
bool WantsRefThis(); // Beef valuetypes want 'this' by ref, Objects and C++ want 'this' by pointer
|
|
bool IsBfObjectPtr();
|
|
bool IsBfObject();
|
|
bool IsBfPayloadEnum();
|
|
bool IsBfEnum();
|
|
bool IsBfTuple();
|
|
bool IsBfUnion();
|
|
bool HasCPPVTable();
|
|
bool IsBaseBfObject();
|
|
bool IsInterface();
|
|
bool IsEnum();
|
|
bool IsSigned();
|
|
bool IsRef();
|
|
bool IsConst();
|
|
bool IsPointer(bool includeBfObjectPointer = true);
|
|
bool HasPointer(bool includeBfObjectPointer = true);
|
|
bool IsPointerOrRef(bool includeBfObjectPointer = true);
|
|
bool IsSizedArray();
|
|
bool IsAnonymous();
|
|
bool IsGlobalsContainer();
|
|
|
|
DbgExtType CalcExtType();
|
|
DbgLanguage GetLanguage();
|
|
void FixName();
|
|
void PopulateType();
|
|
DbgModule* GetDbgModule();
|
|
DbgType* GetUnderlyingType();
|
|
DbgType* GetPrimaryType();
|
|
DbgType* GetBaseType();
|
|
DbgType* GetRootBaseType();
|
|
DbgType* RemoveModifiers(bool* hadRef = NULL);
|
|
String ToStringRaw(DbgLanguage language = DbgLanguage_Unknown);
|
|
String ToString(DbgLanguage language = DbgLanguage_Unknown, bool allowDirectBfObject = false);
|
|
int GetByteCount();
|
|
int GetStride();
|
|
int GetAlign();
|
|
void EnsureMethodsMapped();
|
|
};
|
|
|
|
class DbgBitfieldType : public DbgType
|
|
{
|
|
public:
|
|
int mPosition;
|
|
int mLength;
|
|
};
|
|
|
|
/*enum DbgDerivedTypeRefKind
|
|
{
|
|
DbgDerivedTypeRefKind_Ptr
|
|
};
|
|
|
|
class DbgDerivedTypeRef : public DbgType
|
|
{
|
|
public:
|
|
DbgType* mRefType;
|
|
};*/
|
|
|
|
class DbgLineDataBuilder
|
|
{
|
|
public:
|
|
class SubprogramRecord
|
|
{
|
|
public:
|
|
Array<DbgLineInfoCtx, AllocatorBump<DbgLineInfoCtx> > mContexts;
|
|
Array<DbgLineData, AllocatorBump<DbgLineData> > mLines;
|
|
int mCurContext;
|
|
bool mHasInlinees;
|
|
};
|
|
|
|
BumpAllocator mAlloc;
|
|
DbgModule* mDbgModule;
|
|
Dictionary<DbgSubprogram*, SubprogramRecord*> mRecords;
|
|
DbgSubprogram* mCurSubprogram;
|
|
SubprogramRecord* mCurRecord;
|
|
|
|
public:
|
|
DbgLineDataBuilder(DbgModule* dbgModule);
|
|
// The pointer returned is invalid after the next add
|
|
DbgLineData* Add(DbgCompileUnit* compileUnit, DbgLineData& lineData, DbgSrcFile* srcFile, DbgSubprogram* inlinee);
|
|
void Commit();
|
|
};
|
|
|
|
class DbgLineDataState : public DbgLineData
|
|
{
|
|
public:
|
|
int mOpIndex;
|
|
int mDiscriminator;
|
|
int mIsa;
|
|
bool mBasicBlock;
|
|
bool mIsStmt;
|
|
};
|
|
|
|
class DbgSrcFileReference
|
|
{
|
|
public:
|
|
DbgCompileUnit* mCompileUnit;
|
|
DbgSrcFile* mSrcFile;
|
|
};
|
|
|
|
class DbgDeferredSrcFileReference
|
|
{
|
|
public:
|
|
DbgModule* mDbgModule;
|
|
int mCompileUnitId;
|
|
};
|
|
|
|
typedef Array<DbgLineData*> LineDataVector;
|
|
|
|
class DbgLineDataList
|
|
{
|
|
public:
|
|
LineDataVector mLineData;
|
|
};
|
|
|
|
enum DbgHashKind
|
|
{
|
|
DbgHashKind_None,
|
|
DbgHashKind_MD5,
|
|
DbgHashKind_SHA256
|
|
};
|
|
|
|
class DbgSrcFile
|
|
{
|
|
public:
|
|
String mFilePath;
|
|
String mLocalPath;
|
|
bool mHadLineData;
|
|
bool mHasLineDataFromMultipleModules;
|
|
DbgFileExistKind mFileExistKind;
|
|
int mStepFilterVersion;
|
|
DbgHashKind mHashKind;
|
|
uint8 mHash[32];
|
|
DbgModule* mFirstLineDataDbgModule; // Just used to detect mHasLineDataFromMultipleModules
|
|
Array<DbgDeferredSrcFileReference> mDeferredRefs;
|
|
Array<DbgSubprogram*> mLineDataRefs;
|
|
Array<HotReplacedLineInfo*> mHotReplacedDbgLineInfo; // Indexing starts at -1
|
|
|
|
public:
|
|
DbgSrcFile()
|
|
{
|
|
mHasLineDataFromMultipleModules = false;
|
|
mFirstLineDataDbgModule = NULL;
|
|
mHadLineData = false;
|
|
mHashKind = DbgHashKind_None;
|
|
mFileExistKind = DbgFileExistKind_NotChecked;
|
|
mStepFilterVersion = 0;
|
|
|
|
//mLineData.Reserve(64);
|
|
}
|
|
|
|
bool IsBeef();
|
|
|
|
~DbgSrcFile();
|
|
|
|
void RemoveDeferredRefs(DbgModule* debugModule);
|
|
void RemoveLines(DbgModule* debugModule);
|
|
void RemoveLines(DbgModule* debugModule, DbgSubprogram* dbgSubprogram, bool isHotReplaced);
|
|
void RehupLineData();
|
|
const String& GetLocalPath();
|
|
};
|
|
|
|
class DwCommonFrameDescriptor
|
|
{
|
|
public:
|
|
DbgModule* mDbgModule;
|
|
const char* mAugmentation;
|
|
int mAugmentationLength;
|
|
int mPointerSize;
|
|
int mSegmentSize;
|
|
int mCodeAlignmentFactor;
|
|
int mDataAlignmentFactor;
|
|
int mReturnAddressColumn;
|
|
const uint8* mInstData;
|
|
int mInstLen;
|
|
int mAddressPointerEncoding;
|
|
addr_target mLSDARoutine;
|
|
int mLSDAPointerEncodingFDE;
|
|
|
|
public:
|
|
DwCommonFrameDescriptor()
|
|
{
|
|
mPointerSize = -1;
|
|
mSegmentSize = -1;
|
|
mDbgModule = NULL;
|
|
mAugmentationLength = 0;
|
|
mAddressPointerEncoding = 0;
|
|
mLSDARoutine = 0;
|
|
mLSDAPointerEncodingFDE = 0;
|
|
}
|
|
};
|
|
|
|
class DwFrameDescriptor
|
|
{
|
|
public:
|
|
addr_target mLowPC;
|
|
addr_target mHighPC;
|
|
const uint8* mInstData;
|
|
int mInstLen;
|
|
DwCommonFrameDescriptor* mCommonFrameDescriptor;
|
|
int mAddressPointerEncoding;
|
|
addr_target mLSDARoutine;
|
|
|
|
public:
|
|
DwFrameDescriptor()
|
|
{
|
|
mAddressPointerEncoding = 0;
|
|
mLSDARoutine = 0;
|
|
}
|
|
};
|
|
|
|
class DbgModule;
|
|
|
|
class DbgCompileUnitContrib
|
|
{
|
|
public:
|
|
DbgCompileUnitContrib* mNext;
|
|
DbgModule* mDbgModule;
|
|
addr_target mAddress;
|
|
int mCompileUnitId;
|
|
int mLength;
|
|
};
|
|
|
|
class DbgCompileUnit
|
|
{
|
|
public:
|
|
static const DbgClassType ClassType = DbgClassType_CompileUnit;
|
|
|
|
DbgModule* mDbgModule;
|
|
DbgLanguage mLanguage;
|
|
DbgBlock* mGlobalBlock;
|
|
DbgType* mGlobalType;
|
|
Array<DbgSrcFileReference> mSrcFileRefs;
|
|
String mName;
|
|
String mProducer;
|
|
String mCompileDir;
|
|
addr_target mLowPC;
|
|
addr_target mHighPC;
|
|
bool mNeedsLineDataFixup;
|
|
bool mWasHotReplaced;
|
|
bool mIsMaster;
|
|
|
|
SLIList<DbgSubprogram*> mOrphanMethods;
|
|
|
|
public:
|
|
DbgCompileUnit(DbgModule* dbgModule);
|
|
|
|
virtual ~DbgCompileUnit()
|
|
{
|
|
}
|
|
};
|
|
|
|
//static int gDbgSymbol_Idx = 0;
|
|
class DbgSymbol
|
|
{
|
|
public:
|
|
//int mDbgIdx;
|
|
DbgSymbol()
|
|
{
|
|
//mDbgIdx = ++gDbgSymbol_Idx;
|
|
}
|
|
|
|
public:
|
|
const char* mName;
|
|
addr_target mAddress;
|
|
DbgModule* mDbgModule;
|
|
DbgSymbol* mNext;
|
|
};
|
|
|
|
class DbgSection
|
|
{
|
|
public:
|
|
addr_target mAddrStart;
|
|
addr_target mAddrLength;
|
|
bool mWritingEnabled;
|
|
bool mIsExecutable;
|
|
int mOldProt;
|
|
|
|
public:
|
|
DbgSection()
|
|
{
|
|
mAddrStart = 0;
|
|
mAddrLength = 0;
|
|
mWritingEnabled = false;
|
|
mIsExecutable = false;
|
|
mOldProt = 0;
|
|
}
|
|
};
|
|
|
|
struct DbgCharPtrHash
|
|
{
|
|
size_t operator()(const char* val) const
|
|
{
|
|
int curHash = 0;
|
|
const char* curHashPtr = val;
|
|
while (*curHashPtr != 0)
|
|
{
|
|
curHash = ((curHash ^ *curHashPtr) << 5) - curHash;
|
|
curHashPtr++;
|
|
}
|
|
return curHash;
|
|
}
|
|
};
|
|
|
|
struct DbgCharPtrEquals
|
|
{
|
|
bool operator()(const char* lhs, const char* rhs) const
|
|
{
|
|
return strcmp(lhs, rhs) == 0;
|
|
}
|
|
};
|
|
|
|
struct DbgFileNameHash
|
|
{
|
|
size_t operator()(const char* val) const
|
|
{
|
|
int curHash = 0;
|
|
const char* curHashPtr = val;
|
|
while (*curHashPtr != 0)
|
|
{
|
|
char c = *curHashPtr;
|
|
#ifdef _WIN32
|
|
c = toupper((uint8)c);
|
|
if (c == '\\')
|
|
c = '/';
|
|
#endif
|
|
curHash = ((curHash ^ c) << 5) - curHash;
|
|
curHashPtr++;
|
|
}
|
|
return curHash;
|
|
}
|
|
};
|
|
|
|
struct DbgFileNameEquals
|
|
{
|
|
bool operator()(const char* lhs, const char* rhs) const
|
|
{
|
|
#ifdef _WIN32
|
|
while (true)
|
|
{
|
|
char lc = toupper((uint8)*(lhs++));
|
|
if (lc == '\\')
|
|
lc = '/';
|
|
char rc = toupper((uint8)*(rhs++));
|
|
if (rc == '\\')
|
|
rc = '/';
|
|
if (lc != rc)
|
|
return false;
|
|
if (lc == 0)
|
|
return true;
|
|
}
|
|
#else
|
|
return strcmp(lhs, rhs) == 0;
|
|
#endif
|
|
}
|
|
};
|
|
|
|
struct DbgAutoStaticEntry
|
|
{
|
|
String mFullName;
|
|
DbgVariable* mVariable;
|
|
uint64 mAddrStart;
|
|
uint64 mAddrLen;
|
|
};
|
|
|
|
class DbgHotTargetSection
|
|
{
|
|
public:
|
|
uint8* mData;
|
|
int mDataSize;
|
|
addr_target mTargetSectionAddr;
|
|
int mImageOffset;
|
|
int mTargetSectionSize;
|
|
int mPointerToRelocations;
|
|
int mNumberOfRelocations;
|
|
bool mNoTargetAlloc;
|
|
bool mCanExecute;
|
|
bool mCanWrite;
|
|
|
|
public:
|
|
DbgHotTargetSection()
|
|
{
|
|
mData = NULL;
|
|
mDataSize = 0;
|
|
mImageOffset = 0;
|
|
mTargetSectionAddr = 0;
|
|
mTargetSectionSize = 0;
|
|
mPointerToRelocations = 0;
|
|
mNumberOfRelocations = 0;
|
|
mCanExecute = false;
|
|
mCanWrite = false;
|
|
mNoTargetAlloc = false;
|
|
}
|
|
|
|
~DbgHotTargetSection()
|
|
{
|
|
}
|
|
};
|
|
|
|
typedef Dictionary<String, DbgType*> DbgTypeMapType;
|
|
typedef Dictionary<String, std::pair<uint64, uint64> > DbgAutoValueMapType;
|
|
typedef Dictionary<addr_target, int> DbgAutoStaticEntryBucketMap;
|
|
|
|
struct DbgDeferredHotResolve
|
|
{
|
|
public:
|
|
DbgHotTargetSection* mHotTargetSection;
|
|
String mName;
|
|
addr_target mNewAddr;
|
|
COFFRelocation mReloc;
|
|
};
|
|
|
|
class DbgDataMap
|
|
{
|
|
public:
|
|
// All entries we want to put in this map are at least 4 bytes apart
|
|
static const int IDX_DIV = 4;
|
|
DbgDebugData** mAddrs;
|
|
int mOffset;
|
|
int mSize;
|
|
|
|
DbgDataMap(int startIdx, int endIdx)
|
|
{
|
|
mOffset = startIdx;
|
|
mSize = (((endIdx - startIdx) + IDX_DIV - 1) / IDX_DIV) + 4; // Add a few extra at the end
|
|
mAddrs = new DbgDebugData*[mSize];
|
|
memset(mAddrs, 0, sizeof(DbgDebugData*)*mSize);
|
|
}
|
|
|
|
~DbgDataMap()
|
|
{
|
|
delete mAddrs;
|
|
}
|
|
|
|
void Set(int tagIdx, DbgDebugData* debugData)
|
|
{
|
|
BF_ASSERT(debugData->mTagIdx == 0);
|
|
debugData->mTagIdx = tagIdx;
|
|
|
|
int mapIdx = (tagIdx - mOffset) / IDX_DIV;
|
|
BF_ASSERT(mapIdx < mSize);
|
|
|
|
// Search for empty slot
|
|
while (true)
|
|
{
|
|
BF_ASSERT(mapIdx < mSize);
|
|
if (mAddrs[mapIdx] == NULL)
|
|
{
|
|
mAddrs[mapIdx] = debugData;
|
|
break;
|
|
}
|
|
mapIdx++;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
T Get(int tagIdx)
|
|
{
|
|
int mapIdx = (tagIdx - mOffset) / IDX_DIV;
|
|
|
|
// Search for right slot
|
|
while (mapIdx < mSize)
|
|
{
|
|
DbgDebugData* checkData = mAddrs[mapIdx];
|
|
if (checkData == NULL)
|
|
return NULL;
|
|
if (checkData->mTagIdx == tagIdx)
|
|
return (T)checkData;
|
|
mapIdx++;
|
|
}
|
|
return NULL;
|
|
}
|
|
};
|
|
|
|
class WdStackFrame;
|
|
|
|
enum DbgModuleLoadState
|
|
{
|
|
DbgModuleLoadState_NotLoaded,
|
|
DbgModuleLoadState_Failed,
|
|
DbgModuleLoadState_Loaded
|
|
};
|
|
|
|
struct DbgSizedArrayEntry
|
|
{
|
|
DbgType* mElementType;
|
|
int mCount;
|
|
|
|
bool operator==(const DbgSizedArrayEntry& other) const
|
|
{
|
|
return (other.mElementType == mElementType) &&
|
|
(other.mCount == mCount);
|
|
}
|
|
};
|
|
|
|
class DbgModule
|
|
{
|
|
public:
|
|
static const int ImageBlockSize = 4096;
|
|
|
|
WinDebugger* mDebugger;
|
|
DebugTarget* mDebugTarget;
|
|
DbgModuleLoadState mLoadState;
|
|
MappedFile* mMappedImageFile;
|
|
MemReporter* mMemReporter;
|
|
|
|
const uint8* mDebugLineData;
|
|
const uint8* mDebugInfoData;
|
|
const uint8* mDebugPubNames;
|
|
const uint8* mDebugFrameData;
|
|
const uint8* mDebugLocationData;
|
|
const uint8* mDebugRangesData;
|
|
addr_target mDebugFrameAddress;
|
|
addr_target mCodeAddress;
|
|
const uint8* mDebugAbbrevData;
|
|
const uint8* mDebugStrData;
|
|
const uint8** mDebugAbbrevPtrData;
|
|
Array<DbgSectionData> mExceptionDirectory;
|
|
const uint8* mEHFrameData;
|
|
const char* mStringTable;
|
|
const uint8* mSymbolData;
|
|
addr_target mEHFrameAddress;
|
|
addr_target mTLSAddr;
|
|
addr_target mTLSExtraAddr;
|
|
int mTLSSize;
|
|
int mTLSExtraSize;
|
|
addr_target mTLSIndexAddr;
|
|
DbgFlavor mDbgFlavor;
|
|
|
|
bool mParsedGlobalsData;
|
|
bool mParsedSymbolData;
|
|
bool mParsedTypeData;
|
|
bool mPopulatedStaticVariables;
|
|
bool mParsedFrameDescriptors;
|
|
|
|
bool mMayBeOld; // If we had to load debug info from the SymCache or a SymServer then it may be old
|
|
bool mDeleting;
|
|
bool mFailed;
|
|
int mHotIdx;
|
|
String mFilePath;
|
|
String mDisplayName;
|
|
uint32 mTimeStamp;
|
|
uint32 mExpectedFileSize;
|
|
int mStartSubprogramIdx;
|
|
int mEndSubprogramIdx;
|
|
int mStartTypeIdx;
|
|
int mEndTypeIdx;
|
|
uintptr mPreferredImageBase;
|
|
uintptr mImageBase;
|
|
uint32 mImageSize;
|
|
uintptr mEntryPoint;
|
|
String mVersion;
|
|
String* mFailMsgPtr;
|
|
|
|
DbgModuleMemoryCache* mOrigImageData;
|
|
DbgCompileUnit* mMasterCompileUnit;
|
|
StrHashMap<DbgVariable*> mGlobalVarMap; // Dedups entries into mMasterCompileUnit
|
|
|
|
BumpAllocator mAlloc;
|
|
|
|
std::list<DwAsmDebugLineMap> mAsmDebugLineMaps;
|
|
Array<DbgSection> mSections;
|
|
Dictionary<addr_target, int> mSecRelEncodingMap;
|
|
Array<addr_target> mSecRelEncodingVec;
|
|
bool mCheckedBfObject;
|
|
bool mBfObjectHasFlags;
|
|
bool mIsHotObjectFile;
|
|
bool mIsDwarf64;
|
|
|
|
HashSet<DbgSrcFile*> mSrcFileDeferredRefs;
|
|
Array<addr_target> mSectionRVAs;
|
|
SLIList<DbgSymbol*> mDeferredSymbols;
|
|
Beefy::OwnedVector<DbgDeferredHotResolve> mDeferredHotResolveList;
|
|
Array<DbgHotTargetSection*> mHotTargetSections;
|
|
HashSet<DbgType*> mHotPrimaryTypes; // List of types where we have entries in mHotReplacedMethodList
|
|
DbgCompileUnit mDefaultCompileUnit;
|
|
Dictionary<DbgType*, DbgType*> mConstTypes;
|
|
Dictionary<String, DbgFileExistKind> mFileExistsCache;
|
|
Dictionary<DbgSizedArrayEntry, DbgType*> mSizedArrayTypes;
|
|
|
|
int mAllocSizeData;
|
|
Array<const uint8*> mOwnedSectionData;
|
|
|
|
public:
|
|
Array<DbgSrcFile*> mEmptySrcFiles;
|
|
Array<DbgCompileUnit*> mCompileUnits;
|
|
Array<DbgVariable*> mStaticVariables;
|
|
|
|
DbgType* mCPrimitiveTypes[DbgType_COUNT];
|
|
DbgType* mBfPrimitiveTypes[DbgType_COUNT];
|
|
const char* mPrimitiveStructNames[DbgType_COUNT];
|
|
DbgTypeMap mTypeMap;
|
|
|
|
Array<DbgType*> mTypes;
|
|
Array<DbgSubprogram*> mSubprograms;
|
|
|
|
StrHashMap<DbgSymbol*> mSymbolNameMap;
|
|
std::unordered_map<const char*, DbgVariable*, DbgCharPtrHash, DbgCharPtrEquals> mStaticVariableMap;
|
|
|
|
public:
|
|
virtual void ParseGlobalsData();
|
|
virtual void ParseSymbolData();
|
|
virtual void ParseTypeData();
|
|
virtual DbgCompileUnit* ParseCompileUnit(int compileUnitId);
|
|
virtual void MapCompileUnitMethods(DbgCompileUnit* compileUnit);
|
|
virtual void MapCompileUnitMethods(int compileUnitId);
|
|
virtual void PopulateType(DbgType* dbgType);
|
|
virtual void PopulateTypeGlobals(DbgType* dbgType);
|
|
virtual void PopulateSubprogram(DbgSubprogram* dbgSubprogram) { }
|
|
virtual void FixupInlinee(DbgSubprogram* dbgSubprogram) {}
|
|
virtual void PopulateStaticVariableMap();
|
|
virtual void ProcessDebugInfo();
|
|
virtual bool CanGetOldSource() { return false; }
|
|
virtual String GetOldSourceCommand(const StringImpl& path) { return ""; }
|
|
virtual bool DbgIsStrMutable(const char* str) { return true; } // Always assume its a copy
|
|
virtual addr_target LocateSymbol(const StringImpl& name) { return 0; }
|
|
|
|
void Fail(const StringImpl& error);
|
|
void FindTemplateStr(const char*& name, int& templateNameIdx);
|
|
void TempRemoveTemplateStr(const char*& name, int& templateNameIdx);
|
|
void ReplaceTemplateStr(const char*& name, int& templateNameIdx);
|
|
|
|
char* DbgDupString(const char* str, const char* allocName = NULL);
|
|
DbgModule* GetLinkedModule();
|
|
addr_target GetTargetImageBase();
|
|
addr_target RemapAddr(addr_target addr);
|
|
template <typename T>
|
|
T GetOrCreate(int idx, DbgDataMap& dataMap);
|
|
DbgType* GetOrCreateType(int typeIdx, DbgDataMap& typeMap);
|
|
//void SplitName(const char* inName, const char*& outBaseName, const char*& outTemplateParams, bool alwaysDup = false);
|
|
void MapSubprogram(DbgSubprogram* dbgSubprogram);
|
|
bool ParseDWARF(const uint8*& dataPtr);
|
|
void ParseAbbrevData(const uint8* data);
|
|
void ParseExceptionData();
|
|
void ParseDebugFrameData();
|
|
void ParseEHFrameData();
|
|
void FlushLineData(DbgSubprogram* curSubprogram, std::list<DbgLineData>& queuedLineData);
|
|
DbgSrcFile* AddSrcFile(DbgCompileUnit* compileUnit, const String& srcFilePath);
|
|
void AddLineData(DbgCompileUnit* dwCompileUnit, DbgLineData& lineData, DbgSubprogram*& curSubProgram, std::list<DbgLineData>& queuedLineData);
|
|
bool ParseDebugLineInfo(const uint8*& data, int compileUnitIdx);
|
|
void FixupInnerTypes(int startingTypeIdx);
|
|
void MapTypes(int startingTypeIdx);
|
|
void CreateNamespaces();
|
|
bool IsHotSwapPreserve(const String& name);
|
|
addr_target GetHotTargetAddress(DbgHotTargetSection* hotTargetSection);
|
|
uint8* GetHotTargetData(addr_target address);
|
|
void DoReloc(DbgHotTargetSection* hotTargetSection, COFFRelocation& coffReloc, addr_target resolveSymbolAddr, PE_SymInfo* symInfo);
|
|
void ParseHotTargetSections(DataStream* stream, addr_target* resovledSymbolAddrs);
|
|
void CommitHotTargetSections();
|
|
void HotReplaceType(DbgType* newType);
|
|
void ProcessHotSwapVariables();
|
|
virtual bool LoadPDB(const String& pdbPath, uint8 wantGuid[16], int32 wantAge) { return false; }
|
|
virtual bool CheckSection(const char* name, uint8* sectionData, int sectionSize) { return false; }
|
|
virtual void PreCacheImage() {}
|
|
virtual void PreCacheDebugInfo() {}
|
|
virtual bool RequestImage() { return false; }
|
|
virtual bool HasPendingDebugInfo() { return false; }
|
|
virtual bool RequestDebugInfo(bool allowRemote = true) { return false; }
|
|
virtual bool WantsAutoLoadDebugInfo() { return false; }
|
|
virtual DbgFileExistKind CheckSourceFileExist(const StringImpl& path);
|
|
virtual void ParseFrameDescriptors() {}
|
|
|
|
template <typename T>
|
|
T ReadValue(const uint8*& data, int form, int refOffset = 0, const uint8** extraData = NULL, const uint8* startData = NULL);
|
|
|
|
void EnableWriting(addr_target address);
|
|
void RevertWritingEnable();
|
|
|
|
public:
|
|
DbgModule(DebugTarget* debugTarget);
|
|
virtual ~DbgModule();
|
|
|
|
static bool CanRead(DataStream* stream, DebuggerResult* outResult);
|
|
|
|
bool ReadCOFF(DataStream* stream, bool isHotObjectFile);
|
|
void RemoveTargetData();
|
|
virtual void ReportMemory(MemReporter* memReporter);
|
|
|
|
int64 GetImageSize();
|
|
virtual void FinishHotSwap();
|
|
addr_target ExecuteOps(DbgSubprogram* dwSubprogram, const uint8* locData, int locDataLen, WdStackFrame* stackFrame, CPURegisters* registers, DbgAddrType* outAddrType, bool allowReg, addr_target* pushValue = NULL);
|
|
virtual addr_target EvaluateLocation(DbgSubprogram* dwSubprogram, const uint8* locData, int locDataLen, WdStackFrame* stackFrame, DbgAddrType* outAddrType, bool allowReg = true);
|
|
|
|
//const uint8* CopyOrigImageData(addr_target address, int length);
|
|
|
|
DbgType* FindTypeHelper(const String& typeName, DbgType* checkType);
|
|
DbgType* FindType(const String& typeName, DbgType* contextType = NULL, DbgLanguage language = DbgLanguage_Unknown);
|
|
DbgTypeMap::Entry* FindType(const char* typeName, DbgLanguage language);
|
|
|
|
DbgType* GetPointerType(DbgType* innerType);
|
|
DbgType* GetConstType(DbgType* innerType);
|
|
DbgType* GetPrimaryType(DbgType* dbgType);
|
|
DbgType* GetPrimitiveType(DbgTypeCode typeCode, DbgLanguage language);
|
|
DbgType* GetPrimitiveStructType(DbgTypeCode typeCode);
|
|
DbgType* GetInnerTypeOrVoid(DbgType* dbgType);
|
|
DbgType* GetSizedArrayType(DbgType* elementType, int count);
|
|
};
|
|
|
|
NS_BF_END
|
|
|
|
namespace std
|
|
{
|
|
template<>
|
|
struct hash<NS_BF_DBG::DbgSizedArrayEntry>
|
|
{
|
|
size_t operator()(const NS_BF_DBG::DbgSizedArrayEntry& val) const
|
|
{
|
|
return (size_t)val.mElementType ^ (val.mCount << 10);
|
|
}
|
|
};
|
|
} |