falcon/translator/x86/
mode.rs

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/// Mode used by translators to pick the correct registers/operations
11#[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    /// Gets the value of an operand as an IL expression
51    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 the register value
60                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                // Handle base and scale/index
85                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                // handle disp
98                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                // https://github.com/aquynh/capstone/issues/1586
128                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    /// Gets the value of an operand as an IL expression, performing any required loads as needed.
141    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    /// Stores a value in an operand, performing any stores as necessary.
158    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    /// Convenience function to pop a value off the stack
183    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    /// Convenience function to push a value onto the stack
201    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}