1
0
Fork 0

Load symbols and source line in parallel.

This commit is contained in:
ZehMatt 2017-12-18 20:42:29 +01:00 committed by Duncan Ogilvie
parent 7c6bfcd2c6
commit bd08f67f47
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
4 changed files with 137 additions and 94 deletions

View File

@ -286,7 +286,7 @@ bool ModLoad(duint Base, duint Size, const char* FullPath)
SymbolSourcePDB::isLibraryAvailable())
{
SymbolSourcePDB* symSource = new SymbolSourcePDB();
if(symSource->loadPDB(info.path, Base))
if(symSource->loadPDB(info.path, Base, info.size))
{
symSource->resizeSymbolBitmap(info.size);

View File

@ -50,6 +50,8 @@ PDBDiaFile::PDBDiaFile() :
PDBDiaFile::~PDBDiaFile()
{
if(isOpen())
close();
}
bool PDBDiaFile::initLibrary()

View File

@ -3,15 +3,15 @@
#include "debugger.h"
SymbolSourcePDB::SymbolSourcePDB()
: _isLoading(false),
_requiresShutdown(false),
_imageBase(0)
: _requiresShutdown(false),
_imageBase(0),
_loadCounter(0)
{
}
SymbolSourcePDB::~SymbolSourcePDB()
{
if(_isLoading || _loadThread.joinable())
if(isLoading() || _symbolsThread.joinable() || _sourceLinesThread.joinable())
{
cancelLoading();
}
@ -22,7 +22,7 @@ SymbolSourcePDB::~SymbolSourcePDB()
}
}
bool SymbolSourcePDB::loadPDB(const std::string & path, duint imageBase)
bool SymbolSourcePDB::loadPDB(const std::string & path, duint imageBase, duint imageSize)
{
if(!PDBDiaFile::initLibrary())
{
@ -33,11 +33,12 @@ bool SymbolSourcePDB::loadPDB(const std::string & path, duint imageBase)
#if 1 // Async loading.
if(res)
{
_imageSize = imageSize;
_imageBase = imageBase;
_isLoading = true;
_requiresShutdown = false;
_loadStart = GetTickCount64();
_loadThread = std::thread(&SymbolSourcePDB::loadPDBAsync, this);
_loadCounter.store(2);
_symbolsThread = std::thread(&SymbolSourcePDB::loadSymbolsAsync, this, path);
_sourceLinesThread = std::thread(&SymbolSourcePDB::loadSourceLinesAsync, this, path);
}
#endif
return res;
@ -50,26 +51,43 @@ bool SymbolSourcePDB::isOpen() const
bool SymbolSourcePDB::isLoading() const
{
return _isLoading;
return _loadCounter > 0;
}
bool SymbolSourcePDB::cancelLoading()
{
if(_isLoading || _loadThread.joinable())
_requiresShutdown.store(true);
while(_loadCounter > 0)
{
_requiresShutdown.store(true);
_loadThread.join();
}
else
{
return false;
Sleep(1);
}
if(_symbolsThread.joinable())
_symbolsThread.join();
if(_sourceLinesThread.joinable())
_sourceLinesThread.join();
return true;
}
void SymbolSourcePDB::loadPDBAsync()
{
}
bool SymbolSourcePDB::loadSymbolsAsync(String path)
{
ScopedDecrement ref(_loadCounter);
PDBDiaFile pdb;
if(!pdb.open(path.c_str()))
{
return false;
}
DWORD lastUpdate = 0;
DWORD loadStart = GetTickCount64();
bool res = _pdb.enumerateLexicalHierarchy([&](DiaSymbol_t & sym)->bool
{
@ -89,7 +107,7 @@ void SymbolSourcePDB::loadPDBAsync()
symInfo.addr = sym.virtualAddress;
symInfo.publicSymbol = sym.publicSymbol;
_lock.lock();
_lockSymbols.lock();
// Check if we already have it inside, private symbols have priority over public symbols.
auto it = _sym.find(symInfo.addr);
@ -106,7 +124,7 @@ void SymbolSourcePDB::loadPDBAsync()
_sym.insert(std::make_pair(symInfo.addr, symInfo));
}
_lock.unlock();
_lockSymbols.unlock();
DWORD curTick = GetTickCount();
if(curTick - lastUpdate > 500)
@ -119,22 +137,89 @@ void SymbolSourcePDB::loadPDBAsync()
return true;
}, true);
_isLoading = false;
if(!res)
return;
{
return false;
}
DWORD64 ms = GetTickCount64() - _loadStart;
DWORD64 ms = GetTickCount64() - loadStart;
double secs = (double)ms / 1000.0;
dprintf("Loaded %d symbols in %.03f\n", _sym.size(), secs);
GuiUpdateAllViews();
return true;
}
bool SymbolSourcePDB::loadSourceLinesAsync(String path)
{
ScopedDecrement ref(_loadCounter);
PDBDiaFile pdb;
if(!pdb.open(path.c_str()))
{
return false;
}
dprintf("Loading Source lines...\n");
DWORD64 lineLoadStart = GetTickCount64();
const size_t rangeSize = 1024 * 1024;
for(duint rva = 0; rva < _imageSize; rva += rangeSize)
{
if(_requiresShutdown)
return false;
std::map<uint64_t, DiaLineInfo_t> lines;
bool res = _pdb.getFunctionLineNumbers(rva, rangeSize, _imageBase, lines);
for(const auto & line : lines)
{
if(_requiresShutdown)
return false;
const auto & info = line.second;
auto it = _lines.find(info.virtualAddress);
if(it != _lines.end())
continue;
LineInfo lineInfo;
lineInfo.addr = info.virtualAddress;
lineInfo.disp = 0;
lineInfo.lineNumber = info.lineNumber;
lineInfo.sourceFile = info.fileName;
_lockLines.lock();
_lines.insert(std::make_pair(lineInfo.addr, lineInfo));
_lockLines.unlock();
}
}
if(_requiresShutdown)
return false;
DWORD64 ms = GetTickCount64() - lineLoadStart;
double secs = (double)ms / 1000.0;
dprintf("Loaded %d line infos in %.03f\n", _lines.size(), secs);
GuiUpdateAllViews();
return true;
}
bool SymbolSourcePDB::findSymbolExact(duint rva, SymbolInfo & symInfo)
{
ScopedSpinLock lock(_lock);
ScopedSpinLock lock(_lockSymbols);
if(SymbolSourceBase::isAddressInvalid(rva))
return false;
@ -145,25 +230,9 @@ bool SymbolSourcePDB::findSymbolExact(duint rva, SymbolInfo & symInfo)
symInfo = (*it).second;
return true;
}
/*
DiaSymbol_t sym;
if (_pdb.findSymbolRVA(rva, sym) && sym.disp == 0)
{
symInfo.addr = rva;
symInfo.disp = 0;
symInfo.size = sym.size;
symInfo.decoratedName = sym.undecoratedName;
symInfo.undecoratedName = sym.undecoratedName;
symInfo.valid = true;
_symbols.insert(rva, symInfo);
return true;
}
*/
#if 1
if(_isLoading == false)
if(isLoading() == false)
markAdressInvalid(rva);
#endif
@ -188,7 +257,7 @@ typename A::iterator findExactOrLower(A & ctr, const B key)
bool SymbolSourcePDB::findSymbolExactOrLower(duint rva, SymbolInfo & symInfo)
{
ScopedSpinLock lock(_lock);
ScopedSpinLock lock(_lockSymbols);
auto it = findExactOrLower(_sym, rva);
if(it != _sym.end())
@ -198,27 +267,12 @@ bool SymbolSourcePDB::findSymbolExactOrLower(duint rva, SymbolInfo & symInfo)
return true;
}
/*
DiaSymbol_t sym;
if (_pdb.findSymbolRVA(rva, sym))
{
symInfo.addr = rva;
symInfo.disp = sym.disp;
symInfo.size = sym.size;
symInfo.decoratedName = sym.undecoratedName;
symInfo.undecoratedName = sym.undecoratedName;
symInfo.valid = true;
return true;
}
*/
return nullptr;
}
void SymbolSourcePDB::enumSymbols(const CbEnumSymbol & cbEnum)
{
ScopedSpinLock lock(_lock);
ScopedSpinLock lock(_lockSymbols);
for(auto & it : _sym)
{
@ -235,36 +289,12 @@ bool SymbolSourcePDB::findSourceLineInfo(duint rva, LineInfo & lineInfo)
if(isOpen() == false)
return false;
std::map<uint64_t, DiaLineInfo_t> lines;
ScopedSpinLock lock(_lockLines);
bool res = false;
bool requiresLock = isLoading();
if(requiresLock)
_lock.lock();
res = _pdb.getFunctionLineNumbers(rva, 1, 0, lines);
if(requiresLock)
_lock.unlock();
if(!res)
return res;
if(lines.empty())
auto it = _lines.find(rva);
if(it == _lines.end())
return false;
// Unhandled case, requires refactoring to query ranges instead of single lines.
if(lines.size() > 1)
{
return false;
}
const auto & info = (*lines.begin()).second;
lineInfo.addr = info.virtualAddress;
lineInfo.sourceFile = info.fileName;
lineInfo.lineNumber = info.lineNumber;
lineInfo.disp = rva - info.virtualAddress;
lineInfo = it->second;
return true;
}

View File

@ -37,18 +37,27 @@ public:
class SymbolSourcePDB : public SymbolSourceBase
{
struct ScopedDecrement
{
private:
std::atomic<duint> & _counter;
public:
ScopedDecrement(std::atomic<duint> & counter) : _counter(counter) {}
~ScopedDecrement() { _counter--; }
};
private:
PDBDiaFile _pdb;
SortedLRU<duint, SymbolInfo> _symbols;
std::map<duint, SymbolInfo> _sym;
std::thread _loadThread;
std::atomic<bool> _isLoading;
std::map<duint, LineInfo> _lines;
std::thread _symbolsThread;
std::thread _sourceLinesThread;
std::atomic<bool> _requiresShutdown;
std::atomic_flag _isWriting;
std::atomic<duint> _loadCounter;
duint _imageBase;
SpinLock _lock;
DWORD64 _loadStart;
std::atomic_flag _locked;
duint _imageSize;
SpinLock _lockSymbols;
SpinLock _lockLines;
public:
static bool isLibraryAvailable()
@ -76,10 +85,12 @@ public:
virtual bool findSourceLineInfo(duint rva, LineInfo & lineInfo) override;
public:
bool loadPDB(const std::string & path, duint imageBase);
bool loadPDB(const std::string & path, duint imageBase, duint imageSize);
private:
void loadPDBAsync();
bool loadSymbolsAsync(String path);
bool loadSourceLinesAsync(String path);
};
#endif // _SYMBOLSOURCEPDB_H_