mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 12:32:20 +02:00
Initial checkin
This commit is contained in:
parent
c74712dad9
commit
078564ac9e
3242 changed files with 1616395 additions and 0 deletions
573
IDEHelper/DbgSymSrv.cpp
Normal file
573
IDEHelper/DbgSymSrv.cpp
Normal file
|
@ -0,0 +1,573 @@
|
|||
#include "DbgSymSrv.h"
|
||||
#include "DbgSymSrv.h"
|
||||
#include "BeefySysLib/MemStream.h"
|
||||
#include "BeefySysLib/util/BeefPerf.h"
|
||||
#include "BeefySysLib/util/CabUtil.h"
|
||||
#include "NetManager.h"
|
||||
#include "Compiler/BfUtil.h"
|
||||
#include "DebugManager.h"
|
||||
#include <shlobj.h>
|
||||
#include "COFF.h"
|
||||
|
||||
#include "BeefySysLib/util/AllocDebug.h"
|
||||
|
||||
// #define BF_DBG_64
|
||||
// #include "DebugCommon.h"
|
||||
// #include "COFF.h"
|
||||
// #undef BF_DBG_64
|
||||
|
||||
USING_NS_BF_DBG;
|
||||
|
||||
DbgSymRequest::DbgSymRequest()
|
||||
{
|
||||
mFailed = false;
|
||||
mSearchingSymSrv = false;
|
||||
mCancelling = false;
|
||||
mInProcess = false;
|
||||
mLastUpdateTick = 0;
|
||||
mDbgSymSrv = NULL;
|
||||
mWantAge = 0;
|
||||
mMayBeOld = false;
|
||||
mIsPreCache = false;
|
||||
}
|
||||
|
||||
DbgSymRequest::~DbgSymRequest()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
String DbgSymRequest::GetGuidString()
|
||||
{
|
||||
String str;
|
||||
|
||||
// Seems like weird ordering, but the guid is really supposed to be (uint32, uint16, uint16, uint8[8])
|
||||
str += StrFormat("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||
mWantGuid[3], mWantGuid[2], mWantGuid[1], mWantGuid[0],
|
||||
mWantGuid[5], mWantGuid[4],
|
||||
mWantGuid[7], mWantGuid[6],
|
||||
mWantGuid[8], mWantGuid[9], mWantGuid[10], mWantGuid[11], mWantGuid[12], mWantGuid[13], mWantGuid[14], mWantGuid[15]);
|
||||
return str;
|
||||
}
|
||||
|
||||
String DbgSymRequest::GetPDBStoreDir()
|
||||
{
|
||||
String checkPath = "/";
|
||||
checkPath += GetFileName(mPDBRequested);
|
||||
checkPath += "/";
|
||||
checkPath += GetGuidString();
|
||||
checkPath += StrFormat("%X/", mWantAge);
|
||||
return checkPath;
|
||||
}
|
||||
|
||||
void DbgSymRequest::Fail(const StringImpl& error)
|
||||
{
|
||||
mFailed = true;
|
||||
if (mError.IsEmpty())
|
||||
mError = error;
|
||||
}
|
||||
|
||||
bool DbgSymRequest::CheckPDBData(const StringImpl& pdbPath, uint8 outGuid[16], int32& outAge)
|
||||
{
|
||||
BP_ZONE("DbgSymRequest::CheckPDBData");
|
||||
|
||||
if (!FileExists(pdbPath))
|
||||
return false;
|
||||
|
||||
mDbgSymSrv->mDebugger->OutputRawMessage(StrFormat("symsrv Checking '%s'", pdbPath.c_str()));
|
||||
|
||||
COFF coff(NULL);
|
||||
coff.mParseKind = COFF::ParseKind_Header;
|
||||
bool result = coff.TryLoadPDB(pdbPath, mWantGuid, mWantAge);
|
||||
memcpy(outGuid, coff.mPDBGuid, 16);
|
||||
outAge = coff.mDebugAge;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
if (outAge != -1)
|
||||
{
|
||||
mDbgSymSrv->mDebugger->OutputMessage(StrFormat("ERROR: %s cannot be used due to age mismatch\n", pdbPath.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hasGuid = false;
|
||||
for (int i = 0; i < 16; i++)
|
||||
if (outGuid[i] != 0)
|
||||
hasGuid = true;
|
||||
if (hasGuid)
|
||||
{
|
||||
mDbgSymSrv->mDebugger->OutputMessage(StrFormat("ERROR: %s cannot be used due to GUID mismatch\n", pdbPath.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
mDbgSymSrv->mDebugger->OutputMessage(StrFormat("ERROR: %s failed to load\n", pdbPath.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DbgSymRequest::Get(const StringImpl& url, const StringImpl& destPath, NetResult** chainNetResult, bool ignoreSuccess)
|
||||
{
|
||||
if (mIsPreCache)
|
||||
{
|
||||
auto netResult = mDbgSymSrv->mDebugger->mDebugManager->mNetManager->QueueGet(url, destPath);
|
||||
if (chainNetResult != NULL)
|
||||
{
|
||||
if ((*chainNetResult != NULL) && (netResult != NULL))
|
||||
mDbgSymSrv->mDebugger->mDebugManager->mNetManager->SetCancelOnSuccess(*chainNetResult, netResult);
|
||||
if (!ignoreSuccess)
|
||||
*chainNetResult = netResult;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return mDbgSymSrv->mDebugger->mDebugManager->mNetManager->Get(url, destPath);
|
||||
}
|
||||
|
||||
void DbgSymRequest::SearchLocal()
|
||||
{
|
||||
if ((gDebugManager->mSymSrvOptions.mFlags & BfSymSrvFlag_Disable) != 0)
|
||||
{
|
||||
mFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mPDBRequested.IndexOf('\\') != -1) // Do we have an absolute path at all? System dlls won't.
|
||||
{
|
||||
// Check actual path
|
||||
uint8 outGuid[16];
|
||||
int32 outAge;
|
||||
if (CheckPDBData(mPDBRequested, outGuid, outAge))
|
||||
{
|
||||
mFinalPDBPath = mPDBRequested;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check in same dir as module
|
||||
String checkPath = ::GetFileDir(mModulePath);
|
||||
checkPath += "\\";
|
||||
checkPath += GetFileName(mPDBRequested);
|
||||
if (!FileNameEquals(checkPath, mPDBRequested))
|
||||
{
|
||||
if (CheckPDBData(checkPath, outGuid, outAge))
|
||||
{
|
||||
mFinalPDBPath = checkPath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mMayBeOld = true;
|
||||
}
|
||||
|
||||
void DbgSymRequest::SearchCache()
|
||||
{
|
||||
if ((gDebugManager->mSymSrvOptions.mFlags & BfSymSrvFlag_Disable) != 0)
|
||||
{
|
||||
mFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOptions.mCacheDir.IsEmpty())
|
||||
{
|
||||
mFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 outGuid[16];
|
||||
int32 outAge;
|
||||
|
||||
String cacheDir = mOptions.mCacheDir;
|
||||
cacheDir += GetPDBStoreDir();
|
||||
|
||||
String cacheFilePath = cacheDir + "/" + GetFileName(mPDBRequested);
|
||||
if (CheckPDBData(cacheFilePath, outGuid, outAge))
|
||||
{
|
||||
mFinalPDBPath = cacheFilePath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DbgSymRequest::SearchSymSrv()
|
||||
{
|
||||
if ((gDebugManager->mSymSrvOptions.mFlags & BfSymSrvFlag_Disable) != 0)
|
||||
{
|
||||
mFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOptions.mCacheDir.IsEmpty())
|
||||
{
|
||||
mFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/*if (mPDBRequested.Contains("IDEHelper"))
|
||||
Sleep(3000);*/
|
||||
|
||||
SetAndRestoreValue<bool> prevSearchingSymSrv(mSearchingSymSrv, true);
|
||||
|
||||
NetResult* chainNetResult = NULL;
|
||||
uint8 outGuid[16];
|
||||
int32 outAge;
|
||||
|
||||
String cacheDir = mOptions.mCacheDir;
|
||||
cacheDir += GetPDBStoreDir();
|
||||
|
||||
//TODO: Remove!
|
||||
// for (int i = 0; i < 8; i++)
|
||||
// {
|
||||
// mDbgSymSrv->mDebugger->OutputMessage(StrFormat("Sleep %d\n", i));
|
||||
// if (mCancelling)
|
||||
// break;
|
||||
// Sleep(1000);
|
||||
// }
|
||||
|
||||
String cacheFilePath = cacheDir + "/" + GetFileName(mPDBRequested);
|
||||
|
||||
for (auto& symServAddr : mOptions.mSymbolServers)
|
||||
{
|
||||
if (mCancelling)
|
||||
break;
|
||||
|
||||
int colonPos = symServAddr.IndexOf(':');
|
||||
if (colonPos > 1)
|
||||
{
|
||||
// HTTP
|
||||
bool done = false;
|
||||
|
||||
//TODO: Check for 'index2.txt' for two-tiered structure
|
||||
|
||||
String checkPath = symServAddr;
|
||||
checkPath += GetPDBStoreDir();
|
||||
checkPath += GetFileName(mPDBRequested);
|
||||
if (Get(checkPath, cacheFilePath, &chainNetResult))
|
||||
done = true;
|
||||
|
||||
if ((!done) && (!mCancelling))
|
||||
{
|
||||
// Compressed version
|
||||
checkPath[checkPath.length() - 1] = '_';
|
||||
|
||||
String compCacheFilePath = cacheFilePath;
|
||||
compCacheFilePath[compCacheFilePath.length() - 1] = '_';
|
||||
if (Get(checkPath, compCacheFilePath, &chainNetResult))
|
||||
{
|
||||
CabFile cabFile;
|
||||
cabFile.Load(compCacheFilePath);
|
||||
mDbgSymSrv->mDebugger->OutputRawMessage(StrFormat("symsrv Decompressing '%s'", compCacheFilePath.c_str()));
|
||||
if (!cabFile.DecompressAll(cacheDir))
|
||||
{
|
||||
Fail(cabFile.mError);
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!done) && (!mCancelling))
|
||||
{
|
||||
String checkPath = symServAddr;
|
||||
checkPath += GetPDBStoreDir();
|
||||
checkPath += "/file.dir";
|
||||
|
||||
String fileDirFilePath = symServAddr;
|
||||
fileDirFilePath += GetPDBStoreDir();
|
||||
fileDirFilePath += "/file.dir";
|
||||
|
||||
if (Get(checkPath, fileDirFilePath, &chainNetResult, true))
|
||||
{
|
||||
// What do I do with this?
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!mIsPreCache)
|
||||
{
|
||||
// Uncompressed version
|
||||
String checkPath = symServAddr;
|
||||
checkPath += GetPDBStoreDir();
|
||||
checkPath += GetFileName(mPDBRequested);
|
||||
if (CheckPDBData(checkPath, outGuid, outAge))
|
||||
{
|
||||
mFinalPDBPath = checkPath;
|
||||
return;
|
||||
}
|
||||
|
||||
// Compressed version
|
||||
checkPath[checkPath.length() - 1] = '_';
|
||||
if (FileExists(checkPath))
|
||||
{
|
||||
CabFile cabFile;
|
||||
cabFile.Load(checkPath);
|
||||
mDbgSymSrv->mDebugger->OutputRawMessage(StrFormat("symsrv Decompressing '%s'", checkPath.c_str()));
|
||||
if (!cabFile.DecompressAll(cacheDir))
|
||||
{
|
||||
Fail(cabFile.mError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsPreCache)
|
||||
continue;
|
||||
|
||||
// Re-check cache
|
||||
if (CheckPDBData(cacheFilePath, outGuid, outAge))
|
||||
{
|
||||
mFinalPDBPath = cacheFilePath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mFailed = true;
|
||||
}
|
||||
|
||||
bool DbgSymRequest::CheckPEFile(const StringImpl& filePath, uint32 fileTime, int size)
|
||||
{
|
||||
FileStream fs;
|
||||
|
||||
if (!fs.Open(filePath, "rb"))
|
||||
return false;
|
||||
|
||||
PEHeader hdr;
|
||||
fs.ReadT(hdr);
|
||||
|
||||
PE_NTHeaders64 ntHdr64;
|
||||
fs.SetPos(hdr.e_lfanew);
|
||||
fs.Read(&ntHdr64, sizeof(PE_NTHeaders64));
|
||||
if (ntHdr64.mFileHeader.mMachine == PE_MACHINE_X64)
|
||||
{
|
||||
if ((ntHdr64.mFileHeader.mTimeDateStamp != fileTime) || (ntHdr64.mOptionalHeader.mSizeOfImage != size))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PE_NTHeaders32 ntHdr32;
|
||||
fs.SetPos(hdr.e_lfanew);
|
||||
fs.Read(&ntHdr32, sizeof(PE_NTHeaders32));
|
||||
if ((ntHdr32.mFileHeader.mTimeDateStamp != fileTime) || (ntHdr32.mOptionalHeader.mSizeOfImage != size))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String DbgSymRequest::SearchForImage(const String& filePath, uint32 fileTime, int size)
|
||||
{
|
||||
if ((gDebugManager->mSymSrvOptions.mFlags & BfSymSrvFlag_Disable) != 0)
|
||||
return "";
|
||||
|
||||
if (FileExists(filePath))
|
||||
{
|
||||
if (CheckPEFile(filePath, fileTime, size))
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/*if (filePath.Contains("IDEHelper"))
|
||||
Sleep(3000);*/
|
||||
|
||||
if (mOptions.mCacheDir.IsEmpty())
|
||||
{
|
||||
mFailed = true;
|
||||
return "";
|
||||
}
|
||||
|
||||
NetResult* chainNetResult = NULL;
|
||||
|
||||
String fileName = GetFileName(filePath);
|
||||
String imageStoreDir = "/";
|
||||
imageStoreDir += fileName;
|
||||
imageStoreDir += "/";
|
||||
imageStoreDir += StrFormat("%08X%x/", fileTime, size);
|
||||
|
||||
SetAndRestoreValue<bool> prevSearchingSymSrv(mSearchingSymSrv, true);
|
||||
|
||||
String cacheDir = mOptions.mCacheDir;
|
||||
cacheDir += imageStoreDir;
|
||||
|
||||
/*for (int i = 0; i < 8; i++)
|
||||
{
|
||||
mDbgSymSrv->mDebugger->OutputMessage(StrFormat("Image Sleep %d\n", i));
|
||||
if (mCancelling)
|
||||
break;
|
||||
Sleep(1000);
|
||||
}*/
|
||||
|
||||
String cacheFilePath = cacheDir + "/" + GetFileName(filePath);
|
||||
|
||||
// Check cache
|
||||
if (CheckPEFile(cacheFilePath, fileTime, size))
|
||||
{
|
||||
return cacheFilePath;
|
||||
}
|
||||
|
||||
for (auto& symServAddr : mOptions.mSymbolServers)
|
||||
{
|
||||
if (mCancelling)
|
||||
break;
|
||||
|
||||
int colonPos = symServAddr.IndexOf(':');
|
||||
if (colonPos > 1)
|
||||
{
|
||||
// HTTP
|
||||
bool done = false;
|
||||
|
||||
//TODO: Check for 'index2.txt' for two-tiered structure
|
||||
|
||||
String checkPath = symServAddr;
|
||||
checkPath += imageStoreDir;
|
||||
checkPath += fileName;
|
||||
if (Get(checkPath, cacheFilePath, &chainNetResult))
|
||||
done = true;
|
||||
|
||||
if ((!done) && (!mCancelling))
|
||||
{
|
||||
// Compressed version
|
||||
checkPath[checkPath.length() - 1] = '_';
|
||||
|
||||
String compCacheFilePath = cacheFilePath;
|
||||
compCacheFilePath[compCacheFilePath.length() - 1] = '_';
|
||||
if (Get(checkPath, compCacheFilePath, &chainNetResult))
|
||||
{
|
||||
mDbgSymSrv->mDebugger->mDebugManager->mOutMessages.push_back(StrFormat("symsrv Decompressing '%s'", checkPath.c_str()));
|
||||
|
||||
CabFile cabFile;
|
||||
cabFile.Load(compCacheFilePath);
|
||||
if (!cabFile.DecompressAll(cacheDir))
|
||||
{
|
||||
Fail(cabFile.mError);
|
||||
return "";
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!done) && (!mCancelling))
|
||||
{
|
||||
String checkPath = symServAddr;
|
||||
checkPath += imageStoreDir;
|
||||
checkPath += "/file.dir";
|
||||
|
||||
String fileDirFilePath = symServAddr;
|
||||
fileDirFilePath += imageStoreDir;
|
||||
fileDirFilePath += "/file.dir";
|
||||
|
||||
if (Get(checkPath, fileDirFilePath, &chainNetResult, true))
|
||||
{
|
||||
// What do I do with this?
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!mIsPreCache)
|
||||
{
|
||||
// Uncompressed version
|
||||
String checkPath = symServAddr;
|
||||
checkPath += imageStoreDir;
|
||||
checkPath += fileName;
|
||||
if (CheckPEFile(checkPath, fileTime, size))
|
||||
{
|
||||
return checkPath;
|
||||
}
|
||||
|
||||
// Compressed version
|
||||
checkPath[checkPath.length() - 1] = '_';
|
||||
if (FileExists(checkPath))
|
||||
{
|
||||
CabFile cabFile;
|
||||
cabFile.Load(checkPath);
|
||||
if (!cabFile.DecompressAll(cacheDir))
|
||||
{
|
||||
Fail(cabFile.mError);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsPreCache)
|
||||
continue;
|
||||
|
||||
// Re-check cache
|
||||
if (CheckPEFile(cacheFilePath, fileTime, size))
|
||||
{
|
||||
return cacheFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!mIsPreCache) && (!mDbgSymSrv->mDebugger->mHadImageFindError))
|
||||
{
|
||||
mDbgSymSrv->mDebugger->mHadImageFindError = true;
|
||||
mDbgSymSrv->mDebugger->OutputMessage(StrFormat("ERROR: Unable to locate image '%s'. If this file is located on a symbol server, configure the symbol server location in File\\Preferences\\Settings under Debugger\\Symbol File Locations.\n", GetFileName(filePath).c_str()));
|
||||
}
|
||||
|
||||
mFailed = true;
|
||||
return "";
|
||||
}
|
||||
|
||||
void DbgSymRequest::Cancel()
|
||||
{
|
||||
mCancelling = true;
|
||||
mDbgSymSrv->mDebugger->mDebugManager->mNetManager->CancelCurrent();
|
||||
}
|
||||
|
||||
bool DbgSymRequest::IsDone()
|
||||
{
|
||||
AutoCrit autoCrit(mCritSect);
|
||||
|
||||
if (!mFinalPDBPath.IsEmpty())
|
||||
return true;
|
||||
|
||||
if (mFailed)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DbgSymSrv::DbgSymSrv(Debugger* debugger)
|
||||
{
|
||||
mDebugger = debugger;
|
||||
}
|
||||
|
||||
void DbgSymSrv::PreCacheImage(const String& filePath, uint32 fileTime, int size)
|
||||
{
|
||||
auto request = CreateRequest();
|
||||
request->mIsPreCache = true;
|
||||
request->SearchForImage(filePath, fileTime, size);
|
||||
delete request;
|
||||
}
|
||||
|
||||
DbgSymRequest* DbgSymSrv::CreateRequest(const StringImpl& modulePath, const StringImpl& pdbRequested, uint8 wantGuid[16], int32 wantAge)
|
||||
{
|
||||
AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect);
|
||||
|
||||
DbgSymRequest* symRequest = new DbgSymRequest();
|
||||
symRequest->mOptions = mDebugger->mDebugManager->mSymSrvOptions;
|
||||
symRequest->mDbgSymSrv = this;
|
||||
symRequest->mModulePath = modulePath;
|
||||
symRequest->mPDBRequested = pdbRequested;
|
||||
memcpy(symRequest->mWantGuid, wantGuid, 16);
|
||||
symRequest->mWantAge = wantAge;
|
||||
|
||||
return symRequest;
|
||||
}
|
||||
|
||||
DbgSymRequest* DbgSymSrv::CreateRequest()
|
||||
{
|
||||
AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect);
|
||||
|
||||
DbgSymRequest* symRequest = new DbgSymRequest();
|
||||
symRequest->mOptions = mDebugger->mDebugManager->mSymSrvOptions;
|
||||
symRequest->mDbgSymSrv = this;
|
||||
return symRequest;
|
||||
}
|
||||
|
||||
void DbgSymSrv::ReleaseRequest(DbgSymRequest* dbgSymRequest)
|
||||
{
|
||||
delete dbgSymRequest;
|
||||
}
|
||||
|
||||
void DbgSymSrv::Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue