Co-authored-by: Nilton Constantino <nilton.constantino@visma.com> Reviewed-on: #8
66 lines
2.4 KiB
Rust
66 lines
2.4 KiB
Rust
use crate::common::symbols::{DebugSymbol, SymbolsFile};
|
|
use anyhow::{Context, Result};
|
|
use prometeu_bytecode::disasm::disasm;
|
|
use prometeu_bytecode::BytecodeLoader;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
pub struct Artifacts {
|
|
pub rom: Vec<u8>,
|
|
pub debug_symbols: Vec<DebugSymbol>,
|
|
pub lsp_symbols: SymbolsFile,
|
|
}
|
|
|
|
impl Artifacts {
|
|
pub fn new(rom: Vec<u8>, debug_symbols: Vec<DebugSymbol>, lsp_symbols: SymbolsFile) -> Self {
|
|
Self { rom, debug_symbols, lsp_symbols }
|
|
}
|
|
|
|
pub fn export(&self, out: &Path, emit_disasm: bool, emit_symbols: bool) -> Result<()> {
|
|
// 1. Save the main binary
|
|
fs::write(out, &self.rom).with_context(|| format!("Failed to write PBC to {:?}", out))?;
|
|
|
|
// 2. Export symbols for LSP
|
|
if emit_symbols {
|
|
let symbols_path = out.with_file_name("symbols.json");
|
|
let symbols_json = serde_json::to_string_pretty(&self.lsp_symbols)?;
|
|
fs::write(&symbols_path, symbols_json)?;
|
|
}
|
|
|
|
// 3. Export human-readable disassembly for developer inspection
|
|
if emit_disasm {
|
|
let disasm_path = out.with_extension("disasm.txt");
|
|
|
|
// Extract the actual bytecode (stripping the industrial PBS\0 header)
|
|
let rom_to_disasm = if let Ok(module) = BytecodeLoader::load(&self.rom) {
|
|
module.code
|
|
} else {
|
|
self.rom.clone()
|
|
};
|
|
|
|
let instructions = disasm(&rom_to_disasm).map_err(|e| anyhow::anyhow!("Disassembly failed: {}", e))?;
|
|
|
|
let mut disasm_text = String::new();
|
|
for instr in instructions {
|
|
// Find a matching symbol to show which source line generated this instruction
|
|
let symbol = self.debug_symbols.iter().find(|s| s.pc == instr.pc);
|
|
let comment = if let Some(s) = symbol {
|
|
format!(" ; {}:{}", s.file, s.line)
|
|
} else {
|
|
"".to_string()
|
|
};
|
|
|
|
let operands_str = instr.operands.iter()
|
|
.map(|o| format!("{:?}", o))
|
|
.collect::<Vec<_>>()
|
|
.join(" ");
|
|
|
|
disasm_text.push_str(&format!("{:08X} {:?} {}{}\n", instr.pc, instr.opcode, operands_str, comment));
|
|
}
|
|
fs::write(disasm_path, disasm_text)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|