feat: extract typeIndex from PDB symbols and add symbols.importType MCP tool

extractPdbSymbols() was reading S_GDATA32/S_GTHREAD32 records which
contain a typeIndex field linking the symbol to its type definition in
the TPI stream, but this field was discarded — only name + RVA were
kept. This meant loading symbols gave you address resolution but no
way to automatically import the type associated with a global variable.

Changes:
- PdbSymbol now carries typeIndex (0 = no type info / public symbol)
- extractPdbSymbols() captures typeIndex from all global data symbols
- PdbSymbolSet stores nameToTypeIndex mapping alongside nameToRva
- New importTypeForSymbol() follows LF_POINTER/LF_MODIFIER chains to
  find the underlying UDT/enum and imports it with full recursive children
- New symbols.importType MCP tool: given "ntdll!g_pShimEngineModule",
  resolves its typeIndex, imports the type definition from the PDB, and
  merges it into the active project
- loadPdbIntoStore() helper consolidates the extract+store pattern with
  type index support
This commit is contained in:
IChooseYou
2026-03-14 18:11:57 -06:00
committed by IChooseYou
parent cb10bc8a82
commit dc6963e0d5
8 changed files with 643 additions and 26 deletions

View File

@@ -1025,8 +1025,8 @@ protected:
const double r = 0.75, s = 3.0;
double cx = width() / 2.0;
double cy = height() / 2.0;
// 2 columns x 3 rows, centered
for (int row = -1; row <= 1; row++) {
// 2 columns x 4 rows, centered
for (int row = -2; row <= 1; row++) {
p.drawEllipse(QPointF(cx - s * 0.5, cy + row * s), r, r);
p.drawEllipse(QPointF(cx + s * 0.5, cy + row * s), r, r);
}
@@ -4776,6 +4776,8 @@ void MainWindow::createSymbolsDock() {
m_symDownloadBtn = new QToolButton(titleBar);
m_symDownloadBtn->setIcon(QIcon(QStringLiteral(":/vsicons/cloud-download.svg")));
m_symDownloadBtn->setIconSize(QSize(14, 14));
m_symDownloadBtn->setText(QStringLiteral("Download All"));
m_symDownloadBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
m_symDownloadBtn->setAutoRaise(true);
m_symDownloadBtn->setCursor(Qt::PointingHandCursor);
m_symDownloadBtn->setToolTip(QStringLiteral("Load/Download all symbols"));
@@ -4892,17 +4894,10 @@ void MainWindow::createSymbolsDock() {
return;
}
// Helper to load a PDB file into the symbol store
// Helper to load a PDB file into the symbol store (with type indices)
auto loadPdb = [this, name](const QString& pdbPath) -> bool {
QString symErr;
auto result = rcx::extractPdbSymbols(pdbPath, &symErr);
if (result.symbols.isEmpty()) return false;
QVector<QPair<QString, uint32_t>> pairs;
pairs.reserve(result.symbols.size());
for (const auto& s : result.symbols)
pairs.emplaceBack(s.name, s.rva);
int count = rcx::SymbolStore::instance().addModule(
result.moduleName, pdbPath, pairs);
int count = loadPdbIntoStore(pdbPath);
if (count <= 0) return false;
setAppStatus(QStringLiteral("Loaded %1 symbols for %2").arg(count).arg(name));
rebuildSymbolsModel();
if (auto* c = activeController()) c->refresh();
@@ -5341,6 +5336,28 @@ void MainWindow::createSymbolsDock() {
}
}
int MainWindow::loadPdbIntoStore(const QString& pdbPath) {
QString symErr;
auto result = rcx::extractPdbSymbols(pdbPath, &symErr);
if (result.symbols.isEmpty()) return 0;
QVector<QPair<QString, uint32_t>> pairs;
QHash<QString, uint32_t> typeIndices;
pairs.reserve(result.symbols.size());
for (const auto& s : result.symbols) {
pairs.emplaceBack(s.name, s.rva);
if (s.typeIndex != 0)
typeIndices.insert(s.name, s.typeIndex);
}
int count = rcx::SymbolStore::instance().addModule(
result.moduleName, pdbPath, pairs);
if (!typeIndices.isEmpty())
rcx::SymbolStore::instance().addModuleTypeIndices(
result.moduleName, typeIndices);
return count;
}
void MainWindow::rebuildSymbolsModel() {
if (!m_symbolsModel) return;
m_symbolsModel->clear();