use std::cell::{Ref, RefCell, RefMut};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::simd;
use std::sync::mpsc::{channel, sync_channel, Sender, SyncSender};
use std::sync::{Arc, Barrier, RwLock};
use std::thread;
use std::time;
use applevisor as av;
use regex as re;
use crate::backtrace::*;
use crate::caches::*;
use crate::config::*;
use crate::corpus::*;
use crate::coverage::*;
use crate::crash::*;
use crate::error::*;
use crate::exceptions::*;
use crate::hooks::*;
use crate::loader::*;
use crate::memory::*;
use crate::mutator::*;
use crate::tracer::*;
use crate::utils::*;
thread_local!(
pub static KSE: keystone_engine::Keystone =
keystone_engine::Keystone::new(
keystone_engine::Arch::ARM64,
keystone_engine::Mode::LITTLE_ENDIAN)
.expect("Could not initialize Keystone engine");
pub static CSE: capstone::Capstone = capstone::Capstone::new_raw(
capstone::Arch::ARM64,
capstone::Mode::Arm,
capstone::NO_EXTRA_MODE,
Some(capstone::Endian::Little),
)
.expect("Could not initialize Capstone engine");
);
pub struct HyperPomInfo {
pub start_time: time::Instant,
pub nb_testcases: u64,
pub nb_crashes: u64,
pub nb_uniq_crashes: u64,
pub nb_timeouts: u64,
pub nb_paths: u64,
}
impl HyperPomInfo {
pub fn new() -> Self {
Self {
start_time: time::Instant::now(),
nb_testcases: 0,
nb_crashes: 0,
nb_uniq_crashes: 0,
nb_timeouts: 0,
nb_paths: 0,
}
}
}
impl Default for HyperPomInfo {
fn default() -> Self {
Self::new()
}
}
impl std::ops::Add<WorkerInfo> for HyperPomInfo {
type Output = Self;
fn add(self, other: WorkerInfo) -> Self {
Self {
start_time: self.start_time,
nb_testcases: self.nb_testcases + other.nb_testcases,
nb_crashes: self.nb_crashes + other.nb_crashes,
nb_uniq_crashes: self.nb_uniq_crashes + other.nb_uniq_crashes,
nb_timeouts: self.nb_timeouts + other.nb_timeouts,
nb_paths: self.nb_paths + other.nb_paths,
}
}
}
impl std::ops::AddAssign<WorkerInfo> for HyperPomInfo {
fn add_assign(&mut self, other: WorkerInfo) {
*self = Self {
start_time: self.start_time,
nb_testcases: self.nb_testcases + other.nb_testcases,
nb_crashes: self.nb_crashes + other.nb_crashes,
nb_uniq_crashes: self.nb_uniq_crashes + other.nb_uniq_crashes,
nb_timeouts: self.nb_timeouts + other.nb_timeouts,
nb_paths: self.nb_paths + other.nb_paths,
};
}
}
pub struct HyperPom<L: 'static + Loader, LD, GD> {
hooks: Hooks<LD, GD>,
ldata: LD,
gdata: Arc<RwLock<GD>>,
global_coverage: GlobalCoverage,
loader: L,
nb_workers: u32,
pma: PhysMemAllocator,
working_directory: PathBuf,
rand: Random,
corpus: Corpus,
config: Config<LD, GD>,
_vm: av::VirtualMachine,
}
impl<
L: 'static + Loader + Loader<LD = LD> + Loader<GD = GD>,
LD: 'static + Clone + Send,
GD: 'static + Clone + Send + Sync,
> HyperPom<L, LD, GD>
{
pub fn new(config: ConfigData<LD, GD>, loader: L, ldata: LD, gdata: GD) -> Result<Self> {
let max = Self::max_worker_count()?;
let config = if let ConfigData::Fuzzer(inner_config) = config {
inner_config
} else {
return Err(CoreError::InvalidConfiguration)?;
};
if config.nb_workers > max {
return Err(CoreError::TooManyWorkers(max))?;
}
let mut rand = Random::new(config.seed);
let mut corpus = Corpus::new(
rand.split(),
&config.corpus_directory.as_ref().unwrap(),
&config.working_directory.as_ref().unwrap(),
config.load_corpus_at_init,
)?;
corpus.load_from_dir(config.max_testcase_size)?;
Ok(Self {
hooks: Hooks::<LD, GD>::new(),
ldata,
gdata: Arc::new(RwLock::new(gdata)),
global_coverage: GlobalCoverage::new(loader.coverage_ranges()?),
loader,
nb_workers: config.nb_workers,
pma: PhysMemAllocator::new(config.as_size)?,
working_directory: config.working_directory.as_ref().unwrap().clone(),
rand,
corpus,
config,
_vm: av::VirtualMachine::new()?,
})
}
pub fn max_worker_count() -> Result<u32> {
Ok(av::Vcpu::get_max_count()?)
}
pub fn fuzz(&mut self) -> Result<()> {
fs::create_dir_all(&self.working_directory)?;
let (msg_tx, msg_rx) = channel::<WorkerInfo>();
let barrier = Arc::new(Barrier::new(self.nb_workers as usize));
let mut worker_handles = (0..self.nb_workers)
.map(|i| {
let (instance_tx, instance_rx) = sync_channel::<av::VcpuInstance>(0);
let worker_name = format!("worker_{:02}", i);
let pma = self.pma.clone();
let loader = self.loader.clone();
let ldata = self.ldata.clone();
let gdata = self.gdata.clone();
let hooks = self.hooks.clone();
let corpus = self.corpus.clone();
let global_coverage = self.global_coverage.clone();
let tx = msg_tx.clone();
let rand = self.rand.split();
let working_directory = self.working_directory.join(&worker_name);
let iterations = self.config.iterations;
let config = self.config.clone();
let barrier = Arc::clone(&barrier);
let handle = thread::Builder::new()
.name(worker_name)
.spawn(move || -> Result<()> {
let mut worker = Worker::new(
av::Vcpu::new()?,
pma,
loader,
hooks,
ldata,
gdata,
global_coverage,
tx,
instance_tx,
rand,
corpus,
working_directory,
config,
barrier,
)?;
worker.init()?;
worker.run(i == 0, iterations)?;
Ok(())
})
.expect("An error occured while spawning a worker thread");
let instance = instance_rx.recv().unwrap();
let handle = WorkerHandle::new(handle);
(instance, handle)
})
.collect::<HashMap<_, _>>();
let mut info = HyperPomInfo::new();
let mut corpus_loaded = false;
loop {
while let Some(wi) = msg_rx.try_iter().next() {
if let Some(handle) = worker_handles.get_mut(&wi.instance) {
if !corpus_loaded {
corpus_loaded = true;
info.start_time = time::Instant::now();
}
handle.latest_ping = time::Instant::now();
info += wi;
}
}
if corpus_loaded {
self.loader.display_info(&info);
}
worker_handles.drain_filter(|instance, handle| {
if let Some(join_handle) = handle.join_handle.as_mut() {
if join_handle.is_finished() {
match handle.join_handle.take() {
Some(h) => h
.join()
.expect("An error occured while joining threads")
.expect("thread panicked"),
None => {}
};
true
} else {
if time::Instant::now() - handle.latest_ping > self.config.timeout {
av::Vcpu::stop(&[*instance]).expect("could not stop Vcpu");
}
false
}
} else {
true
}
});
if worker_handles.is_empty() {
break;
}
thread::sleep(std::time::Duration::new(0, 1000));
}
Ok(())
}
}
pub struct WorkerHandle {
join_handle: Option<thread::JoinHandle<Result<()>>>,
latest_ping: time::Instant,
}
impl WorkerHandle {
fn new(handle: thread::JoinHandle<Result<()>>) -> Self {
Self {
join_handle: Some(handle),
latest_ping: time::Instant::now(),
}
}
}
#[derive(Debug)]
pub struct WorkerInfo {
instance: av::VcpuInstance,
nb_testcases: u64,
nb_crashes: u64,
nb_uniq_crashes: u64,
nb_timeouts: u64,
nb_paths: u64,
}
impl WorkerInfo {
fn new(instance: av::VcpuInstance) -> Self {
Self {
instance,
nb_testcases: 0,
nb_crashes: 0,
nb_uniq_crashes: 0,
nb_timeouts: 0,
nb_paths: 0,
}
}
}
#[allow(rustdoc::private_intra_doc_links)]
pub struct Worker<L: Loader, LD, GD> {
executor: Executor<L, LD, GD>,
instance: av::VcpuInstance,
channel_tx: Sender<WorkerInfo>,
corpus: Corpus,
mutator: Mutator,
working_directory: PathBuf,
crash_handler: CrashHandler,
barrier: Arc<Barrier>,
}
impl<L: Loader + Loader<LD = LD> + Loader<GD = GD>, LD: Clone, GD: Clone> Worker<L, LD, GD> {
#[allow(clippy::too_many_arguments)]
fn new(
vcpu: av::Vcpu,
pma: PhysMemAllocator,
loader: L,
hooks: Hooks<LD, GD>,
ldata: LD,
gdata: Arc<RwLock<GD>>,
global_coverage: GlobalCoverage,
channel_tx: Sender<WorkerInfo>,
instance_tx: SyncSender<av::VcpuInstance>,
mut rand: Random,
corpus: Corpus,
working_directory: PathBuf,
config: Config<LD, GD>,
barrier: Arc<Barrier>,
) -> Result<Self> {
let instance = vcpu.get_instance();
instance_tx.send(instance).unwrap();
let crash_handler = CrashHandler::new(working_directory.join("crashes"), rand.split())?;
let mutator = Mutator::new(rand.split());
Ok(Self {
executor: Executor::new_hyperpom(
vcpu,
pma,
loader,
hooks,
ldata,
gdata,
global_coverage,
config,
)?,
instance,
channel_tx,
corpus,
mutator,
working_directory,
crash_handler,
barrier,
})
}
fn init(&mut self) -> Result<()> {
fs::create_dir_all(&self.working_directory)?;
self.executor.init()?;
Ok(())
}
fn load_corpus(&mut self, wi: &mut WorkerInfo) -> Result<()> {
println!("Loading corpus...");
let inner = self.corpus.inner.read().unwrap();
for (_, testcase) in inner.testcases.iter() {
if testcase.path.is_none() {
continue;
}
println!("Loading: {}", &testcase.path.as_ref().unwrap().display());
let _ = self.executor.run(Some(testcase))?;
if let Some(new_paths) = self
.executor
.global_coverage
.update_new_coverage(&self.executor.cdata)
{
wi.nb_paths += new_paths;
}
self.executor.restore_snapshot(SnapshotAction::Restore)?;
self.executor.cdata.clear();
self.executor.bdata.clear();
}
println!("Corpus loaded!");
Ok(())
}
fn get_crash_backtrace(&mut self, crash: &Testcase) -> Result<Option<u64>> {
self.executor
.restore_snapshot(SnapshotAction::SwitchToBacktrace)?;
let mut saved_hash = None;
for _ in 0..self.executor.config.crash_verif_iterations {
self.executor.cdata.clear();
self.executor.bdata.clear();
self.executor.restore_snapshot(SnapshotAction::Restore)?;
match self.executor.run(Some(crash))? {
ExitKind::Crash(_) => {
if let Some(hash) = saved_hash {
if Backtrace::get_crash_hash(&self.executor.bdata) != hash {
return Ok(None);
} else {
continue;
}
} else {
saved_hash = Some(Backtrace::get_crash_hash(&self.executor.bdata));
continue;
}
}
_ => return Ok(None),
}
}
Ok(saved_hash)
}
#[allow(clippy::never_loop)]
fn run(&mut self, init_corpus: bool, mut iterations: Option<u64>) -> Result<()> {
let mut latest_ping = time::Instant::now();
let mut worker_info = WorkerInfo::new(self.instance);
let mut reset = false;
let mut keep_testcase = false;
if init_corpus {
self.load_corpus(&mut worker_info)
.expect("could not load corpus");
}
self.barrier.wait();
let mut loader = self.executor.loader.clone();
let mut testcase = self.corpus.get_testcase();
let mut seed = self.mutator.mutate(
&loader,
testcase.get_data_mut(),
self.executor.config.max_testcase_size,
self.executor.config.max_nb_mutations,
);
let mut prev_cov = Coverage::new();
loop {
if self.executor.config.remove_coverage_hooks_on_hit
&& prev_cov.count() < self.executor.global_coverage.count()
{
let inner = self.executor.global_coverage.inner.read().unwrap();
for addr in inner.coverage.set.difference(&prev_cov.set) {
self.executor.hooks.revert_coverage_hooks(
*addr as u64,
&mut self.executor.vma.borrow_mut(),
&mut self.executor.vma.borrow_snapshot_mut(),
)?;
}
prev_cov = self.executor.global_coverage.cloned();
}
'reset: loop {
if reset {
self.executor.restore_snapshot(SnapshotAction::Restore)?;
}
if !keep_testcase {
self.executor.bdata.clear();
testcase = self.corpus.get_testcase();
seed = self.mutator.mutate(
&loader,
testcase.get_data_mut(),
self.executor.config.max_testcase_size,
self.executor.config.max_nb_mutations,
);
}
loop {
match loader.load_testcase(&mut self.executor, testcase.get_data())? {
LoadTestcaseAction::New => {
keep_testcase = false;
reset = false;
}
LoadTestcaseAction::NewAndReset => {
keep_testcase = false;
reset = true;
}
LoadTestcaseAction::Keep => {
keep_testcase = true;
reset = false;
}
LoadTestcaseAction::KeepAndReset => {
keep_testcase = true;
reset = true;
}
LoadTestcaseAction::Invalid => {
keep_testcase = false;
reset = false;
continue 'reset;
}
LoadTestcaseAction::InvalidAndReset => {
keep_testcase = false;
reset = true;
continue 'reset;
}
}
break;
}
break;
}
let exec_time_start = time::Instant::now();
let ek = {
let pre_exec_ret = loader.pre_exec(&mut self.executor)?;
if let ExitKind::Continue = pre_exec_ret {
self.executor.vcpu.set_reg(av::Reg::LR, END_ADDR)?;
let exec_ret = match iterations.as_mut() {
Some(0) => break,
Some(x) => {
*x -= 1;
self.executor.vcpu_run()?
}
None => self.executor.vcpu_run()?,
};
loader.post_exec(&mut self.executor)?;
exec_ret
} else {
pre_exec_ret
}
};
let exec_time_end = time::Instant::now();
testcase.exec_time = exec_time_end - exec_time_start;
testcase.coverage = self.executor.cdata.clone();
worker_info.nb_testcases += 1;
if time::Instant::now() - latest_ping > time::Duration::new(1, 0) {
latest_ping = time::Instant::now();
let tmp_worker_info = worker_info;
worker_info = WorkerInfo::new(self.executor.vcpu.get_instance());
self.channel_tx.send(tmp_worker_info).unwrap();
}
match ek {
ExitKind::Crash(title) => {
let cdata = self.executor.cdata.clone();
let hash = self.get_crash_backtrace(&testcase)?;
if let Some(hash) = hash {
let new_crash = self.executor.global_coverage.update_new_crashes(hash);
if new_crash && self.executor.config.save_crashes {
self.crash_handler.store_crash(
&loader,
&title,
&testcase,
&self.executor,
false,
)?;
worker_info.nb_uniq_crashes += 1;
}
worker_info.nb_crashes += 1;
}
self.executor
.restore_snapshot(SnapshotAction::SwitchToCoverage)?;
self.executor.cdata = cdata;
reset = true;
keep_testcase = false;
}
ExitKind::Timeout => {
if self.executor.config.save_timeouts {
self.crash_handler.store_crash(
&loader,
"Timeout",
&testcase,
&self.executor,
true,
)?;
}
worker_info.nb_timeouts += 1;
reset = true;
keep_testcase = false;
continue;
}
_ => {}
}
if !testcase.is_empty() && !keep_testcase {
if let Some(new_paths) = self
.executor
.global_coverage
.update_new_coverage(&self.executor.cdata)
{
let mut testcase = testcase.clone();
testcase.set_seed(seed);
self.corpus.add_testcase(testcase)?;
worker_info.nb_paths += new_paths;
}
}
}
Ok(())
}
}
pub enum SnapshotAction {
Restore,
SwitchToCoverage,
SwitchToBacktrace,
}
pub enum VirtMemMode {
Coverage,
Backtrace,
}
pub struct VirtMem {
pub mode: VirtMemMode,
pub covtrace: RefCell<VirtMemAllocator>,
pub covtrace_snapshot: RefCell<VirtMemAllocator>,
pub backtrace: RefCell<VirtMemAllocator>,
pub backtrace_snapshot: RefCell<VirtMemAllocator>,
}
impl VirtMem {
pub fn new(pma: PhysMemAllocator) -> Result<Self> {
Ok(Self {
mode: VirtMemMode::Coverage,
covtrace: RefCell::new(VirtMemAllocator::new(pma.clone())?),
covtrace_snapshot: RefCell::new(VirtMemAllocator::new(pma.clone())?),
backtrace: RefCell::new(VirtMemAllocator::new(pma.clone())?),
backtrace_snapshot: RefCell::new(VirtMemAllocator::new(pma)?),
})
}
pub fn borrow(&self) -> Ref<'_, VirtMemAllocator> {
match self.mode {
VirtMemMode::Coverage => self.covtrace.borrow(),
VirtMemMode::Backtrace => self.backtrace.borrow(),
}
}
pub fn borrow_mut(&self) -> RefMut<'_, VirtMemAllocator> {
match self.mode {
VirtMemMode::Coverage => self.covtrace.borrow_mut(),
VirtMemMode::Backtrace => self.backtrace.borrow_mut(),
}
}
pub fn borrow_snapshot(&self) -> Ref<'_, VirtMemAllocator> {
match self.mode {
VirtMemMode::Coverage => self.covtrace_snapshot.borrow(),
VirtMemMode::Backtrace => self.backtrace_snapshot.borrow(),
}
}
pub fn borrow_snapshot_mut(&self) -> RefMut<'_, VirtMemAllocator> {
match self.mode {
VirtMemMode::Coverage => self.covtrace_snapshot.borrow_mut(),
VirtMemMode::Backtrace => self.backtrace_snapshot.borrow_mut(),
}
}
pub fn map(&mut self, addr: u64, size: usize, perms: av::MemPerms) -> Result<()> {
self.borrow_mut().map(addr, size, perms)
}
pub fn map_privileged(&mut self, addr: u64, size: usize, perms: av::MemPerms) -> Result<()> {
self.borrow_mut().map_privileged(addr, size, perms)
}
pub fn unmap(&mut self, addr: u64, size: usize) -> Result<()> {
self.borrow_mut().unmap(addr, size)
}
pub fn restore_from_snapshot(&mut self, snapshot: &VirtMemAllocator) -> Result<()> {
self.borrow_mut().restore_from_snapshot(snapshot)
}
pub fn read(&self, addr: u64, buf: &mut [u8]) -> Result<usize> {
self.borrow().read(addr, buf)
}
#[inline]
pub fn read_byte(&self, addr: u64) -> Result<u8> {
self.borrow().read_byte(addr)
}
#[inline]
pub fn read_word(&self, addr: u64) -> Result<u16> {
self.borrow().read_word(addr)
}
#[inline]
pub fn read_dword(&self, addr: u64) -> Result<u32> {
self.borrow().read_dword(addr)
}
#[inline]
pub fn read_qword(&self, addr: u64) -> Result<u64> {
self.borrow().read_qword(addr)
}
#[inline]
pub fn read_cstring(&self, addr: u64) -> Result<String> {
self.borrow().read_cstring(addr)
}
#[inline]
pub fn write(&mut self, addr: u64, buf: &[u8]) -> Result<usize> {
self.borrow_mut().write(addr, buf)
}
#[inline]
pub fn write_byte(&mut self, addr: u64, data: u8) -> Result<usize> {
self.borrow_mut().write_byte(addr, data)
}
#[inline]
pub fn write_word(&mut self, addr: u64, data: u16) -> Result<usize> {
self.borrow_mut().write_word(addr, data)
}
#[inline]
pub fn write_dword(&mut self, addr: u64, data: u32) -> Result<usize> {
self.borrow_mut().write_dword(addr, data)
}
#[inline]
pub fn write_qword(&mut self, addr: u64, data: u64) -> Result<usize> {
self.borrow_mut().write_qword(addr, data)
}
#[inline]
pub fn write_cstring(&mut self, addr: u64, s: &str) -> Result<usize> {
self.borrow_mut().write_cstring(addr, s)
}
#[inline]
pub fn write_dirty(&mut self, addr: u64, buf: &[u8]) -> Result<usize> {
self.borrow_mut().write_dirty(addr, buf)
}
#[inline]
pub fn write_byte_dirty(&mut self, addr: u64, data: u8) -> Result<usize> {
self.borrow_mut().write_byte_dirty(addr, data)
}
#[inline]
pub fn write_word_dirty(&mut self, addr: u64, data: u16) -> Result<usize> {
self.borrow_mut().write_word_dirty(addr, data)
}
#[inline]
pub fn write_dword_dirty(&mut self, addr: u64, data: u32) -> Result<usize> {
self.borrow_mut().write_dword_dirty(addr, data)
}
#[inline]
pub fn write_qword_dirty(&mut self, addr: u64, data: u64) -> Result<usize> {
self.borrow_mut().write_qword_dirty(addr, data)
}
#[inline]
pub fn write_cstring_dirty(&mut self, addr: u64, s: &str) -> Result<usize> {
self.borrow_mut().write_cstring_dirty(addr, s)
}
}
pub struct Executor<L: Loader, LD, GD> {
pub vcpu: av::Vcpu,
pub pma: Option<PhysMemAllocator>,
pub vma: VirtMem,
pub loader: L,
pub loader_copy: Option<L>,
pub hooks: Hooks<LD, GD>,
pub ldata: LD,
pub gdata: Arc<RwLock<GD>>,
pub cdata: Coverage,
pub bdata: Backtrace,
pub global_coverage: GlobalCoverage,
pub config: Config<LD, GD>,
pub symbols: Symbols,
pub registers_snapshot: Vec<u64>,
pub sys_registers_snapshot: Vec<u64>,
pub fp_registers_snapshot: Vec<simd::i8x16>,
}
impl<L: Loader + Loader<LD = LD> + Loader<GD = GD>, LD: Clone, GD: Clone> Executor<L, LD, GD> {
pub fn new(config: ConfigData<LD, GD>, loader: L, ldata: LD, gdata: GD) -> Result<Self> {
let config = if let ConfigData::Executor(inner_config) = config {
inner_config
} else {
return Err(CoreError::InvalidConfiguration)?;
};
let pma = PhysMemAllocator::new(config.as_size)?;
let symbols = loader.symbols()?;
let coverage_ranges = loader.coverage_ranges()?;
Ok(Self {
vcpu: av::Vcpu::new()?,
pma: Some(pma.clone()),
vma: VirtMem::new(pma)?,
loader,
loader_copy: None,
hooks: Hooks::<LD, GD>::new(),
ldata,
gdata: Arc::new(RwLock::new(gdata)),
cdata: Coverage::new(),
bdata: Backtrace::new(),
global_coverage: GlobalCoverage::new(coverage_ranges),
config,
symbols,
registers_snapshot: vec![],
sys_registers_snapshot: vec![],
fp_registers_snapshot: vec![],
})
}
#[allow(clippy::too_many_arguments)]
fn new_hyperpom(
vcpu: av::Vcpu,
pma: PhysMemAllocator,
loader: L,
hooks: Hooks<LD, GD>,
ldata: LD,
gdata: Arc<RwLock<GD>>,
global_coverage: GlobalCoverage,
config: Config<LD, GD>,
) -> Result<Self> {
let symbols = loader.symbols()?;
Ok(Self {
vcpu,
pma: None,
vma: VirtMem::new(pma)?,
loader,
loader_copy: None,
hooks,
ldata,
gdata,
cdata: Coverage::new(),
bdata: Backtrace::new(),
global_coverage,
config,
symbols,
registers_snapshot: vec![],
sys_registers_snapshot: vec![],
fp_registers_snapshot: vec![],
})
}
pub fn init(&mut self) -> Result<()> {
let mut loader = self.loader.clone();
loader.map(self)?;
self.vma.covtrace.borrow_mut().init(&mut self.vcpu, true)?;
loader.hooks(self)?;
self.hooks.apply(&mut self.vma.covtrace.borrow_mut())?;
Caches::init(&mut self.vcpu, &mut self.vma.covtrace.borrow_mut())?;
loader.pre_snapshot(self)?;
self.loader = loader.clone();
self.loader_copy = Some(loader);
self.vcpu.set_reg(av::Reg::LR, END_ADDR)?;
*self.vma.backtrace.borrow_mut() = self.vma.covtrace.borrow().clone();
let mut hooks_backtrace = self.hooks.clone();
if self.config.tracer {
Tracer::add_hooks(
self.loader.trace_ranges()?,
self.config.tracer_hook,
&mut self.hooks,
)?;
}
if self.config.coverage {
self.global_coverage.add_hooks(
&self.vma.covtrace.borrow_mut(),
&mut self.hooks,
self.config.comparison_unrolling,
)?;
}
self.hooks.apply(&mut self.vma.covtrace.borrow_mut())?;
*self.vma.covtrace_snapshot.borrow_mut() = self.vma.covtrace.borrow().clone();
Backtrace::add_hooks(
self.loader.coverage_ranges()?,
&self.vma.backtrace.borrow(),
&mut hooks_backtrace,
)?;
Backtrace::add_hooks(
self.loader.coverage_ranges()?,
&self.vma.backtrace.borrow(),
&mut self.hooks,
)?;
hooks_backtrace.apply(&mut self.vma.backtrace.borrow_mut())?;
*self.vma.backtrace_snapshot.borrow_mut() = self.vma.backtrace.borrow().clone();
self.hooks
.fill_instructions(&mut self.vma.covtrace.borrow_mut())?;
self.save_registers()?;
self.save_sys_registers()?;
self.save_fp_registers()?;
Ok(())
}
pub fn add_custom_hook(&mut self, addr: u64, hook: HookFn<LD, GD>) {
self.hooks.add_custom_hook(addr, hook);
}
pub fn add_function_hook(&mut self, name: &str, hook: HookFn<LD, GD>) -> Result<()> {
let symbol = self
.symbols
.symbols
.iter()
.find(|(_, s)| s.name == name)
.map(|(_, s)| s)
.ok_or_else(|| Error::Loader(LoaderError::UnknownSymbol(name.to_string())))?;
self.hooks.add_custom_hook(symbol.addr, hook);
Ok(())
}
pub fn add_instruction_hook(&mut self, pattern: &str, hook: HookFn<LD, GD>) -> Result<()> {
let re = re::Regex::new(pattern).unwrap();
for CodeRange(range) in self.loader.code_ranges()? {
for addr in range.clone().step_by(4) {
let mut code = [0; 4];
self.vma.borrow().read(addr, &mut code)?;
CSE.with(|cs| {
let insns = cs
.disasm_count(&code, addr, 1)
.expect("could not disassemble while adding coverage hooks");
if let Some(insn) = insns.as_ref().get(0) {
if re.is_match(&format!(
"{} {}",
insn.mnemonic().unwrap(),
insn.op_str().unwrap()
)) {
self.hooks.add_custom_hook(addr, hook);
}
}
});
}
}
Ok(())
}
pub fn remove_custom_hook(&mut self, addr: u64) {
self.hooks.remove_custom_hook(addr);
}
pub fn add_exit_hook(&mut self, addr: u64) {
self.hooks.add_exit_hook(addr);
}
pub fn remove_exit_hook(&mut self, addr: u64) {
self.hooks.remove_exit_hook(addr);
}
#[inline]
pub fn vcpu_run(&mut self) -> Result<ExitKind> {
loop {
self.vcpu.run()?;
let exit_info = self.vcpu.get_exit_info();
let exit = match exit_info.reason {
av::ExitReason::CANCELED => ExitKind::Timeout,
av::ExitReason::EXCEPTION => Exceptions::handle::<L, LD, GD>(self)?,
av::ExitReason::VTIMER_ACTIVATED => unimplemented!(),
av::ExitReason::UNKNOWN => panic!(
"Vcpu exited unexpectedly at address {:#x}",
self.vcpu.get_reg(av::Reg::PC)?
),
};
match exit {
ExitKind::Continue => continue,
_ => break Ok(exit),
}
}
}
#[inline]
pub fn run(&mut self, testcase: Option<&Testcase>) -> Result<ExitKind> {
let mut reset = false;
let mut keep_testcase = false;
let mut loader = self.loader_copy.take().unwrap();
loader.reset_state(self)?;
loop {
if let Some(testcase) = testcase {
match loader.load_testcase(self, testcase.get_data())? {
LoadTestcaseAction::Invalid | LoadTestcaseAction::InvalidAndReset => {
self.loader_copy = Some(loader);
return Err(CoreError::InvalidTestcase)?;
}
LoadTestcaseAction::Keep => {
keep_testcase = true;
reset = false;
}
LoadTestcaseAction::KeepAndReset => {
keep_testcase = true;
reset = true;
}
_ => {}
}
}
let ek = self.run_inner(&mut loader)?;
match ek {
ExitKind::Crash(_) | ExitKind::Timeout => {
self.loader_copy = Some(loader);
return Ok(ek);
}
_ => {
if keep_testcase {
if reset {
self.restore_snapshot(SnapshotAction::Restore)?;
}
continue;
}
self.loader_copy = Some(loader);
return Ok(ek);
}
}
}
}
#[inline]
fn run_inner(&mut self, loader: &mut L) -> Result<ExitKind> {
let pre_exec_ret = loader.pre_exec(self)?;
if let ExitKind::Continue = pre_exec_ret {
self.vcpu.set_reg(av::Reg::LR, END_ADDR)?;
let exec_ret = self.vcpu_run()?;
loader.post_exec(self)?;
Ok(exec_ret)
} else {
Ok(pre_exec_ret)
}
}
#[inline]
pub fn restore_snapshot(&mut self, snapshot_action: SnapshotAction) -> Result<()> {
self.vcpu.set_reg(av::Reg::LR, END_ADDR)?;
self.vcpu.set_reg(av::Reg::PC, END_ADDR)?;
match snapshot_action {
SnapshotAction::Restore => {
let mut vma = self.vma.borrow_mut();
let vma_snapshot = self.vma.borrow_snapshot();
vma.restore_from_snapshot(&vma_snapshot)?;
vma.set_trans_table_base_registers(&self.vcpu)?;
Caches::tlbi_vmalle1_ic_ialluis(&mut self.vcpu, &mut vma)?;
}
SnapshotAction::SwitchToCoverage => {
self.vma.mode = VirtMemMode::Coverage;
let mut vma = self.vma.borrow_mut();
vma.set_trans_table_base_registers(&self.vcpu)?;
Caches::tlbi_vmalle1_ic_ialluis(&mut self.vcpu, &mut vma)?;
}
SnapshotAction::SwitchToBacktrace => {
self.vma.mode = VirtMemMode::Backtrace;
let mut vma = self.vma.borrow_mut();
vma.set_trans_table_base_registers(&self.vcpu)?;
Caches::tlbi_vmalle1_ic_ialluis(&mut self.vcpu, &mut vma)?;
}
}
self.vcpu_run()?;
self.restore_registers()?;
self.restore_sys_registers()?;
self.restore_fp_registers()?;
let vma = self.vma.borrow();
vma.set_trans_table_base_registers(&self.vcpu)?;
Ok(())
}
pub fn save_registers(&mut self) -> Result<()> {
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X0)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X1)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X2)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X3)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X4)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X5)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X6)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X7)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X8)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X9)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X10)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X11)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X12)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X13)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X14)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X15)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X16)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X17)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X18)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X19)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X20)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X21)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X22)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X23)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X24)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X25)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X26)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X27)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X28)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::X29)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::PC)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::FPCR)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::FPSR)?);
self.registers_snapshot
.push(self.vcpu.get_reg(av::Reg::CPSR)?);
Ok(())
}
pub fn restore_registers(&self) -> Result<()> {
let mut iter = self.registers_snapshot.iter();
self.vcpu.set_reg(av::Reg::X0, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X1, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X2, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X3, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X4, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X5, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X6, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X7, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X8, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X9, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X10, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X11, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X12, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X13, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X14, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X15, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X16, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X17, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X18, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X19, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X20, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X21, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X22, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X23, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X24, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X25, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X26, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X27, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X28, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::X29, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::PC, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::FPCR, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::FPSR, *iter.next().unwrap())?;
self.vcpu.set_reg(av::Reg::CPSR, *iter.next().unwrap())?;
Ok(())
}
pub fn save_sys_registers(&mut self) -> Result<()> {
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR0_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR0_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR0_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR0_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR1_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR1_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR1_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR1_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR2_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR2_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR2_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR2_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR3_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR3_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR3_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR3_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR4_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR4_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR4_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR4_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR5_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR5_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR5_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR5_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR6_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR6_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR6_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR6_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR7_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR7_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR7_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR7_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR8_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR8_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR8_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR8_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR9_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR9_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR9_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR9_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR10_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR10_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR10_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR10_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR11_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR11_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR11_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR11_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR12_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR12_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR12_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR12_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR13_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR13_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR13_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR13_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR14_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR14_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR14_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR14_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBVR15_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGBCR15_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWVR15_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::DBGWCR15_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::MDCCINT_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::MDSCR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::MIDR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::MPIDR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::SCTLR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::CPACR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::TTBR0_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::TTBR1_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::TCR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APIAKEYLO_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APIAKEYHI_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APIBKEYLO_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APIBKEYHI_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APDAKEYLO_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APDAKEYHI_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APDBKEYLO_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APDBKEYHI_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APGAKEYLO_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::APGAKEYHI_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::SPSR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::ELR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::SP_EL0)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::AFSR0_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::AFSR1_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::ESR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::FAR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::PAR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::MAIR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::AMAIR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::VBAR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::CONTEXTIDR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::TPIDR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::CNTKCTL_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::CSSELR_EL1)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::TPIDR_EL0)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::TPIDRRO_EL0)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::CNTV_CTL_EL0)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::CNTV_CVAL_EL0)?);
self.sys_registers_snapshot
.push(self.vcpu.get_sys_reg(av::SysReg::SP_EL1)?);
Ok(())
}
pub fn restore_sys_registers(&self) -> Result<()> {
let mut iter = self.sys_registers_snapshot.iter();
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR0_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR0_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR0_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR0_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR1_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR1_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR1_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR1_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR2_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR2_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR2_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR2_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR3_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR3_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR3_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR3_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR4_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR4_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR4_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR4_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR5_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR5_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR5_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR5_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR6_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR6_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR6_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR6_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR7_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR7_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR7_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR7_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR8_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR8_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR8_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR8_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR9_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR9_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR9_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR9_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR10_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR10_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR10_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR10_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR11_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR11_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR11_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR11_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR12_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR12_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR12_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR12_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR13_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR13_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR13_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR13_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR14_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR14_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR14_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR14_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBVR15_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGBCR15_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWVR15_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::DBGWCR15_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::MDCCINT_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::MDSCR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::MIDR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::MPIDR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::SCTLR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::CPACR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::TTBR0_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::TTBR1_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::TCR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APIAKEYLO_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APIAKEYHI_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APIBKEYLO_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APIBKEYHI_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APDAKEYLO_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APDAKEYHI_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APDBKEYLO_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APDBKEYHI_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APGAKEYLO_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::APGAKEYHI_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::SPSR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::ELR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::SP_EL0, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::AFSR0_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::AFSR1_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::ESR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::FAR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::PAR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::MAIR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::AMAIR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::VBAR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::CONTEXTIDR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::TPIDR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::CNTKCTL_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::CSSELR_EL1, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::TPIDR_EL0, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::TPIDRRO_EL0, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::CNTV_CTL_EL0, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::CNTV_CVAL_EL0, *iter.next().unwrap())?;
self.vcpu
.set_sys_reg(av::SysReg::SP_EL1, *iter.next().unwrap())?;
Ok(())
}
pub fn save_fp_registers(&mut self) -> Result<()> {
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q0)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q1)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q2)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q3)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q4)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q5)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q6)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q7)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q8)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q9)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q10)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q11)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q12)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q13)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q14)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q15)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q16)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q17)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q18)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q19)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q20)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q21)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q22)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q23)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q24)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q25)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q26)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q27)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q28)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q29)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q30)?);
self.fp_registers_snapshot
.push(self.vcpu.get_simd_fp_reg(av::SimdFpReg::Q31)?);
Ok(())
}
pub fn restore_fp_registers(&self) -> Result<()> {
let mut iter = self.fp_registers_snapshot.iter();
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q0, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q1, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q2, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q3, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q4, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q5, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q6, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q7, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q8, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q9, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q10, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q11, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q12, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q13, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q14, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q15, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q16, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q17, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q18, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q19, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q20, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q21, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q22, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q23, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q24, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q25, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q26, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q27, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q28, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q29, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q30, *iter.next().unwrap())?;
self.vcpu
.set_simd_fp_reg(av::SimdFpReg::Q31, *iter.next().unwrap())?;
Ok(())
}
}
#[macro_export]
macro_rules! args_count {
() => {0};
($head:expr, $($tail:expr,)*) => {1 + args_count!($($tail,)*)};
}
#[macro_export]
macro_rules! call_func {
($exec:expr, $name:tt) => {{
let symbol = $exec
.symbols
.symbols
.iter()
.find(|(_, s)| &s.name == $name)
.map(|(_, s)| s)
.ok_or(Error::Loader(LoaderError::UnknownSymbol($name.to_string())))?;
call_func_by_addr! { $exec, symbol.addr }
}};
($exec:expr, $name:tt, $($x:expr),*) => {{
let saved_sp = $exec.vcpu.get_sys_reg($crate::applevisor::SysReg::SP_EL0)?;
let mut index = 0;
let count = args_count!($($x,)*);
let mut sp = if count > 8 {
let sp_size = (count - 8) * 8;
$exec.vcpu.set_sys_reg($crate::applevisor::SysReg::SP_EL0, saved_sp + sp_size)?;
saved_sp + sp_size
} else {
0
};
$(
match index {
0 => $exec.vcpu.set_reg($crate::applevisor::Reg::X0, $x)?,
1 => $exec.vcpu.set_reg($crate::applevisor::Reg::X1, $x)?,
2 => $exec.vcpu.set_reg($crate::applevisor::Reg::X2, $x)?,
3 => $exec.vcpu.set_reg($crate::applevisor::Reg::X3, $x)?,
4 => $exec.vcpu.set_reg($crate::applevisor::Reg::X4, $x)?,
5 => $exec.vcpu.set_reg($crate::applevisor::Reg::X5, $x)?,
6 => $exec.vcpu.set_reg($crate::applevisor::Reg::X6, $x)?,
7 => $exec.vcpu.set_reg($crate::applevisor::Reg::X7, $x)?,
_ => {
$exec.vcpu.set_sys_reg($crate::applevisor::SysReg::SP_EL0, sp)?;
$exec.vma.borrow_mut().write_qword(sp, $x)?;
sp += 8;
},
}
index += 1;
)*
call_func! { $exec, $name }
}};
}
#[macro_export]
macro_rules! call_func_by_addr {
($exec:expr, $addr:expr) => {{
let saved_psr = $exec.vcpu.get_reg($crate::applevisor::Reg::CPSR)?;
let saved_pc = $exec.vcpu.get_reg($crate::applevisor::Reg::PC)?;
let saved_lr = $exec.vcpu.get_reg($crate::applevisor::Reg::LR)?;
$exec.vcpu.set_reg($crate::applevisor::Reg::LR, $crate::exceptions::END_ADDR)?;
$exec.vcpu.set_reg($crate::applevisor::Reg::PC, $addr)?;
let ret = $exec.vcpu_run()?;
$exec.vcpu.set_reg($crate::applevisor::Reg::LR, saved_lr)?;
$exec.vcpu.set_reg($crate::applevisor::Reg::PC, saved_pc)?;
$exec.vcpu.set_reg($crate::applevisor::Reg::CPSR, saved_psr)?;
Ok::<(u64, $crate::crash::ExitKind), Error>(($exec.vcpu.get_reg($crate::applevisor::Reg::X0)?, ret))
}};
($exec:expr, $addr:expr, $($x:expr),*) => {{
let saved_sp = $exec.vcpu.get_sys_reg($crate::applevisor::SysReg::SP_EL0)?;
let mut index = 0;
let count = args_count!($($x,)*);
let mut sp = if count > 8 {
let sp_size = (count - 8) * 8;
$exec.vcpu.set_sys_reg($crate::applevisor::SysReg::SP_EL0, saved_sp + sp_size)?;
saved_sp + sp_size
} else {
0
};
$(
match index {
0 => $exec.vcpu.set_reg($crate::applevisor::Reg::X0, $x)?,
1 => $exec.vcpu.set_reg($crate::applevisor::Reg::X1, $x)?,
2 => $exec.vcpu.set_reg($crate::applevisor::Reg::X2, $x)?,
3 => $exec.vcpu.set_reg($crate::applevisor::Reg::X3, $x)?,
4 => $exec.vcpu.set_reg($crate::applevisor::Reg::X4, $x)?,
5 => $exec.vcpu.set_reg($crate::applevisor::Reg::X5, $x)?,
6 => $exec.vcpu.set_reg($crate::applevisor::Reg::X6, $x)?,
7 => $exec.vcpu.set_reg($crate::applevisor::Reg::X7, $x)?,
_ => {
$exec.vcpu.set_sys_reg($crate::applevisor::SysReg::SP_EL0, sp)?;
$exec.vma.borrow_mut().write_qword(sp, $x)?;
sp += 8;
},
}
index += 1;
)*
call_func_by_addr! { $exec, $addr }
}};
}