[GH-ISSUE #8314] [Design] Preserve local-variable source and identity in Ghidra function observations #6538

Open
opened 2026-11-01 21:12:03 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Decision needed

When an analyst uses a selected Ghidra project, should REA expose structured local-variable identity and Ghidra's reported source alongside the current human-readable local description, so an agent can distinguish a caller-authored label from a default analysis label without parsing text?

Context and evidence

I copied an owned Ghidra 12.1.4 project for a self-built arm64 Mach-O, renamed parameter record to analyst_input_record and local local_14 to analyst_result using headless Ghidra scripts on the copy, and saved it. In separate REA b43c329df779708e43ae297f498a844e45d9c923 MCP sessions selecting the original and edited projects read-only:

  • procedure_pseudo_code reflected both names. inspect_native_api reported the parameter name and signature_source: user_defined for both projects (the original signature was already caller-authored).
  • procedure_info.locals contained the original undefined4 local_14 @ Stack[-0x14]:4 or edited undefined4 analyst_result @ Stack[-0x14]:4 as a single description, with provenance: ghidra-function-database in both cases.
  • Separate direct Ghidra headless inspection on disposable copies reported Variable.getSource() as DEFAULT for the original local and USER_DEFINED for the renamed local. Those are Ghidra's source labels, not proof the user-supplied name is correct.
  • REA refused annotation changes in both selected-project sessions, as documented. The binary and the original and edited source projects' regular-file hashes stayed unchanged during REA's sessions; the binary was not executed. The headless edits were made deliberately only to an owned copy before those sessions.

The current procedure_info contract accurately identifies the database as the origin of each display string; it does not claim to expose the variable's source. This is a representation and analyst-question gap, not proof of incorrect decompilation or that all local-variable information is unavailable elsewhere.

Expected interaction with targets

Read caller-selected existing project copies and binaries with the existing Ghidra static provider; no target execution, new project mutation or arbitrary script execution through REA is proposed.

Boundary details (optional)

Distinguish variable source classification from confidence or source-code truth. Preserve function identity, target/project/profile and exact Ghidra-reported storage, including unknown or composite storage and aliases. Avoid treating a decompiler temporary name or a stack offset as a stable cross-session identity without evidence. Other providers may not supply an equivalent fact.

Options and tradeoffs

Compare extending the existing procedure_info local observations with structured name/type/storage/source fields against a focused bounded variable view. Preserve the current useful description or make an explicit compatibility decision; avoid adding a raw Ghidra API wrapper or treating USER_DEFINED as a verified source fact. Any editing capability and its authority are separate decisions (#8166 and #8165).

Verification available so far

I have a prototype or observed results.

Success criteria and open questions

Exercise default, analysis, imported and user-defined locals where reproducible; unnamed, register, stack, compound and overlapping storage; matching CLI/MCP and converted schemas; and selected-project read-only behavior. Check provenance and target identity after export/import. Determine what constitutes a usable within-function selector before proposing edits. Only the two named projects and stack local above were tested; no agent-selection, cross-provider or broader stability measurement was run.

References

Related #8166 (analyst hypotheses) and #8165 (checkpoint scope). The current Ghidra local projection assembles a display string and database provenance; its consumer schema exposes those two fields.

Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0.

Originally created by @morluto on GitHub (Oct 31, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8314 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related discussion. - [x] I understand the contribution scope must be reviewed before integration; open questions are welcome here. - [x] This discussion does not include credentials, private samples, or sensitive target data. ### Decision needed When an analyst uses a selected Ghidra project, should REA expose structured local-variable identity and Ghidra's reported source alongside the current human-readable local description, so an agent can distinguish a caller-authored label from a default analysis label without parsing text? ### Context and evidence I copied an owned Ghidra 12.1.4 project for a self-built arm64 Mach-O, renamed parameter `record` to `analyst_input_record` and local `local_14` to `analyst_result` using headless Ghidra scripts on the copy, and saved it. In separate REA `b43c329df779708e43ae297f498a844e45d9c923` MCP sessions selecting the original and edited projects read-only: - `procedure_pseudo_code` reflected both names. `inspect_native_api` reported the parameter name and `signature_source: user_defined` for both projects (the original signature was already caller-authored). - `procedure_info.locals` contained the original `undefined4 local_14 @ Stack[-0x14]:4` or edited `undefined4 analyst_result @ Stack[-0x14]:4` as a single `description`, with `provenance: ghidra-function-database` in both cases. - Separate direct Ghidra headless inspection on disposable copies reported `Variable.getSource()` as `DEFAULT` for the original local and `USER_DEFINED` for the renamed local. Those are Ghidra's source labels, not proof the user-supplied name is correct. - REA refused annotation changes in both selected-project sessions, as documented. The binary and the original and edited source projects' regular-file hashes stayed unchanged during REA's sessions; the binary was not executed. The headless edits were made deliberately only to an owned copy before those sessions. The current `procedure_info` contract accurately identifies the database as the origin of each display string; it does not claim to expose the variable's source. This is a representation and analyst-question gap, not proof of incorrect decompilation or that all local-variable information is unavailable elsewhere. ### Expected interaction with targets Read caller-selected existing project copies and binaries with the existing Ghidra static provider; no target execution, new project mutation or arbitrary script execution through REA is proposed. ### Boundary details (optional) Distinguish variable source classification from confidence or source-code truth. Preserve function identity, target/project/profile and exact Ghidra-reported storage, including unknown or composite storage and aliases. Avoid treating a decompiler temporary name or a stack offset as a stable cross-session identity without evidence. Other providers may not supply an equivalent fact. ### Options and tradeoffs Compare extending the existing `procedure_info` local observations with structured name/type/storage/source fields against a focused bounded variable view. Preserve the current useful description or make an explicit compatibility decision; avoid adding a raw Ghidra API wrapper or treating `USER_DEFINED` as a verified source fact. Any editing capability and its authority are separate decisions (#8166 and #8165). ### Verification available so far I have a prototype or observed results. ### Success criteria and open questions Exercise default, analysis, imported and user-defined locals where reproducible; unnamed, register, stack, compound and overlapping storage; matching CLI/MCP and converted schemas; and selected-project read-only behavior. Check provenance and target identity after export/import. Determine what constitutes a usable within-function selector before proposing edits. Only the two named projects and stack local above were tested; no agent-selection, cross-provider or broader stability measurement was run. ### References Related #8166 (analyst hypotheses) and #8165 (checkpoint scope). The [current Ghidra local projection](https://github.com/morluto/rea/blob/b43c329df779708e43ae297f498a844e45d9c923/bridge/ghidra/ReaGhidraBridge.java#L3883-L3901) assembles a display string and database provenance; its [consumer schema](https://github.com/morluto/rea/blob/b43c329df779708e43ae297f498a844e45d9c923/src/ghidra/GhidraFunctionValues.ts#L146-L153) exposes those two fields. Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0.
Author
Owner

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

CLI parity control

On the edited selected project, real CLI rea function, rea decompile, and rea inspect-native-api all succeeded. Decompile and API normalized results matched the prior MCP results; the function dossier retained analyst_result only in the same display-string local representation. rea annotate-native-function correctly refused the selected read-only project. The target and project regular-file hashes stayed unchanged across the CLI runs and the target was not executed.

The CLI refusal gave a generic target-selection headline even though its details identified the read-only project mode; #8315 tracks that separate recovery-message issue. This confirms one CLI/MCP and one project case, not cross-provider variable identity or runtime behavior.

<!-- gh-comment-id:6544680326 --> @morluto commented on GitHub (Oct 31, 2026): ### CLI parity control On the edited selected project, real CLI `rea function`, `rea decompile`, and `rea inspect-native-api` all succeeded. Decompile and API normalized results matched the prior MCP results; the function dossier retained `analyst_result` only in the same display-string local representation. `rea annotate-native-function` correctly refused the selected read-only project. The target and project regular-file hashes stayed unchanged across the CLI runs and the target was not executed. The CLI refusal gave a generic target-selection headline even though its details identified the read-only project mode; [#8315](https://github.com/morluto/rea/issues/8315) tracks that separate recovery-message issue. This confirms one CLI/MCP and one project case, not cross-provider variable identity or runtime behavior.
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#6538
No description provided.