gbf_core/decompiler/handlers/
special_two_operand.rs

1#![deny(missing_docs)]
2
3use std::backtrace::Backtrace;
4
5use crate::{
6    decompiler::{
7        ProcessedInstruction, ProcessedInstructionBuilder,
8        ast::{
9            expr::ExprKind, new_array_access, new_assignment, new_id_with_version,
10            new_member_access, new_new,
11        },
12        function_decompiler::FunctionDecompilerError,
13        function_decompiler_context::FunctionDecompilerContext,
14    },
15    instruction::Instruction,
16    opcode::Opcode,
17};
18
19use super::OpcodeHandler;
20
21/// Handles other instructions.
22pub struct SpecialTwoOperandHandler;
23
24impl OpcodeHandler for SpecialTwoOperandHandler {
25    fn handle_instruction(
26        &self,
27        context: &mut FunctionDecompilerContext,
28        instruction: &Instruction,
29    ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
30        match instruction.opcode {
31            Opcode::AccessMember => {
32                let mut rhs = context.pop_expression()?;
33                let mut lhs = context.pop_expression()?;
34
35                // TODO: Check this logic. If either rhs or lhs is an identifier, strip the version from it
36                if let ExprKind::Identifier(mut id) = lhs {
37                    id.ssa_version = None;
38                    lhs = id.into();
39                }
40                if let ExprKind::Identifier(mut id) = rhs {
41                    id.ssa_version = None;
42                    rhs = id.into();
43                }
44
45                let ma: ExprKind = new_member_access(lhs, rhs)
46                    .map_err(|e| FunctionDecompilerError::AstNodeError {
47                        source: e,
48                        context: context.get_error_context(),
49                        backtrace: Backtrace::capture(),
50                    })?
51                    .into();
52                context.push_one_node(ma.into())?;
53                Ok(ProcessedInstructionBuilder::new().build())
54            }
55            Opcode::Assign => {
56                let rhs = context.pop_expression()?;
57                let mut lhs = context.pop_expression()?;
58
59                // an assignment bumps the version of the lhs, if it's an identifier
60                if let ExprKind::Identifier(mut id) = lhs {
61                    let ver = context.ssa_context.new_ssa_version_for(id.id());
62                    id.ssa_version = Some(ver);
63                    lhs = id.into();
64                }
65                let stmt = new_assignment(lhs, rhs);
66
67                Ok(ProcessedInstructionBuilder::new()
68                    .push_to_region(stmt.into())
69                    .build())
70            }
71            Opcode::ArrayAccess => {
72                let index = context.pop_expression()?;
73                let arr = context.pop_expression()?;
74
75                let array_access = new_array_access(arr, index);
76
77                context.push_one_node(array_access.into())?;
78                Ok(ProcessedInstructionBuilder::new().build())
79            }
80            Opcode::NewObject => {
81                let new_type = context.pop_expression()?;
82                let arg = context.pop_expression()?;
83
84                let new_node =
85                    new_new(new_type, arg).map_err(|e| FunctionDecompilerError::AstNodeError {
86                        source: e,
87                        context: context.get_error_context(),
88                        backtrace: Backtrace::capture(),
89                    })?;
90
91                // Create SSA ID for the function call
92                let var = context.ssa_context.new_ssa_version_for("new_node");
93                let ssa_id = new_id_with_version("new_node", var);
94                let stmt = new_assignment(ssa_id.clone(), new_node);
95
96                Ok(ProcessedInstructionBuilder::new()
97                    .ssa_id(ssa_id.into())
98                    .push_to_region(stmt.into())
99                    .build())
100            }
101            _ => Err(FunctionDecompilerError::UnimplementedOpcode {
102                opcode: instruction.opcode,
103                context: context.get_error_context(),
104                backtrace: Backtrace::capture(),
105            }),
106        }
107    }
108}