1use crate::il::Expression as Expr;
2use crate::il::*;
3use crate::translator::x86::x86register::{get_register, X86Register};
4use crate::Error;
5use falcon_capstone::capstone;
6use falcon_capstone::capstone::cs_x86_op;
7use falcon_capstone::capstone_sys::{x86_op_type, x86_reg};
8use std::cmp::Ordering;
9
10#[derive(Clone, Debug)]
12pub(crate) enum Mode {
13 X86,
14 Amd64,
15}
16
17impl Mode {
18 pub(crate) fn get_register(&self, capstone_id: x86_reg) -> Result<&'static X86Register, Error> {
19 get_register(self, capstone_id)
20 }
21
22 pub(crate) fn bits(&self) -> usize {
23 match *self {
24 Mode::X86 => 32,
25 Mode::Amd64 => 64,
26 }
27 }
28
29 pub(crate) fn sp(&self) -> Scalar {
30 match *self {
31 Mode::X86 => scalar("esp", 32),
32 Mode::Amd64 => scalar("rsp", 64),
33 }
34 }
35
36 pub(crate) fn get_register_expression(
37 &self,
38 register: capstone::x86_reg,
39 instruction: &capstone::Instr,
40 ) -> Result<Expression, Error> {
41 Ok(match register {
42 x86_reg::X86_REG_RIP => {
43 let value = instruction.address + instruction.size as u64;
44 expr_const(value, 64)
45 }
46 _ => get_register(self, register)?.get()?,
47 })
48 }
49
50 pub(crate) fn operand_value(
52 &self,
53 operand: &cs_x86_op,
54 instruction: &capstone::Instr,
55 ) -> Result<Expression, Error> {
56 match operand.type_ {
57 x86_op_type::X86_OP_INVALID => Err("Invalid operand".into()),
58 x86_op_type::X86_OP_REG => {
59 get_register(self, operand.reg())?.get()
61 }
62 x86_op_type::X86_OP_MEM => {
63 let mem = operand.mem();
64 let base_capstone_reg = mem.base;
65 let index_capstone_reg = mem.index;
66
67 let base = match base_capstone_reg {
68 x86_reg::X86_REG_INVALID => None,
69 reg => Some(self.get_register_expression(reg, instruction)?),
70 };
71
72 let index = match index_capstone_reg {
73 x86_reg::X86_REG_INVALID => None,
74 reg => Some(self.get_register_expression(reg, instruction)?),
75 };
76
77 let scale = Expr::constant(Constant::new(mem.scale as i64 as u64, self.bits()));
78
79 let si = match index {
80 Some(index) => Some(Expr::mul(index, scale)?),
81 None => None,
82 };
83
84 let op: Option<Expression> = match (base, si) {
86 (Some(base), Some(si)) => Some(Expr::add(base, si)?),
87 (Some(base), None) => Some(base),
88 (None, si) => si,
89 };
90
91 let op = if let Some(op) = op {
93 match mem.disp.cmp(&0) {
94 Ordering::Greater => {
95 Expr::add(op, expr_const(mem.disp as u64, self.bits()))?
96 }
97 Ordering::Less => {
98 Expr::sub(op, expr_const(mem.disp.unsigned_abs(), self.bits()))?
99 }
100 Ordering::Equal => op,
101 }
102 } else {
103 expr_const(mem.disp as u64, self.bits())
104 };
105
106 match mem.segment {
107 x86_reg::X86_REG_INVALID => Ok(op),
108 x86_reg::X86_REG_CS
109 | x86_reg::X86_REG_DS
110 | x86_reg::X86_REG_ES
111 | x86_reg::X86_REG_FS
112 | x86_reg::X86_REG_GS
113 | x86_reg::X86_REG_SS => {
114 let segment_register = self.get_register(mem.segment)?.get()?;
115 Ok(Expr::add(segment_register, op)?)
116 }
117 _ => Err(Error::Custom("invalid segment register".to_string())),
118 }
119 }
120 x86_op_type::X86_OP_IMM => {
121 let operand_size = if operand.size == 0 {
123 8
124 } else {
125 operand.size as usize * 8
126 };
127 Ok(expr_const(operand.imm() as u64, operand_size))
128 }
129 }
130 }
131
132 pub fn operand_load(
134 &self,
135 block: &mut Block,
136 operand: &cs_x86_op,
137 instruction: &capstone::Instr,
138 ) -> Result<Expression, Error> {
139 let op = self.operand_value(operand, instruction)?;
140
141 if operand.type_ == x86_op_type::X86_OP_MEM {
142 let temp = Scalar::temp(instruction.address, operand.size as usize * 8);
143 block.load(temp.clone(), op);
144 return Ok(temp.into());
145 }
146 Ok(op)
147 }
148
149 pub fn operand_store(
151 &self,
152 block: &mut Block,
153 operand: &cs_x86_op,
154 value: Expression,
155 instruction: &capstone::Instr,
156 ) -> Result<(), Error> {
157 match operand.type_ {
158 x86_op_type::X86_OP_INVALID => Err("operand_store called on invalid operand".into()),
159 x86_op_type::X86_OP_IMM => Err("operand_store called on immediate operand".into()),
160 x86_op_type::X86_OP_REG => {
161 let dst_register = self.get_register(operand.reg())?;
162 dst_register.set(block, value)
163 }
164 x86_op_type::X86_OP_MEM => {
165 let address = self.operand_value(operand, instruction)?;
166 block.store(address, value);
167 Ok(())
168 }
169 }
170 }
171
172 pub fn pop_value(
174 &self,
175 block: &mut Block,
176 bits: usize,
177 instruction: &capstone::Instr,
178 ) -> Result<Expression, Error> {
179 let temp = Scalar::temp(instruction.address, bits);
180
181 block.load(temp.clone(), self.sp().into());
182 block.assign(
183 self.sp(),
184 Expr::add(self.sp().into(), expr_const((bits / 8) as u64, self.bits()))?,
185 );
186
187 Ok(temp.into())
188 }
189
190 pub fn push_value(&self, block: &mut Block, value: Expression) -> Result<(), Error> {
192 match self {
193 Mode::X86 => block.assign(self.sp(), Expr::sub(self.sp().into(), expr_const(4, 32))?),
194 Mode::Amd64 => block.assign(self.sp(), Expr::sub(self.sp().into(), expr_const(8, 64))?),
195 };
196
197 block.store(self.sp().into(), value);
198 Ok(())
199 }
200}