[PR #2435] feat(managed): bind Portable PDB sequence points to selected methods #5226

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2435
Author: @vincent-peng
Created: 10/13/2026
Status: 🔄 Open

Base: main ← Head: feat/portable-pdb-sequence-points


📝 Commits (9)

  • 1e98721 feat(managed): bind Portable PDB sequence points to selected methods
  • 4c1761f merge(main): resolve docs conflict for Portable PDB section
  • 5cf979b fix(managed): correct Portable PDB identity and review findings
  • 93e60e7 fix(managed): bound debug-map retention and scope identity degradation
  • cb9cfcd Merge branch 'main' into feat/portable-pdb-sequence-points
  • 44366a2 Merge branch 'main' into feat/portable-pdb-sequence-points
  • 777ba66 fix(managed): bound document-name parts and validate blob header rows
  • a1e3e2a test(dotnet): split operand width diagnostics over the lint limit
  • 807c35a Merge branch 'main' into feat/portable-pdb-sequence-points

📊 Changes

22 files changed (+3883 additions, -75 deletions)

View changed files

📝 docs/managed-code-analysis.md (+37 -0)
➕ docs/specs/managed/portable-pdb-sequence-points/plan.md (+37 -0)
➕ docs/specs/managed/portable-pdb-sequence-points/spec.md (+46 -0)
➕ docs/specs/managed/portable-pdb-sequence-points/tasks.md (+14 -0)
➕ docs/specs/managed/portable-pdb-sequence-points/verification.md (+22 -0)
📝 src/cli/managedCommands.ts (+13 -1)
📝 src/contracts/managed/managedToolContracts.ts (+16 -1)
📝 src/contracts/managed/managedWorkflowExamples.ts (+1 -0)
📝 src/domain/managed/managedArtifact.ts (+94 -1)
➕ src/dotnet/ManagedDebugDirectory.ts (+299 -0)
📝 src/dotnet/ManagedMemberInspector.ts (+131 -58)
📝 src/dotnet/ManagedMetadataLayout.ts (+1 -1)
📝 src/dotnet/ManagedPe.fixture.ts (+95 -0)
📝 src/dotnet/ManagedPeReader.ts (+22 -8)
📝 src/dotnet/ManagedStaticProvider.ts (+42 -5)
➕ src/dotnet/PortablePdb.fixture.ts (+424 -0)
➕ src/dotnet/PortablePdbDebugMap.test.ts (+912 -0)
➕ src/dotnet/PortablePdbDebugMap.ts (+817 -0)
➕ src/dotnet/PortablePdbLayout.ts (+429 -0)
📝 tests/acceptance/managedCliOutput.test.ts (+102 -0)

...and 2 more files

📄 Description

Summary

Fixes #2351. inspect_managed_members gains optional pdb_path / pdb_embedded selectors on both CLI (--pdb, --pdb-embedded) and MCP. When a Portable PDB is selected, the result carries a debug_map that verifies the PDB against the assembly's own declarations and reports documents, checksums and sequence points keyed to build-local MethodDef tokens and IL offsets.

Problem and expected behavior

Managed member inspection reported IL extents but no source-level sequence points. The issue asks to bind Portable PDB sequence points to the selected managed methods so callers can map IL offsets to source lines without guessing which PDB belongs to the build.

Change and scope

  • src/dotnet/ManagedDebugDirectory.ts parses PE debug-directory entries: CodeView RSDS (GUID, age, declared path) and MPDB embedded Portable PDB payloads (raw RFC 1951 Deflate, bounded inflation). Directory enumeration is capped at 4096 entries.
  • src/dotnet/PortablePdbLayout.ts parses the Portable PDB metadata root (BSJB), stream headers, the #Pdb stream (20-byte content ID, entry-point token, referenced type-system rows) and debug-table layouts using the existing ECMA-335 coded-index sizing.
  • src/dotnet/PortablePdbDebugMap.ts decodes Document rows (names, path parts, checksum algorithms/bytes, language GUIDs — unknown GUIDs retained), MethodDebugInformation rows, and sequence-point blobs including hidden points, document switches and signed line/column deltas per ECMA-335 II.23.2. MDI rows are bound to MethodDef tokens; rows not covered by MDI are counted in methods_without_debug_information.
  • Identity is verified CodeView RSDS GUID/age against the #Pdb content GUID/stamp and reported as matched / mismatched / undeclared / unverifiable without blocking the evidence.
  • Selectors are validated once in ManagedStaticProvider (mutually exclusive, pdb_path must be absolute, read through the existing bounded/cancellable snapshot path).
  • The PDB projection is charged to its own decode budget so oversized or malformed PDBs degrade debug_map to malformed without discarding member evidence; retained issues are bounded with an omitted count.
  • Intentionally not included: SourceLink resolution, source-file access, non-portable (Windows MSF) PDB support, portable-PDB reading of non-managed artifacts. Spec/plan/tasks/verification docs live in docs/specs/managed/portable-pdb-sequence-points/.

Contract and boundary impact

  • Semantic owner and earliest changed stage: src/dotnet/ readers own the format facts; ManagedStaticProvider owns the external file read; CLI/MCP expose the selectors unchanged elsewhere.
  • Contribution scope fit and linked maintainer decision: static format inspection and evidence reporting; no target interaction — not applicable.
  • CLI and MCP/tool-catalog contract: additive — two optional inputs, one nullable output field (debug_map, defaults null); selector exclusivity enforced in the provider so both adapters agree.
  • Provider, bridge, target-format, or platform compatibility: additive to the managed static provider; embedded PDBs extracted only when selected.
  • Evidence, artifact, provenance, or reconstruction contract: debug_map reports source path, byte_length and sha256; identity mismatch remains visible rather than blocking evidence.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): none — reads only caller-selected local files; no target code is loaded or executed.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none; the catalog is CI-generated from the edited contracts.

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: src/dotnet/PortablePdbDebugMap.test.ts (22), tests/boundary/providers/managed/managedPortablePdb.test.ts (6), plus MCP and CLI parity cases. Fixtures are byte-built synthesizers (PortablePdb.fixture.ts, ManagedPe.fixture.ts debug-directory support), not binaries.
  • Base reproduction or other evidence: without a selector, debug_map is null and prior output is unchanged; with a selector, matching/mismatched/undeclared/malformed states are asserted end-to-end.
  • User-visible CLI/MCP output (if applicable): rea inspect-managed-members <pe> --pdb <pdb> --json reports normalized_result.debug_map with source, pdb provenance, identity, documents, methods[].sequence_points and coverage.
  • Remaining proof gaps: coverage uses synthesized Portable PDBs (including known-answer compressed-integer bytes); a real compiler-produced embedded-PDB round trip is not exercised, though inflateRawSync matches the DeflateStream wire format.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run test:focused -- src/dotnet/PortablePdbDebugMap.test.ts tests/boundary/providers/managed/managedPortablePdb.test.ts tests/boundary/mcp/managedMcp.test.ts tests/acceptance/managedCliOutput.test.ts — 39 tests passed.
  • npm run test:local -- src/dotnet/ManagedMemberInspector.test.ts src/dotnet/ManagedArtifactInspector.test.ts src/dotnet/ManagedArtifactFailures.test.ts (plus the other src/dotnet/ suites) — 183 tests passed.
  • npm run check:fast — typecheck + lint pass.
  • npm run docs:check — pass.
  • npm run verify:test-discovery — 1000 test files discovered.

