fugue_ir/il/pcode/
operand.rs

1use std::fmt;
2
3use crate::address::Address;
4use crate::disassembly::VarnodeData;
5use crate::register::RegisterNames;
6use crate::space::AddressSpaceId;
7use crate::space_manager::SpaceManager;
8use crate::translator::Translator;
9
10use fugue_bv::BitVec;
11use ustr::Ustr;
12
13use super::Register;
14
15#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
16#[derive(serde::Deserialize, serde::Serialize)]
17pub enum Operand {
18    // RAM
19    Address {
20        value: Address,
21        size: usize,
22    },
23    Constant {
24        value: u64,
25        size: usize,
26    },
27    Register {
28        name: Ustr,
29        offset: u64,
30        size: usize,
31    },
32    Variable {
33        offset: u64,
34        size: usize,
35        space: AddressSpaceId,
36    },
37}
38
39impl<'z> Operand {
40    pub fn from_varnode(translator: &Translator, varnode: VarnodeData) -> Operand {
41        Self::from_varnodedata(translator.manager(), translator.registers(), varnode)
42    }
43
44    #[inline(always)]
45    pub(crate) fn from_varnodedata(
46        manager: &SpaceManager,
47        registers: &RegisterNames,
48        vnd: VarnodeData,
49    ) -> Operand {
50        let offset = vnd.offset;
51        let size = vnd.size;
52        let space_id = vnd.space;
53
54        if cfg!(feature = "extra-logging") {
55            log::trace!("building operand from {vnd:?}");
56        }
57
58        if space_id.is_default() {
59            // address
60            Operand::Address {
61                value: Address::new(manager.default_space_ref(), offset),
62                size,
63            }
64        } else if space_id.is_constant() {
65            // constant
66            Operand::Constant {
67                value: offset,
68                size,
69            }
70        } else if space_id.is_register() {
71            // register
72            let name = unsafe { registers.unchecked_get(offset, size) }.clone();
73
74            Operand::Register {
75                name,
76                offset,
77                size,
78            }
79        } else {
80            // variable
81            Operand::Variable {
82                offset,
83                size,
84                space: space_id,
85            }
86        }
87    }
88
89    pub fn address(&self) -> Option<Address> {
90        if let Self::Address { value, .. } = self {
91            Some(*value)
92        } else {
93            None
94        }
95    }
96
97    pub fn as_bitvec(&self) -> Option<BitVec> {
98        if let Self::Constant { value, size, .. } = self {
99            Some(BitVec::from_u64(*value, size * 8))
100        } else {
101            None
102        }
103    }
104
105    pub fn register(&self) -> Option<Register> {
106        if let Self::Register {
107            name,
108            offset,
109            size,
110        } = self
111        {
112            Some(Register {
113                name: name.clone(),
114                offset: *offset,
115                size: *size,
116            })
117        } else {
118            None
119        }
120    }
121
122    pub fn offset(&self) -> u64 {
123        match self {
124            Operand::Address { value, .. } => value.offset(),
125            Operand::Constant { value, .. } => *value,
126            Operand::Register { offset, .. } | Operand::Variable { offset, .. } => *offset,
127        }
128    }
129
130    pub fn size(&self) -> usize {
131        match self {
132            Operand::Address { size, .. }
133            | Operand::Constant { size, .. }
134            | Operand::Register { size, .. }
135            | Operand::Variable { size, .. } => *size,
136        }
137    }
138
139    pub fn display(&self) -> OperandFormatter {
140        OperandFormatter::new(self)
141    }
142}
143
144impl<'z> fmt::Display for Operand {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        write!(f, "{}", self.display())
147    }
148}
149
150impl<'z> AsRef<Operand> for Operand {
151    fn as_ref(&self) -> &Operand {
152        self
153    }
154}
155
156#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
157pub enum OperandCase {
158    Default,
159    Lower,
160    Upper,
161}
162
163#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
164pub enum OperandSize {
165    Default,
166    AsBits,
167    AsBytes,
168}
169
170impl Default for OperandSize {
171    fn default() -> Self {
172        Self::Default
173    }
174}
175
176pub struct OperandFormatter<'operand> {
177    operand: &'operand Operand,
178    signed: bool,
179    sizes: OperandSize,
180    case: OperandCase,
181}
182
183impl Default for OperandCase {
184    fn default() -> Self {
185        Self::Default
186    }
187}
188
189impl<'operand> OperandFormatter<'operand> {
190    pub fn new(operand: &'operand Operand) -> Self {
191        Self {
192            operand,
193            signed: false,
194            sizes: OperandSize::default(),
195            case: OperandCase::default(),
196        }
197    }
198
199    pub fn signed(self, signed: bool) -> Self {
200        Self { signed, ..self }
201    }
202
203    pub fn case(self, case: OperandCase) -> Self {
204        Self { case, ..self }
205    }
206
207    pub fn sizes(self, sizes: OperandSize) -> Self {
208        Self { sizes, ..self }
209    }
210}
211
212impl<'operand> fmt::Debug for OperandFormatter<'operand> {
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        write!(f, "{:?}", self.operand)
215    }
216}
217
218impl<'operand> fmt::Display for OperandFormatter<'operand> {
219    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220        match self.operand {
221            Operand::Address { value, .. } => write!(f, "{}", value)?,
222            Operand::Constant { value, size, .. } => {
223                if !self.signed {
224                    match size {
225                        1 => write!(f, "{:#x}", *value as u8)?,
226                        2 => write!(f, "{:#x}", *value as u16)?,
227                        4 => write!(f, "{:#x}", *value as u32)?,
228                        _ => write!(f, "{:#x}", value)?,
229                    }
230                } else {
231                    match size {
232                        1 => {
233                            let i = *value as u8 as i8;
234                            write!(f, "{}{:#x}", if i < 0 { "-" } else { "" }, i.abs())?
235                        }
236                        2 => {
237                            let i = *value as u16 as i16;
238                            write!(f, "{}{:#x}", if i < 0 { "-" } else { "" }, i.abs())?
239                        }
240                        4 => {
241                            let i = *value as u32 as i32;
242                            write!(f, "{}{:#x}", if i < 0 { "-" } else { "" }, i.abs())?
243                        }
244                        _ => {
245                            let i = *value as u64 as i64;
246                            write!(f, "{}{:#x}", if i < 0 { "-" } else { "" }, i.abs())?
247                        }
248                    }
249                }
250            }
251            Operand::Register { name, .. } => match self.case {
252                OperandCase::Default => write!(f, "{}", name)?,
253                OperandCase::Lower => write!(f, "{}", name.to_lowercase())?,
254                OperandCase::Upper => write!(f, "{}", name.to_uppercase())?,
255            },
256            Operand::Variable { offset, .. } => write!(
257                f,
258                "{}{:04x}",
259                if matches!(self.case, OperandCase::Upper) {
260                    "VAR"
261                } else {
262                    "var"
263                },
264                offset
265            )?,
266        }
267        match self.sizes {
268            OperandSize::Default => (),
269            OperandSize::AsBits => write!(f, ":{}", self.operand.size() * 8)?,
270            OperandSize::AsBytes => write!(f, ":{}", self.operand.size())?,
271        }
272        Ok(())
273    }
274}