Skip to content
Permalink
Browse files

DBG: add symload command to manually load a PDB

  • Loading branch information...
mrexodia committed Jun 12, 2019
1 parent 4ce5b0b commit 1e075142a5983b05496ef0f2b7fe8648c957e8d0
@@ -188,6 +188,44 @@ bool cbDebugDownloadSymbol(int argc, char* argv[])
return true;
}

bool cbDebugLoadSymbol(int argc, char* argv[])
{
if(IsArgumentsLessThan(argc, 3))
return false;
//get some module information
duint modbase = ModBaseFromName(argv[1]);
if(!modbase)
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Invalid module \"%s\"!\n"), argv[1]);
return false;
}
auto pdbFile = argv[2];
if(!FileExists(pdbFile))
{
dputs(QT_TRANSLATE_NOOP("DBG", "File does not exist!"));
return false;
}
bool forceLoad = argc > 3 && DbgEval(argv[3]);
EXCLUSIVE_ACQUIRE(LockModules);
auto info = ModInfoFromAddr(modbase);
if(!info)
{
// TODO: this really isn't supposed to happen, but could if the module is suddenly unloaded
dputs("module not found...");
return false;
}

// trigger a symbol load
if(!info->loadSymbols(pdbFile, forceLoad))
{
dputs(QT_TRANSLATE_NOOP("DBG", "Symbol load failed... See symbol log for more information"));
return false;
}
GuiSymbolRefreshCurrent();
dputs(QT_TRANSLATE_NOOP("DBG", "Done! See symbol log for more information"));
return true;
}

bool cbInstrImageinfo(int argc, char* argv[])
{
duint address;
@@ -12,6 +12,7 @@ bool cbInstrAnalyseadv(int argc, char* argv[]);

bool cbInstrVirtualmod(int argc, char* argv[]);
bool cbDebugDownloadSymbol(int argc, char* argv[]);
bool cbDebugLoadSymbol(int argc, char* argv[]);
bool cbInstrImageinfo(int argc, char* argv[]);
bool cbInstrGetRelocSize(int argc, char* argv[]);
bool cbInstrExhandlers(int argc, char* argv[]);
@@ -832,8 +832,13 @@ bool ModLoad(duint Base, duint Size, const char* FullPath)
GetModuleInfo(info, (ULONG_PTR)data());
}

info.symbols = &EmptySymbolSource; // empty symbol source per default
// TODO: setting to auto load symbols
info.loadSymbols();
for(const auto & pdbPath : info.pdbPaths)
{
if(info.loadSymbols(pdbPath, bForceLoadSymbols))
break;
}

// Add module to list
EXCLUSIVE_ACQUIRE(LockModules);
@@ -1192,10 +1197,9 @@ bool ModRelocationsInRange(duint Address, duint Size, std::vector<MODRELOCATIONI
return !Relocations.empty();
}

bool MODINFO::loadSymbols()
bool MODINFO::loadSymbols(const String & pdbPath, bool forceLoad)
{
unloadSymbols();
symbols = &EmptySymbolSource; // empty symbol source per default

// Try DIA
if(symbols == &EmptySymbolSource && SymbolSourceDIA::isLibraryAvailable())
@@ -1208,32 +1212,29 @@ bool MODINFO::loadSymbols()
validationData.signature = pdbValidation.signature;
validationData.age = pdbValidation.age;
SymbolSourceDIA* symSource = new SymbolSourceDIA();
for(const auto & pdbPath : pdbPaths)
if(!FileExists(pdbPath.c_str()))
{
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, modname, base, size, bForceLoadSymbols ? nullptr : &validationData))
{
symSource->resizeSymbolBitmap(size);

symbols = symSource;
GuiSymbolLogAdd(StringUtils::sprintf("[DIA] Skipping non-existent PDB: %s\n", pdbPath.c_str()).c_str());
}
else if(symSource->loadPDB(pdbPath, modname, base, size, forceLoad ? nullptr : &validationData))
{
symSource->resizeSymbolBitmap(size);

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());
symbols = symSource;

return true;
}
std::string msg;
if(symSource->isLoading())
msg = StringUtils::sprintf("[DIA] Loading PDB (async): %s\n", pdbPath.c_str());
else
{
// TODO: more detailled error codes?
GuiSymbolLogAdd(StringUtils::sprintf("[DIA] Failed to load PDB: %s\n", pdbPath.c_str()).c_str());
}
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;
}
@@ -129,7 +129,7 @@ struct MODINFO
GuiInvalidateSymbolSource(base);
}

