Files
xenia-rs/crates/xenia-analysis/build.rs
MechaCat02 c694bb3f43 Initial commit: xenia-rs workspace for Xbox 360 RE
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>
2026-04-16 23:14:56 +02:00

88 lines
3.2 KiB
Rust

//! Build script: parse xenia's xboxkrnl_table.inc and xam_table.inc to generate
//! ordinal->name lookup tables at compile time.
use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;
fn parse_table(path: &Path) -> Vec<(u32, String, String)> {
let content = match fs::read_to_string(path) {
Ok(c) => c,
Err(e) => {
eprintln!("cargo:warning=could not read {}: {}", path.display(), e);
return Vec::new();
}
};
let mut entries = Vec::new();
for line in content.lines() {
let line = line.trim();
// XE_EXPORT(module, 0xNNNNNNNN, Name, kType),
if !line.starts_with("XE_EXPORT(") { continue; }
let inner = match line.strip_prefix("XE_EXPORT(").and_then(|s| s.strip_suffix("),")) {
Some(s) => s,
None => continue,
};
let parts: Vec<&str> = inner.splitn(4, ',').map(|s| s.trim()).collect();
if parts.len() < 4 { continue; }
let module = parts[0].to_string();
let ordinal = match u32::from_str_radix(parts[1].trim_start_matches("0x").trim_start_matches("0X"), 16) {
Ok(n) => n,
Err(_) => continue,
};
let name = parts[2].to_string();
entries.push((ordinal, name, module));
}
entries
}
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest = Path::new(&out_dir).join("ordinals.rs");
let mut f = fs::File::create(&dest).unwrap();
// Locate xenia tables relative to the workspace root
// crates/xenia-analysis/ -> ../../ -> workspace root -> ../xenia-canary/
let manifest = env::var("CARGO_MANIFEST_DIR").unwrap();
let workspace_root = Path::new(&manifest).parent().unwrap().parent().unwrap();
let project_root = workspace_root.parent().unwrap();
let krnl_path = project_root
.join("xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_table.inc");
let xam_path = project_root
.join("xenia-canary/src/xenia/kernel/xam/xam_table.inc");
println!("cargo:rerun-if-changed={}", krnl_path.display());
println!("cargo:rerun-if-changed={}", xam_path.display());
let krnl = parse_table(&krnl_path);
let xam = parse_table(&xam_path);
writeln!(f, "/// Auto-generated from xenia's export tables.").unwrap();
writeln!(f, "pub fn resolve_ordinal(lib: &str, ordinal: u16) -> Option<&'static str> {{").unwrap();
writeln!(f, " match lib {{").unwrap();
// xboxkrnl.exe
writeln!(f, " \"xboxkrnl.exe\" => match ordinal {{").unwrap();
for (ord, name, _) in &krnl {
writeln!(f, " 0x{ord:04X} => Some(\"{name}\"),").unwrap();
}
writeln!(f, " _ => None,").unwrap();
writeln!(f, " }},").unwrap();
// xam.xex
writeln!(f, " \"xam.xex\" => match ordinal {{").unwrap();
for (ord, name, _) in &xam {
writeln!(f, " 0x{ord:04X} => Some(\"{name}\"),").unwrap();
}
writeln!(f, " _ => None,").unwrap();
writeln!(f, " }},").unwrap();
writeln!(f, " _ => None,").unwrap();
writeln!(f, " }}").unwrap();
writeln!(f, "}}").unwrap();
eprintln!("ordinals.rs: {} xboxkrnl + {} xam entries", krnl.len(), xam.len());
}