1
0
Fork 0

DBG: initial implementation of name-sorted symbol storage

This commit is contained in:
Duncan Ogilvie 2017-12-22 03:16:28 +01:00
parent eb9d55ac61
commit c7d0f50207
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
4 changed files with 185 additions and 23 deletions

View File

@ -1475,13 +1475,13 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
case DBG_GET_SYMBOL_INFO:
{
//hack^2
//TODO: hack^2
auto real = (SymbolInfo*)param1;
auto fake = (SYMBOLINFO*)param2;
fake->addr = real->addr;
fake->decoratedSymbol = (char*)real->decoratedName.c_str();
fake->undecoratedSymbol = (char*)real->undecoratedName.c_str();
fake->isImported = strncmp(fake->decoratedSymbol, "__imp_", 6) == 0;
fake->isImported = strncmp(fake->decoratedSymbol, "__imp_", 6) == 0; //TODO: properly handle this
}
break;
}

View File

@ -99,6 +99,16 @@ public:
{
return false; // Stub
}
virtual bool findSymbolByName(const std::string & name, SymbolInfo & symInfo, bool caseSensitive)
{
return false; // Stub
}
virtual bool findSymbolsByPrefix(const std::string & prefix, std::vector<SymbolInfo> & symbols, bool caseSensitive)
{
return false; // Stub
}
};
static SymbolSourceBase EmptySymbolSource;

View File

