2019-08-23 11:56:54 -07:00
# 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 ( )
2022-07-30 09:11:38 -04:00
{
2019-08-23 11:56:54 -07:00
mFailed = false ;
mSearchingSymSrv = false ;
mCancelling = false ;
mInProcess = false ;
mLastUpdateTick = 0 ;
2022-07-30 09:11:38 -04:00
mDbgSymSrv = NULL ;
2019-08-23 11:56:54 -07:00
mWantAge = 0 ;
mMayBeOld = false ;
mIsPreCache = false ;
}
DbgSymRequest : : ~ DbgSymRequest ( )
{
}
String DbgSymRequest : : GetGuidString ( )
{
String str ;
2022-07-30 09:11:38 -04:00
2019-08-23 11:56:54 -07:00
// Seems like weird ordering, but the guid is really supposed to be (uint32, uint16, uint16, uint8[8])
2022-07-30 09:11:38 -04:00
str + = StrFormat ( " %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X " ,
2019-08-23 11:56:54 -07:00
mWantGuid [ 3 ] , mWantGuid [ 2 ] , mWantGuid [ 1 ] , mWantGuid [ 0 ] ,
mWantGuid [ 5 ] , mWantGuid [ 4 ] ,
2022-07-30 09:11:38 -04:00
mWantGuid [ 7 ] , mWantGuid [ 6 ] ,
2019-08-23 11:56:54 -07:00
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 ( ) ;
2019-09-22 08:25:38 -07:00
checkPath + = StrFormat ( " %x/ " , mWantAge ) ;
2019-08-23 11:56:54 -07:00
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 ( ) ) ) ;
}
2022-07-30 09:11:38 -04:00
else
2019-08-23 11:56:54 -07:00
{
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 )
2022-07-30 09:11:38 -04:00
{
2019-08-23 11:56:54 -07:00
if ( mIsPreCache )
2022-07-30 09:11:38 -04:00
{
2019-09-23 13:48:11 -07:00
auto netResult = mDbgSymSrv - > mDebugger - > mDebugManager - > mNetManager - > QueueGet ( url , destPath , true ) ;
2019-08-23 11:56:54 -07:00
if ( chainNetResult ! = NULL )
{
if ( ( * chainNetResult ! = NULL ) & & ( netResult ! = NULL ) )
mDbgSymSrv - > mDebugger - > mDebugManager - > mNetManager - > SetCancelOnSuccess ( * chainNetResult , netResult ) ;
if ( ! ignoreSuccess )
* chainNetResult = netResult ;
}
return false ;
}
2022-07-30 09:11:38 -04:00
2019-08-23 11:56:54 -07:00
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 ;
}
2022-07-30 09:11:38 -04:00
// Check in same dir as module
2019-08-23 11:56:54 -07:00
String checkPath = : : GetFileDir ( mModulePath ) ;
checkPath + = " \\ " ;
checkPath + = GetFileName ( mPDBRequested ) ;
if ( ! FileNameEquals ( checkPath , mPDBRequested ) )
{
if ( CheckPDBData ( checkPath , outGuid , outAge ) )
{
mFinalPDBPath = checkPath ;
return ;
}
}
}
2022-07-30 09:11:38 -04:00
2019-08-23 11:56:54 -07:00
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 ) ; */
2022-07-30 09:11:38 -04:00
SetAndRestoreValue < bool > prevSearchingSymSrv ( mSearchingSymSrv , true ) ;
2019-08-23 11:56:54 -07:00
NetResult * chainNetResult = NULL ;
uint8 outGuid [ 16 ] ;
int32 outAge ;
2022-07-30 09:11:38 -04:00
2019-08-23 11:56:54 -07:00
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 ;
2022-07-30 09:11:38 -04:00
2019-08-23 11:56:54 -07:00
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 ;
}
2022-07-30 09:11:38 -04:00
}
2019-08-23 11:56:54 -07:00
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 ;
2022-07-30 09:11:38 -04:00
// Re-check cache
2019-08-23 11:56:54 -07:00
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 ;
2022-07-30 09:11:38 -04:00
2019-08-23 11:56:54 -07:00
PEHeader hdr ;
fs . ReadT ( hdr ) ;
2022-07-30 09:11:38 -04:00
PE_NTHeaders64 ntHdr64 ;
fs . SetPos ( hdr . e_lfanew ) ;
2019-08-23 11:56:54 -07:00
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 ;
}
2022-07-30 09:11:38 -04:00
2019-08-23 11:56:54 -07:00
return true ;
}
String DbgSymRequest : : SearchForImage ( const String & filePath , uint32 fileTime , int size )
2022-07-30 09:11:38 -04:00
{
2019-08-23 11:56:54 -07:00
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 " " ;
2022-07-30 09:11:38 -04:00
}
2019-08-23 11:56:54 -07:00
NetResult * chainNetResult = NULL ;
String fileName = GetFileName ( filePath ) ;
String imageStoreDir = " / " ;
imageStoreDir + = fileName ;
2022-07-30 09:11:38 -04:00
imageStoreDir + = " / " ;
imageStoreDir + = StrFormat ( " %08X%x/ " , fileTime , size ) ;
2019-08-23 11:56:54 -07:00
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 ;
2022-07-30 09:11:38 -04:00
}
2019-08-23 11:56:54 -07:00
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 ) )
2022-07-30 09:11:38 -04:00
{
2019-08-23 11:56:54 -07:00
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 ) )
{
2022-07-30 09:11:38 -04:00
return cacheFilePath ;
2019-08-23 11:56:54 -07:00
}
}
2019-09-27 13:05:39 -07:00
if ( ! mIsPreCache )
2019-08-23 11:56:54 -07:00
{
2022-07-30 09:11:38 -04:00
mDbgSymSrv - > mDebugger - > mHadImageFindError = true ;
mDbgSymSrv - > mDebugger - > OutputMessage ( StrFormat ( " ERROR: Unable to locate image '%s' (%08X%x). If this file is located on a symbol server, configure the symbol server location in File \\ Preferences \\ Settings under Debugger \\ Symbol File Locations. \n " ,
2019-09-27 13:05:39 -07:00
GetFileName ( filePath ) . c_str ( ) , fileTime , size ) ) ;
2019-08-23 11:56:54 -07:00
}
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 )
{
2022-07-30 09:11:38 -04:00
mDebugger = debugger ;
2019-08-23 11:56:54 -07:00
}
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 ;
2022-07-30 09:11:38 -04:00
symRequest - > mDbgSymSrv = this ;
2019-08-23 11:56:54 -07:00
return symRequest ;
}
void DbgSymSrv : : ReleaseRequest ( DbgSymRequest * dbgSymRequest )
{
delete dbgSymRequest ;
}
void DbgSymSrv : : Update ( )
{
2022-07-30 09:11:38 -04:00
}