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}