1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-07-04 23:36:00 +02:00

Added diagnostics panel

This commit is contained in:
Brian Fiete 2020-07-31 06:16:29 -07:00
parent efa9566f88
commit f034880723
12 changed files with 1017 additions and 51 deletions

View file

@ -9874,15 +9874,10 @@ void BfModule::CurrentAddToConstHolder(BfIRValue& irVal)
newVals.push_back(newVal);
}
irVal = mCurTypeInstance->mConstHolder->CreateConstArray(constArray->mType, newVals);
irVal = mCurTypeInstance->GetOrCreateConstHolder()->CreateConstArray(constArray->mType, newVals);
return;
}
if (constant->mConstType == BfConstType_GlobalVar)
{
NOP;
}
auto origConst = irVal;
if ((constant->mConstType == BfConstType_BitCast) || (constant->mConstType == BfConstType_BitCastNull))
{

View file

@ -732,10 +732,19 @@ DbgExprEvaluator::DbgExprEvaluator(WinDebugger* winDebugger, DbgModule* dbgModul
mCapturingChildRef = true;
mPassInstance = passInstance;
mDebugger = winDebugger;
mLanguage = DbgLanguage_NotSet;
mDebugTarget = dbgModule->mDebugTarget;
mLanguage = DbgLanguage_NotSet;
mOrigDbgModule = dbgModule;
mDbgModule = dbgModule->GetLinkedModule();
if (dbgModule != NULL)
{
mDebugTarget = dbgModule->mDebugTarget;
mDbgModule = dbgModule->GetLinkedModule();
}
else
{
mDebugTarget = NULL;
mDbgModule = NULL;
}
mDbgCompileUnit = NULL;
mExplicitThisExpr = NULL;
mExpectingType = NULL;
@ -1125,12 +1134,14 @@ DbgTypedValue DbgExprEvaluator::GetBeefTypeById(int typeId)
if (mDebugTarget->mTargetBinary == NULL)
return DbgTypedValue();
mDebugTarget->mTargetBinary->ParseTypeData();
auto typeTypeEntry = mDebugTarget->mTargetBinary->FindType("System.Type", DbgLanguage_Beef);
if ((typeTypeEntry == NULL) || (typeTypeEntry->mValue == NULL))
return DbgTypedValue();
auto typeType = typeTypeEntry->mValue;
mDbgModule->PopulateTypeGlobals(typeType);
if (typeType->mNeedsGlobalsPopulated)
typeType->mCompileUnit->mDbgModule->PopulateTypeGlobals(typeType);
for (auto member : typeType->mMemberList)
{
if ((member->mIsStatic) && (member->mName != NULL) && (strcmp(member->mName, "sTypes") == 0) && (member->mLocationData != NULL))
@ -1232,6 +1243,12 @@ void DbgExprEvaluator::BeefTypeToString(const DbgTypedValue& val, String& outStr
_TypeCode mElementType;
};
struct _SizedArrayType : _Type
{
_TypeId mElementType;
int32 mElementCount;
};
struct _String
{
@ -1267,16 +1284,27 @@ void DbgExprEvaluator::BeefTypeToString(const DbgTypedValue& val, String& outStr
uint8 mInterfaceCount;
int16 mMethodDataCount;
int16 mPropertyDataCount;
int16 mFieldDataCount;
int16 mConstructorDataCount;
int16 mFieldDataCount;
void* mInterfaceDataPtr;
_MethodData* mMethodDataPtr;
void* mPropertyDataPtr;
_FieldData* mFieldDataPtr;
void* mConstructorDataPtr;
_FieldData* mFieldDataPtr;
void** mCustomAttrDataPtr;
};
struct _SpecializedGenericType : _TypeInstance
{
_TypeId mUnspecializedType;
_TypeId* mResolvedTypeRefs;
};
struct _ArrayType : _SpecializedGenericType
{
int32 mElementSize;
uint8 mRank;
uint8 mElemensDataOffset;
};
int typeIdSize = sizeof(_TypeId);
int ptrSize = (int)sizeof(addr_target);
@ -1284,12 +1312,54 @@ void DbgExprEvaluator::BeefTypeToString(const DbgTypedValue& val, String& outStr
int typeSize = sizeof(_Type);
int typeInstanceSize = objectSize + sizeof(_TypeInstance);
auto addr = useVal.mSrcAddress;
auto typeAddr = addr + objectSize;
_TypeFlags typeFlags = mDebugger->ReadMemory<_TypeFlags>(typeAddr + offsetof(_Type, mTypeFlags));
if (((typeFlags & BfTypeFlags_Struct) != 0) || ((typeFlags & BfTypeFlags_TypedPrimitive) != 0) || ((typeFlags & BfTypeFlags_Object) != 0))
if ((typeFlags & BfTypeFlags_Array) != 0)
{
_TypeId unspecializedTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + offsetof(_SpecializedGenericType, mUnspecializedType));
addr_target elementsArrayAddr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_SpecializedGenericType, mResolvedTypeRefs));
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(elementsArrayAddr);
auto elementType = GetBeefTypeById(elementTypeId);
BeefTypeToString(elementType, outStr);
outStr += "[";
int rank = mDebugger->ReadMemory<uint8>(typeAddr + offsetof(_ArrayType, mRank));
for (int commaIdx = 0; commaIdx < rank - 1; commaIdx++)
outStr += ",";
outStr += "]";
}
else if ((typeFlags & BfTypeFlags_Pointer) != 0)
{
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + offsetof(_PointerType, mElementType));
auto elementType = GetBeefTypeById(elementTypeId);
BeefTypeToString(elementType, outStr);
}
else if ((typeFlags & BfTypeFlags_Delegate) != 0)
{
outStr += "delegate";
}
else if ((typeFlags & BfTypeFlags_Function) != 0)
{
outStr += "function";
}
// else if ((typeFlags & BfTypeFlags_Tuple) != 0)
// {
// outStr += "function";
// }
else if ((typeFlags & BfTypeFlags_SizedArray) != 0)
{
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + objectSize + offsetof(_SizedArrayType, mElementType));
auto elementType = GetBeefTypeById(elementTypeId);
BeefTypeToString(elementType, outStr);
int elementCount = mDebugger->ReadMemory<int32>(typeAddr + objectSize + offsetof(_SizedArrayType, mElementCount));
outStr += StrFormat("[%d]", elementCount);
}
else if (((typeFlags & BfTypeFlags_Struct) != 0) || ((typeFlags & BfTypeFlags_TypedPrimitive) != 0) || ((typeFlags & BfTypeFlags_Object) != 0))
{
addr_target namePtr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_TypeInstance, mName));
addr_target namespacePtr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_TypeInstance, mNamespace));

