[GH-ISSUE #8363] [Bug] Ghidra address context hides available function comments and suggests unsupported calls #6562

Open
opened 2026-11-01 21:12:16 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @morluto on GitHub (Oct 31, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8363

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

MCP or agent integration

Observed behavior

A Ghidra session can write and read regular and inline comments at a function entry via annotate_native_function and analyze_function, but inspect_address_context at that same entry reports both comment facets unavailable and tells the agent to call comment and inline_comment. Both suggested calls return non-retryable capability_unavailable for the active Ghidra provider.

Reproduction

  1. Create an unexecuted raw x86-64 fixture with bytes e806000000b878563412c3b821436587c3. Start REA MCP with Ghidra 12.1.4 and call open_binary with format: "raw-binary", architecture: "x86_64", entry_point: "0x1000", and the fixture path.
  2. Call annotate_native_function with {"procedure":"0x1000","comment":"analysis note: evidence marker","inline_comment":"instruction note: marker"}. The readback and refreshed dossier contain both comments.
  3. Call inspect_address_context({"address":"0x1000"}). Both comment facets have state: "unavailable" with a reason that the provider does not declare the corresponding operation and a remediation to call that operation directly. comment({"address":"0x1000"}) and inline_comment({"address":"0x1000"}) each return capability_unavailable.
  4. In the same session, analyze_function({"procedure":"0x1000","detail":"complete"}) independently returns both comments at 0x1000. The Ghidra session is ephemeral; the original fixture SHA-256 remains unchanged.

The bookmarks facet also advises calling unsupported list_bookmarks, but this experiment does not establish a supported way to retrieve Ghidra bookmarks. Requests used the public stdio MCP interface and advertised full output schemas with the TypeScript SDK.

Additional Mach-O control

On REA 7abef04a5, Ghidra 12.1.4, Node 24.22.1 and macOS arm64, an owned unexecuted arm64 Mach-O produced the same outcome at a function entry: after annotate_native_function set a name, regular comment Analyst note: café, and inline comment Review branch, address context reported the name but both comment facets unavailable with direct-call remediation. In the same live session, complete analyze_function returned both exact comments. The annotation response also carried both readbacks. The target SHA-256 87fa65dee009e59a8709a70a2aa731a0dc9cae47cf65d4c69292f7cad4897d93 remained unchanged. This extends the observed formats and architecture; it does not prove arbitrary-address support.

Expected behavior

The context workflow should make supported evidence and applicable recovery discoverable without claiming unsupported arbitrary-address comment access. For an address inside a known function, one possible recovery is to inspect that function's comment evidence and match the exact address; if a lighter or more direct representation is preferable, decide it at the owning boundary. Preserve unsupported/unknown outcomes for addresses where comments cannot be obtained, and do not automatically switch providers or imply absence. A caller should not be directed to an operation already known to be unavailable without making that limitation clear.

Impact and scope

An agent following the context response spends extra calls on operations guaranteed unavailable in this session and is not guided to the existing function dossier containing the comments. No autonomous-agent retry or frequency was measured. Tested one function entry, one raw x86-64 fixture and Ghidra 12.1.4 on macOS arm64; arbitrary addresses, other providers and Windows are unverified.

REA version

d54a4661da

Runtime and platform

Node 24.22.1; macOS 26.3 arm64; Ghidra 12.1.4 / JDK 21; TypeScript MCP SDK 2.3.1.

Target and artifact context

17-byte synthetic raw x86-64 fixture, SHA-256 58658a4b21d7ffc610f7123d0f4e9435c3ba63b54facea49da1bb9bb51cd8cc5; target unexecuted and unchanged.

Interface

MCP

Earliest failure stage

Transport or result projection

Relevant output or evidence

inspect_address_context comment facet: {"state":"unavailable","reason":"Provider ghidra cannot execute comment: operation is not declared by this provider","remediation":"Call comment directly to inspect provider availability and diagnostics."}. The inline facet is equivalent. analyze_function's complete dossier contains {"address":"0x1000","kind":"comment","text":"analysis note: evidence marker"} and the corresponding inline entry.

Analysis or suspected cause

Source-derived: AnalysisContextQueries.ts asks the individual comment and inline_comment operations and constructs the same direct-call remediation for unavailable facets. The dossier already provides function-scoped comment evidence; how to reuse it without unbounded collection, implicit fallback, or losing address/provenance is a design question.

Additional context

Related #6404 requests arbitrary-address Ghidra comment operations. This issue concerns surfacing or navigating to evidence already available for a known function entry and avoiding guaranteed-unavailable recovery, independently of whether those broader operations are implemented. #8241 concerns instruction containment for search hits.

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Existing-project Function ID comment control

On REA 9ebbe67e, Ghidra 12.1.4 and an explicitly selected copied project, a complete analyze_function dossier for 0x201170 contained the ordinary comment Library Function - Single Match, audit_mix, and Library: fixture 1 control. In the same session, inspect_address_context correctly identified the containing audit_mix function but reported the comment facet unavailable and recommended calling unsupported comment; this held in compact and full MCP output profiles. The original unexecuted x86-64 ELF target SHA-256 stayed 0cee46f9e95af174dec7f281c179cbe5233348520302c69fdc9eafc7fcebff1d.

The comment was present in the selected project before the REA session; no annotation call was made in this control. This is another case where existing function-scoped comment evidence is discoverable through the dossier but not the address-context recovery. The text is a Ghidra project comment, not authenticated proof of database identity or behavioral equivalence. This does not establish support at arbitrary addresses or measure agent behavior.

Interior-address distinction

In the same selected-project control, querying inspect_address_context at 0x201171 resolved the containing function entry 0x201170 in both output profiles. The separately retrieved dossier's Function ID comment is explicitly at 0x201170, not the requested interior address. The context's comment facet remained unavailable. The target digest was unchanged. A recovery path can navigate to the containing dossier, but must compare exact addresses and must not project this entry comment onto the interior address or infer that no interior comment exists. Source inspection also shows AnalysisOperationPort exposes execution but not operation availability, so suggesting the dossier as guaranteed requires an appropriate capability source or an explicit conditional, rather than assuming every provider supports it.

Known interior comment control

I copied the prior Ghidra project to a disposable project, used Ghidra headless to add the EOL comment interior review marker at 0x201171, and selected that copied project in fresh REA/Ghidra MCP sessions. In both compact and full profiles, complete analyze_function returned the marker as an inline comment at that exact interior address, alongside the distinct entry comment. inspect_address_context at 0x201171 still marked inline_comment unavailable and suggested the unsupported direct operation. The original target SHA-256 remained 0cee46f9e95af174dec7f281c179cbe5233348520302c69fdc9eafc7fcebff1d; it was not executed. Only the disposable project was edited in preparation.

This confirms a useful existing dossier path for one known interior comment, while exact-address matching remains necessary. It does not prove every provider or every comment type is supported, or that absence from a dossier is proof of absence.

Summary and paged recovery

With the disposable interior-comment project above, analyze_function using its default summary returned a summary with two comments counted, rather than the comment texts. In the same server, passing the summary's parent_evidence_id as retained Evidence to inspect_analysis_view with {kind: "native", facet: "comments", offset: 0, limit: 10} returned the entry and exact interior comments, with an exhausted two-item page. This worked in compact and full output profiles and the unexecuted target digest remained unchanged. Complete dossier output is another tested route; the paged route avoids requiring the complete dossier inline, although the underlying Ghidra analysis still constructs the function dossier. Recovery guidance should distinguish a summary from its parent and honor pagination and facet availability; a comment count alone cannot identify an address or text.

Originally created by @morluto on GitHub (Oct 31, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8363 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area MCP or agent integration ### Observed behavior A Ghidra session can write and read regular and inline comments at a function entry via `annotate_native_function` and `analyze_function`, but `inspect_address_context` at that same entry reports both comment facets unavailable and tells the agent to call `comment` and `inline_comment`. Both suggested calls return non-retryable `capability_unavailable` for the active Ghidra provider. ### Reproduction 1. Create an unexecuted raw x86-64 fixture with bytes `e806000000b878563412c3b821436587c3`. Start REA MCP with Ghidra 12.1.4 and call `open_binary` with `format: "raw-binary"`, `architecture: "x86_64"`, `entry_point: "0x1000"`, and the fixture path. 2. Call `annotate_native_function` with `{"procedure":"0x1000","comment":"analysis note: evidence marker","inline_comment":"instruction note: marker"}`. The readback and refreshed dossier contain both comments. 3. Call `inspect_address_context({"address":"0x1000"})`. Both comment facets have `state: "unavailable"` with a reason that the provider does not declare the corresponding operation and a remediation to call that operation directly. `comment({"address":"0x1000"})` and `inline_comment({"address":"0x1000"})` each return `capability_unavailable`. 4. In the same session, `analyze_function({"procedure":"0x1000","detail":"complete"})` independently returns both comments at `0x1000`. The Ghidra session is ephemeral; the original fixture SHA-256 remains unchanged. The bookmarks facet also advises calling unsupported `list_bookmarks`, but this experiment does not establish a supported way to retrieve Ghidra bookmarks. Requests used the public stdio MCP interface and advertised full output schemas with the TypeScript SDK. ### Additional Mach-O control On REA `7abef04a5`, Ghidra 12.1.4, Node 24.22.1 and macOS arm64, an owned unexecuted arm64 Mach-O produced the same outcome at a function entry: after `annotate_native_function` set a name, regular comment `Analyst note: café`, and inline comment `Review branch`, address context reported the name but both comment facets unavailable with direct-call remediation. In the same live session, complete `analyze_function` returned both exact comments. The annotation response also carried both readbacks. The target SHA-256 `87fa65dee009e59a8709a70a2aa731a0dc9cae47cf65d4c69292f7cad4897d93` remained unchanged. This extends the observed formats and architecture; it does not prove arbitrary-address support. ### Expected behavior The context workflow should make supported evidence and applicable recovery discoverable without claiming unsupported arbitrary-address comment access. For an address inside a known function, one possible recovery is to inspect that function's comment evidence and match the exact address; if a lighter or more direct representation is preferable, decide it at the owning boundary. Preserve unsupported/unknown outcomes for addresses where comments cannot be obtained, and do not automatically switch providers or imply absence. A caller should not be directed to an operation already known to be unavailable without making that limitation clear. ### Impact and scope An agent following the context response spends extra calls on operations guaranteed unavailable in this session and is not guided to the existing function dossier containing the comments. No autonomous-agent retry or frequency was measured. Tested one function entry, one raw x86-64 fixture and Ghidra 12.1.4 on macOS arm64; arbitrary addresses, other providers and Windows are unverified. ### REA version d54a4661da20382ad8456564a08569fdd24131c5 ### Runtime and platform Node 24.22.1; macOS 26.3 arm64; Ghidra 12.1.4 / JDK 21; TypeScript MCP SDK 2.3.1. ### Target and artifact context 17-byte synthetic raw x86-64 fixture, SHA-256 `58658a4b21d7ffc610f7123d0f4e9435c3ba63b54facea49da1bb9bb51cd8cc5`; target unexecuted and unchanged. ### Interface MCP ### Earliest failure stage Transport or result projection ### Relevant output or evidence `inspect_address_context` comment facet: `{"state":"unavailable","reason":"Provider ghidra cannot execute comment: operation is not declared by this provider","remediation":"Call comment directly to inspect provider availability and diagnostics."}`. The inline facet is equivalent. `analyze_function`'s complete dossier contains `{"address":"0x1000","kind":"comment","text":"analysis note: evidence marker"}` and the corresponding `inline` entry. ### Analysis or suspected cause Source-derived: [`AnalysisContextQueries.ts`](https://github.com/morluto/rea/blob/d54a4661da20382ad8456564a08569fdd24131c5/src/application/AnalysisContextQueries.ts#L100-L155) asks the individual `comment` and `inline_comment` operations and constructs the same direct-call remediation for unavailable facets. The dossier already provides function-scoped comment evidence; how to reuse it without unbounded collection, implicit fallback, or losing address/provenance is a design question. ### Additional context Related #6404 requests arbitrary-address Ghidra comment operations. This issue concerns surfacing or navigating to evidence already available for a known function entry and avoiding guaranteed-unavailable recovery, independently of whether those broader operations are implemented. #8241 concerns instruction containment for search hits. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 ### Existing-project Function ID comment control On REA `9ebbe67e`, Ghidra 12.1.4 and an explicitly selected copied project, a complete `analyze_function` dossier for `0x201170` contained the ordinary comment `Library Function - Single Match`, `audit_mix`, and `Library: fixture 1 control`. In the same session, `inspect_address_context` correctly identified the containing `audit_mix` function but reported the comment facet unavailable and recommended calling unsupported `comment`; this held in compact and full MCP output profiles. The original unexecuted x86-64 ELF target SHA-256 stayed `0cee46f9e95af174dec7f281c179cbe5233348520302c69fdc9eafc7fcebff1d`. The comment was present in the selected project before the REA session; no annotation call was made in this control. This is another case where existing function-scoped comment evidence is discoverable through the dossier but not the address-context recovery. The text is a Ghidra project comment, not authenticated proof of database identity or behavioral equivalence. This does not establish support at arbitrary addresses or measure agent behavior. ### Interior-address distinction In the same selected-project control, querying `inspect_address_context` at `0x201171` resolved the containing function entry `0x201170` in both output profiles. The separately retrieved dossier's Function ID comment is explicitly at `0x201170`, not the requested interior address. The context's comment facet remained unavailable. The target digest was unchanged. A recovery path can navigate to the containing dossier, but must compare exact addresses and must not project this entry comment onto the interior address or infer that no interior comment exists. Source inspection also shows `AnalysisOperationPort` exposes execution but not operation availability, so suggesting the dossier as guaranteed requires an appropriate capability source or an explicit conditional, rather than assuming every provider supports it. ### Known interior comment control I copied the prior Ghidra project to a disposable project, used Ghidra headless to add the EOL comment `interior review marker` at `0x201171`, and selected that copied project in fresh REA/Ghidra MCP sessions. In both compact and full profiles, complete `analyze_function` returned the marker as an `inline` comment at that exact interior address, alongside the distinct entry comment. `inspect_address_context` at `0x201171` still marked `inline_comment` unavailable and suggested the unsupported direct operation. The original target SHA-256 remained `0cee46f9e95af174dec7f281c179cbe5233348520302c69fdc9eafc7fcebff1d`; it was not executed. Only the disposable project was edited in preparation. This confirms a useful existing dossier path for one known interior comment, while exact-address matching remains necessary. It does not prove every provider or every comment type is supported, or that absence from a dossier is proof of absence. ### Summary and paged recovery With the disposable interior-comment project above, `analyze_function` using its default summary returned a summary with two comments counted, rather than the comment texts. In the same server, passing the summary's `parent_evidence_id` as retained Evidence to `inspect_analysis_view` with `{kind: "native", facet: "comments", offset: 0, limit: 10}` returned the entry and exact interior comments, with an exhausted two-item page. This worked in compact and full output profiles and the unexecuted target digest remained unchanged. Complete dossier output is another tested route; the paged route avoids requiring the complete dossier inline, although the underlying Ghidra analysis still constructs the function dossier. Recovery guidance should distinguish a summary from its parent and honor pagination and facet availability; a comment count alone cannot identify an address or text.
Author
Owner

@morluto commented on GitHub (Oct 31, 2026):

Related handoff design: #8364 records that the aggregate context response does not link the successful component Evidence it retains, and its unavailable facets are not retained in that aggregate. The reproducer also checks two observations around a session-only name change and a successful export/import control. This is separate from making the Ghidra comment recovery useful.

<!-- gh-comment-id:6548098131 --> @morluto commented on GitHub (Oct 31, 2026): Related handoff design: #8364 records that the aggregate context response does not link the successful component Evidence it retains, and its unavailable facets are not retained in that aggregate. The reproducer also checks two observations around a session-only name change and a successful export/import control. This is separate from making the Ghidra comment recovery useful.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

A second real Ghidra control on main-derived REA confirms the existing narrower route works with the default summary as well as a complete dossier. On a separate source-owned, unexecuted arm64 Mach-O, annotate_native_function recorded a regular comment at the function entry and returned it in both its annotation readback and refreshed dossier. inspect_address_context still marked the comment facet unavailable and directed me to comment, which returned capability_unavailable. The default analyze_function summary did not include the text but counted one comment; inspect_analysis_view using normalized_result.parent_evidence_id and {kind: "native", facet: "comments"} returned the exact comment.

The stdio MCP calls used Ghidra 12.1.4 / JDK 21 on macOS arm64 and SDK 2.3.1 with advertised full output schemas; the target hash was unchanged. This is one entry address and does not establish arbitrary-address comment access or measure agent behavior.

<!-- gh-comment-id:6551870467 --> @morluto commented on GitHub (Nov 1, 2026): A second real Ghidra control on main-derived REA confirms the existing narrower route works with the default summary as well as a complete dossier. On a separate source-owned, unexecuted arm64 Mach-O, `annotate_native_function` recorded a regular comment at the function entry and returned it in both its annotation readback and refreshed dossier. `inspect_address_context` still marked the comment facet unavailable and directed me to `comment`, which returned `capability_unavailable`. The default `analyze_function` summary did not include the text but counted one comment; `inspect_analysis_view` using `normalized_result.parent_evidence_id` and `{kind: "native", facet: "comments"}` returned the exact comment. The stdio MCP calls used Ghidra 12.1.4 / JDK 21 on macOS arm64 and SDK 2.3.1 with advertised full output schemas; the target hash was unchanged. This is one entry address and does not establish arbitrary-address comment access or measure agent behavior.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

A cross-provider control affects the recovery design. On the same unexecuted arm64 Mach-O, Ghidra 12.1.4 resolved the function containing the test address; an address in the Mach-O header and an unmapped address were outside a function. Kuna 1.986 returned containment unavailable even at the known function, and its separately requested dossier explicitly reported analyst comments unavailable. The tested target hash was unchanged. This does not establish arbitrary-address behavior beyond those controls.

Draft #8414 therefore points to the existing function comments view only when containment is observed, and only conditionally on the tools and document being applicable. It retains unknown facets for the other cases and preserves provider-authored recovery. The PR also extends the real-Ghidra COM verifier to annotate both comment kinds and follow the MCP summary-to-comments-view route. It does not make comments directly available in inspect_address_context or resolve the Evidence handoff in #8364.

<!-- gh-comment-id:6551934639 --> @morluto commented on GitHub (Nov 1, 2026): A cross-provider control affects the recovery design. On the same unexecuted arm64 Mach-O, Ghidra 12.1.4 resolved the function containing the test address; an address in the Mach-O header and an unmapped address were outside a function. Kuna 1.986 returned containment unavailable even at the known function, and its separately requested dossier explicitly reported analyst comments unavailable. The tested target hash was unchanged. This does not establish arbitrary-address behavior beyond those controls. Draft #8414 therefore points to the existing function comments view only when containment is observed, and only conditionally on the tools and document being applicable. It retains unknown facets for the other cases and preserves provider-authored recovery. The PR also extends the real-Ghidra COM verifier to annotate both comment kinds and follow the MCP summary-to-comments-view route. It does not make comments directly available in `inspect_address_context` or resolve the Evidence handoff in #8364.
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#6562
No description provided.