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 integral = name.starts_with("float_round_to_integral");
1954 let sticky = inexact && !integral;
1955 let kept = if integral {
1956 result.status
1957 } else {
1958 result.status & !Status::INEXACT
1959 };
1960 let (value, status) =
1961 match Self::narrow_with_sticky(result.bits, sticky, lhs.size, round) {
1962 Some((value, status)) => (value, status | kept),
1963 None => (
1964 SizedValue::from_bits(result.bits, lhs.size as usize),
1965 result.status,
1966 ),
1967 };
1968 return Ok(Some(if name.ends_with("_flags") {
1969 Self::ieee_flags(status)
1970 } else {
1971 value
1972 }));
1973 }
1974 }
1975
1976 let average = |width: usize| -> Option<SizedValue> {
1979 (lhs.size as usize == width && rhs.size as usize == width).then(|| {
1980 let sum = lhs.as_bits() + rhs.as_bits() + 1;
1981 SizedValue::from_bits(sum >> 1, width)
1982 })
1983 };
1984
1985 let value = match name.as_ref() {
1986 "pavgb" => average(1),
1987 "pavgw" => average(2),
1988 "pmulhuw" => Self::packed_lanes(&lhs, &rhs, 2, |a, b| ((a * b) >> 16) & 0xffff),
1990 "paddsb" => Self::saturating(&lhs, &rhs, 1, true, false),
1993 "paddsw" => Self::saturating(&lhs, &rhs, 2, true, false),
1994 "psubsb" => Self::saturating(&lhs, &rhs, 1, true, true),
1995 "psubsw" => Self::saturating(&lhs, &rhs, 2, true, true),
1996 "paddusb" => Self::saturating(&lhs, &rhs, 1, false, false),
1997 "paddusw" => Self::saturating(&lhs, &rhs, 2, false, false),
1998 "psubusb" => Self::saturating(&lhs, &rhs, 1, false, true),
1999 "psubusw" => Self::saturating(&lhs, &rhs, 2, false, true),
2000 "pmaddwd" => Self::packed_lanes(&lhs, &rhs, 4, |a, b| {
2002 let word =
2003 |v: u128, half: u32| i64::from(((v >> (half * 16)) & 0xffff) as u16 as i16);
2004 let product = word(a, 0) * word(b, 0) + word(a, 1) * word(b, 1);
2005 u128::from(product as u32)
2006 }),
2007 _ => None,
2008 };
2009 Ok(value)
2010 }
2011
2012 fn saturating(
2015 lhs: &SizedValue,
2016 rhs: &SizedValue,
2017 width: usize,
2018 signed: bool,
2019 subtract: bool,
2020 ) -> Option<SizedValue> {
2021 let bits = width * 8;
2022 Self::packed_lanes(lhs, rhs, width, |a, b| {
2023 if signed {
2024 let sign =
2025 |v: u128| (v as i128) - (((v >> (bits - 1)) & 1) as i128) * (1i128 << bits);
2026 let (a, b) = (sign(a), sign(b));
2027 let value = if subtract { a - b } else { a + b };
2028 let max = (1i128 << (bits - 1)) - 1;
2029 let min = -(1i128 << (bits - 1));
2030 (value.clamp(min, max) as u128) & ((1u128 << bits) - 1)
2031 } else if subtract {
2032 a.saturating_sub(b)
2033 } else {
2034 (a + b).min((1u128 << bits) - 1)
2035 }
2036 })
2037 }
2038
2039 fn packed_lanes(
2043 lhs: &SizedValue,
2044 rhs: &SizedValue,
2045 width: usize,
2046 lane: impl Fn(u128, u128) -> u128,
2047 ) -> Option<SizedValue> {
2048 let size = lhs.size as usize;
2049 if size != rhs.size as usize || size == 0 || !size.is_multiple_of(width) {
2050 return None;
2051 }
2052 let bits = width * 8;
2053 let mask = (1u128 << bits) - 1;
2054 let mut out = 0u128;
2055 for index in 0..size / width {
2056 let shift = index * bits;
2057 let a = (lhs.as_bits() >> shift) & mask;
2058 let b = (rhs.as_bits() >> shift) & mask;
2059 out |= (lane(a, b) & mask) << shift;
2060 }
2061 Some(SizedValue::from_bits(out, size))
2062 }
2063
2064 fn step_with_event(&mut self, ctx: &Context<'_>) -> crate::Result<StepEvent> {
2065 self.memory.configure_spaces(ctx);
2066 let block_id = self.block;
2067 if self.cached_block != Some(block_id) || self.idx == 0 {
2068 self.refresh_sequence_types(ctx);
2072 self.cached_insns.clear();
2073 self.cached_insns
2074 .extend_from_slice(ctx.block(block_id).instruction_ids());
2075 self.cached_block = Some(block_id);
2076 }
2077 let Some(&local) = self.cached_insns.get(self.idx) else {
2082 return Err(self.make_empty_block_error(ctx));
2083 };
2084 let insn_id = InstructionId::new(block_id.func, local);
2085 let insn = InstructionRef::from_id(ctx, insn_id);
2086 let id = insn.id;
2087
2088 if let Some(hook) = self.instruction_hook.as_ref() {
2089 hook(&insn, self)
2090 }
2091
2092 let mnemonic = insn.mnemonic();
2096
2097 match mnemonic {
2098 Mnemonic::Branch(Branch { target, args }) => {
2099 let target = BlockId::new(id.func, *target);
2102 self.bind_block_args(ctx, id.func, target, args)
2103 .map_err(|kind| self.make_error(ctx, kind))?;
2104 self.block = target;
2105 self.idx = 0;
2106 }
2107
2108 Mnemonic::Call(call) => {
2109 if let Some(event) = self.intercept_call(ctx, block_id, insn_id, call)? {
2110 return Ok(event);
2111 }
2112 let target =
2113 require_real_callee(call.target).map_err(|kind| self.make_error(ctx, kind))?;
2114 self.block = FunctionBody::from_id(ctx, target)
2115 .root()
2116 .ok_or_else(|| {
2117 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
2118 })?
2119 .id;
2120 self.idx = 0;
2121 self.call_site_stack.push(insn_id);
2124 return Ok(StepEvent::DirectCallEntered(target));
2125 }
2126
2127 Mnemonic::TailCall(tc) => {
2128 let target =
2133 require_real_callee(tc.target).map_err(|kind| self.make_error(ctx, kind))?;
2134 self.block = FunctionBody::from_id(ctx, target)
2135 .root()
2136 .ok_or_else(|| {
2137 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
2138 })?
2139 .id;
2140 self.idx = 0;
2141 }
2142
2143 Mnemonic::Apply(apply) => {
2144 const APPLY_STEP_BUDGET: usize = 100_000;
2145 let target =
2146 require_real_callee(apply.target).map_err(|kind| self.make_error(ctx, kind))?;
2147 let args = self
2148 .collect_block_args(ctx, id.func, &apply.args)
2149 .map_err(|kind| self.make_error(ctx, kind))?;
2150 let root = FunctionBody::from_id(ctx, target)
2151 .root()
2152 .ok_or_else(|| {
2153 self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(target))
2154 })?
2155 .id;
2156 let mut nested = StandaloneEmulator::<M>::new_in(root);
2157 nested
2158 .run_pure(ctx, target, &args, APPLY_STEP_BUDGET)
2159 .map_err(|e| self.make_error(ctx, e.kind))?;
2160 let ret_value = lambda_return_value(ctx, nested.current_block())
2161 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2162 if let Some(value) = nested.get_value(ctx, ret_value) {
2163 let size = ctx
2164 .stored_type_of(ret_value)
2165 .map(|ty| ctx.shared.types.size_of(ty))
2166 .unwrap_or(8);
2167 self.insn_values
2168 .insert(insn_id, SizedValue::new(value, size));
2169 } else if let ValueId::Instruction(ret_id) = ret_value
2170 && let Some(agg) = nested.aggregate_values.get(&ret_id).cloned()
2171 {
2172 self.aggregate_values.insert(insn_id, agg);
2177 }
2178 self.idx += 1;
2179 }
2180
2181 Mnemonic::CBranch(CBranch {
2182 condition,
2183 success_block: target,
2184 success_args,
2185 failure_block: fallthrough,
2186 failure_args,
2187 }) => {
2188 let cond_val = self.get_value(ctx, condition.qualify(id.func)).unwrap();
2189 let target = BlockId::new(id.func, *target);
2190 let fallthrough = BlockId::new(id.func, *fallthrough);
2191 if cond_val != 0 {
2192 self.bind_block_args(ctx, id.func, target, success_args)
2193 .map_err(|kind| self.make_error(ctx, kind))?;
2194 self.block = target;
2195 } else {
2196 self.bind_block_args(ctx, id.func, fallthrough, failure_args)
2197 .map_err(|kind| self.make_error(ctx, kind))?;
2198 self.block = fallthrough;
2199 }
2200 self.idx = 0;
2201 }
2202
2203 Mnemonic::Switch(switch) => {
2204 let value = self
2205 .get_value(ctx, switch.scrutinee.qualify(id.func))
2206 .unwrap();
2207 let arm = switch
2208 .cases
2209 .iter()
2210 .find(|case| case.value == value)
2211 .map(|case| (case.target, &case.args));
2212 let (target, args) = match arm
2213 .or_else(|| switch.default.map(|target| (target, &switch.default_args)))
2214 {
2215 Some(arm) => arm,
2216 None => {
2220 return Err(
2221 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(value))
2222 );
2223 }
2224 };
2225 let target = BlockId::new(id.func, target);
2226 self.bind_block_args(ctx, id.func, target, args)
2227 .map_err(|kind| self.make_error(ctx, kind))?;
2228 self.block = target;
2229 self.idx = 0;
2230 }
2231
2232 Mnemonic::BranchInd(BranchInd { 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 }
2240
2241 Mnemonic::CallInd(CallInd { ptr, .. }) => {
2242 let addr = self.get_value(ctx, ptr.qualify(id.func)).unwrap();
2243 let target = self.block_at(ctx, addr).ok_or_else(|| {
2244 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(addr))
2245 })?;
2246 self.block = target;
2247 self.idx = 0;
2248 self.call_site_stack.push(insn_id);
2249 return Ok(StepEvent::IndirectCallEntered);
2250 }
2251
2252 Mnemonic::Return(Return { ptr, value, .. }) => {
2253 if let Some(call_id) = self.call_site_stack.pop() {
2258 if let Some(LocalValueId::Instruction(src_local)) = value {
2259 let src = InstructionId::new(id.func, *src_local);
2260 if let Some(agg) = self.aggregate_values.get(&src).cloned() {
2261 self.aggregate_values.insert(call_id, agg);
2262 } else if let Some(scalar) = self.insn_values.get(&src).copied() {
2263 self.insn_values.insert(call_id, scalar);
2264 }
2265 }
2266 self.writeback_materialized_outputs(ctx, call_id, id.func);
2272 }
2273
2274 let addr = self.get_value(ctx, ptr.qualify(id.func)).unwrap();
2275 let target = self.block_at(ctx, addr).ok_or_else(|| {
2276 self.make_error(ctx, EmulatorErrorKind::InvalidBlockAddress(addr))
2277 })?;
2278 self.block = target;
2279 self.idx = 0;
2280 return Ok(StepEvent::Return);
2281 }
2282
2283 Mnemonic::ReturnValue(_) => {
2284 return Ok(StepEvent::ReturnValue);
2285 }
2286
2287 Mnemonic::Tuple(Tuple { fields }) => {
2291 let fields = fields.clone();
2292 let mut vals: Vec<SizedValue> = Vec::with_capacity(fields.len());
2293 for f in fields {
2294 let val = {
2295 let mut tmp = TempInterpreter {
2296 memory: &mut self.memory,
2297 literals: &mut self.literal_cache,
2298 insn_values: &mut self.insn_values,
2299 block_param_values: &mut self.block_param_values,
2300 poison_params: &self.poison_params,
2301 ctx,
2302 };
2303 tmp.get_value(f.qualify(id.func))
2304 };
2305 vals.push(val.map_err(|kind| self.make_error(ctx, kind))?);
2306 }
2307 self.aggregate_values.insert(insn_id, vals);
2308 self.idx += 1;
2309 }
2310
2311 Mnemonic::Extract(Extract { agg, index }) => {
2313 let field = match agg {
2314 LocalValueId::Instruction(agg_local) => self
2315 .aggregate_values
2316 .get(&InstructionId::new(id.func, *agg_local))
2317 .and_then(|v| v.get(*index))
2318 .copied(),
2319 LocalValueId::BlockParam(pid_local) => self
2322 .block_param_aggregates
2323 .get(&BlockParamId::new(id.func, *pid_local))
2324 .and_then(|v| v.get(*index))
2325 .copied(),
2326 _ => None,
2327 };
2328 if let Some(field) = field {
2329 self.insn_values.insert(insn_id, field);
2330 }
2331 self.idx += 1;
2332 }
2333
2334 Mnemonic::Load(load) if self.is_array_operand(ctx, ValueId::Instruction(insn_id)) => {
2339 let (space, ptr, size) = (load.space, load.ptr.qualify(id.func), load.size);
2340 let addr = self
2341 .get_value(ctx, ptr)
2342 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2343 let buf = self
2344 .read_memory(ctx, space.qualify(id.func), addr, size)
2345 .map_err(|kind| self.make_error(ctx, kind))?;
2346 self.array_values.insert(insn_id, buf);
2347 self.idx += 1;
2348 }
2349
2350 Mnemonic::Store(store)
2354 if self
2355 .register_range_store_address(ctx, id.func, store)
2356 .is_some() =>
2357 {
2358 let address = self
2359 .register_range_store_address(ctx, id.func, store)
2360 .expect("guard checked register range store address");
2361 let mut tmp = TempInterpreter {
2362 memory: &mut self.memory,
2363 literals: &mut self.literal_cache,
2364 insn_values: &mut self.insn_values,
2365 block_param_values: &mut self.block_param_values,
2366 poison_params: &self.poison_params,
2367 ctx,
2368 };
2369 let value = tmp.get_value(store.src.qualify(id.func));
2370 let value = value.map_err(|kind| self.make_error(ctx, kind))?;
2371 self.memory
2372 .write(
2373 store.space.qualify(id.func),
2374 SizedValue::from_u64(address),
2375 store.size,
2376 value,
2377 )
2378 .map_err(|kind| self.make_error(ctx, kind))?;
2379 self.idx += 1;
2380 }
2381
2382 Mnemonic::Store(store) if self.is_array_operand(ctx, store.src.qualify(id.func)) => {
2383 let (space, ptr, src) = (
2384 store.space,
2385 store.ptr.qualify(id.func),
2386 store.src.qualify(id.func),
2387 );
2388 let buf = self
2389 .resolve_array(ctx, src)
2390 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2391 let addr = self
2392 .get_value(ctx, ptr)
2393 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2394 self.write_memory(ctx, space.qualify(id.func), addr, &buf)
2395 .map_err(|kind| self.make_error(ctx, kind))?;
2396 self.idx += 1;
2397 }
2398
2399 Mnemonic::Scan(scan) => {
2403 let scan = scan.clone();
2404 self.eval_scan(ctx, insn_id, &scan)
2405 .map_err(|kind| self.make_error(ctx, kind))?;
2406 self.idx += 1;
2407 }
2408
2409 Mnemonic::Map(map) => {
2411 let map = map.clone();
2412 self.eval_map(ctx, insn_id, &map)
2413 .map_err(|kind| self.make_error(ctx, kind))?;
2414 self.idx += 1;
2415 }
2416
2417 Mnemonic::Range(range) if self.is_array_operand(ctx, range.src.qualify(id.func)) => {
2422 let (src, start, size) = (range.src.qualify(id.func), range.start, range.size);
2423 let buf = self
2424 .resolve_array(ctx, src)
2425 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::ValueError(0)))?;
2426 let end = (start + size).min(buf.len());
2427 let slice = buf.get(start..end).unwrap_or(&[]).to_vec();
2428 self.array_values.insert(insn_id, slice);
2429 self.idx += 1;
2430 }
2431
2432 Mnemonic::Intrinsic(app) if is_array_intrinsic(app.id.name()) => {
2437 let name = app.id.name();
2438 let args: Vec<ValueId> = app.args.iter().map(|a| a.qualify(id.func)).collect();
2439 self.eval_array_intrinsic(ctx, insn_id, name, &args)
2440 .map_err(|kind| self.make_error(ctx, kind))?;
2441 self.idx += 1;
2442 }
2443
2444 _ => {
2445 if let Some(value) = self
2446 .interpret_packed_pcode_op(ctx, &insn, mnemonic)
2447 .map_err(|kind| self.make_error(ctx, kind))?
2448 {
2449 self.insn_values.insert(id, value);
2450 self.idx += 1;
2451 return Ok(StepEvent::Normal);
2452 }
2453 let mut tmp = TempInterpreter {
2454 memory: &mut self.memory,
2455 literals: &mut self.literal_cache,
2456 insn_values: &mut self.insn_values,
2457 block_param_values: &mut self.block_param_values,
2458 poison_params: &self.poison_params,
2459 ctx,
2460 };
2461 if let Some(value) = tmp.interpret(insn, mnemonic)? {
2462 self.insn_values.insert(id, value);
2463 }
2464 self.idx += 1;
2465 }
2466 }
2467
2468 Ok(StepEvent::Normal)
2469 }
2470
2471 pub fn step(&mut self, ctx: &Context<'_>) -> crate::Result<()> {
2472 self.step_with_event(ctx).map(|_| ())
2473 }
2474
2475 pub fn run_block(&mut self, ctx: &Context<'_>) -> crate::Result<()> {
2476 loop {
2477 self.step(ctx)?;
2478 if self.idx == 0 {
2479 break;
2480 }
2481 }
2482 Ok(())
2483 }
2484
2485 pub fn run_until(&mut self, ctx: &Context<'_>, addr: u64) -> crate::Result<()> {
2487 let target = self
2488 .block_at(ctx, addr)
2489 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::UnknownAddress(addr)))?;
2490 while self.block != target {
2491 self.run_block(ctx)?;
2492 }
2493 Ok(())
2494 }
2495
2496 fn writeback_materialized_outputs(
2514 &mut self,
2515 ctx: &Context<'_>,
2516 call_id: InstructionId,
2517 callee: FunctionId,
2518 ) {
2519 if call_is_regpure(ctx, call_id) {
2520 return;
2521 }
2522 let outputs = match &FunctionBody::from_id(ctx, callee).effects().register {
2523 qcode::value::RegisterChannelState::Materialized(map) => map.outputs.clone(),
2524 _ => return,
2525 };
2526 let Some(agg) = self.aggregate_values.get(&call_id).cloned() else {
2527 return;
2528 };
2529 for (field, ®) in agg.iter().zip(&outputs) {
2530 let _ = self.set_varnode_u128(ctx, reg, field.as_bits());
2531 }
2532 }
2533
2534 fn seed_entry_params(&mut self, ctx: &Context<'_>, func: FunctionId) {
2535 let Some(root) = FunctionBody::from_id(ctx, func).root() else {
2536 return;
2537 };
2538 let root_id = root.id;
2539 enum Seed {
2540 Reg(VarnodeId),
2541 Lit(u64),
2547 }
2548 let params: Vec<(BlockParamId, Option<Seed>, usize)> = BasicBlock::from_id(ctx, root_id)
2549 .params()
2550 .map(|param| {
2551 let src = param
2552 .name()
2553 .and_then(|name| ctx.get_named(name))
2554 .and_then(|value| match value {
2555 ValueId::Varnode(id) => Some(Seed::Reg(id)),
2556 _ => None,
2557 })
2558 .or_else(|| match param.origin() {
2559 Some(ValueId::Literal(_)) => {
2560 let ValueRef::Literal(lit) = ValueRef::new(param.origin()?, ctx) else {
2561 return None;
2562 };
2563 Some(Seed::Lit(lit.value()))
2564 }
2565 _ => None,
2566 });
2567 (param.id, src, param.size())
2568 })
2569 .collect();
2570 for (param_id, src, size) in params {
2571 let value = match src {
2572 Some(Seed::Reg(varnode_id)) => self.read_varnode(ctx, varnode_id),
2573 Some(Seed::Lit(addr)) => {
2574 let space = ctx.shared.default_space;
2578 self.read_memory(ctx, space, addr, size).ok().map(|bytes| {
2579 let mut buf = [0u8; 8];
2580 let n = bytes.len().min(8);
2581 buf[..n].copy_from_slice(&bytes[..n]);
2582 u64::from_le_bytes(buf)
2583 })
2584 }
2585 None => None,
2586 };
2587 if let Some(value) = value {
2588 self.block_param_values
2589 .insert(param_id, SizedValue::new(value, size));
2590 }
2591 }
2592 }
2593
2594 fn bind_entry_params_from_args(
2606 &mut self,
2607 ctx: &Context<'_>,
2608 call_id: InstructionId,
2609 target: FunctionId,
2610 ) {
2611 let args = match ctx.get_insn(call_id).mnemonic() {
2612 Mnemonic::Call(call) => call.args.clone(),
2613 _ => return,
2614 };
2615 let Some(root) = FunctionBody::from_id(ctx, target).root() else {
2616 return;
2617 };
2618 let params: Vec<(BlockParamId, usize)> = BasicBlock::from_id(ctx, root.id)
2619 .params()
2620 .map(|p| (p.id, p.size()))
2621 .collect();
2622 if args.len() != params.len() {
2623 self.seed_entry_params(ctx, target);
2626 return;
2627 }
2628 let values: Vec<SizedValue> = args
2630 .iter()
2631 .zip(¶ms)
2632 .map(|(&arg, &(_, size))| {
2633 let raw = self.get_value(ctx, arg.qualify(call_id.func)).unwrap_or(0);
2634 SizedValue::new(raw, size)
2635 })
2636 .collect();
2637 for ((param_id, _), value) in params.into_iter().zip(values) {
2638 self.block_param_values.insert(param_id, value);
2639 }
2640 }
2641
2642 pub fn run_function(&mut self, ctx: &Context<'_>, func: FunctionId) -> crate::Result<()> {
2643 let root = FunctionBody::from_id(ctx, func)
2644 .root()
2645 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
2646 .id;
2647 self.block = root;
2648 self.idx = 0;
2649 self.call_stack.push(func);
2650 self.seed_entry_params(ctx, func);
2651
2652 let mut call_depth: i32 = 0;
2653
2654 let result = loop {
2655 let insn_ids = BasicBlock::from_id(ctx, self.block)
2656 .instruction_ids()
2657 .to_vec();
2658 let insn = InstructionRef::from_id(ctx, insn_ids[self.idx]);
2659
2660 if matches!(insn.mnemonic(), Mnemonic::Return(_)) && call_depth == 0 {
2661 break Ok(());
2662 }
2663
2664 match self.step_with_event(ctx)? {
2665 StepEvent::DirectCallEntered(target) => {
2666 call_depth += 1;
2667 self.call_stack.push(target);
2668 let regpure_site = self
2675 .call_site_stack
2676 .last()
2677 .copied()
2678 .is_some_and(|call_id| call_is_regpure(ctx, call_id));
2679 if regpure_site || FunctionBody::from_id(ctx, target).is_reg_materialized() {
2680 if let Some(&call_id) = self.call_site_stack.last() {
2681 self.bind_entry_params_from_args(ctx, call_id, target);
2682 }
2683 } else {
2684 self.seed_entry_params(ctx, target);
2685 }
2686 }
2687 StepEvent::IndirectCallEntered => {
2688 call_depth += 1;
2689 if let Some(parent) = BasicBlock::from_id(ctx, self.block).parent() {
2691 let callee = parent.id;
2692 self.call_stack.push(callee);
2693 self.seed_entry_params(ctx, callee);
2694 }
2695 }
2696 StepEvent::Return | StepEvent::ReturnValue => {
2697 self.call_stack.pop();
2698 call_depth -= 1;
2699 }
2700 StepEvent::Normal | StepEvent::InterceptedCall => {}
2701 }
2702 };
2703
2704 self.call_stack.pop(); result
2706 }
2707
2708 pub fn run_pure(
2719 &mut self,
2720 ctx: &Context<'_>,
2721 func: FunctionId,
2722 args: &[SizedValue],
2723 max_steps: usize,
2724 ) -> crate::Result<()> {
2725 let opts: Vec<Option<SizedValue>> = args.iter().map(|&v| Some(v)).collect();
2726 self.run_pure_partial(ctx, func, &opts, max_steps)
2727 }
2728
2729 pub fn run_pure_partial(
2736 &mut self,
2737 ctx: &Context<'_>,
2738 func: FunctionId,
2739 args: &[Option<SizedValue>],
2740 max_steps: usize,
2741 ) -> crate::Result<()> {
2742 let root = FunctionBody::from_id(ctx, func)
2743 .root()
2744 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
2745 .id;
2746 self.block = root;
2747 self.idx = 0;
2748 self.call_stack.push(func);
2749
2750 let param_ids: Vec<BlockParamId> = BasicBlock::from_id(ctx, root)
2753 .params()
2754 .map(|p| p.id)
2755 .collect();
2756 for (param_id, arg) in param_ids.into_iter().zip(args) {
2757 match arg {
2758 Some(value) => {
2759 self.block_param_values.insert(param_id, *value);
2760 }
2761 None => {
2762 self.poison_params.insert(param_id);
2763 }
2764 }
2765 }
2766
2767 self.drive_to_return(ctx, root, func, max_steps)
2768 }
2769
2770 fn refresh_sequence_types(&mut self, ctx: &Context<'_>) {
2781 let published = ctx.shared.types.published_len();
2782 if self.sequence_types_checked_at == Some(published) {
2783 return;
2784 }
2785 self.sequence_types = ctx.shared.types.has_sequence_types();
2786 self.sequence_types_checked_at = Some(published);
2787 }
2788
2789 fn is_array_operand(&self, ctx: &Context<'_>, id: ValueId) -> bool {
2790 if !self.sequence_types {
2792 return false;
2793 }
2794 match ctx.stored_type_of(id) {
2795 Some(ty) => {
2796 ctx.shared.types.array_of(ty).is_some() || ctx.shared.types.list_of(ty).is_some()
2797 }
2798 None => false,
2799 }
2800 }
2801
2802 fn resolve_array(&mut self, ctx: &Context<'_>, id: ValueId) -> Option<Vec<u8>> {
2806 match id {
2807 ValueId::Bytes(b) => Some(ctx.shared.values.bytes[b].data.clone()),
2808 ValueId::Instruction(i) => self
2809 .array_values
2810 .get(&i)
2811 .cloned()
2812 .or_else(|| self.get_value_bytes(ctx, id)),
2813 ValueId::Literal(_) => self.get_value_bytes(ctx, id),
2814 ValueId::BlockParam(_) => {
2820 let bytes = self.get_value_bytes(ctx, id)?;
2821 let ty_size = ctx
2822 .stored_type_of(id)
2823 .map(|ty| ctx.shared.types.size_of(ty))?;
2824 (bytes.len() == ty_size).then_some(bytes)
2825 }
2826 _ => None,
2827 }
2828 }
2829
2830 fn eval_array_intrinsic(
2833 &mut self,
2834 ctx: &Context<'_>,
2835 insn_id: InstructionId,
2836 name: &str,
2837 args: &[ValueId],
2838 ) -> Result<(), EmulatorErrorKind> {
2839 match name {
2840 "iota" => {
2841 let n = self
2842 .get_value(ctx, args[0])
2843 .ok_or(EmulatorErrorKind::ValueError(0))?;
2844 let mut buf = Vec::with_capacity(n as usize * 8);
2845 for i in 0..n {
2846 buf.extend_from_slice(&i.to_le_bytes());
2847 }
2848 self.array_values.insert(insn_id, buf);
2849 }
2850 "singleton" => {
2851 let buf = self
2852 .get_value_bytes(ctx, args[0])
2853 .ok_or(EmulatorErrorKind::ValueError(0))?;
2854 self.array_values.insert(insn_id, buf);
2855 }
2856 "concat" => {
2857 let mut a = self
2858 .resolve_array(ctx, args[0])
2859 .ok_or(EmulatorErrorKind::ValueError(0))?;
2860 let b = self
2861 .resolve_array(ctx, args[1])
2862 .ok_or(EmulatorErrorKind::ValueError(0))?;
2863 a.extend_from_slice(&b);
2864 self.array_values.insert(insn_id, a);
2865 }
2866 "insert" => {
2867 let mut buf = self
2868 .resolve_array(ctx, args[0])
2869 .ok_or(EmulatorErrorKind::ValueError(0))?;
2870 let i = self
2871 .get_value(ctx, args[1])
2872 .ok_or(EmulatorErrorKind::ValueError(0))? as usize;
2873 let vbytes = self
2874 .get_value_bytes(ctx, args[2])
2875 .ok_or(EmulatorErrorKind::ValueError(0))?;
2876 let esz = vbytes.len();
2877 let off = i * esz;
2878 if off + esz <= buf.len() {
2879 buf[off..off + esz].copy_from_slice(&vbytes);
2880 }
2881 self.array_values.insert(insn_id, buf);
2882 }
2883 "enumerate" => {
2884 let src_ty = ctx
2889 .stored_type_of(args[0])
2890 .ok_or(EmulatorErrorKind::ValueError(0))?;
2891 if matches!(ctx.shared.types.list_of(src_ty), Some((_, None))) {
2892 return Err(EmulatorErrorKind::UnsupportedIntrinsic(Box::from(
2893 "enumerate",
2894 )));
2895 }
2896 let in_elem = ctx
2897 .shared
2898 .types
2899 .seq_elem_of(src_ty)
2900 .ok_or(EmulatorErrorKind::ValueError(0))?;
2901 let isz = ctx.shared.types.size_of(in_elem).max(1);
2902 let buf = self
2903 .resolve_array(ctx, args[0])
2904 .ok_or(EmulatorErrorKind::ValueError(0))?;
2905 let tuple_ty = ctx
2910 .stored_type_of(ValueId::Instruction(insn_id))
2911 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2912 .ok_or(EmulatorErrorKind::ValueError(0))?;
2913 let (idx_sz, elem_off) = {
2914 let fields = ctx
2915 .shared
2916 .types
2917 .aggregate_fields(tuple_ty)
2918 .ok_or(EmulatorErrorKind::ValueError(0))?;
2919 let [idx_f, _elem_f] = fields else {
2920 return Err(EmulatorErrorKind::ValueError(0));
2921 };
2922 let idx_sz = ctx.shared.types.size_of(idx_f.type_id).min(8);
2923 (idx_sz, idx_sz)
2924 };
2925 let tsz = idx_sz + isz;
2926 let count = buf.len() / isz;
2927 let mut out = vec![0u8; count * tsz];
2928 for i in 0..count {
2929 let base = i * tsz;
2930 let idx_bytes = (i as u64).to_le_bytes();
2931 out[base..base + idx_sz].copy_from_slice(&idx_bytes[..idx_sz]);
2932 out[base + elem_off..base + elem_off + isz]
2933 .copy_from_slice(&buf[i * isz..i * isz + isz]);
2934 }
2935 self.array_values.insert(insn_id, out);
2936 }
2937 "at" => {
2938 let buf = self
2939 .resolve_array(ctx, args[0])
2940 .ok_or(EmulatorErrorKind::ValueError(0))?;
2941 let i = self
2942 .get_value(ctx, args[1])
2943 .ok_or(EmulatorErrorKind::ValueError(0))? as usize;
2944 let esz = ctx
2945 .stored_type_of(ValueId::Instruction(insn_id))
2946 .map(|ty| ctx.shared.types.size_of(ty))
2947 .unwrap_or(8);
2948 let off = i * esz;
2949 let lane = buf
2950 .get(off..off + esz)
2951 .ok_or(EmulatorErrorKind::ValueError(0))?;
2952 self.insn_values
2953 .insert(insn_id, SizedValue::from_bits(le_bits(lane), esz));
2954 }
2955 other => panic!("eval_array_intrinsic called on non-array intrinsic `{other}`"),
2956 }
2957 Ok(())
2958 }
2959
2960 fn eval_scan(
2965 &mut self,
2966 ctx: &Context<'_>,
2967 insn_id: InstructionId,
2968 scan: &Scan,
2969 ) -> Result<(), EmulatorErrorKind> {
2970 const SCAN_STEP_BUDGET: usize = 100_000;
2971
2972 let src = self
2973 .resolve_array(ctx, scan.src.qualify(insn_id.func))
2974 .ok_or(EmulatorErrorKind::ValueError(0))?;
2975 let in_elem = ctx
2980 .stored_type_of(scan.src.qualify(insn_id.func))
2981 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2982 .ok_or(EmulatorErrorKind::ValueError(0))?;
2983 let isz = ctx.shared.types.size_of(in_elem).max(1);
2984 let out_elem = ctx
2985 .stored_type_of(ValueId::Instruction(insn_id))
2986 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
2987 .ok_or(EmulatorErrorKind::ValueError(0))?;
2988 let osz = ctx.shared.types.size_of(out_elem);
2989 let count = src.len() / isz;
2990 let body = require_real_callee(scan.body)?;
2991 if count == 0 {
2992 self.array_values.insert(insn_id, Vec::new());
2993 return Ok(());
2994 }
2995
2996 let capture_args: Vec<BodyArg> = scan
2998 .captures
2999 .iter()
3000 .map(|&c| {
3001 let v = self
3002 .get_value(ctx, c.qualify(insn_id.func))
3003 .ok_or(EmulatorErrorKind::ValueError(0))?;
3004 let sz = ctx
3005 .stored_type_of(c.qualify(insn_id.func))
3006 .map(|ty| ctx.shared.types.size_of(ty))
3007 .unwrap_or(8);
3008 Ok(BodyArg::Scalar(SizedValue::new(v, sz)))
3009 })
3010 .collect::<Result<_, EmulatorErrorKind>>()?;
3011
3012 let init = self
3013 .get_value(ctx, scan.init.qualify(insn_id.func))
3014 .ok_or(EmulatorErrorKind::ValueError(0))?;
3015 let mut acc = SizedValue::new(init, osz);
3016
3017 let root = FunctionBody::from_id(ctx, body)
3018 .root()
3019 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(body))?
3020 .id;
3021
3022 let elem_fields: Option<Vec<(usize, usize)>> =
3028 ctx.shared.types.aggregate_fields(in_elem).map(|fs| {
3029 let mut off = 0;
3030 fs.iter()
3031 .map(|f| {
3032 let sz = ctx.shared.types.size_of(f.type_id);
3033 let field = (off, sz);
3034 off += sz;
3035 field
3036 })
3037 .collect()
3038 });
3039
3040 let mut out = Vec::with_capacity(count * osz);
3041 for k in 0..count {
3042 let elem = &src[k * isz..k * isz + isz];
3043 let elem_arg = match &elem_fields {
3044 Some(fields) => BodyArg::Aggregate(
3045 fields
3046 .iter()
3047 .map(|&(off, sz)| SizedValue::from_bits(le_bits(&elem[off..off + sz]), sz))
3048 .collect(),
3049 ),
3050 None => BodyArg::Scalar(SizedValue::from_bits(le_bits(elem), isz)),
3051 };
3052 let mut body_args = Vec::with_capacity(2 + capture_args.len());
3053 body_args.push(BodyArg::Scalar(acc));
3054 body_args.push(elem_arg);
3055 body_args.extend(capture_args.iter().cloned());
3056
3057 let mut emu = StandaloneEmulator::new(root);
3058 emu.run_map_body(ctx, body, &body_args, SCAN_STEP_BUDGET)
3059 .map_err(|e| e.kind)?;
3060 let ret = body_return_value(ctx, emu.current_block())
3061 .ok_or(EmulatorErrorKind::ValueError(0))?;
3062 let mut lane = emu
3063 .get_value_bytes(ctx, ret)
3064 .ok_or(EmulatorErrorKind::ValueError(0))?;
3065 lane.resize(osz, 0);
3066 acc = SizedValue::from_bits(le_bits(&lane), osz);
3067 out.extend_from_slice(&lane);
3068 }
3069 self.array_values.insert(insn_id, out);
3070 Ok(())
3071 }
3072
3073 fn eval_map(
3077 &mut self,
3078 ctx: &Context<'_>,
3079 insn_id: InstructionId,
3080 map: &qcode::value::insn::Map,
3081 ) -> Result<(), EmulatorErrorKind> {
3082 const MAP_STEP_BUDGET: usize = 100_000;
3083
3084 let src = self
3085 .resolve_array(ctx, map.src.qualify(insn_id.func))
3086 .ok_or(EmulatorErrorKind::ValueError(0))?;
3087 let in_elem = ctx
3088 .stored_type_of(map.src.qualify(insn_id.func))
3089 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
3090 .ok_or(EmulatorErrorKind::ValueError(0))?;
3091 let isz = ctx.shared.types.size_of(in_elem).max(1);
3092 let out_elem = ctx
3093 .stored_type_of(ValueId::Instruction(insn_id))
3094 .and_then(|ty| ctx.shared.types.seq_elem_of(ty))
3095 .ok_or(EmulatorErrorKind::ValueError(0))?;
3096 let osz = ctx.shared.types.size_of(out_elem);
3097 let count = src.len() / isz;
3098 let body = require_real_callee(map.body)?;
3099
3100 let capture_args: Vec<BodyArg> = map
3101 .captures
3102 .iter()
3103 .map(|&c| {
3104 let v = self
3105 .get_value(ctx, c.qualify(insn_id.func))
3106 .ok_or(EmulatorErrorKind::ValueError(0))?;
3107 let sz = ctx
3108 .stored_type_of(c.qualify(insn_id.func))
3109 .map(|ty| ctx.shared.types.size_of(ty))
3110 .unwrap_or(8);
3111 Ok(BodyArg::Scalar(SizedValue::new(v, sz)))
3112 })
3113 .collect::<Result<_, EmulatorErrorKind>>()?;
3114
3115 let elem_fields: Option<Vec<(usize, usize)>> =
3118 ctx.shared.types.aggregate_fields(in_elem).map(|fs| {
3119 let mut off = 0;
3120 fs.iter()
3121 .map(|f| {
3122 let sz = ctx.shared.types.size_of(f.type_id);
3123 let field = (off, sz);
3124 off += sz;
3125 field
3126 })
3127 .collect()
3128 });
3129
3130 let mut out = Vec::with_capacity(count * osz);
3131 for k in 0..count {
3132 let elem = &src[k * isz..k * isz + isz];
3133 let elem_arg = match &elem_fields {
3134 Some(fields) => BodyArg::Aggregate(
3135 fields
3136 .iter()
3137 .map(|&(off, sz)| SizedValue::from_bits(le_bits(&elem[off..off + sz]), sz))
3138 .collect(),
3139 ),
3140 None => BodyArg::Scalar(SizedValue::from_bits(le_bits(elem), isz)),
3141 };
3142 let mut body_args = Vec::with_capacity(1 + capture_args.len());
3143 body_args.push(elem_arg);
3144 body_args.extend(capture_args.iter().cloned());
3145
3146 let mut emu = StandaloneEmulator::new(
3147 FunctionBody::from_id(ctx, body)
3148 .root()
3149 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(body))?
3150 .id,
3151 );
3152 emu.run_map_body(ctx, body, &body_args, MAP_STEP_BUDGET)
3153 .map_err(|e| e.kind)?;
3154 let ret = body_return_value(ctx, emu.current_block())
3155 .ok_or(EmulatorErrorKind::ValueError(0))?;
3156 let mut lane = emu
3157 .get_value_bytes(ctx, ret)
3158 .ok_or(EmulatorErrorKind::ValueError(0))?;
3159 lane.resize(osz, 0);
3160 out.extend_from_slice(&lane);
3161 }
3162 self.array_values.insert(insn_id, out);
3163 Ok(())
3164 }
3165
3166 pub fn run_map_body(
3167 &mut self,
3168 ctx: &Context<'_>,
3169 func: FunctionId,
3170 args: &[BodyArg],
3171 max_steps: usize,
3172 ) -> crate::Result<()> {
3173 let root = FunctionBody::from_id(ctx, func)
3174 .root()
3175 .ok_or_else(|| self.make_error(ctx, EmulatorErrorKind::EmptyFunctionRoot(func)))?
3176 .id;
3177 self.block = root;
3178 self.idx = 0;
3179 self.call_stack.push(func);
3180
3181 let param_ids: Vec<BlockParamId> = BasicBlock::from_id(ctx, root)
3182 .params()
3183 .map(|p| p.id)
3184 .collect();
3185 for (param_id, arg) in param_ids.into_iter().zip(args) {
3186 match arg {
3187 BodyArg::Scalar(v) => {
3188 self.block_param_values.insert(param_id, *v);
3189 }
3190 BodyArg::Aggregate(fields) => {
3191 self.block_param_aggregates.insert(param_id, fields.clone());
3192 }
3193 }
3194 }
3195
3196 self.drive_to_return(ctx, root, func, max_steps)
3197 }
3198
3199 fn drive_to_return(
3205 &mut self,
3206 ctx: &Context<'_>,
3207 _root: BlockId,
3208 _func: FunctionId,
3209 max_steps: usize,
3210 ) -> crate::Result<()> {
3211 let mut steps = 0usize;
3212 let result = loop {
3213 let insn_ids = BasicBlock::from_id(ctx, self.block)
3214 .instruction_ids()
3215 .to_vec();
3216 if self.idx >= insn_ids.len() {
3222 break Err(self.make_empty_block_error(ctx));
3223 }
3224 let insn = InstructionRef::from_id(ctx, insn_ids[self.idx]);
3225 if matches!(
3226 insn.mnemonic(),
3227 Mnemonic::Return(_) | Mnemonic::ReturnValue(_)
3228 ) {
3229 break Ok(());
3230 }
3231 steps += 1;
3232 if steps > max_steps {
3233 break Err(self.make_error(ctx, EmulatorErrorKind::StepBudgetExceeded(max_steps)));
3234 }
3235 if let Err(e) = self.step(ctx) {
3236 break Err(e);
3237 }
3238 };
3239
3240 self.call_stack.pop();
3241 result
3242 }
3243}
3244
3245fn lambda_return_value(ctx: &Context<'_>, block: BlockId) -> Option<ValueId> {
3246 let last = BasicBlock::from_id(ctx, block).iter().last()?;
3247 match last.mnemonic() {
3248 Mnemonic::ReturnValue(ret) => Some(ret.value.qualify(last.id.func)),
3249 _ => None,
3250 }
3251}
3252
3253fn body_return_value(ctx: &Context<'_>, block: BlockId) -> Option<ValueId> {
3257 let last = BasicBlock::from_id(ctx, block).iter().last()?;
3258 match last.mnemonic() {
3259 Mnemonic::Return(ret) => ret.value.map(|v| v.qualify(last.id.func)),
3260 Mnemonic::ReturnValue(ret) => Some(ret.value.qualify(last.id.func)),
3261 _ => None,
3262 }
3263}
3264
3265fn is_array_intrinsic(name: &str) -> bool {
3269 matches!(
3270 name,
3271 "iota" | "singleton" | "concat" | "insert" | "at" | "enumerate"
3272 )
3273}
3274
3275fn le_bits(bytes: &[u8]) -> u128 {
3277 let mut buf = [0u8; 16];
3278 let n = bytes.len().min(16);
3279 buf[..n].copy_from_slice(&bytes[..n]);
3280 u128::from_le_bytes(buf)
3281}
3282
3283#[derive(Debug, Clone)]
3286pub enum BodyArg {
3287 Scalar(SizedValue),
3288 Aggregate(Vec<SizedValue>),
3289}
3290
3291struct TempInterpreter<'a, 'ctx, M> {
3294 memory: &'a mut M,
3295 literals: &'a mut LiteralCache,
3296 insn_values: &'a mut InsnValues,
3297 block_param_values: &'a mut FxHashMap<BlockParamId, SizedValue>,
3298 poison_params: &'a FxHashSet<BlockParamId>,
3299 ctx: &'ctx Context<'ctx>,
3300}
3301
3302impl<'ctx, M: EmulatorMemory> Interpreter for TempInterpreter<'_, 'ctx, M> {
3303 type V = SizedValue;
3304 type M = M;
3305
3306 fn memory(&mut self) -> &mut Self::M {
3307 self.memory
3308 }
3309
3310 fn ctx(&self) -> &Context<'_> {
3311 self.ctx
3312 }
3313
3314 fn get_value(&mut self, id: ValueId) -> Result<Self::V, EmulatorErrorKind> {
3315 if let ValueId::Literal(literal) = id {
3318 return Ok(self.literals.get(self.ctx, literal));
3319 }
3320 match ValueRef::new(id, self.ctx) {
3321 ValueRef::Literal(literal) => Ok(SizedValue::new(literal.value(), literal.size())),
3322 ValueRef::Bytes(_) => Err(EmulatorErrorKind::ValueError(0)),
3324 ValueRef::Instruction(insn) => self
3325 .insn_values
3326 .get(&insn.id)
3327 .copied()
3328 .ok_or(EmulatorErrorKind::ValueError(0)),
3329 ValueRef::Varnode(varnode) => Ok(SizedValue::new(varnode.address() as u64, 8)),
3330 ValueRef::Temp(temp) => Ok(SizedValue::new(temp.address() as u64, 8)),
3331 ValueRef::BasicBlock(_) => panic!("Cannot get value of a block"),
3332 ValueRef::BlockParam(param) => {
3333 if self.poison_params.contains(¶m.id) {
3334 return Err(EmulatorErrorKind::PoisonRead);
3335 }
3336 self.block_param_values
3337 .get(¶m.id)
3338 .copied()
3339 .ok_or(EmulatorErrorKind::ValueError(0))
3340 }
3341 ValueRef::Function(f) => f
3342 .address()
3343 .map(SizedValue::from_u64)
3344 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(f.id)),
3345 ValueRef::Poison(_) => Err(EmulatorErrorKind::PoisonRead),
3348 }
3349 }
3350}
3351
3352pub struct Emulator<'ctx, M = EmulatedMemory> {
3353 inner: StandaloneEmulator<M>,
3354 ctx: &'ctx Context<'ctx>,
3355}
3356
3357impl<'ctx> Emulator<'ctx, EmulatedMemory> {
3358 pub fn new(ctx: &'ctx Context<'ctx>, entry: BlockId) -> Self {
3360 Self::new_in(ctx, entry)
3361 }
3362
3363 pub fn from_function(ctx: &'ctx Context<'ctx>, func: FunctionId) -> Self {
3364 Self::from_function_in(ctx, func)
3365 }
3366
3367 pub fn from_block(ctx: &'ctx Context<'ctx>, block: BlockId) -> Self {
3368 Self::new_in(ctx, block)
3369 }
3370
3371 pub fn from_address(ctx: &'ctx Context<'ctx>, addr: u64) -> Self {
3372 Self::from_address_in(ctx, addr)
3373 }
3374}
3375
3376impl<'ctx, M: EmulatorMemory + Default> Emulator<'ctx, M> {
3377 pub fn new_in(ctx: &'ctx Context<'ctx>, entry: BlockId) -> Self {
3379 let mut inner =
3380 StandaloneEmulator::<M>::with_address_index(entry, AddressIndex::analyze(ctx));
3381 inner.memory.configure_spaces(ctx);
3382 Self { inner, ctx }
3383 }
3384
3385 pub fn set_instruction_hook(
3386 &mut self,
3387 hook: impl Fn(&InstructionRef<'_, '_>, &StandaloneEmulator<M>) + Send + Sync + 'static,
3388 ) {
3389 self.inner.instruction_hook = Some(Box::new(hook));
3390 }
3391
3392 pub fn set_call_interceptor(
3393 &mut self,
3394 interceptor: impl FnMut(
3395 &Context<'_>,
3396 &mut StandaloneEmulator<M>,
3397 &CallSite,
3398 ) -> Result<CallInterception, Box<str>>
3399 + Send
3400 + Sync
3401 + 'static,
3402 ) {
3403 self.inner.set_call_interceptor(interceptor);
3404 }
3405
3406 pub fn clear_call_interceptor(&mut self) {
3407 self.inner.clear_call_interceptor();
3408 }
3409
3410 pub fn from_function_in(ctx: &'ctx Context<'ctx>, func: FunctionId) -> Self {
3412 let entry = FunctionBody::from_id(ctx, func)
3413 .root()
3414 .expect("Cannot create emulator for function with empty root block")
3415 .id;
3416 Self::new_in(ctx, entry)
3417 }
3418
3419 pub fn from_address_in(ctx: &'ctx Context<'ctx>, addr: u64) -> Self {
3421 Self {
3422 inner: StandaloneEmulator::<M>::from_address_in(ctx, addr),
3423 ctx,
3424 }
3425 }
3426
3427 pub fn inspect_memory(&mut self, space: SpaceId, addr: u64, size: usize) -> Option<Vec<u8>> {
3429 self.inner
3430 .memory
3431 .read_bytes(MemorySpaceId::Shared(space), addr, size)
3432 .ok()
3433 }
3434
3435 pub fn set_varnode(&mut self, id: VarnodeId, value: u64) -> Result<(), EmulatorErrorKind> {
3437 self.inner.set_varnode(self.ctx, id, value)
3438 }
3439
3440 pub fn set_varnode_u128(
3442 &mut self,
3443 id: VarnodeId,
3444 value: u128,
3445 ) -> Result<(), EmulatorErrorKind> {
3446 self.inner.set_varnode_u128(self.ctx, id, value)
3447 }
3448
3449 pub fn set_register(&mut self, id: RegisterId, value: u64) -> Result<(), EmulatorErrorKind> {
3451 let id = self.ctx.get_register(id).id;
3452 self.set_varnode(id, value)
3453 }
3454
3455 pub fn write_memory(
3457 &mut self,
3458 space: SpaceId,
3459 addr: u64,
3460 value: &[u8],
3461 ) -> Result<(), EmulatorErrorKind> {
3462 self.inner.write_memory(self.ctx, space, addr, value)
3463 }
3464
3465 pub fn read_memory(
3466 &mut self,
3467 space: SpaceId,
3468 addr: u64,
3469 size: usize,
3470 ) -> Result<Vec<u8>, EmulatorErrorKind> {
3471 self.inner.read_memory(self.ctx, space, addr, size)
3472 }
3473
3474 pub fn set_register_u128(
3476 &mut self,
3477 id: RegisterId,
3478 value: u128,
3479 ) -> Result<(), EmulatorErrorKind> {
3480 let id = self.ctx.get_register(id).id;
3481 self.set_varnode_u128(id, value)
3482 }
3483
3484 pub fn read_varnode(&mut self, id: VarnodeId) -> Option<u64> {
3485 self.inner.read_varnode(self.ctx, id)
3486 }
3487
3488 pub fn read_varnode_u128(&mut self, id: VarnodeId) -> Option<u128> {
3489 self.inner.read_varnode_u128(self.ctx, id)
3490 }
3491
3492 pub fn read_register(&mut self, id: RegisterId) -> Option<u64> {
3493 let id = self.ctx.get_register(id).id;
3494 self.read_varnode(id)
3495 }
3496
3497 pub fn read_register_u128(&mut self, id: RegisterId) -> Option<u128> {
3498 let id = self.ctx.get_register(id).id;
3499 self.read_varnode_u128(id)
3500 }
3501
3502 pub fn set_register_lane(&mut self, id: RegisterId, lane: usize, value: u64) {
3505 let (space_id, base_addr) = {
3506 let vn = self.ctx.get_register(id);
3507 (vn.space().id, vn.address() as u64)
3508 };
3509 let base = base_addr + (lane as u64) * 8;
3510 let _ = self
3511 .inner
3512 .memory
3513 .write_bytes(space_id.into(), base, &value.to_le_bytes());
3514 }
3515
3516 pub fn read_register_lane(&mut self, id: RegisterId, lane: usize) -> u64 {
3519 let (space_id, base_addr) = {
3520 let vn = self.ctx.get_register(id);
3521 (vn.space().id, vn.address() as u64)
3522 };
3523 let base = base_addr + (lane as u64) * 8;
3524 let bytes = self
3527 .inner
3528 .memory
3529 .read_bytes(space_id.into(), base, 8)
3530 .unwrap_or_else(|_| vec![0; 8]);
3531 u64::from_le_bytes(bytes.try_into().expect("read_bytes returns 8 bytes"))
3532 }
3533
3534 pub fn block(&self) -> BlockRef<'ctx, 'ctx> {
3536 BasicBlock::from_id(self.ctx, self.inner.block)
3537 }
3538
3539 pub fn insn(&self) -> Option<InstructionRef<'ctx, 'ctx>> {
3541 let block = self.block();
3542 if self.inner.idx >= block.instruction_count() {
3543 None
3544 } else {
3545 let id = block.instruction_ids()[self.inner.idx];
3546 Some(InstructionRef::from_id(self.ctx, id))
3547 }
3548 }
3549
3550 pub fn step(&mut self) -> crate::Result<()> {
3552 self.inner.step(self.ctx)
3553 }
3554
3555 pub fn run_block(&mut self) -> crate::Result<()> {
3557 self.inner.run_block(self.ctx)
3558 }
3559
3560 pub fn run_until(&mut self, addr: u64) -> crate::Result<()> {
3562 self.inner.run_until(self.ctx, addr)
3563 }
3564
3565 pub fn run_function(&mut self, func: FunctionId) -> crate::Result<()> {
3567 self.inner.run_function(self.ctx, func)
3568 }
3569
3570 pub fn call_stack(&self) -> &[FunctionId] {
3573 &self.inner.call_stack
3574 }
3575}
3576
3577impl<'ctx, M: EmulatorMemory> Interpreter for Emulator<'ctx, M> {
3578 type V = SizedValue;
3579 type M = M;
3580
3581 fn memory(&mut self) -> &mut Self::M {
3582 &mut self.inner.memory
3583 }
3584
3585 fn ctx(&self) -> &Context<'ctx> {
3586 self.ctx
3587 }
3588
3589 fn get_value(&mut self, id: ValueId) -> Result<Self::V, EmulatorErrorKind> {
3590 if let ValueId::Literal(literal) = id {
3591 let value = self.inner.literal_cache.get(self.ctx, literal);
3592 return Ok(value);
3593 }
3594 match ValueRef::new(id, self.ctx) {
3595 ValueRef::Literal(literal) => Ok(SizedValue::new(literal.value(), literal.size())),
3596 ValueRef::Bytes(_) => Err(EmulatorErrorKind::ValueError(0)),
3598 ValueRef::Instruction(insn) => self
3599 .inner
3600 .insn_values
3601 .get(&insn.id)
3602 .copied()
3603 .ok_or(EmulatorErrorKind::ValueError(0)),
3604 ValueRef::Varnode(varnode) => Ok(SizedValue::new(varnode.address() as u64, 8)),
3605 ValueRef::Temp(temp) => Ok(SizedValue::new(temp.address() as u64, 8)),
3606 ValueRef::BasicBlock(_) => panic!("Cannot get value of a block"),
3607 ValueRef::BlockParam(param) => self
3608 .inner
3609 .block_param_values
3610 .get(¶m.id)
3611 .copied()
3612 .ok_or(EmulatorErrorKind::ValueError(0)),
3613 ValueRef::Function(f) => f
3614 .address()
3615 .map(SizedValue::from_u64)
3616 .ok_or(EmulatorErrorKind::EmptyFunctionRoot(f.id)),
3617 ValueRef::Poison(_) => Err(EmulatorErrorKind::PoisonRead),
3620 }
3621 }
3622}
3623
3624#[cfg(test)]
3625mod tests {
3626 use super::*;
3627 use qcode::context::Context;
3628 use qcode::space::{Space, SpaceType};
3629 use qcode::value::QCodeMut;
3630 use qcode::value::TempSpace;
3631 use std::sync::{Arc, Mutex};
3632 use wazabin_qcode_macro::qcode;
3633
3634 #[test]
3637 fn reading_poison_is_a_hard_error() {
3638 let mut ctx = Context::new();
3639 let func = ctx.anon_function();
3640 let block = BasicBlock::make(&mut ctx, func).with_address(0x1000).id;
3641 let i32_ty = ctx.shared.types.get_or_make_int(4);
3642 let poison = ctx.get_poison(i32_ty);
3643 let mut emu = StandaloneEmulator::new(block);
3644 let mut tmp = TempInterpreter {
3645 memory: &mut emu.memory,
3646 literals: &mut emu.literal_cache,
3647 insn_values: &mut emu.insn_values,
3648 block_param_values: &mut emu.block_param_values,
3649 poison_params: &emu.poison_params,
3650 ctx: &ctx,
3651 };
3652 assert!(matches!(
3653 tmp.get_value(poison),
3654 Err(EmulatorErrorKind::PoisonRead)
3655 ));
3656 }
3657
3658 #[test]
3659 fn minted_callee_is_not_executable() {
3660 assert!(matches!(
3661 require_real_callee(Callee::Minted(7)),
3662 Err(EmulatorErrorKind::UnresolvedMintedCallee(7))
3663 ));
3664 }
3665
3666 #[test]
3667 fn sized_value_masks_to_declared_width() {
3668 let value = SizedValue::new(0x1234, 1);
3669 assert_eq!(value.size().unwrap(), 1);
3670 assert_eq!(value.value().unwrap(), 0x34);
3671 }
3672
3673 #[test]
3674 fn from_address_resolves_function_entry_to_root() {
3675 let mut ctx = Context::new();
3676 let function = FunctionBody::make_at_addr(&mut ctx, 0x1000, None).id;
3677 let root = BasicBlock::make(&mut ctx, function).with_address(0x1000).id;
3678
3679 let emulator = StandaloneEmulator::from_address(&ctx, 0x1000);
3680
3681 assert_eq!(emulator.current_block(), root);
3682 assert!(emulator.address_index.is_some());
3683 }
3684
3685 #[test]
3686 fn standalone_address_lookup_builds_one_lazy_snapshot() {
3687 let mut ctx = Context::new();
3688 let function = ctx.anon_function();
3689 let block = BasicBlock::make(&mut ctx, function).with_address(0x2000).id;
3690 ctx.block_mut(block).extra_addresses.push(0x2001);
3691 let mut emulator = StandaloneEmulator::new(block);
3692
3693 assert!(emulator.address_index.is_none());
3694 assert_eq!(emulator.block_at(&ctx, 0x2001), Some(block));
3695 assert!(emulator.address_index.is_some());
3696 assert_eq!(emulator.block_at(&ctx, 0x2000), Some(block));
3697 }
3698
3699 #[test]
3700 fn int_add_wraps_by_width_and_sets_carry() {
3701 let lhs = SizedValue::new(0xff, 1);
3702 let rhs = SizedValue::new(0x01, 1);
3703
3704 let sum = lhs.int_add(&rhs).unwrap();
3705 let carry = lhs.carry(&rhs).unwrap();
3706
3707 assert_eq!(sum.value().unwrap(), 0x00);
3708 assert_eq!(sum.size().unwrap(), 1);
3709 assert_eq!(carry.value().unwrap(), 1);
3710 assert_eq!(carry.size().unwrap(), 1);
3711 }
3712
3713 #[test]
3714 fn branch_args_bind_block_params() {
3715 let mut ctx = Context::new();
3716 qcode!(
3717 ctx,
3718 "
3719 <src>
3720 goto <dst @x=0x2>;
3721 <dst @x>
3722 %sum = i64 @x + 0x3;
3723 goto <0x1001>;
3724 "
3725 );
3726
3727 let mut emu = StandaloneEmulator::new(src);
3728 emu.step(&ctx).expect("branch binds block params");
3729 emu.step(&ctx).expect("destination uses block param");
3730
3731 assert_eq!(emu.get_value(&ctx, sum.into()), Some(5));
3732 }
3733
3734 #[test]
3735 fn apply_evaluates_recursive_lambda_value_return() {
3736 let mut ctx = Context::new();
3737 qcode!(
3738 ctx,
3739 "
3740 lambda dec:
3741 <entry @n:i64>
3742 %is_zero = @n == 0;
3743 if %is_zero goto <done @r=@n> else goto <step @m=@n>;
3744
3745 <step @m:i64>
3746 %next = @m - 1;
3747 %out = apply dec(%next);
3748 return %out;
3749
3750 <done @r:i64>
3751 return @r;
3752 "
3753 );
3754
3755 let dec = qcode::value::FunctionBody::from_name(&ctx, "dec")
3756 .expect("lambda exists")
3757 .id;
3758 let root = qcode::value::FunctionBody::from_id(&ctx, dec)
3759 .root()
3760 .expect("lambda has root")
3761 .id;
3762 let mut emu = StandaloneEmulator::new(root);
3763 emu.run_pure(&ctx, dec, &[SizedValue::new(3, 8)], 1000)
3764 .expect("recursive lambda evaluates");
3765 let ret = lambda_return_value(&ctx, emu.current_block()).expect("lambda returned a value");
3766 assert_eq!(emu.get_value(&ctx, ret), Some(0));
3767 }
3768
3769 fn publish_iota_result(ctx: &mut Context) {
3772 use qcode::types::TypeRequest;
3773 let i64_ty = ctx.shared.types.get_or_make_int(8);
3774 ctx.shared
3775 .types
3776 .create_requested_types(&[TypeRequest::list(i64_ty, None)]);
3777 }
3778
3779 #[test]
3782 fn map_over_array_is_emulated() {
3783 let mut ctx = Context::new();
3784 publish_iota_result(&mut ctx);
3785 qcode!(
3786 ctx,
3787 "
3788 lambda triple:
3789 <tb @x:i64>
3790 %r = @x * 3;
3791 return %r;
3792 fn main:
3793 <me>
3794 %src = $iota(i64 0x4);
3795 %m = triple <$> %src;
3796 goto <0x1001>;
3797 "
3798 );
3799
3800 let mut emu = StandaloneEmulator::new(me);
3801 emu.step(&ctx).expect("iota");
3802 emu.step(&ctx).expect("map");
3803
3804 let buf = emu.array_values.get(&m).expect("map produced an array");
3805 let words: Vec<u64> = buf
3806 .as_chunks::<8>()
3807 .0
3808 .iter()
3809 .map(|&c| u64::from_le_bytes(c))
3810 .collect();
3811 assert_eq!(words, vec![0, 3, 6, 9]);
3813 }
3814
3815 #[test]
3820 fn scan_over_iota_is_emulated() {
3821 let mut ctx = Context::new();
3822 publish_iota_result(&mut ctx);
3823 qcode!(
3824 ctx,
3825 "
3826 lambda step:
3827 <sb @acc:i64 @x:i64>
3828 %r = @acc + @x;
3829 return %r;
3830 fn main:
3831 <me>
3832 %src = $iota(i64 0x3);
3833 %s = scanl @step i64 0xa %src;
3834 goto <0x1001>;
3835 "
3836 );
3837
3838 let mut emu = StandaloneEmulator::new(me);
3839 emu.step(&ctx).expect("iota");
3841 emu.step(&ctx).expect("scan");
3842
3843 let buf = emu.array_values.get(&s).expect("scan produced an array");
3844 let words: Vec<u64> = buf
3845 .as_chunks::<8>()
3846 .0
3847 .iter()
3848 .map(|&c| u64::from_le_bytes(c))
3849 .collect();
3850 assert_eq!(words, vec![10, 11, 13]);
3851 }
3852
3853 #[test]
3854 fn enumerate_over_array_is_emulated() {
3855 use qcode::value::{FunctionBody, ValueId, insn::IntrinsicId};
3856
3857 let mut ctx = Context::new();
3858 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
3859 let entry = ctx.get_or_make_block(0x1000, f);
3860 {
3861 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
3862 fm.set_root(entry).unwrap();
3863 fm.add_block(entry);
3864 }
3865 let i64_ty = ctx.shared.types.get_or_make_int(8);
3867 let arr_ty = ctx.shared.types.get_or_make_array(i64_ty, 4);
3868 let data: Vec<u8> = [10u64, 20, 30, 40]
3869 .iter()
3870 .flat_map(|w| w.to_le_bytes())
3871 .collect();
3872 let src = ctx.get_bytes(data).id();
3873 if let ValueId::Bytes(bid) = src {
3874 ctx.shared.values.bytes[bid].type_id = arr_ty;
3875 }
3876 {
3879 use qcode::types::{AggregateField, TypeRequest};
3880 let fields = vec![
3881 AggregateField::new("index", i64_ty),
3882 AggregateField::new("elem", i64_ty),
3883 ];
3884 let tuple = ctx
3885 .shared
3886 .types
3887 .create_requested_types(&[TypeRequest::aggregate(fields)])[0];
3888 ctx.shared
3889 .types
3890 .create_requested_types(&[TypeRequest::array(tuple, 4)]);
3891 }
3892 let enum_id = IntrinsicId::from_name("enumerate").unwrap();
3893 let e = {
3894 let mut b = ctx.builder(entry);
3895 let e = b.push_intrinsic(enum_id, vec![src]).id();
3896 let ptr = b.shr().get_const(0, 8);
3897 b.push_return(ptr);
3898 e
3899 };
3900 let ValueId::Instruction(eid) = e else {
3901 unreachable!()
3902 };
3903
3904 let mut emu = StandaloneEmulator::new(entry);
3905 emu.step(&ctx).expect("enumerate");
3906
3907 let buf = emu
3910 .array_values
3911 .get(&eid)
3912 .expect("enumerate produced an array");
3913 let words: Vec<u64> = buf
3914 .as_chunks::<8>()
3915 .0
3916 .iter()
3917 .map(|&c| u64::from_le_bytes(c))
3918 .collect();
3919 assert_eq!(words, vec![0, 10, 1, 20, 2, 30, 3, 40]);
3920 }
3921
3922 #[test]
3927 fn enumerate_of_unbounded_list_bails_recoverably() {
3928 use qcode::value::{
3929 BasicBlock, FunctionBody, InstructionRef, ValueId,
3930 insn::{IntrinsicApp, IntrinsicId, Return},
3931 };
3932
3933 let mut ctx = Context::new();
3934 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
3935 let entry = ctx.get_or_make_block(0x1000, f);
3936 {
3937 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
3938 fm.set_root(entry).unwrap();
3939 fm.add_block(entry);
3940 }
3941 let i8 = ctx.shared.types.get_or_make_int(1);
3942 let list_ty = ctx.shared.types.get_or_make_unbounded_list(i8);
3943 let src = {
3944 let mut b = ctx.builder(entry);
3945 b.push_param(8).id()
3946 };
3947 if let ValueId::BlockParam(pid) = src {
3948 ctx.block_param_mut(pid).type_id = list_ty;
3949 }
3950 let enum_id = IntrinsicId::from_name("enumerate").unwrap();
3954 let env = {
3959 let insn = InstructionRef::from_mnemonic_with_type(
3960 &mut ctx,
3961 entry.func,
3962 Mnemonic::Intrinsic(IntrinsicApp {
3963 id: enum_id,
3964 args: vec![src.localize(entry.func)],
3965 }),
3966 list_ty,
3967 )
3968 .id;
3969 BasicBlock::from_id_mut(&mut ctx, entry).push_insn(insn);
3970 ValueId::Instruction(insn)
3971 };
3972 let ptr = ctx.get_const(0, 8).id();
3973 {
3974 let mut b = ctx.builder(entry);
3975 b.push_return(ptr);
3976 }
3977 let rid = BasicBlock::from_id(&ctx, entry).iter().last().unwrap().id;
3978 ctx.replace_instruction_mnemonic(
3979 rid,
3980 Mnemonic::Return(Return {
3981 ptr: ptr.localize(rid.func),
3982 value: Some(env.localize(rid.func)),
3983 }),
3984 );
3985
3986 let mut emu = StandaloneEmulator::new(entry);
3987 let err = emu
3988 .run_pure(&ctx, f, &[SizedValue::new(0, 4)], 1000)
3989 .expect_err("enumerate must not be emulated");
3990 assert!(
3991 matches!(err.kind, EmulatorErrorKind::UnsupportedIntrinsic(ref n) if &**n == "enumerate"),
3992 "expected recoverable UnsupportedIntrinsic, got {:?}",
3993 err.kind
3994 );
3995 }
3996
3997 fn run_at_over_array_param(n: usize, idx: u64, bound: SizedValue) -> Option<u64> {
4001 use qcode::value::{
4002 BasicBlock, FunctionBody, ValueId,
4003 insn::{IntrinsicId, Return},
4004 };
4005
4006 let mut ctx = Context::new();
4007 let arr_ty = {
4008 let i8 = ctx.shared.types.get_or_make_int(1);
4009 ctx.shared.types.get_or_make_array(i8, n)
4010 };
4011 let f = FunctionBody::make(&mut ctx, "f".into()).unwrap().id;
4012 let entry = ctx.get_or_make_block(0x1000, f);
4013 {
4014 let mut fm = FunctionBody::from_id_mut(&mut ctx, f);
4015 fm.set_root(entry).unwrap();
4016 fm.add_block(entry);
4017 }
4018 let arr_pid = BasicBlock::from_id_mut(&mut ctx, entry).push_param(n).id;
4019 ctx.block_param_mut(arr_pid).type_id = arr_ty;
4020
4021 let at_id = IntrinsicId::from_name("at").unwrap();
4022 let (ret, ptr, lane);
4023 {
4024 let mut b = ctx.builder(entry);
4025 let arr = ValueId::BlockParam(arr_pid);
4026 let i = b.shr().get_const(idx, 8);
4027 lane = b.push_intrinsic(at_id, vec![arr, i]).id();
4028 ptr = b.shr().get_const(0, 8);
4029 ret = b.push_return(ptr).id();
4030 }
4031 let ValueId::Instruction(rid) = ret else {
4032 unreachable!()
4033 };
4034 ctx.replace_instruction_mnemonic(
4035 rid,
4036 Mnemonic::Return(Return {
4037 ptr: ptr.localize(rid.func),
4038 value: Some(lane.localize(rid.func)),
4039 }),
4040 );
4041
4042 let mut emu = StandaloneEmulator::new(entry);
4043 emu.run_pure(&ctx, f, &[bound], 1000).ok()?;
4044 emu.get_value(&ctx, lane)
4045 }
4046
4047 fn run_switch(scrutinee: u64) -> Option<u64> {
4051 let mut ctx = Context::new();
4052 qcode!(
4053 ctx,
4054 "
4055 lambda sw:
4056 <entry @i:i64>
4057 switch @i { 0x0 => <a>, 0x3 => <b @v=0x63>, default => <d> };
4058 <a>
4059 return 0x11;
4060 <b @v:i64>
4061 return @v;
4062 <d>
4063 return 0x99;
4064 "
4065 );
4066 let root = FunctionBody::from_id(&ctx, sw).root().expect("root").id;
4067 let mut emu = StandaloneEmulator::new(root);
4068 emu.run_pure(&ctx, sw, &[SizedValue::new(scrutinee, 8)], 1000)
4069 .ok()?;
4070 let term = BasicBlock::from_id(&ctx, emu.block)
4071 .instruction_ids()
4072 .last()
4073 .copied()?;
4074 let Mnemonic::ReturnValue(r) = Instruction::from_id(&ctx, term).mnemonic() else {
4075 return None;
4076 };
4077 emu.get_value(&ctx, r.value.qualify(term.func))
4078 }
4079
4080 #[test]
4081 fn switch_selects_the_matching_arm() {
4082 assert_eq!(run_switch(0), Some(0x11));
4083 assert_eq!(run_switch(3), Some(0x63));
4085 assert_eq!(run_switch(7), Some(0x99));
4087 }
4088
4089 #[test]
4093 fn run_pure_reads_array_param_bytes_little_endian() {
4094 let arg = SizedValue::new(0x2f76bfc2, 4);
4095 assert_eq!(run_at_over_array_param(4, 0, arg), Some(0xc2));
4097 assert_eq!(run_at_over_array_param(4, 1, arg), Some(0xbf));
4098 assert_eq!(run_at_over_array_param(4, 2, arg), Some(0x76));
4099 assert_eq!(run_at_over_array_param(4, 3, arg), Some(0x2f));
4100 }
4101
4102 #[test]
4106 fn run_pure_rejects_oversize_array_param() {
4107 assert_eq!(
4110 run_at_over_array_param(20, 0, SizedValue::new(0xff, 20)),
4111 None
4112 );
4113 }
4114
4115 #[test]
4116 fn int_mul_wraps_for_64_bit_values() {
4117 let lhs = SizedValue::new(u64::MAX, 8);
4118 let rhs = SizedValue::new(2, 8);
4119
4120 let product = lhs.int_mul(&rhs).unwrap();
4121
4122 assert_eq!(product.value().unwrap(), u64::MAX.wrapping_mul(2));
4123 assert_eq!(product.size().unwrap(), 8);
4124 }
4125
4126 #[test]
4127 fn int_mul_wraps_for_128_bit_values() {
4128 let lhs = SizedValue::from_bits(u128::MAX, 16);
4129 let rhs = SizedValue::from_bits(u128::from(2u8), 16);
4130
4131 let product = lhs.int_mul(&rhs).unwrap();
4132
4133 assert_eq!(product.as_bits(), u128::MAX.wrapping_mul(u128::from(2u8)));
4134 assert_eq!(product.size().unwrap(), 16);
4135 assert!(matches!(
4136 product.value(),
4137 Err(EmulatorErrorKind::ValueError(_))
4138 ));
4139 }
4140
4141 #[test]
4142 fn int_div_and_rem_work_for_128_bit_values() {
4143 let lhs = SizedValue::from_bits(u128::MAX, 16);
4144 let rhs = SizedValue::from_bits(u128::from(3u8), 16);
4145
4146 let q = lhs.int_div(&rhs).unwrap();
4147 let r = lhs.int_rem(&rhs).unwrap();
4148
4149 assert_eq!(q.as_bits(), u128::MAX / u128::from(3u8));
4150 assert_eq!(r.as_bits(), u128::MAX % u128::from(3u8));
4151 assert_eq!(q.size().unwrap(), 16);
4152 assert_eq!(r.size().unwrap(), 16);
4153 }
4154
4155 #[test]
4156 fn int_sdiv_and_srem_work_for_128_bit_values() {
4157 let lhs = SizedValue::from_bits(u128::from(0xffff_ffff_ffff_ffffu64), 16);
4158 let rhs = SizedValue::from_bits(u128::from(2u8), 16);
4159
4160 let q = lhs.int_sdiv(&rhs).unwrap();
4161 let r = lhs.int_srem(&rhs).unwrap();
4162
4163 assert_eq!(q.as_bits(), u128::from(0x7fff_ffff_ffff_ffffu64));
4164 assert_eq!(r.as_bits(), u128::from(1u8));
4165 assert_eq!(q.size().unwrap(), 16);
4166 assert_eq!(r.size().unwrap(), 16);
4167 }
4168
4169 #[test]
4170 fn signed_extension_and_shift_behave_as_expected() {
4171 let negative_byte = SizedValue::new(0x80, 1);
4172 let extended = negative_byte.sext(8).unwrap();
4173 let shifted = negative_byte
4174 .int_sshift_right(&SizedValue::new(1, 1))
4175 .unwrap();
4176
4177 assert_eq!(extended.value().unwrap(), 0xffff_ffff_ffff_ff80);
4178 assert_eq!(extended.size().unwrap(), 8);
4179 assert_eq!(shifted.value().unwrap(), 0xc0);
4180 assert_eq!(shifted.size().unwrap(), 1);
4181 }
4182
4183 #[test]
4184 fn signed_comparisons_use_value_width() {
4185 let lhs = SizedValue::new(0xff, 1);
4186 let rhs = SizedValue::new(0x01, 1);
4187
4188 assert_eq!(lhs.int_sless(&rhs).and_then(|v| v.value()).unwrap(), 1);
4189 assert_eq!(rhs.int_sless(&lhs).and_then(|v| v.value()).unwrap(), 0);
4190 }
4191
4192 #[test]
4193 fn int_sub_uses_lhs_width_with_default_u64_immediate() {
4194 let lhs = SizedValue::new(0, 4);
4195 let rhs = SizedValue::from_u64(1);
4196
4197 let diff = lhs.int_sub(&rhs).unwrap();
4198
4199 assert_eq!(diff.size().unwrap(), 4);
4200 assert_eq!(diff.value().unwrap(), 0xffff_ffff);
4201 }
4202
4203 #[test]
4204 fn sborrow_uses_lhs_width_with_default_u64_immediate() {
4205 let lhs = SizedValue::new(0x80, 1);
4206 let rhs = SizedValue::new(1, 1);
4207
4208 assert_eq!(lhs.sborrow(&rhs).and_then(|v| v.value()).unwrap(), 1);
4210 }
4211
4212 #[test]
4213 fn scarry_uses_lhs_width_with_default_u64_immediate() {
4214 let lhs = SizedValue::new(0x7f, 1);
4215 let rhs = SizedValue::new(1, 1);
4216
4217 assert_eq!(lhs.scarry(&rhs).and_then(|v| v.value()).unwrap(), 1);
4219 }
4220
4221 #[test]
4222 fn sborrow_neg() {
4223 let lhs = SizedValue::new(0x0, 1);
4224 let rhs = SizedValue::new(0x80, 1);
4225
4226 assert_eq!(lhs.sborrow(&rhs).and_then(|v| v.value()).unwrap(), 1);
4228 }
4229
4230 #[test]
4231 fn lz_count_respects_width() {
4232 let value = SizedValue::new(0x01, 1);
4233 let lz = value.lz_count().unwrap();
4234
4235 assert_eq!(lz.value().unwrap(), 7);
4236 assert_eq!(lz.size().unwrap(), 1);
4237 }
4238
4239 #[test]
4240 fn float_conversion_handles_f32_and_f64() {
4241 let minus_one = SizedValue::new(0xff, 1);
4242 let as_f32 = minus_one.int_to_float(4).unwrap();
4243 assert_eq!(as_f32.value().unwrap(), (-1.0f32).to_bits() as u64);
4244 assert_eq!(as_f32.size().unwrap(), 4);
4245
4246 let f32_value = SizedValue::new((1.5f32).to_bits() as u64, 4);
4247 let promoted = f32_value.float_to_float(8).unwrap();
4248 let promoted_bits = promoted.value().unwrap();
4249 assert_eq!(f64::from_bits(promoted_bits), 1.5f64);
4250 assert_eq!(promoted.size().unwrap(), 8);
4251
4252 let demoted = promoted.float_to_float(4).unwrap();
4253 assert_eq!(demoted.value().unwrap(), (1.5f32).to_bits() as u64);
4254 assert_eq!(demoted.size().unwrap(), 4);
4255 }
4256
4257 #[test]
4258 fn x87_precision_and_store_rounding_are_separate_from_generic_arithmetic() {
4259 let one = 0x3fff_8000_0000_0000_0000u128;
4260 let one_plus_half_single_ulp = one + (1u128 << 39);
4263 assert_eq!(
4264 float80::round_to_precision(one_plus_half_single_ulp, 24, Round::NearestTiesToEven)
4265 .bits,
4266 one
4267 );
4268 assert_eq!(
4269 float80::round_to_precision(one_plus_half_single_ulp, 24, Round::TowardPositive).bits,
4270 one + (1u128 << 40)
4271 );
4272 assert_eq!(
4274 float80::round_to_precision(one_plus_half_single_ulp, 64, Round::TowardPositive).bits,
4275 one_plus_half_single_ulp
4276 );
4277
4278 let extended = SizedValue::from_bits(one_plus_half_single_ulp, 10);
4282 assert_eq!(
4283 StandaloneEmulator::<EmulatedMemory>::ieee_narrow(
4284 extended,
4285 4,
4286 Round::NearestTiesToEven
4287 )
4288 .unwrap()
4289 .0
4290 .as_bits(),
4291 u128::from(1.0f32.to_bits())
4292 );
4293 assert_eq!(
4294 StandaloneEmulator::<EmulatedMemory>::ieee_narrow(extended, 4, Round::TowardPositive)
4295 .unwrap()
4296 .0
4297 .as_bits(),
4298 u128::from((1.0f32).to_bits() + 1)
4299 );
4300
4301 let mut ctx = Context::new();
4305 qcode!(
4306 ctx,
4307 "
4308 varnode i16 FPUControlWord;
4309 varnode i16 FPUStatusWord;
4310 varnode f80 A;
4311 varnode f80 B;
4312
4313 <block>
4314 %a = load(A:10, &A);
4315 %b = load(B:10, &B);
4316 %result = %a f/ %b;
4317 goto <0x1001>;
4318 "
4319 );
4320 let mut emu = Emulator::from_block(&ctx, block);
4321 emu.set_varnode(FPUControlWord, 0x037b).unwrap(); emu.set_varnode_u128(A, one).unwrap();
4323 emu.set_varnode_u128(B, 0).unwrap();
4324 emu.run_block().unwrap();
4325 assert_eq!(emu.get_value(result.into()).unwrap().size().unwrap(), 10);
4326 assert_eq!(emu.read_varnode(FPUStatusWord), None);
4328 }
4329
4330 #[test]
4334 fn f80_comparison_records_no_status() {
4335 let mut ctx = Context::new();
4336 qcode!(
4337 ctx,
4338 "
4339 varnode i16 FPUControlWord;
4340 varnode i16 FPUStatusWord;
4341 varnode f80 A;
4342 varnode f80 B;
4343
4344 <block>
4345 %a = load(A:10, &A);
4346 %b = load(B:10, &B);
4347 %equal = %a f== %b;
4348 goto <0x1001>;
4349 "
4350 );
4351 let mut emu = Emulator::from_block(&ctx, block);
4352 emu.set_varnode(FPUControlWord, 0x037f).unwrap();
4353 emu.set_varnode_u128(A, 0x7fff_8000_0000_0000_0001).unwrap();
4356 emu.set_varnode_u128(B, 0x3fff_8000_0000_0000_0000).unwrap();
4357 emu.run_block().unwrap();
4358 assert_eq!(emu.get_value(equal.into()).unwrap().value().unwrap(), 0);
4359 assert_eq!(emu.read_varnode(FPUStatusWord), None);
4360 }
4361
4362 #[test]
4367 fn float80_partial_remainder_is_exact() {
4368 let dividend = 0x7ffe_ffff_ffff_ffff_ffffu128;
4369 let one = 0x3fff_8000_0000_0000_0000u128;
4370 for ieee in [false, true] {
4371 let result = float80::remainder(dividend, one, ieee);
4372 assert!(result.incomplete);
4373 assert_eq!(result.bits, 0);
4374 }
4375
4376 let half = 0x3ffe_8000_0000_0000_0000u128;
4380 let result = float80::remainder(dividend, half, false);
4381 assert!(result.incomplete);
4382 assert_eq!(result.bits, 0x7fdd_ffff_fffe_0000_0000);
4383
4384 let three = 0x4000_c000_0000_0000_0000u128;
4387 let result = float80::remainder(three, one, false);
4388 assert!(!result.incomplete);
4389 assert_eq!(result.bits, 0);
4390 assert_eq!(result.quotient & 7, 3);
4391 }
4392
4393 #[test]
4396 fn float80_sqrt_is_correctly_rounded_at_extended_precision() {
4397 let two = 0x4000_8000_0000_0000_0000;
4398 let four = 0x4001_8000_0000_0000_0000;
4399 let one = 0x3fff_8000_0000_0000_0000;
4400
4401 let root_two = float80::sqrt_ieee(two, Round::NearestTiesToEven);
4403 assert_eq!(root_two.bits, 0x3fff_b504_f333_f9de_6484);
4404 assert!(root_two.status.contains(Status::INEXACT));
4405
4406 for (input, expect) in [(four, two), (one, one), (0, 0)] {
4408 let result = float80::sqrt_ieee(input, Round::NearestTiesToEven);
4409 assert_eq!(result.bits, expect);
4410 assert_eq!(result.status, Status::OK);
4411 }
4412
4413 let three = 0x4000_c000_0000_0000_0000;
4416 assert_eq!(
4417 float80::sqrt_ieee(three, Round::NearestTiesToEven).bits,
4418 0x3fff_ddb3_d742_c265_539e
4419 );
4420 assert_eq!(
4421 float80::sqrt_ieee(three, Round::TowardZero).bits,
4422 0x3fff_ddb3_d742_c265_539d
4423 );
4424
4425 let negative = float80::sqrt_ieee(0xbfff_8000_0000_0000_0000, Round::NearestTiesToEven);
4428 assert_eq!(negative.bits, 0xbfff_8000_0000_0000_0000);
4429 assert!(negative.status.contains(Status::INVALID_OP));
4430 }
4431
4432 #[test]
4433 fn float80_arithmetic_preserves_extended_precision_bits() {
4434 let one = SizedValue::from_bits(0x3fff_8000_0000_0000_0000, 10);
4438 let two = SizedValue::from_bits(0x4000_8000_0000_0000_0000, 10);
4439 let three = one.float_add(&two).unwrap();
4440
4441 assert_eq!(three.as_bits(), 0x4000_c000_0000_0000_0000);
4442 assert_eq!(three.size().unwrap(), 10);
4443 assert_eq!(two.float_to_float(10).unwrap().as_bits(), two.as_bits());
4444 assert_eq!(
4445 SizedValue::new(3, 1).int_to_float(10).unwrap().as_bits(),
4446 three.as_bits()
4447 );
4448 }
4449
4450 #[test]
4451 fn explicit_ieee_arithmetic_pairs_results_and_flags_in_every_rounding_mode() {
4452 let cases = [
4457 (
4458 4,
4459 0x3f80_0000,
4460 0x3380_0000,
4461 0x3f80_0001,
4462 0x3fc0_0000,
4463 0x3f80_0000,
4464 0x4040_0000,
4465 ),
4466 (
4467 8,
4468 0x3ff0_0000_0000_0000,
4469 0x3ca0_0000_0000_0000,
4470 0x3ff0_0000_0000_0001,
4471 0x3ff8_0000_0000_0000,
4472 0x3ff0_0000_0000_0000,
4473 0x4008_0000_0000_0000,
4474 ),
4475 (
4476 10,
4477 0x3fff_8000_0000_0000_0000,
4478 0x3fbf_8000_0000_0000_0000,
4479 0x3fff_8000_0000_0000_0001,
4480 0x3fff_c000_0000_0000_0000,
4481 0x3fff_8000_0000_0000_0000,
4482 0x4000_c000_0000_0000_0000,
4483 ),
4484 ];
4485 let operations = [
4486 ("float_add", "float_add_flags", 0usize),
4487 ("float_sub", "float_sub_flags", 1),
4488 ("float_mul", "float_mul_flags", 2),
4489 ("float_div", "float_div_flags", 3),
4490 ];
4491
4492 for (size, add_lhs, add_rhs, mul_lhs, mul_rhs, div_lhs, div_rhs) in cases {
4493 let sub_rhs = match size {
4496 4 => 0x3300_0000,
4497 8 => 0x3c90_0000_0000_0000,
4498 10 => 0x3fbe_8000_0000_0000_0000,
4499 _ => unreachable!(),
4500 };
4501 let operands = [
4502 (add_lhs, add_rhs),
4503 (add_lhs, sub_rhs),
4504 (mul_lhs, mul_rhs),
4505 (div_lhs, div_rhs),
4506 ];
4507 for (result_name, flags_name, pair) in operations {
4508 let (lhs, rhs) = operands[pair];
4509 for mode in 0..4 {
4510 let round =
4511 StandaloneEmulator::<EmulatedMemory>::ieee_rounding_mode(mode).unwrap();
4512 let (result, status) = StandaloneEmulator::<EmulatedMemory>::ieee_arithmetic(
4513 SizedValue::from_bits(lhs, size),
4514 SizedValue::from_bits(rhs, size),
4515 round,
4516 result_name,
4517 )
4518 .unwrap();
4519 let (_, flag_status) = StandaloneEmulator::<EmulatedMemory>::ieee_arithmetic(
4520 SizedValue::from_bits(lhs, size),
4521 SizedValue::from_bits(rhs, size),
4522 round,
4523 flags_name,
4524 )
4525 .unwrap();
4526 assert_eq!(
4527 status,
4528 flag_status,
4529 "{result_name}, f{}, mode {mode}",
4530 size * 8
4531 );
4532 let flags = StandaloneEmulator::<EmulatedMemory>::ieee_flags(flag_status);
4533 assert_ne!(
4534 flags.as_bits() & (1 << 5),
4535 0,
4536 "{result_name}, f{}, mode {mode}",
4537 size * 8
4538 );
4539 assert_eq!(result.size as usize, size);
4540 }
4541 }
4542 }
4543 }
4544
4545 #[test]
4546 fn simple_addition() {
4547 let mut ctx = Context::new();
4548
4549 qcode!(
4550 ctx,
4551 "
4552 varnode i64 V0;
4553 varnode i64 V1;
4554
4555 <block>
4556 %v0 = load(V0:8, &V0);
4557 %v1 = load(V1:8, &V1);
4558 %res = %v0 + %v1;
4559 goto <0x1001>;
4560 "
4561 );
4562
4563 let mut emu = Emulator::from_block(&ctx, block);
4564 emu.set_varnode(V0, 2).unwrap();
4565 emu.set_varnode(V1, 3).unwrap();
4566 emu.run_block().unwrap();
4567
4568 assert_eq!(
4569 emu.get_value(res.into()).and_then(|v| v.value()).unwrap(),
4570 5
4571 );
4572 }
4573
4574 #[test]
4575 fn gep_emulates_as_base_plus_offset() {
4576 let mut ctx = Context::new();
4577
4578 qcode!(
4580 ctx,
4581 "
4582 type Inner { _: 8, val: 4 };
4583 varnode i64 V0;
4584
4585 <block>
4586 Inner* %p = load(V0:8, &V0);
4587 %fld = gep(%p.val);
4588 goto <0x1001>;
4589 "
4590 );
4591
4592 let mut emu = Emulator::from_block(&ctx, block);
4593 emu.set_varnode(V0, 0x1000).unwrap();
4594 emu.run_block().unwrap();
4595
4596 let fld = emu.get_value(fld.into()).unwrap();
4597 assert_eq!(fld.value().unwrap(), 0x1008);
4598 assert_eq!(fld.size().unwrap(), 8);
4600 }
4601
4602 #[test]
4603 fn emulator_int_div_works_with_128_bit_operands() {
4604 let mut ctx = Context::new();
4605 qcode!(
4606 ctx,
4607 "
4608 varnode i128 V0;
4609 varnode i128 V1;
4610
4611 <block>
4612 %v0 = load(V0:16, &V0);
4613 %v1 = load(V1:16, &V1);
4614
4615 %res = %v0 / %v1;
4616 goto <0x1001>;
4617 "
4618 );
4619
4620 let mut emu = Emulator::from_block(&ctx, block);
4621 let v0_bits = u128::from(1u8) << 100;
4622 let v1_bits = u128::from(1u8) << 99;
4623
4624 emu.set_varnode_u128(V0, v0_bits).unwrap();
4625 emu.set_varnode_u128(V1, v1_bits).unwrap();
4626 emu.run_block().unwrap();
4627
4628 assert_eq!(
4630 emu.get_value(res.into()).and_then(|v| v.value()).unwrap(),
4631 2
4632 );
4633 }
4634
4635 #[test]
4640 fn uninitialized_memory_reads_error() {
4641 let space = EmulatedSpace::default();
4642 assert!(matches!(
4643 space.read_byte(0xdead_beef),
4644 Err(EmulatorErrorKind::MemoryReadError(0xdead_beef))
4645 ));
4646 assert!(matches!(
4647 space.read(0x1000, 4),
4648 Err(EmulatorErrorKind::MemoryReadError(0x1000))
4649 ));
4650 }
4651
4652 #[test]
4653 fn configured_register_and_body_temporary_spaces_zero_fill_missing_bytes() {
4654 let mut ctx = Context::new();
4655 let mut register = Space::new(Some("register"), 1, 8);
4656 register.ty = SpaceType::Register;
4657 let register = ctx.add_space(register);
4658 let function = ctx.anon_function();
4659 let temporary = MemorySpaceId::Temp(ctx.bodies[function].push_temp_space(TempSpace::new(
4660 Some("scratch"),
4661 1,
4662 8,
4663 )));
4664 let mut memory = EmulatedMemory::default();
4665 memory.configure_spaces(&ctx);
4666
4667 for space in [register.into(), temporary] {
4668 assert_eq!(
4669 memory
4670 .read(space, SizedValue::from_u64(0x1000), 4)
4671 .unwrap()
4672 .value()
4673 .unwrap(),
4674 0
4675 );
4676 }
4677
4678 memory
4679 .write(
4680 ctx.shared.default_space.into(),
4681 SizedValue::from_u64(0x1000),
4682 1,
4683 SizedValue::new(0xaa, 1),
4684 )
4685 .unwrap();
4686 assert!(matches!(
4687 memory.read(
4688 ctx.shared.default_space.into(),
4689 SizedValue::from_u64(0x1001),
4690 1
4691 ),
4692 Err(EmulatorErrorKind::MemoryReadError(0x1001))
4693 ));
4694 }
4695
4696 #[test]
4697 fn temporary_spaces_with_the_same_address_are_isolated() {
4698 use qcode::value::TempSpace;
4699
4700 let mut ctx = Context::new();
4701 let first_fn = FunctionBody::make(&mut ctx, "first".into()).unwrap().id;
4702 let second_fn = FunctionBody::make(&mut ctx, "second".into()).unwrap().id;
4703 let first = ctx.bodies[first_fn].push_temp_space(TempSpace::new(None, 1, 8));
4704 let second = ctx.bodies[second_fn].push_temp_space(TempSpace::new(None, 1, 8));
4705 assert_eq!(first.local, second.local, "fixture must collide local IDs");
4706 let first = MemorySpaceId::Temp(first);
4707 let second = MemorySpaceId::Temp(second);
4708 let mut memory = EmulatedMemory::default();
4709 memory.configure_spaces(&ctx);
4710
4711 let address = SizedValue::from_u64(0x20);
4712 memory
4713 .write(first, address, 1, SizedValue::new(0xaa, 1))
4714 .unwrap();
4715 memory
4716 .write(second, address, 1, SizedValue::new(0x55, 1))
4717 .unwrap();
4718
4719 assert_eq!(
4720 memory.read(first, address, 1).unwrap().value().unwrap(),
4721 0xaa
4722 );
4723 assert_eq!(
4724 memory.read(second, address, 1).unwrap().value().unwrap(),
4725 0x55
4726 );
4727 }
4728
4729 #[test]
4730 fn interpreter_qualifies_colliding_local_spaces_by_function() {
4731 use qcode::value::TempSpace;
4732
4733 fn make_writer(
4734 ctx: &mut Context<'static>,
4735 name: &'static str,
4736 byte: u64,
4737 ) -> (FunctionId, qcode::value::TempSpaceId) {
4738 let fid = FunctionBody::make(ctx, name.into()).unwrap().id;
4739 let root = BasicBlock::make(ctx, fid).id;
4740 FunctionBody::from_id_mut(ctx, fid).set_root(root).unwrap();
4741 let space = ctx.bodies[fid].push_temp_space(TempSpace::new(None, 1, 8));
4742 let mut b = (ctx).builder(root);
4743 let ptr = b.shr().get_const(0x20, 8);
4744 let value = b.shr().get_const(byte, 1);
4745 b.push_store(
4746 value,
4747 ptr,
4748 qcode::space::LocalMemorySpaceId::Temp(space.local),
4749 );
4750 b.push_return(ptr);
4751 (fid, space)
4752 }
4753
4754 let mut ctx = Context::new();
4755 let (first, first_space) = make_writer(&mut ctx, "first", 0xaa);
4756 let (second, second_space) = make_writer(&mut ctx, "second", 0x55);
4757 assert_eq!(first_space.local, second_space.local);
4758
4759 let root = FunctionBody::from_id(&ctx, first).root().unwrap().id;
4760 let mut emulator = StandaloneEmulator::new(root);
4761 emulator.run_function(&ctx, first).unwrap();
4762 emulator.run_function(&ctx, second).unwrap();
4763
4764 let address = SizedValue::from_u64(0x20);
4765 assert_eq!(
4766 emulator
4767 .memory
4768 .read(MemorySpaceId::Temp(first_space), address, 1)
4769 .unwrap()
4770 .value()
4771 .unwrap(),
4772 0xaa
4773 );
4774 assert_eq!(
4775 emulator
4776 .memory
4777 .read(MemorySpaceId::Temp(second_space), address, 1)
4778 .unwrap()
4779 .value()
4780 .unwrap(),
4781 0x55
4782 );
4783 }
4784
4785 #[test]
4786 fn sized_value_byte_swap_preserves_width() {
4787 let value = SizedValue::new(0x1234, 2).byte_swap().unwrap();
4788 assert_eq!(value.value().unwrap(), 0x3412);
4789 assert_eq!(value.size().unwrap(), 2);
4790 }
4791
4792 #[test]
4793 fn swap_bytes_pcode_op_is_emulated() {
4794 let mut ctx = Context::new();
4795 let op = ctx.shared.pcode_ops.push(Box::from("swap_bytes"));
4796 let block_id = {
4797 let __f = ctx.anon_function();
4798 ctx.get_or_make_block(0x1000, __f)
4799 };
4800 let target = ctx.get_or_make_block(0x1001, block_id.func);
4801 let result = {
4802 let src = ctx.get_const(0x1234, 2).id();
4803 let mut builder = ctx.builder(block_id);
4804 let result = builder.push_pcode_op(op, vec![src], None, 2).id;
4805 builder.finalize(target);
4806 result
4807 };
4808 let mut emulator = Emulator::from_block(&ctx, block_id);
4809
4810 emulator.step().unwrap();
4811
4812 assert_eq!(
4813 emulator
4814 .get_value(result.into())
4815 .and_then(|value| value.value())
4816 .unwrap(),
4817 0x3412
4818 );
4819 }
4820
4821 #[test]
4822 fn undef_pcode_op_is_zero_at_its_declared_width() {
4823 let mut ctx = Context::new();
4824 let op = ctx.shared.pcode_ops.push(Box::from("undef"));
4825 let block_id = {
4826 let function = ctx.anon_function();
4827 ctx.get_or_make_block(0x1000, function)
4828 };
4829 let target = ctx.get_or_make_block(0x1001, block_id.func);
4830 let result = {
4831 let mut builder = ctx.builder(block_id);
4832 let result = builder.push_pcode_op(op, vec![], None, 1).id;
4833 builder.finalize(target);
4834 result
4835 };
4836 let mut emulator = Emulator::from_block(&ctx, block_id);
4837
4838 emulator.step().unwrap();
4839
4840 let value = emulator.get_value(result.into()).unwrap();
4841 assert_eq!(value.value().unwrap(), 0);
4842 assert_eq!(value.size().unwrap(), 1);
4843 }
4844
4845 #[test]
4846 fn rol_intrinsic_is_emulated() {
4847 use qcode::value::insn::IntrinsicId;
4848 let mut ctx = Context::new();
4849 let rol = IntrinsicId::from_name("rol").unwrap();
4850 let block_id = {
4851 let __f = ctx.anon_function();
4852 ctx.get_or_make_block(0x1000, __f)
4853 };
4854 let target = ctx.get_or_make_block(0x1001, block_id.func);
4855 let result = {
4856 let x = ctx.get_const(0x1234_5678, 4).id();
4857 let k = ctx.get_const(8, 4).id();
4858 let mut builder = ctx.builder(block_id);
4859 let result = builder.push_intrinsic(rol, vec![x, k]).id;
4860 builder.finalize(target);
4861 result
4862 };
4863 let mut emulator = Emulator::from_block(&ctx, block_id);
4864
4865 emulator.step().unwrap();
4866
4867 assert_eq!(
4868 emulator
4869 .get_value(result.into())
4870 .and_then(|value| value.value())
4871 .unwrap(),
4872 0x1234_5678u32.rotate_left(8) as u64,
4873 );
4874 }
4875
4876 #[test]
4877 fn unknown_pcode_op_returns_typed_error() {
4878 let mut ctx = Context::new();
4879 let op = ctx.shared.pcode_ops.push(Box::from("rdpmc"));
4880 let block_id = {
4881 let __f = ctx.anon_function();
4882 ctx.get_or_make_block(0x1000, __f)
4883 };
4884 let target = ctx.get_or_make_block(0x1001, block_id.func);
4885 {
4886 let mut builder = ctx.builder(block_id);
4887 builder.push_pcode_op(op, vec![], None, 0);
4888 builder.finalize(target);
4889 }
4890 let mut emulator = Emulator::from_block(&ctx, block_id);
4891
4892 let error = emulator.step().unwrap_err();
4893
4894 assert!(matches!(
4895 error.kind,
4896 EmulatorErrorKind::UnsupportedPCodeOp(operation) if operation.as_ref() == "rdpmc"
4897 ));
4898 }
4899
4900 #[test]
4901 fn get_region_overflow_does_not_panic() {
4902 let mut space = EmulatedSpace::default();
4903 assert!(matches!(
4905 space.get_mut_region(u64::MAX - 2, 8),
4906 Err(EmulatorErrorKind::AddressOverflow(_, _))
4907 ));
4908 }
4909
4910 #[test]
4915 fn run_function_returns_ok_for_trivial_function() {
4916 let mut ctx = Context::new();
4917 qcode!(
4918 ctx,
4919 "
4920 fn function:
4921 <entry>
4922 return at i64 0;
4923 "
4924 );
4925
4926 let mut emu = Emulator::from_function(&ctx, function);
4927 assert!(emu.run_function(function).is_ok());
4928 }
4929
4930 #[test]
4931 fn run_function_executes_instructions_before_return() {
4932 let mut ctx = Context::new();
4933 qcode!(
4934 ctx,
4935 "
4936 varnode i64 A;
4937 varnode i64 B;
4938
4939 fn function:
4940 <entry>
4941 %a = load(A:8, &A);
4942 %b = load(B:8, &B);
4943 %sum = %a + %b;
4944 return at i64 0;
4945 "
4946 );
4947
4948 let mut emu = Emulator::from_function(&ctx, function);
4949 emu.set_varnode(A, 7).unwrap();
4950 emu.set_varnode(B, 5).unwrap();
4951 emu.run_function(function).unwrap();
4952
4953 assert_eq!(
4954 emu.get_value(sum.into()).and_then(|v| v.value()).unwrap(),
4955 12
4956 );
4957 }
4958
4959 #[test]
4960 fn run_function_call_stack_empty_after_successful_return() {
4961 let mut ctx = Context::new();
4962
4963 qcode!(
4964 ctx,
4965 "
4966 varnode i64 A;
4967 varnode i64 B;
4968
4969 fn function:
4970 <entry>
4971 %a = load(A:8, &A);
4972 %b = load(B:8, &B);
4973 %sum = %a + %b;
4974 return at i64 0;
4975 "
4976 );
4977
4978 let mut emu = Emulator::from_function(&ctx, function);
4979 emu.set_varnode(A, 0).unwrap();
4980 emu.set_varnode(B, 0).unwrap();
4981 emu.run_function(function).unwrap();
4982
4983 assert!(emu.call_stack().is_empty());
4984 }
4985
4986 #[test]
4987 fn unhandled_direct_call_still_enters_callee() {
4988 let mut ctx = Context::new();
4989 qcode!(
4990 ctx,
4991 "
4992 fn callee:
4993 <callee_entry>
4994 return at i64 0;
4995
4996 <caller>
4997 call <callee>;
4998 "
4999 );
5000
5001 let mut emu = Emulator::from_block(&ctx, caller);
5002 emu.step().unwrap();
5003
5004 assert_eq!(emu.block().id, callee_entry);
5005 }
5006
5007 #[test]
5008 fn handled_direct_call_resumes_at_selected_block() {
5009 let mut ctx = Context::new();
5010 qcode!(
5011 ctx,
5012 "
5013 varnode i64 RET;
5014
5015 fn library:
5016 <library_entry>
5017 return at i64 0;
5018
5019 fn function:
5020 <entry>
5021 call <library>;
5022 <after_call>
5023 %ret = load(RET:8, &RET);
5024 return at i64 0;
5025 "
5026 );
5027
5028 let mut emu = Emulator::from_function(&ctx, function);
5029 emu.set_call_interceptor(move |ctx, emu, site| {
5030 if site.target == library {
5031 emu.set_varnode(ctx, RET, 42)
5032 .map_err(|err| err.to_string().into_boxed_str())?;
5033 Ok(CallInterception::Handled(CallContinuation::Block(
5034 after_call,
5035 )))
5036 } else {
5037 Ok(CallInterception::PassThrough)
5038 }
5039 });
5040
5041 emu.run_function(function).unwrap();
5042
5043 assert_eq!(
5044 emu.get_value(ret.into()).and_then(|v| v.value()).unwrap(),
5045 42
5046 );
5047 assert!(emu.call_stack().is_empty());
5048 }
5049
5050 #[test]
5051 fn handled_direct_call_can_resume_by_address() {
5052 let mut ctx = Context::new();
5053 qcode!(
5054 ctx,
5055 "
5056 fn library:
5057 <library_entry>
5058 return at i64 0;
5059
5060 <entry>
5061 call <library>;
5062 <0x2000>
5063 return at i64 0;
5064 "
5065 );
5066
5067 let mut emu = Emulator::from_block(&ctx, entry);
5068 emu.set_call_interceptor(move |_, _, site| {
5069 if site.target == library {
5070 Ok(CallInterception::Handled(CallContinuation::Address(0x2000)))
5071 } else {
5072 Ok(CallInterception::PassThrough)
5073 }
5074 });
5075
5076 emu.step().unwrap();
5077
5078 assert_eq!(emu.block().address(), Some(0x2000));
5079 }
5080
5081 #[test]
5082 fn handled_direct_call_reports_unknown_continuation_address() {
5083 let mut ctx = Context::new();
5084 qcode!(
5085 ctx,
5086 "
5087 fn library:
5088 <library_entry>
5089 return at i64 0;
5090
5091 <entry>
5092 call <library>;
5093 "
5094 );
5095
5096 let mut emu = Emulator::from_block(&ctx, entry);
5097 emu.set_call_interceptor(move |_, _, site| {
5098 if site.target == library {
5099 Ok(CallInterception::Handled(CallContinuation::Address(0xdead)))
5100 } else {
5101 Ok(CallInterception::PassThrough)
5102 }
5103 });
5104
5105 let err = emu.step().unwrap_err();
5106
5107 assert!(matches!(
5108 err.kind,
5109 EmulatorErrorKind::InvalidBlockAddress(0xdead)
5110 ));
5111 }
5112
5113 #[test]
5114 fn call_interceptor_errors_are_reported_at_call_site() {
5115 let mut ctx = Context::new();
5116 qcode!(
5117 ctx,
5118 "
5119 fn library:
5120 <library_entry>
5121 return at i64 0;
5122
5123 <entry>
5124 call <library>;
5125 "
5126 );
5127
5128 let mut emu = Emulator::from_block(&ctx, entry);
5129 emu.set_call_interceptor(|_, _, _| Err("model failed".into()));
5130
5131 let err = emu.step().unwrap_err();
5132
5133 assert!(matches!(
5134 err.kind,
5135 EmulatorErrorKind::InterceptError(message) if message.as_ref() == "model failed"
5136 ));
5137 assert!(err.ctx.contains("call fn library();"));
5138 }
5139
5140 #[test]
5141 fn interceptor_can_model_state_across_calls() {
5142 let mut ctx = Context::new();
5143 qcode!(
5144 ctx,
5145 "
5146 fn make_object:
5147 <make_object_entry>
5148 return at i64 0;
5149
5150 fn append_byte:
5151 <append_byte_entry>
5152 return at i64 0;
5153
5154 fn function:
5155 <entry>
5156 call <make_object>;
5157 <append>
5158 call <append_byte>;
5159 <done>
5160 return at i64 0;
5161 "
5162 );
5163
5164 let modeled = Arc::new(Mutex::new(Vec::<u8>::new()));
5165 let modeled_for_hook = Arc::clone(&modeled);
5166 let mut emu = Emulator::from_function(&ctx, function);
5167 emu.set_call_interceptor(move |_, _, site| {
5168 let mut model = modeled_for_hook.lock().unwrap();
5169 if site.target == make_object {
5170 model.clear();
5171 Ok(CallInterception::Handled(CallContinuation::Block(append)))
5172 } else if site.target == append_byte {
5173 model.push(0x41);
5174 Ok(CallInterception::Handled(CallContinuation::Block(done)))
5175 } else {
5176 Ok(CallInterception::PassThrough)
5177 }
5178 });
5179
5180 emu.run_function(function).unwrap();
5181
5182 assert_eq!(*modeled.lock().unwrap(), vec![0x41]);
5183 }
5184
5185 #[test]
5190 fn branchind_to_unknown_address_returns_error() {
5191 let mut ctx = Context::new();
5192 qcode!(
5193 ctx,
5194 "
5195 fn function:
5196 <entry>
5197 # Branching to literal 0 — no block lives at address 0
5198 goto [i64 0];
5199 "
5200 );
5201
5202 let mut emu = Emulator::from_function(&ctx, function);
5203 let err = emu.run_function(function).unwrap_err();
5204 assert!(matches!(
5205 err.kind,
5206 EmulatorErrorKind::InvalidBlockAddress(0)
5207 ));
5208 }
5209
5210 #[test]
5211 fn error_includes_faulting_instruction_id() {
5212 let mut ctx = Context::new();
5213 qcode!(
5214 ctx,
5215 "
5216 fn function:
5217 <entry>
5218 # Null pointer dereference
5219 %bad_load = load(ram:8, i64 0);
5220 return at i64 0;
5221 "
5222 );
5223
5224 let mut emu = Emulator::from_function(&ctx, function);
5225 let err = emu.run_function(function).unwrap_err();
5226
5227 assert!(
5228 err.ctx.contains(
5229 &Instruction::from_id(&ctx, bad_load)
5230 .as_statement()
5231 .to_string()
5232 )
5233 );
5234 }
5235
5236 #[test]
5237 fn error_call_stack_reflects_active_frames_at_fault() {
5238 let mut ctx = Context::new();
5240 qcode!(
5241 ctx,
5242 "
5243 fn callee:
5244 <entry1>
5245 # Branching to literal 0 — no block lives at address 0
5246 goto [i64 0];
5247
5248 fn caller:
5249 <entry2>
5250 call <callee>;
5251 "
5252 );
5253
5254 let mut emu = Emulator::from_function(&ctx, caller);
5256 let err = emu.run_function(caller).unwrap_err();
5257
5258 assert!(matches!(
5259 err.kind,
5260 EmulatorErrorKind::InvalidBlockAddress(0)
5261 ));
5262 assert_eq!(emu.call_stack(), &[caller, callee]);
5263 }
5264}