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> = if base.is_some() {
86 if si.is_some() {
87 Some(Expr::add(base.unwrap(), si.unwrap())?)
88 } else {
89 base
90 }
91 } else if si.is_some() {
92 si
93 } else {
94 None
95 };
96
97 let op = if let Some(op) = op {
99 match mem.disp.cmp(&0) {
100 Ordering::Greater => {
101 Expr::add(op, expr_const(mem.disp as u64, self.bits()))?
102 }
103 Ordering::Less => {
104 Expr::sub(op, expr_const(mem.disp.unsigned_abs(), self.bits()))?
105 }
106 Ordering::Equal => op,
107 }
108 } else {
109 expr_const(mem.disp as u64, self.bits())
110 };
111
112 match mem.segment {
113 x86_reg::X86_REG_INVALID => Ok(op),
114 x86_reg::X86_REG_CS
115 | x86_reg::X86_REG_DS
116 | x86_reg::X86_REG_ES
117 | x86_reg::X86_REG_FS
118 | x86_reg::X86_REG_GS
119 | x86_reg::X86_REG_SS => {
120 let segment_register = self.get_register(mem.segment)?.get()?;
121 Ok(Expr::add(segment_register, op)?)
122 }
123 _ => Err(Error::Custom("invalid segment register".to_string())),
124 }
125 }
126 x86_op_type::X86_OP_IMM => {
127 let operand_size = if operand.size == 0 {
129 8
130 } else {
131 operand.size as usize * 8
132 };
133 Ok(expr_const(operand.imm() as u64, operand_size))
134 }
135 #[cfg(not(feature = "capstone4"))]
136 x86_op_type::X86_OP_FP => Err("Unhandled operand".into()),
137 }
138 }
139
140 pub fn operand_load(
142 &self,
143 block: &mut Block,
144 operand: &cs_x86_op,
145 instruction: &capstone::Instr,
146 ) -> Result<Expression, Error> {
147 let op = self.operand_value(operand, instruction)?;
148
149 if operand.type_ == x86_op_type::X86_OP_MEM {
150 let temp = Scalar::temp(instruction.address, operand.size as usize * 8);
151 block.load(temp.clone(), op);
152 return Ok(temp.into());
153 }
154 Ok(op)
155 }
156
157 pub fn operand_store(
159 &self,
160 block: &mut Block,
161 operand: &cs_x86_op,
162 value: Expression,
163 instruction: &capstone::Instr,
164 ) -> Result<(), Error> {
165 match operand.type_ {
166 x86_op_type::X86_OP_INVALID => Err("operand_store called on invalid operand".into()),
167 x86_op_type::X86_OP_IMM => Err("operand_store called on immediate operand".into()),
168 x86_op_type::X86_OP_REG => {
169 let dst_register = self.get_register(operand.reg())?;
170 dst_register.set(block, value)
171 }
172 x86_op_type::X86_OP_MEM => {
173 let address = self.operand_value(operand, instruction)?;
174 block.store(address, value);
175 Ok(())
176 }
177 #[cfg(not(feature = "capstone4"))]
178 x86_op_type::X86_OP_FP => Err("operand_store called on fp operand".into()),
179 }
180 }
181
182 pub fn pop_value(
184 &self,
185 block: &mut Block,
186 bits: usize,
187 instruction: &capstone::Instr,
188 ) -> Result<Expression, Error> {
189 let temp = Scalar::temp(instruction.address, bits);
190
191 block.load(temp.clone(), self.sp().into());
192 block.assign(
193 self.sp(),
194 Expr::add(self.sp().into(), expr_const((bits / 8) as u64, self.bits()))?,
195 );
196
197 Ok(temp.into())
198 }
199
200 pub fn push_value(&self, block: &mut Block, value: Expression) -> Result<(), Error> {
202 match self {
203 Mode::X86 => block.assign(self.sp(), Expr::sub(self.sp().into(), expr_const(4, 32))?),
204 Mode::Amd64 => block.assign(self.sp(), Expr::sub(self.sp().into(), expr_const(8, 64))?),
205 };
206
207 block.store(self.sp().into(), value);
208 Ok(())
209 }
210}