@ -1,6 +1,7 @@
#include "symbolsourcepdb.h"
#include "console.h"
#include "debugger.h"
#include <algorithm>
SymbolSourcePDB::SymbolSourcePDB()
: _requiresShutdown(false),
@ -89,6 +90,37 @@ void SymbolSourcePDB::loadPDBAsync()
{
}
inline int mystricmp(const char* s1, const char* s2)
{
unsigned char c1, c2;
while((c1 = tolower(*s1++)) == (c2 = tolower(*s2++)))
if(c1 == '\0')
return 0;
return c1 - c2;
}
inline int hackicmp(const char* s1, const char* s2)
{
unsigned char c1, c2;
while((c1 = *s1++) == (c2 = *s2++))
if(c1 == '\0')
return 0;
return mystricmp(s1 - 1, s2 - 1);
}
struct HackCmp
{
bool operator()(const SymbolInfo & a, const SymbolInfo & b)
{
return cmp(a, b, false) < 0;
}
int cmp(const SymbolInfo & a, const SymbolInfo & b, bool caseSensitive)
{
return (caseSensitive ? strcmp : hackicmp)(a.decoratedName.c_str(), b.decoratedName.c_str());
}
};
bool SymbolSourcePDB::loadSymbolsAsync(String path)
{
ScopedDecrement ref(_loadCounter);
@ -114,7 +146,7 @@ bool SymbolSourcePDB::loadSymbolsAsync(String path)
if(sym.type == DiaSymbolType::PUBLIC ||
sym.type == DiaSymbolType::FUNCTION ||
sym.type == DiaSymbolType::LABEL ||
sym.type == DiaSymbolType::DATA)
sym.type == DiaSymbolType::DATA) //TODO: properly handle import thunks + empty names + line symbols
{
SymbolInfo symInfo;
symInfo.decoratedName = sym.name;
@ -123,26 +155,28 @@ bool SymbolSourcePDB::loadSymbolsAsync(String path)
symInfo.disp = sym.disp;
symInfo.addr = sym.virtualAddress;
symInfo.publicSymbol = sym.publicSymbol;
_symNames.push_back(symInfo);
// Check if we already have it inside, private symbols have priority over public symbols.
{
ScopedSpinLock lock(_lockSymbols);
auto it = _sym.find(symInfo.addr);
if(it != _sym.end())
auto it = _symAddrs.find(symInfo.addr);
if(it != _symAddrs.end())
{
if(it->second.publicSymbol == true && symInfo.publicSymbol == false)
if(_symNames[it->second].publicSymbol == true && symInfo.publicSymbol == false)
{
// Replace.
it->second = symInfo;
it->second = _symNames.size() - 1;
}
}
else
{
_sym.insert(std::make_pair(symInfo.addr, symInfo));
_symAddrs.insert({ symInfo.addr, _symNames.size() - 1 });
}
}
//TODO: perhaps this shouldn't be done...
DWORD curTick = GetTickCount();
if(curTick - lastUpdate > 500)
{
@ -161,19 +195,49 @@ bool SymbolSourcePDB::loadSymbolsAsync(String path)
return false;
}
//TODO: gracefully handle temporary storage (the spin lock will now starve the GUI while sorting)
{
ScopedSpinLock lock(_lockSymbols);
//handle symbol sorting
std::sort(_symNames.begin(), _symNames.end(), HackCmp());
_symAddrs.clear();
for(size_t i = 0; i < _symNames.size(); i++)
{
auto & symInfo = _symNames.at(i);
// Check if we already have it inside, private symbols have priority over public symbols.
auto it = _symAddrs.find(symInfo.addr);
if(it != _symAddrs.end())
{
if(_symNames[it->second].publicSymbol == true && symInfo.publicSymbol == false)
{
// Replace.
it->second = i;
}
}
else
{
_symAddrs.insert({ symInfo.addr, i });
}
}
}
DWORD64 ms = GetTickCount64() - loadStart;
double secs = (double)ms / 1000.0;
dprintf("Loaded %d symbols in %.03f\n", _sym.size(), secs);
dprintf("Loaded %d symbols in %.03f\n", _symAddrs.size(), secs);
//TODO: make beautiful
ListInfo blub;
blub.count = _sym.size();
blub.count = _symAddrs.size();
blub.size = blub.count * sizeof(void*);
std::vector<SymbolInfo*> fuck;
fuck.resize(_sym.size());
fuck.resize(_symAddrs.size());
size_t i = 0;
for(auto it = _sym.begin(); it != _sym.end(); ++it)
fuck[i++] = &it->second;
for(auto it = _symAddrs.begin(); it != _symAddrs.end(); ++it)
fuck[i++] = &_symNames[it->second];
blub.data = fuck.data();
GuiSetModuleSymbols(_imageBase, &blub);
@ -273,10 +337,10 @@ bool SymbolSourcePDB::findSymbolExact(duint rva, SymbolInfo & symInfo)
if(SymbolSourceBase::isAddressInvalid(rva))
return false;
auto it = _sym.find(rva);
if(it != _sym.end())
auto it = _symAddrs.find(rva);
if(it != _symAddrs.end())
{
symInfo = (*it).second;
symInfo = _symNames[(*it).second];
return true;
}
@ -308,10 +372,10 @@ bool SymbolSourcePDB::findSymbolExactOrLower(duint rva, SymbolInfo & symInfo)
{
ScopedSpinLock lock(_lockSymbols);
auto it = findExactOrLower(_sym, rva);
if(it != _sym.end())
auto it = findExactOrLower(_symAddrs, rva);
if(it != _symAddrs.end())
{
symInfo = (*it).second;
symInfo = _symNames[(*it).second];
symInfo.disp = (int32_t)(rva - symInfo.addr);
return true;
}
@ -323,9 +387,9 @@ void SymbolSourcePDB::enumSymbols(const CbEnumSymbol & cbEnum)
{
ScopedSpinLock lock(_lockSymbols);
for(auto & it : _sym)
for(auto & it : _symAddrs)
{
const SymbolInfo & sym = it.second;
const SymbolInfo & sym = _symNames[it.second];
if(!cbEnum(sym))
{
break;
@ -352,4 +416,82 @@ bool SymbolSourcePDB::findSourceLineInfo(duint rva, LineInfo & lineInfo)
}
return false;
}
}
//http://en.cppreference.com/w/cpp/algorithm/lower_bound
template<class ForwardIt, class T, class Compare = std::less<>>
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T & value, Compare comp = {})
{
// Note: BOTH type T and the type after ForwardIt is dereferenced
// must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
// This is stricter than lower_bound requirement (see above)
first = std::lower_bound(first, last, value, comp);
return first != last && !comp(value, *first) ? first : last;
}
bool SymbolSourcePDB::findSymbolByName(const std::string & name, SymbolInfo & symInfo, bool caseSensitive)
{
HackCmp hackCmp;
ScopedSpinLock lock(_lockSymbols);
SymbolInfo find;
find.decoratedName = name;
auto found = binary_find(_symNames.begin(), _symNames.end(), find, hackCmp);
if(found != _symNames.end())
{
do
{
if(hackCmp.cmp(*found, find, caseSensitive) == 0)
{
symInfo = *found;
return true;
}
++found;
}
while(found != _symNames.end() && hackCmp.cmp(find, *found, false) == 0);
}
return false;
}
bool SymbolSourcePDB::findSymbolsByPrefix(const std::string & prefix, std::vector<SymbolInfo> & symbols, bool caseSensitive)
{
struct PrefixCmp
{
PrefixCmp(size_t n) : n(n) { }
bool operator()(const SymbolInfo & a, const SymbolInfo & b)
{
return cmp(a, b, false) < 0;
}
int cmp(const SymbolInfo & a, const SymbolInfo & b, bool caseSensitive)
{
return (caseSensitive ? strncmp : _strnicmp)(a.decoratedName.c_str(), b.decoratedName.c_str(), n);
}
private:
size_t n;
} prefixCmp(prefix.size());
ScopedSpinLock lock(_lockSymbols);
SymbolInfo find;
find.decoratedName = prefix;
auto found = binary_find(_symNames.begin(), _symNames.end(), find, prefixCmp);
if(found == _symNames.end())
return false;
bool result = false;
for(; found != _symNames.end() && prefixCmp.cmp(find, *found, false); ++found)
{
if(!caseSensitive || prefixCmp.cmp(find, *found, true))
{
symbols.push_back(*found);
result = true;
}
}
return result;
}

View File

@ -55,7 +55,13 @@ class SymbolSourcePDB : public SymbolSourceBase
private:
PDBDiaFile _pdb;
std::map<duint, SymbolInfo> _sym;
//All the symbol data, sorted by name
std::vector<SymbolInfo> _symNames;
//Symbol addresses to index in _symNames (TODO: refactor to std::vector)
std::map<duint, size_t> _symAddrs;
//std::map<duint, SymbolInfo> _sym;
std::map<duint, CachedLineInfo> _lines;
std::thread _symbolsThread;
std::thread _sourceLinesThread;
@ -92,6 +98,10 @@ public:
virtual bool findSourceLineInfo(duint rva, LineInfo & lineInfo) override;
virtual bool findSymbolByName(const std::string & name, SymbolInfo & symInfo, bool caseSensitive) override;
virtual bool findSymbolsByPrefix(const std::string & prefix, std::vector<SymbolInfo> & symbols, bool caseSensitive) override;
public:
bool loadPDB(const std::string & path, duint imageBase, duint imageSize);