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
363 lines
11 KiB
C++
363 lines
11 KiB
C++
#include "MiniDumpDebugger.h"
|
|
#include "DebugManager.h"
|
|
|
|
#pragma warning(disable:4091)
|
|
#include <DbgHelp.h>
|
|
|
|
#include "BeefySysLib/util/AllocDebug.h"
|
|
|
|
USING_NS_BF_DBG;
|
|
USING_NS_BF;
|
|
|
|
MiniDumpDebugger::MiniDumpDebugger(DebugManager* debugManager, DbgMiniDump* miniDump) : WinDebugger(debugManager)
|
|
{
|
|
mMiniDump = miniDump;
|
|
mRunState = RunState_Paused;
|
|
mExceptionThread = NULL;
|
|
mExceptionContextRVA = 0;
|
|
|
|
mDebugTarget = new DebugTarget(this);
|
|
|
|
for (auto section : mMiniDump->mDirectory)
|
|
{
|
|
if (section.mStreamType == ThreadExListStream)
|
|
{
|
|
auto& threadEx = mMiniDump->GetStreamData<MINIDUMP_THREAD_EX_LIST>(section);
|
|
|
|
/*WdThreadInfo* threadInfo = new WdThreadInfo();
|
|
threadInfo->mThreadId = threadEx.ThreadId;
|
|
mThreadList.Add(threadInfo);
|
|
|
|
if (mActiveThread == NULL)
|
|
{
|
|
mActiveThread = threadInfo;
|
|
mDebuggerWaitingThread = threadInfo;
|
|
}
|
|
|
|
mThreadMap[threadInfo->mThreadId] = threadInfo;*/
|
|
}
|
|
else if (section.mStreamType == ModuleListStream)
|
|
{
|
|
auto& moduleList = mMiniDump->GetStreamData<MINIDUMP_MODULE_LIST>(section);
|
|
for (int moduleIdx = 0; moduleIdx < (int)moduleList.NumberOfModules; moduleIdx++)
|
|
{
|
|
auto& module = moduleList.Modules[moduleIdx];
|
|
COFF* dbgModule = new COFF(mDebugTarget);
|
|
if (mDebugTarget->mTargetBinary == NULL)
|
|
{
|
|
mDebugTarget->mLaunchBinary = dbgModule;
|
|
mDebugTarget->mTargetBinary = dbgModule;
|
|
}
|
|
dbgModule->mImageBase = module.BaseOfImage;
|
|
dbgModule->mImageSize = module.SizeOfImage;
|
|
|
|
//TODO: 'get' the actual image
|
|
dbgModule->mTimeStamp = module.TimeDateStamp;
|
|
//dbgModule->mExpectedFileSize = module.;
|
|
|
|
const wchar_t* moduleName = &mMiniDump->GetData<wchar_t>(module.ModuleNameRva + 4);
|
|
dbgModule->mFilePath = UTF8Encode(moduleName);
|
|
dbgModule->mDisplayName = GetFileName(dbgModule->mFilePath);
|
|
|
|
struct _CodeViewEntry
|
|
{
|
|
public:
|
|
int32 mSig;
|
|
uint8 mGUID[16];
|
|
int32 mAge;
|
|
const char mPDBPath[1];
|
|
};
|
|
auto& codeViewEntry = mMiniDump->GetData<_CodeViewEntry>(module.CvRecord.Rva);
|
|
if (codeViewEntry.mSig == 'SDSR')
|
|
{
|
|
// Do nothing, let the binay load the PDB itself
|
|
//dbgModule->LoadPDB(codeViewEntry.mPDBPath, codeViewEntry.mGUID, codeViewEntry.mAge);
|
|
}
|
|
|
|
auto miscEntry = &mMiniDump->GetData<char>(module.MiscRecord.Rva);
|
|
|
|
mDebugTarget->mDbgModules.Add(dbgModule);
|
|
|
|
//TESTING
|
|
/*{
|
|
AutoCrit autoCrit(mDebugManager->mCritSect);
|
|
mDebuggerThreadId = GetCurrentThreadId();
|
|
dbgModule->RequestImage();
|
|
dbgModule->RequestDebugInfo();
|
|
mDebuggerThreadId = 0;
|
|
}*/
|
|
|
|
mPendingImageLoad.Add(dbgModule);
|
|
|
|
// This is optional
|
|
mPendingDebugInfoRequests.Add(dbgModule);
|
|
}
|
|
}
|
|
else if (section.mStreamType == ThreadListStream)
|
|
{
|
|
auto& threadList = mMiniDump->GetStreamData<MINIDUMP_THREAD_LIST>(section);
|
|
for (int threadIdx = 0; threadIdx < (int)threadList.NumberOfThreads; threadIdx++)
|
|
{
|
|
auto& thread = threadList.Threads[threadIdx];
|
|
|
|
WdThreadInfo* threadInfo = new WdThreadInfo();
|
|
threadInfo->mThreadId = thread.ThreadId;
|
|
mThreadList.Add(threadInfo);
|
|
|
|
if (mActiveThread == NULL)
|
|
{
|
|
mActiveThread = threadInfo;
|
|
mDebuggerWaitingThread = threadInfo;
|
|
}
|
|
|
|
if ((thread.Stack.Memory.Rva != 0) && (thread.Stack.Memory.DataSize > 0))
|
|
{
|
|
void* stackMemory = &mMiniDump->GetData<uint8>(thread.Stack.Memory.Rva);
|
|
MapMemory((addr_target)thread.Stack.StartOfMemoryRange, stackMemory, thread.Stack.Memory.DataSize);
|
|
}
|
|
|
|
mThreadMap[threadInfo->mThreadId] = threadInfo;
|
|
}
|
|
}
|
|
else if (section.mStreamType == MemoryInfoListStream)
|
|
{
|
|
auto& memoryInfoList = mMiniDump->GetStreamData<MINIDUMP_MEMORY_INFO_LIST>(section);
|
|
for (int memoryInfoIdx = 0; memoryInfoIdx < (int)memoryInfoList.NumberOfEntries; memoryInfoIdx++)
|
|
{
|
|
auto& memoryInfo = mMiniDump->GetData<MINIDUMP_MEMORY_INFO>(section.mDataRVA + memoryInfoList.SizeOfHeader + memoryInfoIdx*memoryInfoList.SizeOfEntry);
|
|
}
|
|
}
|
|
else if (section.mStreamType == MemoryListStream)
|
|
{
|
|
auto& memoryList = mMiniDump->GetStreamData<MINIDUMP_MEMORY_LIST>(section);
|
|
for (int memoryIdx = 0; memoryIdx < (int)memoryList.NumberOfMemoryRanges; memoryIdx++)
|
|
{
|
|
auto& memory = memoryList.MemoryRanges[memoryIdx];
|
|
if (memory.Memory.Rva != 0)
|
|
{
|
|
void* memoryPtr = &mMiniDump->GetData<uint8>(memory.Memory.Rva);
|
|
MapMemory((addr_target)memory.StartOfMemoryRange, memoryPtr, memory.Memory.DataSize);
|
|
}
|
|
}
|
|
}
|
|
else if (section.mStreamType == ExceptionStream)
|
|
{
|
|
auto& exceptionStream = mMiniDump->GetStreamData<MINIDUMP_EXCEPTION_STREAM>(section);
|
|
|
|
//mCurException = exceptionStream.ExceptionRecord;
|
|
mCurException.ExceptionCode = exceptionStream.ExceptionRecord.ExceptionCode;
|
|
mCurException.ExceptionFlags = exceptionStream.ExceptionRecord.ExceptionFlags;
|
|
mCurException.ExceptionAddress = (PVOID)exceptionStream.ExceptionRecord.ExceptionAddress;
|
|
mCurException.NumberParameters = exceptionStream.ExceptionRecord.NumberParameters;
|
|
for (int i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
|
|
mCurException.ExceptionInformation[i] = exceptionStream.ExceptionRecord.ExceptionInformation[i];
|
|
|
|
WdThreadInfo* threadInfo = NULL;
|
|
if (mThreadMap.TryGetValue(exceptionStream.ThreadId, &threadInfo))
|
|
{
|
|
mActiveThread = threadInfo;
|
|
mExplicitStopThread = mActiveThread;
|
|
mRunState = RunState_Exception;
|
|
|
|
/*mDebugPendingExpr->mException = StrFormat("Exception at 0x%@ in thread %d, exception code 0x%08X",
|
|
mCurException.ExceptionAddress, mActiveThread->mThreadId, mCurException.ExceptionCode);*/
|
|
|
|
mExceptionThread = mActiveThread;
|
|
mExceptionContextRVA = exceptionStream.ThreadContext.Rva;
|
|
}
|
|
}
|
|
else if (section.mStreamType == SystemInfoStream)
|
|
{
|
|
auto& systemInfo = mMiniDump->GetStreamData<MINIDUMP_SYSTEM_INFO>(section);
|
|
}
|
|
else if (section.mStreamType == MiscInfoStream)
|
|
{
|
|
auto& miscInfo = mMiniDump->GetStreamData<MINIDUMP_MISC_INFO>(section);
|
|
}
|
|
else if (section.mStreamType == 21/*SystemMemoryInfoStream*/)
|
|
{
|
|
auto data = ((uint8*)mMiniDump->mMF.mData + section.mDataRVA);
|
|
}
|
|
else if (section.mStreamType == 22/*ProcessVmCountersStream*/)
|
|
{
|
|
auto data = ((uint8*)mMiniDump->mMF.mData + section.mDataRVA);
|
|
}
|
|
else if (section.mStreamType == 24) // Thread names
|
|
{
|
|
auto data = ((uint8*)mMiniDump->mMF.mData + section.mDataRVA);
|
|
int count = *(int32*)(data);
|
|
for (int threadIdx = 0; threadIdx < count; threadIdx++)
|
|
{
|
|
struct ThreadNameInfo
|
|
{
|
|
int32 mThreadId;
|
|
int32 mNameRVA;
|
|
int32 mFlags; // Always zero
|
|
};
|
|
|
|
ThreadNameInfo* threadNameInfo = (ThreadNameInfo*)(data + 4 + threadIdx*12);
|
|
|
|
int nameLen = *(int32*)((uint8*)mMiniDump->mMF.mData + threadNameInfo->mNameRVA);
|
|
UTF16String name = UTF16String((wchar_t*)((uint8*)mMiniDump->mMF.mData + threadNameInfo->mNameRVA + 4), nameLen);
|
|
|
|
WdThreadInfo* threadInfo = NULL;
|
|
if (mThreadMap.TryGetValue(threadNameInfo->mThreadId, &threadInfo))
|
|
{
|
|
threadInfo->mName = UTF8Encode(name);
|
|
}
|
|
}
|
|
}
|
|
else if (section.mStreamType == 0x43500001) // kMinidumpStreamTypeCrashpadInfo
|
|
{
|
|
struct _MiniDumpCrashPadInfo
|
|
{
|
|
uint32 mVersion;
|
|
GUID mReportID;
|
|
GUID mClientID;
|
|
};
|
|
|
|
auto& crashPadInfo = mMiniDump->GetStreamData<_MiniDumpCrashPadInfo>(section);
|
|
}
|
|
else if (section.mStreamType == 0x4b6b0002) // Stability report
|
|
{
|
|
const char* report = &mMiniDump->GetStreamData<char>(section);
|
|
}
|
|
}
|
|
|
|
Run();
|
|
}
|
|
|
|
MiniDumpDebugger::~MiniDumpDebugger()
|
|
{
|
|
delete mMiniDump;
|
|
|
|
for (auto mappedFile : mMappedFiles)
|
|
delete mappedFile;
|
|
}
|
|
|
|
void MiniDumpDebugger::MapMemory(addr_target addr, void* data, intptr_target size)
|
|
{
|
|
addr_target beginAddress = addr;
|
|
addr_target endAddress = addr + size;
|
|
|
|
int memSize = (int)(endAddress - beginAddress);
|
|
for (int memOffset = 0; true; memOffset += DBG_MAX_LOOKBACK)
|
|
{
|
|
int curSize = memSize - memOffset;
|
|
if (curSize <= 0)
|
|
break;
|
|
|
|
MiniDumpMemoryRegion* memRegion = mAlloc.Alloc<MiniDumpMemoryRegion>();
|
|
memRegion->mAddress = beginAddress + memOffset;
|
|
memRegion->mAddressLength = curSize;
|
|
memRegion->mData = (uint8*)data + memOffset;
|
|
memRegion->mNext = NULL;
|
|
mMemMap.Insert(memRegion);
|
|
}
|
|
}
|
|
|
|
MappedFile* MiniDumpDebugger::MapModule(COFF* dbgModule, const StringImpl& fileName)
|
|
{
|
|
auto mappedFile = new MappedFile();
|
|
if (!mappedFile->Open(fileName))
|
|
{
|
|
delete mappedFile;
|
|
return NULL;
|
|
}
|
|
mMappedFiles.Add(mappedFile);
|
|
return mappedFile;
|
|
}
|
|
|
|
bool MiniDumpDebugger::PopulateRegisters(CPURegisters* registers)
|
|
{
|
|
if (mActiveThread == mExceptionThread)
|
|
{
|
|
auto& ctx = mMiniDump->GetData<BF_CONTEXT>(mExceptionContextRVA);
|
|
return PopulateRegisters(registers, ctx);
|
|
}
|
|
|
|
for (auto section : mMiniDump->mDirectory)
|
|
{
|
|
if (section.mStreamType == ThreadExListStream)
|
|
{
|
|
|
|
}
|
|
else if (section.mStreamType == ThreadListStream)
|
|
{
|
|
auto& threadList = mMiniDump->GetStreamData<MINIDUMP_THREAD_LIST>(section);
|
|
for (int threadIdx = 0; threadIdx < (int)threadList.NumberOfThreads; threadIdx++)
|
|
{
|
|
auto& thread = threadList.Threads[threadIdx];
|
|
if (thread.ThreadId == mActiveThread->mThreadId)
|
|
{
|
|
auto& ctx = mMiniDump->GetData<BF_CONTEXT>(thread.ThreadContext.Rva);
|
|
return PopulateRegisters(registers, ctx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MiniDumpDebugger::ReadMemory(intptr address, uint64 length, void* dest, bool local)
|
|
{
|
|
if (local)
|
|
{
|
|
__try
|
|
{
|
|
memcpy(dest, (void*)address, length);
|
|
return true;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
uintptr useAddr = (uintptr)address;
|
|
|
|
while (true)
|
|
{
|
|
MiniDumpMemoryRegion* memRegion = mMemMap.Get(useAddr, DBG_MAX_LOOKBACK);
|
|
if (memRegion == NULL)
|
|
return false;
|
|
|
|
if ((uintptr)address < (uintptr)memRegion->mAddress)
|
|
return false; // Out of bounds, done
|
|
|
|
while (memRegion != NULL)
|
|
{
|
|
if (((uintptr)address >= (uintptr)memRegion->mAddress) && ((uintptr)address < memRegion->mAddress + memRegion->mAddressLength))
|
|
{
|
|
if ((uintptr)address + length <= (uintptr)(memRegion->mAddress + memRegion->mAddressLength))
|
|
{
|
|
// In bounds
|
|
memcpy(dest, (uint8*)memRegion->mData + (address - memRegion->mAddress), length);
|
|
}
|
|
else
|
|
{
|
|
int headBytes = (int)(memRegion->mAddress + memRegion->mAddressLength - address);
|
|
memcpy(dest, (uint8*)memRegion->mData + (address - memRegion->mAddress), headBytes);
|
|
if (!ReadMemory(address + headBytes, length - headBytes, (uint8*)dest + headBytes, local))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
useAddr = BF_MIN(useAddr, memRegion->mAddress - 1);
|
|
memRegion = memRegion->mNext;
|
|
}
|
|
|
|
//if (((uintptr)address < (uintptr)memRegion->mAddress) || ((uintptr)(address + length) > uintptr(memRegion->mAddress + memRegion->mAddressLength)))
|
|
//return false; // Out of bounds
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool MiniDumpDebugger::WriteMemory(intptr address, void* src, uint64 length)
|
|
{
|
|
return false;
|
|
}
|
|
|