gbf_core/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#![deny(missing_docs)]

//! This crate provides basic block definitions, function definitions, module definitions,
//! graph definitions, instruction definitions, opcode definitions, and operand definitions.

use bytecode_loader::{BytecodeLoaderBuilder, BytecodeLoaderError};

/// This module contains basic block definitions and operations.
pub mod basic_block;
/// This module reads bytecode from a reader and disassembles it.
pub mod bytecode_loader;
/// This module contains the logic to visualize the control flow graph of a module.
pub mod cfg_dot;
/// Decompiler module
pub mod decompiler;
/// This module contains the definition of a function.
pub mod function;
/// This module contains the definition of Graal IO.
pub mod graal_io;
/// This module contains the definition of an instruction.
pub mod instruction;
/// This module contains the definition of a module.
pub mod module;
/// This module contains the definition of an opcode.
pub mod opcode;
/// This module contains the definition of an operand.
pub mod operand;
/// This module contains utility functions and types.
pub mod utils;

/// Disassemble bytecode using a reader.
///
/// # Arguments
/// - `reader`: The reader to read the bytecode from.
///
/// # Returns
/// - The string representation of the disassembled bytecode.
///
/// # Errors
/// - `BytecodeLoaderError`: An error occurred while loading the bytecode.
///
/// # Examples
/// ```
/// use gbf_core::disassemble_bytecode;
///
/// // read from a file
/// let reader = std::fs::File::open("tests/gs2bc/simple.gs2bc").unwrap();
/// let result = disassemble_bytecode(reader).unwrap();
/// ```
pub fn disassemble_bytecode<R: std::io::Read>(reader: R) -> Result<String, BytecodeLoaderError> {
    // create a new bytecode loader builder
    let loader = BytecodeLoaderBuilder::new(reader).build()?;

    // write a string representation of the bytecode using each instruction in the instructions vec
    let mut result = String::new();
    for (index, instruction) in loader.instructions.iter().enumerate() {
        result.push_str(&format!("{:08x}: {}\n", index, instruction));
    }
    Ok(result)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_disassemble() {
        let reader = std::io::Cursor::new(vec![
            0x00, 0x00, 0x00, 0x01, // Section type: Gs1Flags
            0x00, 0x00, 0x00, 0x04, // Length: 4
            0x00, 0x00, 0x00, 0x00, // Flags: 0
            0x00, 0x00, 0x00, 0x02, // Section type: Functions
            0x00, 0x00, 0x00, 0x09, // Length: 9
            0x00, 0x00, 0x00, 0x00, // Function location: 0
            0x6d, 0x61, 0x69, 0x6e, // Function name: "main"
            0x00, // Null terminator
            0x00, 0x00, 0x00, 0x03, // Section type: Strings
            0x00, 0x00, 0x00, 0x04, // Length: 4
            0x61, 0x62, 0x63, 0x00, // String: "abc"
            0x00, 0x00, 0x00, 0x04, // Section type: Instructions
            0x00, 0x00, 0x00, 0x0c, // Length: 12
            0x01, // Opcode: Jmp
            0xF3, // Opcode: ImmByte
            0x01, // Operand: 1
            0x14, // Opcode: PushNumber
            0xF4, // Opcode: ImmShort
            0x00, 0x01, // Operand: 1
            0x15, // Opcode: PushString
            0xF0, // Opcode: ImmStringByte
            0x00, // Operand: 0
            0x1b, // Opcode: PushPi
            0x07, // Opcode: Ret
        ]);

        let result = disassemble_bytecode(reader).unwrap();

        assert_eq!(
            result,
            "00000000: Jmp 0x1\n\
            00000001: PushNumber 0x1\n\
            00000002: PushString abc\n\
            00000003: PushPi\n\
            00000004: Ret\n"
        );

        // test failure case
        let reader = std::io::Cursor::new(vec![0x00, 0x00, 0x00, 0x01]);
        let result = disassemble_bytecode(reader);
        assert!(result.is_err());
    }
}