if_decompiler/glulx/
mod.rs1use std::collections::BTreeMap;
13use std::io::Cursor;
14
15use bytes::Buf;
16
17use super::*;
18
19mod disassembler;
20pub mod opcodes;
21
22pub struct GlulxState {
23 pub debug_function_data: Option<BTreeMap<u32, DebugFunctionData>>,
24 pub functions: BTreeMap<u32, Function>,
25 pub ramstart: u32,
26 pub safe_function_overides: Option<Vec<u32>>,
27 pub stop_on_string: bool,
28 pub unsafe_function_overides: Option<Vec<u32>>,
29}
30
31impl GlulxState {
32 pub fn new(debug_function_data: Option<BTreeMap<u32, DebugFunctionData>>, safe_function_overides: Option<Vec<u32>>, stop_on_string: bool, unsafe_function_overides: Option<Vec<u32>>) -> Self {
33 GlulxState {
34 debug_function_data,
35 functions: BTreeMap::default(),
36 ramstart: 0,
37 safe_function_overides,
38 stop_on_string,
39 unsafe_function_overides,
40 }
41 }
42
43 pub fn decompile_rom(&mut self, image: &[u8]) {
44 let edges = self.disassemble(image);
45 self.mark_all_unsafe_functions(edges);
46 }
47
48 pub fn read_addr(&self, image: &[u8], addr: u32) -> u32 {
49 let mut cursor = Cursor::new(image);
50 cursor.set_position(addr as u64);
51 cursor.get_u32()
52 }
53}
54
55impl VirtualMachine for GlulxState {
56 fn get_functions(&self) -> FnvHashMap<u32, FunctionSafety> {
57 let mut res = FnvHashMap::default();
58 for (&addr, function) in &self.functions {
59 res.insert(addr, function.safety);
60 }
61 res
62 }
63
64 fn mark_function_as_unsafe(&mut self, addr: u32) {
65 let function = self.functions.get_mut(&addr).unwrap();
66 if function.safety == FunctionSafety::SafetyTBD {
67 function.safety = FunctionSafety::Unsafe;
68 }
69 }
70}
71
72pub struct Function {
73 pub addr: u32,
74 pub argument_mode: FunctionArgumentMode,
75 pub blocks: BTreeMap<u32, BasicBlock<Instruction>>,
76 pub locals: u32,
77 pub safety: FunctionSafety,
78}
79
80#[derive(Copy, Clone, Debug, PartialEq)]
81pub enum FunctionArgumentMode {
82 Stack,
83 Locals,
84}
85
86pub struct Instruction {
87 pub addr: u32,
88 pub opcode: u32,
89 pub operands: Vec<Operand>,
90 pub branch: Option<BranchTarget>,
91 pub storer: Operand,
93 pub storer2: Operand,
94 pub next: u32,
95}
96
97impl VMInstruction for Instruction {
98 fn addr(&self) -> u32 {
99 self.addr
100 }
101
102 fn does_halt(&self) -> bool {
103 opcodes::instruction_halts(self.opcode)
104 }
105}
106
107#[derive(Copy, Clone, Debug)]
108pub enum Operand {
109 Constant(u32),
110 Memory(u32),
111 Stack,
112 Local(u32),
113 RAM(u32),
114}