--- name: xenia-rs CLI Reference description: Complete CLI commands, arguments, and environment variables for the xenia-rs tool — update this when CLI changes type: project originSessionId: 08576735-74b4-4180-994a-2eb93dc60997 --- > **Update trigger**: Whenever the xenia-rs CLI changes (new commands, flags, env vars), update this file and the MEMORY.md index entry. Last documented: 2026-04-22 (added `exec --halt-on-deadlock` + `XENIA_HALT_ON_DEADLOCK` env var for deadlock investigation — bypasses the force-wake recovery path so the ctx snapshot survives). ## Binary `xenia-rs` — Xbox 360 XEX/XISO reverse-engineering toolchain **CLI framework**: Clap 4.x with derive macros **Entry point**: `xenia-rs/crates/xenia-app/src/main.rs` **Observability module**: `xenia-rs/crates/xenia-app/src/observability.rs` --- ## Global flags (apply to every subcommand) | Flag | Type | Effect | |------|------|--------| | `--log-json` | bool | Force JSON on the console fmt layer (default is compact text, stderr) | | `--log-file ` | path | Additionally write logs to file via non-blocking appender. `.json` extension → JSON formatter; else text | | `--log-filter ` | env-filter | Overrides `RUST_LOG`. Precedence: `--log-filter` > `RUST_LOG` > default (`warn` for `exec --quiet`, else `info`) | | `--trace-chrome ` | path | Emit Chrome `about:tracing` JSON of all spans (uses `tracing-chrome`). Loadable in `chrome://tracing` / Perfetto | | `--profile ` | path | Start pprof sampling profiler at 100 Hz. `.svg` → flamegraph; `.pb` → pprof protobuf. Requires `profiling` Cargo feature (on by default) | **Cargo features** on `xenia-app`: - `profiling` (default): pulls `pprof = { features = ["flamegraph", "protobuf-codec"] }`. Disable with `--no-default-features` for minimal release builds; `--profile` then fails at startup with a clear error. --- ## Commands ### `disasm` — Disassemble XEX from entry point ``` xenia-rs disasm [-n ] ``` | Arg | Type | Default | Description | |-----|------|---------|-------------| | `path` | String (positional) | — | Path to XEX file | | `-n, --count` | usize | 64 | Number of instructions to disassemble | --- ### `exec` — Load and execute XEX with tracing ``` xenia-rs exec [-n ] [--ips-limit ] [--db ] [--trace-instructions] [--trace-imports] [--trace-branches] [--quiet] [--ui] [--halt-on-deadlock] ``` | Arg | Type | Default | Description | |-----|------|---------|-------------| | `path` | String (positional) | — | Path to XEX file | | `-n, --max-instructions` | Option\ | none | Max instructions before stop (unlimited if omitted) | | `--ips-limit` | Option\ | none | Throttle to N instructions per second (unlimited if omitted). Check runs once per scheduler round at `run_execution`'s outer loop — anchor is `Instant::now()` at function entry | | `--db` | Option\ | none | SQLite DB path; includes full static analysis + opt-in trace tables | | `--trace-instructions` | bool flag | false | Log each instruction to `exec_trace` table | | `--trace-imports` | bool flag | false | Log kernel/import calls to `import_calls` table | | `--trace-branches` | bool flag | false | Log taken branches to `branch_trace` table | | `--quiet` | bool flag | false | Suppress banners, kernel logs, register dump | | `--ui` | bool flag | false | Open winit+wgpu window for dynamic analysis; backs XamInputGetState with gilrs; presents guest frontbuffer on VdSwap; CPU runs on worker thread. HUD shows swap count + last frontbuffer addr + pad state. Phase 1: no PM4/shader execution, so the frontbuffer is typically black for real games — HUD remains live. | | `--halt-on-deadlock` | bool flag | false | At the hard-deadlock branch in `run_execution` (all live HW threads `Blocked` on handle waits, no pending timer), emit a per-HW-slot `warn!` with `tid`/`state`/`pc`/`lr`/`sp` and break instead of force-waking waiters with `STATUS_TIMEOUT`. Increments `scheduler.deadlock_halts` metric; sets the UI shutdown flag so the window closes alongside the worker. Default is force-wake (preserved probe-run behaviour — counts as `scheduler.deadlock_recoveries`). Also settable via `XENIA_HALT_ON_DEADLOCK=1`. | --- ### `browse` — Browse XISO disc image contents ``` xenia-rs browse ``` | Arg | Type | Default | Description | |-----|------|---------|-------------| | `path` | String (positional) | — | Path to XISO file | --- ### `info` — Display XEX header information ``` xenia-rs info ``` | Arg | Type | Default | Description | |-----|------|---------|-------------| | `path` | String (positional) | — | Path to XEX file | --- ### `extract` — Extract PE image and metadata from XEX ``` xenia-rs extract [-o ] [--db ] ``` | Arg | Type | Default | Description | |-----|------|---------|-------------| | `path` | String (positional) | — | Path to XEX or ISO file | | `-o, --output` | Option\ | input dir | Output directory | | `--db` | Option\ | none | SQLite DB; writes `metadata`, `sections`, `imports` tables | --- ### `dis` — Full disassembly with function detection and xrefs ``` xenia-rs dis [-o ] [--db ] [--quiet] ``` | Arg | Type | Default | Description | |-----|------|---------|-------------| | `path` | String (positional) | — | Path to XEX or ISO file | | `-o, --output` | Option\ | stdout | Output .asm file | | `--db` | Option\ | none | SQLite DB; includes extract tables + `functions`, `labels`, `instructions`, `xrefs` | | `--quiet` | bool flag | false | Suppress assembly text output (DB-only mode) | --- ### `check` — Deterministic run digest + golden-diff regression detector (P8) ``` xenia-rs check [-n ] [--out ] [--expect ] ``` | Arg | Type | Default | Description | |-----|------|---------|-------------| | `path` | String (positional) | — | Path to XEX or ISO file | | `-n, --max-instructions` | u64 | 2_000_000 | Instructions to execute before computing the digest | | `--out` | Option\ | stdout | Write the 14-field JSON digest to this path | | `--expect` | Option\ | none | Golden digest JSON; byte-for-byte (trimmed) diff against the run's output. Exits non-zero on mismatch with `expected vs actual` on stderr | **Digest fields** (stable order, one `u64` per line): `path`, `instructions`, `imports`, `unimpl`, `packets`, `draws`, `swaps`, `resolves`, `unique_render_targets`, `shader_blobs_live`, `interrupts_delivered`, `interrupts_dropped`, `texture_cache_entries`, `texture_decodes`. **Typical use**: Run once on a known-good build → commit the output as `run.digest.json`. CI re-runs `xenia-rs check … --expect run.digest.json`; non-zero exit blocks the PR on drift. --- ## Environment Variables ### `XENIA_DB_BATCH_SIZE` - **Source**: `xenia-rs/crates/xenia-analysis/src/db.rs` (lines 35-45) - **Type**: u64 - **Default**: `100_000` - **Validation**: Must be > 0; invalid values fall back to default - **Effect**: Rows per streaming commit / trace buffer flush. `import_calls` always flushes at 1,000 (not configurable). ### `RUST_LOG` - **Source**: standard `tracing-subscriber` env filter - **Default behavior**: `"warn"` when `exec --quiet`, otherwise `"info"` - **Override**: Set to any tracing filter string (e.g. `debug`, `xenia_analysis=trace`) - **Note**: `--log-filter` takes precedence over `RUST_LOG`. ### `XENIA_FAKE_PAD` - **Source**: `xenia-rs/crates/xenia-ui/src/input.rs` (`fake_pad_policy`) - **Default**: enabled (simulated pad when no physical controller) - **Disable with**: `XENIA_FAKE_PAD=0` (or `false` / `off`) - **Effect**: when no gilrs pad is attached, `XamInputGetState` still returns `STATUS_SUCCESS` with an all-zero `X_INPUT_STATE` so games don't bail with `ERROR_DEVICE_NOT_CONNECTED`. Set to `0` to get truthful "no controller" reporting. ### `XENIA_SCHED_ORDER` / `XENIA_SCHED_SEED` - **Source**: `xenia-rs/crates/xenia-cpu/src/scheduler.rs` (`OrderMode::from_env`) - **Default**: fixed 0..=5 - **Effect**: `random` (with optional u64 `XENIA_SCHED_SEED`) shuffles round order for fuzzing thread interleavings. ### `XENIA_HALT_ON_DEADLOCK` - **Source**: `xenia-rs/crates/xenia-app/src/main.rs` (resolved at the top of `run_execution`) - **Values**: `1` or `true` (case-insensitive) to enable; anything else = disabled - **Default**: disabled (force-wake waiters with `STATUS_TIMEOUT`, increment `scheduler.deadlock_recoveries`) - **Effect**: equivalent to `exec --halt-on-deadlock`. OR'd with the flag — either source is sufficient to trip the halt path. Use from shells / recipes without rewiring CLI args. ### `RUST_LOG_SPAN_EVENTS` - **Source**: parsed by `observability::parse_span_events` - **Values**: `full | close | active | enter | exit | new` (anything else = none) - **Effect**: Controls the `FmtSpan` setting on fmt layers. `close` is the most useful — every span emits a line with `time.busy`/`time.idle` elapsed, giving per-phase timing in the console without reading a Chrome trace. --- ## Database Table Layering | Command | Tables | |---------|--------| | `extract --db` | `metadata`, `sections`, `imports` | | `dis --db` | above + `functions`, `labels`, `instructions`, `xrefs` | | `exec --db` | above + `exec_trace`*, `import_calls`*, `branch_trace`* | *Only written when corresponding `--trace-*` flag is passed to `exec`. **Why:** Cumulative schema lets analysis tools query across all levels without joining separate DBs. **How to apply:** When suggesting DB workflows, recommend the appropriate command tier for the user's analysis goal.