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