View file

@ -1535,6 +1535,22 @@ BF_EXPORT void BF_CALLTYPE Debugger_InitiateHotResolve(int flags)
gDebugger->InitiateHotResolve((DbgHotResolveFlags)flags);
}
BF_EXPORT intptr BF_CALLTYPE Debugger_GetDbgAllocHeapSize()
{
AutoCrit autoCrit(gDebugManager->mCritSect);
return gDebugger->GetDbgAllocHeapSize();
}
BF_EXPORT const char* BF_CALLTYPE Debugger_GetDbgAllocInfo()
{
AutoCrit autoCrit(gDebugManager->mCritSect);
String& outString = *gTLStrReturn.Get();
outString = gDebugger->GetDbgAllocInfo();
return outString.c_str();
}
BF_EXPORT const char* BF_CALLTYPE Debugger_GetHotResolveData(uint8* outTypeData, int* outTypeDataSize)
{
AutoCrit autoCrit(gDebugManager->mCritSect);
@ -1554,7 +1570,10 @@ BF_EXPORT const char* BF_CALLTYPE Debugger_GetHotResolveData(uint8* outTypeData,
*outTypeDataSize = dataSize;
if (dataSize > 0)
memcpy(outTypeData, &gDebugger->mHotResolveData->mTypeData[0], dataSize);
{
for (int i = 0; i < dataSize; i++)
outTypeData[i] = (gDebugger->mHotResolveData->mTypeData[i].mCount > 0) ? 1 : 0;
}
String& outString = *gTLStrReturn.Get();
outString.Clear();

View file

@ -215,7 +215,20 @@ public:
class DbgHotResolveData
{
public:
Array<uint8> mTypeData;
struct TypeData
{
intptr mCount;
intptr mSize;
TypeData()
{
mCount = 0;
mSize = 0;
}
};
public:
Array<TypeData> mTypeData;
Beefy::HashSet<String> mBeefCallStackEntries;
};
@ -248,6 +261,8 @@ public:
virtual void Run() = 0;
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) = 0;
virtual void InitiateHotResolve(DbgHotResolveFlags flags) = 0;
virtual intptr GetDbgAllocHeapSize() = 0;
virtual String GetDbgAllocInfo() = 0;
virtual void Update() = 0;
virtual void ContinueDebugEvent() = 0;
virtual void ForegroundTarget() = 0;

View file

@ -169,11 +169,15 @@ void DbgHotScanner::ScanSpan(TCFake::Span* span, int expectedStartPage, int memK
elementSize = spanSize;
//BF_LOGASSERT(elementSize >= sizeof(bf::System::Object));
auto _MarkTypeUsed = [&](int typeId)
auto _MarkTypeUsed = [&](int typeId, intptr size)
{
if (typeId < 0)
return;
while (mDebugger->mHotResolveData->mTypeData.size() <= typeId)
mDebugger->mHotResolveData->mTypeData.Add(0);
mDebugger->mHotResolveData->mTypeData[typeId] = 1;
mDebugger->mHotResolveData->mTypeData.Add(DbgHotResolveData::TypeData());
auto& typeData = mDebugger->mHotResolveData->mTypeData[typeId];
typeData.mSize += size;
typeData.mCount++;
};
int objectSize = ((mDbgGCData.mDbgFlags & BfRtFlags_ObjectHasDebugFlags) != 0) ? sizeof(addr_target)*2 : sizeof(addr_target);
@ -206,36 +210,68 @@ void DbgHotScanner::ScanSpan(TCFake::Span* span, int expectedStartPage, int memK
if ((mDbgGCData.mDbgFlags & BfRtFlags_ObjectHasDebugFlags) != 0)
classVDataAddr = classVDataAddr & ~0xFF;
}
else if (mFoundRawAllocDataAddrs.Add(rawAllocDataAddr))
else
{
Fake_DbgRawAllocData rawAllocData = mDebugger->ReadMemory<Fake_DbgRawAllocData>(rawAllocDataAddr);
if ((rawAllocData.mType != NULL) && (mFoundTypeAddrs.Add(rawAllocData.mType)))
int* rawTypeIdPtr = NULL;
if (mFoundRawAllocDataAddrs.TryAdd(rawAllocDataAddr, NULL, &rawTypeIdPtr))
{
Fake_Type_Data typeData;
if (mDebugger->ReadMemory(rawAllocData.mType + objectSize, sizeof(typeData), &typeData))
_MarkTypeUsed(typeData.mTypeId);
*rawTypeIdPtr = -1;
Fake_DbgRawAllocData rawAllocData = mDebugger->ReadMemory<Fake_DbgRawAllocData>(rawAllocDataAddr);
if (rawAllocData.mType != NULL)
{
int* typeAddrIdPtr = NULL;
if (mFoundTypeAddrs.TryAdd(rawAllocData.mType, NULL, &typeAddrIdPtr))
{
*typeAddrIdPtr = -1;
Fake_Type_Data typeData;
if (mDebugger->ReadMemory(rawAllocData.mType + objectSize, sizeof(typeData), &typeData))
{
*typeAddrIdPtr = typeData.mTypeId;
*rawTypeIdPtr = typeData.mTypeId;
_MarkTypeUsed(typeData.mTypeId, elementSize);
}
}
else
{
_MarkTypeUsed(*typeAddrIdPtr, elementSize);
}
}
}
else
{
_MarkTypeUsed(*rawTypeIdPtr, elementSize);
}
}
}
}
if ((classVDataAddr != 0) && (mFoundClassVDataAddrs.Add(classVDataAddr)))
if (classVDataAddr != 0)
{
addr_target typeAddr = mDebugger->ReadMemory<addr_target>(classVDataAddr);
Fake_Type_Data typeData;
mDebugger->ReadMemory(typeAddr + objectSize, sizeof(typeData), &typeData);
_MarkTypeUsed(typeData.mTypeId);
if ((typeData.mTypeFlags & BfTypeFlags_Delegate) != 0)
int* typeIdPtr = NULL;
if (mFoundClassVDataAddrs.TryAdd(classVDataAddr, NULL, &typeIdPtr))
{
Fake_Delegate_Data* dlg = (Fake_Delegate_Data*)((uint8*)spanPtr + objectSize);
if (mFoundFuncPtrs.Add(dlg->mFuncPtr))
addr_target typeAddr = mDebugger->ReadMemory<addr_target>(classVDataAddr);
Fake_Type_Data typeData;
mDebugger->ReadMemory(typeAddr + objectSize, sizeof(typeData), &typeData);
*typeIdPtr = typeData.mTypeId;
_MarkTypeUsed(typeData.mTypeId, elementSize);
if ((typeData.mTypeFlags & BfTypeFlags_Delegate) != 0)
{
auto subProgram = mDebugger->mDebugTarget->FindSubProgram(dlg->mFuncPtr, DbgOnDemandKind_None);
if ((subProgram != NULL) && (subProgram->GetLanguage() == DbgLanguage_Beef))
AddSubProgram(subProgram, true, "D ");
Fake_Delegate_Data* dlg = (Fake_Delegate_Data*)((uint8*)spanPtr + objectSize);
if (mFoundFuncPtrs.Add(dlg->mFuncPtr))
{
auto subProgram = mDebugger->mDebugTarget->FindSubProgram(dlg->mFuncPtr, DbgOnDemandKind_None);
if ((subProgram != NULL) && (subProgram->GetLanguage() == DbgLanguage_Beef))
AddSubProgram(subProgram, true, "D ");
}
}
}
else
{
_MarkTypeUsed(*typeIdPtr, elementSize);
}
}
spanPtr = (void*)((intptr)spanPtr + elementSize);

