if_decompiler/glulx/
mod.rs

1/*
2
3Glulx
4=====
5
6Copyright (c) 2021 Dannii Willis
7MIT licenced
8https://github.com/curiousdannii/if-decompiler
9
10*/
11
12use 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    // These could be inside an Option, but we can just set them to Constants if the instruction doesn't store
92    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}