warden export converts the knowledge base for a given version into one of six deliverable
formats. All six are deterministic: given the same KB state, the output is byte-identical
on every run. That means they diff cleanly in git and compose naturally with CI pipelines.
The six formats
headers
A C header of recovered function prototypes. Use this to feed names into a downstream
C/C++ toolchain or as a human-readable symbol sheet.
pseudo
Per-function listings: the recovered name, type signature, agent summary, provenance, and
lifted pseudo-C (requires the original
.wasm to be present; falls back to a mnemonic count
otherwise). Use this for manual review.kb-text
A columnar, stable text dump of every symbol (index, stable id, lock flag, provenance,
confidence, and name), sorted by function index. The primary format for committing alongside
source and reading diffs across versions.
ghidra
A Python script that pushes recovered names back into a Ghidra project. Run it from Ghidra’s
Python console after loading the same module.
csv
A neutral CSV file of every defined function: index, stable id, name, type, provenance, and
confidence. Edit it in any spreadsheet or script and import it back with
warden import.json
The same content as
csv but in JSON array form, one object per function. Useful when
automating annotation workflows or feeding into IDA scripts.Basic usage
--out <file> to write to a file instead.
--db selects the project database when it is not the default warden.db:
Format details
headers
Emits a C header wrapped in an include guard. Each defined function gets a comment line with
its function index, Wasm type signature, provenance, and confidence score, followed by a
skeleton declaration. Only defined (non-imported) functions are emitted; imports are excluded.
The prototypes are stubs. Parameter types are not yet recovered from the Wasm type signature.
The comment carries the full signature string so you can fill it in. This is a known limitation;
proper C prototype reconstruction is on the roadmap.
pseudo
Emits a readable listing of every defined function with its recovered name, type signature,
agent-generated summary, and provenance/confidence. When the original .wasm path is still
accessible in the KB, instruction mnemonics are included inline; otherwise the listing notes
the instruction count without disassembly.
kb-text
A columnar dump of every function in index order (including imports) with a fixed-width
layout designed for git diff. The format is:
index (Wasm function index), stable_id (first 16 hex chars of the full stable
identity hash), lk (L when the symbol is locked; space otherwise), provenance,
confidence, name (dash when unnamed).
When to use it: source-controlled annotation snapshots, CI regression detection, sharing the
current KB state without giving someone access to the database.
ghidra
Emits a Python script for Ghidra’s built-in scripting console. The script iterates over every
defined function that has a recovered name and calls fn.setName(name, SourceType.USER_DEFINED)
to apply it.
.wasm is the same binary that WARDEN ingested for that version.
Built-in decompiler
Thewarden.lift module contains a pure-Python stack-machine lifter that re-folds Wasm
stack operations back into readable pseudo-C. It handles the integer subset comprehensively
including infix arithmetic, memory loads and stores, local and global variables, and function calls.
It also renders f32 and f64 arithmetic, comparisons, and constants as readable expressions, so
floating-point code reads the same way the integer subset does. Float min, max, and copysign render
as named calls (fminf, fmax, copysign); unary ops render as name(x) (and neg as -(x));
f32.const and f64.const decode their raw IEEE-754 bytes to clean literals like 0.5; and
conversions render as a C cast ((float)x) or a named call. It degrades gracefully for anything
unmodeled by emitting a /* mnemonic */ comment and an opaque temporary instead of crashing.
samples.float_demo() to lift the float sample interactively.
Structured control flow
The lifter now reconstructs structured control flow, not just straight-line code. WebAssembly’sblock, loop, and if constructs are already well-nested, so the lifter builds a control-flow
tree and emits proper C constructs from it:
- if/else. Result-typed ifs assign each branch into a fresh temp so the value is available after the closing brace.
- while loops with break/continue. The common
block+loopidiom renders as a cleanwhile (1) { ... if (cond) break; ... }with no goto. A labeled goto is the fallback for control flow that does not fit the innermost-loop/break pattern, so output is always correct. - switch for
br_table. Multi-way branches become aswitchstatement with a case per target and adefault.
/* mnemonic */ comment and pushes an opaque temp.
The lifter never crashes; every function produces valid pseudo-C.
Two samples ship with WARDEN and illustrate both constructs:
samples.control_flow() to lift them interactively.
How --format pseudo uses it
When you run warden export --format pseudo and the original .wasm is available, the
exporter now calls the lifter instead of dumping raw instruction mnemonics. Each function
block contains a proper pseudo-C body:
.wasm is not on disk fall back to the previous mnemonic-count note; the
switch is automatic.
Targeting a single function
Usewarden lift to decompile one function by name without running a full export:
--index N flag is useful when multiple functions share a recovered name across an
ambiguous KB state.
Python API
lift_module skips imports (they have no body) and concatenates in function-index order so
the result diffs cleanly across builds.
The lifter covers the integer, floating-point, and control-flow subset that
Emscripten-compiled C/C++ produces in practice.
f32 and f64 arithmetic, comparisons,
and constants render as readable expressions, the same as the integer subset. SIMD (v128)
opcodes are not modeled and degrade to a single /* v128 op 0xNN */ comment with an opaque
temp, so a SIMD-using function still lifts without a crash or a stack desync. The output is
always valid pseudo-C, never a crash or a partial file.Round-trip bridge
warden export --format csv|json and the new warden import command deliver
annotations that round-trip. Export a version’s names to a neutral file, edit
them in Ghidra, IDA, or a text editor, and import the result back into the knowledge base.
Exporting to CSV or JSON
Two new format values are accepted bywarden export:
index, stable_id, name, type, provenance, confidence. The
stable_id column is the key used on import. The type column carries the Wasm type
signature and is round-tripped as-is.
The Python API:
Importing back
After editing the file, import it with the newwarden import command:
How identity and the economy interact
The bridge resolves each row to a function bystable_id first. This means a name recovered
against one build lands on the same logical function in a later build, even when the function
index shifts. If the stable_id is absent or unrecognized, the bridge falls back to the
index column.
Writes go through the same provenance/confidence economy as every other annotation source.
An import never clobbers a higher-authority annotation. For example, a human 1.00 name
already in the KB is not overwritten by an oracle 0.94 row from the file. Pass
--provenance human to assert human authority for all rows in the file.
The existing
warden export --format ghidra script is the push side of the Ghidra
round-trip. The CSV/JSON formats are the neutral pull side: they work with any tool that
can read a spreadsheet or JSON file, including IDA’s name-import scripts and manual
annotation sessions.Format details
HTML report
warden report writes a self-contained HTML file: no server, no CDN, no build step.
Everything is inlined so the file opens from any clone with a double-click, and the output
is deterministic (same KB state in, byte-identical HTML out) so it diffs cleanly in git.
What the report contains
The heatmap color key:
Python API
module=<Module> to either function if you have the parsed .wasm on hand; it is
optional and reserved for future inline disassembly views. The report is fully driven by
the KB without it.
Comparing across versions
Because all formats are deterministic, you can snapshot them at each version and use standard diff tooling to review what changed:stable_id and annotations appear as unchanged lines. New functions,
dropped functions, and any confidence or provenance changes are visible immediately.
For a richer semantic changelog (which functions are new, removed, carried over, or only
partially matched), use
warden diff before exporting. The diff engine
runs the same fingerprinting that export relies on, so the two views are consistent.