Files
rea/docs/ghidra-provider.md

13 KiB

Ghidra provider semantics

REA imports one target into an ephemeral Ghidra database. Linux/macOS support read-only analysis and atomic function-name/entry-comment edits; Windows P0 is read-only. GUI controls and persistent database mutation are unavailable. Executable bytes remain unchanged.

Use installation for supported hosts, prerequisites, configuration, startup deadlines, resource controls, and cleanup recovery. Windows P0 has its own admission and lifecycle boundary; NativeAOT recovery is an optional, separately verified extension. Check the release boundary when using npm.

Provider selection and profile identity follow MCP contracts. One deep provider stays bound to the target; runtime failure never selects another provider automatically. The contracts below describe Ghidra observations, not equivalence with another engine's pseudocode or analysis database.

Admitted inventory semantics

Concern Ghidra contract
Program identity One analyzeHeadless import produces exactly one Program; list_documents therefore returns exactly one name.
Addresses Default memory uses lowercase 0x hexadecimal. Non-default and external spaces use <percent-encoded-space>:0x<hex> and remain round-trippable. The handshake commits image base and default address-space name.
Symbols list_names includes address-bearing memory and external symbols, including dynamic symbols, while excluding variable and no-address namespace records. Each item reports primary, dynamic, external, symbol type, and source facts.
Procedures Both non-external and external functions are listed. A local thunk remains distinct from its resolved target; exact and qualified name lookup fails on ambiguity rather than guessing.
Strings Only Ghidra-defined string Data is observed. Items report charset, byte length, and whether a required null terminator is missing. The API cannot distinguish a present terminator from fixed/Pascal layouts when no terminator is missing, so that state is named present_or_not_required.
Memory Memory-block end addresses are exclusive. Read/write/execute, initialization, overlay, address space, and image base are direct Ghidra observations.
Inventory Procedure, symbol, and string listings plus searches return the complete matching collection in one response; callers do not provide offsets or result-count limits.
Search Literal and Java-regex searches scan the complete immutable inventory and return all matching entries inline. Search waits for a reply or caller cancellation; there are no caller-supplied offsets or result-count limits.
Analysis state The socket is exposed only after default auto-analysis completes. Established operations wait for their reply or caller cancellation; there is no fixed response-size ceiling.

Admitted function-analysis semantics

Concern Ghidra contract
Decompiler lifetime One persistent DecompInterface is opened for the imported Program and disposed during bridge shutdown. Native decompilation has no fixed per-function deadline. External functions or functions without bodies return null; cancellation and native failure remain distinct.
Serialization A FIFO sends one Program request at a time. Caller cancellation removes queued work promptly and is passed to active socket waits. This is an adapter safety commitment, not a claim that every Ghidra API is thread-safe.
Function identity Every function result carries the entry address and Ghidra FunctionManager classification for external, thunk, and resolved thunk target. These are observations, not proof that unresolved targetless calls have been recovered.
Assembly and pseudocode Assembly is complete Ghidra Listing text; pseudocode is Ghidra decompiler output. Neither is original source, and cross-provider comparison never treats Hopper and Ghidra text as equal or unequal semantic facts.
Instruction fast path read_function_instructions returns every raw Listing instruction for the requested function without invoking the decompiler or whole-program name/string inventories.
Calls and references Callers/callees contain only resolved functions. Reference edges preserve exact ReferenceManager type and call/jump/data/read/write/indirect/computed/conditional/terminal/external facts. Targetless computed flow remains unknown. Synthetic entry-point references without actionable memory sources are omitted explicitly.
CFG Dossiers use BasicBlockModel and retain only non-call successors inside the function body. CFG topology is address-normalized for comparison; provider-specific block construction remains a declared difference.
P-code value flow Function dossiers include up to 3,000 high-p-code operations, at most 64 inputs per operation, and 12,000 def-use edges. Results identify memory reads/writes, branches, and calls by p-code opcode, and mark decompiler-dead operations. Large results report truncation, an omitted-operation lower bound, and known omitted-input/edge counts. The dossier is an intra-function graph; trace_native_values composes derived parameter/argument and return/output dependencies across resolved calls. It does not resolve memory aliasing, call side effects, runtime behavior, persistent state, or business meaning.
Result extent Function instruction scans and native API boundary observations remain complete. P-code flow is the explicit bounded exception; its count fields distinguish exact retained counts from lower-bound or known-omitted counts. Caller cancellation and provider failures remain distinct.

npm run verify:ghidra compiles the versioned C oracle into debug and stripped host-native targets (x86-64/AArch64 ELF on Linux or Mach-O on macOS), plus a native DWARF 4 type-layout object. It proves the admitted operations, external functions, resolved thunks, exports, stripped-name behavior, direct and targetless indirect calls, typed references, strings/xrefs, multi-block CFG, bounded p-code def-use/effect links, semantic enhanced workflows, cancellation, startup deadlines, serialized concurrency, malformed-target rejection, profile identity, and process/project cleanup against real Ghidra 12.1.4. Unit fixtures separately cover startup deadlines, process exit, queued cancellation, and malformed wire output.

npm run verify:ghidra:cross-format adds AArch64 ELF, x86-64 PE, and x86-64 Mach-O target coverage. It requires clang, LLD, and lld-link; set REA_CLANG, REA_LLD, or REA_LLD_LINK to select them. The verifier checks these tools before compilation. Keeping this matrix separate lets Linux host/provider acceptance run with only the host compiler.

npm run verify:ghidra:windows checks source-owned native x86-64 PE applications; -- --x86 selects x86 and -- --dll selects DLLs, and the flags can be combined. These lanes check all 25 read-only operations, target/snapshot/import SHA-256 linkage, and project, endpoint, process, and runtime cleanup. The independent native lane checks DACLs, handle admission, cancellation, and Job Object lifecycle. npm run verify:ghidra:windows:package packs and installs REA into an isolated prefix, then checks ordinary-user CLI/MCP operations against canonical contracts. It accepts the same architecture and DLL flags and verifies the selected PE role in the analysis profile. All lanes require matching native controls; package startup alone establishes only package compatibility.