[PR #2275] [MERGED] fix(ghidra): disclose missing PDB symbol coverage #5132

Closed
opened 2026-10-31 01:04:13 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2275
Author: @hifzabuildsai
Created: 10/12/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @morluto

Base: main ← Head: fix/ghidra-pdb-coverage


📝 Commits (5)

  • 5890b2a fix(ghidra): disclose missing PDB symbol coverage
  • a6df916 fix(ghidra): reconcile provider docs and cover missing PDB reports
  • 63deb71 chore: merge latest main after source review
  • 6fc0e13 style: format reviewed source changes
  • c84ced1 fix(ghidra): bound PDB handshake and retain coverage uncertainty

📊 Changes

9 files changed (+391 additions, -7 deletions)

View changed files

📝 bridge/ghidra/ReaGhidraBridge.java (+40 -0)
📝 docs/ghidra-provider.md (+20 -0)
📝 src/ghidra/GhidraAnalysisProfile.ts (+3 -0)
📝 src/ghidra/GhidraProvider.behavior.test.ts (+107 -0)
📝 src/ghidra/GhidraProviderClient.ts (+21 -5)
📝 src/ghidra/GhidraSessionValues.test.ts (+43 -0)
📝 src/ghidra/GhidraSessionValues.ts (+71 -0)
📝 tests/boundary/mcp/ghidraInventoryMcp.test.ts (+76 -0)
📝 tests/boundary/mcp/ghidraMcpHarness.ts (+10 -2)

📄 Description

Problem

Refs #2259. A PE's CodeView metadata can reference a PDB that Ghidra did not load. REA's private executable import omits the sibling PDB, but successful analysis Evidence does not disclose missing symbol coverage. An empty name search can therefore look complete without explaining why original names are unavailable.

Change

  • Report Ghidra's post-analysis PDB Program Information attributes in the authenticated handshake: file, GUID, hexadecimal age, legacy signature, version, and nullable loaded state. Preserve source strings and absent attributes.
  • Carry a limitation into PE health, inventory, search, and function observations when referenced symbols are not loaded or their load state is unknown. Include identity and an address-based next probe. A missing bridge report remains unknown.
  • Read the established handshake before direct PE calls; the client reuses its existing startup promise rather than launching another engine. Rename the shared handshake projection to reflect its broader ownership.
  • Add pdb_observations: program-info-v1 to PE analysis profiles so snapshots produced before this reporting change have a different identity.
  • Document the symbol-coverage boundary. A reported loaded flag does not independently prove a matching PDB identity or complete symbols. The change does not copy PDBs, contact symbol servers, change analyzers, or add mutation authority.

Validation

Published commit 5890b2a076127dd2801e8aa781928d7106a766e9 has the exact validated tree f5d14d3dc7b10ab1be8971f882ae05002318af52 of local commit 23b6b11176fefa9c94ffb16881d7feed5eef332a, based on upstream 11fe5a13f8aee87d0c0e036a9f497407e085fe48. Linux x64, repository-pinned Node 24.18.0 and npm 11.16.0:

  • npm run test:focused -- src/ghidra/GhidraSessionValues.test.ts src/ghidra/GhidraProvider.behavior.test.ts src/ghidra/GhidraInventoryValues.test.ts tests/boundary/mcp/ghidraInventoryMcp.test.ts — 4 suites, 85 tests passed.
  • npm run check — passed: runtime compilation, typecheck, formatting, lint (0 errors; warnings reported), knip, metadata, resolved module boundaries, architecture guards.
  • npm run docs:check — passed, including both README consistency tests.
  • npm run verify:test-discovery — all 950 test files discovered exactly once.
  • git diff --check — passed.

The regressions first failed on the original source: the handshake rejected PDB facts and direct searches skipped the handshake projection. After the change they pass. Public MCP testing uses the actual provider/service/server pipeline with synthetic bridge facts, a generated PE fixture, retained Evidence, and function snapshot replay. It does not establish behavior of an installed Ghidra engine.

The Java APIs and attribute meanings were checked against Ghidra 12.1.4 source:
PdbParserConstants and PdbProgramAttributes.

Remaining verification — draft

Real producer verification (2026-10-12)

Ghidra 12.1.4 and Temurin JDK 21.0.12.1+1 were downloaded from official GitHub releases, and both published SHA-256 digests matched. All packaged Java bridge sources compiled against the installed Ghidra jars.

On Linux x64, Clang/LLD 18.1.8 cross-compiled a small self-owned C fixture to x86_64-pc-windows-msvc PE32+ with a matching PDB and a relative CodeView PDB path. This is a Linux-host PE/PDB producer check, not Windows/MSVC-host verification.

  • Executable SHA-256: 3828e3c48d2670453cd054837a9a44f2ad91d95895013460de83eb82c6a89a6c.
  • PDB GUID: 7047ef95-97c7-9e00-4c4c-44205044422e; hexadecimal age 1.
  • With the sidecar, actual headless Ghidra loaded the PDB and recovered add_numbers and main. Calling the compiled production bridge's pdbObservation against this Program returned loaded: true; the production TypeScript limitation projection returned no missing-PDB warning.
  • An identical executable copied to a directory without the PDB produced FUN_140001000 and entry. Ghidra omitted the PDB Loaded attribute. The production bridge preserved that omission as loaded: null; the TypeScript projection reported the referenced file/GUID/age and unknown load state. It did not manufacture a false loaded state.
  • Producer probing used a test-only headless script invoking the production observation method on the actual analyzed Program. It did not exercise the authenticated REA socket handshake or full CLI/MCP successful Evidence path.

Remaining host/provider gap

Actual REA CLI and MCP search attempts remain blocked before engine launch by this environment's process-ownership prerequisite: Node-spawned ps -axo pid=,ppid=,pgid=,uid=,stat=,command= fails with fatal library error, lookup self. The same command works from the outer shell, and the Node subprocess failure was checked independently. Ownership checks were not bypassed, and the failed workflows are not counted as PASS.

Complete real CLI/MCP outcome propagation and lifecycle/cleanup verification still need a compatible host. Windows native ownership and MSVC-host reproduction were not exercised. Keep the PR draft until the required real-provider lane completes.

This addresses the reporting portion of #2259. Automatic or caller-selected matching-PDB admission remains outside this change; do not close the broader issue as fully resolved without the maintainer's scope decision.

The added output consists of six handshake attributes and one limitation when needed. Cold/warm real-engine elapsed time, CPU, peak process-family memory, and completed-task token costs have not been measured.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2275 **Author:** [@hifzabuildsai](https://github.com/hifzabuildsai) **Created:** 10/12/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/ghidra-pdb-coverage` --- ### 📝 Commits (5) - [`5890b2a`](https://github.com/morluto/rea/commit/5890b2a076127dd2801e8aa781928d7106a766e9) fix(ghidra): disclose missing PDB symbol coverage - [`a6df916`](https://github.com/morluto/rea/commit/a6df916523615845d15171f8925e8e2a5ef2e0be) fix(ghidra): reconcile provider docs and cover missing PDB reports - [`63deb71`](https://github.com/morluto/rea/commit/63deb717b5ca8ccdbdd303e57a2ec835d640a0c2) chore: merge latest main after source review - [`6fc0e13`](https://github.com/morluto/rea/commit/6fc0e136bc384a0c6aca42ae62f8d4bf5fed17db) style: format reviewed source changes - [`c84ced1`](https://github.com/morluto/rea/commit/c84ced1589f5f139c4d096bb0c3cd97c6ea06ecb) fix(ghidra): bound PDB handshake and retain coverage uncertainty ### 📊 Changes **9 files changed** (+391 additions, -7 deletions) <details> <summary>View changed files</summary> 📝 `bridge/ghidra/ReaGhidraBridge.java` (+40 -0) 📝 `docs/ghidra-provider.md` (+20 -0) 📝 `src/ghidra/GhidraAnalysisProfile.ts` (+3 -0) 📝 `src/ghidra/GhidraProvider.behavior.test.ts` (+107 -0) 📝 `src/ghidra/GhidraProviderClient.ts` (+21 -5) 📝 `src/ghidra/GhidraSessionValues.test.ts` (+43 -0) 📝 `src/ghidra/GhidraSessionValues.ts` (+71 -0) 📝 `tests/boundary/mcp/ghidraInventoryMcp.test.ts` (+76 -0) 📝 `tests/boundary/mcp/ghidraMcpHarness.ts` (+10 -2) </details> ### 📄 Description ## Problem Refs #2259. A PE's CodeView metadata can reference a PDB that Ghidra did not load. REA's private executable import omits the sibling PDB, but successful analysis Evidence does not disclose missing symbol coverage. An empty name search can therefore look complete without explaining why original names are unavailable. ## Change - Report Ghidra's post-analysis PDB Program Information attributes in the authenticated handshake: file, GUID, hexadecimal age, legacy signature, version, and nullable loaded state. Preserve source strings and absent attributes. - Carry a limitation into PE health, inventory, search, and function observations when referenced symbols are not loaded or their load state is unknown. Include identity and an address-based next probe. A missing bridge report remains unknown. - Read the established handshake before direct PE calls; the client reuses its existing startup promise rather than launching another engine. Rename the shared handshake projection to reflect its broader ownership. - Add `pdb_observations: program-info-v1` to PE analysis profiles so snapshots produced before this reporting change have a different identity. - Document the symbol-coverage boundary. A reported loaded flag does not independently prove a matching PDB identity or complete symbols. The change does not copy PDBs, contact symbol servers, change analyzers, or add mutation authority. ## Validation Published commit `5890b2a076127dd2801e8aa781928d7106a766e9` has the exact validated tree `f5d14d3dc7b10ab1be8971f882ae05002318af52` of local commit `23b6b11176fefa9c94ffb16881d7feed5eef332a`, based on upstream `11fe5a13f8aee87d0c0e036a9f497407e085fe48`. Linux x64, repository-pinned Node 24.18.0 and npm 11.16.0: - `npm run test:focused -- src/ghidra/GhidraSessionValues.test.ts src/ghidra/GhidraProvider.behavior.test.ts src/ghidra/GhidraInventoryValues.test.ts tests/boundary/mcp/ghidraInventoryMcp.test.ts` — 4 suites, 85 tests passed. - `npm run check` — passed: runtime compilation, typecheck, formatting, lint (0 errors; warnings reported), knip, metadata, resolved module boundaries, architecture guards. - `npm run docs:check` — passed, including both README consistency tests. - `npm run verify:test-discovery` — all 950 test files discovered exactly once. - `git diff --check` — passed. The regressions first failed on the original source: the handshake rejected PDB facts and direct searches skipped the handshake projection. After the change they pass. Public MCP testing uses the actual provider/service/server pipeline with synthetic bridge facts, a generated PE fixture, retained Evidence, and function snapshot replay. It does not establish behavior of an installed Ghidra engine. The Java APIs and attribute meanings were checked against Ghidra 12.1.4 source: [PdbParserConstants](https://github.com/NationalSecurityAgency/ghidra/blob/Ghidra_12.1.4_build/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pdb/PdbParserConstants.java) and [PdbProgramAttributes](https://github.com/NationalSecurityAgency/ghidra/blob/Ghidra_12.1.4_build/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbProgramAttributes.java). ## Remaining verification — draft ### Real producer verification (2026-10-12) Ghidra 12.1.4 and Temurin JDK 21.0.12.1+1 were downloaded from official GitHub releases, and both published SHA-256 digests matched. All packaged Java bridge sources compiled against the installed Ghidra jars. On Linux x64, Clang/LLD 18.1.8 cross-compiled a small self-owned C fixture to x86_64-pc-windows-msvc PE32+ with a matching PDB and a relative CodeView PDB path. This is a Linux-host PE/PDB producer check, not Windows/MSVC-host verification. - Executable SHA-256: `3828e3c48d2670453cd054837a9a44f2ad91d95895013460de83eb82c6a89a6c`. - PDB GUID: `7047ef95-97c7-9e00-4c4c-44205044422e`; hexadecimal age `1`. - With the sidecar, actual headless Ghidra loaded the PDB and recovered `add_numbers` and `main`. Calling the compiled production bridge's `pdbObservation` against this Program returned `loaded: true`; the production TypeScript limitation projection returned no missing-PDB warning. - An identical executable copied to a directory without the PDB produced `FUN_140001000` and `entry`. Ghidra omitted the `PDB Loaded` attribute. The production bridge preserved that omission as `loaded: null`; the TypeScript projection reported the referenced file/GUID/age and unknown load state. It did not manufacture a false loaded state. - Producer probing used a test-only headless script invoking the production observation method on the actual analyzed Program. It did not exercise the authenticated REA socket handshake or full CLI/MCP successful Evidence path. ### Remaining host/provider gap Actual REA CLI and MCP search attempts remain blocked before engine launch by this environment's process-ownership prerequisite: Node-spawned `ps -axo pid=,ppid=,pgid=,uid=,stat=,command=` fails with `fatal library error, lookup self`. The same command works from the outer shell, and the Node subprocess failure was checked independently. Ownership checks were not bypassed, and the failed workflows are not counted as PASS. Complete real CLI/MCP outcome propagation and lifecycle/cleanup verification still need a compatible host. Windows native ownership and MSVC-host reproduction were not exercised. Keep the PR draft until the required real-provider lane completes. This addresses the reporting portion of #2259. Automatic or caller-selected matching-PDB admission remains outside this change; do not close the broader issue as fully resolved without the maintainer's scope decision. The added output consists of six handshake attributes and one limitation when needed. Cold/warm real-engine elapsed time, CPU, peak process-family memory, and completed-task token costs have not been measured. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:04:13 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5132
No description provided.