Files
archived-Reclass/src/symbolstore.cpp
IChooseYou 5d2d324946 fix: add missing symbol store and PDB debug info sources
These files were referenced in CMakeLists.txt and main.cpp but
never committed, breaking the CI build.
2026-03-14 08:13:58 -06:00

172 lines
5.3 KiB
C++

#include "symbolstore.h"
#include "providers/provider.h"
#include <QDebug>
namespace rcx {
uint64_t SymbolStore::getModuleBase(const Provider* provider, const QString& canonical) const {
if (!provider)
return 0;
uint64_t base = provider->symbolToAddress(canonical);
if (base == 0)
base = provider->symbolToAddress(canonical + QStringLiteral(".exe"));
if (base == 0)
base = provider->symbolToAddress(canonical + QStringLiteral(".dll"));
if (base == 0)
base = provider->symbolToAddress(canonical + QStringLiteral(".sys"));
return base;
}
int SymbolStore::addModule(const QString& moduleName, const QString& pdbPath,
const QVector<QPair<QString, uint32_t>>& symbols) {
QString canonical = resolveAlias(moduleName);
PdbSymbolSet set;
set.pdbPath = pdbPath;
set.moduleName = canonical;
set.nameToRva.reserve(symbols.size());
set.rvaToName.reserve(symbols.size());
for (const auto& sym : symbols) {
if (set.nameToRva.contains(sym.first))
continue;
set.nameToRva.insert(sym.first, sym.second);
set.rvaToName.append({sym.second, sym.first});
}
set.sortRvaIndex();
int count = set.nameToRva.size();
// Register the raw module name as an alias if it differs from canonical
QString rawLower = moduleName.toLower();
if (rawLower.endsWith(QStringLiteral(".exe")) || rawLower.endsWith(QStringLiteral(".dll")) ||
rawLower.endsWith(QStringLiteral(".sys")))
rawLower = rawLower.left(rawLower.lastIndexOf('.'));
if (rawLower != canonical)
m_aliases[rawLower] = canonical;
m_modules[canonical] = std::move(set);
qDebug() << "[SymbolStore] loaded" << count << "symbols for module" << canonical
<< "(from" << pdbPath << ")";
return count;
}
void SymbolStore::unloadModule(const QString& moduleName) {
QString canonical = resolveAlias(moduleName);
m_modules.remove(canonical);
}
uint64_t SymbolStore::resolve(const QString& token, const Provider* provider, bool* ok) const {
*ok = false;
// Check for "module!symbol" syntax
int bangIdx = token.indexOf('!');
if (bangIdx > 0 && bangIdx < token.size() - 1) {
QString modPart = token.left(bangIdx);
QString symPart = token.mid(bangIdx + 1);
QString canonical = resolveAlias(modPart);
auto modIt = m_modules.find(canonical);
if (modIt == m_modules.end())
return 0;
auto symIt = modIt->nameToRva.find(symPart);
if (symIt == modIt->nameToRva.end())
return 0;
uint32_t rva = *symIt;
uint64_t moduleBase = getModuleBase(provider, canonical);
// Also try the user-supplied module name form
if (moduleBase == 0)
moduleBase = getModuleBase(provider, modPart);
*ok = true;
return moduleBase + rva;
}
// Bare symbol — search all loaded modules
uint32_t foundRva = 0;
QString foundModule;
int matches = 0;
for (auto it = m_modules.begin(); it != m_modules.end(); ++it) {
auto symIt = it->nameToRva.find(token);
if (symIt != it->nameToRva.end()) {
foundRva = *symIt;
foundModule = it.key();
matches++;
if (matches > 1)
return 0; // ambiguous
}
}
if (matches == 1) {
uint64_t moduleBase = getModuleBase(provider, foundModule);
*ok = true;
return moduleBase + foundRva;
}
// Fallback: treat bare token as a module name (e.g. "ntdll" → ntdll base)
if (matches == 0) {
QString canonical = resolveAlias(token);
uint64_t moduleBase = getModuleBase(provider, canonical);
if (moduleBase != 0) {
*ok = true;
return moduleBase;
}
}
return 0;
}
QString SymbolStore::getSymbolForAddress(uint64_t addr, const Provider* provider) const {
if (m_modules.isEmpty() || !provider)
return {};
for (auto it = m_modules.begin(); it != m_modules.end(); ++it) {
const PdbSymbolSet& set = *it;
uint64_t moduleBase = getModuleBase(provider, set.moduleName);
if (moduleBase == 0)
continue;
if (addr < moduleBase)
continue;
uint32_t rva = static_cast<uint32_t>(addr - moduleBase);
if (set.rvaToName.isEmpty())
continue;
// Binary search: find last entry with RVA <= target
auto upper = std::upper_bound(set.rvaToName.begin(), set.rvaToName.end(), rva,
[](uint32_t val, const QPair<uint32_t, QString>& entry) {
return val < entry.first;
});
if (upper == set.rvaToName.begin())
continue;
--upper;
uint32_t displacement = rva - upper->first;
static constexpr uint32_t kMaxDisplacement = 0x1000;
if (displacement > kMaxDisplacement)
continue;
if (displacement == 0)
return set.moduleName + QStringLiteral("!") + upper->second;
return set.moduleName + QStringLiteral("!") + upper->second
+ QStringLiteral("+0x") + QString::number(displacement, 16);
}
return {};
}
void SymbolStore::addAlias(const QString& alias, const QString& canonicalModule) {
m_aliases[alias.toLower()] = canonicalModule.toLower();
}
} // namespace rcx