Skip to main content

tsffs/arch/
arm.rs

1// Copyright (C) 2024 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4//! Architecture-specific implementation for ARM architecture
5
6use anyhow::{anyhow, bail, Result};
7use libafl::prelude::CmpValues;
8use raw_cstr::AsRawCstr;
9use simics::api::{
10    get_interface, read_phys_memory, sys::instruction_handle_t, Access, ConfObject,
11    CpuInstructionQueryInterface, CpuInstrumentationSubscribeInterface, CycleInterface,
12    IntRegisterInterface, ProcessorInfoV2Interface,
13};
14use std::{ffi::CStr, mem::size_of, slice::from_raw_parts};
15use yaxpeax_arch::{Decoder, U8Reader};
16use yaxpeax_arm::armv7::{InstDecoder, Instruction, Opcode, Operand, RegShiftStyle, ShiftStyle};
17
18use crate::{
19    tracer::{CmpExpr, CmpExprShift, CmpType, CmpValue, TraceEntry},
20    traits::TracerDisassembler,
21};
22
23use super::ArchitectureOperations;
24
25pub(crate) struct ARMArchitectureOperations {
26    cpu: *mut ConfObject,
27    disassembler: Disassembler,
28    int_register: IntRegisterInterface,
29    processor_info_v2: ProcessorInfoV2Interface,
30    cpu_instruction_query: CpuInstructionQueryInterface,
31    #[allow(dead_code)]
32    cpu_instrumentation_subscribe: CpuInstrumentationSubscribeInterface,
33    cycle: CycleInterface,
34}
35
36impl ArchitectureOperations for ARMArchitectureOperations {
37    const INDEX_SELECTOR_REGISTER: &'static str = "r10";
38
39    const ARGUMENT_REGISTER_0: &'static str = "r9";
40
41    const ARGUMENT_REGISTER_1: &'static str = "r8";
42
43    const ARGUMENT_REGISTER_2: &'static str = "r7";
44
45    fn new(cpu: *mut ConfObject) -> Result<Self> {
46        let mut processor_info_v2: ProcessorInfoV2Interface = get_interface(cpu)?;
47
48        let arch = unsafe { CStr::from_ptr(processor_info_v2.architecture()?) }
49            .to_str()?
50            .to_string();
51
52        if arch == "arm" || arch == "armv7" || arch == "armv6" || arch == "armv5" || arch == "arm32"
53        {
54            Ok(Self {
55                cpu,
56                disassembler: Disassembler::new(),
57                int_register: get_interface(cpu)?,
58                processor_info_v2,
59                cpu_instruction_query: get_interface(cpu)?,
60                cpu_instrumentation_subscribe: get_interface(cpu)?,
61                cycle: get_interface(cpu)?,
62            })
63        } else {
64            bail!("Architecture {} is not arm", arch);
65        }
66    }
67
68    fn new_unchecked(cpu: *mut ConfObject) -> Result<Self>
69    where
70        Self: Sized,
71    {
72        Ok(Self {
73            cpu,
74            disassembler: Disassembler::new(),
75            int_register: get_interface(cpu)?,
76            processor_info_v2: get_interface(cpu)?,
77            cpu_instruction_query: get_interface(cpu)?,
78            cpu_instrumentation_subscribe: get_interface(cpu)?,
79            cycle: get_interface(cpu)?,
80        })
81    }
82
83    fn cpu(&self) -> *mut ConfObject {
84        self.cpu
85    }
86
87    fn disassembler(&mut self) -> &mut dyn TracerDisassembler {
88        &mut self.disassembler
89    }
90
91    fn int_register(&mut self) -> &mut IntRegisterInterface {
92        &mut self.int_register
93    }
94
95    fn processor_info_v2(&mut self) -> &mut ProcessorInfoV2Interface {
96        &mut self.processor_info_v2
97    }
98
99    fn cpu_instruction_query(&mut self) -> &mut CpuInstructionQueryInterface {
100        &mut self.cpu_instruction_query
101    }
102
103    fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface {
104        &mut self.cpu_instrumentation_subscribe
105    }
106
107    fn cycle(&mut self) -> &mut CycleInterface {
108        &mut self.cycle
109    }
110
111    fn trace_pc(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
112        let instruction_bytes = self
113            .cpu_instruction_query
114            .get_instruction_bytes(instruction_query)?;
115
116        self.disassembler.disassemble(unsafe {
117            from_raw_parts(instruction_bytes.data, instruction_bytes.size)
118        })?;
119
120        if self.disassembler.last_was_call()
121            || self.disassembler.last_was_control_flow()
122            || self.disassembler.last_was_ret()
123        {
124            Ok(TraceEntry::builder()
125                .edge(self.processor_info_v2.get_program_counter()?)
126                .build())
127        } else {
128            Ok(TraceEntry::default())
129        }
130    }
131
132    fn trace_cmp(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
133        let instruction_bytes = self
134            .cpu_instruction_query
135            .get_instruction_bytes(instruction_query)?;
136        self.disassembler.disassemble(unsafe {
137            from_raw_parts(instruction_bytes.data, instruction_bytes.size)
138        })?;
139
140        let pc = self.processor_info_v2.get_program_counter()?;
141
142        let mut cmp_values = Vec::new();
143
144        for expr in self.disassembler.cmp() {
145            if let Ok(value) = self.simplify(&expr) {
146                cmp_values.push(value);
147            }
148        }
149
150        let cmp_value = if let (Some(l), Some(r)) = (cmp_values.first(), cmp_values.get(1)) {
151            match (l, r) {
152                (CmpValue::U8(l), CmpValue::U8(r)) => Some(CmpValues::U8((*l, *r))),
153                (CmpValue::I8(l), CmpValue::I8(r)) => Some(CmpValues::U8((
154                    u8::from_le_bytes(l.to_le_bytes()),
155                    u8::from_le_bytes(r.to_le_bytes()),
156                ))),
157                (CmpValue::U16(l), CmpValue::U16(r)) => Some(CmpValues::U16((*l, *r))),
158                (CmpValue::I16(l), CmpValue::I16(r)) => Some(CmpValues::U16((
159                    u16::from_le_bytes(l.to_le_bytes()),
160                    u16::from_le_bytes(r.to_le_bytes()),
161                ))),
162                (CmpValue::U32(l), CmpValue::U32(r)) => Some(CmpValues::U32((*l, *r))),
163                (CmpValue::I32(l), CmpValue::I32(r)) => Some(CmpValues::U32((
164                    u32::from_le_bytes(l.to_le_bytes()),
165                    u32::from_le_bytes(r.to_le_bytes()),
166                ))),
167                (CmpValue::U64(l), CmpValue::U64(r)) => Some(CmpValues::U64((*l, *r))),
168                (CmpValue::I64(l), CmpValue::I64(r)) => Some(CmpValues::U64((
169                    u64::from_le_bytes(l.to_le_bytes()),
170                    u64::from_le_bytes(r.to_le_bytes()),
171                ))),
172                (CmpValue::Expr(_), CmpValue::Expr(_)) => None,
173                _ => None,
174            }
175        } else {
176            None
177        };
178
179        Ok(TraceEntry::builder()
180            .cmp((
181                pc,
182                self.disassembler.cmp_type(),
183                cmp_value.ok_or_else(|| anyhow!("No cmp value available"))?,
184            ))
185            .build())
186    }
187}
188
189impl ARMArchitectureOperations {
190    fn simplify(&mut self, expr: &CmpExpr) -> Result<CmpValue> {
191        match expr {
192            CmpExpr::Deref((b, _)) => {
193                let v = self.simplify(b)?;
194                match v {
195                    CmpValue::U64(a) => {
196                        let address = self
197                            .processor_info_v2
198                            .logical_to_physical(a, Access::Sim_Access_Read)?;
199                        Ok(CmpValue::U64(read_phys_memory(
200                            self.cpu,
201                            address.address,
202                            size_of::<u64>() as i32,
203                        )?))
204                    }
205                    CmpValue::U32(a) => {
206                        let address = self
207                            .processor_info_v2
208                            .logical_to_physical(a as u64, Access::Sim_Access_Read)?;
209                        Ok(CmpValue::U64(read_phys_memory(
210                            self.cpu,
211                            address.address,
212                            size_of::<u32>() as i32,
213                        )?))
214                    }
215                    _ => bail!("Invalid dereference size {:?}", v),
216                }
217            }
218            CmpExpr::Reg((n, _)) => {
219                let regno = self.int_register.get_number(n.as_raw_cstr()?)?;
220                let value = self.int_register.read(regno)?;
221                if self.processor_info_v2.get_logical_address_width()? as u32 / u8::BITS == 8 {
222                    Ok(CmpValue::U64(value))
223                } else {
224                    Ok(CmpValue::U32(value as u32))
225                }
226            }
227            CmpExpr::Add((l, r)) => {
228                let lv = self.simplify(l)?;
229                let rv = self.simplify(r)?;
230
231                match (lv, rv) {
232                    (CmpValue::U8(lu), CmpValue::U8(ru)) => Ok(CmpValue::U8(lu.wrapping_add(ru))),
233                    (CmpValue::U8(lu), CmpValue::I8(ru)) => {
234                        Ok(CmpValue::U8(lu.wrapping_add_signed(ru)))
235                    }
236                    (CmpValue::U8(lu), CmpValue::U16(ru)) => {
237                        Ok(CmpValue::U8((lu as u16).wrapping_add(ru) as u8))
238                    }
239                    (CmpValue::U8(lu), CmpValue::I16(ru)) => {
240                        Ok(CmpValue::U8((lu as u16).wrapping_add_signed(ru) as u8))
241                    }
242                    (CmpValue::U8(lu), CmpValue::U32(ru)) => {
243                        Ok(CmpValue::U8((lu as u32).wrapping_add(ru) as u8))
244                    }
245                    (CmpValue::U8(lu), CmpValue::I32(ru)) => {
246                        Ok(CmpValue::U8((lu as u32).wrapping_add_signed(ru) as u8))
247                    }
248                    (CmpValue::U8(lu), CmpValue::U64(ru)) => {
249                        Ok(CmpValue::U8((lu as u64).wrapping_add(ru) as u8))
250                    }
251                    (CmpValue::U8(lu), CmpValue::I64(ru)) => {
252                        Ok(CmpValue::U8((lu as u64).wrapping_add_signed(ru) as u8))
253                    }
254                    (CmpValue::I8(lu), CmpValue::U8(ru)) => {
255                        Ok(CmpValue::I8(lu.wrapping_add_unsigned(ru)))
256                    }
257                    (CmpValue::I8(lu), CmpValue::I8(ru)) => Ok(CmpValue::I8(lu.wrapping_add(ru))),
258                    (CmpValue::I8(lu), CmpValue::U16(ru)) => {
259                        Ok(CmpValue::I8((lu as i16).wrapping_add_unsigned(ru) as i8))
260                    }
261                    (CmpValue::I8(lu), CmpValue::I16(ru)) => {
262                        Ok(CmpValue::I8((lu as i16).wrapping_add(ru) as i8))
263                    }
264                    (CmpValue::I8(lu), CmpValue::U32(ru)) => {
265                        Ok(CmpValue::I8((lu as i32).wrapping_add_unsigned(ru) as i8))
266                    }
267                    (CmpValue::I8(lu), CmpValue::I32(ru)) => {
268                        Ok(CmpValue::I8((lu as i32).wrapping_add(ru) as i8))
269                    }
270                    (CmpValue::I8(lu), CmpValue::U64(ru)) => {
271                        Ok(CmpValue::I8((lu as i64).wrapping_add_unsigned(ru) as i8))
272                    }
273                    (CmpValue::I8(lu), CmpValue::I64(ru)) => {
274                        Ok(CmpValue::I8((lu as i64).wrapping_add(ru) as i8))
275                    }
276                    (CmpValue::U16(lu), CmpValue::U8(ru)) => {
277                        Ok(CmpValue::U16(lu.wrapping_add(ru as u16)))
278                    }
279                    (CmpValue::U16(lu), CmpValue::I8(ru)) => {
280                        Ok(CmpValue::U16(lu.wrapping_add_signed(ru as i16)))
281                    }
282                    (CmpValue::U16(lu), CmpValue::U16(ru)) => {
283                        Ok(CmpValue::U16(lu.wrapping_add(ru)))
284                    }
285                    (CmpValue::U16(lu), CmpValue::I16(ru)) => {
286                        Ok(CmpValue::U16(lu.wrapping_add_signed(ru)))
287                    }
288                    (CmpValue::U16(lu), CmpValue::U32(ru)) => {
289                        Ok(CmpValue::U16((lu as u32).wrapping_add(ru) as u16))
290                    }
291                    (CmpValue::U16(lu), CmpValue::I32(ru)) => {
292                        Ok(CmpValue::U16((lu as u32).wrapping_add_signed(ru) as u16))
293                    }
294                    (CmpValue::U16(lu), CmpValue::U64(ru)) => {
295                        Ok(CmpValue::U16((lu as u64).wrapping_add(ru) as u16))
296                    }
297                    (CmpValue::U16(lu), CmpValue::I64(ru)) => {
298                        Ok(CmpValue::U16((lu as u64).wrapping_add_signed(ru) as u16))
299                    }
300                    (CmpValue::I16(lu), CmpValue::U8(ru)) => {
301                        Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru as u16)))
302                    }
303                    (CmpValue::I16(lu), CmpValue::I8(ru)) => {
304                        Ok(CmpValue::I16(lu.wrapping_add(ru as i16)))
305                    }
306                    (CmpValue::I16(lu), CmpValue::U16(ru)) => {
307                        Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru)))
308                    }
309                    (CmpValue::I16(lu), CmpValue::I16(ru)) => {
310                        Ok(CmpValue::I16(lu.wrapping_add(ru)))
311                    }
312                    (CmpValue::I16(lu), CmpValue::U32(ru)) => {
313                        Ok(CmpValue::I16((lu as i32).wrapping_add_unsigned(ru) as i16))
314                    }
315                    (CmpValue::I16(lu), CmpValue::I32(ru)) => {
316                        Ok(CmpValue::I16((lu as i32).wrapping_add(ru) as i16))
317                    }
318                    (CmpValue::I16(lu), CmpValue::U64(ru)) => {
319                        Ok(CmpValue::I16((lu as i64).wrapping_add_unsigned(ru) as i16))
320                    }
321                    (CmpValue::I16(lu), CmpValue::I64(ru)) => {
322                        Ok(CmpValue::I16((lu as i64).wrapping_add(ru) as i16))
323                    }
324                    (CmpValue::U32(lu), CmpValue::U8(ru)) => {
325                        Ok(CmpValue::U32(lu.wrapping_add(ru as u32)))
326                    }
327                    (CmpValue::U32(lu), CmpValue::I8(ru)) => {
328                        Ok(CmpValue::U32(lu.wrapping_add_signed(ru as i32)))
329                    }
330                    (CmpValue::U32(lu), CmpValue::U16(ru)) => {
331                        Ok(CmpValue::U32(lu.wrapping_add(ru as u32)))
332                    }
333                    (CmpValue::U32(lu), CmpValue::I16(ru)) => {
334                        Ok(CmpValue::U32(lu.wrapping_add_signed(ru as i32)))
335                    }
336                    (CmpValue::U32(lu), CmpValue::U32(ru)) => {
337                        Ok(CmpValue::U32(lu.wrapping_add(ru)))
338                    }
339                    (CmpValue::U32(lu), CmpValue::I32(ru)) => {
340                        Ok(CmpValue::U32(lu.wrapping_add_signed(ru)))
341                    }
342                    (CmpValue::U32(lu), CmpValue::U64(ru)) => {
343                        Ok(CmpValue::U32((lu as u64).wrapping_add(ru) as u32))
344                    }
345                    (CmpValue::U32(lu), CmpValue::I64(ru)) => {
346                        Ok(CmpValue::U32((lu as u64).wrapping_add_signed(ru) as u32))
347                    }
348                    (CmpValue::I32(lu), CmpValue::U8(ru)) => {
349                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
350                    }
351                    (CmpValue::I32(lu), CmpValue::I8(ru)) => {
352                        Ok(CmpValue::I32(lu.wrapping_add(ru as i32)))
353                    }
354                    (CmpValue::I32(lu), CmpValue::U16(ru)) => {
355                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
356                    }
357                    (CmpValue::I32(lu), CmpValue::I16(ru)) => {
358                        Ok(CmpValue::I32(lu.wrapping_add(ru as i32)))
359                    }
360                    (CmpValue::I32(lu), CmpValue::U32(ru)) => {
361                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru)))
362                    }
363                    (CmpValue::I32(lu), CmpValue::I32(ru)) => {
364                        Ok(CmpValue::I32(lu.wrapping_add(ru)))
365                    }
366                    (CmpValue::I32(lu), CmpValue::U64(ru)) => {
367                        Ok(CmpValue::I32((lu as i64).wrapping_add_unsigned(ru) as i32))
368                    }
369                    (CmpValue::I32(lu), CmpValue::I64(ru)) => {
370                        Ok(CmpValue::I32((lu as i64).wrapping_add(ru) as i32))
371                    }
372                    (CmpValue::U64(lu), CmpValue::U8(ru)) => {
373                        Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
374                    }
375                    (CmpValue::U64(lu), CmpValue::I8(ru)) => {
376                        Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
377                    }
378                    (CmpValue::U64(lu), CmpValue::U16(ru)) => {
379                        Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
380                    }
381                    (CmpValue::U64(lu), CmpValue::I16(ru)) => {
382                        Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
383                    }
384                    (CmpValue::U64(lu), CmpValue::U32(ru)) => {
385                        Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
386                    }
387                    (CmpValue::U64(lu), CmpValue::I32(ru)) => {
388                        Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
389                    }
390                    (CmpValue::U64(lu), CmpValue::U64(ru)) => {
391                        Ok(CmpValue::U64(lu.wrapping_add(ru)))
392                    }
393                    (CmpValue::U64(lu), CmpValue::I64(ru)) => {
394                        Ok(CmpValue::U64(lu.wrapping_add_signed(ru)))
395                    }
396                    (CmpValue::I64(lu), CmpValue::U8(ru)) => {
397                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
398                    }
399                    (CmpValue::I64(lu), CmpValue::I8(ru)) => {
400                        Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
401                    }
402                    (CmpValue::I64(lu), CmpValue::U16(ru)) => {
403                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
404                    }
405                    (CmpValue::I64(lu), CmpValue::I16(ru)) => {
406                        Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
407                    }
408                    (CmpValue::I64(lu), CmpValue::U32(ru)) => {
409                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
410                    }
411                    (CmpValue::I64(lu), CmpValue::I32(ru)) => {
412                        Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
413                    }
414                    (CmpValue::I64(lu), CmpValue::U64(ru)) => {
415                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru)))
416                    }
417                    (CmpValue::I64(lu), CmpValue::I64(ru)) => {
418                        Ok(CmpValue::I64(lu.wrapping_add(ru)))
419                    }
420                    _ => bail!("Cannot multiply non-integral types"),
421                }
422            }
423            CmpExpr::Sub((l, r)) => {
424                let lv = self.simplify(l)?;
425                let rv = self.simplify(r)?;
426
427                match (lv, rv) {
428                    (CmpValue::U8(lu), CmpValue::U8(ru)) => Ok(CmpValue::U8(lu.wrapping_sub(ru))),
429                    (CmpValue::U8(lu), CmpValue::I8(ru)) => {
430                        Ok(CmpValue::U8(lu.wrapping_add_signed(-ru)))
431                    }
432                    (CmpValue::U8(lu), CmpValue::U16(ru)) => {
433                        Ok(CmpValue::U8((lu as u16).wrapping_sub(ru) as u8))
434                    }
435                    (CmpValue::U8(lu), CmpValue::I16(ru)) => {
436                        Ok(CmpValue::U8((lu as u16).wrapping_add_signed(-ru) as u8))
437                    }
438                    (CmpValue::U8(lu), CmpValue::U32(ru)) => {
439                        Ok(CmpValue::U8((lu as u32).wrapping_sub(ru) as u8))
440                    }
441                    (CmpValue::U8(lu), CmpValue::I32(ru)) => {
442                        Ok(CmpValue::U8((lu as u32).wrapping_add_signed(-ru) as u8))
443                    }
444                    (CmpValue::U8(lu), CmpValue::U64(ru)) => {
445                        Ok(CmpValue::U8((lu as u64).wrapping_sub(ru) as u8))
446                    }
447                    (CmpValue::U8(lu), CmpValue::I64(ru)) => {
448                        Ok(CmpValue::U8((lu as u64).wrapping_add_signed(-ru) as u8))
449                    }
450                    (CmpValue::I8(lu), CmpValue::U8(ru)) => {
451                        Ok(CmpValue::I8(lu.wrapping_add_unsigned(ru)))
452                    }
453                    (CmpValue::I8(lu), CmpValue::I8(ru)) => Ok(CmpValue::I8(lu.wrapping_sub(ru))),
454                    (CmpValue::I8(lu), CmpValue::U16(ru)) => {
455                        Ok(CmpValue::I8((lu as i16).wrapping_add_unsigned(ru) as i8))
456                    }
457                    (CmpValue::I8(lu), CmpValue::I16(ru)) => {
458                        Ok(CmpValue::I8((lu as i16).wrapping_sub(ru) as i8))
459                    }
460                    (CmpValue::I8(lu), CmpValue::U32(ru)) => {
461                        Ok(CmpValue::I8((lu as i32).wrapping_add_unsigned(ru) as i8))
462                    }
463                    (CmpValue::I8(lu), CmpValue::I32(ru)) => {
464                        Ok(CmpValue::I8((lu as i32).wrapping_sub(ru) as i8))
465                    }
466                    (CmpValue::I8(lu), CmpValue::U64(ru)) => {
467                        Ok(CmpValue::I8((lu as i64).wrapping_add_unsigned(ru) as i8))
468                    }
469                    (CmpValue::I8(lu), CmpValue::I64(ru)) => {
470                        Ok(CmpValue::I8((lu as i64).wrapping_sub(ru) as i8))
471                    }
472                    (CmpValue::U16(lu), CmpValue::U8(ru)) => {
473                        Ok(CmpValue::U16(lu.wrapping_sub(ru as u16)))
474                    }
475                    (CmpValue::U16(lu), CmpValue::I8(ru)) => {
476                        Ok(CmpValue::U16(lu.wrapping_add_signed(-ru as i16)))
477                    }
478                    (CmpValue::U16(lu), CmpValue::U16(ru)) => {
479                        Ok(CmpValue::U16(lu.wrapping_sub(ru)))
480                    }
481                    (CmpValue::U16(lu), CmpValue::I16(ru)) => {
482                        Ok(CmpValue::U16(lu.wrapping_add_signed(-ru)))
483                    }
484                    (CmpValue::U16(lu), CmpValue::U32(ru)) => {
485                        Ok(CmpValue::U16((lu as u32).wrapping_sub(ru) as u16))
486                    }
487                    (CmpValue::U16(lu), CmpValue::I32(ru)) => {
488                        Ok(CmpValue::U16((lu as u32).wrapping_add_signed(-ru) as u16))
489                    }
490                    (CmpValue::U16(lu), CmpValue::U64(ru)) => {
491                        Ok(CmpValue::U16((lu as u64).wrapping_sub(ru) as u16))
492                    }
493                    (CmpValue::U16(lu), CmpValue::I64(ru)) => {
494                        Ok(CmpValue::U16((lu as u64).wrapping_add_signed(-ru) as u16))
495                    }
496                    (CmpValue::I16(lu), CmpValue::U8(ru)) => {
497                        Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru as u16)))
498                    }
499                    (CmpValue::I16(lu), CmpValue::I8(ru)) => {
500                        Ok(CmpValue::I16(lu.wrapping_sub(ru as i16)))
501                    }
502                    (CmpValue::I16(lu), CmpValue::U16(ru)) => {
503                        Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru)))
504                    }
505                    (CmpValue::I16(lu), CmpValue::I16(ru)) => {
506                        Ok(CmpValue::I16(lu.wrapping_sub(ru)))
507                    }
508                    (CmpValue::I16(lu), CmpValue::U32(ru)) => {
509                        Ok(CmpValue::I16((lu as i32).wrapping_add_unsigned(ru) as i16))
510                    }
511                    (CmpValue::I16(lu), CmpValue::I32(ru)) => {
512                        Ok(CmpValue::I16((lu as i32).wrapping_sub(ru) as i16))
513                    }
514                    (CmpValue::I16(lu), CmpValue::U64(ru)) => {
515                        Ok(CmpValue::I16((lu as i64).wrapping_add_unsigned(ru) as i16))
516                    }
517                    (CmpValue::I16(lu), CmpValue::I64(ru)) => {
518                        Ok(CmpValue::I16((lu as i64).wrapping_sub(ru) as i16))
519                    }
520                    (CmpValue::U32(lu), CmpValue::U8(ru)) => {
521                        Ok(CmpValue::U32(lu.wrapping_sub(ru as u32)))
522                    }
523                    (CmpValue::U32(lu), CmpValue::I8(ru)) => {
524                        Ok(CmpValue::U32(lu.wrapping_add_signed(-ru as i32)))
525                    }
526                    (CmpValue::U32(lu), CmpValue::U16(ru)) => {
527                        Ok(CmpValue::U32(lu.wrapping_sub(ru as u32)))
528                    }
529                    (CmpValue::U32(lu), CmpValue::I16(ru)) => {
530                        Ok(CmpValue::U32(lu.wrapping_add_signed(-ru as i32)))
531                    }
532                    (CmpValue::U32(lu), CmpValue::U32(ru)) => {
533                        Ok(CmpValue::U32(lu.wrapping_sub(ru)))
534                    }
535                    (CmpValue::U32(lu), CmpValue::I32(ru)) => {
536                        Ok(CmpValue::U32(lu.wrapping_add_signed(-ru)))
537                    }
538                    (CmpValue::U32(lu), CmpValue::U64(ru)) => {
539                        Ok(CmpValue::U32((lu as u64).wrapping_sub(ru) as u32))
540                    }
541                    (CmpValue::U32(lu), CmpValue::I64(ru)) => {
542                        Ok(CmpValue::U32((lu as u64).wrapping_add_signed(-ru) as u32))
543                    }
544                    (CmpValue::I32(lu), CmpValue::U8(ru)) => {
545                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
546                    }
547                    (CmpValue::I32(lu), CmpValue::I8(ru)) => {
548                        Ok(CmpValue::I32(lu.wrapping_sub(ru as i32)))
549                    }
550                    (CmpValue::I32(lu), CmpValue::U16(ru)) => {
551                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
552                    }
553                    (CmpValue::I32(lu), CmpValue::I16(ru)) => {
554                        Ok(CmpValue::I32(lu.wrapping_sub(ru as i32)))
555                    }
556                    (CmpValue::I32(lu), CmpValue::U32(ru)) => {
557                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru)))
558                    }
559                    (CmpValue::I32(lu), CmpValue::I32(ru)) => {
560                        Ok(CmpValue::I32(lu.wrapping_sub(ru)))
561                    }
562                    (CmpValue::I32(lu), CmpValue::U64(ru)) => {
563                        Ok(CmpValue::I32((lu as i64).wrapping_add_unsigned(ru) as i32))
564                    }
565                    (CmpValue::I32(lu), CmpValue::I64(ru)) => {
566                        Ok(CmpValue::I32((lu as i64).wrapping_sub(ru) as i32))
567                    }
568                    (CmpValue::U64(lu), CmpValue::U8(ru)) => {
569                        Ok(CmpValue::U64(lu.wrapping_sub(ru as u64)))
570                    }
571                    (CmpValue::U64(lu), CmpValue::I8(ru)) => {
572                        Ok(CmpValue::U64(lu.wrapping_add_signed(-ru as i64)))
573                    }
574                    (CmpValue::U64(lu), CmpValue::U16(ru)) => {
575                        Ok(CmpValue::U64(lu.wrapping_sub(ru as u64)))
576                    }
577                    (CmpValue::U64(lu), CmpValue::I16(ru)) => {
578                        Ok(CmpValue::U64(lu.wrapping_add_signed(-ru as i64)))
579                    }
580                    (CmpValue::U64(lu), CmpValue::U32(ru)) => {
581                        Ok(CmpValue::U64(lu.wrapping_sub(ru as u64)))
582                    }
583                    (CmpValue::U64(lu), CmpValue::I32(ru)) => {
584                        Ok(CmpValue::U64(lu.wrapping_add_signed(-ru as i64)))
585                    }
586                    (CmpValue::U64(lu), CmpValue::U64(ru)) => {
587                        Ok(CmpValue::U64(lu.wrapping_sub(ru)))
588                    }
589                    (CmpValue::U64(lu), CmpValue::I64(ru)) => {
590                        Ok(CmpValue::U64(lu.wrapping_add_signed(-ru)))
591                    }
592                    (CmpValue::I64(lu), CmpValue::U8(ru)) => {
593                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
594                    }
595                    (CmpValue::I64(lu), CmpValue::I8(ru)) => {
596                        Ok(CmpValue::I64(lu.wrapping_sub(ru as i64)))
597                    }
598                    (CmpValue::I64(lu), CmpValue::U16(ru)) => {
599                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
600                    }
601                    (CmpValue::I64(lu), CmpValue::I16(ru)) => {
602                        Ok(CmpValue::I64(lu.wrapping_sub(ru as i64)))
603                    }
604                    (CmpValue::I64(lu), CmpValue::U32(ru)) => {
605                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
606                    }
607                    (CmpValue::I64(lu), CmpValue::I32(ru)) => {
608                        Ok(CmpValue::I64(lu.wrapping_sub(ru as i64)))
609                    }
610                    (CmpValue::I64(lu), CmpValue::U64(ru)) => {
611                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru)))
612                    }
613                    (CmpValue::I64(lu), CmpValue::I64(ru)) => {
614                        Ok(CmpValue::I64(lu.wrapping_sub(ru)))
615                    }
616                    _ => bail!("Cannot multiply non-integral types"),
617                }
618            }
619            CmpExpr::Shift((shiftee, shifter, typ)) => {
620                let shiftee = self.simplify(shiftee)?;
621                let shifter = self.simplify(shifter)?;
622
623                match (shiftee, shifter) {
624                    (CmpValue::U8(lu), CmpValue::U8(ru)) => match typ {
625                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru as u32))),
626                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
627                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
628                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru as u32))),
629                    },
630                    (CmpValue::U8(lu), CmpValue::I8(ri)) => {
631                        let ru = ri as u8;
632                        match typ {
633                            CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru as u32))),
634                            CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
635                            CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
636                            CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru as u32))),
637                        }
638                    }
639                    (CmpValue::U8(lu), CmpValue::U16(ru)) => match typ {
640                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru as u32))),
641                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
642                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
643                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru as u32))),
644                    },
645                    (CmpValue::U8(lu), CmpValue::I16(ri)) => match typ {
646                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ri as u32))),
647                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
648                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
649                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ri as u32))),
650                    },
651                    (CmpValue::U8(lu), CmpValue::U32(ru)) => match typ {
652                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru))),
653                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru))),
654                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru))),
655                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru))),
656                    },
657                    (CmpValue::U8(lu), CmpValue::I32(ri)) => match typ {
658                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ri as u32))),
659                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
660                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
661                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ri as u32))),
662                    },
663                    (CmpValue::U8(lu), CmpValue::U64(ru)) => match typ {
664                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru as u32))),
665                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
666                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
667                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru as u32))),
668                    },
669                    (CmpValue::U8(lu), CmpValue::I64(ri)) => match typ {
670                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ri as u32))),
671                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
672                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
673                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ri as u32))),
674                    },
675                    (CmpValue::I8(li), CmpValue::U8(ru)) => match typ {
676                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ru as u32))),
677                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
678                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
679                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ru as u32))),
680                    },
681                    (CmpValue::I8(li), CmpValue::I8(ri)) => match typ {
682                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ri as u32))),
683                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
684                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
685                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ri as u32))),
686                    },
687                    (CmpValue::I8(li), CmpValue::U16(ru)) => match typ {
688                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ru as u32))),
689                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
690                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
691                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ru as u32))),
692                    },
693                    (CmpValue::I8(li), CmpValue::I16(ri)) => match typ {
694                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ri as u32))),
695                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
696                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
697                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ri as u32))),
698                    },
699                    (CmpValue::I8(li), CmpValue::U32(ru)) => match typ {
700                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ru))),
701                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ru))),
702                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ru))),
703                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ru))),
704                    },
705                    (CmpValue::I8(li), CmpValue::I32(ri)) => match typ {
706                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ri as u32))),
707                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
708                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
709                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ri as u32))),
710                    },
711                    (CmpValue::I8(li), CmpValue::U64(ru)) => match typ {
712                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ru as u32))),
713                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
714                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
715                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ru as u32))),
716                    },
717                    (CmpValue::I8(li), CmpValue::I64(ri)) => match typ {
718                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ri as u32))),
719                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
720                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
721                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ri as u32))),
722                    },
723                    (CmpValue::U16(lu), CmpValue::U8(ru)) => match typ {
724                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ru as u32))),
725                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
726                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
727                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ru as u32))),
728                    },
729                    (CmpValue::U16(lu), CmpValue::I8(ri)) => match typ {
730                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ri as u32))),
731                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
732                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
733                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ri as u32))),
734                    },
735                    (CmpValue::U16(lu), CmpValue::U16(ru)) => match typ {
736                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ru as u32))),
737                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
738                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
739                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ru as u32))),
740                    },
741                    (CmpValue::U16(lu), CmpValue::I16(ri)) => match typ {
742                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ri as u32))),
743                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
744                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
745                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ri as u32))),
746                    },
747                    (CmpValue::U16(lu), CmpValue::U32(ru)) => match typ {
748                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ru))),
749                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ru))),
750                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ru))),
751                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ru))),
752                    },
753                    (CmpValue::U16(lu), CmpValue::I32(ri)) => match typ {
754                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ri as u32))),
755                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
756                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
757                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ri as u32))),
758                    },
759                    (CmpValue::U16(lu), CmpValue::U64(ru)) => match typ {
760                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ru as u32))),
761                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
762                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
763                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ru as u32))),
764                    },
765                    (CmpValue::U16(lu), CmpValue::I64(ri)) => match typ {
766                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ri as u32))),
767                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
768                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
769                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ri as u32))),
770                    },
771                    (CmpValue::I16(li), CmpValue::U8(ru)) => match typ {
772                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ru as u32))),
773                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
774                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
775                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ru as u32))),
776                    },
777                    (CmpValue::I16(li), CmpValue::I8(ri)) => match typ {
778                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ri as u32))),
779                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
780                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
781                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ri as u32))),
782                    },
783                    (CmpValue::I16(li), CmpValue::U16(ru)) => match typ {
784                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ru as u32))),
785                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
786                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
787                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ru as u32))),
788                    },
789                    (CmpValue::I16(li), CmpValue::I16(ri)) => match typ {
790                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ri as u32))),
791                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
792                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
793                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ri as u32))),
794                    },
795                    (CmpValue::I16(li), CmpValue::U32(ru)) => match typ {
796                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ru))),
797                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ru))),
798                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ru))),
799                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ru))),
800                    },
801                    (CmpValue::I16(li), CmpValue::I32(ri)) => match typ {
802                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ri as u32))),
803                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
804                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
805                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ri as u32))),
806                    },
807                    (CmpValue::I16(li), CmpValue::U64(ru)) => match typ {
808                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ru as u32))),
809                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
810                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
811                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ru as u32))),
812                    },
813                    (CmpValue::I16(li), CmpValue::I64(ri)) => match typ {
814                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ri as u32))),
815                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
816                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
817                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ri as u32))),
818                    },
819                    (CmpValue::U32(lu), CmpValue::U8(ru)) => match typ {
820                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ru as u32))),
821                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
822                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
823                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ru as u32))),
824                    },
825                    (CmpValue::U32(lu), CmpValue::I8(ri)) => match typ {
826                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ri as u32))),
827                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
828                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
829                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ri as u32))),
830                    },
831                    (CmpValue::U32(lu), CmpValue::U16(ru)) => match typ {
832                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ru as u32))),
833                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
834                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
835                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ru as u32))),
836                    },
837                    (CmpValue::U32(lu), CmpValue::I16(ri)) => match typ {
838                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ri as u32))),
839                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
840                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
841                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ri as u32))),
842                    },
843                    (CmpValue::U32(lu), CmpValue::U32(ru)) => match typ {
844                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ru))),
845                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ru))),
846                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ru))),
847                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ru))),
848                    },
849                    (CmpValue::U32(lu), CmpValue::I32(ri)) => match typ {
850                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ri as u32))),
851                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
852                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
853                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ri as u32))),
854                    },
855                    (CmpValue::U32(lu), CmpValue::U64(ru)) => match typ {
856                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ru as u32))),
857                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
858                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
859                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ru as u32))),
860                    },
861                    (CmpValue::U32(lu), CmpValue::I64(ri)) => match typ {
862                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ri as u32))),
863                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
864                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
865                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ri as u32))),
866                    },
867                    (CmpValue::I32(li), CmpValue::U8(ru)) => match typ {
868                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ru as u32))),
869                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
870                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
871                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ru as u32))),
872                    },
873                    (CmpValue::I32(li), CmpValue::I8(ri)) => match typ {
874                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ri as u32))),
875                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
876                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
877                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ri as u32))),
878                    },
879                    (CmpValue::I32(li), CmpValue::U16(ru)) => match typ {
880                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ru as u32))),
881                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
882                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
883                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ru as u32))),
884                    },
885                    (CmpValue::I32(li), CmpValue::I16(ri)) => match typ {
886                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ri as u32))),
887                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
888                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
889                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ri as u32))),
890                    },
891                    (CmpValue::I32(li), CmpValue::U32(ru)) => match typ {
892                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ru))),
893                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ru))),
894                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ru))),
895                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ru))),
896                    },
897                    (CmpValue::I32(li), CmpValue::I32(ri)) => match typ {
898                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ri as u32))),
899                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
900                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
901                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ri as u32))),
902                    },
903                    (CmpValue::I32(li), CmpValue::U64(ru)) => match typ {
904                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ru as u32))),
905                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
906                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
907                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ru as u32))),
908                    },
909                    (CmpValue::I32(li), CmpValue::I64(ri)) => match typ {
910                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ri as u32))),
911                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
912                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
913                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ri as u32))),
914                    },
915                    (CmpValue::U64(lu), CmpValue::U8(ru)) => match typ {
916                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ru as u32))),
917                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
918                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
919                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ru as u32))),
920                    },
921                    (CmpValue::U64(lu), CmpValue::I8(ri)) => match typ {
922                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ri as u32))),
923                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
924                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
925                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ri as u32))),
926                    },
927                    (CmpValue::U64(lu), CmpValue::U16(ru)) => match typ {
928                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ru as u32))),
929                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
930                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
931                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ru as u32))),
932                    },
933                    (CmpValue::U64(lu), CmpValue::I16(ri)) => match typ {
934                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ri as u32))),
935                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
936                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
937                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ri as u32))),
938                    },
939                    (CmpValue::U64(lu), CmpValue::U32(ru)) => match typ {
940                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ru))),
941                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ru))),
942                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ru))),
943                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ru))),
944                    },
945                    (CmpValue::U64(lu), CmpValue::I32(ri)) => match typ {
946                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ri as u32))),
947                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
948                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
949                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ri as u32))),
950                    },
951                    (CmpValue::U64(lu), CmpValue::U64(ru)) => match typ {
952                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ru as u32))),
953                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
954                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
955                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ru as u32))),
956                    },
957                    (CmpValue::U64(lu), CmpValue::I64(ri)) => match typ {
958                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ri as u32))),
959                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
960                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
961                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ri as u32))),
962                    },
963                    (CmpValue::I64(li), CmpValue::U8(ru)) => match typ {
964                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ru as u32))),
965                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
966                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
967                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ru as u32))),
968                    },
969                    (CmpValue::I64(li), CmpValue::I8(ri)) => match typ {
970                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ri as u32))),
971                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
972                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
973                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ri as u32))),
974                    },
975                    (CmpValue::I64(li), CmpValue::U16(ru)) => match typ {
976                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ru as u32))),
977                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
978                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
979                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ru as u32))),
980                    },
981                    (CmpValue::I64(li), CmpValue::I16(ri)) => match typ {
982                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ri as u32))),
983                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
984                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
985                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ri as u32))),
986                    },
987                    (CmpValue::I64(li), CmpValue::U32(ru)) => match typ {
988                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ru))),
989                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ru))),
990                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ru))),
991                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ru))),
992                    },
993                    (CmpValue::I64(li), CmpValue::I32(ri)) => match typ {
994                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ri as u32))),
995                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
996                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
997                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ri as u32))),
998                    },
999                    (CmpValue::I64(li), CmpValue::U64(ru)) => match typ {
1000                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ru as u32))),
1001                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
1002                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
1003                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ru as u32))),
1004                    },
1005                    (CmpValue::I64(li), CmpValue::I64(ri)) => match typ {
1006                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ri as u32))),
1007                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
1008                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
1009                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ri as u32))),
1010                    },
1011                    _ => {
1012                        bail!("Cannot shift non-integral types");
1013                    }
1014                }
1015            }
1016            CmpExpr::I16(i) => Ok(CmpValue::I16(*i)),
1017            CmpExpr::U32(u) => Ok(CmpValue::U32(*u)),
1018            CmpExpr::I32(i) => Ok(CmpValue::I32(*i)),
1019            _ => bail!("Unsupported expression {:?}", expr),
1020        }
1021    }
1022}
1023
1024pub(crate) struct Disassembler {
1025    decoder: InstDecoder,
1026    last: Option<Instruction>,
1027}
1028
1029impl Disassembler {
1030    pub fn new() -> Self {
1031        Self {
1032            decoder: InstDecoder::default(),
1033            last: None,
1034        }
1035    }
1036}
1037
1038impl Default for Disassembler {
1039    fn default() -> Self {
1040        Self::new()
1041    }
1042}
1043
1044impl TracerDisassembler for Disassembler {
1045    fn disassemble(&mut self, bytes: &[u8]) -> Result<()> {
1046        let mut r = U8Reader::new(bytes);
1047
1048        if let Ok(insn) = self.decoder.decode(&mut r) {
1049            self.last = Some(insn);
1050        } else {
1051            bail!("Could not disassemble {:?}", bytes);
1052        }
1053
1054        Ok(())
1055    }
1056
1057    fn disassemble_to_string(&mut self, bytes: &[u8]) -> Result<String> {
1058        let mut r = U8Reader::new(bytes);
1059
1060        if let Ok(insn) = self.decoder.decode(&mut r) {
1061            Ok(insn.to_string())
1062        } else {
1063            bail!("Could not disassemble {:?}", bytes);
1064        }
1065    }
1066
1067    fn last_was_control_flow(&self) -> bool {
1068        if let Some(last) = self.last.as_ref() {
1069            // NOTE: This is imprecise on ARM because PC is not restricted
1070            // TODO: Are there any other control flow instructions?
1071            return matches!(last.opcode, Opcode::B);
1072        }
1073
1074        false
1075    }
1076
1077    // TODO: Make call/ret distinction more accurate, all three can ret/call far or near, but
1078    // there are semantic versions based on operands:
1079    // https://inst.eecs.berkeley.edu/~cs61c/fa20/pdfs/lectures/lec12-bw.pdf
1080
1081    fn last_was_call(&self) -> bool {
1082        if let Some(last) = self.last.as_ref() {
1083            return matches!(last.opcode, Opcode::BL | Opcode::BLX);
1084        }
1085
1086        false
1087    }
1088
1089    // https://quantum5.ca/2017/10/19/arm-ways-to-return/
1090    fn last_was_ret(&self) -> bool {
1091        if let Some(last) = self.last.as_ref() {
1092            if (last.opcode == Opcode::POP
1093                && last.operands.iter().any(|o| match o {
1094                    Operand::Reg(r) => r.number() == 15,
1095                    Operand::RegList(l) => l & (1 << 15) != 0,
1096                    _ => false,
1097                }))
1098                || (last.opcode == Opcode::MOV
1099                    && last
1100                        .operands
1101                        .first()
1102                        .is_some_and(|f| matches!(f, Operand::Reg(r) if r.number() == 15)))
1103            {
1104                true
1105            } else {
1106                last.opcode == Opcode::BX
1107            }
1108        } else {
1109            false
1110        }
1111    }
1112
1113    fn last_was_cmp(&self) -> bool {
1114        if let Some(last) = self.last.as_ref() {
1115            return matches!(
1116                last.opcode,
1117                Opcode::CMN | Opcode::CMP | Opcode::TST | Opcode::TEQ
1118            );
1119        }
1120
1121        false
1122    }
1123
1124    fn cmp(&self) -> Vec<CmpExpr> {
1125        let mut cmp_exprs = Vec::new();
1126        if self.last_was_cmp() {
1127            if let Some(last) = self.last.as_ref() {
1128                for operand in &last.operands {
1129                    match operand {
1130                        Operand::Reg(r) => {
1131                            cmp_exprs.push(CmpExpr::Reg((format!("r{}", r.number()), 0)));
1132                        }
1133                        Operand::RegWBack(r, _w) => {
1134                            cmp_exprs.push(CmpExpr::Reg((format!("r{}", r.number()), 0)));
1135                        }
1136                        Operand::RegList(l) => {
1137                            for i in 0..16 {
1138                                if l & (1 << i) != 0 {
1139                                    cmp_exprs.push(CmpExpr::Reg((format!("r{}", i), 0)));
1140                                }
1141                            }
1142                        }
1143                        Operand::RegDeref(r) => {
1144                            cmp_exprs.push(CmpExpr::Deref((
1145                                Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1146                                None,
1147                            )));
1148                        }
1149                        Operand::RegShift(rs) => match rs.into_shift() {
1150                            RegShiftStyle::RegImm(r) => {
1151                                let reg = r.shiftee();
1152                                let imm = r.imm();
1153                                let typ = match r.stype() {
1154                                    ShiftStyle::LSL => CmpExprShift::Lsl,
1155                                    ShiftStyle::LSR => CmpExprShift::Lsr,
1156                                    ShiftStyle::ASR => CmpExprShift::Asr,
1157                                    ShiftStyle::ROR => CmpExprShift::Ror,
1158                                };
1159                                cmp_exprs.push(CmpExpr::Shift((
1160                                    Box::new(CmpExpr::Reg((format!("r{}", reg.number()), 0))),
1161                                    Box::new(CmpExpr::U8(imm)),
1162                                    typ,
1163                                )));
1164                            }
1165                            RegShiftStyle::RegReg(r) => {
1166                                let shiftee = r.shiftee();
1167                                let by = r.shifter();
1168                                let typ = match r.stype() {
1169                                    ShiftStyle::LSL => CmpExprShift::Lsl,
1170                                    ShiftStyle::LSR => CmpExprShift::Lsr,
1171                                    ShiftStyle::ASR => CmpExprShift::Asr,
1172                                    ShiftStyle::ROR => CmpExprShift::Ror,
1173                                };
1174                                cmp_exprs.push(CmpExpr::Shift((
1175                                    Box::new(CmpExpr::Reg((format!("r{}", shiftee.number()), 0))),
1176                                    Box::new(CmpExpr::Reg((format!("r{}", by.number()), 0))),
1177                                    typ,
1178                                )));
1179                            }
1180                        },
1181                        Operand::RegDerefPostindexRegShift(r, _, _, _) => {
1182                            cmp_exprs.push(CmpExpr::Deref((
1183                                Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1184                                None,
1185                            )));
1186                        }
1187                        Operand::RegDerefPreindexRegShift(r, rs, a, _) => match rs.into_shift() {
1188                            RegShiftStyle::RegImm(ri) => {
1189                                let reg = ri.shiftee();
1190                                let imm = ri.imm();
1191                                let typ = match ri.stype() {
1192                                    ShiftStyle::LSL => CmpExprShift::Lsl,
1193                                    ShiftStyle::LSR => CmpExprShift::Lsr,
1194                                    ShiftStyle::ASR => CmpExprShift::Asr,
1195                                    ShiftStyle::ROR => CmpExprShift::Ror,
1196                                };
1197                                cmp_exprs.push(CmpExpr::Deref((
1198                                    Box::new(CmpExpr::Add((
1199                                        Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1200                                        Box::new(CmpExpr::Shift((
1201                                            Box::new(CmpExpr::Reg((
1202                                                format!("r{}", reg.number()),
1203                                                0,
1204                                            ))),
1205                                            Box::new(CmpExpr::U8(imm)),
1206                                            typ,
1207                                        ))),
1208                                    ))),
1209                                    None,
1210                                )));
1211                            }
1212                            RegShiftStyle::RegReg(ri) => {
1213                                let shiftee = ri.shiftee();
1214                                let by = ri.shifter();
1215                                let typ = match ri.stype() {
1216                                    ShiftStyle::LSL => CmpExprShift::Lsl,
1217                                    ShiftStyle::LSR => CmpExprShift::Lsr,
1218                                    ShiftStyle::ASR => CmpExprShift::Asr,
1219                                    ShiftStyle::ROR => CmpExprShift::Ror,
1220                                };
1221                                cmp_exprs.push(CmpExpr::Deref((
1222                                    if *a {
1223                                        Box::new(CmpExpr::Add((
1224                                            Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1225                                            Box::new(CmpExpr::Shift((
1226                                                Box::new(CmpExpr::Reg((
1227                                                    format!("r{}", shiftee.number()),
1228                                                    0,
1229                                                ))),
1230                                                Box::new(CmpExpr::Reg((
1231                                                    format!("r{}", by.number()),
1232                                                    0,
1233                                                ))),
1234                                                typ,
1235                                            ))),
1236                                        )))
1237                                    } else {
1238                                        Box::new(CmpExpr::Sub((
1239                                            Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1240                                            Box::new(CmpExpr::Shift((
1241                                                Box::new(CmpExpr::Reg((
1242                                                    format!("r{}", shiftee.number()),
1243                                                    0,
1244                                                ))),
1245                                                Box::new(CmpExpr::Reg((
1246                                                    format!("r{}", by.number()),
1247                                                    0,
1248                                                ))),
1249                                                typ,
1250                                            ))),
1251                                        )))
1252                                    },
1253                                    None,
1254                                )));
1255                            }
1256                        },
1257                        Operand::RegDerefPostindexOffset(r, _, _, _) => {
1258                            cmp_exprs.push(CmpExpr::Deref((
1259                                Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1260                                None,
1261                            )));
1262                        }
1263                        Operand::RegDerefPreindexOffset(r, i, a, _) => {
1264                            cmp_exprs.push(CmpExpr::Deref((
1265                                if *a {
1266                                    Box::new(CmpExpr::Add((
1267                                        Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1268                                        Box::new(CmpExpr::U16(*i)),
1269                                    )))
1270                                } else {
1271                                    Box::new(CmpExpr::Sub((
1272                                        Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1273                                        Box::new(CmpExpr::U16(*i)),
1274                                    )))
1275                                },
1276                                None,
1277                            )))
1278                        }
1279                        Operand::RegDerefPostindexReg(r, _, _, _) => {
1280                            cmp_exprs.push(CmpExpr::Deref((
1281                                Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1282                                None,
1283                            )));
1284                        }
1285                        Operand::RegDerefPreindexReg(r, i, a, _) => {
1286                            cmp_exprs.push(CmpExpr::Deref((
1287                                if *a {
1288                                    Box::new(CmpExpr::Add((
1289                                        Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1290                                        Box::new(CmpExpr::Reg((format!("r{}", i.number()), 0))),
1291                                    )))
1292                                } else {
1293                                    Box::new(CmpExpr::Sub((
1294                                        Box::new(CmpExpr::Reg((format!("r{}", r.number()), 0))),
1295                                        Box::new(CmpExpr::Reg((format!("r{}", i.number()), 0))),
1296                                    )))
1297                                },
1298                                None,
1299                            )))
1300                        }
1301                        Operand::Imm12(i) => {
1302                            cmp_exprs.push(CmpExpr::U16(*i));
1303                        }
1304                        Operand::Imm32(i) => {
1305                            cmp_exprs.push(CmpExpr::U32(*i));
1306                        }
1307                        _ => {}
1308                    }
1309                }
1310            }
1311        }
1312
1313        cmp_exprs
1314    }
1315
1316    // NOTE: CmpType is not well suited for arm
1317    fn cmp_type(&self) -> Vec<CmpType> {
1318        if self.last_was_cmp() {
1319            if let Some(last) = self.last.as_ref() {
1320                return match last.opcode {
1321                    Opcode::CMP => vec![CmpType::Equal, CmpType::Lesser, CmpType::Greater],
1322                    Opcode::CMN => vec![CmpType::Equal, CmpType::Lesser, CmpType::Greater],
1323                    Opcode::TST => vec![CmpType::Equal, CmpType::Lesser, CmpType::Greater],
1324                    Opcode::TEQ => vec![CmpType::Equal],
1325                    _ => vec![],
1326                };
1327            }
1328        }
1329
1330        vec![]
1331    }
1332}