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 let mut loses_info = false;
1617 macro_rules! to {
1618 ($source:expr, $target:ty, $bytes:expr) => {{
1619 let converted: rustc_apfloat::StatusAnd<$target> =
1620 $source.convert_r(round, &mut loses_info);
1621 Some((
1622 SizedValue::from_bits(converted.value.to_bits(), $bytes),
1623 converted.status,
1624 ))
1625 }};
1626 }
1627 match (value.size, size) {
1628 (8, 4) => to!(Double::from_bits(value.as_bits()), Single, 4),
1629 (10, 4) => to!(X87DoubleExtended::from_bits(value.as_bits()), Single, 4),
1630 (10, 8) => to!(X87DoubleExtended::from_bits(value.as_bits()), Double, 8),
1631 _ => None,
1632 }
1633 }
1634
1635 fn is_signaling_nan(value: SizedValue) -> bool {
1642 let bits = value.as_bits();
1643 match value.size {
1644 4 => Single::from_bits(bits).is_signaling(),
1645 8 => Double::from_bits(bits).is_signaling(),
1646 10 => X87DoubleExtended::from_bits(bits).is_signaling(),
1647 _ => false,
1648 }
1649 }
1650
1651 fn widen_to_f80(value: SizedValue) -> Option<X87DoubleExtended> {
1652 let mut loses_info = false;
1653 match value.size {
1654 4 => Some(
1655 Single::from_bits(value.as_bits())
1656 .convert_r(Round::NearestTiesToEven, &mut loses_info)
1657 .value,
1658 ),
1659 8 => Some(
1660 Double::from_bits(value.as_bits())
1661 .convert_r(Round::NearestTiesToEven, &mut loses_info)
1662 .value,
1663 ),
1664 10 => Some(X87DoubleExtended::from_bits(value.as_bits())),
1665 _ => None,
1666 }
1667 }
1668
1669 fn narrow_with_sticky(
1675 bits: u128,
1676 inexact: bool,
1677 size: u8,
1678 round: Round,
1679 ) -> Option<(SizedValue, Status)> {
1680 if size == 10 {
1681 return Some((
1682 SizedValue::from_bits(bits, 10),
1683 if inexact { Status::INEXACT } else { Status::OK },
1684 ));
1685 }
1686 let sticky = if inexact { bits | 1 } else { bits };
1687 let (mut result, mut status) =
1688 Self::ieee_narrow(SizedValue::from_bits(sticky, 10), u128::from(size), round)?;
1689 if inexact {
1690 status |= Status::INEXACT;
1691 }
1692 result = SizedValue::from_bits(result.as_bits(), size as usize);
1693 Some((result, status))
1694 }
1695
1696 fn ieee_to_int(value: SizedValue, size: u128, round: Round) -> Option<(SizedValue, Status)> {
1701 let signaling = Self::is_signaling_nan(value);
1704 let value = SizedValue::from_bits(Self::widen_to_f80(value)?.to_bits(), 10);
1705 let size = usize::try_from(size).ok()?;
1706 if !matches!(size, 2 | 4 | 8) {
1707 return None;
1708 }
1709 let mut exact = false;
1710 let converted =
1711 X87DoubleExtended::from_bits(value.as_bits()).to_i128_r(size * 8, round, &mut exact);
1712 let mask = (1u128 << (size * 8)) - 1;
1713 let mut status = converted.status;
1714 if signaling {
1715 status |= Status::INVALID_OP;
1716 }
1717 Some((
1718 SizedValue::from_bits(converted.value as u128 & mask, size),
1719 status,
1720 ))
1721 }
1722
1723 fn ieee_from_int(value: SizedValue, size: u128, round: Round) -> Option<(SizedValue, Status)> {
1728 let source = value.signed_value();
1729 let width = usize::from(value.size) * 8;
1730 match size {
1731 4 => {
1732 let converted = Single::from_i128_r(source, round);
1733 Some((
1734 SizedValue::from_bits(converted.value.to_bits(), 4),
1735 converted.status,
1736 ))
1737 }
1738 8 => {
1739 let converted = Double::from_i128_r(source, round);
1740 Some((
1741 SizedValue::from_bits(converted.value.to_bits(), 8),
1742 converted.status,
1743 ))
1744 }
1745 10 => {
1746 let converted = X87DoubleExtended::from_i128_r(source, round);
1747 Some((
1748 SizedValue::from_bits(converted.value.to_bits(), 10),
1749 converted.status,
1750 ))
1751 }
1752 _ => {
1753 let _ = width;
1754 None
1755 }
1756 }
1757 }
1758
1759 fn ieee_flags(status: Status) -> SizedValue {
1760 let mut flags = 0u128;
1761 if status.contains(Status::INVALID_OP) {
1762 flags |= 1;
1763 }
1764 if status.contains(Status::DIV_BY_ZERO) {
1765 flags |= 1 << 2;
1766 }
1767 if status.contains(Status::OVERFLOW) {
1768 flags |= 1 << 3;
1769 }
1770 if status.contains(Status::UNDERFLOW) {
1771 flags |= 1 << 4;
1772 }
1773 if status.contains(Status::INEXACT) {
1774 flags |= 1 << 5;
1775 }
1776 SizedValue::from_bits(flags, 1)
1777 }
1778
1779 fn interpret_packed_pcode_op(
1787 &mut self,
1788 ctx: &Context<'_>,
1789 insn: &InstructionRef<'_, '_>,
1790 mnemonic: &Mnemonic,
1791 ) -> Result<Option<SizedValue>, EmulatorErrorKind> {
1792 let Mnemonic::PCodeOp(op) = mnemonic else {
1793 return Ok(None);
1794 };
1795 let name = ctx.shared.pcode_ops[op.id].clone();
1796 let func = insn.id.func;
1797
1798 if let [src] = op.args.as_slice() {
1801 let value = self.scalar_value(ctx, src.qualify(func))?;
1802 if value.size != 10 {
1803 return Ok(None);
1804 }
1805 return Ok(match name.as_ref() {
1806 "extract_significand" => Some(SizedValue::from_f80_bits(
1807 float80::extract_significand(value.as_bits()),
1808 )),
1809 "extract_exponent" => Some(SizedValue::from_f80_bits(
1810 float80::extract_exponent(value.as_bits()).bits,
1811 )),
1812 _ => None,
1813 });
1814 }
1815
1816 if let [lhs, rhs, rounding_mode] = op.args.as_slice() {
1819 let lhs = self.scalar_value(ctx, lhs.qualify(func))?;
1820 let rhs = self.scalar_value(ctx, rhs.qualify(func))?;
1821 let rounding_mode = self.scalar_value(ctx, rounding_mode.qualify(func))?;
1822
1823 if matches!(name.as_ref(), "float_rem_partial" | "float_rem_quotient")
1828 && lhs.size == 10
1829 && rhs.size == 10
1830 {
1831 let to_nearest = rounding_mode.as_bits() != 0;
1832 let result = float80::remainder(lhs.as_bits(), rhs.as_bits(), to_nearest);
1833 return Ok(Some(if name.as_ref() == "float_rem_quotient" {
1834 let code = if result.incomplete {
1839 8
1840 } else {
1841 u128::from(result.quotient & 7)
1842 };
1843 SizedValue::from_bits(code, 1)
1844 } else {
1845 SizedValue::from_f80_bits(result.bits)
1846 }));
1847 }
1848
1849 let Some(round) = Self::ieee_rounding_mode(rounding_mode.as_bits()) else {
1850 return Ok(None);
1851 };
1852 let evaluated = match name.as_ref() {
1853 "float_round_to_precision" | "float_round_to_precision_flags" => {
1854 Self::ieee_round_to_precision(lhs, rhs.as_bits(), round)
1855 }
1856 "float_narrow" | "float_narrow_flags" => {
1857 Self::ieee_narrow(lhs, rhs.as_bits(), round)
1858 }
1859 "float_to_int" | "float_to_int_flags" => {
1860 Self::ieee_to_int(lhs, rhs.as_bits(), round)
1861 }
1862 "float_scalb" | "float_scalb_flags" if lhs.size == 10 => {
1863 let steps = i32::try_from(rhs.as_bits() as i64).unwrap_or(
1864 if (rhs.as_bits() as i64) < 0 {
1865 i32::MIN
1866 } else {
1867 i32::MAX
1868 },
1869 );
1870 let result = float80::scalb_ieee(lhs.as_bits(), steps, round);
1871 Some((SizedValue::from_f80_bits(result.bits), result.status))
1872 }
1873 "float_from_int" | "float_from_int_flags" => {
1874 Self::ieee_from_int(lhs, rhs.as_bits(), round)
1875 }
1876 _ => Self::ieee_arithmetic(lhs, rhs, round, name.as_ref()),
1877 };
1878 if let Some((result, status)) = evaluated {
1879 return Ok(Some(if name.ends_with("_flags") {
1880 Self::ieee_flags(status)
1881 } else {
1882 result
1883 }));
1884 }
1885 return Ok(None);
1886 }
1887
1888 let [lhs, rhs] = op.args.as_slice() else {
1889 return Ok(None);
1890 };
1891 let lhs = self.scalar_value(ctx, lhs.qualify(func))?;
1892 let rhs = self.scalar_value(ctx, rhs.qualify(func))?;
1893
1894 if let (true, Some(round)) = (
1898 matches!(lhs.size, 4 | 8 | 10),
1899 Self::ieee_rounding_mode(rhs.as_bits()),
1900 ) {
1901 let extended_only = matches!(
1906 name.as_ref(),
1907 "float_log2" | "float_log2_flags" | "to_bcd" | "to_bcd_flags"
1908 );
1909 let wide = (!extended_only || lhs.size == 10)
1910 .then(|| Self::widen_to_f80(lhs))
1911 .flatten();
1912 let unary = wide.and_then(|wide| {
1913 let wide = wide.to_bits();
1914 let inner = if lhs.size == 10 {
1919 round
1920 } else {
1921 Round::TowardZero
1922 };
1923 Some(match name.as_ref() {
1924 "float_sqrt" | "float_sqrt_flags" => float80::sqrt_ieee(wide, inner),
1925 "float_round_to_integral" | "float_round_to_integral_flags" => {
1926 float80::round_to_integral_ieee(wide, round)
1927 }
1928 "float_log2" | "float_log2_flags" => float80::log2_ieee(wide),
1929 "to_bcd" | "to_bcd_flags" => float80::to_bcd(wide, round),
1930 _ => return None,
1931 })
1932 });
1933 if let Some(result) = unary {
1934 if name.starts_with("to_bcd") {
1935 return Ok(Some(if name.ends_with("_flags") {
1936 Self::ieee_flags(result.status)
1937 } else {
1938 SizedValue::from_bits(result.bits, 10)
1940 }));
1941 }
1942 let mut result = result;
1945 if Self::is_signaling_nan(lhs) {
1946 result.status |= Status::INVALID_OP;
1947 }
1948 let inexact = result.status.contains(Status::INEXACT);
1949 let (value, status) =
1950 match Self::narrow_with_sticky(result.bits, inexact, lhs.size, round) {
1951 Some((value, status)) => {
1952 (value, status | (result.status & !Status::INEXACT))
1953 }
1954 None => (
1955 SizedValue::from_bits(result.bits, lhs.size as usize),
1956 result.status,
1957 ),
1958 };
1959 return Ok(Some(if name.ends_with("_flags") {
1960 Self::ieee_flags(status)
1961 } else {
1962 value
1963 }));
1964 }
1965 }
1966
1967 let average = |width: usize| -> Option<SizedValue> {
1970 (lhs.size as usize == width && rhs.size as usize == width).then(|| {
1971 let sum = lhs.as_bits() + rhs.as_bits() + 1;
1972 SizedValue::from_bits(sum >> 1, width)
1973 })
1974 };
1975
1976 let value = match name.as_ref() {
1977 "pavgb" => average(1),
1978 "pavgw" => average(2),
1979 "pmulhuw" => Self::packed_lanes(&lhs, &rhs, 2, |a, b| ((a * b) >> 16) & 0xffff),
1981 "paddsb" => Self::saturating(&lhs, &rhs, 1, true, false),
1984 "paddsw" => Self::saturating(&lhs, &rhs, 2, true, false),
1985 "psubsb" => Self::saturating(&lhs, &rhs, 1, true, true),
1986 "psubsw" => Self::saturating(&lhs, &rhs, 2, true, true),
1987 "paddusb" => Self::saturating(&lhs, &rhs, 1, false, false),
1988 "paddusw" => Self::saturating(&lhs, &rhs, 2, false, false),
1989 "psubusb" => Self::saturating(&lhs, &rhs, 1, false, true),
1990 "psubusw" => Self::saturating(&lhs, &rhs, 2, false, true),
1991 "pmaddwd" => Self::packed_lanes(&lhs, &rhs, 4, |a, b| {
1993 let word =
1994 |v: u128, half: u32| i64::from(((v >> (half * 16)) & 0xffff) as u16 as i16);
1995 let product = word(a, 0) * word(b, 0) + word(a, 1) * word(b, 1);
1996 u128::from(product as u32)
1997 }),
1998 _ => None,
1999 };
2000 Ok(value)
2001 }
2002
2003 fn saturating(
2006 lhs: &SizedValue,
2007 rhs: &SizedValue,
2008 width: usize,
2009 signed: bool,
2010 subtract: bool,
2011 ) -> Option<SizedValue> {
2012 let bits = width * 8;
2013 Self::packed_lanes(lhs, rhs, width, |a, b| {
2014 if signed {
2015 let sign =
2016 |v: u128| (v as i128) - (((v >> (bits - 1)) & 1) as i128) * (1i128 << bits);
2017 let (a, b) = (sign(a), sign(b));
2018 let value = if subtract { a - b } else { a + b };
2019 let max = (1i128 << (bits - 1)) - 1;
2020 let min = -(1i128 << (bits - 1));
2021 (value.clamp(min, max) as u128) & ((1u128 << bits) - 1)
2022 } else if subtract {
2023 a.saturating_sub(b)
2024 } else {
2025 (a + b).min((1u128 << bits) - 1)
2026 }
2027 })
2028 }
2029
2030 fn packed_lanes(
2034 lhs: &SizedValue,
2035 rhs: &SizedValue,
2036 width: usize,
2037 lane: impl Fn(u128, u128) -> u128,
2038 ) -> Option<SizedValue> {
2039 let size = lhs.size as usize;
2040 if size != rhs.size as usize || size == 0 || !size.is_multiple_of(width) {
2041 return None;
2042 }
2043 let bits = width * 8;
2044 let mask = (1u128 << bits) - 1;
2045 let mut out = 0u128;
2046 for index in 0..size / width {
2047 let shift = index * bits;
2048 let a = (lhs.as_bits() >> shift) & mask;
2049 let b = (rhs.as_bits() >> shift) & mask;
2050 out |= (lane(a, b) & mask) << shift;
2051 }
2052 Some(SizedValue::from_bits(out, size))
2053 }
2054
2055 fn step_with_event(&mut self, ctx: &Context<'_>) -> crate::Result<StepEvent> {
2056 self.memory.configure_spaces(ctx);
2057 let block_id = self.block;
2058 if self.cached_block != Some(block_id) || self.idx == 0 {
2059 self.refresh_sequence_types(ctx);
2063 self.cached_insns.clear();
2064 self.cached_insns
2065 .extend_from_slice(ctx.block(block_id).instruction_ids());
2066 self.cached_block = Some(block_id);
2067 }
2068 let Some(&local) = self.cached_insns.get(self.idx) else {
2073 return Err(self.make_empty_block_error(ctx));
2074 };
2075 let insn_id = InstructionId::new(block_id.func, local);
2076 let insn = InstructionRef::from_id(ctx, insn_id);
2077 let id = insn.id;
2078
2079 if let Some(hook) = self.instruction_hook.as_ref() {
2080 hook(&insn, self)
2081 }
2082
2083 let mnemonic = insn.mnemonic();
2087
2088 match mnemonic {
2089 Mnemonic::Branch(Branch { target, args }) => {
2090 let target = BlockId::new(id.func, *target);
2093 self.bind_block_args(ctx, id.func, target, args)
2094 .map_err(|kind| self.make_error(ctx, kind))?;
2095 self.block = target;
2096 self.idx = 0;
2097 }
2098
2099 Mnemonic::Call(call) => {
2100 if let Some(event) = self.intercept_call(ctx, block_id, insn_id, call)? {
2101 return Ok(event);
2102 }
2103 let target =
2104 require_real_callee(call.target).map_err(|kind| self.make_error(ctx, kind))?;
2105 self.block = FunctionBody::from_id(ctx, target)
2106 .root()
2107 .ok_or_else(|| {
2108 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
2109 })?
2110 .id;
2111 self.idx = 0;
2112 self.call_site_stack.push(insn_id);
2115 return Ok(StepEvent::DirectCallEntered(target));
2116 }
2117
2118 Mnemonic::TailCall(tc) => {
2119 let target =
2124 require_real_callee(tc.target).map_err(|kind| self.make_error(ctx, kind))?;
2125 self.block = FunctionBody::from_id(ctx, target)
2126 .root()
2127 .ok_or_else(|| {
2128 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
2129 })?
2130 .id;
2131 self.idx = 0;
2132 }
2133
2134 Mnemonic::Apply(apply) => {
2135 const APPLY_STEP_BUDGET: usize = 100_000;
2136 let target =
2137 require_real_callee(apply.target).map_err(|kind| self.make_error(ctx, kind))?;
2138 let args = self
2139 .collect_block_args(ctx, id.func, &apply.args)
2140 .map_err(|kind| self.make_error(ctx, kind))?;
2141 let root = FunctionBody::from_id(ctx, target)
2142 .root()
2143 .ok_or_else(|| {
2144 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
2145 })?
2146 .id;
2147 let mut nested = StandaloneEmulator::<M>::new_in(root);
2148 nested
2149 .run_pure(ctx, target, &args, APPLY_STEP_BUDGET)
2150 .map_err(|e| self.make_error(ctx, e.kind))?;
2151 let ret_value = lambda_return_value(ctx, nested.current_block())
2152 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2153 if let Some(value) = nested.get_value(ctx, ret_value) {
2154 let size = ctx
2155 .stored_type_of(ret_value)
2156 .map(|ty| ctx.shared.types.size_of(ty))
2157 .unwrap_or(8);
2158 self.insn_values
2159 .insert(insn_id, SizedValue::new(value, size));
2160 } else if let ValueId::Instruction(ret_id) = ret_value
2161 && let Some(agg) = nested.aggregate_values.get(&ret_id).cloned()
2162 {
2163 self.aggregate_values.insert(insn_id, agg);
2168 }
2169 self.idx += 1;
2170 }
2171
2172 Mnemonic::CBranch(CBranch {
2173 condition,
2174 success_block: target,
2175 success_args,
2176 failure_block: fallthrough,
2177 failure_args,
2178 }) => {
2179 let cond_val = self.get_value(ctx, condition.qualify(id.func)).unwrap();
2180 let target = BlockId::new(id.func, *target);
2181 let fallthrough = BlockId::new(id.func, *fallthrough);
2182 if cond_val != 0 {
2183 self.bind_block_args(ctx, id.func, target, success_args)
2184 .map_err(|kind| self.make_error(ctx, kind))?;
2185 self.block = target;
2186 } else {
2187 self.bind_block_args(ctx, id.func, fallthrough, failure_args)
2188 .map_err(|kind| self.make_error(ctx, kind))?;
2189 self.block = fallthrough;
2190 }
2191 self.idx = 0;
2192 }
2193
2194 Mnemonic::Switch(switch) => {
2195 let value = self
2196 .get_value(ctx, switch.scrutinee.qualify(id.func))
2197 .unwrap();
2198 let arm = switch
2199 .cases
2200 .iter()
2201 .find(|case| case.value == value)
2202 .map(|case| (case.target, &case.args));
2203 let (target, args) = match arm
2204 .or_else(|| switch.default.map(|target| (target, &switch.default_args)))
2205 {
2206 Some(arm) => arm,
2207 None => {
2211 return Err(
2212 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(value))
2213 );
2214 }
2215 };
2216 let target = BlockId::new(id.func, target);
2217 self.bind_block_args(ctx, id.func, target, args)
2218 .map_err(|kind| self.make_error(ctx, kind))?;
2219 self.block = target;
2220 self.idx = 0;
2221 }
2222
2223 Mnemonic::BranchInd(BranchInd { ptr }) => {
2224 let addr = self.get_value(ctx, ptr.qualify(id.func)).unwrap();
2225 let target = self.block_at(ctx, addr).ok_or_else(|| {
2226 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(addr))
2227 })?;
2228 self.block = target;
2229 self.idx = 0;
2230 }
2231
2232 Mnemonic::CallInd(CallInd { ptr, .. }) => {
2233 let addr = self.get_value(ctx, ptr.qualify(id.func)).unwrap();
2234 let target = self.block_at(ctx, addr).ok_or_else(|| {
2235 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(addr))
2236 })?;
2237 self.block = target;
2238 self.idx = 0;
2239 self.call_site_stack.push(insn_id);
2240 return Ok(StepEvent::IndirectCallEntered);
2241 }
2242
2243 Mnemonic::Return(Return { ptr, value, .. }) => {
2244 if let Some(call_id) = self.call_site_stack.pop() {
2249 if let Some(LocalValueId::Instruction(src_local)) = value {
2250 let src = InstructionId::new(id.func, *src_local);
2251 if let Some(agg) = self.aggregate_values.get(&src).cloned() {
2252 self.aggregate_values.insert(call_id, agg);
2253 } else if let Some(scalar) = self.insn_values.get(&src).copied() {
2254 self.insn_values.insert(call_id, scalar);
2255 }
2256 }
2257 self.writeback_materialized_outputs(ctx, call_id, id.func);
2263 }
2264
2265 let addr = self.get_value(ctx, ptr.qualify(id.func)).unwrap();
2266 let target = self.block_at(ctx, addr).ok_or_else(|| {
2267 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(addr))
2268 })?;
2269 self.block = target;
2270 self.idx = 0;
2271 return Ok(StepEvent::Return);
2272 }
2273
2274 Mnemonic::ReturnValue(_) => {
2275 return Ok(StepEvent::ReturnValue);
2276 }
2277
2278 Mnemonic::Tuple(Tuple { fields }) => {
2282 let fields = fields.clone();
2283 let mut vals: Vec<SizedValue> = Vec::with_capacity(fields.len());
2284 for f in fields {
2285 let val = {
2286 let mut tmp = TempInterpreter {
2287 memory: &mut self.memory,
2288 literals: &mut self.literal_cache,
2289 insn_values: &mut self.insn_values,
2290 block_param_values: &mut self.block_param_values,
2291 poison_params: &self.poison_params,
2292 ctx,
2293 };
2294 tmp.get_value(f.qualify(id.func))
2295 };
2296 vals.push(val.map_err(|kind| self.make_error(ctx, kind))?);
2297 }
2298 self.aggregate_values.insert(insn_id, vals);
2299 self.idx += 1;
2300 }
2301
2302 Mnemonic::Extract(Extract { agg, index }) => {
2304 let field = match agg {
2305 LocalValueId::Instruction(agg_local) => self
2306 .aggregate_values
2307 .get(&InstructionId::new(id.func, *agg_local))
2308 .and_then(|v| v.get(*index))
2309 .copied(),
2310 LocalValueId::BlockParam(pid_local) => self
2313 .block_param_aggregates
2314 .get(&BlockParamId::new(id.func, *pid_local))
2315 .and_then(|v| v.get(*index))
2316 .copied(),
2317 _ => None,
2318 };
2319 if let Some(field) = field {
2320 self.insn_values.insert(insn_id, field);
2321 }
2322 self.idx += 1;
2323 }
2324
2325 Mnemonic::Load(load) if self.is_array_operand(ctx, ValueId::Instruction(insn_id)) => {
2330 let (space, ptr, size) = (load.space, load.ptr.qualify(id.func), load.size);
2331 let addr = self
2332 .get_value(ctx, ptr)
2333 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2334 let buf = self
2335 .read_memory(ctx, space.qualify(id.func), addr, size)
2336 .map_err(|kind| self.make_error(ctx, kind))?;
2337 self.array_values.insert(insn_id, buf);
2338 self.idx += 1;
2339 }
2340
2341 Mnemonic::Store(store)
2345 if self
2346 .register_range_store_address(ctx, id.func, store)
2347 .is_some() =>
2348 {
2349 let address = self
2350 .register_range_store_address(ctx, id.func, store)
2351 .expect("guard checked register range store address");
2352 let mut tmp = TempInterpreter {
2353 memory: &mut self.memory,
2354 literals: &mut self.literal_cache,
2355 insn_values: &mut self.insn_values,
2356 block_param_values: &mut self.block_param_values,
2357 poison_params: &self.poison_params,
2358 ctx,
2359 };
2360 let value = tmp.get_value(store.src.qualify(id.func));
2361 let value = value.map_err(|kind| self.make_error(ctx, kind))?;
2362 self.memory
2363 .write(
2364 store.space.qualify(id.func),
2365 SizedValue::from_u64(address),
2366 store.size,
2367 value,
2368 )
2369 .map_err(|kind| self.make_error(ctx, kind))?;
2370 self.idx += 1;
2371 }
2372
2373 Mnemonic::Store(store) if self.is_array_operand(ctx, store.src.qualify(id.func)) => {
2374 let (space, ptr, src) = (
2375 store.space,
2376 store.ptr.qualify(id.func),
2377 store.src.qualify(id.func),
2378 );
2379 let buf = self
2380 .resolve_array(ctx, src)
2381 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2382 let addr = self
2383 .get_value(ctx, ptr)
2384 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2385 self.write_memory(ctx, space.qualify(id.func), addr, &buf)
2386 .map_err(|kind| self.make_error(ctx, kind))?;
2387 self.idx += 1;
2388 }
2389
2390 Mnemonic::Scan(scan) => {
2394 let scan = scan.clone();
2395 self.eval_scan(ctx, insn_id, &scan)
2396 .map_err(|kind| self.make_error(ctx, kind))?;
2397 self.idx += 1;
2398 }
2399
2400 Mnemonic::Map(map) => {
2402 let map = map.clone();
2403 self.eval_map(ctx, insn_id, &map)
2404 .map_err(|kind| self.make_error(ctx, kind))?;
2405 self.idx += 1;
2406 }
2407
2408 Mnemonic::Range(range) if self.is_array_operand(ctx, range.src.qualify(id.func)) => {
2413 let (src, start, size) = (range.src.qualify(id.func), range.start, range.size);
2414 let buf = self
2415 .resolve_array(ctx, src)
2416 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2417 let end = (start + size).min(buf.len());
2418 let slice = buf.get(start..end).unwrap_or(&[]).to_vec();
2419 self.array_values.insert(insn_id, slice);
2420 self.idx += 1;
2421 }
2422
2423 Mnemonic::Intrinsic(app) if is_array_intrinsic(app.id.name()) => {
2428 let name = app.id.name();
2429 let args: Vec<ValueId> = app.args.iter().map(|a| a.qualify(id.func)).collect();
2430 self.eval_array_intrinsic(ctx, insn_id, name, &args)
2431 .map_err(|kind| self.make_error(ctx, kind))?;
2432 self.idx += 1;
2433 }
2434
2435 _ => {
2436 if let Some(value) = self
2437 .interpret_packed_pcode_op(ctx, &insn, mnemonic)
2438 .map_err(|kind| self.make_error(ctx, kind))?
2439 {
2440 self.insn_values.insert(id, value);
2441 self.idx += 1;
2442 return Ok(StepEvent::Normal);
2443 }
2444 let mut tmp = TempInterpreter {
2445 memory: &mut self.memory,
2446 literals: &mut self.literal_cache,
2447 insn_values: &mut self.insn_values,
2448 block_param_values: &mut self.block_param_values,
2449 poison_params: &self.poison_params,
2450 ctx,
2451 };
2452 if let Some(value) = tmp.interpret(insn, mnemonic)? {
2453 self.insn_values.insert(id, value);
2454 }
2455 self.idx += 1;
2456 }
2457 }
2458
2459 Ok(StepEvent::Normal)
2460 }
2461
2462 pub fn step(&mut self, ctx: &Context<'_>) -> crate::Result<()> {
2463 self.step_with_event(ctx).map(|_| ())
2464 }
2465
2466 pub fn run_block(&mut self, ctx: &Context<'_>) -> crate::Result<()> {
2467 loop {
2468 self.step(ctx)?;
2469 if self.idx == 0 {
2470 break;
2471 }
2472 }
2473 Ok(())
2474 }
2475
2476 pub fn run_until(&mut self, ctx: &Context<'_>, addr: u64) -> crate::Result<()> {
2478 let target = self
2479 .block_at(ctx, addr)
2480 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::UnknownAddress(addr)))?;
2481 while self.block != target {
2482 self.run_block(ctx)?;
2483 }
2484 Ok(())
2485 }
2486
2487 fn writeback_materialized_outputs(
2505 &mut self,
2506 ctx: &Context<'_>,
2507 call_id: InstructionId,
2508 callee: FunctionId,
2509 ) {
2510 if call_is_regpure(ctx, call_id) {
2511 return;
2512 }
2513 let outputs = match &FunctionBody::from_id(ctx, callee).effects().register {
2514 qcode::value::RegisterChannelState::Materialized(map) => map.outputs.clone(),
2515 _ => return,
2516 };
2517 let Some(agg) = self.aggregate_values.get(&call_id).cloned() else {
2518 return;
2519 };
2520 for (field, ®) in agg.iter().zip(&outputs) {
2521 let _ = self.set_varnode_u128(ctx, reg, field.as_bits());
2522 }
2523 }
2524
2525 fn seed_entry_params(&mut self, ctx: &Context<'_>, func: FunctionId) {
2526 let Some(root) = FunctionBody::from_id(ctx, func).root() else {
2527 return;
2528 };
2529 let root_id = root.id;
2530 enum Seed {
2531 Reg(VarnodeId),
2532 Lit(u64),
2538 }
2539 let params: Vec<(BlockParamId, Option<Seed>, usize)> = BasicBlock::from_id(ctx, root_id)
2540 .params()
2541 .map(|param| {
2542 let src = param
2543 .name()
2544 .and_then(|name| ctx.get_named(name))
2545 .and_then(|value| match value {
2546 ValueId::Varnode(id) => Some(Seed::Reg(id)),
2547 _ => None,
2548 })
2549 .or_else(|| match param.origin() {
2550 Some(ValueId::Literal(_)) => {
2551 let ValueRef::Literal(lit) = ValueRef::new(param.origin()?, ctx) else {
2552 return None;
2553 };
2554 Some(Seed::Lit(lit.value()))
2555 }
2556 _ => None,
2557 });
2558 (param.id, src, param.size())
2559 })
2560 .collect();
2561 for (param_id, src, size) in params {
2562 let value = match src {
2563 Some(Seed::Reg(varnode_id)) => self.read_varnode(ctx, varnode_id),
2564 Some(Seed::Lit(addr)) => {
2565 let space = ctx.shared.default_space;
2569 self.read_memory(ctx, space, addr, size).ok().map(|bytes| {
2570 let mut buf = [0u8; 8];
2571 let n = bytes.len().min(8);
2572 buf[..n].copy_from_slice(&bytes[..n]);
2573 u64::from_le_bytes(buf)
2574 })
2575 }
2576 None => None,
2577 };
2578 if let Some(value) = value {
2579 self.block_param_values
2580 .insert(param_id, SizedValue::new(value, size));
2581 }
2582 }
2583 }
2584
2585 fn bind_entry_params_from_args(
2597 &mut self,
2598 ctx: &Context<'_>,
2599 call_id: InstructionId,
2600 target: FunctionId,
2601 ) {
2602 let args = match ctx.get_insn(call_id).mnemonic() {
2603 Mnemonic::Call(call) => call.args.clone(),
2604 _ => return,
2605 };
2606 let Some(root) = FunctionBody::from_id(ctx, target).root() else {
2607 return;
2608 };
2609 let params: Vec<(BlockParamId, usize)> = BasicBlock::from_id(ctx, root.id)
2610 .params()
2611 .map(|p| (p.id, p.size()))
2612 .collect();
2613 if args.len() != params.len() {
2614 self.seed_entry_params(ctx, target);
2617 return;
2618 }
2619 let values: Vec<SizedValue> = args
2621 .iter()
2622 .zip(¶ms)
2623 .map(|(&arg, &(_, size))| {
2624 let raw = self.get_value(ctx, arg.qualify(call_id.func)).unwrap_or(0);
2625 SizedValue::new(raw, size)
2626 })
2627 .collect();
2628 for ((param_id, _), value) in params.into_iter().zip(values) {
2629 self.block_param_values.insert(param_id, value);
2630 }
2631 }
2632
2633 pub fn run_function(&mut self, ctx: &Context<'_>, func: FunctionId) -> crate::Result<()> {
2634 let root = FunctionBody::from_id(ctx, func)
2635 .root()
2636 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
2637 .id;
2638 self.block = root;
2639 self.idx = 0;
2640 self.call_stack.push(func);
2641 self.seed_entry_params(ctx, func);
2642
2643 let mut call_depth: i32 = 0;
2644
2645 let result = loop {
2646 let insn_ids = BasicBlock::from_id(ctx, self.block)
2647 .instruction_ids()
2648 .to_vec();
2649 let insn = InstructionRef::from_id(ctx, insn_ids[self.idx]);
2650
2651 if matches!(insn.mnemonic(), Mnemonic::Return(_)) && call_depth == 0 {
2652 break Ok(());
2653 }
2654
2655 match self.step_with_event(ctx)? {
2656 StepEvent::DirectCallEntered(target) => {
2657 call_depth += 1;
2658 self.call_stack.push(target);
2659 let regpure_site = self
2666 .call_site_stack
2667 .last()
2668 .copied()
2669 .is_some_and(|call_id| call_is_regpure(ctx, call_id));
2670 if regpure_site || FunctionBody::from_id(ctx, target).is_reg_materialized() {
2671 if let Some(&call_id) = self.call_site_stack.last() {
2672 self.bind_entry_params_from_args(ctx, call_id, target);
2673 }
2674 } else {
2675 self.seed_entry_params(ctx, target);
2676 }
2677 }
2678 StepEvent::IndirectCallEntered => {
2679 call_depth += 1;
2680 if let Some(parent) = BasicBlock::from_id(ctx, self.block).parent() {
2682 let callee = parent.id;
2683 self.call_stack.push(callee);
2684 self.seed_entry_params(ctx, callee);
2685 }
2686 }
2687 StepEvent::Return | StepEvent::ReturnValue => {
2688 self.call_stack.pop();
2689 call_depth -= 1;
2690 }
2691 StepEvent::Normal | StepEvent::InterceptedCall => {}
2692 }
2693 };
2694
2695 self.call_stack.pop(); result
2697 }
2698
2699 pub fn run_pure(
2710 &mut self,
2711 ctx: &Context<'_>,
2712 func: FunctionId,
2713 args: &[SizedValue],
2714 max_steps: usize,
2715 ) -> crate::Result<()> {
2716 let opts: Vec<Option<SizedValue>> = args.iter().map(|&v| Some(v)).collect();
2717 self.run_pure_partial(ctx, func, &opts, max_steps)
2718 }
2719
2720 pub fn run_pure_partial(
2727 &mut self,
2728 ctx: &Context<'_>,
2729 func: FunctionId,
2730 args: &[Option<SizedValue>],
2731 max_steps: usize,
2732 ) -> crate::Result<()> {
2733 let root = FunctionBody::from_id(ctx, func)
2734 .root()
2735 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
2736 .id;
2737 self.block = root;
2738 self.idx = 0;
2739 self.call_stack.push(func);
2740
2741 let param_ids: Vec<BlockParamId> = BasicBlock::from_id(ctx, root)
2744 .params()
2745 .map(|p| p.id)
2746 .collect();
2747 for (param_id, arg) in param_ids.into_iter().zip(args) {
2748 match arg {
2749 Some(value) => {
2750 self.block_param_values.insert(param_id, *value);
2751 }
2752 None => {
2753 self.poison_params.insert(param_id);
2754 }
2755 }
2756 }
2757
2758 self.drive_to_return(ctx, root, func, max_steps)
2759 }
2760
2761 fn refresh_sequence_types(&mut self, ctx: &Context<'_>) {
2772 let published = ctx.shared.types.published_len();
2773 if self.sequence_types_checked_at == Some(published) {
2774 return;
2775 }
2776 self.sequence_types = ctx.shared.types.has_sequence_types();
2777 self.sequence_types_checked_at = Some(published);
2778 }
2779
2780 fn is_array_operand(&self, ctx: &Context<'_>, id: ValueId) -> bool {
2781 if !self.sequence_types {
2783 return false;
2784 }
2785 match ctx.stored_type_of(id) {
2786 Some(ty) => {
2787 ctx.shared.types.array_of(ty).is_some() || ctx.shared.types.list_of(ty).is_some()
2788 }
2789 None => false,
2790 }
2791 }
2792
2793 fn resolve_array(&mut self, ctx: &Context<'_>, id: ValueId) -> Option<Vec<u8>> {
2797 match id {
2798 ValueId::Bytes(b) => Some(ctx.shared.values.bytes[b].data.clone()),
2799 ValueId::Instruction(i) => self
2800 .array_values
2801 .get(&i)
2802 .cloned()
2803 .or_else(|| self.get_value_bytes(ctx, id)),
2804 ValueId::Literal(_) => self.get_value_bytes(ctx, id),
2805 ValueId::BlockParam(_) => {
2811 let bytes = self.get_value_bytes(ctx, id)?;
2812 let ty_size = ctx
2813 .stored_type_of(id)
2814 .map(|ty| ctx.shared.types.size_of(ty))?;
2815 (bytes.len() == ty_size).then_some(bytes)
2816 }
2817 _ => None,
2818 }
2819 }
2820
2821 fn eval_array_intrinsic(
2824 &mut self,
2825 ctx: &Context<'_>,
2826 insn_id: InstructionId,
2827 name: &str,
2828 args: &[ValueId],
2829 ) -> Result<(), EmulatorErrorKind> {
2830 match name {
2831 "iota" => {
2832 let n = self
2833 .get_value(ctx, args[0])
2834 .ok_or(EmulatorErrorKind::ValueError(0))?;
2835 let mut buf = Vec::with_capacity(n as usize * 8);
2836 for i in 0..n {
2837 buf.extend_from_slice(&i.to_le_bytes());
2838 }
2839 self.array_values.insert(insn_id, buf);
2840 }
2841 "singleton" => {
2842 let buf = self
2843 .get_value_bytes(ctx, args[0])
2844 .ok_or(EmulatorErrorKind::ValueError(0))?;
2845 self.array_values.insert(insn_id, buf);
2846 }
2847 "concat" => {
2848 let mut a = self
2849 .resolve_array(ctx, args[0])
2850 .ok_or(EmulatorErrorKind::ValueError(0))?;
2851 let b = self
2852 .resolve_array(ctx, args[1])
2853 .ok_or(EmulatorErrorKind::ValueError(0))?;
2854 a.extend_from_slice(&b);
2855 self.array_values.insert(insn_id, a);
2856 }
2857 "insert" => {
2858 let mut buf = self
2859 .resolve_array(ctx, args[0])
2860 .ok_or(EmulatorErrorKind::ValueError(0))?;
2861 let i = self
2862 .get_value(ctx, args[1])
2863 .ok_or(EmulatorErrorKind::ValueError(0))? as usize;
2864 let vbytes = self
2865 .get_value_bytes(ctx, args[2])
2866 .ok_or(EmulatorErrorKind::ValueError(0))?;
2867 let esz = vbytes.len();
2868 let off = i * esz;
2869 if off + esz <= buf.len() {
2870 buf[off..off + esz].copy_from_slice(&vbytes);
2871 }
2872 self.array_values.insert(insn_id, buf);
2873 }
2874 "enumerate" => {
2875 let src_ty = ctx
2880 .stored_type_of(args[0])
2881 .ok_or(EmulatorErrorKind::ValueError(0))?;
2882 if matches!(ctx.shared.types.list_of(src_ty), Some((_, None))) {
2883 return Err(EmulatorErrorKind::UnsupportedIntrinsic(Box::from(
2884 "enumerate",
2885 )));
2886 }
2887 let in_elem = ctx
2888 .shared
2889 .types
2890 .seq_elem_of(src_ty)
2891 .ok_or(EmulatorErrorKind::ValueError(0))?;
2892 let isz = ctx.shared.types.size_of(in_elem).max(1);
2893 let buf = self
2894 .resolve_array(ctx, args[0])
2895 .ok_or(EmulatorErrorKind::ValueError(0))?;
2896 let tuple_ty = ctx
2901 .stored_type_of(ValueId::Instruction(insn_id))
2902 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2903 .ok_or(EmulatorErrorKind::ValueError(0))?;
2904 let (idx_sz, elem_off) = {
2905 let fields = ctx
2906 .shared
2907 .types
2908 .aggregate_fields(tuple_ty)
2909 .ok_or(EmulatorErrorKind::ValueError(0))?;
2910 let [idx_f, _elem_f] = fields else {
2911 return Err(EmulatorErrorKind::ValueError(0));
2912 };
2913 let idx_sz = ctx.shared.types.size_of(idx_f.type_id).min(8);
2914 (idx_sz, idx_sz)
2915 };
2916 let tsz = idx_sz + isz;
2917 let count = buf.len() / isz;
2918 let mut out = vec![0u8; count * tsz];
2919 for i in 0..count {
2920 let base = i * tsz;
2921 let idx_bytes = (i as u64).to_le_bytes();
2922 out[base..base + idx_sz].copy_from_slice(&idx_bytes[..idx_sz]);
2923 out[base + elem_off..base + elem_off + isz]
2924 .copy_from_slice(&buf[i * isz..i * isz + isz]);
2925 }
2926 self.array_values.insert(insn_id, out);
2927 }
2928 "at" => {
2929 let buf = self
2930 .resolve_array(ctx, args[0])
2931 .ok_or(EmulatorErrorKind::ValueError(0))?;
2932 let i = self
2933 .get_value(ctx, args[1])
2934 .ok_or(EmulatorErrorKind::ValueError(0))? as usize;
2935 let esz = ctx
2936 .stored_type_of(ValueId::Instruction(insn_id))
2937 .map(|ty| ctx.shared.types.size_of(ty))
2938 .unwrap_or(8);
2939 let off = i * esz;
2940 let lane = buf
2941 .get(off..off + esz)
2942 .ok_or(EmulatorErrorKind::ValueError(0))?;
2943 self.insn_values
2944 .insert(insn_id, SizedValue::from_bits(le_bits(lane), esz));
2945 }
2946 other => panic!("eval_array_intrinsic called on non-array intrinsic `{other}`"),
2947 }
2948 Ok(())
2949 }
2950
2951 fn eval_scan(
2956 &mut self,
2957 ctx: &Context<'_>,
2958 insn_id: InstructionId,
2959 scan: &Scan,
2960 ) -> Result<(), EmulatorErrorKind> {
2961 const SCAN_STEP_BUDGET: usize = 100_000;
2962
2963 let src = self
2964 .resolve_array(ctx, scan.src.qualify(insn_id.func))
2965 .ok_or(EmulatorErrorKind::ValueError(0))?;
2966 let in_elem = ctx
2971 .stored_type_of(scan.src.qualify(insn_id.func))
2972 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2973 .ok_or(EmulatorErrorKind::ValueError(0))?;
2974 let isz = ctx.shared.types.size_of(in_elem).max(1);
2975 let out_elem = ctx
2976 .stored_type_of(ValueId::Instruction(insn_id))
2977 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2978 .ok_or(EmulatorErrorKind::ValueError(0))?;
2979 let osz = ctx.shared.types.size_of(out_elem);
2980 let count = src.len() / isz;
2981 let body = require_real_callee(scan.body)?;
2982 if count == 0 {
2983 self.array_values.insert(insn_id, Vec::new());
2984 return Ok(());
2985 }
2986
2987 let capture_args: Vec<BodyArg> = scan
2989 .captures
2990 .iter()
2991 .map(|&c| {
2992 let v = self
2993 .get_value(ctx, c.qualify(insn_id.func))
2994 .ok_or(EmulatorErrorKind::ValueError(0))?;
2995 let sz = ctx
2996 .stored_type_of(c.qualify(insn_id.func))
2997 .map(|ty| ctx.shared.types.size_of(ty))
2998 .unwrap_or(8);
2999 Ok(BodyArg::Scalar(SizedValue::new(v, sz)))
3000 })
3001 .collect::<Result<_, EmulatorErrorKind>>()?;
3002
3003 let init = self
3004 .get_value(ctx, scan.init.qualify(insn_id.func))
3005 .ok_or(EmulatorErrorKind::ValueError(0))?;
3006 let mut acc = SizedValue::new(init, osz);
3007
3008 let root = FunctionBody::from_id(ctx, body)
3009 .root()
3010 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(body))?
3011 .id;
3012
3013 let elem_fields: Option<Vec<(usize, usize)>> =
3019 ctx.shared.types.aggregate_fields(in_elem).map(|fs| {
3020 let mut off = 0;
3021 fs.iter()
3022 .map(|f| {
3023 let sz = ctx.shared.types.size_of(f.type_id);
3024 let field = (off, sz);
3025 off += sz;
3026 field
3027 })
3028 .collect()
3029 });
3030
3031 let mut out = Vec::with_capacity(count * osz);
3032 for k in 0..count {
3033 let elem = &src[k * isz..k * isz + isz];
3034 let elem_arg = match &elem_fields {
3035 Some(fields) => BodyArg::Aggregate(
3036 fields
3037 .iter()
3038 .map(|&(off, sz)| SizedValue::from_bits(le_bits(&elem[off..off + sz]), sz))
3039 .collect(),
3040 ),
3041 None => BodyArg::Scalar(SizedValue::from_bits(le_bits(elem), isz)),
3042 };
3043 let mut body_args = Vec::with_capacity(2 + capture_args.len());
3044 body_args.push(BodyArg::Scalar(acc));
3045 body_args.push(elem_arg);
3046 body_args.extend(capture_args.iter().cloned());
3047
3048 let mut emu = StandaloneEmulator::new(root);
3049 emu.run_map_body(ctx, body, &body_args, SCAN_STEP_BUDGET)
3050 .map_err(|e| e.kind)?;
3051 let ret = body_return_value(ctx, emu.current_block())
3052 .ok_or(EmulatorErrorKind::ValueError(0))?;
3053 let mut lane = emu
3054 .get_value_bytes(ctx, ret)
3055 .ok_or(EmulatorErrorKind::ValueError(0))?;
3056 lane.resize(osz, 0);
3057 acc = SizedValue::from_bits(le_bits(&lane), osz);
3058 out.extend_from_slice(&lane);
3059 }
3060 self.array_values.insert(insn_id, out);
3061 Ok(())
3062 }
3063
3064 fn eval_map(
3068 &mut self,
3069 ctx: &Context<'_>,
3070 insn_id: InstructionId,
3071 map: &qcode::value::insn::Map,
3072 ) -> Result<(), EmulatorErrorKind> {
3073 const MAP_STEP_BUDGET: usize = 100_000;
3074
3075 let src = self
3076 .resolve_array(ctx, map.src.qualify(insn_id.func))
3077 .ok_or(EmulatorErrorKind::ValueError(0))?;
3078 let in_elem = ctx
3079 .stored_type_of(map.src.qualify(insn_id.func))
3080 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
3081 .ok_or(EmulatorErrorKind::ValueError(0))?;
3082 let isz = ctx.shared.types.size_of(in_elem).max(1);
3083 let out_elem = ctx
3084 .stored_type_of(ValueId::Instruction(insn_id))
3085 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
3086 .ok_or(EmulatorErrorKind::ValueError(0))?;
3087 let osz = ctx.shared.types.size_of(out_elem);
3088 let count = src.len() / isz;
3089 let body = require_real_callee(map.body)?;
3090
3091 let capture_args: Vec<BodyArg> = map
3092 .captures
3093 .iter()
3094 .map(|&c| {
3095 let v = self
3096 .get_value(ctx, c.qualify(insn_id.func))
3097 .ok_or(EmulatorErrorKind::ValueError(0))?;
3098 let sz = ctx
3099 .stored_type_of(c.qualify(insn_id.func))
3100 .map(|ty| ctx.shared.types.size_of(ty))
3101 .unwrap_or(8);
3102 Ok(BodyArg::Scalar(SizedValue::new(v, sz)))
3103 })
3104 .collect::<Result<_, EmulatorErrorKind>>()?;
3105
3106 let elem_fields: Option<Vec<(usize, usize)>> =
3109 ctx.shared.types.aggregate_fields(in_elem).map(|fs| {
3110 let mut off = 0;
3111 fs.iter()
3112 .map(|f| {
3113 let sz = ctx.shared.types.size_of(f.type_id);
3114 let field = (off, sz);
3115 off += sz;
3116 field
3117 })
3118 .collect()
3119 });
3120
3121 let mut out = Vec::with_capacity(count * osz);
3122 for k in 0..count {
3123 let elem = &src[k * isz..k * isz + isz];
3124 let elem_arg = match &elem_fields {
3125 Some(fields) => BodyArg::Aggregate(
3126 fields
3127 .iter()
3128 .map(|&(off, sz)| SizedValue::from_bits(le_bits(&elem[off..off + sz]), sz))
3129 .collect(),
3130 ),
3131 None => BodyArg::Scalar(SizedValue::from_bits(le_bits(elem), isz)),
3132 };
3133 let mut body_args = Vec::with_capacity(1 + capture_args.len());
3134 body_args.push(elem_arg);
3135 body_args.extend(capture_args.iter().cloned());
3136
3137 let mut emu = StandaloneEmulator::new(
3138 FunctionBody::from_id(ctx, body)
3139 .root()
3140 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(body))?
3141 .id,
3142 );
3143 emu.run_map_body(ctx, body, &body_args, MAP_STEP_BUDGET)
3144 .map_err(|e| e.kind)?;
3145 let ret = body_return_value(ctx, emu.current_block())
3146 .ok_or(EmulatorErrorKind::ValueError(0))?;
3147 let mut lane = emu
3148 .get_value_bytes(ctx, ret)
3149 .ok_or(EmulatorErrorKind::ValueError(0))?;
3150 lane.resize(osz, 0);
3151 out.extend_from_slice(&lane);
3152 }
3153 self.array_values.insert(insn_id, out);
3154 Ok(())
3155 }
3156
3157 pub fn run_map_body(
3158 &mut self,
3159 ctx: &Context<'_>,
3160 func: FunctionId,
3161 args: &[BodyArg],
3162 max_steps: usize,
3163 ) -> crate::Result<()> {
3164 let root = FunctionBody::from_id(ctx, func)
3165 .root()
3166 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
3167 .id;
3168 self.block = root;
3169 self.idx = 0;
3170 self.call_stack.push(func);
3171
3172 let param_ids: Vec<BlockParamId> = BasicBlock::from_id(ctx, root)
3173 .params()
3174 .map(|p| p.id)
3175 .collect();
3176 for (param_id, arg) in param_ids.into_iter().zip(args) {
3177 match arg {
3178 BodyArg::Scalar(v) => {
3179 self.block_param_values.insert(param_id, *v);
3180 }
3181 BodyArg::Aggregate(fields) => {
3182 self.block_param_aggregates.insert(param_id, fields.clone());
3183 }
3184 }
3185 }
3186
3187 self.drive_to_return(ctx, root, func, max_steps)
3188 }
3189
3190 fn drive_to_return(
3196 &mut self,
3197 ctx: &Context<'_>,
3198 _root: BlockId,
3199 _func: FunctionId,
3200 max_steps: usize,
3201 ) -> crate::Result<()> {
3202 let mut steps = 0usize;
3203 let result = loop {
3204 let insn_ids = BasicBlock::from_id(ctx, self.block)
3205 .instruction_ids()
3206 .to_vec();
3207 if self.idx >= insn_ids.len() {
3213 break Err(self.make_empty_block_error(ctx));
3214 }
3215 let insn = InstructionRef::from_id(ctx, insn_ids[self.idx]);
3216 if matches!(
3217 insn.mnemonic(),
3218 Mnemonic::Return(_) | Mnemonic::ReturnValue(_)
3219 ) {
3220 break Ok(());
3221 }
3222 steps += 1;
3223 if steps > max_steps {
3224 break Err(self.make_error(ctx, EmulatorErrorKind::StepBudgetExceeded(max_steps)));
3225 }
3226 if let Err(e) = self.step(ctx) {
3227 break Err(e);
3228 }
3229 };
3230
3231 self.call_stack.pop();
3232 result
3233 }
3234}
3235
3236fn lambda_return_value(ctx: &Context<'_>, block: BlockId) -> Option<ValueId> {
3237 let last = BasicBlock::from_id(ctx, block).iter().last()?;
3238 match last.mnemonic() {
3239 Mnemonic::ReturnValue(ret) => Some(ret.value.qualify(last.id.func)),
3240 _ => None,
3241 }
3242}
3243
3244fn body_return_value(ctx: &Context<'_>, block: BlockId) -> Option<ValueId> {
3248 let last = BasicBlock::from_id(ctx, block).iter().last()?;
3249 match last.mnemonic() {
3250 Mnemonic::Return(ret) => ret.value.map(|v| v.qualify(last.id.func)),
3251 Mnemonic::ReturnValue(ret) => Some(ret.value.qualify(last.id.func)),
3252 _ => None,
3253 }
3254}
3255
3256fn is_array_intrinsic(name: &str) -> bool {
3260 matches!(
3261 name,
3262 "iota" | "singleton" | "concat" | "insert" | "at" | "enumerate"
3263 )
3264}
3265
3266fn le_bits(bytes: &[u8]) -> u128 {
3268 let mut buf = [0u8; 16];
3269 let n = bytes.len().min(16);
3270 buf[..n].copy_from_slice(&bytes[..n]);
3271 u128::from_le_bytes(buf)
3272}
3273
3274#[derive(Debug, Clone)]
3277pub enum BodyArg {
3278 Scalar(SizedValue),
3279 Aggregate(Vec<SizedValue>),
3280}
3281
3282struct TempInterpreter<'a, 'ctx, M> {
3285 memory: &'a mut M,
3286 literals: &'a mut LiteralCache,
3287 insn_values: &'a mut InsnValues,
3288 block_param_values: &'a mut FxHashMap<BlockParamId, SizedValue>,
3289 poison_params: &'a FxHashSet<BlockParamId>,
3290 ctx: &'ctx Context<'ctx>,
3291}
3292
3293impl<'ctx, M: EmulatorMemory> Interpreter for TempInterpreter<'_, 'ctx, M> {
3294 type V = SizedValue;
3295 type M = M;
3296
3297 fn memory(&mut self) -> &mut Self::M {
3298 self.memory
3299 }
3300
3301 fn ctx(&self) -> &Context<'_> {
3302 self.ctx
3303 }
3304
3305 fn get_value(&mut self, id: ValueId) -> Result<Self::V, EmulatorErrorKind> {
3306 if let ValueId::Literal(literal) = id {
3309 return Ok(self.literals.get(self.ctx, literal));
3310 }
3311 match ValueRef::new(id, self.ctx) {
3312 ValueRef::Literal(literal) => Ok(SizedValue::new(literal.value(), literal.size())),
3313 ValueRef::Bytes(_) => Err(EmulatorErrorKind::ValueError(0)),
3315 ValueRef::Instruction(insn) => self
3316 .insn_values
3317 .get(&insn.id)
3318 .copied()
3319 .ok_or(EmulatorErrorKind::ValueError(0)),
3320 ValueRef::Varnode(varnode) => Ok(SizedValue::new(varnode.address() as u64, 8)),
3321 ValueRef::Temp(temp) => Ok(SizedValue::new(temp.address() as u64, 8)),
3322 ValueRef::BasicBlock(_) => panic!("Cannot get value of a block"),
3323 ValueRef::BlockParam(param) => {
3324 if self.poison_params.contains(¶m.id) {
3325 return Err(EmulatorErrorKind::PoisonRead);
3326 }
3327 self.block_param_values
3328 .get(¶m.id)
3329 .copied()
3330 .ok_or(EmulatorErrorKind::ValueError(0))
3331 }
3332 ValueRef::Function(f) => f
3333 .address()
3334 .map(SizedValue::from_u64)
3335 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(f.id)),
3336 ValueRef::Poison(_) => Err(EmulatorErrorKind::PoisonRead),
3339 }
3340 }
3341}
3342
3343pub struct Emulator<'ctx, M = EmulatedMemory> {
3344 inner: StandaloneEmulator<M>,
3345 ctx: &'ctx Context<'ctx>,
3346}
3347
3348impl<'ctx> Emulator<'ctx, EmulatedMemory> {
3349 pub fn new(ctx: &'ctx Context<'ctx>, entry: BlockId) -> Self {
3351 Self::new_in(ctx, entry)
3352 }
3353
3354 pub fn from_function(ctx: &'ctx Context<'ctx>, func: FunctionId) -> Self {
3355 Self::from_function_in(ctx, func)
3356 }
3357
3358 pub fn from_block(ctx: &'ctx Context<'ctx>, block: BlockId) -> Self {
3359 Self::new_in(ctx, block)
3360 }
3361
3362 pub fn from_address(ctx: &'ctx Context<'ctx>, addr: u64) -> Self {
3363 Self::from_address_in(ctx, addr)
3364 }
3365}
3366
3367impl<'ctx, M: EmulatorMemory + Default> Emulator<'ctx, M> {
3368 pub fn new_in(ctx: &'ctx Context<'ctx>, entry: BlockId) -> Self {
3370 let mut inner =
3371 StandaloneEmulator::<M>::with_address_index(entry, AddressIndex::analyze(ctx));
3372 inner.memory.configure_spaces(ctx);
3373 Self { inner, ctx }
3374 }
3375
3376 pub fn set_instruction_hook(
3377 &mut self,
3378 hook: impl Fn(&InstructionRef<'_, '_>, &StandaloneEmulator<M>) + Send + Sync + 'static,
3379 ) {
3380 self.inner.instruction_hook = Some(Box::new(hook));
3381 }
3382
3383 pub fn set_call_interceptor(
3384 &mut self,
3385 interceptor: impl FnMut(
3386 &Context<'_>,
3387 &mut StandaloneEmulator<M>,
3388 &CallSite,
3389 ) -> Result<CallInterception, Box<str>>
3390 + Send
3391 + Sync
3392 + 'static,
3393 ) {
3394 self.inner.set_call_interceptor(interceptor);
3395 }
3396
3397 pub fn clear_call_interceptor(&mut self) {
3398 self.inner.clear_call_interceptor();
3399 }
3400
3401 pub fn from_function_in(ctx: &'ctx Context<'ctx>, func: FunctionId) -> Self {
3403 let entry = FunctionBody::from_id(ctx, func)
3404 .root()
3405 .expect("Cannot create emulator for function with empty root block")
3406 .id;
3407 Self::new_in(ctx, entry)
3408 }
3409
3410 pub fn from_address_in(ctx: &'ctx Context<'ctx>, addr: u64) -> Self {
3412 Self {
3413 inner: StandaloneEmulator::<M>::from_address_in(ctx, addr),
3414 ctx,
3415 }
3416 }
3417
3418 pub fn inspect_memory(&mut self, space: SpaceId, addr: u64, size: usize) -> Option<Vec<u8>> {
3420 self.inner
3421 .memory
3422 .read_bytes(MemorySpaceId::Shared(space), addr, size)
3423 .ok()
3424 }
3425
3426 pub fn set_varnode(&mut self, id: VarnodeId, value: u64) -> Result<(), EmulatorErrorKind> {
3428 self.inner.set_varnode(self.ctx, id, value)
3429 }
3430
3431 pub fn set_varnode_u128(
3433 &mut self,
3434 id: VarnodeId,
3435 value: u128,
3436 ) -> Result<(), EmulatorErrorKind> {
3437 self.inner.set_varnode_u128(self.ctx, id, value)
3438 }
3439
3440 pub fn set_register(&mut self, id: RegisterId, value: u64) -> Result<(), EmulatorErrorKind> {
3442 let id = self.ctx.get_register(id).id;
3443 self.set_varnode(id, value)
3444 }
3445
3446 pub fn write_memory(
3448 &mut self,
3449 space: SpaceId,
3450 addr: u64,
3451 value: &[u8],
3452 ) -> Result<(), EmulatorErrorKind> {
3453 self.inner.write_memory(self.ctx, space, addr, value)
3454 }
3455
3456 pub fn read_memory(
3457 &mut self,
3458 space: SpaceId,
3459 addr: u64,
3460 size: usize,
3461 ) -> Result<Vec<u8>, EmulatorErrorKind> {
3462 self.inner.read_memory(self.ctx, space, addr, size)
3463 }
3464
3465 pub fn set_register_u128(
3467 &mut self,
3468 id: RegisterId,
3469 value: u128,
3470 ) -> Result<(), EmulatorErrorKind> {
3471 let id = self.ctx.get_register(id).id;
3472 self.set_varnode_u128(id, value)
3473 }
3474
3475 pub fn read_varnode(&mut self, id: VarnodeId) -> Option<u64> {
3476 self.inner.read_varnode(self.ctx, id)
3477 }
3478
3479 pub fn read_varnode_u128(&mut self, id: VarnodeId) -> Option<u128> {
3480 self.inner.read_varnode_u128(self.ctx, id)
3481 }
3482
3483 pub fn read_register(&mut self, id: RegisterId) -> Option<u64> {
3484 let id = self.ctx.get_register(id).id;
3485 self.read_varnode(id)
3486 }
3487
3488 pub fn read_register_u128(&mut self, id: RegisterId) -> Option<u128> {
3489 let id = self.ctx.get_register(id).id;
3490 self.read_varnode_u128(id)
3491 }
3492
3493 pub fn set_register_lane(&mut self, id: RegisterId, lane: usize, value: u64) {
3496 let (space_id, base_addr) = {
3497 let vn = self.ctx.get_register(id);
3498 (vn.space().id, vn.address() as u64)
3499 };
3500 let base = base_addr + (lane as u64) * 8;
3501 let _ = self
3502 .inner
3503 .memory
3504 .write_bytes(space_id.into(), base, &value.to_le_bytes());
3505 }
3506
3507 pub fn read_register_lane(&mut self, id: RegisterId, lane: usize) -> u64 {
3510 let (space_id, base_addr) = {
3511 let vn = self.ctx.get_register(id);
3512 (vn.space().id, vn.address() as u64)
3513 };
3514 let base = base_addr + (lane as u64) * 8;
3515 let bytes = self
3518 .inner
3519 .memory
3520 .read_bytes(space_id.into(), base, 8)
3521 .unwrap_or_else(|_| vec![0; 8]);
3522 u64::from_le_bytes(bytes.try_into().expect("read_bytes returns 8 bytes"))
3523 }
3524
3525 pub fn block(&self) -> BlockRef<'ctx, 'ctx> {
3527 BasicBlock::from_id(self.ctx, self.inner.block)
3528 }
3529
3530 pub fn insn(&self) -> Option<InstructionRef<'ctx, 'ctx>> {
3532 let block = self.block();
3533 if self.inner.idx >= block.instruction_count() {
3534 None
3535 } else {
3536 let id = block.instruction_ids()[self.inner.idx];
3537 Some(InstructionRef::from_id(self.ctx, id))
3538 }
3539 }
3540
3541 pub fn step(&mut self) -> crate::Result<()> {
3543 self.inner.step(self.ctx)
3544 }
3545
3546 pub fn run_block(&mut self) -> crate::Result<()> {
3548 self.inner.run_block(self.ctx)
3549 }
3550
3551 pub fn run_until(&mut self, addr: u64) -> crate::Result<()> {
3553 self.inner.run_until(self.ctx, addr)
3554 }
3555
3556 pub fn run_function(&mut self, func: FunctionId) -> crate::Result<()> {
3558 self.inner.run_function(self.ctx, func)
3559 }
3560
3561 pub fn call_stack(&self) -> &[FunctionId] {
3564 &self.inner.call_stack
3565 }
3566}
3567
3568impl<'ctx, M: EmulatorMemory> Interpreter for Emulator<'ctx, M> {
3569 type V = SizedValue;
3570 type M = M;
3571
3572 fn memory(&mut self) -> &mut Self::M {
3573 &mut self.inner.memory
3574 }
3575
3576 fn ctx(&self) -> &Context<'ctx> {
3577 self.ctx
3578 }
3579
3580 fn get_value(&mut self, id: ValueId) -> Result<Self::V, EmulatorErrorKind> {
3581 if let ValueId::Literal(literal) = id {
3582 let value = self.inner.literal_cache.get(self.ctx, literal);
3583 return Ok(value);
3584 }
3585 match ValueRef::new(id, self.ctx) {
3586 ValueRef::Literal(literal) => Ok(SizedValue::new(literal.value(), literal.size())),
3587 ValueRef::Bytes(_) => Err(EmulatorErrorKind::ValueError(0)),
3589 ValueRef::Instruction(insn) => self
3590 .inner
3591 .insn_values
3592 .get(&insn.id)
3593 .copied()
3594 .ok_or(EmulatorErrorKind::ValueError(0)),
3595 ValueRef::Varnode(varnode) => Ok(SizedValue::new(varnode.address() as u64, 8)),
3596 ValueRef::Temp(temp) => Ok(SizedValue::new(temp.address() as u64, 8)),
3597 ValueRef::BasicBlock(_) => panic!("Cannot get value of a block"),
3598 ValueRef::BlockParam(param) => self
3599 .inner
3600 .block_param_values
3601 .get(¶m.id)
3602 .copied()
3603 .ok_or(EmulatorErrorKind::ValueError(0)),
3604 ValueRef::Function(f) => f
3605 .address()
3606 .map(SizedValue::from_u64)
3607 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(f.id)),
3608 ValueRef::Poison(_) => Err(EmulatorErrorKind::PoisonRead),
3611 }
3612 }
3613}
3614
3615#[cfg(test)]
3616mod tests {
3617 use super::*;
3618 use qcode::context::Context;
3619 use qcode::space::{Space, SpaceType};
3620 use qcode::value::QCodeMut;
3621 use qcode::value::TempSpace;
3622 use std::sync::{Arc, Mutex};
3623 use wazabin_qcode_macro::qcode;
3624
3625 #[test]
3628 fn reading_poison_is_a_hard_error() {
3629 let mut ctx = Context::new();
3630 let func = ctx.anon_function();
3631 let block = BasicBlock::make(&mut ctx, func).with_address(0x1000).id;
3632 let i32_ty = ctx.shared.types.get_or_make_int(4);
3633 let poison = ctx.get_poison(i32_ty);
3634 let mut emu = StandaloneEmulator::new(block);
3635 let mut tmp = TempInterpreter {
3636 memory: &mut emu.memory,
3637 literals: &mut emu.literal_cache,
3638 insn_values: &mut emu.insn_values,
3639 block_param_values: &mut emu.block_param_values,
3640 poison_params: &emu.poison_params,
3641 ctx: &ctx,
3642 };
3643 assert!(matches!(
3644 tmp.get_value(poison),
3645 Err(EmulatorErrorKind::PoisonRead)
3646 ));
3647 }
3648
3649 #[test]
3650 fn minted_callee_is_not_executable() {
3651 assert!(matches!(
3652 require_real_callee(Callee::Minted(7)),
3653 Err(EmulatorErrorKind::UnresolvedMintedCallee(7))
3654 ));
3655 }
3656
3657 #[test]
3658 fn sized_value_masks_to_declared_width() {
3659 let value = SizedValue::new(0x1234, 1);
3660 assert_eq!(value.size().unwrap(), 1);
3661 assert_eq!(value.value().unwrap(), 0x34);
3662 }
3663
3664 #[test]
3665 fn from_address_resolves_function_entry_to_root() {
3666 let mut ctx = Context::new();
3667 let function = FunctionBody::make_at_addr(&mut ctx, 0x1000, None).id;
3668 let root = BasicBlock::make(&mut ctx, function).with_address(0x1000).id;
3669
3670 let emulator = StandaloneEmulator::from_address(&ctx, 0x1000);
3671
3672 assert_eq!(emulator.current_block(), root);
3673 assert!(emulator.address_index.is_some());
3674 }
3675
3676 #[test]
3677 fn standalone_address_lookup_builds_one_lazy_snapshot() {
3678 let mut ctx = Context::new();
3679 let function = ctx.anon_function();
3680 let block = BasicBlock::make(&mut ctx, function).with_address(0x2000).id;
3681 ctx.block_mut(block).extra_addresses.push(0x2001);
3682 let mut emulator = StandaloneEmulator::new(block);
3683
3684 assert!(emulator.address_index.is_none());
3685 assert_eq!(emulator.block_at(&ctx, 0x2001), Some(block));
3686 assert!(emulator.address_index.is_some());
3687 assert_eq!(emulator.block_at(&ctx, 0x2000), Some(block));
3688 }
3689
3690 #[test]
3691 fn int_add_wraps_by_width_and_sets_carry() {
3692 let lhs = SizedValue::new(0xff, 1);
3693 let rhs = SizedValue::new(0x01, 1);
3694
3695 let sum = lhs.int_add(&rhs).unwrap();
3696 let carry = lhs.carry(&rhs).unwrap();
3697
3698 assert_eq!(sum.value().unwrap(), 0x00);
3699 assert_eq!(sum.size().unwrap(), 1);
3700 assert_eq!(carry.value().unwrap(), 1);
3701 assert_eq!(carry.size().unwrap(), 1);
3702 }
3703
3704 #[test]
3705 fn branch_args_bind_block_params() {
3706 let mut ctx = Context::new();
3707 qcode!(
3708 ctx,
3709 "
3710 <src>
3711 goto <dst @x=0x2>;
3712 <dst @x>
3713 %sum = i64 @x + 0x3;
3714 goto <0x1001>;
3715 "
3716 );
3717
3718 let mut emu = StandaloneEmulator::new(src);
3719 emu.step(&ctx).expect("branch binds block params");
3720 emu.step(&ctx).expect("destination uses block param");
3721
3722 assert_eq!(emu.get_value(&ctx, sum.into()), Some(5));
3723 }
3724
3725 #[test]
3726 fn apply_evaluates_recursive_lambda_value_return() {
3727 let mut ctx = Context::new();
3728 qcode!(
3729 ctx,
3730 "
3731 lambda dec:
3732 <entry @n:i64>
3733 %is_zero = @n == 0;
3734 if %is_zero goto <done @r=@n> else goto <step @m=@n>;
3735
3736 <step @m:i64>
3737 %next = @m - 1;
3738 %out = apply dec(%next);
3739 return %out;
3740
3741 <done @r:i64>
3742 return @r;
3743 "
3744 );
3745
3746 let dec = qcode::value::FunctionBody::from_name(&ctx, "dec")
3747 .expect("lambda exists")
3748 .id;
3749 let root = qcode::value::FunctionBody::from_id(&ctx, dec)
3750 .root()
3751 .expect("lambda has root")
3752 .id;
3753 let mut emu = StandaloneEmulator::new(root);
3754 emu.run_pure(&ctx, dec, &[SizedValue::new(3, 8)], 1000)
3755 .expect("recursive lambda evaluates");
3756 let ret = lambda_return_value(&ctx, emu.current_block()).expect("lambda returned a value");
3757 assert_eq!(emu.get_value(&ctx, ret), Some(0));
3758 }
3759
3760 fn publish_iota_result(ctx: &mut Context) {
3763 use qcode::types::TypeRequest;
3764 let i64_ty = ctx.shared.types.get_or_make_int(8);
3765 ctx.shared
3766 .types
3767 .create_requested_types(&[TypeRequest::list(i64_ty, None)]);
3768 }
3769
3770 #[test]
3773 fn map_over_array_is_emulated() {
3774 let mut ctx = Context::new();
3775 publish_iota_result(&mut ctx);
3776 qcode!(
3777 ctx,
3778 "
3779 lambda triple:
3780 <tb @x:i64>
3781 %r = @x * 3;
3782 return %r;
3783 fn main:
3784 <me>
3785 %src = $iota(i64 0x4);
3786 %m = triple <$> %src;
3787 goto <0x1001>;
3788 "
3789 );
3790
3791 let mut emu = StandaloneEmulator::new(me);
3792 emu.step(&ctx).expect("iota");
3793 emu.step(&ctx).expect("map");
3794
3795 let buf = emu.array_values.get(&m).expect("map produced an array");
3796 let words: Vec<u64> = buf
3797 .as_chunks::<8>()
3798 .0
3799 .iter()
3800 .map(|&c| u64::from_le_bytes(c))
3801 .collect();
3802 assert_eq!(words, vec![0, 3, 6, 9]);
3804 }
3805
3806 #[test]
3811 fn scan_over_iota_is_emulated() {
3812 let mut ctx = Context::new();
3813 publish_iota_result(&mut ctx);
3814 qcode!(
3815 ctx,
3816 "
3817 lambda step:
3818 <sb @acc:i64 @x:i64>
3819 %r = @acc + @x;
3820 return %r;
3821 fn main:
3822 <me>
3823 %src = $iota(i64 0x3);
3824 %s = scanl @step i64 0xa %src;
3825 goto <0x1001>;
3826 "
3827 );
3828
3829 let mut emu = StandaloneEmulator::new(me);
3830 emu.step(&ctx).expect("iota");
3832 emu.step(&ctx).expect("scan");
3833
3834 let buf = emu.array_values.get(&s).expect("scan produced an array");
3835 let words: Vec<u64> = buf
3836 .as_chunks::<8>()
3837 .0
3838 .iter()
3839 .map(|&c| u64::from_le_bytes(c))
3840 .collect();
3841 assert_eq!(words, vec![10, 11, 13]);
3842 }
3843
3844 #[test]
3845 fn enumerate_over_array_is_emulated() {
3846 use qcode::value::{FunctionBody, ValueId, insn::IntrinsicId};
3847
3848 let mut ctx = Context::new();
3849 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
3850 let entry = ctx.get_or_make_block(0x1000, f);
3851 {
3852 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
3853 fm.set_root(entry).unwrap();
3854 fm.add_block(entry);
3855 }
3856 let i64_ty = ctx.shared.types.get_or_make_int(8);
3858 let arr_ty = ctx.shared.types.get_or_make_array(i64_ty, 4);
3859 let data: Vec<u8> = [10u64, 20, 30, 40]
3860 .iter()
3861 .flat_map(|w| w.to_le_bytes())
3862 .collect();
3863 let src = ctx.get_bytes(data).id();
3864 if let ValueId::Bytes(bid) = src {
3865 ctx.shared.values.bytes[bid].type_id = arr_ty;
3866 }
3867 {
3870 use qcode::types::{AggregateField, TypeRequest};
3871 let fields = vec![
3872 AggregateField::new("index", i64_ty),
3873 AggregateField::new("elem", i64_ty),
3874 ];
3875 let tuple = ctx
3876 .shared
3877 .types
3878 .create_requested_types(&[TypeRequest::aggregate(fields)])[0];
3879 ctx.shared
3880 .types
3881 .create_requested_types(&[TypeRequest::array(tuple, 4)]);
3882 }
3883 let enum_id = IntrinsicId::from_name("enumerate").unwrap();
3884 let e = {
3885 let mut b = ctx.builder(entry);
3886 let e = b.push_intrinsic(enum_id, vec![src]).id();
3887 let ptr = b.shr().get_const(0, 8);
3888 b.push_return(ptr);
3889 e
3890 };
3891 let ValueId::Instruction(eid) = e else {
3892 unreachable!()
3893 };
3894
3895 let mut emu = StandaloneEmulator::new(entry);
3896 emu.step(&ctx).expect("enumerate");
3897
3898 let buf = emu
3901 .array_values
3902 .get(&eid)
3903 .expect("enumerate produced an array");
3904 let words: Vec<u64> = buf
3905 .as_chunks::<8>()
3906 .0
3907 .iter()
3908 .map(|&c| u64::from_le_bytes(c))
3909 .collect();
3910 assert_eq!(words, vec![0, 10, 1, 20, 2, 30, 3, 40]);
3911 }
3912
3913 #[test]
3918 fn enumerate_of_unbounded_list_bails_recoverably() {
3919 use qcode::value::{
3920 BasicBlock, FunctionBody, InstructionRef, ValueId,
3921 insn::{IntrinsicApp, IntrinsicId, Return},
3922 };
3923
3924 let mut ctx = Context::new();
3925 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
3926 let entry = ctx.get_or_make_block(0x1000, f);
3927 {
3928 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
3929 fm.set_root(entry).unwrap();
3930 fm.add_block(entry);
3931 }
3932 let i8 = ctx.shared.types.get_or_make_int(1);
3933 let list_ty = ctx.shared.types.get_or_make_unbounded_list(i8);
3934 let src = {
3935 let mut b = ctx.builder(entry);
3936 b.push_param(8).id()
3937 };
3938 if let ValueId::BlockParam(pid) = src {
3939 ctx.block_param_mut(pid).type_id = list_ty;
3940 }
3941 let enum_id = IntrinsicId::from_name("enumerate").unwrap();
3945 let env = {
3950 let insn = InstructionRef::from_mnemonic_with_type(
3951 &mut ctx,
3952 entry.func,
3953 Mnemonic::Intrinsic(IntrinsicApp {
3954 id: enum_id,
3955 args: vec![src.localize(entry.func)],
3956 }),
3957 list_ty,
3958 )
3959 .id;
3960 BasicBlock::from_id_mut(&mut ctx, entry).push_insn(insn);
3961 ValueId::Instruction(insn)
3962 };
3963 let ptr = ctx.get_const(0, 8).id();
3964 {
3965 let mut b = ctx.builder(entry);
3966 b.push_return(ptr);
3967 }
3968 let rid = BasicBlock::from_id(&ctx, entry).iter().last().unwrap().id;
3969 ctx.replace_instruction_mnemonic(
3970 rid,
3971 Mnemonic::Return(Return {
3972 ptr: ptr.localize(rid.func),
3973 value: Some(env.localize(rid.func)),
3974 }),
3975 );
3976
3977 let mut emu = StandaloneEmulator::new(entry);
3978 let err = emu
3979 .run_pure(&ctx, f, &[SizedValue::new(0, 4)], 1000)
3980 .expect_err("enumerate must not be emulated");
3981 assert!(
3982 matches!(err.kind, EmulatorErrorKind::UnsupportedIntrinsic(ref n) if &**n == "enumerate"),
3983 "expected recoverable UnsupportedIntrinsic, got {:?}",
3984 err.kind
3985 );
3986 }
3987
3988 fn run_at_over_array_param(n: usize, idx: u64, bound: SizedValue) -> Option<u64> {
3992 use qcode::value::{
3993 BasicBlock, FunctionBody, ValueId,
3994 insn::{IntrinsicId, Return},
3995 };
3996
3997 let mut ctx = Context::new();
3998 let arr_ty = {
3999 let i8 = ctx.shared.types.get_or_make_int(1);
4000 ctx.shared.types.get_or_make_array(i8, n)
4001 };
4002 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
4003 let entry = ctx.get_or_make_block(0x1000, f);
4004 {
4005 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
4006 fm.set_root(entry).unwrap();
4007 fm.add_block(entry);
4008 }
4009 let arr_pid = BasicBlock::from_id_mut(&mut ctx, entry).push_param(n).id;
4010 ctx.block_param_mut(arr_pid).type_id = arr_ty;
4011
4012 let at_id = IntrinsicId::from_name("at").unwrap();
4013 let (ret, ptr, lane);
4014 {
4015 let mut b = ctx.builder(entry);
4016 let arr = ValueId::BlockParam(arr_pid);
4017 let i = b.shr().get_const(idx, 8);
4018 lane = b.push_intrinsic(at_id, vec![arr, i]).id();
4019 ptr = b.shr().get_const(0, 8);
4020 ret = b.push_return(ptr).id();
4021 }
4022 let ValueId::Instruction(rid) = ret else {
4023 unreachable!()
4024 };
4025 ctx.replace_instruction_mnemonic(
4026 rid,
4027 Mnemonic::Return(Return {
4028 ptr: ptr.localize(rid.func),
4029 value: Some(lane.localize(rid.func)),
4030 }),
4031 );
4032
4033 let mut emu = StandaloneEmulator::new(entry);
4034 emu.run_pure(&ctx, f, &[bound], 1000).ok()?;
4035 emu.get_value(&ctx, lane)
4036 }
4037
4038 fn run_switch(scrutinee: u64) -> Option<u64> {
4042 let mut ctx = Context::new();
4043 qcode!(
4044 ctx,
4045 "
4046 lambda sw:
4047 <entry @i:i64>
4048 switch @i { 0x0 => <a>, 0x3 => <b @v=0x63>, default => <d> };
4049 <a>
4050 return 0x11;
4051 <b @v:i64>
4052 return @v;
4053 <d>
4054 return 0x99;
4055 "
4056 );
4057 let root = FunctionBody::from_id(&ctx, sw).root().expect("root").id;
4058 let mut emu = StandaloneEmulator::new(root);
4059 emu.run_pure(&ctx, sw, &[SizedValue::new(scrutinee, 8)], 1000)
4060 .ok()?;
4061 let term = BasicBlock::from_id(&ctx, emu.block)
4062 .instruction_ids()
4063 .last()
4064 .copied()?;
4065 let Mnemonic::ReturnValue(r) = Instruction::from_id(&ctx, term).mnemonic() else {
4066 return None;
4067 };
4068 emu.get_value(&ctx, r.value.qualify(term.func))
4069 }
4070
4071 #[test]
4072 fn switch_selects_the_matching_arm() {
4073 assert_eq!(run_switch(0), Some(0x11));
4074 assert_eq!(run_switch(3), Some(0x63));
4076 assert_eq!(run_switch(7), Some(0x99));
4078 }
4079
4080 #[test]
4084 fn run_pure_reads_array_param_bytes_little_endian() {
4085 let arg = SizedValue::new(0x2f76bfc2, 4);
4086 assert_eq!(run_at_over_array_param(4, 0, arg), Some(0xc2));
4088 assert_eq!(run_at_over_array_param(4, 1, arg), Some(0xbf));
4089 assert_eq!(run_at_over_array_param(4, 2, arg), Some(0x76));
4090 assert_eq!(run_at_over_array_param(4, 3, arg), Some(0x2f));
4091 }
4092
4093 #[test]
4097 fn run_pure_rejects_oversize_array_param() {
4098 assert_eq!(
4101 run_at_over_array_param(20, 0, SizedValue::new(0xff, 20)),
4102 None
4103 );
4104 }
4105
4106 #[test]
4107 fn int_mul_wraps_for_64_bit_values() {
4108 let lhs = SizedValue::new(u64::MAX, 8);
4109 let rhs = SizedValue::new(2, 8);
4110
4111 let product = lhs.int_mul(&rhs).unwrap();
4112
4113 assert_eq!(product.value().unwrap(), u64::MAX.wrapping_mul(2));
4114 assert_eq!(product.size().unwrap(), 8);
4115 }
4116
4117 #[test]
4118 fn int_mul_wraps_for_128_bit_values() {
4119 let lhs = SizedValue::from_bits(u128::MAX, 16);
4120 let rhs = SizedValue::from_bits(u128::from(2u8), 16);
4121
4122 let product = lhs.int_mul(&rhs).unwrap();
4123
4124 assert_eq!(product.as_bits(), u128::MAX.wrapping_mul(u128::from(2u8)));
4125 assert_eq!(product.size().unwrap(), 16);
4126 assert!(matches!(
4127 product.value(),
4128 Err(EmulatorErrorKind::ValueError(_))
4129 ));
4130 }
4131
4132 #[test]
4133 fn int_div_and_rem_work_for_128_bit_values() {
4134 let lhs = SizedValue::from_bits(u128::MAX, 16);
4135 let rhs = SizedValue::from_bits(u128::from(3u8), 16);
4136
4137 let q = lhs.int_div(&rhs).unwrap();
4138 let r = lhs.int_rem(&rhs).unwrap();
4139
4140 assert_eq!(q.as_bits(), u128::MAX / u128::from(3u8));
4141 assert_eq!(r.as_bits(), u128::MAX % u128::from(3u8));
4142 assert_eq!(q.size().unwrap(), 16);
4143 assert_eq!(r.size().unwrap(), 16);
4144 }
4145
4146 #[test]
4147 fn int_sdiv_and_srem_work_for_128_bit_values() {
4148 let lhs = SizedValue::from_bits(u128::from(0xffff_ffff_ffff_ffffu64), 16);
4149 let rhs = SizedValue::from_bits(u128::from(2u8), 16);
4150
4151 let q = lhs.int_sdiv(&rhs).unwrap();
4152 let r = lhs.int_srem(&rhs).unwrap();
4153
4154 assert_eq!(q.as_bits(), u128::from(0x7fff_ffff_ffff_ffffu64));
4155 assert_eq!(r.as_bits(), u128::from(1u8));
4156 assert_eq!(q.size().unwrap(), 16);
4157 assert_eq!(r.size().unwrap(), 16);
4158 }
4159
4160 #[test]
4161 fn signed_extension_and_shift_behave_as_expected() {
4162 let negative_byte = SizedValue::new(0x80, 1);
4163 let extended = negative_byte.sext(8).unwrap();
4164 let shifted = negative_byte
4165 .int_sshift_right(&SizedValue::new(1, 1))
4166 .unwrap();
4167
4168 assert_eq!(extended.value().unwrap(), 0xffff_ffff_ffff_ff80);
4169 assert_eq!(extended.size().unwrap(), 8);
4170 assert_eq!(shifted.value().unwrap(), 0xc0);
4171 assert_eq!(shifted.size().unwrap(), 1);
4172 }
4173
4174 #[test]
4175 fn signed_comparisons_use_value_width() {
4176 let lhs = SizedValue::new(0xff, 1);
4177 let rhs = SizedValue::new(0x01, 1);
4178
4179 assert_eq!(lhs.int_sless(&rhs).and_then(|v| v.value()).unwrap(), 1);
4180 assert_eq!(rhs.int_sless(&lhs).and_then(|v| v.value()).unwrap(), 0);
4181 }
4182
4183 #[test]
4184 fn int_sub_uses_lhs_width_with_default_u64_immediate() {
4185 let lhs = SizedValue::new(0, 4);
4186 let rhs = SizedValue::from_u64(1);
4187
4188 let diff = lhs.int_sub(&rhs).unwrap();
4189
4190 assert_eq!(diff.size().unwrap(), 4);
4191 assert_eq!(diff.value().unwrap(), 0xffff_ffff);
4192 }
4193
4194 #[test]
4195 fn sborrow_uses_lhs_width_with_default_u64_immediate() {
4196 let lhs = SizedValue::new(0x80, 1);
4197 let rhs = SizedValue::new(1, 1);
4198
4199 assert_eq!(lhs.sborrow(&rhs).and_then(|v| v.value()).unwrap(), 1);
4201 }
4202
4203 #[test]
4204 fn scarry_uses_lhs_width_with_default_u64_immediate() {
4205 let lhs = SizedValue::new(0x7f, 1);
4206 let rhs = SizedValue::new(1, 1);
4207
4208 assert_eq!(lhs.scarry(&rhs).and_then(|v| v.value()).unwrap(), 1);
4210 }
4211
4212 #[test]
4213 fn sborrow_neg() {
4214 let lhs = SizedValue::new(0x0, 1);
4215 let rhs = SizedValue::new(0x80, 1);
4216
4217 assert_eq!(lhs.sborrow(&rhs).and_then(|v| v.value()).unwrap(), 1);
4219 }
4220
4221 #[test]
4222 fn lz_count_respects_width() {
4223 let value = SizedValue::new(0x01, 1);
4224 let lz = value.lz_count().unwrap();
4225
4226 assert_eq!(lz.value().unwrap(), 7);
4227 assert_eq!(lz.size().unwrap(), 1);
4228 }
4229
4230 #[test]
4231 fn float_conversion_handles_f32_and_f64() {
4232 let minus_one = SizedValue::new(0xff, 1);
4233 let as_f32 = minus_one.int_to_float(4).unwrap();
4234 assert_eq!(as_f32.value().unwrap(), (-1.0f32).to_bits() as u64);
4235 assert_eq!(as_f32.size().unwrap(), 4);
4236
4237 let f32_value = SizedValue::new((1.5f32).to_bits() as u64, 4);
4238 let promoted = f32_value.float_to_float(8).unwrap();
4239 let promoted_bits = promoted.value().unwrap();
4240 assert_eq!(f64::from_bits(promoted_bits), 1.5f64);
4241 assert_eq!(promoted.size().unwrap(), 8);
4242
4243 let demoted = promoted.float_to_float(4).unwrap();
4244 assert_eq!(demoted.value().unwrap(), (1.5f32).to_bits() as u64);
4245 assert_eq!(demoted.size().unwrap(), 4);
4246 }
4247
4248 #[test]
4249 fn x87_precision_and_store_rounding_are_separate_from_generic_arithmetic() {
4250 let one = 0x3fff_8000_0000_0000_0000u128;
4251 let one_plus_half_single_ulp = one + (1u128 << 39);
4254 assert_eq!(
4255 float80::round_to_precision(one_plus_half_single_ulp, 24, Round::NearestTiesToEven)
4256 .bits,
4257 one
4258 );
4259 assert_eq!(
4260 float80::round_to_precision(one_plus_half_single_ulp, 24, Round::TowardPositive).bits,
4261 one + (1u128 << 40)
4262 );
4263 assert_eq!(
4265 float80::round_to_precision(one_plus_half_single_ulp, 64, Round::TowardPositive).bits,
4266 one_plus_half_single_ulp
4267 );
4268
4269 let extended = SizedValue::from_bits(one_plus_half_single_ulp, 10);
4273 assert_eq!(
4274 StandaloneEmulator::<EmulatedMemory>::ieee_narrow(
4275 extended,
4276 4,
4277 Round::NearestTiesToEven
4278 )
4279 .unwrap()
4280 .0
4281 .as_bits(),
4282 u128::from(1.0f32.to_bits())
4283 );
4284 assert_eq!(
4285 StandaloneEmulator::<EmulatedMemory>::ieee_narrow(extended, 4, Round::TowardPositive)
4286 .unwrap()
4287 .0
4288 .as_bits(),
4289 u128::from((1.0f32).to_bits() + 1)
4290 );
4291
4292 let mut ctx = Context::new();
4296 qcode!(
4297 ctx,
4298 "
4299 varnode i16 FPUControlWord;
4300 varnode i16 FPUStatusWord;
4301 varnode f80 A;
4302 varnode f80 B;
4303
4304 <block>
4305 %a = load(A:10, &A);
4306 %b = load(B:10, &B);
4307 %result = %a f/ %b;
4308 goto <0x1001>;
4309 "
4310 );
4311 let mut emu = Emulator::from_block(&ctx, block);
4312 emu.set_varnode(FPUControlWord, 0x037b).unwrap(); emu.set_varnode_u128(A, one).unwrap();
4314 emu.set_varnode_u128(B, 0).unwrap();
4315 emu.run_block().unwrap();
4316 assert_eq!(emu.get_value(result.into()).unwrap().size().unwrap(), 10);
4317 assert_eq!(emu.read_varnode(FPUStatusWord), None);
4319 }
4320
4321 #[test]
4325 fn f80_comparison_records_no_status() {
4326 let mut ctx = Context::new();
4327 qcode!(
4328 ctx,
4329 "
4330 varnode i16 FPUControlWord;
4331 varnode i16 FPUStatusWord;
4332 varnode f80 A;
4333 varnode f80 B;
4334
4335 <block>
4336 %a = load(A:10, &A);
4337 %b = load(B:10, &B);
4338 %equal = %a f== %b;
4339 goto <0x1001>;
4340 "
4341 );
4342 let mut emu = Emulator::from_block(&ctx, block);
4343 emu.set_varnode(FPUControlWord, 0x037f).unwrap();
4344 emu.set_varnode_u128(A, 0x7fff_8000_0000_0000_0001).unwrap();
4347 emu.set_varnode_u128(B, 0x3fff_8000_0000_0000_0000).unwrap();
4348 emu.run_block().unwrap();
4349 assert_eq!(emu.get_value(equal.into()).unwrap().value().unwrap(), 0);
4350 assert_eq!(emu.read_varnode(FPUStatusWord), None);
4351 }
4352
4353 #[test]
4358 fn float80_partial_remainder_is_exact() {
4359 let dividend = 0x7ffe_ffff_ffff_ffff_ffffu128;
4360 let one = 0x3fff_8000_0000_0000_0000u128;
4361 for ieee in [false, true] {
4362 let result = float80::remainder(dividend, one, ieee);
4363 assert!(result.incomplete);
4364 assert_eq!(result.bits, 0);
4365 }
4366
4367 let half = 0x3ffe_8000_0000_0000_0000u128;
4371 let result = float80::remainder(dividend, half, false);
4372 assert!(result.incomplete);
4373 assert_eq!(result.bits, 0x7fdd_ffff_fffe_0000_0000);
4374
4375 let three = 0x4000_c000_0000_0000_0000u128;
4378 let result = float80::remainder(three, one, false);
4379 assert!(!result.incomplete);
4380 assert_eq!(result.bits, 0);
4381 assert_eq!(result.quotient & 7, 3);
4382 }
4383
4384 #[test]
4387 fn float80_sqrt_is_correctly_rounded_at_extended_precision() {
4388 let two = 0x4000_8000_0000_0000_0000;
4389 let four = 0x4001_8000_0000_0000_0000;
4390 let one = 0x3fff_8000_0000_0000_0000;
4391
4392 let root_two = float80::sqrt_ieee(two, Round::NearestTiesToEven);
4394 assert_eq!(root_two.bits, 0x3fff_b504_f333_f9de_6484);
4395 assert!(root_two.status.contains(Status::INEXACT));
4396
4397 for (input, expect) in [(four, two), (one, one), (0, 0)] {
4399 let result = float80::sqrt_ieee(input, Round::NearestTiesToEven);
4400 assert_eq!(result.bits, expect);
4401 assert_eq!(result.status, Status::OK);
4402 }
4403
4404 let three = 0x4000_c000_0000_0000_0000;
4407 assert_eq!(
4408 float80::sqrt_ieee(three, Round::NearestTiesToEven).bits,
4409 0x3fff_ddb3_d742_c265_539e
4410 );
4411 assert_eq!(
4412 float80::sqrt_ieee(three, Round::TowardZero).bits,
4413 0x3fff_ddb3_d742_c265_539d
4414 );
4415
4416 let negative = float80::sqrt_ieee(0xbfff_8000_0000_0000_0000, Round::NearestTiesToEven);
4419 assert_eq!(negative.bits, 0xbfff_8000_0000_0000_0000);
4420 assert!(negative.status.contains(Status::INVALID_OP));
4421 }
4422
4423 #[test]
4424 fn float80_arithmetic_preserves_extended_precision_bits() {
4425 let one = SizedValue::from_bits(0x3fff_8000_0000_0000_0000, 10);
4429 let two = SizedValue::from_bits(0x4000_8000_0000_0000_0000, 10);
4430 let three = one.float_add(&two).unwrap();
4431
4432 assert_eq!(three.as_bits(), 0x4000_c000_0000_0000_0000);
4433 assert_eq!(three.size().unwrap(), 10);
4434 assert_eq!(two.float_to_float(10).unwrap().as_bits(), two.as_bits());
4435 assert_eq!(
4436 SizedValue::new(3, 1).int_to_float(10).unwrap().as_bits(),
4437 three.as_bits()
4438 );
4439 }
4440
4441 #[test]
4442 fn explicit_ieee_arithmetic_pairs_results_and_flags_in_every_rounding_mode() {
4443 let cases = [
4448 (
4449 4,
4450 0x3f80_0000,
4451 0x3380_0000,
4452 0x3f80_0001,
4453 0x3fc0_0000,
4454 0x3f80_0000,
4455 0x4040_0000,
4456 ),
4457 (
4458 8,
4459 0x3ff0_0000_0000_0000,
4460 0x3ca0_0000_0000_0000,
4461 0x3ff0_0000_0000_0001,
4462 0x3ff8_0000_0000_0000,
4463 0x3ff0_0000_0000_0000,
4464 0x4008_0000_0000_0000,
4465 ),
4466 (
4467 10,
4468 0x3fff_8000_0000_0000_0000,
4469 0x3fbf_8000_0000_0000_0000,
4470 0x3fff_8000_0000_0000_0001,
4471 0x3fff_c000_0000_0000_0000,
4472 0x3fff_8000_0000_0000_0000,
4473 0x4000_c000_0000_0000_0000,
4474 ),
4475 ];
4476 let operations = [
4477 ("float_add", "float_add_flags", 0usize),
4478 ("float_sub", "float_sub_flags", 1),
4479 ("float_mul", "float_mul_flags", 2),
4480 ("float_div", "float_div_flags", 3),
4481 ];
4482
4483 for (size, add_lhs, add_rhs, mul_lhs, mul_rhs, div_lhs, div_rhs) in cases {
4484 let sub_rhs = match size {
4487 4 => 0x3300_0000,
4488 8 => 0x3c90_0000_0000_0000,
4489 10 => 0x3fbe_8000_0000_0000_0000,
4490 _ => unreachable!(),
4491 };
4492 let operands = [
4493 (add_lhs, add_rhs),
4494 (add_lhs, sub_rhs),
4495 (mul_lhs, mul_rhs),
4496 (div_lhs, div_rhs),
4497 ];
4498 for (result_name, flags_name, pair) in operations {
4499 let (lhs, rhs) = operands[pair];
4500 for mode in 0..4 {
4501 let round =
4502 StandaloneEmulator::<EmulatedMemory>::ieee_rounding_mode(mode).unwrap();
4503 let (result, status) = StandaloneEmulator::<EmulatedMemory>::ieee_arithmetic(
4504 SizedValue::from_bits(lhs, size),
4505 SizedValue::from_bits(rhs, size),
4506 round,
4507 result_name,
4508 )
4509 .unwrap();
4510 let (_, flag_status) = StandaloneEmulator::<EmulatedMemory>::ieee_arithmetic(
4511 SizedValue::from_bits(lhs, size),
4512 SizedValue::from_bits(rhs, size),
4513 round,
4514 flags_name,
4515 )
4516 .unwrap();
4517 assert_eq!(
4518 status,
4519 flag_status,
4520 "{result_name}, f{}, mode {mode}",
4521 size * 8
4522 );
4523 let flags = StandaloneEmulator::<EmulatedMemory>::ieee_flags(flag_status);
4524 assert_ne!(
4525 flags.as_bits() & (1 << 5),
4526 0,
4527 "{result_name}, f{}, mode {mode}",
4528 size * 8
4529 );
4530 assert_eq!(result.size as usize, size);
4531 }
4532 }
4533 }
4534 }
4535
4536 #[test]
4537 fn simple_addition() {
4538 let mut ctx = Context::new();
4539
4540 qcode!(
4541 ctx,
4542 "
4543 varnode i64 V0;
4544 varnode i64 V1;
4545
4546 <block>
4547 %v0 = load(V0:8, &V0);
4548 %v1 = load(V1:8, &V1);
4549 %res = %v0 + %v1;
4550 goto <0x1001>;
4551 "
4552 );
4553
4554 let mut emu = Emulator::from_block(&ctx, block);
4555 emu.set_varnode(V0, 2).unwrap();
4556 emu.set_varnode(V1, 3).unwrap();
4557 emu.run_block().unwrap();
4558
4559 assert_eq!(
4560 emu.get_value(res.into()).and_then(|v| v.value()).unwrap(),
4561 5
4562 );
4563 }
4564
4565 #[test]
4566 fn gep_emulates_as_base_plus_offset() {
4567 let mut ctx = Context::new();
4568
4569 qcode!(
4571 ctx,
4572 "
4573 type Inner { _: 8, val: 4 };
4574 varnode i64 V0;
4575
4576 <block>
4577 Inner* %p = load(V0:8, &V0);
4578 %fld = gep(%p.val);
4579 goto <0x1001>;
4580 "
4581 );
4582
4583 let mut emu = Emulator::from_block(&ctx, block);
4584 emu.set_varnode(V0, 0x1000).unwrap();
4585 emu.run_block().unwrap();
4586
4587 let fld = emu.get_value(fld.into()).unwrap();
4588 assert_eq!(fld.value().unwrap(), 0x1008);
4589 assert_eq!(fld.size().unwrap(), 8);
4591 }
4592
4593 #[test]
4594 fn emulator_int_div_works_with_128_bit_operands() {
4595 let mut ctx = Context::new();
4596 qcode!(
4597 ctx,
4598 "
4599 varnode i128 V0;
4600 varnode i128 V1;
4601
4602 <block>
4603 %v0 = load(V0:16, &V0);
4604 %v1 = load(V1:16, &V1);
4605
4606 %res = %v0 / %v1;
4607 goto <0x1001>;
4608 "
4609 );
4610
4611 let mut emu = Emulator::from_block(&ctx, block);
4612 let v0_bits = u128::from(1u8) << 100;
4613 let v1_bits = u128::from(1u8) << 99;
4614
4615 emu.set_varnode_u128(V0, v0_bits).unwrap();
4616 emu.set_varnode_u128(V1, v1_bits).unwrap();
4617 emu.run_block().unwrap();
4618
4619 assert_eq!(
4621 emu.get_value(res.into()).and_then(|v| v.value()).unwrap(),
4622 2
4623 );
4624 }
4625
4626 #[test]
4631 fn uninitialized_memory_reads_error() {
4632 let space = EmulatedSpace::default();
4633 assert!(matches!(
4634 space.read_byte(0xdead_beef),
4635 Err(EmulatorErrorKind::MemoryReadError(0xdead_beef))
4636 ));
4637 assert!(matches!(
4638 space.read(0x1000, 4),
4639 Err(EmulatorErrorKind::MemoryReadError(0x1000))
4640 ));
4641 }
4642
4643 #[test]
4644 fn configured_register_and_body_temporary_spaces_zero_fill_missing_bytes() {
4645 let mut ctx = Context::new();
4646 let mut register = Space::new(Some("register"), 1, 8);
4647 register.ty = SpaceType::Register;
4648 let register = ctx.add_space(register);
4649 let function = ctx.anon_function();
4650 let temporary = MemorySpaceId::Temp(ctx.bodies[function].push_temp_space(TempSpace::new(
4651 Some("scratch"),
4652 1,
4653 8,
4654 )));
4655 let mut memory = EmulatedMemory::default();
4656 memory.configure_spaces(&ctx);
4657
4658 for space in [register.into(), temporary] {
4659 assert_eq!(
4660 memory
4661 .read(space, SizedValue::from_u64(0x1000), 4)
4662 .unwrap()
4663 .value()
4664 .unwrap(),
4665 0
4666 );
4667 }
4668
4669 memory
4670 .write(
4671 ctx.shared.default_space.into(),
4672 SizedValue::from_u64(0x1000),
4673 1,
4674 SizedValue::new(0xaa, 1),
4675 )
4676 .unwrap();
4677 assert!(matches!(
4678 memory.read(
4679 ctx.shared.default_space.into(),
4680 SizedValue::from_u64(0x1001),
4681 1
4682 ),
4683 Err(EmulatorErrorKind::MemoryReadError(0x1001))
4684 ));
4685 }
4686
4687 #[test]
4688 fn temporary_spaces_with_the_same_address_are_isolated() {
4689 use qcode::value::TempSpace;
4690
4691 let mut ctx = Context::new();
4692 let first_fn = FunctionBody::make(&mut ctx, "first".into()).unwrap().id;
4693 let second_fn = FunctionBody::make(&mut ctx, "second".into()).unwrap().id;
4694 let first = ctx.bodies[first_fn].push_temp_space(TempSpace::new(None, 1, 8));
4695 let second = ctx.bodies[second_fn].push_temp_space(TempSpace::new(None, 1, 8));
4696 assert_eq!(first.local, second.local, "fixture must collide local IDs");
4697 let first = MemorySpaceId::Temp(first);
4698 let second = MemorySpaceId::Temp(second);
4699 let mut memory = EmulatedMemory::default();
4700 memory.configure_spaces(&ctx);
4701
4702 let address = SizedValue::from_u64(0x20);
4703 memory
4704 .write(first, address, 1, SizedValue::new(0xaa, 1))
4705 .unwrap();
4706 memory
4707 .write(second, address, 1, SizedValue::new(0x55, 1))
4708 .unwrap();
4709
4710 assert_eq!(
4711 memory.read(first, address, 1).unwrap().value().unwrap(),
4712 0xaa
4713 );
4714 assert_eq!(
4715 memory.read(second, address, 1).unwrap().value().unwrap(),
4716 0x55
4717 );
4718 }
4719
4720 #[test]
4721 fn interpreter_qualifies_colliding_local_spaces_by_function() {
4722 use qcode::value::TempSpace;
4723
4724 fn make_writer(
4725 ctx: &mut Context<'static>,
4726 name: &'static str,
4727 byte: u64,
4728 ) -> (FunctionId, qcode::value::TempSpaceId) {
4729 let fid = FunctionBody::make(ctx, name.into()).unwrap().id;
4730 let root = BasicBlock::make(ctx, fid).id;
4731 FunctionBody::from_id_mut(ctx, fid).set_root(root).unwrap();
4732 let space = ctx.bodies[fid].push_temp_space(TempSpace::new(None, 1, 8));
4733 let mut b = (ctx).builder(root);
4734 let ptr = b.shr().get_const(0x20, 8);
4735 let value = b.shr().get_const(byte, 1);
4736 b.push_store(
4737 value,
4738 ptr,
4739 qcode::space::LocalMemorySpaceId::Temp(space.local),
4740 );
4741 b.push_return(ptr);
4742 (fid, space)
4743 }
4744
4745 let mut ctx = Context::new();
4746 let (first, first_space) = make_writer(&mut ctx, "first", 0xaa);
4747 let (second, second_space) = make_writer(&mut ctx, "second", 0x55);
4748 assert_eq!(first_space.local, second_space.local);
4749
4750 let root = FunctionBody::from_id(&ctx, first).root().unwrap().id;
4751 let mut emulator = StandaloneEmulator::new(root);
4752 emulator.run_function(&ctx, first).unwrap();
4753 emulator.run_function(&ctx, second).unwrap();
4754
4755 let address = SizedValue::from_u64(0x20);
4756 assert_eq!(
4757 emulator
4758 .memory
4759 .read(MemorySpaceId::Temp(first_space), address, 1)
4760 .unwrap()
4761 .value()
4762 .unwrap(),
4763 0xaa
4764 );
4765 assert_eq!(
4766 emulator
4767 .memory
4768 .read(MemorySpaceId::Temp(second_space), address, 1)
4769 .unwrap()
4770 .value()
4771 .unwrap(),
4772 0x55
4773 );
4774 }
4775
4776 #[test]
4777 fn sized_value_byte_swap_preserves_width() {
4778 let value = SizedValue::new(0x1234, 2).byte_swap().unwrap();
4779 assert_eq!(value.value().unwrap(), 0x3412);
4780 assert_eq!(value.size().unwrap(), 2);
4781 }
4782
4783 #[test]
4784 fn swap_bytes_pcode_op_is_emulated() {
4785 let mut ctx = Context::new();
4786 let op = ctx.shared.pcode_ops.push(Box::from("swap_bytes"));
4787 let block_id = {
4788 let __f = ctx.anon_function();
4789 ctx.get_or_make_block(0x1000, __f)
4790 };
4791 let target = ctx.get_or_make_block(0x1001, block_id.func);
4792 let result = {
4793 let src = ctx.get_const(0x1234, 2).id();
4794 let mut builder = ctx.builder(block_id);
4795 let result = builder.push_pcode_op(op, vec![src], None, 2).id;
4796 builder.finalize(target);
4797 result
4798 };
4799 let mut emulator = Emulator::from_block(&ctx, block_id);
4800
4801 emulator.step().unwrap();
4802
4803 assert_eq!(
4804 emulator
4805 .get_value(result.into())
4806 .and_then(|value| value.value())
4807 .unwrap(),
4808 0x3412
4809 );
4810 }
4811
4812 #[test]
4813 fn undef_pcode_op_is_zero_at_its_declared_width() {
4814 let mut ctx = Context::new();
4815 let op = ctx.shared.pcode_ops.push(Box::from("undef"));
4816 let block_id = {
4817 let function = ctx.anon_function();
4818 ctx.get_or_make_block(0x1000, function)
4819 };
4820 let target = ctx.get_or_make_block(0x1001, block_id.func);
4821 let result = {
4822 let mut builder = ctx.builder(block_id);
4823 let result = builder.push_pcode_op(op, vec![], None, 1).id;
4824 builder.finalize(target);
4825 result
4826 };
4827 let mut emulator = Emulator::from_block(&ctx, block_id);
4828
4829 emulator.step().unwrap();
4830
4831 let value = emulator.get_value(result.into()).unwrap();
4832 assert_eq!(value.value().unwrap(), 0);
4833 assert_eq!(value.size().unwrap(), 1);
4834 }
4835
4836 #[test]
4837 fn rol_intrinsic_is_emulated() {
4838 use qcode::value::insn::IntrinsicId;
4839 let mut ctx = Context::new();
4840 let rol = IntrinsicId::from_name("rol").unwrap();
4841 let block_id = {
4842 let __f = ctx.anon_function();
4843 ctx.get_or_make_block(0x1000, __f)
4844 };
4845 let target = ctx.get_or_make_block(0x1001, block_id.func);
4846 let result = {
4847 let x = ctx.get_const(0x1234_5678, 4).id();
4848 let k = ctx.get_const(8, 4).id();
4849 let mut builder = ctx.builder(block_id);
4850 let result = builder.push_intrinsic(rol, vec![x, k]).id;
4851 builder.finalize(target);
4852 result
4853 };
4854 let mut emulator = Emulator::from_block(&ctx, block_id);
4855
4856 emulator.step().unwrap();
4857
4858 assert_eq!(
4859 emulator
4860 .get_value(result.into())
4861 .and_then(|value| value.value())
4862 .unwrap(),
4863 0x1234_5678u32.rotate_left(8) as u64,
4864 );
4865 }
4866
4867 #[test]
4868 fn unknown_pcode_op_returns_typed_error() {
4869 let mut ctx = Context::new();
4870 let op = ctx.shared.pcode_ops.push(Box::from("rdpmc"));
4871 let block_id = {
4872 let __f = ctx.anon_function();
4873 ctx.get_or_make_block(0x1000, __f)
4874 };
4875 let target = ctx.get_or_make_block(0x1001, block_id.func);
4876 {
4877 let mut builder = ctx.builder(block_id);
4878 builder.push_pcode_op(op, vec![], None, 0);
4879 builder.finalize(target);
4880 }
4881 let mut emulator = Emulator::from_block(&ctx, block_id);
4882
4883 let error = emulator.step().unwrap_err();
4884
4885 assert!(matches!(
4886 error.kind,
4887 EmulatorErrorKind::UnsupportedPCodeOp(operation) if operation.as_ref() == "rdpmc"
4888 ));
4889 }
4890
4891 #[test]
4892 fn get_region_overflow_does_not_panic() {
4893 let mut space = EmulatedSpace::default();
4894 assert!(matches!(
4896 space.get_mut_region(u64::MAX - 2, 8),
4897 Err(EmulatorErrorKind::AddressOverflow(_, _))
4898 ));
4899 }
4900
4901 #[test]
4906 fn run_function_returns_ok_for_trivial_function() {
4907 let mut ctx = Context::new();
4908 qcode!(
4909 ctx,
4910 "
4911 fn function:
4912 <entry>
4913 return at i64 0;
4914 "
4915 );
4916
4917 let mut emu = Emulator::from_function(&ctx, function);
4918 assert!(emu.run_function(function).is_ok());
4919 }
4920
4921 #[test]
4922 fn run_function_executes_instructions_before_return() {
4923 let mut ctx = Context::new();
4924 qcode!(
4925 ctx,
4926 "
4927 varnode i64 A;
4928 varnode i64 B;
4929
4930 fn function:
4931 <entry>
4932 %a = load(A:8, &A);
4933 %b = load(B:8, &B);
4934 %sum = %a + %b;
4935 return at i64 0;
4936 "
4937 );
4938
4939 let mut emu = Emulator::from_function(&ctx, function);
4940 emu.set_varnode(A, 7).unwrap();
4941 emu.set_varnode(B, 5).unwrap();
4942 emu.run_function(function).unwrap();
4943
4944 assert_eq!(
4945 emu.get_value(sum.into()).and_then(|v| v.value()).unwrap(),
4946 12
4947 );
4948 }
4949
4950 #[test]
4951 fn run_function_call_stack_empty_after_successful_return() {
4952 let mut ctx = Context::new();
4953
4954 qcode!(
4955 ctx,
4956 "
4957 varnode i64 A;
4958 varnode i64 B;
4959
4960 fn function:
4961 <entry>
4962 %a = load(A:8, &A);
4963 %b = load(B:8, &B);
4964 %sum = %a + %b;
4965 return at i64 0;
4966 "
4967 );
4968
4969 let mut emu = Emulator::from_function(&ctx, function);
4970 emu.set_varnode(A, 0).unwrap();
4971 emu.set_varnode(B, 0).unwrap();
4972 emu.run_function(function).unwrap();
4973
4974 assert!(emu.call_stack().is_empty());
4975 }
4976
4977 #[test]
4978 fn unhandled_direct_call_still_enters_callee() {
4979 let mut ctx = Context::new();
4980 qcode!(
4981 ctx,
4982 "
4983 fn callee:
4984 <callee_entry>
4985 return at i64 0;
4986
4987 <caller>
4988 call <callee>;
4989 "
4990 );
4991
4992 let mut emu = Emulator::from_block(&ctx, caller);
4993 emu.step().unwrap();
4994
4995 assert_eq!(emu.block().id, callee_entry);
4996 }
4997
4998 #[test]
4999 fn handled_direct_call_resumes_at_selected_block() {
5000 let mut ctx = Context::new();
5001 qcode!(
5002 ctx,
5003 "
5004 varnode i64 RET;
5005
5006 fn library:
5007 <library_entry>
5008 return at i64 0;
5009
5010 fn function:
5011 <entry>
5012 call <library>;
5013 <after_call>
5014 %ret = load(RET:8, &RET);
5015 return at i64 0;
5016 "
5017 );
5018
5019 let mut emu = Emulator::from_function(&ctx, function);
5020 emu.set_call_interceptor(move |ctx, emu, site| {
5021 if site.target == library {
5022 emu.set_varnode(ctx, RET, 42)
5023 .map_err(|err| err.to_string().into_boxed_str())?;
5024 Ok(CallInterception::Handled(CallContinuation::Block(
5025 after_call,
5026 )))
5027 } else {
5028 Ok(CallInterception::PassThrough)
5029 }
5030 });
5031
5032 emu.run_function(function).unwrap();
5033
5034 assert_eq!(
5035 emu.get_value(ret.into()).and_then(|v| v.value()).unwrap(),
5036 42
5037 );
5038 assert!(emu.call_stack().is_empty());
5039 }
5040
5041 #[test]
5042 fn handled_direct_call_can_resume_by_address() {
5043 let mut ctx = Context::new();
5044 qcode!(
5045 ctx,
5046 "
5047 fn library:
5048 <library_entry>
5049 return at i64 0;
5050
5051 <entry>
5052 call <library>;
5053 <0x2000>
5054 return at i64 0;
5055 "
5056 );
5057
5058 let mut emu = Emulator::from_block(&ctx, entry);
5059 emu.set_call_interceptor(move |_, _, site| {
5060 if site.target == library {
5061 Ok(CallInterception::Handled(CallContinuation::Address(0x2000)))
5062 } else {
5063 Ok(CallInterception::PassThrough)
5064 }
5065 });
5066
5067 emu.step().unwrap();
5068
5069 assert_eq!(emu.block().address(), Some(0x2000));
5070 }
5071
5072 #[test]
5073 fn handled_direct_call_reports_unknown_continuation_address() {
5074 let mut ctx = Context::new();
5075 qcode!(
5076 ctx,
5077 "
5078 fn library:
5079 <library_entry>
5080 return at i64 0;
5081
5082 <entry>
5083 call <library>;
5084 "
5085 );
5086
5087 let mut emu = Emulator::from_block(&ctx, entry);
5088 emu.set_call_interceptor(move |_, _, site| {
5089 if site.target == library {
5090 Ok(CallInterception::Handled(CallContinuation::Address(0xdead)))
5091 } else {
5092 Ok(CallInterception::PassThrough)
5093 }
5094 });
5095
5096 let err = emu.step().unwrap_err();
5097
5098 assert!(matches!(
5099 err.kind,
5100 EmulatorErrorKind::InvalidBlockAddress(0xdead)
5101 ));
5102 }
5103
5104 #[test]
5105 fn call_interceptor_errors_are_reported_at_call_site() {
5106 let mut ctx = Context::new();
5107 qcode!(
5108 ctx,
5109 "
5110 fn library:
5111 <library_entry>
5112 return at i64 0;
5113
5114 <entry>
5115 call <library>;
5116 "
5117 );
5118
5119 let mut emu = Emulator::from_block(&ctx, entry);
5120 emu.set_call_interceptor(|_, _, _| Err("model failed".into()));
5121
5122 let err = emu.step().unwrap_err();
5123
5124 assert!(matches!(
5125 err.kind,
5126 EmulatorErrorKind::InterceptError(message) if message.as_ref() == "model failed"
5127 ));
5128 assert!(err.ctx.contains("call fn library();"));
5129 }
5130
5131 #[test]
5132 fn interceptor_can_model_state_across_calls() {
5133 let mut ctx = Context::new();
5134 qcode!(
5135 ctx,
5136 "
5137 fn make_object:
5138 <make_object_entry>
5139 return at i64 0;
5140
5141 fn append_byte:
5142 <append_byte_entry>
5143 return at i64 0;
5144
5145 fn function:
5146 <entry>
5147 call <make_object>;
5148 <append>
5149 call <append_byte>;
5150 <done>
5151 return at i64 0;
5152 "
5153 );
5154
5155 let modeled = Arc::new(Mutex::new(Vec::<u8>::new()));
5156 let modeled_for_hook = Arc::clone(&modeled);
5157 let mut emu = Emulator::from_function(&ctx, function);
5158 emu.set_call_interceptor(move |_, _, site| {
5159 let mut model = modeled_for_hook.lock().unwrap();
5160 if site.target == make_object {
5161 model.clear();
5162 Ok(CallInterception::Handled(CallContinuation::Block(append)))
5163 } else if site.target == append_byte {
5164 model.push(0x41);
5165 Ok(CallInterception::Handled(CallContinuation::Block(done)))
5166 } else {
5167 Ok(CallInterception::PassThrough)
5168 }
5169 });
5170
5171 emu.run_function(function).unwrap();
5172
5173 assert_eq!(*modeled.lock().unwrap(), vec![0x41]);
5174 }
5175
5176 #[test]
5181 fn branchind_to_unknown_address_returns_error() {
5182 let mut ctx = Context::new();
5183 qcode!(
5184 ctx,
5185 "
5186 fn function:
5187 <entry>
5188 # Branching to literal 0 — no block lives at address 0
5189 goto [i64 0];
5190 "
5191 );
5192
5193 let mut emu = Emulator::from_function(&ctx, function);
5194 let err = emu.run_function(function).unwrap_err();
5195 assert!(matches!(
5196 err.kind,
5197 EmulatorErrorKind::InvalidBlockAddress(0)
5198 ));
5199 }
5200
5201 #[test]
5202 fn error_includes_faulting_instruction_id() {
5203 let mut ctx = Context::new();
5204 qcode!(
5205 ctx,
5206 "
5207 fn function:
5208 <entry>
5209 # Null pointer dereference
5210 %bad_load = load(ram:8, i64 0);
5211 return at i64 0;
5212 "
5213 );
5214
5215 let mut emu = Emulator::from_function(&ctx, function);
5216 let err = emu.run_function(function).unwrap_err();
5217
5218 assert!(
5219 err.ctx.contains(
5220 &Instruction::from_id(&ctx, bad_load)
5221 .as_statement()
5222 .to_string()
5223 )
5224 );
5225 }
5226
5227 #[test]
5228 fn error_call_stack_reflects_active_frames_at_fault() {
5229 let mut ctx = Context::new();
5231 qcode!(
5232 ctx,
5233 "
5234 fn callee:
5235 <entry1>
5236 # Branching to literal 0 — no block lives at address 0
5237 goto [i64 0];
5238
5239 fn caller:
5240 <entry2>
5241 call <callee>;
5242 "
5243 );
5244
5245 let mut emu = Emulator::from_function(&ctx, caller);
5247 let err = emu.run_function(caller).unwrap_err();
5248
5249 assert!(matches!(
5250 err.kind,
5251 EmulatorErrorKind::InvalidBlockAddress(0)
5252 ));
5253 assert_eq!(emu.call_stack(), &[caller, callee]);
5254 }
5255}