gbf_core/decompiler/handlers/
special_one_operand.rs1#![deny(missing_docs)]
2
3use std::backtrace::Backtrace;
4
5use crate::{
6 decompiler::{
7 ProcessedInstruction, ProcessedInstructionBuilder,
8 ast::{
9 bin_op::BinOpType, expr::ExprKind, new_assignment, new_bin_op, new_id_with_version,
10 new_num, new_return, new_uninitialized_array,
11 },
12 function_decompiler::FunctionDecompilerError,
13 function_decompiler_context::FunctionDecompilerContext,
14 },
15 instruction::Instruction,
16 opcode::Opcode,
17};
18
19use super::OpcodeHandler;
20
21pub struct SpecialOneOperandHandler;
23
24impl OpcodeHandler for SpecialOneOperandHandler {
25 fn handle_instruction(
26 &self,
27 context: &mut FunctionDecompilerContext,
28 instruction: &Instruction,
29 ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
30 match instruction.opcode {
31 Opcode::Ret => {
32 let ret_val = context.pop_expression()?;
33
34 let ret = new_return(ret_val);
35 Ok(ProcessedInstructionBuilder::new()
36 .push_to_region(ret.into())
37 .build())
38 }
39 Opcode::Copy => {
40 let operand = context.pop_expression()?;
41 context.push_one_node(operand.clone().into())?;
42 context.push_one_node(operand.clone().into())?;
43 Ok(ProcessedInstructionBuilder::new().build())
44 }
45 Opcode::GetRegister => {
46 let register_id = instruction
47 .operand
48 .as_ref()
49 .ok_or(FunctionDecompilerError::InstructionMustHaveOperand {
50 opcode: instruction.opcode,
51 context: context.get_error_context(),
52 backtrace: Backtrace::capture(),
53 })?
54 .get_number_value()
55 .map_err(|e| FunctionDecompilerError::OperandError {
56 source: e,
57 context: context.get_error_context(),
58 backtrace: Backtrace::capture(),
59 })?;
60
61 let ssa_id = context
62 .register_mapping
63 .get(&(register_id as usize))
64 .ok_or(FunctionDecompilerError::RegisterNotFound {
65 register_id: register_id as usize,
66 context: context.get_error_context(),
67 backtrace: Backtrace::capture(),
68 })?;
69 context.push_one_node(ssa_id.clone().into())?;
70 Ok(ProcessedInstructionBuilder::new().build())
71 }
72 Opcode::SetRegister => {
73 let register_id = instruction
74 .operand
75 .as_ref()
76 .ok_or(FunctionDecompilerError::InstructionMustHaveOperand {
77 opcode: instruction.opcode,
78 context: context.get_error_context(),
79 backtrace: Backtrace::capture(),
80 })?
81 .get_number_value()
82 .map_err(|e| FunctionDecompilerError::OperandError {
83 source: e,
84 context: context.get_error_context(),
85 backtrace: Backtrace::capture(),
86 })?;
87
88 let register_store = context.pop_expression()?;
89
90 let (register_map_add, processed_instruction): (ExprKind, ProcessedInstruction) =
92 match register_store.clone() {
93 ExprKind::Identifier(assignable) => (
94 assignable.clone().into(),
95 ProcessedInstructionBuilder::new().build(),
96 ),
97 ExprKind::MemberAccess(member_access) => (
98 member_access.clone().into(),
99 ProcessedInstructionBuilder::new().build(),
100 ),
101 _ => {
102 let var = context.ssa_context.new_ssa_version_for("set_register");
103 let ssa_id = new_id_with_version("set_register", var);
104 let stmt = new_assignment(ssa_id.clone(), register_store.clone());
105 (
106 ssa_id.clone().into(),
107 ProcessedInstructionBuilder::new()
108 .push_to_region(stmt.into())
109 .ssa_id(ssa_id.into())
110 .build(),
111 )
112 }
113 };
114
115 context.push_one_node(register_store.clone().into())?;
117
118 context
119 .register_mapping
120 .insert(register_id as usize, register_map_add);
121
122 Ok(processed_instruction)
123 }
124 Opcode::Inc => {
125 let expr = context.pop_expression()?;
127 let bin_op = new_bin_op(expr.clone(), new_num(1), BinOpType::Add).map_err(|e| {
128 FunctionDecompilerError::AstNodeError {
129 source: e,
130 context: context.get_error_context(),
131 backtrace: Backtrace::capture(),
132 }
133 })?;
134
135 let mut lhs = expr;
137 if let ExprKind::Identifier(mut id) = lhs {
138 let ver = context.ssa_context.new_ssa_version_for(id.id());
139 id.ssa_version = Some(ver);
140 lhs = id.clone().into();
141 }
142 let stmt = new_assignment(lhs.clone(), bin_op);
143
144 context.push_one_node(lhs.clone().into())?;
145
146 Ok(ProcessedInstructionBuilder::new()
147 .push_to_region(stmt.into())
148 .build())
149 }
150 Opcode::Dec => {
151 let expr = context.pop_expression()?;
153 let bin_op = new_bin_op(expr.clone(), new_num(1), BinOpType::Sub).map_err(|e| {
154 FunctionDecompilerError::AstNodeError {
155 source: e,
156 context: context.get_error_context(),
157 backtrace: Backtrace::capture(),
158 }
159 })?;
160
161 let mut lhs = expr;
163 if let ExprKind::Identifier(mut id) = lhs {
164 let ver = context.ssa_context.new_ssa_version_for(id.id());
165 id.ssa_version = Some(ver);
166 lhs = id.clone().into();
167 }
168 let stmt = new_assignment(lhs.clone(), bin_op);
169
170 context.push_one_node(lhs.clone().into())?;
171
172 Ok(ProcessedInstructionBuilder::new()
173 .push_to_region(stmt.into())
174 .build())
175 }
176 Opcode::New => {
177 let new_type = context.pop_expression()?;
179
180 let var = context.ssa_context.new_ssa_version_for("gbf_new_obj");
182 let ssa_id = new_id_with_version("gbf_new_obj", var);
183 let stmt = new_assignment(ssa_id.clone(), new_type.clone());
184
185 context.push_one_node(ssa_id.clone().into())?;
186
187 Ok(ProcessedInstructionBuilder::new()
188 .push_to_region(stmt.into())
189 .build())
190 }
191 Opcode::NewUninitializedArray => {
192 let num_elems = context.pop_expression()?;
194
195 let new_array = new_uninitialized_array(num_elems);
197 context.push_one_node(new_array.into())?;
198 Ok(ProcessedInstructionBuilder::new().build())
199 }
200 _ => Err(FunctionDecompilerError::UnimplementedOpcode {
201 opcode: instruction.opcode,
202 context: context.get_error_context(),
203 backtrace: Backtrace::capture(),
204 }),
205 }
206 }
207}