Compatibility, safety, and release

  • Breaking changes or migration steps: none — inputs are optional and debug_map is a nullable additive field.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable; the managed static path is provider-free.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: reads only the caller-selected PE/PDB paths through the existing bounded, cancellable snapshot path; embedded inflation is size-bounded; no network or SourceLink access; local file paths are caller-provided inputs echoed back as provenance.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 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/2435 **Author:** [@vincent-peng](https://github.com/vincent-peng) **Created:** 10/13/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/portable-pdb-sequence-points` --- ### 📝 Commits (9) - [`1e98721`](https://github.com/morluto/rea/commit/1e98721b1d8fbec4fccd2491293764f4723a6778) feat(managed): bind Portable PDB sequence points to selected methods - [`4c1761f`](https://github.com/morluto/rea/commit/4c1761fea08ae573e67591a00bfecd5b50802528) merge(main): resolve docs conflict for Portable PDB section - [`5cf979b`](https://github.com/morluto/rea/commit/5cf979bfa65b91d8796d89398bd7ceaba48c0509) fix(managed): correct Portable PDB identity and review findings - [`93e60e7`](https://github.com/morluto/rea/commit/93e60e7b2ed58c95377ac2517016736c4277f549) fix(managed): bound debug-map retention and scope identity degradation - [`cb9cfcd`](https://github.com/morluto/rea/commit/cb9cfcd76a364cf389add22517633ec1c909ca48) Merge branch 'main' into feat/portable-pdb-sequence-points - [`44366a2`](https://github.com/morluto/rea/commit/44366a23a68ce015e2ae606fffe05eb0d66c208a) Merge branch 'main' into feat/portable-pdb-sequence-points - [`777ba66`](https://github.com/morluto/rea/commit/777ba665f7056e121c288c1bf2fd531695459983) fix(managed): bound document-name parts and validate blob header rows - [`a1e3e2a`](https://github.com/morluto/rea/commit/a1e3e2a11d868f3ff5563f370e693f3776b41245) test(dotnet): split operand width diagnostics over the lint limit - [`807c35a`](https://github.com/morluto/rea/commit/807c35a6122b4810bed345ab85b9ef58dcad60cf) Merge branch 'main' into feat/portable-pdb-sequence-points ### 📊 Changes **22 files changed** (+3883 additions, -75 deletions) <details> <summary>View changed files</summary> 📝 `docs/managed-code-analysis.md` (+37 -0) ➕ `docs/specs/managed/portable-pdb-sequence-points/plan.md` (+37 -0) ➕ `docs/specs/managed/portable-pdb-sequence-points/spec.md` (+46 -0) ➕ `docs/specs/managed/portable-pdb-sequence-points/tasks.md` (+14 -0) ➕ `docs/specs/managed/portable-pdb-sequence-points/verification.md` (+22 -0) 📝 `src/cli/managedCommands.ts` (+13 -1) 📝 `src/contracts/managed/managedToolContracts.ts` (+16 -1) 📝 `src/contracts/managed/managedWorkflowExamples.ts` (+1 -0) 📝 `src/domain/managed/managedArtifact.ts` (+94 -1) ➕ `src/dotnet/ManagedDebugDirectory.ts` (+299 -0) 📝 `src/dotnet/ManagedMemberInspector.ts` (+131 -58) 📝 `src/dotnet/ManagedMetadataLayout.ts` (+1 -1) 📝 `src/dotnet/ManagedPe.fixture.ts` (+95 -0) 📝 `src/dotnet/ManagedPeReader.ts` (+22 -8) 📝 `src/dotnet/ManagedStaticProvider.ts` (+42 -5) ➕ `src/dotnet/PortablePdb.fixture.ts` (+424 -0) ➕ `src/dotnet/PortablePdbDebugMap.test.ts` (+912 -0) ➕ `src/dotnet/PortablePdbDebugMap.ts` (+817 -0) ➕ `src/dotnet/PortablePdbLayout.ts` (+429 -0) 📝 `tests/acceptance/managedCliOutput.test.ts` (+102 -0) _...and 2 more files_ </details> ### 📄 Description ## Summary Fixes #2351. `inspect_managed_members` gains optional `pdb_path` / `pdb_embedded` selectors on both CLI (`--pdb`, `--pdb-embedded`) and MCP. When a Portable PDB is selected, the result carries a `debug_map` that verifies the PDB against the assembly's own declarations and reports documents, checksums and sequence points keyed to build-local MethodDef tokens and IL offsets. ## Problem and expected behavior Managed member inspection reported IL extents but no source-level sequence points. The issue asks to bind Portable PDB sequence points to the selected managed methods so callers can map IL offsets to source lines without guessing which PDB belongs to the build. ## Change and scope - `src/dotnet/ManagedDebugDirectory.ts` parses PE debug-directory entries: CodeView `RSDS` (GUID, age, declared path) and `MPDB` embedded Portable PDB payloads (raw RFC 1951 Deflate, bounded inflation). Directory enumeration is capped at 4096 entries. - `src/dotnet/PortablePdbLayout.ts` parses the Portable PDB metadata root (`BSJB`), stream headers, the `#Pdb` stream (20-byte content ID, entry-point token, referenced type-system rows) and debug-table layouts using the existing ECMA-335 coded-index sizing. - `src/dotnet/PortablePdbDebugMap.ts` decodes Document rows (names, path parts, checksum algorithms/bytes, language GUIDs — unknown GUIDs retained), MethodDebugInformation rows, and sequence-point blobs including hidden points, document switches and signed line/column deltas per ECMA-335 II.23.2. MDI rows are bound to MethodDef tokens; rows not covered by MDI are counted in `methods_without_debug_information`. - Identity is verified CodeView RSDS GUID/age against the `#Pdb` content GUID/stamp and reported as `matched` / `mismatched` / `undeclared` / `unverifiable` without blocking the evidence. - Selectors are validated once in `ManagedStaticProvider` (mutually exclusive, `pdb_path` must be absolute, read through the existing bounded/cancellable snapshot path). - The PDB projection is charged to its own decode budget so oversized or malformed PDBs degrade `debug_map` to `malformed` without discarding member evidence; retained issues are bounded with an omitted count. - Intentionally not included: SourceLink resolution, source-file access, non-portable (Windows MSF) PDB support, portable-PDB reading of non-managed artifacts. Spec/plan/tasks/verification docs live in `docs/specs/managed/portable-pdb-sequence-points/`. ## Contract and boundary impact - Semantic owner and earliest changed stage: `src/dotnet/` readers own the format facts; `ManagedStaticProvider` owns the external file read; CLI/MCP expose the selectors unchanged elsewhere. - Contribution scope fit and linked maintainer decision: static format inspection and evidence reporting; no target interaction — not applicable. - CLI and MCP/tool-catalog contract: additive — two optional inputs, one nullable output field (`debug_map`, defaults `null`); selector exclusivity enforced in the provider so both adapters agree. - Provider, bridge, target-format, or platform compatibility: additive to the managed static provider; embedded PDBs extracted only when selected. - Evidence, artifact, provenance, or reconstruction contract: `debug_map` reports source `path`, `byte_length` and `sha256`; identity mismatch remains visible rather than blocking evidence. - Target selection, authority, upstream behavior, and cleanup details (if applicable): none — reads only caller-selected local files; no target code is loaded or executed. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none; the catalog is CI-generated from the edited contracts. Expected effects: - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: `src/dotnet/PortablePdbDebugMap.test.ts` (22), `tests/boundary/providers/managed/managedPortablePdb.test.ts` (6), plus MCP and CLI parity cases. Fixtures are byte-built synthesizers (`PortablePdb.fixture.ts`, `ManagedPe.fixture.ts` debug-directory support), not binaries. - Base reproduction or other evidence: without a selector, `debug_map` is `null` and prior output is unchanged; with a selector, matching/mismatched/undeclared/malformed states are asserted end-to-end. - User-visible CLI/MCP output (if applicable): `rea inspect-managed-members <pe> --pdb <pdb> --json` reports `normalized_result.debug_map` with `source`, `pdb` provenance, `identity`, `documents`, `methods[].sequence_points` and `coverage`. - Remaining proof gaps: coverage uses synthesized Portable PDBs (including known-answer compressed-integer bytes); a real compiler-produced embedded-PDB round trip is not exercised, though `inflateRawSync` matches the `DeflateStream` wire format. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run test:focused -- src/dotnet/PortablePdbDebugMap.test.ts tests/boundary/providers/managed/managedPortablePdb.test.ts tests/boundary/mcp/managedMcp.test.ts tests/acceptance/managedCliOutput.test.ts` — 39 tests passed. - `npm run test:local -- src/dotnet/ManagedMemberInspector.test.ts src/dotnet/ManagedArtifactInspector.test.ts src/dotnet/ManagedArtifactFailures.test.ts` (plus the other `src/dotnet/` suites) — 183 tests passed. - `npm run check:fast` — typecheck + lint pass. - `npm run docs:check` — pass. - `npm run verify:test-discovery` — 1000 test files discovered. ## Compatibility, safety, and release - Breaking changes or migration steps: none — inputs are optional and `debug_map` is a nullable additive field. - Real Hopper/Ghidra, browser, or OS coverage: not applicable; the managed static path is provider-free. - Package or release metadata impact: none. - Security, privacy, process, or containment review: reads only the caller-selected PE/PDB paths through the existing bounded, cancellable snapshot path; embedded inflation is size-bounded; no network or SourceLink access; local file paths are caller-provided inputs echoed back as provenance. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
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#5226
No description provided.