View file

@ -84,9 +84,9 @@ class DbgHotScanner
public:
WinDebugger* mDebugger;
DbgGCData mDbgGCData;
Beefy::HashSet<addr_target> mFoundClassVDataAddrs;
Beefy::HashSet<addr_target> mFoundRawAllocDataAddrs;
Beefy::HashSet<addr_target> mFoundTypeAddrs;
Beefy::Dictionary<addr_target, int> mFoundClassVDataAddrs;
Beefy::Dictionary<addr_target, int> mFoundRawAllocDataAddrs;
Beefy::Dictionary<addr_target, int> mFoundTypeAddrs;
Beefy::HashSet<addr_target> mFoundFuncPtrs;
#ifdef BF_DBG_32

View file

@ -523,6 +523,7 @@ WinDebugger::WinDebugger(DebugManager* debugManager) : mDbgSymSrv(this)
mDbgProcessHandle = 0;
mDbgThreadHandle = 0;
mDbgProcessId = 0;
mDbgHeapData = NULL;
mIsPartialCallStack = true;
for (int i = 0; i < 4; i++)
@ -1174,6 +1175,76 @@ void WinDebugger::InitiateHotResolve(DbgHotResolveFlags flags)
delete hotScanner;
}
intptr WinDebugger::GetDbgAllocHeapSize()
{
if (mDbgHeapData == NULL)
{
Beefy::String memName = StrFormat("BFGC_stats_%d", mProcessInfo.dwProcessId);
mDbgHeapData = new WinDbgHeapData();
mDbgHeapData->mFileMapping = ::OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, memName.c_str());
if (mDbgHeapData->mFileMapping == 0)
{
delete mDbgHeapData;
mDbgHeapData = NULL;
return 0;
}
mDbgHeapData->mStats = (WinDbgHeapData::Stats*)MapViewOfFile(mDbgHeapData->mFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(WinDbgHeapData::Stats));
}
if (mDbgHeapData->mStats == NULL)
return 0;
return mDbgHeapData->mStats->mHeapSize;
}
String WinDebugger::GetDbgAllocInfo()
{
AutoCrit autoCrit(mDebugManager->mCritSect);
for (auto threadInfo : mThreadList)
::SuspendThread(threadInfo->mHThread);
delete mHotResolveData;
mHotResolveData = NULL;
mHotResolveData = new DbgHotResolveData();
DbgHotScanner* hotScanner = new DbgHotScanner(this);
hotScanner->Scan(DbgHotResolveFlag_Allocations);
delete hotScanner;
String result;
if (mHotResolveData != NULL)
{
DbgExprEvaluator exprEvaluator(this, NULL, NULL, -1, -1);
exprEvaluator.mDebugTarget = mDebugTarget;
String typeName;
result += ":types\n";
for (int typeId = 0; typeId < mHotResolveData->mTypeData.size(); typeId++)
{
auto& typeData = mHotResolveData->mTypeData[typeId];
if (typeData.mCount > 0)
{
auto type = exprEvaluator.GetBeefTypeById(typeId);
typeName.Clear();
exprEvaluator.BeefTypeToString(type, typeName);
result += StrFormat("type\t%d\t%s\t%lld\t%lld\n", typeId, typeName.c_str(), typeData.mCount, typeData.mSize);
}
}
}
for (auto threadInfo : mThreadList)
::ResumeThread(threadInfo->mHThread);
return result;
}
bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock)
{
BP_ZONE("WinDebugger::DoOpenFile");
@ -1398,6 +1469,8 @@ void WinDebugger::Detach()
mDbgAttachFlags = BfDbgAttachFlag_None;
mDbgProcessId = 0;
delete mDbgHeapData;
mDbgHeapData = NULL;
mDbgProcessHandle = 0;
ClearCallStack();
mWantsDebugContinue = false;
@ -10208,21 +10281,27 @@ String WinDebugger::GetProcessInfo()
if ((mActiveThread == NULL) && (!mIsRunning))
return "";
SYSTEM_INFO sysinfo = { 0 };
GetSystemInfo(&sysinfo);
FILETIME creationTime = { 0 };
FILETIME exitTime = { 0 };
FILETIME kernelTime = { 0 };
FILETIME userTime = { 0 };
GetProcessTimes(mProcessInfo.hProcess, &creationTime, &exitTime, &kernelTime, &userTime);
::GetProcessTimes(mProcessInfo.hProcess, &creationTime, &exitTime, &kernelTime, &userTime);
String retStr;
PROCESS_MEMORY_COUNTERS memInfo = { 0 };
GetProcessMemoryInfo(mProcessInfo.hProcess, &memInfo, sizeof(PROCESS_MEMORY_COUNTERS));
::GetProcessMemoryInfo(mProcessInfo.hProcess, &memInfo, sizeof(PROCESS_MEMORY_COUNTERS));
FILETIME currentTime = { 0 };
::GetSystemTimeAsFileTime(&currentTime);
retStr += StrFormat("VirtualMemory\t%d\n", memInfo.PagefileUsage);
retStr += StrFormat("WorkingMemory\t%d\n", memInfo.WorkingSetSize);
retStr += StrFormat("RunningTime\t%lld\n", *(int64*)&creationTime);
retStr += StrFormat("KernelTime\t%lld\n", *(int64*)&kernelTime);
retStr += StrFormat("UserTime\t%lld\n", *(int64*)&userTime);
retStr += StrFormat("RunningTime\t%lld\n", *(int64*)&currentTime - *(int64*)&creationTime);
retStr += StrFormat("KernelTime\t%lld\n", *(int64*)&kernelTime / sysinfo.dwNumberOfProcessors);
retStr += StrFormat("UserTime\t%lld\n", *(int64*)&userTime / sysinfo.dwNumberOfProcessors);
return retStr;
}

View file

@ -384,6 +384,31 @@ struct WinHotThreadState
int mThreadId;
};
class WinDbgHeapData
{
public:
struct Stats
{
intptr mHeapSize;
};
public:
HANDLE mFileMapping;
Stats* mStats;
WinDbgHeapData()
{
mFileMapping = 0;
mStats = NULL;
}
~WinDbgHeapData()
{
if (mFileMapping != 0)
::CloseHandle(mFileMapping);
}
};
class WinDebugger : public Debugger
{
public:
@ -407,6 +432,7 @@ public:
CPU* mCPU;
PROCESS_INFORMATION mProcessInfo;
BfDbgAttachFlags mDbgAttachFlags;
WinDbgHeapData* mDbgHeapData;
DWORD mDbgProcessId;
HANDLE mDbgProcessHandle;
HANDLE mDbgThreadHandle;
@ -593,6 +619,8 @@ public:
virtual void Run() override;
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;
virtual void InitiateHotResolve(DbgHotResolveFlags flags) override;
virtual intptr GetDbgAllocHeapSize() override;
virtual String GetDbgAllocInfo() override;
virtual void Update() override;
virtual void ContinueDebugEvent() override;
virtual void ForegroundTarget() override;