1use crate::{
2 CallContinuation, CallInterception, CallSite, DomainMemory, EmulatorError, EmulatorErrorKind,
3 Interpreter,
4};
5use qcode::{
6 address_index::{AddressIndex, AddressTarget},
7 context::Context,
8 space::{MemorySpaceId, Space, SpaceId, SpaceType},
9 value::{
10 BasicBlock, BlockId, BlockParamId, BlockRef, FunctionBody, FunctionId, Instruction,
11 LocalValueId, Value, ValueId, ValueRef, Varnode,
12 insn::{
13 Branch, BranchInd, CBranch, Call, CallInd, Callee, Carry, Extract, InstructionId,
14 InstructionRef, IntBinop, LzCount, Mnemonic, PopCount, Range, Return, SBorrow, SCarry,
15 Scan, Sext, Store, Tuple, Unop, Zext,
16 },
17 varnode::{VarnodeId, register::RegisterId},
18 },
19};
20use std::cmp;
21
22mod float80;
23
24use rustc_apfloat::{
25 Float, FloatConvert, Round, Status,
26 ieee::{Double, Single, X87DoubleExtended},
27};
28use rustc_hash::{FxHashMap, FxHashSet};
29
30use super::DomainValue;
31
32fn require_real_callee(callee: Callee) -> Result<FunctionId, EmulatorErrorKind> {
33 match callee {
34 Callee::Real(target) => Ok(target),
35 Callee::Minted(slot) => Err(EmulatorErrorKind::UnresolvedMintedCallee(slot)),
36 }
37}
38
39fn call_is_regpure(ctx: &Context<'_>, call_id: InstructionId) -> bool {
44 matches!(
45 ctx.get_insn(call_id).mnemonic(),
46 Mnemonic::Call(call) if call.tag.is_regpure()
47 )
48}
49
50#[derive(Debug, Default, Clone)]
51pub struct EmulatedSpace(FxHashMap<u64, u8>);
52
53impl EmulatedSpace {
54 pub fn read_byte(&self, addr: u64) -> Result<u8, EmulatorErrorKind> {
55 self.0
56 .get(&addr)
57 .copied()
58 .ok_or(EmulatorErrorKind::MemoryReadError(addr))
59 }
60
61 pub fn read(&self, addr: u64, size: usize) -> Result<Vec<u8>, EmulatorErrorKind> {
62 (0..size).map(|i| self.read_byte(addr + i as u64)).collect()
63 }
64
65 pub fn read_zero_filled(&self, addr: u64, size: usize) -> Vec<u8> {
66 (0..size)
67 .map(|i| self.0.get(&(addr + i as u64)).copied().unwrap_or(0))
68 .collect()
69 }
70
71 pub fn write_byte(&mut self, addr: u64, value: u8) {
72 self.0.insert(addr, value);
73 }
74
75 pub fn reserve(&mut self, additional: usize) {
78 self.0.reserve(additional);
79 }
80
81 pub fn get_mut_region(
84 &mut self,
85 addr: u64,
86 size: usize,
87 ) -> Result<EmulatedSpaceRegion<'_>, EmulatorErrorKind> {
88 let end = addr
89 .checked_add(size as u64)
90 .ok_or(EmulatorErrorKind::AddressOverflow(addr, size))?;
91 Ok(EmulatedSpaceRegion::new(self, addr, end))
92 }
93
94 pub fn read_u128(&self, addr: u64, size: u64) -> Result<u128, EmulatorErrorKind> {
96 let mut res = 0u128;
97
98 for cur in addr..addr + cmp::min(size, 16) {
99 let byte = self.read_byte(cur)?;
100 res |= u128::from(byte) << ((cur - addr) * 8);
101 }
102
103 Ok(res)
104 }
105
106 pub fn read_u128_zero_filled(&self, addr: u64, size: u64) -> u128 {
108 let mut res = 0u128;
109
110 for cur in addr..addr + cmp::min(size, 16) {
111 let byte = self.0.get(&cur).copied().unwrap_or(0);
112 res |= u128::from(byte) << ((cur - addr) * 8);
113 }
114
115 res
116 }
117}
118
119pub struct EmulatedSpaceRegion<'space> {
121 space: &'space mut EmulatedSpace,
122 start: u64,
123 end: u64,
124}
125
126impl<'space> EmulatedSpaceRegion<'space> {
127 pub fn new(space: &'space mut EmulatedSpace, start: u64, end: u64) -> Self {
128 Self { space, start, end }
129 }
130
131 pub fn size(&self) -> usize {
133 (self.end - self.start) as usize
134 }
135
136 pub fn write_u128(&mut self, value: u128) {
138 let end = self.start + cmp::min(16, self.size()) as u64;
139 for addr in self.start..end {
140 let byte = u8::try_from((value >> ((addr - self.start) * 8)) & 0xffu128).unwrap();
141 self.space.write_byte(addr, byte);
142 }
143 }
144}
145
146#[derive(Debug, Default, Clone)]
147pub struct EmulatedMemory {
148 spaces: FxHashMap<MemorySpaceId, EmulatedSpace>,
149 zero_filled_spaces: FxHashSet<MemorySpaceId>,
150 configured_space_count: Option<usize>,
154}
155
156impl EmulatedMemory {
157 fn is_zero_filled(&self, space: MemorySpaceId) -> bool {
158 matches!(space, MemorySpaceId::Temp(_)) || self.zero_filled_spaces.contains(&space)
159 }
160
161 fn configure_spaces(&mut self, ctx: &Context<'_>) {
162 let space_count = ctx.space_count();
163 if self.configured_space_count == Some(space_count) {
164 return;
165 }
166 self.zero_filled_spaces.clear();
167 for index in 0..space_count {
168 let id = SpaceId::from(index);
169 let space = Space::from_id(ctx, id);
170 if matches!(space.ty, SpaceType::Register) || space.name.as_deref() == Some("x87") {
175 self.zero_filled_spaces.insert(id.into());
176 }
177 }
178 self.configured_space_count = Some(space_count);
179 }
180
181 fn read_raw(
182 &self,
183 space: MemorySpaceId,
184 addr: u64,
185 size: usize,
186 ) -> Result<Vec<u8>, EmulatorErrorKind> {
187 match self.spaces.get(&space) {
188 Some(value) if self.is_zero_filled(space) => Ok(value.read_zero_filled(addr, size)),
189 Some(value) => value.read(addr, size),
190 None if self.is_zero_filled(space) => Ok(vec![0; size]),
191 None => Err(EmulatorErrorKind::UnknownSpace(space)),
192 }
193 }
194}
195
196fn bool_to_u64(value: bool) -> u64 {
197 if value { 1 } else { 0 }
198}
199
200fn mask_for_size(size: usize) -> u128 {
201 let bits = size.saturating_mul(8);
202 if bits >= u128::BITS as usize {
203 u128::MAX
204 } else if bits == 0 {
205 0u128
206 } else {
207 (1u128 << bits) - 1
208 }
209}
210
211fn u128_to_u64(value: u128) -> u64 {
212 u64::try_from(value & u128::from(u64::MAX)).unwrap()
213}
214
215#[derive(Debug, Clone, Copy)]
216pub struct SizedValue {
217 value: u128,
219
220 size: u8,
222}
223
224impl SizedValue {
225 pub fn new(value: u64, size: usize) -> Self {
226 let size = cmp::min(size, 16) as u8;
227 let value = u128::from(value) & mask_for_size(size as usize);
228 Self { value, size }
229 }
230
231 pub fn from_bits(value: u128, size: usize) -> Self {
232 let size = cmp::min(size, 16) as u8;
233 let value = value & mask_for_size(size as usize);
234 Self { value, size }
235 }
236
237 fn as_u64(&self) -> u64 {
238 u128_to_u64(self.value & mask_for_size(self.size as usize))
239 }
240
241 pub fn as_bits(&self) -> u128 {
242 self.value & mask_for_size(self.size as usize)
243 }
244
245 fn signed_value(&self) -> i128 {
246 let bits = (self.size as usize).saturating_mul(8);
247 if bits == 0 {
248 return i128::from(0i8);
249 }
250 if bits >= u128::BITS as usize {
251 return self.as_bits() as i128;
252 }
253
254 let value = self.as_bits();
255 let sign_bit = u128::from(1u8) << (bits - 1);
256 let extended = if (value & sign_bit) != u128::from(0u8) {
257 value | !mask_for_size(self.size as usize)
258 } else {
259 value
260 };
261 extended as i128
262 }
263
264 fn widen_size(&self, _other: &Self) -> usize {
280 self.size as usize
281 }
282
283 fn from_f80_bits(value: u128) -> Self {
284 Self::from_bits(value, 10)
285 }
286
287 fn f64_from_self(&self) -> f64 {
288 match self.size as usize {
289 0..=4 => f32::from_bits(self.as_u64() as u32) as f64,
290 8 => f64::from_bits(self.as_u64()),
291 10 => float80::to_f64(self.as_bits()),
292 _ => 0.0,
293 }
294 }
295
296 fn from_f64(value: f64, size: usize) -> Self {
297 match size {
298 0..=4 => Self::new((value as f32).to_bits() as u64, 4),
299 8 => Self::new(value.to_bits(), 8),
300 10 => Self::from_f80_bits(float80::from_f64(value)),
301 _ => Self::new(0, size),
302 }
303 }
304}
305
306impl DomainValue for SizedValue {
307 fn size(&self) -> Result<usize, EmulatorErrorKind> {
308 Ok(self.size as usize)
309 }
310
311 fn value(&self) -> Result<u64, EmulatorErrorKind> {
312 let value = self.as_bits();
313 if value > u128::from(u64::MAX) {
314 Err(EmulatorErrorKind::ValueError(value)) } else {
316 Ok(u64::try_from(value).unwrap())
317 }
318 }
319
320 fn from_u64(value: u64) -> Self {
321 Self::new(value, 8)
322 }
323
324 fn zero(size: usize) -> Self {
325 Self::new(0, size)
326 }
327
328 fn is_float_nan(&self) -> Result<Self, EmulatorErrorKind> {
329 let is_nan = if self.size == 10 {
330 float80::is_nan(self.as_bits())
331 } else {
332 self.f64_from_self().is_nan()
333 };
334 Ok(Self::new(bool_to_u64(is_nan), 1))
335 }
336
337 fn int_to_float(&self, size: usize) -> Result<Self, EmulatorErrorKind> {
338 let signed = self.signed_value();
339 match size {
340 4 => Ok(Self::new((signed as f32).to_bits() as u64, 4)),
341 8 => Ok(Self::new((signed as f64).to_bits(), 8)),
342 10 => Ok(Self::from_f80_bits(float80::from_i128(signed))),
343 _ => Ok(Self::new(0, size)),
344 }
345 }
346
347 fn float_to_float(&self, size: usize) -> Result<Self, EmulatorErrorKind> {
348 if size == 10 {
349 let value = match self.size as usize {
350 0..=4 => float80::from_f32_bits(self.as_u64() as u32),
351 8 => float80::from_f64(f64::from_bits(self.as_u64())),
352 10 => self.as_bits(),
353 _ => 0,
354 };
355 return Ok(Self::from_f80_bits(value));
356 }
357 match size {
358 4 => Ok(Self::new((self.f64_from_self() as f32).to_bits() as u64, 4)),
359 8 => Ok(Self::new(self.f64_from_self().to_bits(), 8)),
360 _ => Ok(Self::new(0, size)),
361 }
362 }
363
364 fn float_to_int(&self, size: usize) -> Result<Self, EmulatorErrorKind> {
365 let value = if self.size == 10 {
366 float80::to_i128(self.as_bits(), size * 8) as u64
367 } else {
368 self.f64_from_self() as i64 as u64
369 };
370 Ok(Self::new(value, size))
371 }
372
373 fn zext(&self, size: usize) -> Result<Self, EmulatorErrorKind> {
374 Ok(Self::from_bits(Zext::eval(self.as_bits(), size), size))
375 }
376
377 fn sext(&self, size: usize) -> Result<Self, EmulatorErrorKind> {
378 Ok(Self::from_bits(
379 Sext::eval(self.as_bits(), self.size as usize, size),
380 size,
381 ))
382 }
383
384 fn range(&self, start: usize, size: usize) -> Result<Self, EmulatorErrorKind> {
385 Ok(Self::from_bits(
386 Range::eval(self.as_bits(), start, size),
387 size,
388 ))
389 }
390
391 fn byte_swap(&self) -> Result<Self, EmulatorErrorKind> {
392 let size = self.size as usize;
393 let mut value = 0u128;
394 for index in 0..size {
395 let byte = (self.as_bits() >> (index * 8)) & 0xff;
396 value |= byte << ((size - index - 1) * 8);
397 }
398 Ok(Self::from_bits(value, size))
399 }
400
401 fn intrinsic(
402 id: qcode::value::insn::IntrinsicId,
403 args: &[Self],
404 out_size: usize,
405 ) -> Result<Self, EmulatorErrorKind> {
406 let operands: Vec<(u128, usize)> = args
407 .iter()
408 .map(|a| (a.as_bits(), a.size as usize))
409 .collect();
410 let value = id
411 .desc()
412 .eval(&operands, out_size)
413 .ok_or_else(|| EmulatorErrorKind::UnsupportedIntrinsic(Box::from(id.name())))?;
414 Ok(Self::from_bits(value, out_size))
415 }
416
417 fn pop_count(&self) -> Result<Self, EmulatorErrorKind> {
418 let size = self.size as usize;
419 Ok(Self::from_bits(PopCount::eval(self.as_bits(), size), size))
420 }
421
422 fn lz_count(&self) -> Result<Self, EmulatorErrorKind> {
423 let size = self.size as usize;
424 Ok(Self::from_bits(LzCount::eval(self.as_bits(), size), size))
425 }
426
427 fn carry(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
428 let size = self.widen_size(other);
429 Ok(Self::from_bits(
430 Carry::eval(self.as_bits(), other.as_bits(), size),
431 1,
432 ))
433 }
434
435 fn scarry(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
436 let size = self.widen_size(other);
437 Ok(Self::from_bits(
438 SCarry::eval(self.as_bits(), other.as_bits(), size),
439 1,
440 ))
441 }
442
443 fn sborrow(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
444 let size = self.widen_size(other);
445 Ok(Self::from_bits(
446 SBorrow::eval(self.as_bits(), other.as_bits(), size),
447 1,
448 ))
449 }
450
451 fn int_not(&self) -> Result<Self, EmulatorErrorKind> {
452 let size = self.size as usize;
453 Ok(Self::from_bits(
454 Unop::IntNot.eval_int(self.as_bits(), size).unwrap(),
455 size,
456 ))
457 }
458
459 fn int_negate(&self) -> Result<Self, EmulatorErrorKind> {
460 let size = self.size as usize;
461 Ok(Self::from_bits(
462 Unop::IntNegate.eval_int(self.as_bits(), size).unwrap(),
463 size,
464 ))
465 }
466
467 fn float_negate(&self) -> Result<Self, EmulatorErrorKind> {
468 if self.size == 10 {
469 return Ok(Self::from_f80_bits(float80::negate(self.as_bits())));
470 }
471 Ok(Self::from_f64(-self.f64_from_self(), self.size as usize))
472 }
473
474 fn float_abs(&self) -> Result<Self, EmulatorErrorKind> {
475 if self.size == 10 {
476 return Ok(Self::from_f80_bits(float80::abs(self.as_bits())));
477 }
478 Ok(Self::from_f64(
479 self.f64_from_self().abs(),
480 self.size as usize,
481 ))
482 }
483
484 fn float_sqrt(&self) -> Result<Self, EmulatorErrorKind> {
485 Ok(Self::from_f64(
486 self.f64_from_self().sqrt(),
487 self.size as usize,
488 ))
489 }
490
491 fn float_ceil(&self) -> Result<Self, EmulatorErrorKind> {
492 Ok(Self::from_f64(
493 self.f64_from_self().ceil(),
494 self.size as usize,
495 ))
496 }
497
498 fn float_floor(&self) -> Result<Self, EmulatorErrorKind> {
499 Ok(Self::from_f64(
500 self.f64_from_self().floor(),
501 self.size as usize,
502 ))
503 }
504
505 fn float_round(&self) -> Result<Self, EmulatorErrorKind> {
506 Ok(Self::from_f64(
507 self.f64_from_self().round(),
508 self.size as usize,
509 ))
510 }
511
512 fn int_equal(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
513 Ok(Self::from_bits(
514 IntBinop::Equal.eval(self.as_bits(), other.as_bits(), self.size as usize),
515 1,
516 ))
517 }
518
519 fn int_not_equal(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
520 Ok(Self::from_bits(
521 IntBinop::NotEqual.eval(self.as_bits(), other.as_bits(), self.size as usize),
522 1,
523 ))
524 }
525
526 fn int_less(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
527 Ok(Self::from_bits(
528 IntBinop::Less.eval(self.as_bits(), other.as_bits(), self.size as usize),
529 1,
530 ))
531 }
532
533 fn int_sless(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
534 Ok(Self::from_bits(
535 IntBinop::SLess.eval(self.as_bits(), other.as_bits(), self.size as usize),
536 1,
537 ))
538 }
539
540 fn int_less_equal(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
541 Ok(Self::from_bits(
542 IntBinop::LessEqual.eval(self.as_bits(), other.as_bits(), self.size as usize),
543 1,
544 ))
545 }
546
547 fn int_sless_equal(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
548 Ok(Self::from_bits(
549 IntBinop::SLessEqual.eval(self.as_bits(), other.as_bits(), self.size as usize),
550 1,
551 ))
552 }
553
554 fn int_add(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
555 let size = self.widen_size(other);
556 Ok(Self::from_bits(
557 IntBinop::Add.eval(self.as_bits(), other.as_bits(), size),
558 size,
559 ))
560 }
561
562 fn int_sub(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
563 let size = self.widen_size(other);
564 Ok(Self::from_bits(
565 IntBinop::Sub.eval(self.as_bits(), other.as_bits(), size),
566 size,
567 ))
568 }
569
570 fn int_xor(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
571 let size = self.widen_size(other);
572 Ok(Self::from_bits(
573 IntBinop::Xor.eval(self.as_bits(), other.as_bits(), size),
574 size,
575 ))
576 }
577
578 fn int_and(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
579 let size = self.widen_size(other);
580 Ok(Self::from_bits(
581 IntBinop::And.eval(self.as_bits(), other.as_bits(), size),
582 size,
583 ))
584 }
585
586 fn int_or(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
587 let size = self.widen_size(other);
588 Ok(Self::from_bits(
589 IntBinop::Or.eval(self.as_bits(), other.as_bits(), size),
590 size,
591 ))
592 }
593
594 fn int_shift_left(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
595 let size = self.size as usize;
596 Ok(Self::from_bits(
597 IntBinop::ShiftLeft.eval(self.as_bits(), other.as_bits(), size),
598 size,
599 ))
600 }
601
602 fn int_shift_right(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
603 let size = self.size as usize;
604 Ok(Self::from_bits(
605 IntBinop::ShiftRight.eval(self.as_bits(), other.as_bits(), size),
606 size,
607 ))
608 }
609
610 fn int_sshift_right(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
611 let size = self.size as usize;
612 Ok(Self::from_bits(
613 IntBinop::SShiftRight.eval(self.as_bits(), other.as_bits(), size),
614 size,
615 ))
616 }
617
618 fn int_mul(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
619 let size = self.widen_size(other);
620 Ok(Self::from_bits(
621 IntBinop::Mul.eval(self.as_bits(), other.as_bits(), size),
622 size,
623 ))
624 }
625
626 fn int_div(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
627 let size = self.widen_size(other);
628 Ok(Self::from_bits(
629 IntBinop::Div.eval(self.as_bits(), other.as_bits(), size),
630 size,
631 ))
632 }
633
634 fn int_rem(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
635 let size = self.widen_size(other);
636 Ok(Self::from_bits(
637 IntBinop::Rem.eval(self.as_bits(), other.as_bits(), size),
638 size,
639 ))
640 }
641
642 fn int_sdiv(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
643 let size = self.widen_size(other);
644 Ok(Self::from_bits(
645 IntBinop::Sdiv.eval(self.as_bits(), other.as_bits(), size),
646 size,
647 ))
648 }
649
650 fn int_srem(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
651 let size = self.widen_size(other);
652 Ok(Self::from_bits(
653 IntBinop::Srem.eval(self.as_bits(), other.as_bits(), size),
654 size,
655 ))
656 }
657
658 fn float_add(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
659 let size = self.widen_size(other);
660 if size == 10 {
661 return Ok(Self::from_f80_bits(float80::add(
662 self.as_bits(),
663 other.as_bits(),
664 )));
665 }
666 Ok(Self::from_f64(
667 self.f64_from_self() + other.f64_from_self(),
668 size,
669 ))
670 }
671
672 fn float_sub(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
673 let size = self.widen_size(other);
674 if size == 10 {
675 return Ok(Self::from_f80_bits(float80::sub(
676 self.as_bits(),
677 other.as_bits(),
678 )));
679 }
680 Ok(Self::from_f64(
681 self.f64_from_self() - other.f64_from_self(),
682 size,
683 ))
684 }
685
686 fn float_mul(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
687 let size = self.widen_size(other);
688 if size == 10 {
689 return Ok(Self::from_f80_bits(float80::mul(
690 self.as_bits(),
691 other.as_bits(),
692 )));
693 }
694 Ok(Self::from_f64(
695 self.f64_from_self() * other.f64_from_self(),
696 size,
697 ))
698 }
699
700 fn float_div(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
701 let size = self.widen_size(other);
702 if size == 10 {
703 return Ok(Self::from_f80_bits(float80::div(
704 self.as_bits(),
705 other.as_bits(),
706 )));
707 }
708 Ok(Self::from_f64(
709 self.f64_from_self() / other.f64_from_self(),
710 size,
711 ))
712 }
713
714 fn float_equal(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
715 let equal = if self.size == 10 {
716 float80::equal(self.as_bits(), other.as_bits())
717 } else {
718 self.f64_from_self() == other.f64_from_self()
719 };
720 Ok(Self::new(bool_to_u64(equal), 1))
721 }
722
723 fn float_not_equal(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
724 let unequal = if self.size == 10 {
725 !float80::equal(self.as_bits(), other.as_bits())
726 } else {
727 self.f64_from_self() != other.f64_from_self()
728 };
729 Ok(Self::new(bool_to_u64(unequal), 1))
730 }
731
732 fn float_less(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
733 let less = if self.size == 10 {
734 float80::less(self.as_bits(), other.as_bits())
735 } else {
736 self.f64_from_self() < other.f64_from_self()
737 };
738 Ok(Self::new(bool_to_u64(less), 1))
739 }
740
741 fn float_less_equal(&self, other: &Self) -> Result<Self, EmulatorErrorKind> {
742 let less_equal = if self.size == 10 {
743 float80::less_equal(self.as_bits(), other.as_bits())
744 } else {
745 self.f64_from_self() <= other.f64_from_self()
746 };
747 Ok(Self::new(bool_to_u64(less_equal), 1))
748 }
749}
750
751pub trait EmulatorMemory: DomainMemory<V = SizedValue> {
761 fn configure_spaces(&mut self, ctx: &Context<'_>);
765
766 fn read_bytes(
768 &self,
769 space: MemorySpaceId,
770 addr: u64,
771 size: usize,
772 ) -> Result<Vec<u8>, EmulatorErrorKind>;
773
774 fn write_bytes(
776 &mut self,
777 space: MemorySpaceId,
778 addr: u64,
779 bytes: &[u8],
780 ) -> Result<(), EmulatorErrorKind>;
781}
782
783impl EmulatorMemory for EmulatedMemory {
784 fn configure_spaces(&mut self, ctx: &Context<'_>) {
785 EmulatedMemory::configure_spaces(self, ctx)
786 }
787
788 fn read_bytes(
789 &self,
790 space: MemorySpaceId,
791 addr: u64,
792 size: usize,
793 ) -> Result<Vec<u8>, EmulatorErrorKind> {
794 self.read_raw(space, addr, size)
795 }
796
797 fn write_bytes(
798 &mut self,
799 space: MemorySpaceId,
800 addr: u64,
801 bytes: &[u8],
802 ) -> Result<(), EmulatorErrorKind> {
803 let space = self.spaces.entry(space).or_default();
804 space.reserve(bytes.len());
805 for (index, byte) in bytes.iter().enumerate() {
806 space.write_byte(addr + index as u64, *byte);
807 }
808 Ok(())
809 }
810}
811
812impl DomainMemory for EmulatedMemory {
813 type V = SizedValue;
814
815 fn read(
816 &self,
817 space: MemorySpaceId,
818 addr: Self::V,
819 size: usize,
820 ) -> Result<Self::V, EmulatorErrorKind> {
821 let addr = addr.value()?;
822 let zero_filled = self.is_zero_filled(space);
823 let bits = match self.spaces.get(&space) {
824 Some(s) if zero_filled => s.read_u128_zero_filled(addr, size as u64),
825 Some(s) => s.read_u128(addr, size as u64)?,
826 None if zero_filled => 0,
827 None => return Err(EmulatorErrorKind::UnknownSpace(space)),
828 };
829 Ok(SizedValue::from_bits(bits, size))
830 }
831
832 fn write(
833 &mut self,
834 space: MemorySpaceId,
835 addr: Self::V,
836 size: usize,
837 value: Self::V,
838 ) -> Result<(), EmulatorErrorKind> {
839 let addr = addr.value()?;
840
841 self.spaces
842 .entry(space)
843 .or_default()
844 .get_mut_region(addr, size)?
845 .write_u128(value.as_bits());
846 Ok(())
847 }
848}
849
850#[derive(Debug, Default, Clone)]
860pub struct LiteralCache(Vec<Option<SizedValue>>);
861
862impl LiteralCache {
863 fn get(&mut self, ctx: &Context<'_>, id: qcode::value::LiteralId) -> SizedValue {
864 let index: usize = id.into();
865 if index >= self.0.len() {
866 self.0.resize(index + 1, None);
867 }
868 match self.0[index] {
869 Some(value) => value,
870 None => {
871 let ValueRef::Literal(literal) = ValueRef::new(ValueId::Literal(id), ctx) else {
873 unreachable!("a literal id resolves to a literal")
874 };
875 let value = SizedValue::new(literal.value(), literal.size());
876 self.0[index] = Some(value);
877 value
878 }
879 }
880 }
881}
882
883#[derive(Debug, Default, Clone)]
894pub struct InsnValues(Vec<Vec<Option<SizedValue>>>);
895
896impl InsnValues {
897 pub fn get(&self, id: &InstructionId) -> Option<&SizedValue> {
898 let func: usize = id.func.into();
899 let local: usize = id.local.into();
900 self.0.get(func)?.get(local)?.as_ref()
901 }
902
903 pub fn insert(&mut self, id: InstructionId, value: SizedValue) {
904 let func: usize = id.func.into();
905 let local: usize = id.local.into();
906 if func >= self.0.len() {
907 self.0.resize_with(func + 1, Vec::new);
908 }
909 let slots = &mut self.0[func];
910 if local >= slots.len() {
911 slots.resize(local + 1, None);
912 }
913 slots[local] = Some(value);
914 }
915
916 pub fn clear(&mut self) {
917 self.0.clear();
918 }
919}
920
921type InstructionHook<M> =
923 Box<dyn Fn(&InstructionRef<'_, '_>, &StandaloneEmulator<M>) + Send + Sync>;
924type CallInterceptor<M> = Box<
925 dyn FnMut(
926 &Context<'_>,
927 &mut StandaloneEmulator<M>,
928 &CallSite,
929 ) -> Result<CallInterception, Box<str>>
930 + Send
931 + Sync,
932>;
933
934#[derive(Debug, Clone, Copy, PartialEq, Eq)]
935enum StepEvent {
936 Normal,
937 DirectCallEntered(FunctionId),
938 IndirectCallEntered,
939 Return,
940 ReturnValue,
941 InterceptedCall,
942}
943
944pub struct StandaloneEmulator<M = EmulatedMemory> {
947 pub memory: M,
948 literal_cache: LiteralCache,
950 sequence_types: bool,
958 sequence_types_checked_at: Option<usize>,
959 cached_block: Option<BlockId>,
968 cached_insns: Vec<qcode::value::LocalInsnId>,
969 pub insn_values: InsnValues,
970 pub block_param_values: FxHashMap<BlockParamId, SizedValue>,
971 pub poison_params: FxHashSet<BlockParamId>,
976 pub aggregate_values: FxHashMap<InstructionId, Vec<SizedValue>>,
981 pub block_param_aggregates: FxHashMap<BlockParamId, Vec<SizedValue>>,
985 pub array_values: FxHashMap<InstructionId, Vec<u8>>,
992 pub block: BlockId,
993 pub idx: usize,
994 pub call_stack: Vec<FunctionId>,
996 call_site_stack: Vec<InstructionId>,
999
1000 address_index: Option<AddressIndex>,
1004
1005 pub instruction_hook: Option<InstructionHook<M>>,
1006 call_interceptor: Option<CallInterceptor<M>>,
1007}
1008
1009impl StandaloneEmulator<EmulatedMemory> {
1010 pub fn new(entry: BlockId) -> Self {
1012 Self::new_in(entry)
1013 }
1014
1015 pub fn from_address(ctx: &Context<'_>, addr: u64) -> Self {
1017 Self::from_address_in(ctx, addr)
1018 }
1019}
1020
1021impl<M: EmulatorMemory + Default> StandaloneEmulator<M> {
1022 pub fn new_in(entry: BlockId) -> Self {
1029 Self {
1030 memory: M::default(),
1031 literal_cache: LiteralCache::default(),
1032 sequence_types: false,
1033 sequence_types_checked_at: None,
1034 cached_block: None,
1035 cached_insns: Vec::new(),
1036 insn_values: InsnValues::default(),
1037 block_param_values: FxHashMap::default(),
1038 poison_params: FxHashSet::default(),
1039 aggregate_values: FxHashMap::default(),
1040 block_param_aggregates: FxHashMap::default(),
1041 array_values: FxHashMap::default(),
1042 block: entry,
1043 idx: 0,
1044 call_stack: Vec::new(),
1045 call_site_stack: Vec::new(),
1046 address_index: None,
1047 instruction_hook: None,
1048 call_interceptor: None,
1049 }
1050 }
1051
1052 pub fn invalidate_block_cache(&mut self) {
1059 self.cached_block = None;
1060 }
1061
1062 pub fn take_address_index(&mut self) -> Option<AddressIndex> {
1071 self.address_index.take()
1072 }
1073
1074 pub fn address_index(&self) -> Option<&AddressIndex> {
1077 self.address_index.as_ref()
1078 }
1079
1080 pub fn set_address_index(&mut self, address_index: AddressIndex) {
1081 self.address_index = Some(address_index);
1082 }
1083
1084 pub fn block_at_address(&mut self, ctx: &Context<'_>, address: u64) -> Option<BlockId> {
1087 self.block_at(ctx, address)
1088 }
1089
1090 fn with_address_index(entry: BlockId, address_index: AddressIndex) -> Self {
1091 let mut emulator = Self::new_in(entry);
1092 emulator.address_index = Some(address_index);
1093 emulator
1094 }
1095
1096 fn resolve_block_at(ctx: &Context<'_>, index: &AddressIndex, address: u64) -> Option<BlockId> {
1097 match index.get(address) {
1098 Some(AddressTarget::Block(block)) => Some(block),
1099 Some(AddressTarget::Function(function)) => FunctionBody::from_id(ctx, function)
1100 .root()
1101 .map(|root| root.id),
1102 None => None,
1103 }
1104 }
1105
1106 fn block_at(&mut self, ctx: &Context<'_>, address: u64) -> Option<BlockId> {
1107 let index = self
1108 .address_index
1109 .get_or_insert_with(|| AddressIndex::analyze(ctx));
1110 Self::resolve_block_at(ctx, index, address)
1111 }
1112
1113 fn make_error(&self, ctx: &Context<'_>, kind: EmulatorErrorKind) -> EmulatorError {
1114 let block = BasicBlock::from_id(ctx, self.block);
1115 let instruction = block
1116 .instruction_ids()
1117 .get(self.idx)
1118 .copied()
1119 .or_else(|| block.instruction_ids().last().copied())
1120 .expect("cannot construct EmulatorError for empty block");
1121
1122 EmulatorError::new(kind, &Instruction::from_id(ctx, instruction))
1123 }
1124
1125 fn make_empty_block_error(&self, ctx: &Context<'_>) -> EmulatorError {
1129 let block = BasicBlock::from_id(ctx, self.block);
1130 EmulatorError {
1131 kind: EmulatorErrorKind::EmptyBlock(self.block),
1132 ctx: format!(
1133 "Block: {:?}\nFunction: {:?}",
1134 block.name(),
1135 block.function().map(|f| f.name())
1136 ),
1137 address: block.address(),
1138 }
1139 }
1140
1141 fn make_error_at(
1142 &self,
1143 ctx: &Context<'_>,
1144 instruction: InstructionId,
1145 kind: EmulatorErrorKind,
1146 ) -> EmulatorError {
1147 EmulatorError::new(kind, &Instruction::from_id(ctx, instruction))
1148 }
1149
1150 pub fn from_address_in(ctx: &Context<'_>, addr: u64) -> Self {
1152 let address_index = AddressIndex::analyze(ctx);
1153 let entry = Self::resolve_block_at(ctx, &address_index, addr)
1154 .expect("Invalid block or function address");
1155 let mut emulator = Self::with_address_index(entry, address_index);
1156 emulator.memory.configure_spaces(ctx);
1157 emulator
1158 }
1159
1160 pub fn set_varnode(
1161 &mut self,
1162 ctx: &Context<'_>,
1163 id: VarnodeId,
1164 value: u64,
1165 ) -> Result<(), EmulatorErrorKind> {
1166 self.set_varnode_u128(ctx, id, u128::from(value))
1167 }
1168
1169 pub fn set_varnode_u128(
1170 &mut self,
1171 ctx: &Context<'_>,
1172 id: VarnodeId,
1173 value: u128,
1174 ) -> Result<(), EmulatorErrorKind> {
1175 self.memory.configure_spaces(ctx);
1176 let varnode = Varnode::from_id(ctx, id);
1177 let space = varnode.space().id;
1178 let addr = varnode.address() as u64;
1179 let size = varnode.size();
1180 self.memory.write(
1181 space.into(),
1182 SizedValue::from_u64(addr),
1183 size,
1184 SizedValue::from_bits(value, size),
1185 )
1186 }
1187
1188 pub fn read_varnode(&self, ctx: &Context<'_>, id: VarnodeId) -> Option<u64> {
1189 let value = self.read_varnode_u128(ctx, id)?;
1190 u64::try_from(value).ok()
1191 }
1192
1193 pub fn read_varnode_u128(&self, ctx: &Context<'_>, id: VarnodeId) -> Option<u128> {
1194 let varnode = Varnode::from_id(ctx, id);
1195 let space = varnode.space().id;
1196 let addr = varnode.address() as u64;
1197 let size = varnode.size();
1198 self.memory
1199 .read(space.into(), SizedValue::from_u64(addr), size)
1200 .ok()
1201 .map(|v| v.as_bits())
1202 }
1203
1204 pub fn get_value(&mut self, ctx: &Context<'_>, id: ValueId) -> Option<u64> {
1205 let mut tmp = TempInterpreter {
1206 memory: &mut self.memory,
1207 literals: &mut self.literal_cache,
1208 insn_values: &mut self.insn_values,
1209 block_param_values: &mut self.block_param_values,
1210 poison_params: &self.poison_params,
1211 ctx,
1212 };
1213 tmp.get_value(id).ok().and_then(|v| v.value().ok())
1214 }
1215
1216 pub fn set_varnode_bytes(
1217 &mut self,
1218 ctx: &Context<'_>,
1219 id: VarnodeId,
1220 bytes: &[u8],
1221 ) -> Result<(), EmulatorErrorKind> {
1222 let varnode = Varnode::from_id(ctx, id);
1223 let space = varnode.space().id;
1224 let base_addr = varnode.address() as u64;
1225 for (i, chunk) in bytes.chunks(8).enumerate() {
1226 let addr = base_addr + (i * 8) as u64;
1227 let mut buf = [0u8; 8];
1228 buf[..chunk.len()].copy_from_slice(chunk);
1229 let value = u64::from_le_bytes(buf);
1230 self.memory.write(
1231 space.into(),
1232 SizedValue::from_u64(addr),
1233 chunk.len(),
1234 SizedValue::new(value, chunk.len()),
1235 )?;
1236 }
1237 Ok(())
1238 }
1239
1240 pub fn set_varnode_by_name(
1241 &mut self,
1242 ctx: &Context<'_>,
1243 name: &str,
1244 value: u64,
1245 ) -> Result<bool, EmulatorErrorKind> {
1246 self.set_varnode_by_name_u128(ctx, name, u128::from(value))
1247 }
1248
1249 pub fn set_varnode_by_name_u128(
1250 &mut self,
1251 ctx: &Context<'_>,
1252 name: &str,
1253 value: u128,
1254 ) -> Result<bool, EmulatorErrorKind> {
1255 match ctx.get_named(name) {
1256 Some(ValueId::Varnode(id)) => {
1257 self.set_varnode_u128(ctx, id, value)?;
1258 Ok(true)
1259 }
1260 _ => Ok(false),
1261 }
1262 }
1263
1264 pub fn set_varnode_by_name_bytes(
1265 &mut self,
1266 ctx: &Context<'_>,
1267 name: &str,
1268 bytes: &[u8],
1269 ) -> Result<bool, EmulatorErrorKind> {
1270 match ctx.get_named(name) {
1271 Some(ValueId::Varnode(id)) => {
1272 self.set_varnode_bytes(ctx, id, bytes)?;
1273 Ok(true)
1274 }
1275 _ => Ok(false),
1276 }
1277 }
1278
1279 pub fn read_varnode_by_name(&mut self, ctx: &Context<'_>, name: &str) -> Option<u64> {
1280 let value = self.read_varnode_by_name_u128(ctx, name)?;
1281 u64::try_from(value).ok()
1282 }
1283
1284 pub fn read_varnode_by_name_u128(&mut self, ctx: &Context<'_>, name: &str) -> Option<u128> {
1285 match ctx.get_named(name)? {
1286 ValueId::Varnode(id) => self.read_varnode_u128(ctx, id),
1287 _ => None,
1288 }
1289 }
1290
1291 pub fn read_varnode_bytes(&mut self, ctx: &Context<'_>, id: VarnodeId) -> Vec<u8> {
1292 let varnode = Varnode::from_id(ctx, id);
1293 let space = varnode.space().id;
1294 let addr = varnode.address() as u64;
1295 let size = varnode.size();
1296 self.memory
1297 .read_bytes(space.into(), addr, size)
1298 .unwrap_or_default()
1299 }
1300
1301 pub fn read_varnode_by_name_bytes(&mut self, ctx: &Context<'_>, name: &str) -> Option<Vec<u8>> {
1302 match ctx.get_named(name)? {
1303 ValueId::Varnode(id) => Some(self.read_varnode_bytes(ctx, id)),
1304 _ => None,
1305 }
1306 }
1307
1308 pub fn get_value_bytes(&mut self, ctx: &Context<'_>, id: ValueId) -> Option<Vec<u8>> {
1309 let mut tmp = TempInterpreter {
1310 memory: &mut self.memory,
1311 literals: &mut self.literal_cache,
1312 insn_values: &mut self.insn_values,
1313 block_param_values: &mut self.block_param_values,
1314 poison_params: &self.poison_params,
1315 ctx,
1316 };
1317 let sv = tmp.get_value(id).ok()?;
1318 let size = sv.size().ok()?;
1319 let bits = sv.as_bits();
1320 let mut bytes = vec![0u8; size];
1321 for (i, byte) in bytes.iter_mut().enumerate() {
1322 *byte = u8::try_from((bits >> (i * 8)) & u128::from(0xffu8)).unwrap();
1323 }
1324 Some(bytes)
1325 }
1326
1327 pub fn current_block(&self) -> BlockId {
1328 self.block
1329 }
1330
1331 pub fn set_call_interceptor(
1332 &mut self,
1333 interceptor: impl FnMut(
1334 &Context<'_>,
1335 &mut StandaloneEmulator<M>,
1336 &CallSite,
1337 ) -> Result<CallInterception, Box<str>>
1338 + Send
1339 + Sync
1340 + 'static,
1341 ) {
1342 self.call_interceptor = Some(Box::new(interceptor));
1343 }
1344
1345 pub fn clear_call_interceptor(&mut self) {
1346 self.call_interceptor = None;
1347 }
1348
1349 pub fn read_memory(
1350 &mut self,
1351 ctx: &Context<'_>,
1352 space: impl Into<MemorySpaceId>,
1353 addr: u64,
1354 size: usize,
1355 ) -> Result<Vec<u8>, EmulatorErrorKind> {
1356 self.memory.configure_spaces(ctx);
1357 self.memory.read_bytes(space.into(), addr, size)
1358 }
1359
1360 pub fn write_memory(
1361 &mut self,
1362 ctx: &Context<'_>,
1363 space: impl Into<MemorySpaceId>,
1364 addr: u64,
1365 value: &[u8],
1366 ) -> Result<(), EmulatorErrorKind> {
1367 self.memory.configure_spaces(ctx);
1368 self.memory.write_bytes(space.into(), addr, value)
1369 }
1370
1371 fn collect_block_args(
1374 &mut self,
1375 ctx: &Context<'_>,
1376 func: FunctionId,
1377 args: &[LocalValueId],
1378 ) -> Result<Vec<SizedValue>, EmulatorErrorKind> {
1379 let mut tmp = TempInterpreter {
1380 memory: &mut self.memory,
1381 literals: &mut self.literal_cache,
1382 insn_values: &mut self.insn_values,
1383 block_param_values: &mut self.block_param_values,
1384 poison_params: &self.poison_params,
1385 ctx,
1386 };
1387 args.iter()
1388 .map(|&arg| tmp.get_value(arg.qualify(func)))
1389 .collect()
1390 }
1391
1392 fn bind_block_args(
1393 &mut self,
1394 ctx: &Context<'_>,
1395 func: FunctionId,
1396 target: BlockId,
1397 args: &[LocalValueId],
1398 ) -> Result<(), EmulatorErrorKind> {
1399 let values = self.collect_block_args(ctx, func, args)?;
1400 let params = BasicBlock::from_id(ctx, target)
1401 .params()
1402 .map(|param| param.id)
1403 .collect::<Vec<_>>();
1404 if values.len() != params.len() {
1405 return Err(EmulatorErrorKind::ValueError(values.len() as u128));
1406 }
1407 for (param, value) in params.into_iter().zip(values) {
1408 self.block_param_values.insert(param, value);
1409 }
1410 Ok(())
1411 }
1412
1413 fn register_range_store_address(
1422 &self,
1423 ctx: &Context<'_>,
1424 func: FunctionId,
1425 store: &Store,
1426 ) -> Option<u64> {
1427 let space = store.space.qualify(func);
1428 let space_id = space.shared()?;
1429 if !matches!(Space::from_id(ctx, space_id).ty, SpaceType::Register) {
1430 return None;
1431 }
1432 let ValueRef::Instruction(range) = ValueRef::new(store.ptr.qualify(func), ctx) else {
1433 return None;
1434 };
1435 let Mnemonic::Range(Range { src, start, .. }) = range.mnemonic() else {
1436 return None;
1437 };
1438 let ValueRef::Varnode(varnode) = ValueRef::new(src.qualify(func), ctx) else {
1439 return None;
1440 };
1441 let varnode = Varnode::from_id(ctx, varnode.id);
1442 (varnode.space().id == space_id).then_some(varnode.address() as u64 + *start as u64)
1443 }
1444
1445 fn apply_call_continuation(
1446 &mut self,
1447 ctx: &Context<'_>,
1448 continuation: CallContinuation,
1449 ) -> Result<(), EmulatorErrorKind> {
1450 let target = match continuation {
1451 CallContinuation::Block(block) => block,
1452 CallContinuation::Address(addr) => self
1453 .block_at(ctx, addr)
1454 .ok_or(EmulatorErrorKind::InvalidBlockAddress(addr))?,
1455 };
1456 self.block = target;
1457 self.idx = 0;
1458 Ok(())
1459 }
1460
1461 fn intercept_call(
1462 &mut self,
1463 ctx: &Context<'_>,
1464 block: BlockId,
1465 instruction: InstructionId,
1466 call: &Call,
1467 ) -> crate::Result<Option<StepEvent>> {
1468 let Some(mut interceptor) = self.call_interceptor.take() else {
1469 return Ok(None);
1470 };
1471 let target = require_real_callee(call.target)
1472 .map_err(|kind| self.make_error_at(ctx, instruction, kind))?;
1473
1474 let site = CallSite {
1475 instruction,
1476 block,
1477 target,
1478 args: call
1481 .args
1482 .iter()
1483 .map(|a| a.qualify(instruction.func))
1484 .collect(),
1485 };
1486 let result = interceptor(ctx, self, &site);
1487 self.call_interceptor = Some(interceptor);
1488
1489 match result {
1490 Ok(CallInterception::PassThrough) => Ok(None),
1491 Ok(CallInterception::Handled(continuation)) => {
1492 self.apply_call_continuation(ctx, continuation)
1493 .map_err(|kind| self.make_error_at(ctx, instruction, kind))?;
1494 Ok(Some(StepEvent::InterceptedCall))
1495 }
1496 Err(message) => Err(self.make_error_at(
1497 ctx,
1498 instruction,
1499 EmulatorErrorKind::InterceptError(message),
1500 )),
1501 }
1502 }
1503
1504 fn scalar_value(
1508 &mut self,
1509 ctx: &Context<'_>,
1510 id: ValueId,
1511 ) -> Result<SizedValue, EmulatorErrorKind> {
1512 let mut interpreter = TempInterpreter {
1513 memory: &mut self.memory,
1514 literals: &mut self.literal_cache,
1515 insn_values: &mut self.insn_values,
1516 block_param_values: &mut self.block_param_values,
1517 poison_params: &self.poison_params,
1518 ctx,
1519 };
1520 interpreter.get_value(id)
1521 }
1522
1523 fn ieee_rounding_mode(value: u128) -> Option<Round> {
1528 match value {
1529 0 => Some(Round::NearestTiesToEven),
1530 1 => Some(Round::TowardNegative),
1531 2 => Some(Round::TowardPositive),
1532 3 => Some(Round::TowardZero),
1533 _ => None,
1534 }
1535 }
1536
1537 fn ieee_arithmetic(
1541 lhs: SizedValue,
1542 rhs: SizedValue,
1543 round: Round,
1544 name: &str,
1545 ) -> Option<(SizedValue, Status)> {
1546 if lhs.size != rhs.size {
1547 return None;
1548 }
1549 macro_rules! operation {
1550 ($lhs:expr, $rhs:expr) => {
1551 match name {
1552 "float_add" | "float_add_flags" => $lhs.add_r($rhs, round),
1553 "float_sub" | "float_sub_flags" => $lhs.sub_r($rhs, round),
1554 "float_mul" | "float_mul_flags" => $lhs.mul_r($rhs, round),
1555 "float_div" | "float_div_flags" => $lhs.div_r($rhs, round),
1556 _ => return None,
1557 }
1558 };
1559 }
1560 match lhs.size {
1563 4 => {
1564 let lhs = Single::from_bits(lhs.as_bits());
1565 let rhs = Single::from_bits(rhs.as_bits());
1566 let value = operation!(lhs, rhs);
1567 Some((
1568 SizedValue::from_bits(value.value.to_bits(), 4),
1569 value.status,
1570 ))
1571 }
1572 8 => {
1573 let lhs = Double::from_bits(lhs.as_bits());
1574 let rhs = Double::from_bits(rhs.as_bits());
1575 let value = operation!(lhs, rhs);
1576 Some((
1577 SizedValue::from_bits(value.value.to_bits(), 8),
1578 value.status,
1579 ))
1580 }
1581 10 => {
1582 let lhs = X87DoubleExtended::from_bits(lhs.as_bits());
1583 let rhs = X87DoubleExtended::from_bits(rhs.as_bits());
1584 let value = operation!(lhs, rhs);
1585 Some((
1586 SizedValue::from_bits(value.value.to_bits(), 10),
1587 value.status,
1588 ))
1589 }
1590 _ => None,
1591 }
1592 }
1593
1594 fn ieee_round_to_precision(
1600 value: SizedValue,
1601 precision: u128,
1602 round: Round,
1603 ) -> Option<(SizedValue, Status)> {
1604 if value.size != 10 {
1605 return None;
1606 }
1607 let precision = u32::try_from(precision).ok()?;
1608 let result = float80::round_to_precision(value.as_bits(), precision, round);
1609 Some((SizedValue::from_bits(result.bits, 10), result.status))
1610 }
1611
1612 fn ieee_narrow(value: SizedValue, size: u128, round: Round) -> Option<(SizedValue, Status)> {
1616 if value.size != 10 {
1617 return None;
1618 }
1619 let source = X87DoubleExtended::from_bits(value.as_bits());
1620 let mut loses_info = false;
1621 match size {
1622 4 => {
1623 let converted: rustc_apfloat::StatusAnd<Single> =
1624 source.convert_r(round, &mut loses_info);
1625 Some((
1626 SizedValue::from_bits(converted.value.to_bits(), 4),
1627 converted.status,
1628 ))
1629 }
1630 8 => {
1631 let converted: rustc_apfloat::StatusAnd<Double> =
1632 source.convert_r(round, &mut loses_info);
1633 Some((
1634 SizedValue::from_bits(converted.value.to_bits(), 8),
1635 converted.status,
1636 ))
1637 }
1638 _ => None,
1639 }
1640 }
1641
1642 fn ieee_to_int(value: SizedValue, size: u128, round: Round) -> Option<(SizedValue, Status)> {
1647 if value.size != 10 {
1648 return None;
1649 }
1650 let size = usize::try_from(size).ok()?;
1651 if !matches!(size, 2 | 4 | 8) {
1652 return None;
1653 }
1654 let mut exact = false;
1655 let converted =
1656 X87DoubleExtended::from_bits(value.as_bits()).to_i128_r(size * 8, round, &mut exact);
1657 let mask = (1u128 << (size * 8)) - 1;
1658 Some((
1659 SizedValue::from_bits(converted.value as u128 & mask, size),
1660 converted.status,
1661 ))
1662 }
1663
1664 fn ieee_flags(status: Status) -> SizedValue {
1665 let mut flags = 0u128;
1666 if status.contains(Status::INVALID_OP) {
1667 flags |= 1;
1668 }
1669 if status.contains(Status::DIV_BY_ZERO) {
1670 flags |= 1 << 2;
1671 }
1672 if status.contains(Status::OVERFLOW) {
1673 flags |= 1 << 3;
1674 }
1675 if status.contains(Status::UNDERFLOW) {
1676 flags |= 1 << 4;
1677 }
1678 if status.contains(Status::INEXACT) {
1679 flags |= 1 << 5;
1680 }
1681 SizedValue::from_bits(flags, 1)
1682 }
1683
1684 fn interpret_packed_pcode_op(
1692 &mut self,
1693 ctx: &Context<'_>,
1694 insn: &InstructionRef<'_, '_>,
1695 mnemonic: &Mnemonic,
1696 ) -> Result<Option<SizedValue>, EmulatorErrorKind> {
1697 let Mnemonic::PCodeOp(op) = mnemonic else {
1698 return Ok(None);
1699 };
1700 let name = ctx.shared.pcode_ops[op.id].clone();
1701 let func = insn.id.func;
1702
1703 if let [src] = op.args.as_slice() {
1706 let value = self.scalar_value(ctx, src.qualify(func))?;
1707 if value.size != 10 {
1708 return Ok(None);
1709 }
1710 return Ok(match name.as_ref() {
1711 "extract_significand" => Some(SizedValue::from_f80_bits(
1712 float80::extract_significand(value.as_bits()),
1713 )),
1714 "extract_exponent" => Some(SizedValue::from_f80_bits(
1715 float80::extract_exponent(value.as_bits()).bits,
1716 )),
1717 _ => None,
1718 });
1719 }
1720
1721 if let [lhs, rhs, rounding_mode] = op.args.as_slice() {
1724 let lhs = self.scalar_value(ctx, lhs.qualify(func))?;
1725 let rhs = self.scalar_value(ctx, rhs.qualify(func))?;
1726 let rounding_mode = self.scalar_value(ctx, rounding_mode.qualify(func))?;
1727
1728 if matches!(name.as_ref(), "float_rem_partial" | "float_rem_quotient")
1733 && lhs.size == 10
1734 && rhs.size == 10
1735 {
1736 let to_nearest = rounding_mode.as_bits() != 0;
1737 let result = float80::remainder(lhs.as_bits(), rhs.as_bits(), to_nearest);
1738 return Ok(Some(if name.as_ref() == "float_rem_quotient" {
1739 let code = if result.incomplete {
1744 8
1745 } else {
1746 u128::from(result.quotient & 7)
1747 };
1748 SizedValue::from_bits(code, 1)
1749 } else {
1750 SizedValue::from_f80_bits(result.bits)
1751 }));
1752 }
1753
1754 let Some(round) = Self::ieee_rounding_mode(rounding_mode.as_bits()) else {
1755 return Ok(None);
1756 };
1757 let evaluated = match name.as_ref() {
1758 "float_round_to_precision" | "float_round_to_precision_flags" => {
1759 Self::ieee_round_to_precision(lhs, rhs.as_bits(), round)
1760 }
1761 "float_narrow" | "float_narrow_flags" => {
1762 Self::ieee_narrow(lhs, rhs.as_bits(), round)
1763 }
1764 "float_to_int" | "float_to_int_flags" => {
1765 Self::ieee_to_int(lhs, rhs.as_bits(), round)
1766 }
1767 "float_scalb" | "float_scalb_flags" if lhs.size == 10 => {
1768 let steps = i32::try_from(rhs.as_bits() as i64).unwrap_or(
1769 if (rhs.as_bits() as i64) < 0 {
1770 i32::MIN
1771 } else {
1772 i32::MAX
1773 },
1774 );
1775 let result = float80::scalb_ieee(lhs.as_bits(), steps, round);
1776 Some((SizedValue::from_f80_bits(result.bits), result.status))
1777 }
1778 _ => Self::ieee_arithmetic(lhs, rhs, round, name.as_ref()),
1779 };
1780 if let Some((result, status)) = evaluated {
1781 return Ok(Some(if name.ends_with("_flags") {
1782 Self::ieee_flags(status)
1783 } else {
1784 result
1785 }));
1786 }
1787 return Ok(None);
1788 }
1789
1790 let [lhs, rhs] = op.args.as_slice() else {
1791 return Ok(None);
1792 };
1793 let lhs = self.scalar_value(ctx, lhs.qualify(func))?;
1794 let rhs = self.scalar_value(ctx, rhs.qualify(func))?;
1795
1796 if lhs.size == 10 {
1800 let unary = Self::ieee_rounding_mode(rhs.as_bits()).and_then(|round| {
1801 Some(match name.as_ref() {
1802 "float_sqrt" | "float_sqrt_flags" => float80::sqrt_ieee(lhs.as_bits(), round),
1803 "float_round_to_integral" | "float_round_to_integral_flags" => {
1804 float80::round_to_integral_ieee(lhs.as_bits(), round)
1805 }
1806 "float_log2" | "float_log2_flags" => float80::log2_ieee(lhs.as_bits()),
1807 "to_bcd" | "to_bcd_flags" => float80::to_bcd(lhs.as_bits(), round),
1808 _ => return None,
1809 })
1810 });
1811 if let Some(result) = unary {
1812 return Ok(Some(if name.ends_with("_flags") {
1813 Self::ieee_flags(result.status)
1814 } else if name.starts_with("to_bcd") {
1815 SizedValue::from_bits(result.bits, 10)
1817 } else {
1818 SizedValue::from_f80_bits(result.bits)
1819 }));
1820 }
1821 }
1822
1823 let average = |width: usize| -> Option<SizedValue> {
1826 (lhs.size as usize == width && rhs.size as usize == width).then(|| {
1827 let sum = lhs.as_bits() + rhs.as_bits() + 1;
1828 SizedValue::from_bits(sum >> 1, width)
1829 })
1830 };
1831
1832 let value = match name.as_ref() {
1833 "pavgb" => average(1),
1834 "pavgw" => average(2),
1835 "pmulhuw" => Self::packed_lanes(&lhs, &rhs, 2, |a, b| ((a * b) >> 16) & 0xffff),
1837 "paddsb" => Self::saturating(&lhs, &rhs, 1, true, false),
1840 "paddsw" => Self::saturating(&lhs, &rhs, 2, true, false),
1841 "psubsb" => Self::saturating(&lhs, &rhs, 1, true, true),
1842 "psubsw" => Self::saturating(&lhs, &rhs, 2, true, true),
1843 "paddusb" => Self::saturating(&lhs, &rhs, 1, false, false),
1844 "paddusw" => Self::saturating(&lhs, &rhs, 2, false, false),
1845 "psubusb" => Self::saturating(&lhs, &rhs, 1, false, true),
1846 "psubusw" => Self::saturating(&lhs, &rhs, 2, false, true),
1847 "pmaddwd" => Self::packed_lanes(&lhs, &rhs, 4, |a, b| {
1849 let word =
1850 |v: u128, half: u32| i64::from(((v >> (half * 16)) & 0xffff) as u16 as i16);
1851 let product = word(a, 0) * word(b, 0) + word(a, 1) * word(b, 1);
1852 u128::from(product as u32)
1853 }),
1854 _ => None,
1855 };
1856 Ok(value)
1857 }
1858
1859 fn saturating(
1862 lhs: &SizedValue,
1863 rhs: &SizedValue,
1864 width: usize,
1865 signed: bool,
1866 subtract: bool,
1867 ) -> Option<SizedValue> {
1868 let bits = width * 8;
1869 Self::packed_lanes(lhs, rhs, width, |a, b| {
1870 if signed {
1871 let sign =
1872 |v: u128| (v as i128) - (((v >> (bits - 1)) & 1) as i128) * (1i128 << bits);
1873 let (a, b) = (sign(a), sign(b));
1874 let value = if subtract { a - b } else { a + b };
1875 let max = (1i128 << (bits - 1)) - 1;
1876 let min = -(1i128 << (bits - 1));
1877 (value.clamp(min, max) as u128) & ((1u128 << bits) - 1)
1878 } else if subtract {
1879 a.saturating_sub(b)
1880 } else {
1881 (a + b).min((1u128 << bits) - 1)
1882 }
1883 })
1884 }
1885
1886 fn packed_lanes(
1890 lhs: &SizedValue,
1891 rhs: &SizedValue,
1892 width: usize,
1893 lane: impl Fn(u128, u128) -> u128,
1894 ) -> Option<SizedValue> {
1895 let size = lhs.size as usize;
1896 if size != rhs.size as usize || size == 0 || !size.is_multiple_of(width) {
1897 return None;
1898 }
1899 let bits = width * 8;
1900 let mask = (1u128 << bits) - 1;
1901 let mut out = 0u128;
1902 for index in 0..size / width {
1903 let shift = index * bits;
1904 let a = (lhs.as_bits() >> shift) & mask;
1905 let b = (rhs.as_bits() >> shift) & mask;
1906 out |= (lane(a, b) & mask) << shift;
1907 }
1908 Some(SizedValue::from_bits(out, size))
1909 }
1910
1911 fn step_with_event(&mut self, ctx: &Context<'_>) -> crate::Result<StepEvent> {
1912 self.memory.configure_spaces(ctx);
1913 let block_id = self.block;
1914 if self.cached_block != Some(block_id) || self.idx == 0 {
1915 self.refresh_sequence_types(ctx);
1919 self.cached_insns.clear();
1920 self.cached_insns
1921 .extend_from_slice(ctx.block(block_id).instruction_ids());
1922 self.cached_block = Some(block_id);
1923 }
1924 let Some(&local) = self.cached_insns.get(self.idx) else {
1929 return Err(self.make_empty_block_error(ctx));
1930 };
1931 let insn_id = InstructionId::new(block_id.func, local);
1932 let insn = InstructionRef::from_id(ctx, insn_id);
1933 let id = insn.id;
1934
1935 if let Some(hook) = self.instruction_hook.as_ref() {
1936 hook(&insn, self)
1937 }
1938
1939 let mnemonic = insn.mnemonic();
1943
1944 match mnemonic {
1945 Mnemonic::Branch(Branch { target, args }) => {
1946 let target = BlockId::new(id.func, *target);
1949 self.bind_block_args(ctx, id.func, target, args)
1950 .map_err(|kind| self.make_error(ctx, kind))?;
1951 self.block = target;
1952 self.idx = 0;
1953 }
1954
1955 Mnemonic::Call(call) => {
1956 if let Some(event) = self.intercept_call(ctx, block_id, insn_id, call)? {
1957 return Ok(event);
1958 }
1959 let target =
1960 require_real_callee(call.target).map_err(|kind| self.make_error(ctx, kind))?;
1961 self.block = FunctionBody::from_id(ctx, target)
1962 .root()
1963 .ok_or_else(|| {
1964 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
1965 })?
1966 .id;
1967 self.idx = 0;
1968 self.call_site_stack.push(insn_id);
1971 return Ok(StepEvent::DirectCallEntered(target));
1972 }
1973
1974 Mnemonic::TailCall(tc) => {
1975 let target =
1980 require_real_callee(tc.target).map_err(|kind| self.make_error(ctx, kind))?;
1981 self.block = FunctionBody::from_id(ctx, target)
1982 .root()
1983 .ok_or_else(|| {
1984 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
1985 })?
1986 .id;
1987 self.idx = 0;
1988 }
1989
1990 Mnemonic::Apply(apply) => {
1991 const APPLY_STEP_BUDGET: usize = 100_000;
1992 let target =
1993 require_real_callee(apply.target).map_err(|kind| self.make_error(ctx, kind))?;
1994 let args = self
1995 .collect_block_args(ctx, id.func, &apply.args)
1996 .map_err(|kind| self.make_error(ctx, kind))?;
1997 let root = FunctionBody::from_id(ctx, target)
1998 .root()
1999 .ok_or_else(|| {
2000 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
2001 })?
2002 .id;
2003 let mut nested = StandaloneEmulator::<M>::new_in(root);
2004 nested
2005 .run_pure(ctx, target, &args, APPLY_STEP_BUDGET)
2006 .map_err(|e| self.make_error(ctx, e.kind))?;
2007 let ret_value = lambda_return_value(ctx, nested.current_block())
2008 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2009 if let Some(value) = nested.get_value(ctx, ret_value) {
2010 let size = ctx
2011 .stored_type_of(ret_value)
2012 .map(|ty| ctx.shared.types.size_of(ty))
2013 .unwrap_or(8);
2014 self.insn_values
2015 .insert(insn_id, SizedValue::new(value, size));
2016 } else if let ValueId::Instruction(ret_id) = ret_value
2017 && let Some(agg) = nested.aggregate_values.get(&ret_id).cloned()
2018 {
2019 self.aggregate_values.insert(insn_id, agg);
2024 }
2025 self.idx += 1;
2026 }
2027
2028 Mnemonic::CBranch(CBranch {
2029 condition,
2030 success_block: target,
2031 success_args,
2032 failure_block: fallthrough,
2033 failure_args,
2034 }) => {
2035 let cond_val = self.get_value(ctx, condition.qualify(id.func)).unwrap();
2036 let target = BlockId::new(id.func, *target);
2037 let fallthrough = BlockId::new(id.func, *fallthrough);
2038 if cond_val != 0 {
2039 self.bind_block_args(ctx, id.func, target, success_args)
2040 .map_err(|kind| self.make_error(ctx, kind))?;
2041 self.block = target;
2042 } else {
2043 self.bind_block_args(ctx, id.func, fallthrough, failure_args)
2044 .map_err(|kind| self.make_error(ctx, kind))?;
2045 self.block = fallthrough;
2046 }
2047 self.idx = 0;
2048 }
2049
2050 Mnemonic::Switch(switch) => {
2051 let value = self
2052 .get_value(ctx, switch.scrutinee.qualify(id.func))
2053 .unwrap();
2054 let arm = switch
2055 .cases
2056 .iter()
2057 .find(|case| case.value == value)
2058 .map(|case| (case.target, &case.args));
2059 let (target, args) = match arm
2060 .or_else(|| switch.default.map(|target| (target, &switch.default_args)))
2061 {
2062 Some(arm) => arm,
2063 None => {
2067 return Err(
2068 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(value))
2069 );
2070 }
2071 };
2072 let target = BlockId::new(id.func, target);
2073 self.bind_block_args(ctx, id.func, target, args)
2074 .map_err(|kind| self.make_error(ctx, kind))?;
2075 self.block = target;
2076 self.idx = 0;
2077 }
2078
2079 Mnemonic::BranchInd(BranchInd { ptr }) => {
2080 let addr = self.get_value(ctx, ptr.qualify(id.func)).unwrap();
2081 let target = self.block_at(ctx, addr).ok_or_else(|| {
2082 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(addr))
2083 })?;
2084 self.block = target;
2085 self.idx = 0;
2086 }
2087
2088 Mnemonic::CallInd(CallInd { ptr, .. }) => {
2089 let addr = self.get_value(ctx, ptr.qualify(id.func)).unwrap();
2090 let target = self.block_at(ctx, addr).ok_or_else(|| {
2091 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(addr))
2092 })?;
2093 self.block = target;
2094 self.idx = 0;
2095 self.call_site_stack.push(insn_id);
2096 return Ok(StepEvent::IndirectCallEntered);
2097 }
2098
2099 Mnemonic::Return(Return { ptr, value, .. }) => {
2100 if let Some(call_id) = self.call_site_stack.pop() {
2105 if let Some(LocalValueId::Instruction(src_local)) = value {
2106 let src = InstructionId::new(id.func, *src_local);
2107 if let Some(agg) = self.aggregate_values.get(&src).cloned() {
2108 self.aggregate_values.insert(call_id, agg);
2109 } else if let Some(scalar) = self.insn_values.get(&src).copied() {
2110 self.insn_values.insert(call_id, scalar);
2111 }
2112 }
2113 self.writeback_materialized_outputs(ctx, call_id, id.func);
2119 }
2120
2121 let addr = self.get_value(ctx, ptr.qualify(id.func)).unwrap();
2122 let target = self.block_at(ctx, addr).ok_or_else(|| {
2123 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(addr))
2124 })?;
2125 self.block = target;
2126 self.idx = 0;
2127 return Ok(StepEvent::Return);
2128 }
2129
2130 Mnemonic::ReturnValue(_) => {
2131 return Ok(StepEvent::ReturnValue);
2132 }
2133
2134 Mnemonic::Tuple(Tuple { fields }) => {
2138 let fields = fields.clone();
2139 let mut vals: Vec<SizedValue> = Vec::with_capacity(fields.len());
2140 for f in fields {
2141 let val = {
2142 let mut tmp = TempInterpreter {
2143 memory: &mut self.memory,
2144 literals: &mut self.literal_cache,
2145 insn_values: &mut self.insn_values,
2146 block_param_values: &mut self.block_param_values,
2147 poison_params: &self.poison_params,
2148 ctx,
2149 };
2150 tmp.get_value(f.qualify(id.func))
2151 };
2152 vals.push(val.map_err(|kind| self.make_error(ctx, kind))?);
2153 }
2154 self.aggregate_values.insert(insn_id, vals);
2155 self.idx += 1;
2156 }
2157
2158 Mnemonic::Extract(Extract { agg, index }) => {
2160 let field = match agg {
2161 LocalValueId::Instruction(agg_local) => self
2162 .aggregate_values
2163 .get(&InstructionId::new(id.func, *agg_local))
2164 .and_then(|v| v.get(*index))
2165 .copied(),
2166 LocalValueId::BlockParam(pid_local) => self
2169 .block_param_aggregates
2170 .get(&BlockParamId::new(id.func, *pid_local))
2171 .and_then(|v| v.get(*index))
2172 .copied(),
2173 _ => None,
2174 };
2175 if let Some(field) = field {
2176 self.insn_values.insert(insn_id, field);
2177 }
2178 self.idx += 1;
2179 }
2180
2181 Mnemonic::Load(load) if self.is_array_operand(ctx, ValueId::Instruction(insn_id)) => {
2186 let (space, ptr, size) = (load.space, load.ptr.qualify(id.func), load.size);
2187 let addr = self
2188 .get_value(ctx, ptr)
2189 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2190 let buf = self
2191 .read_memory(ctx, space.qualify(id.func), addr, size)
2192 .map_err(|kind| self.make_error(ctx, kind))?;
2193 self.array_values.insert(insn_id, buf);
2194 self.idx += 1;
2195 }
2196
2197 Mnemonic::Store(store)
2201 if self
2202 .register_range_store_address(ctx, id.func, store)
2203 .is_some() =>
2204 {
2205 let address = self
2206 .register_range_store_address(ctx, id.func, store)
2207 .expect("guard checked register range store address");
2208 let mut tmp = TempInterpreter {
2209 memory: &mut self.memory,
2210 literals: &mut self.literal_cache,
2211 insn_values: &mut self.insn_values,
2212 block_param_values: &mut self.block_param_values,
2213 poison_params: &self.poison_params,
2214 ctx,
2215 };
2216 let value = tmp.get_value(store.src.qualify(id.func));
2217 let value = value.map_err(|kind| self.make_error(ctx, kind))?;
2218 self.memory
2219 .write(
2220 store.space.qualify(id.func),
2221 SizedValue::from_u64(address),
2222 store.size,
2223 value,
2224 )
2225 .map_err(|kind| self.make_error(ctx, kind))?;
2226 self.idx += 1;
2227 }
2228
2229 Mnemonic::Store(store) if self.is_array_operand(ctx, store.src.qualify(id.func)) => {
2230 let (space, ptr, src) = (
2231 store.space,
2232 store.ptr.qualify(id.func),
2233 store.src.qualify(id.func),
2234 );
2235 let buf = self
2236 .resolve_array(ctx, src)
2237 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2238 let addr = self
2239 .get_value(ctx, ptr)
2240 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2241 self.write_memory(ctx, space.qualify(id.func), addr, &buf)
2242 .map_err(|kind| self.make_error(ctx, kind))?;
2243 self.idx += 1;
2244 }
2245
2246 Mnemonic::Scan(scan) => {
2250 let scan = scan.clone();
2251 self.eval_scan(ctx, insn_id, &scan)
2252 .map_err(|kind| self.make_error(ctx, kind))?;
2253 self.idx += 1;
2254 }
2255
2256 Mnemonic::Map(map) => {
2258 let map = map.clone();
2259 self.eval_map(ctx, insn_id, &map)
2260 .map_err(|kind| self.make_error(ctx, kind))?;
2261 self.idx += 1;
2262 }
2263
2264 Mnemonic::Range(range) if self.is_array_operand(ctx, range.src.qualify(id.func)) => {
2269 let (src, start, size) = (range.src.qualify(id.func), range.start, range.size);
2270 let buf = self
2271 .resolve_array(ctx, src)
2272 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2273 let end = (start + size).min(buf.len());
2274 let slice = buf.get(start..end).unwrap_or(&[]).to_vec();
2275 self.array_values.insert(insn_id, slice);
2276 self.idx += 1;
2277 }
2278
2279 Mnemonic::Intrinsic(app) if is_array_intrinsic(app.id.name()) => {
2284 let name = app.id.name();
2285 let args: Vec<ValueId> = app.args.iter().map(|a| a.qualify(id.func)).collect();
2286 self.eval_array_intrinsic(ctx, insn_id, name, &args)
2287 .map_err(|kind| self.make_error(ctx, kind))?;
2288 self.idx += 1;
2289 }
2290
2291 _ => {
2292 if let Some(value) = self
2293 .interpret_packed_pcode_op(ctx, &insn, mnemonic)
2294 .map_err(|kind| self.make_error(ctx, kind))?
2295 {
2296 self.insn_values.insert(id, value);
2297 self.idx += 1;
2298 return Ok(StepEvent::Normal);
2299 }
2300 let mut tmp = TempInterpreter {
2301 memory: &mut self.memory,
2302 literals: &mut self.literal_cache,
2303 insn_values: &mut self.insn_values,
2304 block_param_values: &mut self.block_param_values,
2305 poison_params: &self.poison_params,
2306 ctx,
2307 };
2308 if let Some(value) = tmp.interpret(insn, mnemonic)? {
2309 self.insn_values.insert(id, value);
2310 }
2311 self.idx += 1;
2312 }
2313 }
2314
2315 Ok(StepEvent::Normal)
2316 }
2317
2318 pub fn step(&mut self, ctx: &Context<'_>) -> crate::Result<()> {
2319 self.step_with_event(ctx).map(|_| ())
2320 }
2321
2322 pub fn run_block(&mut self, ctx: &Context<'_>) -> crate::Result<()> {
2323 loop {
2324 self.step(ctx)?;
2325 if self.idx == 0 {
2326 break;
2327 }
2328 }
2329 Ok(())
2330 }
2331
2332 pub fn run_until(&mut self, ctx: &Context<'_>, addr: u64) -> crate::Result<()> {
2334 let target = self
2335 .block_at(ctx, addr)
2336 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::UnknownAddress(addr)))?;
2337 while self.block != target {
2338 self.run_block(ctx)?;
2339 }
2340 Ok(())
2341 }
2342
2343 fn writeback_materialized_outputs(
2361 &mut self,
2362 ctx: &Context<'_>,
2363 call_id: InstructionId,
2364 callee: FunctionId,
2365 ) {
2366 if call_is_regpure(ctx, call_id) {
2367 return;
2368 }
2369 let outputs = match &FunctionBody::from_id(ctx, callee).effects().register {
2370 qcode::value::RegisterChannelState::Materialized(map) => map.outputs.clone(),
2371 _ => return,
2372 };
2373 let Some(agg) = self.aggregate_values.get(&call_id).cloned() else {
2374 return;
2375 };
2376 for (field, ®) in agg.iter().zip(&outputs) {
2377 let _ = self.set_varnode_u128(ctx, reg, field.as_bits());
2378 }
2379 }
2380
2381 fn seed_entry_params(&mut self, ctx: &Context<'_>, func: FunctionId) {
2382 let Some(root) = FunctionBody::from_id(ctx, func).root() else {
2383 return;
2384 };
2385 let root_id = root.id;
2386 enum Seed {
2387 Reg(VarnodeId),
2388 Lit(u64),
2394 }
2395 let params: Vec<(BlockParamId, Option<Seed>, usize)> = BasicBlock::from_id(ctx, root_id)
2396 .params()
2397 .map(|param| {
2398 let src = param
2399 .name()
2400 .and_then(|name| ctx.get_named(name))
2401 .and_then(|value| match value {
2402 ValueId::Varnode(id) => Some(Seed::Reg(id)),
2403 _ => None,
2404 })
2405 .or_else(|| match param.origin() {
2406 Some(ValueId::Literal(_)) => {
2407 let ValueRef::Literal(lit) = ValueRef::new(param.origin()?, ctx) else {
2408 return None;
2409 };
2410 Some(Seed::Lit(lit.value()))
2411 }
2412 _ => None,
2413 });
2414 (param.id, src, param.size())
2415 })
2416 .collect();
2417 for (param_id, src, size) in params {
2418 let value = match src {
2419 Some(Seed::Reg(varnode_id)) => self.read_varnode(ctx, varnode_id),
2420 Some(Seed::Lit(addr)) => {
2421 let space = ctx.shared.default_space;
2425 self.read_memory(ctx, space, addr, size).ok().map(|bytes| {
2426 let mut buf = [0u8; 8];
2427 let n = bytes.len().min(8);
2428 buf[..n].copy_from_slice(&bytes[..n]);
2429 u64::from_le_bytes(buf)
2430 })
2431 }
2432 None => None,
2433 };
2434 if let Some(value) = value {
2435 self.block_param_values
2436 .insert(param_id, SizedValue::new(value, size));
2437 }
2438 }
2439 }
2440
2441 fn bind_entry_params_from_args(
2453 &mut self,
2454 ctx: &Context<'_>,
2455 call_id: InstructionId,
2456 target: FunctionId,
2457 ) {
2458 let args = match ctx.get_insn(call_id).mnemonic() {
2459 Mnemonic::Call(call) => call.args.clone(),
2460 _ => return,
2461 };
2462 let Some(root) = FunctionBody::from_id(ctx, target).root() else {
2463 return;
2464 };
2465 let params: Vec<(BlockParamId, usize)> = BasicBlock::from_id(ctx, root.id)
2466 .params()
2467 .map(|p| (p.id, p.size()))
2468 .collect();
2469 if args.len() != params.len() {
2470 self.seed_entry_params(ctx, target);
2473 return;
2474 }
2475 let values: Vec<SizedValue> = args
2477 .iter()
2478 .zip(¶ms)
2479 .map(|(&arg, &(_, size))| {
2480 let raw = self.get_value(ctx, arg.qualify(call_id.func)).unwrap_or(0);
2481 SizedValue::new(raw, size)
2482 })
2483 .collect();
2484 for ((param_id, _), value) in params.into_iter().zip(values) {
2485 self.block_param_values.insert(param_id, value);
2486 }
2487 }
2488
2489 pub fn run_function(&mut self, ctx: &Context<'_>, func: FunctionId) -> crate::Result<()> {
2490 let root = FunctionBody::from_id(ctx, func)
2491 .root()
2492 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
2493 .id;
2494 self.block = root;
2495 self.idx = 0;
2496 self.call_stack.push(func);
2497 self.seed_entry_params(ctx, func);
2498
2499 let mut call_depth: i32 = 0;
2500
2501 let result = loop {
2502 let insn_ids = BasicBlock::from_id(ctx, self.block)
2503 .instruction_ids()
2504 .to_vec();
2505 let insn = InstructionRef::from_id(ctx, insn_ids[self.idx]);
2506
2507 if matches!(insn.mnemonic(), Mnemonic::Return(_)) && call_depth == 0 {
2508 break Ok(());
2509 }
2510
2511 match self.step_with_event(ctx)? {
2512 StepEvent::DirectCallEntered(target) => {
2513 call_depth += 1;
2514 self.call_stack.push(target);
2515 let regpure_site = self
2522 .call_site_stack
2523 .last()
2524 .copied()
2525 .is_some_and(|call_id| call_is_regpure(ctx, call_id));
2526 if regpure_site || FunctionBody::from_id(ctx, target).is_reg_materialized() {
2527 if let Some(&call_id) = self.call_site_stack.last() {
2528 self.bind_entry_params_from_args(ctx, call_id, target);
2529 }
2530 } else {
2531 self.seed_entry_params(ctx, target);
2532 }
2533 }
2534 StepEvent::IndirectCallEntered => {
2535 call_depth += 1;
2536 if let Some(parent) = BasicBlock::from_id(ctx, self.block).parent() {
2538 let callee = parent.id;
2539 self.call_stack.push(callee);
2540 self.seed_entry_params(ctx, callee);
2541 }
2542 }
2543 StepEvent::Return | StepEvent::ReturnValue => {
2544 self.call_stack.pop();
2545 call_depth -= 1;
2546 }
2547 StepEvent::Normal | StepEvent::InterceptedCall => {}
2548 }
2549 };
2550
2551 self.call_stack.pop(); result
2553 }
2554
2555 pub fn run_pure(
2566 &mut self,
2567 ctx: &Context<'_>,
2568 func: FunctionId,
2569 args: &[SizedValue],
2570 max_steps: usize,
2571 ) -> crate::Result<()> {
2572 let opts: Vec<Option<SizedValue>> = args.iter().map(|&v| Some(v)).collect();
2573 self.run_pure_partial(ctx, func, &opts, max_steps)
2574 }
2575
2576 pub fn run_pure_partial(
2583 &mut self,
2584 ctx: &Context<'_>,
2585 func: FunctionId,
2586 args: &[Option<SizedValue>],
2587 max_steps: usize,
2588 ) -> crate::Result<()> {
2589 let root = FunctionBody::from_id(ctx, func)
2590 .root()
2591 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
2592 .id;
2593 self.block = root;
2594 self.idx = 0;
2595 self.call_stack.push(func);
2596
2597 let param_ids: Vec<BlockParamId> = BasicBlock::from_id(ctx, root)
2600 .params()
2601 .map(|p| p.id)
2602 .collect();
2603 for (param_id, arg) in param_ids.into_iter().zip(args) {
2604 match arg {
2605 Some(value) => {
2606 self.block_param_values.insert(param_id, *value);
2607 }
2608 None => {
2609 self.poison_params.insert(param_id);
2610 }
2611 }
2612 }
2613
2614 self.drive_to_return(ctx, root, func, max_steps)
2615 }
2616
2617 fn refresh_sequence_types(&mut self, ctx: &Context<'_>) {
2628 let published = ctx.shared.types.published_len();
2629 if self.sequence_types_checked_at == Some(published) {
2630 return;
2631 }
2632 self.sequence_types = ctx.shared.types.has_sequence_types();
2633 self.sequence_types_checked_at = Some(published);
2634 }
2635
2636 fn is_array_operand(&self, ctx: &Context<'_>, id: ValueId) -> bool {
2637 if !self.sequence_types {
2639 return false;
2640 }
2641 match ctx.stored_type_of(id) {
2642 Some(ty) => {
2643 ctx.shared.types.array_of(ty).is_some() || ctx.shared.types.list_of(ty).is_some()
2644 }
2645 None => false,
2646 }
2647 }
2648
2649 fn resolve_array(&mut self, ctx: &Context<'_>, id: ValueId) -> Option<Vec<u8>> {
2653 match id {
2654 ValueId::Bytes(b) => Some(ctx.shared.values.bytes[b].data.clone()),
2655 ValueId::Instruction(i) => self
2656 .array_values
2657 .get(&i)
2658 .cloned()
2659 .or_else(|| self.get_value_bytes(ctx, id)),
2660 ValueId::Literal(_) => self.get_value_bytes(ctx, id),
2661 ValueId::BlockParam(_) => {
2667 let bytes = self.get_value_bytes(ctx, id)?;
2668 let ty_size = ctx
2669 .stored_type_of(id)
2670 .map(|ty| ctx.shared.types.size_of(ty))?;
2671 (bytes.len() == ty_size).then_some(bytes)
2672 }
2673 _ => None,
2674 }
2675 }
2676
2677 fn eval_array_intrinsic(
2680 &mut self,
2681 ctx: &Context<'_>,
2682 insn_id: InstructionId,
2683 name: &str,
2684 args: &[ValueId],
2685 ) -> Result<(), EmulatorErrorKind> {
2686 match name {
2687 "iota" => {
2688 let n = self
2689 .get_value(ctx, args[0])
2690 .ok_or(EmulatorErrorKind::ValueError(0))?;
2691 let mut buf = Vec::with_capacity(n as usize * 8);
2692 for i in 0..n {
2693 buf.extend_from_slice(&i.to_le_bytes());
2694 }
2695 self.array_values.insert(insn_id, buf);
2696 }
2697 "singleton" => {
2698 let buf = self
2699 .get_value_bytes(ctx, args[0])
2700 .ok_or(EmulatorErrorKind::ValueError(0))?;
2701 self.array_values.insert(insn_id, buf);
2702 }
2703 "concat" => {
2704 let mut a = self
2705 .resolve_array(ctx, args[0])
2706 .ok_or(EmulatorErrorKind::ValueError(0))?;
2707 let b = self
2708 .resolve_array(ctx, args[1])
2709 .ok_or(EmulatorErrorKind::ValueError(0))?;
2710 a.extend_from_slice(&b);
2711 self.array_values.insert(insn_id, a);
2712 }
2713 "insert" => {
2714 let mut buf = self
2715 .resolve_array(ctx, args[0])
2716 .ok_or(EmulatorErrorKind::ValueError(0))?;
2717 let i = self
2718 .get_value(ctx, args[1])
2719 .ok_or(EmulatorErrorKind::ValueError(0))? as usize;
2720 let vbytes = self
2721 .get_value_bytes(ctx, args[2])
2722 .ok_or(EmulatorErrorKind::ValueError(0))?;
2723 let esz = vbytes.len();
2724 let off = i * esz;
2725 if off + esz <= buf.len() {
2726 buf[off..off + esz].copy_from_slice(&vbytes);
2727 }
2728 self.array_values.insert(insn_id, buf);
2729 }
2730 "enumerate" => {
2731 let src_ty = ctx
2736 .stored_type_of(args[0])
2737 .ok_or(EmulatorErrorKind::ValueError(0))?;
2738 if matches!(ctx.shared.types.list_of(src_ty), Some((_, None))) {
2739 return Err(EmulatorErrorKind::UnsupportedIntrinsic(Box::from(
2740 "enumerate",
2741 )));
2742 }
2743 let in_elem = ctx
2744 .shared
2745 .types
2746 .seq_elem_of(src_ty)
2747 .ok_or(EmulatorErrorKind::ValueError(0))?;
2748 let isz = ctx.shared.types.size_of(in_elem).max(1);
2749 let buf = self
2750 .resolve_array(ctx, args[0])
2751 .ok_or(EmulatorErrorKind::ValueError(0))?;
2752 let tuple_ty = ctx
2757 .stored_type_of(ValueId::Instruction(insn_id))
2758 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2759 .ok_or(EmulatorErrorKind::ValueError(0))?;
2760 let (idx_sz, elem_off) = {
2761 let fields = ctx
2762 .shared
2763 .types
2764 .aggregate_fields(tuple_ty)
2765 .ok_or(EmulatorErrorKind::ValueError(0))?;
2766 let [idx_f, _elem_f] = fields else {
2767 return Err(EmulatorErrorKind::ValueError(0));
2768 };
2769 let idx_sz = ctx.shared.types.size_of(idx_f.type_id).min(8);
2770 (idx_sz, idx_sz)
2771 };
2772 let tsz = idx_sz + isz;
2773 let count = buf.len() / isz;
2774 let mut out = vec![0u8; count * tsz];
2775 for i in 0..count {
2776 let base = i * tsz;
2777 let idx_bytes = (i as u64).to_le_bytes();
2778 out[base..base + idx_sz].copy_from_slice(&idx_bytes[..idx_sz]);
2779 out[base + elem_off..base + elem_off + isz]
2780 .copy_from_slice(&buf[i * isz..i * isz + isz]);
2781 }
2782 self.array_values.insert(insn_id, out);
2783 }
2784 "at" => {
2785 let buf = self
2786 .resolve_array(ctx, args[0])
2787 .ok_or(EmulatorErrorKind::ValueError(0))?;
2788 let i = self
2789 .get_value(ctx, args[1])
2790 .ok_or(EmulatorErrorKind::ValueError(0))? as usize;
2791 let esz = ctx
2792 .stored_type_of(ValueId::Instruction(insn_id))
2793 .map(|ty| ctx.shared.types.size_of(ty))
2794 .unwrap_or(8);
2795 let off = i * esz;
2796 let lane = buf
2797 .get(off..off + esz)
2798 .ok_or(EmulatorErrorKind::ValueError(0))?;
2799 self.insn_values
2800 .insert(insn_id, SizedValue::from_bits(le_bits(lane), esz));
2801 }
2802 other => panic!("eval_array_intrinsic called on non-array intrinsic `{other}`"),
2803 }
2804 Ok(())
2805 }
2806
2807 fn eval_scan(
2812 &mut self,
2813 ctx: &Context<'_>,
2814 insn_id: InstructionId,
2815 scan: &Scan,
2816 ) -> Result<(), EmulatorErrorKind> {
2817 const SCAN_STEP_BUDGET: usize = 100_000;
2818
2819 let src = self
2820 .resolve_array(ctx, scan.src.qualify(insn_id.func))
2821 .ok_or(EmulatorErrorKind::ValueError(0))?;
2822 let in_elem = ctx
2827 .stored_type_of(scan.src.qualify(insn_id.func))
2828 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2829 .ok_or(EmulatorErrorKind::ValueError(0))?;
2830 let isz = ctx.shared.types.size_of(in_elem).max(1);
2831 let out_elem = ctx
2832 .stored_type_of(ValueId::Instruction(insn_id))
2833 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2834 .ok_or(EmulatorErrorKind::ValueError(0))?;
2835 let osz = ctx.shared.types.size_of(out_elem);
2836 let count = src.len() / isz;
2837 let body = require_real_callee(scan.body)?;
2838 if count == 0 {
2839 self.array_values.insert(insn_id, Vec::new());
2840 return Ok(());
2841 }
2842
2843 let capture_args: Vec<BodyArg> = scan
2845 .captures
2846 .iter()
2847 .map(|&c| {
2848 let v = self
2849 .get_value(ctx, c.qualify(insn_id.func))
2850 .ok_or(EmulatorErrorKind::ValueError(0))?;
2851 let sz = ctx
2852 .stored_type_of(c.qualify(insn_id.func))
2853 .map(|ty| ctx.shared.types.size_of(ty))
2854 .unwrap_or(8);
2855 Ok(BodyArg::Scalar(SizedValue::new(v, sz)))
2856 })
2857 .collect::<Result<_, EmulatorErrorKind>>()?;
2858
2859 let init = self
2860 .get_value(ctx, scan.init.qualify(insn_id.func))
2861 .ok_or(EmulatorErrorKind::ValueError(0))?;
2862 let mut acc = SizedValue::new(init, osz);
2863
2864 let root = FunctionBody::from_id(ctx, body)
2865 .root()
2866 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(body))?
2867 .id;
2868
2869 let elem_fields: Option<Vec<(usize, usize)>> =
2875 ctx.shared.types.aggregate_fields(in_elem).map(|fs| {
2876 let mut off = 0;
2877 fs.iter()
2878 .map(|f| {
2879 let sz = ctx.shared.types.size_of(f.type_id);
2880 let field = (off, sz);
2881 off += sz;
2882 field
2883 })
2884 .collect()
2885 });
2886
2887 let mut out = Vec::with_capacity(count * osz);
2888 for k in 0..count {
2889 let elem = &src[k * isz..k * isz + isz];
2890 let elem_arg = match &elem_fields {
2891 Some(fields) => BodyArg::Aggregate(
2892 fields
2893 .iter()
2894 .map(|&(off, sz)| SizedValue::from_bits(le_bits(&elem[off..off + sz]), sz))
2895 .collect(),
2896 ),
2897 None => BodyArg::Scalar(SizedValue::from_bits(le_bits(elem), isz)),
2898 };
2899 let mut body_args = Vec::with_capacity(2 + capture_args.len());
2900 body_args.push(BodyArg::Scalar(acc));
2901 body_args.push(elem_arg);
2902 body_args.extend(capture_args.iter().cloned());
2903
2904 let mut emu = StandaloneEmulator::new(root);
2905 emu.run_map_body(ctx, body, &body_args, SCAN_STEP_BUDGET)
2906 .map_err(|e| e.kind)?;
2907 let ret = body_return_value(ctx, emu.current_block())
2908 .ok_or(EmulatorErrorKind::ValueError(0))?;
2909 let mut lane = emu
2910 .get_value_bytes(ctx, ret)
2911 .ok_or(EmulatorErrorKind::ValueError(0))?;
2912 lane.resize(osz, 0);
2913 acc = SizedValue::from_bits(le_bits(&lane), osz);
2914 out.extend_from_slice(&lane);
2915 }
2916 self.array_values.insert(insn_id, out);
2917 Ok(())
2918 }
2919
2920 fn eval_map(
2924 &mut self,
2925 ctx: &Context<'_>,
2926 insn_id: InstructionId,
2927 map: &qcode::value::insn::Map,
2928 ) -> Result<(), EmulatorErrorKind> {
2929 const MAP_STEP_BUDGET: usize = 100_000;
2930
2931 let src = self
2932 .resolve_array(ctx, map.src.qualify(insn_id.func))
2933 .ok_or(EmulatorErrorKind::ValueError(0))?;
2934 let in_elem = ctx
2935 .stored_type_of(map.src.qualify(insn_id.func))
2936 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2937 .ok_or(EmulatorErrorKind::ValueError(0))?;
2938 let isz = ctx.shared.types.size_of(in_elem).max(1);
2939 let out_elem = ctx
2940 .stored_type_of(ValueId::Instruction(insn_id))
2941 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2942 .ok_or(EmulatorErrorKind::ValueError(0))?;
2943 let osz = ctx.shared.types.size_of(out_elem);
2944 let count = src.len() / isz;
2945 let body = require_real_callee(map.body)?;
2946
2947 let capture_args: Vec<BodyArg> = map
2948 .captures
2949 .iter()
2950 .map(|&c| {
2951 let v = self
2952 .get_value(ctx, c.qualify(insn_id.func))
2953 .ok_or(EmulatorErrorKind::ValueError(0))?;
2954 let sz = ctx
2955 .stored_type_of(c.qualify(insn_id.func))
2956 .map(|ty| ctx.shared.types.size_of(ty))
2957 .unwrap_or(8);
2958 Ok(BodyArg::Scalar(SizedValue::new(v, sz)))
2959 })
2960 .collect::<Result<_, EmulatorErrorKind>>()?;
2961
2962 let elem_fields: Option<Vec<(usize, usize)>> =
2965 ctx.shared.types.aggregate_fields(in_elem).map(|fs| {
2966 let mut off = 0;
2967 fs.iter()
2968 .map(|f| {
2969 let sz = ctx.shared.types.size_of(f.type_id);
2970 let field = (off, sz);
2971 off += sz;
2972 field
2973 })
2974 .collect()
2975 });
2976
2977 let mut out = Vec::with_capacity(count * osz);
2978 for k in 0..count {
2979 let elem = &src[k * isz..k * isz + isz];
2980 let elem_arg = match &elem_fields {
2981 Some(fields) => BodyArg::Aggregate(
2982 fields
2983 .iter()
2984 .map(|&(off, sz)| SizedValue::from_bits(le_bits(&elem[off..off + sz]), sz))
2985 .collect(),
2986 ),
2987 None => BodyArg::Scalar(SizedValue::from_bits(le_bits(elem), isz)),
2988 };
2989 let mut body_args = Vec::with_capacity(1 + capture_args.len());
2990 body_args.push(elem_arg);
2991 body_args.extend(capture_args.iter().cloned());
2992
2993 let mut emu = StandaloneEmulator::new(
2994 FunctionBody::from_id(ctx, body)
2995 .root()
2996 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(body))?
2997 .id,
2998 );
2999 emu.run_map_body(ctx, body, &body_args, MAP_STEP_BUDGET)
3000 .map_err(|e| e.kind)?;
3001 let ret = body_return_value(ctx, emu.current_block())
3002 .ok_or(EmulatorErrorKind::ValueError(0))?;
3003 let mut lane = emu
3004 .get_value_bytes(ctx, ret)
3005 .ok_or(EmulatorErrorKind::ValueError(0))?;
3006 lane.resize(osz, 0);
3007 out.extend_from_slice(&lane);
3008 }
3009 self.array_values.insert(insn_id, out);
3010 Ok(())
3011 }
3012
3013 pub fn run_map_body(
3014 &mut self,
3015 ctx: &Context<'_>,
3016 func: FunctionId,
3017 args: &[BodyArg],
3018 max_steps: usize,
3019 ) -> crate::Result<()> {
3020 let root = FunctionBody::from_id(ctx, func)
3021 .root()
3022 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
3023 .id;
3024 self.block = root;
3025 self.idx = 0;
3026 self.call_stack.push(func);
3027
3028 let param_ids: Vec<BlockParamId> = BasicBlock::from_id(ctx, root)
3029 .params()
3030 .map(|p| p.id)
3031 .collect();
3032 for (param_id, arg) in param_ids.into_iter().zip(args) {
3033 match arg {
3034 BodyArg::Scalar(v) => {
3035 self.block_param_values.insert(param_id, *v);
3036 }
3037 BodyArg::Aggregate(fields) => {
3038 self.block_param_aggregates.insert(param_id, fields.clone());
3039 }
3040 }
3041 }
3042
3043 self.drive_to_return(ctx, root, func, max_steps)
3044 }
3045
3046 fn drive_to_return(
3052 &mut self,
3053 ctx: &Context<'_>,
3054 _root: BlockId,
3055 _func: FunctionId,
3056 max_steps: usize,
3057 ) -> crate::Result<()> {
3058 let mut steps = 0usize;
3059 let result = loop {
3060 let insn_ids = BasicBlock::from_id(ctx, self.block)
3061 .instruction_ids()
3062 .to_vec();
3063 if self.idx >= insn_ids.len() {
3069 break Err(self.make_empty_block_error(ctx));
3070 }
3071 let insn = InstructionRef::from_id(ctx, insn_ids[self.idx]);
3072 if matches!(
3073 insn.mnemonic(),
3074 Mnemonic::Return(_) | Mnemonic::ReturnValue(_)
3075 ) {
3076 break Ok(());
3077 }
3078 steps += 1;
3079 if steps > max_steps {
3080 break Err(self.make_error(ctx, EmulatorErrorKind::StepBudgetExceeded(max_steps)));
3081 }
3082 if let Err(e) = self.step(ctx) {
3083 break Err(e);
3084 }
3085 };
3086
3087 self.call_stack.pop();
3088 result
3089 }
3090}
3091
3092fn lambda_return_value(ctx: &Context<'_>, block: BlockId) -> Option<ValueId> {
3093 let last = BasicBlock::from_id(ctx, block).iter().last()?;
3094 match last.mnemonic() {
3095 Mnemonic::ReturnValue(ret) => Some(ret.value.qualify(last.id.func)),
3096 _ => None,
3097 }
3098}
3099
3100fn body_return_value(ctx: &Context<'_>, block: BlockId) -> Option<ValueId> {
3104 let last = BasicBlock::from_id(ctx, block).iter().last()?;
3105 match last.mnemonic() {
3106 Mnemonic::Return(ret) => ret.value.map(|v| v.qualify(last.id.func)),
3107 Mnemonic::ReturnValue(ret) => Some(ret.value.qualify(last.id.func)),
3108 _ => None,
3109 }
3110}
3111
3112fn is_array_intrinsic(name: &str) -> bool {
3116 matches!(
3117 name,
3118 "iota" | "singleton" | "concat" | "insert" | "at" | "enumerate"
3119 )
3120}
3121
3122fn le_bits(bytes: &[u8]) -> u128 {
3124 let mut buf = [0u8; 16];
3125 let n = bytes.len().min(16);
3126 buf[..n].copy_from_slice(&bytes[..n]);
3127 u128::from_le_bytes(buf)
3128}
3129
3130#[derive(Debug, Clone)]
3133pub enum BodyArg {
3134 Scalar(SizedValue),
3135 Aggregate(Vec<SizedValue>),
3136}
3137
3138struct TempInterpreter<'a, 'ctx, M> {
3141 memory: &'a mut M,
3142 literals: &'a mut LiteralCache,
3143 insn_values: &'a mut InsnValues,
3144 block_param_values: &'a mut FxHashMap<BlockParamId, SizedValue>,
3145 poison_params: &'a FxHashSet<BlockParamId>,
3146 ctx: &'ctx Context<'ctx>,
3147}
3148
3149impl<'ctx, M: EmulatorMemory> Interpreter for TempInterpreter<'_, 'ctx, M> {
3150 type V = SizedValue;
3151 type M = M;
3152
3153 fn memory(&mut self) -> &mut Self::M {
3154 self.memory
3155 }
3156
3157 fn ctx(&self) -> &Context<'_> {
3158 self.ctx
3159 }
3160
3161 fn get_value(&mut self, id: ValueId) -> Result<Self::V, EmulatorErrorKind> {
3162 if let ValueId::Literal(literal) = id {
3165 return Ok(self.literals.get(self.ctx, literal));
3166 }
3167 match ValueRef::new(id, self.ctx) {
3168 ValueRef::Literal(literal) => Ok(SizedValue::new(literal.value(), literal.size())),
3169 ValueRef::Bytes(_) => Err(EmulatorErrorKind::ValueError(0)),
3171 ValueRef::Instruction(insn) => self
3172 .insn_values
3173 .get(&insn.id)
3174 .copied()
3175 .ok_or(EmulatorErrorKind::ValueError(0)),
3176 ValueRef::Varnode(varnode) => Ok(SizedValue::new(varnode.address() as u64, 8)),
3177 ValueRef::Temp(temp) => Ok(SizedValue::new(temp.address() as u64, 8)),
3178 ValueRef::BasicBlock(_) => panic!("Cannot get value of a block"),
3179 ValueRef::BlockParam(param) => {
3180 if self.poison_params.contains(¶m.id) {
3181 return Err(EmulatorErrorKind::PoisonRead);
3182 }
3183 self.block_param_values
3184 .get(¶m.id)
3185 .copied()
3186 .ok_or(EmulatorErrorKind::ValueError(0))
3187 }
3188 ValueRef::Function(f) => f
3189 .address()
3190 .map(SizedValue::from_u64)
3191 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(f.id)),
3192 ValueRef::Poison(_) => Err(EmulatorErrorKind::PoisonRead),
3195 }
3196 }
3197}
3198
3199pub struct Emulator<'ctx, M = EmulatedMemory> {
3200 inner: StandaloneEmulator<M>,
3201 ctx: &'ctx Context<'ctx>,
3202}
3203
3204impl<'ctx> Emulator<'ctx, EmulatedMemory> {
3205 pub fn new(ctx: &'ctx Context<'ctx>, entry: BlockId) -> Self {
3207 Self::new_in(ctx, entry)
3208 }
3209
3210 pub fn from_function(ctx: &'ctx Context<'ctx>, func: FunctionId) -> Self {
3211 Self::from_function_in(ctx, func)
3212 }
3213
3214 pub fn from_block(ctx: &'ctx Context<'ctx>, block: BlockId) -> Self {
3215 Self::new_in(ctx, block)
3216 }
3217
3218 pub fn from_address(ctx: &'ctx Context<'ctx>, addr: u64) -> Self {
3219 Self::from_address_in(ctx, addr)
3220 }
3221}
3222
3223impl<'ctx, M: EmulatorMemory + Default> Emulator<'ctx, M> {
3224 pub fn new_in(ctx: &'ctx Context<'ctx>, entry: BlockId) -> Self {
3226 let mut inner =
3227 StandaloneEmulator::<M>::with_address_index(entry, AddressIndex::analyze(ctx));
3228 inner.memory.configure_spaces(ctx);
3229 Self { inner, ctx }
3230 }
3231
3232 pub fn set_instruction_hook(
3233 &mut self,
3234 hook: impl Fn(&InstructionRef<'_, '_>, &StandaloneEmulator<M>) + Send + Sync + 'static,
3235 ) {
3236 self.inner.instruction_hook = Some(Box::new(hook));
3237 }
3238
3239 pub fn set_call_interceptor(
3240 &mut self,
3241 interceptor: impl FnMut(
3242 &Context<'_>,
3243 &mut StandaloneEmulator<M>,
3244 &CallSite,
3245 ) -> Result<CallInterception, Box<str>>
3246 + Send
3247 + Sync
3248 + 'static,
3249 ) {
3250 self.inner.set_call_interceptor(interceptor);
3251 }
3252
3253 pub fn clear_call_interceptor(&mut self) {
3254 self.inner.clear_call_interceptor();
3255 }
3256
3257 pub fn from_function_in(ctx: &'ctx Context<'ctx>, func: FunctionId) -> Self {
3259 let entry = FunctionBody::from_id(ctx, func)
3260 .root()
3261 .expect("Cannot create emulator for function with empty root block")
3262 .id;
3263 Self::new_in(ctx, entry)
3264 }
3265
3266 pub fn from_address_in(ctx: &'ctx Context<'ctx>, addr: u64) -> Self {
3268 Self {
3269 inner: StandaloneEmulator::<M>::from_address_in(ctx, addr),
3270 ctx,
3271 }
3272 }
3273
3274 pub fn inspect_memory(&mut self, space: SpaceId, addr: u64, size: usize) -> Option<Vec<u8>> {
3276 self.inner
3277 .memory
3278 .read_bytes(MemorySpaceId::Shared(space), addr, size)
3279 .ok()
3280 }
3281
3282 pub fn set_varnode(&mut self, id: VarnodeId, value: u64) -> Result<(), EmulatorErrorKind> {
3284 self.inner.set_varnode(self.ctx, id, value)
3285 }
3286
3287 pub fn set_varnode_u128(
3289 &mut self,
3290 id: VarnodeId,
3291 value: u128,
3292 ) -> Result<(), EmulatorErrorKind> {
3293 self.inner.set_varnode_u128(self.ctx, id, value)
3294 }
3295
3296 pub fn set_register(&mut self, id: RegisterId, value: u64) -> Result<(), EmulatorErrorKind> {
3298 let id = self.ctx.get_register(id).id;
3299 self.set_varnode(id, value)
3300 }
3301
3302 pub fn write_memory(
3304 &mut self,
3305 space: SpaceId,
3306 addr: u64,
3307 value: &[u8],
3308 ) -> Result<(), EmulatorErrorKind> {
3309 self.inner.write_memory(self.ctx, space, addr, value)
3310 }
3311
3312 pub fn read_memory(
3313 &mut self,
3314 space: SpaceId,
3315 addr: u64,
3316 size: usize,
3317 ) -> Result<Vec<u8>, EmulatorErrorKind> {
3318 self.inner.read_memory(self.ctx, space, addr, size)
3319 }
3320
3321 pub fn set_register_u128(
3323 &mut self,
3324 id: RegisterId,
3325 value: u128,
3326 ) -> Result<(), EmulatorErrorKind> {
3327 let id = self.ctx.get_register(id).id;
3328 self.set_varnode_u128(id, value)
3329 }
3330
3331 pub fn read_varnode(&mut self, id: VarnodeId) -> Option<u64> {
3332 self.inner.read_varnode(self.ctx, id)
3333 }
3334
3335 pub fn read_varnode_u128(&mut self, id: VarnodeId) -> Option<u128> {
3336 self.inner.read_varnode_u128(self.ctx, id)
3337 }
3338
3339 pub fn read_register(&mut self, id: RegisterId) -> Option<u64> {
3340 let id = self.ctx.get_register(id).id;
3341 self.read_varnode(id)
3342 }
3343
3344 pub fn read_register_u128(&mut self, id: RegisterId) -> Option<u128> {
3345 let id = self.ctx.get_register(id).id;
3346 self.read_varnode_u128(id)
3347 }
3348
3349 pub fn set_register_lane(&mut self, id: RegisterId, lane: usize, value: u64) {
3352 let (space_id, base_addr) = {
3353 let vn = self.ctx.get_register(id);
3354 (vn.space().id, vn.address() as u64)
3355 };
3356 let base = base_addr + (lane as u64) * 8;
3357 let _ = self
3358 .inner
3359 .memory
3360 .write_bytes(space_id.into(), base, &value.to_le_bytes());
3361 }
3362
3363 pub fn read_register_lane(&mut self, id: RegisterId, lane: usize) -> u64 {
3366 let (space_id, base_addr) = {
3367 let vn = self.ctx.get_register(id);
3368 (vn.space().id, vn.address() as u64)
3369 };
3370 let base = base_addr + (lane as u64) * 8;
3371 let bytes = self
3374 .inner
3375 .memory
3376 .read_bytes(space_id.into(), base, 8)
3377 .unwrap_or_else(|_| vec![0; 8]);
3378 u64::from_le_bytes(bytes.try_into().expect("read_bytes returns 8 bytes"))
3379 }
3380
3381 pub fn block(&self) -> BlockRef<'ctx, 'ctx> {
3383 BasicBlock::from_id(self.ctx, self.inner.block)
3384 }
3385
3386 pub fn insn(&self) -> Option<InstructionRef<'ctx, 'ctx>> {
3388 let block = self.block();
3389 if self.inner.idx >= block.instruction_count() {
3390 None
3391 } else {
3392 let id = block.instruction_ids()[self.inner.idx];
3393 Some(InstructionRef::from_id(self.ctx, id))
3394 }
3395 }
3396
3397 pub fn step(&mut self) -> crate::Result<()> {
3399 self.inner.step(self.ctx)
3400 }
3401
3402 pub fn run_block(&mut self) -> crate::Result<()> {
3404 self.inner.run_block(self.ctx)
3405 }
3406
3407 pub fn run_until(&mut self, addr: u64) -> crate::Result<()> {
3409 self.inner.run_until(self.ctx, addr)
3410 }
3411
3412 pub fn run_function(&mut self, func: FunctionId) -> crate::Result<()> {
3414 self.inner.run_function(self.ctx, func)
3415 }
3416
3417 pub fn call_stack(&self) -> &[FunctionId] {
3420 &self.inner.call_stack
3421 }
3422}
3423
3424impl<'ctx, M: EmulatorMemory> Interpreter for Emulator<'ctx, M> {
3425 type V = SizedValue;
3426 type M = M;
3427
3428 fn memory(&mut self) -> &mut Self::M {
3429 &mut self.inner.memory
3430 }
3431
3432 fn ctx(&self) -> &Context<'ctx> {
3433 self.ctx
3434 }
3435
3436 fn get_value(&mut self, id: ValueId) -> Result<Self::V, EmulatorErrorKind> {
3437 if let ValueId::Literal(literal) = id {
3438 let value = self.inner.literal_cache.get(self.ctx, literal);
3439 return Ok(value);
3440 }
3441 match ValueRef::new(id, self.ctx) {
3442 ValueRef::Literal(literal) => Ok(SizedValue::new(literal.value(), literal.size())),
3443 ValueRef::Bytes(_) => Err(EmulatorErrorKind::ValueError(0)),
3445 ValueRef::Instruction(insn) => self
3446 .inner
3447 .insn_values
3448 .get(&insn.id)
3449 .copied()
3450 .ok_or(EmulatorErrorKind::ValueError(0)),
3451 ValueRef::Varnode(varnode) => Ok(SizedValue::new(varnode.address() as u64, 8)),
3452 ValueRef::Temp(temp) => Ok(SizedValue::new(temp.address() as u64, 8)),
3453 ValueRef::BasicBlock(_) => panic!("Cannot get value of a block"),
3454 ValueRef::BlockParam(param) => self
3455 .inner
3456 .block_param_values
3457 .get(¶m.id)
3458 .copied()
3459 .ok_or(EmulatorErrorKind::ValueError(0)),
3460 ValueRef::Function(f) => f
3461 .address()
3462 .map(SizedValue::from_u64)
3463 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(f.id)),
3464 ValueRef::Poison(_) => Err(EmulatorErrorKind::PoisonRead),
3467 }
3468 }
3469}
3470
3471#[cfg(test)]
3472mod tests {
3473 use super::*;
3474 use qcode::context::Context;
3475 use qcode::space::{Space, SpaceType};
3476 use qcode::value::QCodeMut;
3477 use qcode::value::TempSpace;
3478 use std::sync::{Arc, Mutex};
3479 use wazabin_qcode_macro::qcode;
3480
3481 #[test]
3484 fn reading_poison_is_a_hard_error() {
3485 let mut ctx = Context::new();
3486 let func = ctx.anon_function();
3487 let block = BasicBlock::make(&mut ctx, func).with_address(0x1000).id;
3488 let i32_ty = ctx.shared.types.get_or_make_int(4);
3489 let poison = ctx.get_poison(i32_ty);
3490 let mut emu = StandaloneEmulator::new(block);
3491 let mut tmp = TempInterpreter {
3492 memory: &mut emu.memory,
3493 literals: &mut emu.literal_cache,
3494 insn_values: &mut emu.insn_values,
3495 block_param_values: &mut emu.block_param_values,
3496 poison_params: &emu.poison_params,
3497 ctx: &ctx,
3498 };
3499 assert!(matches!(
3500 tmp.get_value(poison),
3501 Err(EmulatorErrorKind::PoisonRead)
3502 ));
3503 }
3504
3505 #[test]
3506 fn minted_callee_is_not_executable() {
3507 assert!(matches!(
3508 require_real_callee(Callee::Minted(7)),
3509 Err(EmulatorErrorKind::UnresolvedMintedCallee(7))
3510 ));
3511 }
3512
3513 #[test]
3514 fn sized_value_masks_to_declared_width() {
3515 let value = SizedValue::new(0x1234, 1);
3516 assert_eq!(value.size().unwrap(), 1);
3517 assert_eq!(value.value().unwrap(), 0x34);
3518 }
3519
3520 #[test]
3521 fn from_address_resolves_function_entry_to_root() {
3522 let mut ctx = Context::new();
3523 let function = FunctionBody::make_at_addr(&mut ctx, 0x1000, None).id;
3524 let root = BasicBlock::make(&mut ctx, function).with_address(0x1000).id;
3525
3526 let emulator = StandaloneEmulator::from_address(&ctx, 0x1000);
3527
3528 assert_eq!(emulator.current_block(), root);
3529 assert!(emulator.address_index.is_some());
3530 }
3531
3532 #[test]
3533 fn standalone_address_lookup_builds_one_lazy_snapshot() {
3534 let mut ctx = Context::new();
3535 let function = ctx.anon_function();
3536 let block = BasicBlock::make(&mut ctx, function).with_address(0x2000).id;
3537 ctx.block_mut(block).extra_addresses.push(0x2001);
3538 let mut emulator = StandaloneEmulator::new(block);
3539
3540 assert!(emulator.address_index.is_none());
3541 assert_eq!(emulator.block_at(&ctx, 0x2001), Some(block));
3542 assert!(emulator.address_index.is_some());
3543 assert_eq!(emulator.block_at(&ctx, 0x2000), Some(block));
3544 }
3545
3546 #[test]
3547 fn int_add_wraps_by_width_and_sets_carry() {
3548 let lhs = SizedValue::new(0xff, 1);
3549 let rhs = SizedValue::new(0x01, 1);
3550
3551 let sum = lhs.int_add(&rhs).unwrap();
3552 let carry = lhs.carry(&rhs).unwrap();
3553
3554 assert_eq!(sum.value().unwrap(), 0x00);
3555 assert_eq!(sum.size().unwrap(), 1);
3556 assert_eq!(carry.value().unwrap(), 1);
3557 assert_eq!(carry.size().unwrap(), 1);
3558 }
3559
3560 #[test]
3561 fn branch_args_bind_block_params() {
3562 let mut ctx = Context::new();
3563 qcode!(
3564 ctx,
3565 "
3566 <src>
3567 goto <dst @x=0x2>;
3568 <dst @x>
3569 %sum = i64 @x + 0x3;
3570 goto <0x1001>;
3571 "
3572 );
3573
3574 let mut emu = StandaloneEmulator::new(src);
3575 emu.step(&ctx).expect("branch binds block params");
3576 emu.step(&ctx).expect("destination uses block param");
3577
3578 assert_eq!(emu.get_value(&ctx, sum.into()), Some(5));
3579 }
3580
3581 #[test]
3582 fn apply_evaluates_recursive_lambda_value_return() {
3583 let mut ctx = Context::new();
3584 qcode!(
3585 ctx,
3586 "
3587 lambda dec:
3588 <entry @n:i64>
3589 %is_zero = @n == 0;
3590 if %is_zero goto <done @r=@n> else goto <step @m=@n>;
3591
3592 <step @m:i64>
3593 %next = @m - 1;
3594 %out = apply dec(%next);
3595 return %out;
3596
3597 <done @r:i64>
3598 return @r;
3599 "
3600 );
3601
3602 let dec = qcode::value::FunctionBody::from_name(&ctx, "dec")
3603 .expect("lambda exists")
3604 .id;
3605 let root = qcode::value::FunctionBody::from_id(&ctx, dec)
3606 .root()
3607 .expect("lambda has root")
3608 .id;
3609 let mut emu = StandaloneEmulator::new(root);
3610 emu.run_pure(&ctx, dec, &[SizedValue::new(3, 8)], 1000)
3611 .expect("recursive lambda evaluates");
3612 let ret = lambda_return_value(&ctx, emu.current_block()).expect("lambda returned a value");
3613 assert_eq!(emu.get_value(&ctx, ret), Some(0));
3614 }
3615
3616 fn publish_iota_result(ctx: &mut Context) {
3619 use qcode::types::TypeRequest;
3620 let i64_ty = ctx.shared.types.get_or_make_int(8);
3621 ctx.shared
3622 .types
3623 .create_requested_types(&[TypeRequest::list(i64_ty, None)]);
3624 }
3625
3626 #[test]
3629 fn map_over_array_is_emulated() {
3630 let mut ctx = Context::new();
3631 publish_iota_result(&mut ctx);
3632 qcode!(
3633 ctx,
3634 "
3635 lambda triple:
3636 <tb @x:i64>
3637 %r = @x * 3;
3638 return %r;
3639 fn main:
3640 <me>
3641 %src = $iota(i64 0x4);
3642 %m = triple <$> %src;
3643 goto <0x1001>;
3644 "
3645 );
3646
3647 let mut emu = StandaloneEmulator::new(me);
3648 emu.step(&ctx).expect("iota");
3649 emu.step(&ctx).expect("map");
3650
3651 let buf = emu.array_values.get(&m).expect("map produced an array");
3652 let words: Vec<u64> = buf
3653 .as_chunks::<8>()
3654 .0
3655 .iter()
3656 .map(|&c| u64::from_le_bytes(c))
3657 .collect();
3658 assert_eq!(words, vec![0, 3, 6, 9]);
3660 }
3661
3662 #[test]
3667 fn scan_over_iota_is_emulated() {
3668 let mut ctx = Context::new();
3669 publish_iota_result(&mut ctx);
3670 qcode!(
3671 ctx,
3672 "
3673 lambda step:
3674 <sb @acc:i64 @x:i64>
3675 %r = @acc + @x;
3676 return %r;
3677 fn main:
3678 <me>
3679 %src = $iota(i64 0x3);
3680 %s = scanl @step i64 0xa %src;
3681 goto <0x1001>;
3682 "
3683 );
3684
3685 let mut emu = StandaloneEmulator::new(me);
3686 emu.step(&ctx).expect("iota");
3688 emu.step(&ctx).expect("scan");
3689
3690 let buf = emu.array_values.get(&s).expect("scan produced an array");
3691 let words: Vec<u64> = buf
3692 .as_chunks::<8>()
3693 .0
3694 .iter()
3695 .map(|&c| u64::from_le_bytes(c))
3696 .collect();
3697 assert_eq!(words, vec![10, 11, 13]);
3698 }
3699
3700 #[test]
3701 fn enumerate_over_array_is_emulated() {
3702 use qcode::value::{FunctionBody, ValueId, insn::IntrinsicId};
3703
3704 let mut ctx = Context::new();
3705 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
3706 let entry = ctx.get_or_make_block(0x1000, f);
3707 {
3708 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
3709 fm.set_root(entry).unwrap();
3710 fm.add_block(entry);
3711 }
3712 let i64_ty = ctx.shared.types.get_or_make_int(8);
3714 let arr_ty = ctx.shared.types.get_or_make_array(i64_ty, 4);
3715 let data: Vec<u8> = [10u64, 20, 30, 40]
3716 .iter()
3717 .flat_map(|w| w.to_le_bytes())
3718 .collect();
3719 let src = ctx.get_bytes(data).id();
3720 if let ValueId::Bytes(bid) = src {
3721 ctx.shared.values.bytes[bid].type_id = arr_ty;
3722 }
3723 {
3726 use qcode::types::{AggregateField, TypeRequest};
3727 let fields = vec![
3728 AggregateField::new("index", i64_ty),
3729 AggregateField::new("elem", i64_ty),
3730 ];
3731 let tuple = ctx
3732 .shared
3733 .types
3734 .create_requested_types(&[TypeRequest::aggregate(fields)])[0];
3735 ctx.shared
3736 .types
3737 .create_requested_types(&[TypeRequest::array(tuple, 4)]);
3738 }
3739 let enum_id = IntrinsicId::from_name("enumerate").unwrap();
3740 let e = {
3741 let mut b = ctx.builder(entry);
3742 let e = b.push_intrinsic(enum_id, vec![src]).id();
3743 let ptr = b.shr().get_const(0, 8);
3744 b.push_return(ptr);
3745 e
3746 };
3747 let ValueId::Instruction(eid) = e else {
3748 unreachable!()
3749 };
3750
3751 let mut emu = StandaloneEmulator::new(entry);
3752 emu.step(&ctx).expect("enumerate");
3753
3754 let buf = emu
3757 .array_values
3758 .get(&eid)
3759 .expect("enumerate produced an array");
3760 let words: Vec<u64> = buf
3761 .as_chunks::<8>()
3762 .0
3763 .iter()
3764 .map(|&c| u64::from_le_bytes(c))
3765 .collect();
3766 assert_eq!(words, vec![0, 10, 1, 20, 2, 30, 3, 40]);
3767 }
3768
3769 #[test]
3774 fn enumerate_of_unbounded_list_bails_recoverably() {
3775 use qcode::value::{
3776 BasicBlock, FunctionBody, InstructionRef, ValueId,
3777 insn::{IntrinsicApp, IntrinsicId, Return},
3778 };
3779
3780 let mut ctx = Context::new();
3781 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
3782 let entry = ctx.get_or_make_block(0x1000, f);
3783 {
3784 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
3785 fm.set_root(entry).unwrap();
3786 fm.add_block(entry);
3787 }
3788 let i8 = ctx.shared.types.get_or_make_int(1);
3789 let list_ty = ctx.shared.types.get_or_make_unbounded_list(i8);
3790 let src = {
3791 let mut b = ctx.builder(entry);
3792 b.push_param(8).id()
3793 };
3794 if let ValueId::BlockParam(pid) = src {
3795 ctx.block_param_mut(pid).type_id = list_ty;
3796 }
3797 let enum_id = IntrinsicId::from_name("enumerate").unwrap();
3801 let env = {
3806 let insn = InstructionRef::from_mnemonic_with_type(
3807 &mut ctx,
3808 entry.func,
3809 Mnemonic::Intrinsic(IntrinsicApp {
3810 id: enum_id,
3811 args: vec![src.localize(entry.func)],
3812 }),
3813 list_ty,
3814 )
3815 .id;
3816 BasicBlock::from_id_mut(&mut ctx, entry).push_insn(insn);
3817 ValueId::Instruction(insn)
3818 };
3819 let ptr = ctx.get_const(0, 8).id();
3820 {
3821 let mut b = ctx.builder(entry);
3822 b.push_return(ptr);
3823 }
3824 let rid = BasicBlock::from_id(&ctx, entry).iter().last().unwrap().id;
3825 ctx.replace_instruction_mnemonic(
3826 rid,
3827 Mnemonic::Return(Return {
3828 ptr: ptr.localize(rid.func),
3829 value: Some(env.localize(rid.func)),
3830 }),
3831 );
3832
3833 let mut emu = StandaloneEmulator::new(entry);
3834 let err = emu
3835 .run_pure(&ctx, f, &[SizedValue::new(0, 4)], 1000)
3836 .expect_err("enumerate must not be emulated");
3837 assert!(
3838 matches!(err.kind, EmulatorErrorKind::UnsupportedIntrinsic(ref n) if &**n == "enumerate"),
3839 "expected recoverable UnsupportedIntrinsic, got {:?}",
3840 err.kind
3841 );
3842 }
3843
3844 fn run_at_over_array_param(n: usize, idx: u64, bound: SizedValue) -> Option<u64> {
3848 use qcode::value::{
3849 BasicBlock, FunctionBody, ValueId,
3850 insn::{IntrinsicId, Return},
3851 };
3852
3853 let mut ctx = Context::new();
3854 let arr_ty = {
3855 let i8 = ctx.shared.types.get_or_make_int(1);
3856 ctx.shared.types.get_or_make_array(i8, n)
3857 };
3858 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
3859 let entry = ctx.get_or_make_block(0x1000, f);
3860 {
3861 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
3862 fm.set_root(entry).unwrap();
3863 fm.add_block(entry);
3864 }
3865 let arr_pid = BasicBlock::from_id_mut(&mut ctx, entry).push_param(n).id;
3866 ctx.block_param_mut(arr_pid).type_id = arr_ty;
3867
3868 let at_id = IntrinsicId::from_name("at").unwrap();
3869 let (ret, ptr, lane);
3870 {
3871 let mut b = ctx.builder(entry);
3872 let arr = ValueId::BlockParam(arr_pid);
3873 let i = b.shr().get_const(idx, 8);
3874 lane = b.push_intrinsic(at_id, vec![arr, i]).id();
3875 ptr = b.shr().get_const(0, 8);
3876 ret = b.push_return(ptr).id();
3877 }
3878 let ValueId::Instruction(rid) = ret else {
3879 unreachable!()
3880 };
3881 ctx.replace_instruction_mnemonic(
3882 rid,
3883 Mnemonic::Return(Return {
3884 ptr: ptr.localize(rid.func),
3885 value: Some(lane.localize(rid.func)),
3886 }),
3887 );
3888
3889 let mut emu = StandaloneEmulator::new(entry);
3890 emu.run_pure(&ctx, f, &[bound], 1000).ok()?;
3891 emu.get_value(&ctx, lane)
3892 }
3893
3894 fn run_switch(scrutinee: u64) -> Option<u64> {
3898 let mut ctx = Context::new();
3899 qcode!(
3900 ctx,
3901 "
3902 lambda sw:
3903 <entry @i:i64>
3904 switch @i { 0x0 => <a>, 0x3 => <b @v=0x63>, default => <d> };
3905 <a>
3906 return 0x11;
3907 <b @v:i64>
3908 return @v;
3909 <d>
3910 return 0x99;
3911 "
3912 );
3913 let root = FunctionBody::from_id(&ctx, sw).root().expect("root").id;
3914 let mut emu = StandaloneEmulator::new(root);
3915 emu.run_pure(&ctx, sw, &[SizedValue::new(scrutinee, 8)], 1000)
3916 .ok()?;
3917 let term = BasicBlock::from_id(&ctx, emu.block)
3918 .instruction_ids()
3919 .last()
3920 .copied()?;
3921 let Mnemonic::ReturnValue(r) = Instruction::from_id(&ctx, term).mnemonic() else {
3922 return None;
3923 };
3924 emu.get_value(&ctx, r.value.qualify(term.func))
3925 }
3926
3927 #[test]
3928 fn switch_selects_the_matching_arm() {
3929 assert_eq!(run_switch(0), Some(0x11));
3930 assert_eq!(run_switch(3), Some(0x63));
3932 assert_eq!(run_switch(7), Some(0x99));
3934 }
3935
3936 #[test]
3940 fn run_pure_reads_array_param_bytes_little_endian() {
3941 let arg = SizedValue::new(0x2f76bfc2, 4);
3942 assert_eq!(run_at_over_array_param(4, 0, arg), Some(0xc2));
3944 assert_eq!(run_at_over_array_param(4, 1, arg), Some(0xbf));
3945 assert_eq!(run_at_over_array_param(4, 2, arg), Some(0x76));
3946 assert_eq!(run_at_over_array_param(4, 3, arg), Some(0x2f));
3947 }
3948
3949 #[test]
3953 fn run_pure_rejects_oversize_array_param() {
3954 assert_eq!(
3957 run_at_over_array_param(20, 0, SizedValue::new(0xff, 20)),
3958 None
3959 );
3960 }
3961
3962 #[test]
3963 fn int_mul_wraps_for_64_bit_values() {
3964 let lhs = SizedValue::new(u64::MAX, 8);
3965 let rhs = SizedValue::new(2, 8);
3966
3967 let product = lhs.int_mul(&rhs).unwrap();
3968
3969 assert_eq!(product.value().unwrap(), u64::MAX.wrapping_mul(2));
3970 assert_eq!(product.size().unwrap(), 8);
3971 }
3972
3973 #[test]
3974 fn int_mul_wraps_for_128_bit_values() {
3975 let lhs = SizedValue::from_bits(u128::MAX, 16);
3976 let rhs = SizedValue::from_bits(u128::from(2u8), 16);
3977
3978 let product = lhs.int_mul(&rhs).unwrap();
3979
3980 assert_eq!(product.as_bits(), u128::MAX.wrapping_mul(u128::from(2u8)));
3981 assert_eq!(product.size().unwrap(), 16);
3982 assert!(matches!(
3983 product.value(),
3984 Err(EmulatorErrorKind::ValueError(_))
3985 ));
3986 }
3987
3988 #[test]
3989 fn int_div_and_rem_work_for_128_bit_values() {
3990 let lhs = SizedValue::from_bits(u128::MAX, 16);
3991 let rhs = SizedValue::from_bits(u128::from(3u8), 16);
3992
3993 let q = lhs.int_div(&rhs).unwrap();
3994 let r = lhs.int_rem(&rhs).unwrap();
3995
3996 assert_eq!(q.as_bits(), u128::MAX / u128::from(3u8));
3997 assert_eq!(r.as_bits(), u128::MAX % u128::from(3u8));
3998 assert_eq!(q.size().unwrap(), 16);
3999 assert_eq!(r.size().unwrap(), 16);
4000 }
4001
4002 #[test]
4003 fn int_sdiv_and_srem_work_for_128_bit_values() {
4004 let lhs = SizedValue::from_bits(u128::from(0xffff_ffff_ffff_ffffu64), 16);
4005 let rhs = SizedValue::from_bits(u128::from(2u8), 16);
4006
4007 let q = lhs.int_sdiv(&rhs).unwrap();
4008 let r = lhs.int_srem(&rhs).unwrap();
4009
4010 assert_eq!(q.as_bits(), u128::from(0x7fff_ffff_ffff_ffffu64));
4011 assert_eq!(r.as_bits(), u128::from(1u8));
4012 assert_eq!(q.size().unwrap(), 16);
4013 assert_eq!(r.size().unwrap(), 16);
4014 }
4015
4016 #[test]
4017 fn signed_extension_and_shift_behave_as_expected() {
4018 let negative_byte = SizedValue::new(0x80, 1);
4019 let extended = negative_byte.sext(8).unwrap();
4020 let shifted = negative_byte
4021 .int_sshift_right(&SizedValue::new(1, 1))
4022 .unwrap();
4023
4024 assert_eq!(extended.value().unwrap(), 0xffff_ffff_ffff_ff80);
4025 assert_eq!(extended.size().unwrap(), 8);
4026 assert_eq!(shifted.value().unwrap(), 0xc0);
4027 assert_eq!(shifted.size().unwrap(), 1);
4028 }
4029
4030 #[test]
4031 fn signed_comparisons_use_value_width() {
4032 let lhs = SizedValue::new(0xff, 1);
4033 let rhs = SizedValue::new(0x01, 1);
4034
4035 assert_eq!(lhs.int_sless(&rhs).and_then(|v| v.value()).unwrap(), 1);
4036 assert_eq!(rhs.int_sless(&lhs).and_then(|v| v.value()).unwrap(), 0);
4037 }
4038
4039 #[test]
4040 fn int_sub_uses_lhs_width_with_default_u64_immediate() {
4041 let lhs = SizedValue::new(0, 4);
4042 let rhs = SizedValue::from_u64(1);
4043
4044 let diff = lhs.int_sub(&rhs).unwrap();
4045
4046 assert_eq!(diff.size().unwrap(), 4);
4047 assert_eq!(diff.value().unwrap(), 0xffff_ffff);
4048 }
4049
4050 #[test]
4051 fn sborrow_uses_lhs_width_with_default_u64_immediate() {
4052 let lhs = SizedValue::new(0x80, 1);
4053 let rhs = SizedValue::new(1, 1);
4054
4055 assert_eq!(lhs.sborrow(&rhs).and_then(|v| v.value()).unwrap(), 1);
4057 }
4058
4059 #[test]
4060 fn scarry_uses_lhs_width_with_default_u64_immediate() {
4061 let lhs = SizedValue::new(0x7f, 1);
4062 let rhs = SizedValue::new(1, 1);
4063
4064 assert_eq!(lhs.scarry(&rhs).and_then(|v| v.value()).unwrap(), 1);
4066 }
4067
4068 #[test]
4069 fn sborrow_neg() {
4070 let lhs = SizedValue::new(0x0, 1);
4071 let rhs = SizedValue::new(0x80, 1);
4072
4073 assert_eq!(lhs.sborrow(&rhs).and_then(|v| v.value()).unwrap(), 1);
4075 }
4076
4077 #[test]
4078 fn lz_count_respects_width() {
4079 let value = SizedValue::new(0x01, 1);
4080 let lz = value.lz_count().unwrap();
4081
4082 assert_eq!(lz.value().unwrap(), 7);
4083 assert_eq!(lz.size().unwrap(), 1);
4084 }
4085
4086 #[test]
4087 fn float_conversion_handles_f32_and_f64() {
4088 let minus_one = SizedValue::new(0xff, 1);
4089 let as_f32 = minus_one.int_to_float(4).unwrap();
4090 assert_eq!(as_f32.value().unwrap(), (-1.0f32).to_bits() as u64);
4091 assert_eq!(as_f32.size().unwrap(), 4);
4092
4093 let f32_value = SizedValue::new((1.5f32).to_bits() as u64, 4);
4094 let promoted = f32_value.float_to_float(8).unwrap();
4095 let promoted_bits = promoted.value().unwrap();
4096 assert_eq!(f64::from_bits(promoted_bits), 1.5f64);
4097 assert_eq!(promoted.size().unwrap(), 8);
4098
4099 let demoted = promoted.float_to_float(4).unwrap();
4100 assert_eq!(demoted.value().unwrap(), (1.5f32).to_bits() as u64);
4101 assert_eq!(demoted.size().unwrap(), 4);
4102 }
4103
4104 #[test]
4105 fn x87_precision_and_store_rounding_are_separate_from_generic_arithmetic() {
4106 let one = 0x3fff_8000_0000_0000_0000u128;
4107 let one_plus_half_single_ulp = one + (1u128 << 39);
4110 assert_eq!(
4111 float80::round_to_precision(one_plus_half_single_ulp, 24, Round::NearestTiesToEven)
4112 .bits,
4113 one
4114 );
4115 assert_eq!(
4116 float80::round_to_precision(one_plus_half_single_ulp, 24, Round::TowardPositive).bits,
4117 one + (1u128 << 40)
4118 );
4119 assert_eq!(
4121 float80::round_to_precision(one_plus_half_single_ulp, 64, Round::TowardPositive).bits,
4122 one_plus_half_single_ulp
4123 );
4124
4125 let extended = SizedValue::from_bits(one_plus_half_single_ulp, 10);
4129 assert_eq!(
4130 StandaloneEmulator::<EmulatedMemory>::ieee_narrow(
4131 extended,
4132 4,
4133 Round::NearestTiesToEven
4134 )
4135 .unwrap()
4136 .0
4137 .as_bits(),
4138 u128::from(1.0f32.to_bits())
4139 );
4140 assert_eq!(
4141 StandaloneEmulator::<EmulatedMemory>::ieee_narrow(extended, 4, Round::TowardPositive)
4142 .unwrap()
4143 .0
4144 .as_bits(),
4145 u128::from((1.0f32).to_bits() + 1)
4146 );
4147
4148 let mut ctx = Context::new();
4152 qcode!(
4153 ctx,
4154 "
4155 varnode i16 FPUControlWord;
4156 varnode i16 FPUStatusWord;
4157 varnode f80 A;
4158 varnode f80 B;
4159
4160 <block>
4161 %a = load(A:10, &A);
4162 %b = load(B:10, &B);
4163 %result = %a f/ %b;
4164 goto <0x1001>;
4165 "
4166 );
4167 let mut emu = Emulator::from_block(&ctx, block);
4168 emu.set_varnode(FPUControlWord, 0x037b).unwrap(); emu.set_varnode_u128(A, one).unwrap();
4170 emu.set_varnode_u128(B, 0).unwrap();
4171 emu.run_block().unwrap();
4172 assert_eq!(emu.get_value(result.into()).unwrap().size().unwrap(), 10);
4173 assert_eq!(emu.read_varnode(FPUStatusWord), None);
4175 }
4176
4177 #[test]
4181 fn f80_comparison_records_no_status() {
4182 let mut ctx = Context::new();
4183 qcode!(
4184 ctx,
4185 "
4186 varnode i16 FPUControlWord;
4187 varnode i16 FPUStatusWord;
4188 varnode f80 A;
4189 varnode f80 B;
4190
4191 <block>
4192 %a = load(A:10, &A);
4193 %b = load(B:10, &B);
4194 %equal = %a f== %b;
4195 goto <0x1001>;
4196 "
4197 );
4198 let mut emu = Emulator::from_block(&ctx, block);
4199 emu.set_varnode(FPUControlWord, 0x037f).unwrap();
4200 emu.set_varnode_u128(A, 0x7fff_8000_0000_0000_0001).unwrap();
4203 emu.set_varnode_u128(B, 0x3fff_8000_0000_0000_0000).unwrap();
4204 emu.run_block().unwrap();
4205 assert_eq!(emu.get_value(equal.into()).unwrap().value().unwrap(), 0);
4206 assert_eq!(emu.read_varnode(FPUStatusWord), None);
4207 }
4208
4209 #[test]
4214 fn float80_partial_remainder_is_exact() {
4215 let dividend = 0x7ffe_ffff_ffff_ffff_ffffu128;
4216 let one = 0x3fff_8000_0000_0000_0000u128;
4217 for ieee in [false, true] {
4218 let result = float80::remainder(dividend, one, ieee);
4219 assert!(result.incomplete);
4220 assert_eq!(result.bits, 0);
4221 }
4222
4223 let half = 0x3ffe_8000_0000_0000_0000u128;
4227 let result = float80::remainder(dividend, half, false);
4228 assert!(result.incomplete);
4229 assert_eq!(result.bits, 0x7fdd_ffff_fffe_0000_0000);
4230
4231 let three = 0x4000_c000_0000_0000_0000u128;
4234 let result = float80::remainder(three, one, false);
4235 assert!(!result.incomplete);
4236 assert_eq!(result.bits, 0);
4237 assert_eq!(result.quotient & 7, 3);
4238 }
4239
4240 #[test]
4243 fn float80_sqrt_is_correctly_rounded_at_extended_precision() {
4244 let two = 0x4000_8000_0000_0000_0000;
4245 let four = 0x4001_8000_0000_0000_0000;
4246 let one = 0x3fff_8000_0000_0000_0000;
4247
4248 let root_two = float80::sqrt_ieee(two, Round::NearestTiesToEven);
4250 assert_eq!(root_two.bits, 0x3fff_b504_f333_f9de_6484);
4251 assert!(root_two.status.contains(Status::INEXACT));
4252
4253 for (input, expect) in [(four, two), (one, one), (0, 0)] {
4255 let result = float80::sqrt_ieee(input, Round::NearestTiesToEven);
4256 assert_eq!(result.bits, expect);
4257 assert_eq!(result.status, Status::OK);
4258 }
4259
4260 let three = 0x4000_c000_0000_0000_0000;
4263 assert_eq!(
4264 float80::sqrt_ieee(three, Round::NearestTiesToEven).bits,
4265 0x3fff_ddb3_d742_c265_539e
4266 );
4267 assert_eq!(
4268 float80::sqrt_ieee(three, Round::TowardZero).bits,
4269 0x3fff_ddb3_d742_c265_539d
4270 );
4271
4272 let negative = float80::sqrt_ieee(0xbfff_8000_0000_0000_0000, Round::NearestTiesToEven);
4275 assert_eq!(negative.bits, 0xbfff_8000_0000_0000_0000);
4276 assert!(negative.status.contains(Status::INVALID_OP));
4277 }
4278
4279 #[test]
4280 fn float80_arithmetic_preserves_extended_precision_bits() {
4281 let one = SizedValue::from_bits(0x3fff_8000_0000_0000_0000, 10);
4285 let two = SizedValue::from_bits(0x4000_8000_0000_0000_0000, 10);
4286 let three = one.float_add(&two).unwrap();
4287
4288 assert_eq!(three.as_bits(), 0x4000_c000_0000_0000_0000);
4289 assert_eq!(three.size().unwrap(), 10);
4290 assert_eq!(two.float_to_float(10).unwrap().as_bits(), two.as_bits());
4291 assert_eq!(
4292 SizedValue::new(3, 1).int_to_float(10).unwrap().as_bits(),
4293 three.as_bits()
4294 );
4295 }
4296
4297 #[test]
4298 fn explicit_ieee_arithmetic_pairs_results_and_flags_in_every_rounding_mode() {
4299 let cases = [
4304 (
4305 4,
4306 0x3f80_0000,
4307 0x3380_0000,
4308 0x3f80_0001,
4309 0x3fc0_0000,
4310 0x3f80_0000,
4311 0x4040_0000,
4312 ),
4313 (
4314 8,
4315 0x3ff0_0000_0000_0000,
4316 0x3ca0_0000_0000_0000,
4317 0x3ff0_0000_0000_0001,
4318 0x3ff8_0000_0000_0000,
4319 0x3ff0_0000_0000_0000,
4320 0x4008_0000_0000_0000,
4321 ),
4322 (
4323 10,
4324 0x3fff_8000_0000_0000_0000,
4325 0x3fbf_8000_0000_0000_0000,
4326 0x3fff_8000_0000_0000_0001,
4327 0x3fff_c000_0000_0000_0000,
4328 0x3fff_8000_0000_0000_0000,
4329 0x4000_c000_0000_0000_0000,
4330 ),
4331 ];
4332 let operations = [
4333 ("float_add", "float_add_flags", 0usize),
4334 ("float_sub", "float_sub_flags", 1),
4335 ("float_mul", "float_mul_flags", 2),
4336 ("float_div", "float_div_flags", 3),
4337 ];
4338
4339 for (size, add_lhs, add_rhs, mul_lhs, mul_rhs, div_lhs, div_rhs) in cases {
4340 let sub_rhs = match size {
4343 4 => 0x3300_0000,
4344 8 => 0x3c90_0000_0000_0000,
4345 10 => 0x3fbe_8000_0000_0000_0000,
4346 _ => unreachable!(),
4347 };
4348 let operands = [
4349 (add_lhs, add_rhs),
4350 (add_lhs, sub_rhs),
4351 (mul_lhs, mul_rhs),
4352 (div_lhs, div_rhs),
4353 ];
4354 for (result_name, flags_name, pair) in operations {
4355 let (lhs, rhs) = operands[pair];
4356 for mode in 0..4 {
4357 let round =
4358 StandaloneEmulator::<EmulatedMemory>::ieee_rounding_mode(mode).unwrap();
4359 let (result, status) = StandaloneEmulator::<EmulatedMemory>::ieee_arithmetic(
4360 SizedValue::from_bits(lhs, size),
4361 SizedValue::from_bits(rhs, size),
4362 round,
4363 result_name,
4364 )
4365 .unwrap();
4366 let (_, flag_status) = StandaloneEmulator::<EmulatedMemory>::ieee_arithmetic(
4367 SizedValue::from_bits(lhs, size),
4368 SizedValue::from_bits(rhs, size),
4369 round,
4370 flags_name,
4371 )
4372 .unwrap();
4373 assert_eq!(
4374 status,
4375 flag_status,
4376 "{result_name}, f{}, mode {mode}",
4377 size * 8
4378 );
4379 let flags = StandaloneEmulator::<EmulatedMemory>::ieee_flags(flag_status);
4380 assert_ne!(
4381 flags.as_bits() & (1 << 5),
4382 0,
4383 "{result_name}, f{}, mode {mode}",
4384 size * 8
4385 );
4386 assert_eq!(result.size as usize, size);
4387 }
4388 }
4389 }
4390 }
4391
4392 #[test]
4393 fn simple_addition() {
4394 let mut ctx = Context::new();
4395
4396 qcode!(
4397 ctx,
4398 "
4399 varnode i64 V0;
4400 varnode i64 V1;
4401
4402 <block>
4403 %v0 = load(V0:8, &V0);
4404 %v1 = load(V1:8, &V1);
4405 %res = %v0 + %v1;
4406 goto <0x1001>;
4407 "
4408 );
4409
4410 let mut emu = Emulator::from_block(&ctx, block);
4411 emu.set_varnode(V0, 2).unwrap();
4412 emu.set_varnode(V1, 3).unwrap();
4413 emu.run_block().unwrap();
4414
4415 assert_eq!(
4416 emu.get_value(res.into()).and_then(|v| v.value()).unwrap(),
4417 5
4418 );
4419 }
4420
4421 #[test]
4422 fn gep_emulates_as_base_plus_offset() {
4423 let mut ctx = Context::new();
4424
4425 qcode!(
4427 ctx,
4428 "
4429 type Inner { _: 8, val: 4 };
4430 varnode i64 V0;
4431
4432 <block>
4433 Inner* %p = load(V0:8, &V0);
4434 %fld = gep(%p.val);
4435 goto <0x1001>;
4436 "
4437 );
4438
4439 let mut emu = Emulator::from_block(&ctx, block);
4440 emu.set_varnode(V0, 0x1000).unwrap();
4441 emu.run_block().unwrap();
4442
4443 let fld = emu.get_value(fld.into()).unwrap();
4444 assert_eq!(fld.value().unwrap(), 0x1008);
4445 assert_eq!(fld.size().unwrap(), 8);
4447 }
4448
4449 #[test]
4450 fn emulator_int_div_works_with_128_bit_operands() {
4451 let mut ctx = Context::new();
4452 qcode!(
4453 ctx,
4454 "
4455 varnode i128 V0;
4456 varnode i128 V1;
4457
4458 <block>
4459 %v0 = load(V0:16, &V0);
4460 %v1 = load(V1:16, &V1);
4461
4462 %res = %v0 / %v1;
4463 goto <0x1001>;
4464 "
4465 );
4466
4467 let mut emu = Emulator::from_block(&ctx, block);
4468 let v0_bits = u128::from(1u8) << 100;
4469 let v1_bits = u128::from(1u8) << 99;
4470
4471 emu.set_varnode_u128(V0, v0_bits).unwrap();
4472 emu.set_varnode_u128(V1, v1_bits).unwrap();
4473 emu.run_block().unwrap();
4474
4475 assert_eq!(
4477 emu.get_value(res.into()).and_then(|v| v.value()).unwrap(),
4478 2
4479 );
4480 }
4481
4482 #[test]
4487 fn uninitialized_memory_reads_error() {
4488 let space = EmulatedSpace::default();
4489 assert!(matches!(
4490 space.read_byte(0xdead_beef),
4491 Err(EmulatorErrorKind::MemoryReadError(0xdead_beef))
4492 ));
4493 assert!(matches!(
4494 space.read(0x1000, 4),
4495 Err(EmulatorErrorKind::MemoryReadError(0x1000))
4496 ));
4497 }
4498
4499 #[test]
4500 fn configured_register_and_body_temporary_spaces_zero_fill_missing_bytes() {
4501 let mut ctx = Context::new();
4502 let mut register = Space::new(Some("register"), 1, 8);
4503 register.ty = SpaceType::Register;
4504 let register = ctx.add_space(register);
4505 let function = ctx.anon_function();
4506 let temporary = MemorySpaceId::Temp(ctx.bodies[function].push_temp_space(TempSpace::new(
4507 Some("scratch"),
4508 1,
4509 8,
4510 )));
4511 let mut memory = EmulatedMemory::default();
4512 memory.configure_spaces(&ctx);
4513
4514 for space in [register.into(), temporary] {
4515 assert_eq!(
4516 memory
4517 .read(space, SizedValue::from_u64(0x1000), 4)
4518 .unwrap()
4519 .value()
4520 .unwrap(),
4521 0
4522 );
4523 }
4524
4525 memory
4526 .write(
4527 ctx.shared.default_space.into(),
4528 SizedValue::from_u64(0x1000),
4529 1,
4530 SizedValue::new(0xaa, 1),
4531 )
4532 .unwrap();
4533 assert!(matches!(
4534 memory.read(
4535 ctx.shared.default_space.into(),
4536 SizedValue::from_u64(0x1001),
4537 1
4538 ),
4539 Err(EmulatorErrorKind::MemoryReadError(0x1001))
4540 ));
4541 }
4542
4543 #[test]
4544 fn temporary_spaces_with_the_same_address_are_isolated() {
4545 use qcode::value::TempSpace;
4546
4547 let mut ctx = Context::new();
4548 let first_fn = FunctionBody::make(&mut ctx, "first".into()).unwrap().id;
4549 let second_fn = FunctionBody::make(&mut ctx, "second".into()).unwrap().id;
4550 let first = ctx.bodies[first_fn].push_temp_space(TempSpace::new(None, 1, 8));
4551 let second = ctx.bodies[second_fn].push_temp_space(TempSpace::new(None, 1, 8));
4552 assert_eq!(first.local, second.local, "fixture must collide local IDs");
4553 let first = MemorySpaceId::Temp(first);
4554 let second = MemorySpaceId::Temp(second);
4555 let mut memory = EmulatedMemory::default();
4556 memory.configure_spaces(&ctx);
4557
4558 let address = SizedValue::from_u64(0x20);
4559 memory
4560 .write(first, address, 1, SizedValue::new(0xaa, 1))
4561 .unwrap();
4562 memory
4563 .write(second, address, 1, SizedValue::new(0x55, 1))
4564 .unwrap();
4565
4566 assert_eq!(
4567 memory.read(first, address, 1).unwrap().value().unwrap(),
4568 0xaa
4569 );
4570 assert_eq!(
4571 memory.read(second, address, 1).unwrap().value().unwrap(),
4572 0x55
4573 );
4574 }
4575
4576 #[test]
4577 fn interpreter_qualifies_colliding_local_spaces_by_function() {
4578 use qcode::value::TempSpace;
4579
4580 fn make_writer(
4581 ctx: &mut Context<'static>,
4582 name: &'static str,
4583 byte: u64,
4584 ) -> (FunctionId, qcode::value::TempSpaceId) {
4585 let fid = FunctionBody::make(ctx, name.into()).unwrap().id;
4586 let root = BasicBlock::make(ctx, fid).id;
4587 FunctionBody::from_id_mut(ctx, fid).set_root(root).unwrap();
4588 let space = ctx.bodies[fid].push_temp_space(TempSpace::new(None, 1, 8));
4589 let mut b = (ctx).builder(root);
4590 let ptr = b.shr().get_const(0x20, 8);
4591 let value = b.shr().get_const(byte, 1);
4592 b.push_store(
4593 value,
4594 ptr,
4595 qcode::space::LocalMemorySpaceId::Temp(space.local),
4596 );
4597 b.push_return(ptr);
4598 (fid, space)
4599 }
4600
4601 let mut ctx = Context::new();
4602 let (first, first_space) = make_writer(&mut ctx, "first", 0xaa);
4603 let (second, second_space) = make_writer(&mut ctx, "second", 0x55);
4604 assert_eq!(first_space.local, second_space.local);
4605
4606 let root = FunctionBody::from_id(&ctx, first).root().unwrap().id;
4607 let mut emulator = StandaloneEmulator::new(root);
4608 emulator.run_function(&ctx, first).unwrap();
4609 emulator.run_function(&ctx, second).unwrap();
4610
4611 let address = SizedValue::from_u64(0x20);
4612 assert_eq!(
4613 emulator
4614 .memory
4615 .read(MemorySpaceId::Temp(first_space), address, 1)
4616 .unwrap()
4617 .value()
4618 .unwrap(),
4619 0xaa
4620 );
4621 assert_eq!(
4622 emulator
4623 .memory
4624 .read(MemorySpaceId::Temp(second_space), address, 1)
4625 .unwrap()
4626 .value()
4627 .unwrap(),
4628 0x55
4629 );
4630 }
4631
4632 #[test]
4633 fn sized_value_byte_swap_preserves_width() {
4634 let value = SizedValue::new(0x1234, 2).byte_swap().unwrap();
4635 assert_eq!(value.value().unwrap(), 0x3412);
4636 assert_eq!(value.size().unwrap(), 2);
4637 }
4638
4639 #[test]
4640 fn swap_bytes_pcode_op_is_emulated() {
4641 let mut ctx = Context::new();
4642 let op = ctx.shared.pcode_ops.push(Box::from("swap_bytes"));
4643 let block_id = {
4644 let __f = ctx.anon_function();
4645 ctx.get_or_make_block(0x1000, __f)
4646 };
4647 let target = ctx.get_or_make_block(0x1001, block_id.func);
4648 let result = {
4649 let src = ctx.get_const(0x1234, 2).id();
4650 let mut builder = ctx.builder(block_id);
4651 let result = builder.push_pcode_op(op, vec![src], None, 2).id;
4652 builder.finalize(target);
4653 result
4654 };
4655 let mut emulator = Emulator::from_block(&ctx, block_id);
4656
4657 emulator.step().unwrap();
4658
4659 assert_eq!(
4660 emulator
4661 .get_value(result.into())
4662 .and_then(|value| value.value())
4663 .unwrap(),
4664 0x3412
4665 );
4666 }
4667
4668 #[test]
4669 fn undef_pcode_op_is_zero_at_its_declared_width() {
4670 let mut ctx = Context::new();
4671 let op = ctx.shared.pcode_ops.push(Box::from("undef"));
4672 let block_id = {
4673 let function = ctx.anon_function();
4674 ctx.get_or_make_block(0x1000, function)
4675 };
4676 let target = ctx.get_or_make_block(0x1001, block_id.func);
4677 let result = {
4678 let mut builder = ctx.builder(block_id);
4679 let result = builder.push_pcode_op(op, vec![], None, 1).id;
4680 builder.finalize(target);
4681 result
4682 };
4683 let mut emulator = Emulator::from_block(&ctx, block_id);
4684
4685 emulator.step().unwrap();
4686
4687 let value = emulator.get_value(result.into()).unwrap();
4688 assert_eq!(value.value().unwrap(), 0);
4689 assert_eq!(value.size().unwrap(), 1);
4690 }
4691
4692 #[test]
4693 fn rol_intrinsic_is_emulated() {
4694 use qcode::value::insn::IntrinsicId;
4695 let mut ctx = Context::new();
4696 let rol = IntrinsicId::from_name("rol").unwrap();
4697 let block_id = {
4698 let __f = ctx.anon_function();
4699 ctx.get_or_make_block(0x1000, __f)
4700 };
4701 let target = ctx.get_or_make_block(0x1001, block_id.func);
4702 let result = {
4703 let x = ctx.get_const(0x1234_5678, 4).id();
4704 let k = ctx.get_const(8, 4).id();
4705 let mut builder = ctx.builder(block_id);
4706 let result = builder.push_intrinsic(rol, vec![x, k]).id;
4707 builder.finalize(target);
4708 result
4709 };
4710 let mut emulator = Emulator::from_block(&ctx, block_id);
4711
4712 emulator.step().unwrap();
4713
4714 assert_eq!(
4715 emulator
4716 .get_value(result.into())
4717 .and_then(|value| value.value())
4718 .unwrap(),
4719 0x1234_5678u32.rotate_left(8) as u64,
4720 );
4721 }
4722
4723 #[test]
4724 fn unknown_pcode_op_returns_typed_error() {
4725 let mut ctx = Context::new();
4726 let op = ctx.shared.pcode_ops.push(Box::from("rdpmc"));
4727 let block_id = {
4728 let __f = ctx.anon_function();
4729 ctx.get_or_make_block(0x1000, __f)
4730 };
4731 let target = ctx.get_or_make_block(0x1001, block_id.func);
4732 {
4733 let mut builder = ctx.builder(block_id);
4734 builder.push_pcode_op(op, vec![], None, 0);
4735 builder.finalize(target);
4736 }
4737 let mut emulator = Emulator::from_block(&ctx, block_id);
4738
4739 let error = emulator.step().unwrap_err();
4740
4741 assert!(matches!(
4742 error.kind,
4743 EmulatorErrorKind::UnsupportedPCodeOp(operation) if operation.as_ref() == "rdpmc"
4744 ));
4745 }
4746
4747 #[test]
4748 fn get_region_overflow_does_not_panic() {
4749 let mut space = EmulatedSpace::default();
4750 assert!(matches!(
4752 space.get_mut_region(u64::MAX - 2, 8),
4753 Err(EmulatorErrorKind::AddressOverflow(_, _))
4754 ));
4755 }
4756
4757 #[test]
4762 fn run_function_returns_ok_for_trivial_function() {
4763 let mut ctx = Context::new();
4764 qcode!(
4765 ctx,
4766 "
4767 fn function:
4768 <entry>
4769 return at i64 0;
4770 "
4771 );
4772
4773 let mut emu = Emulator::from_function(&ctx, function);
4774 assert!(emu.run_function(function).is_ok());
4775 }
4776
4777 #[test]
4778 fn run_function_executes_instructions_before_return() {
4779 let mut ctx = Context::new();
4780 qcode!(
4781 ctx,
4782 "
4783 varnode i64 A;
4784 varnode i64 B;
4785
4786 fn function:
4787 <entry>
4788 %a = load(A:8, &A);
4789 %b = load(B:8, &B);
4790 %sum = %a + %b;
4791 return at i64 0;
4792 "
4793 );
4794
4795 let mut emu = Emulator::from_function(&ctx, function);
4796 emu.set_varnode(A, 7).unwrap();
4797 emu.set_varnode(B, 5).unwrap();
4798 emu.run_function(function).unwrap();
4799
4800 assert_eq!(
4801 emu.get_value(sum.into()).and_then(|v| v.value()).unwrap(),
4802 12
4803 );
4804 }
4805
4806 #[test]
4807 fn run_function_call_stack_empty_after_successful_return() {
4808 let mut ctx = Context::new();
4809
4810 qcode!(
4811 ctx,
4812 "
4813 varnode i64 A;
4814 varnode i64 B;
4815
4816 fn function:
4817 <entry>
4818 %a = load(A:8, &A);
4819 %b = load(B:8, &B);
4820 %sum = %a + %b;
4821 return at i64 0;
4822 "
4823 );
4824
4825 let mut emu = Emulator::from_function(&ctx, function);
4826 emu.set_varnode(A, 0).unwrap();
4827 emu.set_varnode(B, 0).unwrap();
4828 emu.run_function(function).unwrap();
4829
4830 assert!(emu.call_stack().is_empty());
4831 }
4832
4833 #[test]
4834 fn unhandled_direct_call_still_enters_callee() {
4835 let mut ctx = Context::new();
4836 qcode!(
4837 ctx,
4838 "
4839 fn callee:
4840 <callee_entry>
4841 return at i64 0;
4842
4843 <caller>
4844 call <callee>;
4845 "
4846 );
4847
4848 let mut emu = Emulator::from_block(&ctx, caller);
4849 emu.step().unwrap();
4850
4851 assert_eq!(emu.block().id, callee_entry);
4852 }
4853
4854 #[test]
4855 fn handled_direct_call_resumes_at_selected_block() {
4856 let mut ctx = Context::new();
4857 qcode!(
4858 ctx,
4859 "
4860 varnode i64 RET;
4861
4862 fn library:
4863 <library_entry>
4864 return at i64 0;
4865
4866 fn function:
4867 <entry>
4868 call <library>;
4869 <after_call>
4870 %ret = load(RET:8, &RET);
4871 return at i64 0;
4872 "
4873 );
4874
4875 let mut emu = Emulator::from_function(&ctx, function);
4876 emu.set_call_interceptor(move |ctx, emu, site| {
4877 if site.target == library {
4878 emu.set_varnode(ctx, RET, 42)
4879 .map_err(|err| err.to_string().into_boxed_str())?;
4880 Ok(CallInterception::Handled(CallContinuation::Block(
4881 after_call,
4882 )))
4883 } else {
4884 Ok(CallInterception::PassThrough)
4885 }
4886 });
4887
4888 emu.run_function(function).unwrap();
4889
4890 assert_eq!(
4891 emu.get_value(ret.into()).and_then(|v| v.value()).unwrap(),
4892 42
4893 );
4894 assert!(emu.call_stack().is_empty());
4895 }
4896
4897 #[test]
4898 fn handled_direct_call_can_resume_by_address() {
4899 let mut ctx = Context::new();
4900 qcode!(
4901 ctx,
4902 "
4903 fn library:
4904 <library_entry>
4905 return at i64 0;
4906
4907 <entry>
4908 call <library>;
4909 <0x2000>
4910 return at i64 0;
4911 "
4912 );
4913
4914 let mut emu = Emulator::from_block(&ctx, entry);
4915 emu.set_call_interceptor(move |_, _, site| {
4916 if site.target == library {
4917 Ok(CallInterception::Handled(CallContinuation::Address(0x2000)))
4918 } else {
4919 Ok(CallInterception::PassThrough)
4920 }
4921 });
4922
4923 emu.step().unwrap();
4924
4925 assert_eq!(emu.block().address(), Some(0x2000));
4926 }
4927
4928 #[test]
4929 fn handled_direct_call_reports_unknown_continuation_address() {
4930 let mut ctx = Context::new();
4931 qcode!(
4932 ctx,
4933 "
4934 fn library:
4935 <library_entry>
4936 return at i64 0;
4937
4938 <entry>
4939 call <library>;
4940 "
4941 );
4942
4943 let mut emu = Emulator::from_block(&ctx, entry);
4944 emu.set_call_interceptor(move |_, _, site| {
4945 if site.target == library {
4946 Ok(CallInterception::Handled(CallContinuation::Address(0xdead)))
4947 } else {
4948 Ok(CallInterception::PassThrough)
4949 }
4950 });
4951
4952 let err = emu.step().unwrap_err();
4953
4954 assert!(matches!(
4955 err.kind,
4956 EmulatorErrorKind::InvalidBlockAddress(0xdead)
4957 ));
4958 }
4959
4960 #[test]
4961 fn call_interceptor_errors_are_reported_at_call_site() {
4962 let mut ctx = Context::new();
4963 qcode!(
4964 ctx,
4965 "
4966 fn library:
4967 <library_entry>
4968 return at i64 0;
4969
4970 <entry>
4971 call <library>;
4972 "
4973 );
4974
4975 let mut emu = Emulator::from_block(&ctx, entry);
4976 emu.set_call_interceptor(|_, _, _| Err("model failed".into()));
4977
4978 let err = emu.step().unwrap_err();
4979
4980 assert!(matches!(
4981 err.kind,
4982 EmulatorErrorKind::InterceptError(message) if message.as_ref() == "model failed"
4983 ));
4984 assert!(err.ctx.contains("call fn library();"));
4985 }
4986
4987 #[test]
4988 fn interceptor_can_model_state_across_calls() {
4989 let mut ctx = Context::new();
4990 qcode!(
4991 ctx,
4992 "
4993 fn make_object:
4994 <make_object_entry>
4995 return at i64 0;
4996
4997 fn append_byte:
4998 <append_byte_entry>
4999 return at i64 0;
5000
5001 fn function:
5002 <entry>
5003 call <make_object>;
5004 <append>
5005 call <append_byte>;
5006 <done>
5007 return at i64 0;
5008 "
5009 );
5010
5011 let modeled = Arc::new(Mutex::new(Vec::<u8>::new()));
5012 let modeled_for_hook = Arc::clone(&modeled);
5013 let mut emu = Emulator::from_function(&ctx, function);
5014 emu.set_call_interceptor(move |_, _, site| {
5015 let mut model = modeled_for_hook.lock().unwrap();
5016 if site.target == make_object {
5017 model.clear();
5018 Ok(CallInterception::Handled(CallContinuation::Block(append)))
5019 } else if site.target == append_byte {
5020 model.push(0x41);
5021 Ok(CallInterception::Handled(CallContinuation::Block(done)))
5022 } else {
5023 Ok(CallInterception::PassThrough)
5024 }
5025 });
5026
5027 emu.run_function(function).unwrap();
5028
5029 assert_eq!(*modeled.lock().unwrap(), vec![0x41]);
5030 }
5031
5032 #[test]
5037 fn branchind_to_unknown_address_returns_error() {
5038 let mut ctx = Context::new();
5039 qcode!(
5040 ctx,
5041 "
5042 fn function:
5043 <entry>
5044 # Branching to literal 0 — no block lives at address 0
5045 goto [i64 0];
5046 "
5047 );
5048
5049 let mut emu = Emulator::from_function(&ctx, function);
5050 let err = emu.run_function(function).unwrap_err();
5051 assert!(matches!(
5052 err.kind,
5053 EmulatorErrorKind::InvalidBlockAddress(0)
5054 ));
5055 }
5056
5057 #[test]
5058 fn error_includes_faulting_instruction_id() {
5059 let mut ctx = Context::new();
5060 qcode!(
5061 ctx,
5062 "
5063 fn function:
5064 <entry>
5065 # Null pointer dereference
5066 %bad_load = load(ram:8, i64 0);
5067 return at i64 0;
5068 "
5069 );
5070
5071 let mut emu = Emulator::from_function(&ctx, function);
5072 let err = emu.run_function(function).unwrap_err();
5073
5074 assert!(
5075 err.ctx.contains(
5076 &Instruction::from_id(&ctx, bad_load)
5077 .as_statement()
5078 .to_string()
5079 )
5080 );
5081 }
5082
5083 #[test]
5084 fn error_call_stack_reflects_active_frames_at_fault() {
5085 let mut ctx = Context::new();
5087 qcode!(
5088 ctx,
5089 "
5090 fn callee:
5091 <entry1>
5092 # Branching to literal 0 — no block lives at address 0
5093 goto [i64 0];
5094
5095 fn caller:
5096 <entry2>
5097 call <callee>;
5098 "
5099 );
5100
5101 let mut emu = Emulator::from_function(&ctx, caller);
5103 let err = emu.run_function(caller).unwrap_err();
5104
5105 assert!(matches!(
5106 err.kind,
5107 EmulatorErrorKind::InvalidBlockAddress(0)
5108 ));
5109 assert_eq!(emu.call_stack(), &[caller, callee]);
5110 }
5111}