[GH-ISSUE #2335] [Feature] Headless IDA: resolve containing procedures and report the admitted program as the document #772

Closed
opened 2026-10-15 18:28:13 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @nikolay-dementiev on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2335

I'm working on this and will open a PR.

Before submitting

  • I searched the open and closed issues and pull requests for a related proposal.
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This request does not include credentials, private samples, or sensitive target data.

Area

Native analysis or decompilation

Current limitation

With the modern headless IDA profile, two shared workflows stop at an operation the provider does not declare:

  • trace_feature fails with capability_unavailable for resolve_containing_procedure as soon as a literal has references, so it cannot attribute a reference source to a function.
  • inspect_address_context without document fails with capability_unavailable for list_documents. With an explicit document it answers, but every facet that needs containment stays unavailable.

Observed on real IDA Professional 9.1 (headless idalib, ida-pro-mcp c133c38, main at a97b713f7) with a small arm64 Mach-O: trace_feature {"query": "sum_point"} and inspect_address_context {"address": "0x100000564"} both return capability_unavailable naming those operations.

Use cases

  • Trace a string or symbol literal to the functions that reference it (trace_feature) when IDA is the native provider.
  • Ask which function an address belongs to (resolve_containing_procedure, inspect_address_context) without first knowing a document identity.

Desired outcome and success criteria

  • resolve_containing_procedure works for the modern headless profile: an entry, interior or tail address returns the canonical containing procedure (body stays unavailable, as for the other IDA identities). An address inside a segment but outside any function returns not_in_procedure, and an unmapped address returns outside_segments. If segment membership cannot be established, the read fails instead of guessing either reason.
  • list_documents returns the single admitted program identity (the target REA admitted), so default document resolution works without enumerating unrelated upstream databases.
  • trace_feature keeps upstream xref caps visible: a capped xrefs read sets truncated and adds a residual unknown instead of reporting a complete trace.
  • No public schema change. binary_overview, whole-symbol inventory (list_names), typed reference kinds and complete body ranges stay outside the adapter, as docs/ida-provider.md states.

Expected interaction with targets

Read existing files or captured data

Target and scope details (optional)

Modern headless profile only. Legacy and native profiles keep their current capabilities unless implemented separately.

Verification available so far

I have a prototype or observed results

Verification details (optional)

On real IDA 9.1 through the pinned upstream (idalib-mcp --stdio):

  • lookup_funcs {"queries": ["0x100000564"]} returns the containing function _use_wrapper at 0x100000560 (an interior address); 0x100008030 (data) returns fn: null, error: "Not a function".
  • survey_binary {"detail_level": "minimal"} returns the database's segments with start, end and permissions, which separates not_in_procedure from outside_segments. The supervisor does not route ida://idb/segments resource reads, so the database-scoped tool is the usable source.

I can run the real npm run verify:ida lane and an extended containment/context scenario on IDA 9.1 (macOS arm64).

Alternatives considered

  • list_segments: the segment schema's provenance currently admits only Hopper and Ghidra sources, so honest IDA segments would need a schema change; left out of this slice.
  • read_bytes via upstream get_bytes: upstream fills unloaded bytes with zeros without an error (an unmapped address returns 0x0 bytes), so it needs its own segment check; left for a separate change.
  • address_to_file_offset: the pinned upstream exposes no file-region mapping; stays unavailable.

Possible direction

  • IdaOperationRunner: containment from lookup_funcs (positive answers are native containment observations); for fn: null, segment intervals from a database-scoped minimal survey_binary decide between the two negative reasons. Parse "found / expected missing / producer failure" once and keep the existing selector semantics of procedure_* reads.
  • IdaProviderCapabilities / IdaSessionClient: declare both operations for the modern headless profile and return the admitted target identity from list_documents.
  • Shared trace plumbing: carry the producer's xref cap into trace_feature's truncated and residual unknowns instead of dropping execution metadata.
  • Tests in the IDA fake fixtures and boundary lane, and an extended real verify:ida scenario.

References

docs/ida-provider.md (coverage section), #2001 and #1964 (related workflow coverage work).

Originally created by @nikolay-dementiev on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2335 > I'm working on this and will open a PR. ### Before submitting - [x] I searched the open and closed issues and pull requests for a related proposal. - [x] I understand the contribution scope must be reviewed before integration; open questions are welcome here. - [x] This request does not include credentials, private samples, or sensitive target data. ### Area Native analysis or decompilation ### Current limitation With the modern headless IDA profile, two shared workflows stop at an operation the provider does not declare: - `trace_feature` fails with `capability_unavailable` for `resolve_containing_procedure` as soon as a literal has references, so it cannot attribute a reference source to a function. - `inspect_address_context` without `document` fails with `capability_unavailable` for `list_documents`. With an explicit `document` it answers, but every facet that needs containment stays unavailable. Observed on real IDA Professional 9.1 (headless idalib, ida-pro-mcp c133c38, `main` at a97b713f7) with a small arm64 Mach-O: `trace_feature {"query": "sum_point"}` and `inspect_address_context {"address": "0x100000564"}` both return `capability_unavailable` naming those operations. ### Use cases - Trace a string or symbol literal to the functions that reference it (`trace_feature`) when IDA is the native provider. - Ask which function an address belongs to (`resolve_containing_procedure`, `inspect_address_context`) without first knowing a document identity. ### Desired outcome and success criteria - `resolve_containing_procedure` works for the modern headless profile: an entry, interior or tail address returns the canonical containing procedure (body stays unavailable, as for the other IDA identities). An address inside a segment but outside any function returns `not_in_procedure`, and an unmapped address returns `outside_segments`. If segment membership cannot be established, the read fails instead of guessing either reason. - `list_documents` returns the single admitted program identity (the target REA admitted), so default document resolution works without enumerating unrelated upstream databases. - `trace_feature` keeps upstream xref caps visible: a capped `xrefs` read sets `truncated` and adds a residual unknown instead of reporting a complete trace. - No public schema change. `binary_overview`, whole-symbol inventory (`list_names`), typed reference kinds and complete body ranges stay outside the adapter, as `docs/ida-provider.md` states. ### Expected interaction with targets Read existing files or captured data ### Target and scope details (optional) Modern headless profile only. Legacy and native profiles keep their current capabilities unless implemented separately. ### Verification available so far I have a prototype or observed results ### Verification details (optional) On real IDA 9.1 through the pinned upstream (`idalib-mcp --stdio`): - `lookup_funcs {"queries": ["0x100000564"]}` returns the containing function `_use_wrapper` at `0x100000560` (an interior address); `0x100008030` (data) returns `fn: null, error: "Not a function"`. - `survey_binary {"detail_level": "minimal"}` returns the database's segments with start, end and permissions, which separates `not_in_procedure` from `outside_segments`. The supervisor does not route `ida://idb/segments` resource reads, so the database-scoped tool is the usable source. I can run the real `npm run verify:ida` lane and an extended containment/context scenario on IDA 9.1 (macOS arm64). ### Alternatives considered - `list_segments`: the segment schema's provenance currently admits only Hopper and Ghidra sources, so honest IDA segments would need a schema change; left out of this slice. - `read_bytes` via upstream `get_bytes`: upstream fills unloaded bytes with zeros without an error (an unmapped address returns `0x0` bytes), so it needs its own segment check; left for a separate change. - `address_to_file_offset`: the pinned upstream exposes no file-region mapping; stays unavailable. ### Possible direction - `IdaOperationRunner`: containment from `lookup_funcs` (positive answers are native containment observations); for `fn: null`, segment intervals from a database-scoped minimal `survey_binary` decide between the two negative reasons. Parse "found / expected missing / producer failure" once and keep the existing selector semantics of `procedure_*` reads. - `IdaProviderCapabilities` / `IdaSessionClient`: declare both operations for the modern headless profile and return the admitted target identity from `list_documents`. - Shared trace plumbing: carry the producer's xref cap into `trace_feature`'s `truncated` and residual unknowns instead of dropping execution metadata. - Tests in the IDA fake fixtures and boundary lane, and an extended real `verify:ida` scenario. ### References `docs/ida-provider.md` (coverage section), #2001 and #1964 (related workflow coverage work).
Author
Owner

@matbrgz commented on GitHub (Oct 12, 2026):

Triage & Implementation Review

Enabling resolve_containing_procedure and reporting the admitted program as the document in headless IDA resolves the capability_unavailable failure in trace_feature and inspect_address_context.

  • Contract Alignment: Preserving containment queries without requiring an explicit GUI document identifier matches the behavior of the headless Ghidra lane.
  • Tracking: Implemented in PR #2374 (feat(ida): resolve containing procedures and report the admitted program as the document).
<!-- gh-comment-id:6134247082 --> @matbrgz commented on GitHub (Oct 12, 2026): ### Triage & Implementation Review Enabling `resolve_containing_procedure` and reporting the admitted program as the document in headless IDA resolves the `capability_unavailable` failure in `trace_feature` and `inspect_address_context`. - **Contract Alignment:** Preserving containment queries without requiring an explicit GUI document identifier matches the behavior of the headless Ghidra lane. - **Tracking:** Implemented in PR #2374 (`feat(ida): resolve containing procedures and report the admitted program as the document`).
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#772
No description provided.