gbf_core/
lib.rs

1#![deny(missing_docs)]
2#![feature(error_generic_member_access)]
3#![feature(backtrace_frames)]
4
5//! This crate provides basic block definitions, function definitions, module definitions,
6//! graph definitions, instruction definitions, opcode definitions, and operand definitions.
7
8use bytecode_loader::{BytecodeLoaderBuilder, BytecodeLoaderError};
9
10/// This module contains basic block definitions and operations.
11pub mod basic_block;
12/// This module reads bytecode from a reader and disassembles it.
13pub mod bytecode_loader;
14/// This module contains the logic to visualize the control flow graph of a module.
15pub mod cfg_dot;
16/// Decompiler module
17pub mod decompiler;
18/// This module contains the definition of a function.
19pub mod function;
20/// This module contains the definition of Graal IO.
21pub mod graal_io;
22/// This module contains the definition of an instruction.
23pub mod instruction;
24/// This module contains the definition of a module.
25pub mod module;
26/// This module contains the definition of an opcode.
27pub mod opcode;
28/// This module contains the definition of an operand.
29pub mod operand;
30/// This module contains utility functions and types.
31pub mod utils;
32
33/// Disassemble bytecode using a reader.
34///
35/// # Arguments
36/// - `reader`: The reader to read the bytecode from.
37///
38/// # Returns
39/// - The string representation of the disassembled bytecode.
40///
41/// # Errors
42/// - `BytecodeLoaderError`: An error occurred while loading the bytecode.
43///
44/// # Examples
45/// ```
46/// use gbf_core::disassemble_bytecode;
47///
48/// // read from a file
49/// let reader = std::fs::File::open("tests/gs2bc/simple.gs2bc").unwrap();
50/// let result = disassemble_bytecode(reader).unwrap();
51/// ```
52pub fn disassemble_bytecode<R: std::io::Read>(reader: R) -> Result<String, BytecodeLoaderError> {
53    // create a new bytecode loader builder
54    let loader = BytecodeLoaderBuilder::new(reader).build()?;
55
56    // write a string representation of the bytecode using each instruction in the instructions vec
57    let mut result = String::new();
58    for (index, instruction) in loader.instructions.iter().enumerate() {
59        result.push_str(&format!("{:08x}: {}\n", index, instruction));
60    }
61    Ok(result)
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn test_disassemble() {
70        let reader = std::io::Cursor::new(vec![
71            0x00, 0x00, 0x00, 0x01, // Section type: Gs1Flags
72            0x00, 0x00, 0x00, 0x04, // Length: 4
73            0x00, 0x00, 0x00, 0x00, // Flags: 0
74            0x00, 0x00, 0x00, 0x02, // Section type: Functions
75            0x00, 0x00, 0x00, 0x09, // Length: 9
76            0x00, 0x00, 0x00, 0x00, // Function location: 0
77            0x6d, 0x61, 0x69, 0x6e, // Function name: "main"
78            0x00, // Null terminator
79            0x00, 0x00, 0x00, 0x03, // Section type: Strings
80            0x00, 0x00, 0x00, 0x04, // Length: 4
81            0x61, 0x62, 0x63, 0x00, // String: "abc"
82            0x00, 0x00, 0x00, 0x04, // Section type: Instructions
83            0x00, 0x00, 0x00, 0x0c, // Length: 12
84            0x01, // Opcode: Jmp
85            0xF3, // Opcode: ImmByte
86            0x01, // Operand: 1
87            0x14, // Opcode: PushNumber
88            0xF4, // Opcode: ImmShort
89            0x00, 0x01, // Operand: 1
90            0x15, // Opcode: PushString
91            0xF0, // Opcode: ImmStringByte
92            0x00, // Operand: 0
93            0x1b, // Opcode: PushPi
94            0x07, // Opcode: Ret
95        ]);
96
97        let result = disassemble_bytecode(reader).unwrap();
98
99        assert_eq!(
100            result,
101            "00000000: Jmp 0x1\n\
102            00000001: PushNumber 0x1\n\
103            00000002: PushString abc\n\
104            00000003: Pi\n\
105            00000004: Ret\n"
106        );
107
108        // test failure case
109        let reader = std::io::Cursor::new(vec![0x00, 0x00, 0x00, 0x01]);
110        let result = disassemble_bytecode(reader);
111        assert!(result.is_err());
112    }
113}