DBG: attempt to load symbols from multiple locations
This commit is contained in:
parent
637815b63d
commit
ff11a39533
|
@ -7,7 +7,9 @@
|
|||
#include "memory.h"
|
||||
#include "label.h"
|
||||
#include <algorithm>
|
||||
#include <shlwapi.h>
|
||||
#include "console.h"
|
||||
#include "debugger.h"
|
||||
|
||||
std::map<Range, MODINFO, RangeCompare> modinfo;
|
||||
std::unordered_map<duint, std::string> hashNameMap;
|
||||
|
@ -181,8 +183,8 @@ void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
}
|
||||
}(debugDir.Type);
|
||||
|
||||
dprintf("IMAGE_DEBUG_DIRECTORY:\nCharacteristics: %08X\nTimeDateStamp: %08X\nMajorVersion: %04X\nMinorVersion: %04X\nType: %s\nSizeOfData: %08X\nAddressOfRawData: %08X\nPointerToRawData: %08X\n",
|
||||
debugDir.Characteristics, debugDir.TimeDateStamp, debugDir.MajorVersion, debugDir.MinorVersion, typeName, debugDir.SizeOfData, debugDir.AddressOfRawData, debugDir.PointerToRawData);
|
||||
/*dprintf("IMAGE_DEBUG_DIRECTORY:\nCharacteristics: %08X\nTimeDateStamp: %08X\nMajorVersion: %04X\nMinorVersion: %04X\nType: %s\nSizeOfData: %08X\nAddressOfRawData: %08X\nPointerToRawData: %08X\n",
|
||||
debugDir.Characteristics, debugDir.TimeDateStamp, debugDir.MajorVersion, debugDir.MinorVersion, typeName, debugDir.SizeOfData, debugDir.AddressOfRawData, debugDir.PointerToRawData);*/
|
||||
|
||||
if(debugDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) //TODO: support other types (DBG)?
|
||||
{
|
||||
|
@ -227,6 +229,8 @@ void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
auto cv = (CV_INFO_PDB20*)(FileMapVA + codeViewOffset);
|
||||
Info.pdbSignature = StringUtils::sprintf("%X%X", cv->Signature, cv->Age);
|
||||
Info.pdbFile = String((const char*)cv->PdbFileName);
|
||||
Info.pdbValidation.signature = cv->Signature;
|
||||
Info.pdbValidation.age = cv->Age;
|
||||
}
|
||||
else if(signature == 'SDSR')
|
||||
{
|
||||
|
@ -236,6 +240,8 @@ void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
StringUtils::ToHex(cv->Signature.Data4, 8).c_str(),
|
||||
cv->Age);
|
||||
Info.pdbFile = String((const char*)cv->PdbFileName);
|
||||
memcpy(&Info.pdbValidation.guid, &cv->Signature, sizeof(GUID));
|
||||
Info.pdbValidation.age = cv->Age;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -243,7 +249,44 @@ void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
return;
|
||||
}
|
||||
|
||||
dprintf("%s%s pdbSignature: %s, pdbFile: \"%s\"\n", Info.name, Info.extension, Info.pdbSignature.c_str(), Info.pdbFile.c_str());
|
||||
//dprintf("%s%s pdbSignature: %s, pdbFile: \"%s\"\n", Info.name, Info.extension, Info.pdbSignature.c_str(), Info.pdbFile.c_str());
|
||||
|
||||
if(!Info.pdbFile.empty())
|
||||
{
|
||||
// Get the directory/filename from the debug directory PDB path
|
||||
String dir, file;
|
||||
auto lastIdx = Info.pdbFile.rfind('\\');
|
||||
if(lastIdx == String::npos)
|
||||
file = Info.pdbFile;
|
||||
else
|
||||
{
|
||||
dir = Info.pdbFile.substr(0, lastIdx - 1);
|
||||
file = Info.pdbFile.substr(lastIdx + 1);
|
||||
}
|
||||
|
||||
// Program directory
|
||||
char pdbPath[MAX_PATH];
|
||||
strcpy_s(pdbPath, Info.path);
|
||||
auto lastBack = strrchr(pdbPath, '\\');
|
||||
if(lastBack)
|
||||
{
|
||||
lastBack[1] = '\0';
|
||||
strncat_s(pdbPath, file.c_str(), _TRUNCATE);
|
||||
Info.pdbPaths.push_back(pdbPath);
|
||||
}
|
||||
|
||||
// Debug directory full path
|
||||
const bool bAllowUncPathsInDebugDirectory = false; // TODO: create setting for this
|
||||
if(!dir.empty() && (bAllowUncPathsInDebugDirectory || !PathIsUNCW(StringUtils::Utf8ToUtf16(Info.pdbFile).c_str())))
|
||||
Info.pdbPaths.push_back(Info.pdbFile);
|
||||
|
||||
// Symbol cache
|
||||
auto cachePath = String(szSymbolCachePath);
|
||||
if(cachePath.back() != '\\')
|
||||
cachePath += '\\';
|
||||
cachePath += StringUtils::sprintf("%s\\%s\\%s", file.c_str(), Info.pdbSignature.c_str(), file.c_str());
|
||||
Info.pdbPaths.push_back(cachePath);
|
||||
}
|
||||
}
|
||||
|
||||
void GetModuleInfo(MODINFO & Info, ULONG_PTR FileMapVA)
|
||||
|
@ -346,7 +389,6 @@ bool ModLoad(duint Base, duint Size, const char* FullPath)
|
|||
info.loadedSize = 0;
|
||||
info.fileMap = nullptr;
|
||||
info.fileMapVA = 0;
|
||||
//info.invalidSymbols.resize(Size);
|
||||
|
||||
// Determine whether the module is located in system
|
||||
wchar_t sysdir[MAX_PATH];
|
||||
|
@ -396,43 +438,8 @@ bool ModLoad(duint Base, duint Size, const char* FullPath)
|
|||
GetModuleInfo(info, (ULONG_PTR)data());
|
||||
}
|
||||
|
||||
// Load Symbols.
|
||||
info.symbols = &EmptySymbolSource; // Set to empty as default one.
|
||||
|
||||
// Try DIA
|
||||
if(info.symbols == &EmptySymbolSource &&
|
||||
SymbolSourceDIA::isLibraryAvailable())
|
||||
{
|
||||
SymbolSourceDIA* symSource = new SymbolSourceDIA();
|
||||
if(symSource->loadPDB(info.path, Base, info.size))
|
||||
{
|
||||
symSource->resizeSymbolBitmap(info.size);
|
||||
|
||||
info.symbols = symSource;
|
||||
|
||||
std::string msg;
|
||||
if(symSource->isLoading())
|
||||
msg = StringUtils::sprintf("Loading async (MSDIA) PDB: %s\n", info.path);
|
||||
else
|
||||
msg = StringUtils::sprintf("Loaded (MSDIA) PDB: %s\n", info.path);
|
||||
|
||||
GuiAddLogMessage(msg.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
delete symSource;
|
||||
}
|
||||
}
|
||||
if(info.symbols == &EmptySymbolSource &&
|
||||
true /* TODO */)
|
||||
{
|
||||
}
|
||||
|
||||
if(info.symbols->isOpen() == false)
|
||||
{
|
||||
std::string msg = StringUtils::sprintf("No symbols loaded for: %s\n", info.path);
|
||||
GuiAddLogMessage(msg.c_str());
|
||||
}
|
||||
// TODO: setting to auto load symbols
|
||||
info.loadSymbols();
|
||||
|
||||
// Add module to list
|
||||
EXCLUSIVE_ACQUIRE(LockModules);
|
||||
|
@ -466,20 +473,12 @@ bool ModUnload(duint Base)
|
|||
return false;
|
||||
|
||||
// Unload the mapped file from memory
|
||||
const auto & info = found->second;
|
||||
auto & info = found->second;
|
||||
if(info.fileMapVA)
|
||||
StaticFileUnloadW(StringUtils::Utf8ToUtf16(info.path).c_str(), false, info.fileHandle, info.loadedSize, info.fileMap, info.fileMapVA);
|
||||
|
||||
if(info.symbols != nullptr &&
|
||||
info.symbols != &EmptySymbolSource)
|
||||
{
|
||||
if(info.symbols->isLoading())
|
||||
{
|
||||
info.symbols->cancelLoading();
|
||||
}
|
||||
|
||||
delete info.symbols;
|
||||
}
|
||||
// Unload symbols from the module
|
||||
info.unloadSymbols();
|
||||
|
||||
// Remove it from the list
|
||||
modinfo.erase(found);
|
||||
|
@ -878,3 +877,74 @@ bool ModRelocationsInRange(duint Address, duint Size, std::vector<MODRELOCATIONI
|
|||
|
||||
return !Relocations.empty();
|
||||
}
|
||||
|
||||
bool MODINFO::loadSymbols()
|
||||
{
|
||||
unloadSymbols();
|
||||
symbols = &EmptySymbolSource; // empty symbol source per default
|
||||
|
||||
// Try DIA
|
||||
if(symbols == &EmptySymbolSource && SymbolSourceDIA::isLibraryAvailable())
|
||||
{
|
||||
// TODO: do something with searchPaths
|
||||
DiaValidationData_t validationData;
|
||||
memcpy(&validationData.guid, &pdbValidation.guid, sizeof(GUID));
|
||||
validationData.signature = pdbValidation.signature;
|
||||
validationData.age = pdbValidation.age;
|
||||
SymbolSourceDIA* symSource = new SymbolSourceDIA();
|
||||
for(const auto & pdbPath : pdbPaths)
|
||||
{
|
||||
if(!FileExists(pdbPath.c_str()))
|
||||
{
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("[DIA] Skipping non-existent PDB: %s\n", pdbPath.c_str()).c_str());
|
||||
}
|
||||
else if(symSource->loadPDB(pdbPath, base, size, &validationData))
|
||||
{
|
||||
symSource->resizeSymbolBitmap(size);
|
||||
|
||||
symbols = symSource;
|
||||
|
||||
std::string msg;
|
||||
if(symSource->isLoading())
|
||||
msg = StringUtils::sprintf("[DIA] Loading PDB (async): %s\n", pdbPath.c_str());
|
||||
else
|
||||
msg = StringUtils::sprintf("[DIA] Loaded PDB: %s\n", pdbPath.c_str());
|
||||
GuiSymbolLogAdd(msg.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: more detailled error codes?
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("[DIA] Failed to load PDB: %s\n", pdbPath.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
delete symSource;
|
||||
}
|
||||
if(symbols == &EmptySymbolSource && true) // TODO: try loading from other sources?
|
||||
{
|
||||
}
|
||||
|
||||
if(!symbols->isOpen())
|
||||
{
|
||||
std::string msg = StringUtils::sprintf("No symbols loaded for: %s%s\n", name, extension);
|
||||
GuiSymbolLogAdd(msg.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MODINFO::unloadSymbols()
|
||||
{
|
||||
if(symbols != nullptr && symbols != &EmptySymbolSource)
|
||||
{
|
||||
if(symbols->isLoading())
|
||||
{
|
||||
symbols->cancelLoading();
|
||||
}
|
||||
|
||||
delete symbols;
|
||||
symbols = &EmptySymbolSource;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,18 @@ struct MODRELOCATIONINFO
|
|||
bool Contains(duint Address) const;
|
||||
};
|
||||
|
||||
struct PdbValidationData
|
||||
{
|
||||
GUID guid;
|
||||
DWORD signature = 0;
|
||||
DWORD age = 0;
|
||||
|
||||
PdbValidationData()
|
||||
{
|
||||
memset(&guid, 0, sizeof(guid));
|
||||
}
|
||||
};
|
||||
|
||||
struct MODINFO
|
||||
{
|
||||
duint base = 0; // Module base
|
||||
|
@ -44,10 +56,12 @@ struct MODINFO
|
|||
std::vector<MODIMPORTINFO> imports;
|
||||
std::vector<MODRELOCATIONINFO> relocations;
|
||||
std::vector<duint> tlsCallbacks;
|
||||
//std::vector<bool> invalidSymbols; //TODO: remove?
|
||||
SymbolSourceBase* symbols;
|
||||
|
||||
SymbolSourceBase* symbols = nullptr;
|
||||
String pdbSignature;
|
||||
String pdbFile;
|
||||
PdbValidationData pdbValidation;
|
||||
std::vector<String> pdbPaths; // Possible PDB paths (tried in order)
|
||||
|
||||
HANDLE fileHandle = nullptr;
|
||||
DWORD loadedSize = 0;
|
||||
|
@ -62,6 +76,9 @@ struct MODINFO
|
|||
memset(extension, 0, sizeof(extension));
|
||||
memset(path, 0, sizeof(path));
|
||||
}
|
||||
|
||||
bool loadSymbols();
|
||||
void unloadSymbols();
|
||||
};
|
||||
|
||||
bool ModLoad(duint Base, duint Size, const char* FullPath);
|
||||
|
|
|
@ -20,7 +20,7 @@ class DiaLoadCallback : public IDiaLoadCallback2
|
|||
/* [in] */ DWORD cbData,
|
||||
/* [size_is][in] */ BYTE* pbData) override
|
||||
{
|
||||
dprintf("[DIA] NotifyDebugDir: %s\n", StringUtils::ToHex(pbData, cbData).c_str());
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("[DIA] NotifyDebugDir: %s\n", StringUtils::ToHex(pbData, cbData).c_str()).c_str());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ class DiaLoadCallback : public IDiaLoadCallback2
|
|||
/* [in] */ LPCOLESTR dbgPath,
|
||||
/* [in] */ HRESULT resultCode) override
|
||||
{
|
||||
dprintf("[DIA] NotifyOpenDBG: %s, %08X\n", StringUtils::Utf16ToUtf8(dbgPath).c_str(), resultCode);
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("[DIA] NotifyOpenDBG: %s, %08X\n", StringUtils::Utf16ToUtf8(dbgPath).c_str(), resultCode).c_str());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ class DiaLoadCallback : public IDiaLoadCallback2
|
|||
/* [in] */ LPCOLESTR pdbPath,
|
||||
/* [in] */ HRESULT resultCode) override
|
||||
{
|
||||
dprintf("[DIA] NotifyOpenPDB: %s, %08X\n", StringUtils::Utf16ToUtf8(pdbPath).c_str(), resultCode);
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("[DIA] NotifyOpenPDB: %s, %08X\n", StringUtils::Utf16ToUtf8(pdbPath).c_str(), resultCode).c_str());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -157,11 +157,7 @@ bool PDBDiaFile::shutdownLibrary()
|
|||
|
||||
bool PDBDiaFile::open(const char* file, uint64_t loadAddress, DiaValidationData_t* validationData)
|
||||
{
|
||||
wchar_t buf[1024];
|
||||
|
||||
mbstowcs_s(nullptr, buf, file, 1024);
|
||||
|
||||
return open(buf, loadAddress, validationData);
|
||||
return open(StringUtils::Utf8ToUtf16(file).c_str(), loadAddress, validationData);
|
||||
}
|
||||
|
||||
bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationData_t* validationData)
|
||||
|
@ -189,7 +185,7 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
|
|||
}
|
||||
else
|
||||
{
|
||||
printf("Unable to initialize PDBDia Library.\n");
|
||||
GuiSymbolLogAdd("Unable to initialize PDBDia Library.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -200,15 +196,15 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
|
|||
{
|
||||
if(validationData != nullptr)
|
||||
{
|
||||
hr = m_dataSource->loadAndValidateDataFromPdb(file, (GUID*)validationData->guid, validationData->signature, validationData->age);
|
||||
hr = m_dataSource->loadAndValidateDataFromPdb(file, &validationData->guid, validationData->signature, validationData->age);
|
||||
if((hr == E_PDB_INVALID_SIG) || (hr == E_PDB_INVALID_AGE))
|
||||
{
|
||||
printf("PDB is not matching.\n");
|
||||
GuiSymbolLogAdd("PDB is not matching.\n");
|
||||
return false;
|
||||
}
|
||||
else if(hr == E_PDB_FORMAT)
|
||||
{
|
||||
printf("PDB uses an obsolete format.\n");
|
||||
GuiSymbolLogAdd("PDB uses an obsolete format.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +223,7 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
|
|||
{
|
||||
if(hr != E_PDB_NOT_FOUND)
|
||||
{
|
||||
printf("Unable to open PDB file - %08X\n", hr);
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("Unable to open PDB file - %08X\n", hr).c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -235,7 +231,7 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
|
|||
hr = m_dataSource->openSession(&m_session);
|
||||
if(testError(hr) || m_session == nullptr)
|
||||
{
|
||||
printf("Unable to create new PDBDia Session - %08X\n", hr);
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("Unable to create new PDBDia Session - %08X\n", hr).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -689,7 +685,7 @@ bool PDBDiaFile::processFunctionSymbol(IDiaSymbol* functionSym, InternalQueryCon
|
|||
uint32_t symId = getSymbolId(functionSym);
|
||||
if(context.visited.find(symId) != context.visited.end())
|
||||
{
|
||||
printf("Dupe\n");
|
||||
GuiSymbolLogAdd("Dupe\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -976,9 +972,9 @@ bool PDBDiaFile::convertSymbolInfo(IDiaSymbol* symbol, DiaSymbol_t & symbolInfo,
|
|||
{
|
||||
if(test != symbolInfo.undecoratedName)
|
||||
{
|
||||
dprintf("undecoration mismatch, msvcrt: \"%s\", DIA: \"%s\"\n",
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("undecoration mismatch, msvcrt: \"%s\", DIA: \"%s\"\n",
|
||||
symbolInfo.undecoratedName.c_str(),
|
||||
test.c_str());
|
||||
test.c_str()).c_str());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ enum class DiaCallingConvention
|
|||
|
||||
struct DiaValidationData_t
|
||||
{
|
||||
uint8_t guid[16];
|
||||
GUID guid;
|
||||
uint32_t signature;
|
||||
uint32_t age;
|
||||
};
|
||||
|
|
|
@ -32,7 +32,7 @@ using CbEnumSymbol = std::function<bool(const SymbolInfo &)>;
|
|||
class SymbolSourceBase
|
||||
{
|
||||
private:
|
||||
std::vector<uint8_t> _symbolBitmap;
|
||||
std::vector<uint8_t> _symbolBitmap; // TODO: what is the maximum size for this?
|
||||
|
||||
public:
|
||||
virtual ~SymbolSourceBase() = default;
|
||||
|
|
|
@ -35,14 +35,14 @@ static void SetThreadDescription(std::thread & thread, WString name)
|
|||
fp(handle, name.c_str());
|
||||
}
|
||||
|
||||
bool SymbolSourceDIA::loadPDB(const std::string & path, duint imageBase, duint imageSize)
|
||||
bool SymbolSourceDIA::loadPDB(const std::string & path, duint imageBase, duint imageSize, DiaValidationData_t* validationData)
|
||||
{
|
||||
if(!PDBDiaFile::initLibrary())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = _pdb.open(path.c_str());
|
||||
bool res = _pdb.open(path.c_str(), 0, validationData);
|
||||
#if 1 // Async loading.
|
||||
if(res)
|
||||
{
|
||||
|
@ -195,7 +195,7 @@ bool SymbolSourceDIA::loadSymbolsAsync(String path)
|
|||
DWORD64 ms = GetTickCount64() - loadStart;
|
||||
double secs = (double)ms / 1000.0;
|
||||
|
||||
dprintf("Loaded %d symbols in %.03f\n", _symAddrs.size(), secs);
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("Loaded %d symbols in %.03f\n", _symAddrs.size(), secs).c_str());
|
||||
|
||||
//TODO: make beautiful
|
||||
ListInfo blub;
|
||||
|
@ -225,7 +225,7 @@ bool SymbolSourceDIA::loadSourceLinesAsync(String path)
|
|||
return false;
|
||||
}
|
||||
|
||||
dprintf("Loading Source lines...\n");
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("Loading Source lines...\n").c_str());
|
||||
|
||||
DWORD64 lineLoadStart = GetTickCount64();
|
||||
|
||||
|
@ -291,7 +291,7 @@ bool SymbolSourceDIA::loadSourceLinesAsync(String path)
|
|||
DWORD64 ms = GetTickCount64() - lineLoadStart;
|
||||
double secs = (double)ms / 1000.0;
|
||||
|
||||
dprintf("Loaded %d line infos in %.03f\n", _lines.size(), secs);
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("Loaded %d line infos in %.03f\n", _lines.size(), secs).c_str());
|
||||
|
||||
GuiUpdateAllViews();
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ public:
|
|||
virtual bool findSymbolsByPrefix(const std::string & prefix, const std::function<bool(const SymbolInfo &)> & cbSymbol, bool caseSensitive) override;
|
||||
|
||||
public:
|
||||
bool loadPDB(const std::string & path, duint imageBase, duint imageSize);
|
||||
bool loadPDB(const std::string & path, duint imageBase, duint imageSize, DiaValidationData_t* validationData);
|
||||
|
||||
private:
|
||||
void loadPDBAsync();
|
||||
|
|
|
@ -147,7 +147,7 @@ void SymbolView::loadWindowSettings()
|
|||
void SymbolView::setModuleSymbols(duint base, const std::vector<void*> & symbols)
|
||||
{
|
||||
//TODO: reload actual symbol list, race conditions
|
||||
GuiAddLogMessage(QString("base: %1, count: %2\n").arg(ToPtrString(base)).arg(symbols.size()).toUtf8().constData());
|
||||
GuiSymbolLogAdd(QString("[SymbolView] base: %1, count: %2\n").arg(ToPtrString(base)).arg(symbols.size()).toUtf8().constData());
|
||||
mModuleSymbolMap[base] = symbols;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue