use iced_x86::{Decoder, DecoderOptions};
use crate::debug::console::Console;
use crate::emu::Emu;
use crate::engine;
use crate::err::MwemuError;
use crate::windows::constants;
use super::assert_x86_arch;
pub(crate) fn ensure_instruction_cache_populated_x86(
emu: &mut Emu,
pc: u64,
block: &mut Vec<u8>,
arch_bits: u32,
) -> Result<(), MwemuError> {
let cache_hit = emu.x86_instruction_cache().lookup_entry(pc, 0);
if cache_hit {
return Ok(());
}
if block.is_empty() {
return Err(MwemuError::new("cannot read code block, weird address."));
}
let code = match emu.maps.get_mem_by_addr(pc) {
Some(code) => code,
None => {
log::trace!("code flow to unmapped address 0x{:x}", pc);
Console::spawn_console(emu);
return Err(MwemuError::new("cannot read program counter"));
}
};
let block_slice = code.read_bytes(pc, constants::BLOCK_LEN);
if block_slice.len() != block.len() {
block.resize(block_slice.len(), 0);
}
block.clone_from_slice(block_slice);
let mut decoder = Decoder::with_ip(arch_bits, block, pc, DecoderOptions::NONE);
emu.rep = None;
let addition = block.len().min(16);
emu.x86_instruction_cache()
.insert_x86_from_decoder(&mut decoder, addition, pc);
Ok(())
}
pub(crate) fn decode_and_execute_x86(emu: &mut Emu) -> (usize, bool) {
assert_x86_arch(emu, "decode_and_execute_x86");
let pc = emu.pc();
let code = match emu.maps.get_mem_by_addr(pc) {
Some(c) => c,
None => {
log::trace!("code flow to unmapped address 0x{:x}", pc);
Console::spawn_console(emu);
return (0, false);
}
};
emu.memory_operations.clear();
let block = code.read_from(pc).to_vec();
let mut decoder = if emu.cfg.is_x64() {
Decoder::with_ip(64, &block, pc, DecoderOptions::NONE)
} else {
Decoder::with_ip(32, &block, pc, DecoderOptions::NONE)
};
let ins = decoder.decode();
let sz = ins.len();
emu.set_x86_instruction(Some(ins));
let decoded = emu.last_decoded_x86(pc, ins);
if let Some(mut hook_fn) = emu.hooks.hook_on_pre_instruction.take() {
let skip = !hook_fn(emu, pc, &decoded, sz);
emu.hooks.hook_on_pre_instruction = Some(hook_fn);
if skip {
return (sz, true); }
}
let result_ok = engine::emulate_instruction(emu, &ins, sz, true);
emu.last_instruction_size = sz;
if let Some(mut hook_fn) = emu.hooks.hook_on_post_instruction.take() {
hook_fn(emu, pc, &decoded, sz, result_ok);
emu.hooks.hook_on_post_instruction = Some(hook_fn);
}
(sz, result_ok)
}
#[inline]
pub(crate) fn advance_pc_x86(emu: &mut Emu, sz: usize) {
assert_x86_arch(emu, "advance_pc_x86");
if emu.force_reload {
emu.force_reload = false;
} else if emu.cfg.is_x64() {
emu.regs_mut().rip += sz as u64;
} else {
let eip = emu.regs().get_eip() + sz as u64;
emu.regs_mut().set_eip(eip);
}
}