bool loadSymbols();
bool loadSymbols(const String & pdbPath, bool forceLoad);
void unloadSymbols();
void unmapFile();
const MODEXPORT* findExport(duint rva) const;
@@ -274,7 +274,7 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa

if(validationData != nullptr)
{
CComPtr<IDiaSymbol> globalSym;
IDiaSymbol* globalSym = nullptr;
hr = m_session->get_globalScope(&globalSym);
if(testError(hr))
{
@@ -286,9 +286,10 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
hr = globalSym->get_age(&age);
if(!testError(hr) && validationData->age != age)
{
globalSym->Release();
close();

GuiSymbolLogAdd("PDB age is not matching.\n");
GuiSymbolLogAdd(StringUtils::sprintf("Validation error: PDB age is not matching (expected: %u, actual: %u).\n", validationData->age, age).c_str());
return false;
}

@@ -310,12 +311,28 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
hr = globalSym->get_guid(&guid);
if(!testError(hr) && memcmp(&guid, &validationData->guid, sizeof(GUID)) != 0)
{
globalSym->Release();
close();

GuiSymbolLogAdd("PDB guid is not matching.\n");
auto guidStr = [](const GUID & guid) -> String
{
// https://stackoverflow.com/a/22848342/1806760
char guid_string[37]; // 32 hex chars + 4 hyphens + null terminator
sprintf_s(guid_string,
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2],
guid.Data4[3], guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
return guid_string;
};

GuiSymbolLogAdd(StringUtils::sprintf("Validation error: PDB guid is not matching (expected: %s, actual: %s).\n",
guidStr(validationData->guid).c_str(), guidStr(guid).c_str()).c_str());
return false;
}
}
globalSym->Release();
}
else
{
@@ -513,7 +513,7 @@ String StringUtils::ToHex(unsigned long long value)

#define HEXLOOKUP "0123456789ABCDEF"

String StringUtils::ToHex(unsigned char* buffer, size_t size, bool reverse)
String StringUtils::ToHex(const unsigned char* buffer, size_t size, bool reverse)
{
String result;
result.resize(size * 2);
@@ -526,7 +526,7 @@ String StringUtils::ToHex(unsigned char* buffer, size_t size, bool reverse)
return result;
}

String StringUtils::ToCompressedHex(unsigned char* buffer, size_t size)
String StringUtils::ToCompressedHex(const unsigned char* buffer, size_t size)
{
if(!size)
return "";
@@ -42,8 +42,8 @@ class StringUtils
static bool EndsWith(const String & str, const String & suffix);
static bool FromHex(const String & text, std::vector<unsigned char> & data, bool reverse = false);
static String ToHex(unsigned long long value);
static String ToHex(unsigned char* buffer, size_t size, bool reverse = false);
static String ToCompressedHex(unsigned char* buffer, size_t size);
static String ToHex(const unsigned char* buffer, size_t size, bool reverse = false);
static String ToCompressedHex(const unsigned char* buffer, size_t size);
static bool FromCompressedHex(const String & text, std::vector<unsigned char> & data);

template<typename T>
@@ -243,20 +243,8 @@ bool SymDownloadSymbol(duint Base, const char* SymbolStore)
return false;
}

// insert the downloaded symbol path in the beginning of the PDB load order
auto destPathUtf8 = StringUtils::Utf16ToUtf8(destinationPath);
for(auto it = info->pdbPaths.begin(); it != info->pdbPaths.end(); ++it)
{
if(*it == destPathUtf8)
{
info->pdbPaths.erase(it);
break;
}
}
info->pdbPaths.insert(info->pdbPaths.begin(), destPathUtf8);

// trigger a symbol load
info->loadSymbols();
info->loadSymbols(StringUtils::Utf16ToUtf8(destinationPath), bForceLoadSymbols);
}

return true;
@@ -324,6 +324,7 @@ static void registercommands()

dbgcmdnew("virtualmod", cbInstrVirtualmod, true); //virtual module
dbgcmdnew("symdownload,downloadsym", cbDebugDownloadSymbol, true); //download symbols
dbgcmdnew("symload,loadsym", cbDebugLoadSymbol, true); //load symbols
dbgcmdnew("imageinfo,modimageinfo", cbInstrImageinfo, true); //print module image information
dbgcmdnew("GetRelocSize,grs", cbInstrGetRelocSize, true); //get relocation table size
dbgcmdnew("exhandlers", cbInstrExhandlers, true); //enumerate exception handlers

0 comments on commit 1e07514

Please sign in to comment.
You can’t perform that action at this time.