Rust reimplementation of the xenia Xbox 360 emulator targeting reverse- engineering and preservation, initially scoped to Project Sylpheed. Includes: - XEX2 loader (LZX decompression, AES decryption, PE parsing) - XISO / XGD2 disc image VFS - PPC interpreter with 200+ opcodes and VMX128 decoding - Static analyzer: functions, cross-references, labels, asm + SQLite output - HLE kernel covering the xboxkrnl/xam subset used by Sylpheed init - Debugger with in-memory and SQLite-backed execution tracing - `xenia-rs` CLI with extract/dis/exec commands that produce cumulative, superset SQLite databases and opt-in instruction/import/branch traces Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
133 lines
5.2 KiB
Markdown
133 lines
5.2 KiB
Markdown
# xenia-rs
|
|
|
|
Rust reimplementation of the Xbox 360 emulator [xenia](https://github.com/xenia-project/xenia),
|
|
focused on **reverse-engineering and preservation** rather than full-speed play.
|
|
The initial target is *Project Sylpheed — Arc of Deception*; getting the title
|
|
disassembled, traced, and far enough into its init path to understand its engine.
|
|
|
|
Heavy cross-reference to [xenia-canary](https://github.com/xenia-canary/xenia-canary)
|
|
for CPU context setup, kernel export behavior, and XEX loading semantics.
|
|
|
|
## Status
|
|
|
|
- **XEX loader** — XEX2 header parsing, LZX decompression, AES decryption, PE section parsing.
|
|
- **VFS / XISO** — XGD2 dual-layer disc images (with the 0x0FD90000 partition offset).
|
|
- **PPC interpreter** — 200+ opcodes, PowerPC 32/64-bit GPR/FPR, VMX128 decoding.
|
|
- **Static analyzer** — function discovery (prolog/epilog heuristics), cross-references, labels,
|
|
save/restore helper detection, assembly text + SQLite database output.
|
|
- **Kernel HLE** — minimal subset driving Project Sylpheed: ~170 xboxkrnl + xam exports
|
|
(critical sections, events, TLS, virtual memory, Vd stubs, XAM input/user/content).
|
|
- **Debugger** — in-memory step/break, SQLite execution + import-call + branch tracing.
|
|
|
|
Not yet: GPU (xenos/xe-shader), APU audio, HID, kernel scheduler, full threading,
|
|
exception delivery.
|
|
|
|
## Workspace
|
|
|
|
```
|
|
crates/
|
|
xenia-types # shared primitive types, bitflags
|
|
xenia-memory # guest memory, paged allocator, page table
|
|
xenia-cpu # PPC decoder, interpreter, context
|
|
xenia-xex # XEX2 loader, PE parser, LZX, AES
|
|
xenia-vfs # XISO / disc-image reader
|
|
xenia-kernel # HLE kernel state, exports, XAM
|
|
xenia-gpu # (stub) Xenos command processor
|
|
xenia-apu # (stub) XAudio
|
|
xenia-hid # (stub) XInput
|
|
xenia-debugger # in-memory trace, breakpoints, step modes
|
|
xenia-analysis # function/xref analysis, assembly formatter, SQLite DbWriter
|
|
xenia-app # `xenia-rs` CLI binary
|
|
```
|
|
|
|
## CLI
|
|
|
|
Build:
|
|
```sh
|
|
cargo build --release
|
|
```
|
|
|
|
The binary `xenia-rs` accepts XEX2 files or ISO / XISO disc images as input
|
|
(the loader auto-detects discs and extracts `default.xex`).
|
|
|
|
### `info` / `browse` / `disasm`
|
|
|
|
Quick header / disc / first-N-instructions inspection. See `--help`.
|
|
|
|
### `extract` — unpack PE + metadata
|
|
|
|
```sh
|
|
xenia-rs extract <xex-or-iso> [-o <out-dir>] [--db <sqlite-path>]
|
|
```
|
|
|
|
Writes `<name>.pe` (decompressed/decrypted PE image) and `<name>.xex.json`
|
|
(header metadata). With `--db`, also emits a SQLite database containing the
|
|
**base tables**: `metadata`, `sections`, `imports`.
|
|
|
|
### `dis` — full disassembly
|
|
|
|
```sh
|
|
xenia-rs dis <xex-or-iso> [-o <asm-file>] [--db <sqlite-path>] [--quiet]
|
|
```
|
|
|
|
Runs function + cross-reference analysis and produces:
|
|
- assembly text to stdout or `-o <file>` (unless `--quiet`)
|
|
- optional SQLite DB with the **base tables + disasm tables**:
|
|
`functions`, `labels`, `instructions`, `xrefs`
|
|
|
|
### `exec` — interpret with tracing
|
|
|
|
```sh
|
|
xenia-rs exec <xex-or-iso> [-n <max-instrs>] [--db <sqlite-path>]
|
|
[--trace-instructions] [--trace-imports] [--trace-branches]
|
|
```
|
|
|
|
Loads the title, initializes CPU state per xenia-canary, intercepts import
|
|
thunks with HLE kernel calls, and interprets from the entry point. Without
|
|
`-n`, runs until halt/fault. With `--db`, produces a DB that is a **superset
|
|
of `dis --db`** plus opt-in trace tables:
|
|
|
|
| flag | table | rows |
|
|
|-------------------------|----------------|---------------------------------------------------------|
|
|
| `--trace-instructions` | `exec_trace` | one row per interpreted instruction (PC, r3/r4, LR, SP) |
|
|
| `--trace-imports` | `import_calls` | one row per kernel/XAM call (module, ordinal, args) |
|
|
| `--trace-branches` | `branch_trace` | taken branches classified as `call`/`return`/`jump`/`branch` |
|
|
|
|
### Cumulative DB layering
|
|
|
|
Each command's DB is a superset of the previous. A single
|
|
`xenia-rs exec <iso> --db full.db --trace-instructions --trace-imports --trace-branches`
|
|
produces the full picture in one pass — base tables, complete static
|
|
disassembly, and runtime traces correlatable by address/cycle.
|
|
|
|
## Performance knobs
|
|
|
|
- **`XENIA_DB_BATCH_SIZE`** — rows per streaming commit / trace-buffer flush
|
|
(default `100_000`). Lower values reduce memory use; higher values reduce
|
|
fsync overhead on slow disks.
|
|
|
|
The DB writer uses `journal_mode=OFF`, `synchronous=OFF`, `locking_mode=EXCLUSIVE`
|
|
and commits in batches; no `ANALYZE` is run at finalize. Indices are created
|
|
after bulk insertion with progress messages.
|
|
|
|
## Example queries
|
|
|
|
```sql
|
|
-- Top 20 kernel functions called during early init
|
|
SELECT name, COUNT(*) FROM import_calls GROUP BY name ORDER BY 2 DESC LIMIT 20;
|
|
|
|
-- All basic-block leaders (targets of taken branches) not already labelled
|
|
SELECT DISTINCT bt.target
|
|
FROM branch_trace bt LEFT JOIN labels l ON l.address = bt.target
|
|
WHERE l.address IS NULL;
|
|
|
|
-- Correlate a traced call site with its static disassembly
|
|
SELECT et.cycle, i.disasm, i.ext_disasm
|
|
FROM exec_trace et JOIN instructions i ON i.address = et.address
|
|
WHERE et.address = 0x824AB748 ORDER BY et.cycle;
|
|
```
|
|
|
|
## License
|
|
|
|
BSD-3-Clause, matching upstream xenia.
|