hypervisor: emulator: switch to use vec in MockVMM

The customized hashmap macro can't be lifted to common MockVMM code.
MockVMM only needs a collection to iterate over to get initial register
states. A vector is just as good as a hashmap.

Switch to use a vector to store initial register states. This allows us
to drop the hashmap macro everywhere.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2020-12-05 23:31:59 +00:00 committed by Samuel Ortiz
parent 93b7dcac12
commit a44d96c9cc
3 changed files with 24 additions and 57 deletions

View File

@ -241,14 +241,6 @@ mod tests {
use super::*;
use crate::arch::x86::emulator::mock_vmm::*;
macro_rules! hashmap {
($( $key: expr => $val: expr ),*) => {{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key, $val); )*
map
}}
}
#[test]
// cmp ah,al
fn test_cmp_rm8_r8_1() -> MockResult {
@ -256,7 +248,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x38, 0xc4]; // cmp ah,al
let mut vmm = MockVMM::new(ip, hashmap![Register::RAX => rax], None);
let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax)], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let rflags: u64 = vmm.cpu_state(cpu_id).unwrap().flags() & FLAGS_MASK;
@ -272,7 +264,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x83, 0xf8, 0x64]; // cmp eax,100
let mut vmm = MockVMM::new(ip, hashmap![Register::RAX => rax], None);
let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax)], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let rflags: u64 = vmm.cpu_state(cpu_id).unwrap().flags() & FLAGS_MASK;
@ -288,7 +280,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x83, 0xf8, 0xff]; // cmp eax,-1
let mut vmm = MockVMM::new(ip, hashmap![Register::RAX => rax], None);
let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax)], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let rflags: u64 = vmm.cpu_state(cpu_id).unwrap().flags() & FLAGS_MASK;
@ -305,11 +297,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x48, 0x39, 0xd8, 0x00, 0xc3]; // cmp rax,rbx + two bytes garbage
let mut vmm = MockVMM::new(
ip,
hashmap![Register::RAX => rax, Register::RBX => rbx],
None,
);
let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax), (Register::RBX, rbx)], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let rflags: u64 = vmm.cpu_state(cpu_id).unwrap().flags() & FLAGS_MASK;
@ -336,7 +324,7 @@ mod tests {
let insn = [0x48, 0x39, 0xd8]; // cmp rax,rbx
let mut vmm = MockVMM::new(
0x1000,
hashmap![Register::RAX => rax, Register::RBX => rbx],
vec![(Register::RAX, rax), (Register::RBX, rbx)],
None,
);
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
@ -366,7 +354,7 @@ mod tests {
let insn = [0x39, 0xd8]; // cmp eax,ebx
let mut vmm = MockVMM::new(
0x1000,
hashmap![Register::RAX => rax, Register::RBX => rbx],
vec![(Register::RAX, rax), (Register::RBX, rbx)],
None,
);
assert!(vmm.emulate_first_insn(0, &insn).is_ok());

View File

@ -216,14 +216,6 @@ mod tests {
use super::*;
use crate::arch::x86::emulator::mock_vmm::*;
macro_rules! hashmap {
($( $key: expr => $val: expr ),*) => {{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key, $val); )*
map
}}
}
#[test]
// mov rax,rbx
fn test_mov_r64_r64() -> MockResult {
@ -231,7 +223,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x48, 0x89, 0xd8];
let mut vmm = MockVMM::new(ip, hashmap![Register::RBX => rbx], None);
let mut vmm = MockVMM::new(ip, vec![(Register::RBX, rbx)], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let rax: u64 = vmm
@ -251,7 +243,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x48, 0xb8, 0x44, 0x33, 0x22, 0x11, 0x44, 0x33, 0x22, 0x11];
let mut vmm = MockVMM::new(ip, hashmap![], None);
let mut vmm = MockVMM::new(ip, vec![], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let rax: u64 = vmm
@ -273,11 +265,7 @@ mod tests {
let cpu_id = 0;
let memory: [u8; 8] = target_rax.to_le_bytes();
let insn = [0x48, 0x8b, 0x04, 0x00];
let mut vmm = MockVMM::new(
ip,
hashmap![Register::RAX => rax],
Some((rax + rax, &memory)),
);
let mut vmm = MockVMM::new(ip, vec![(Register::RAX, rax)], Some((rax + rax, &memory)));
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
rax = vmm
@ -297,7 +285,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0xb0, 0x11];
let mut vmm = MockVMM::new(ip, hashmap![], None);
let mut vmm = MockVMM::new(ip, vec![], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let al = vmm
@ -317,7 +305,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0xb8, 0x11, 0x00, 0x00, 0x00];
let mut vmm = MockVMM::new(ip, hashmap![], None);
let mut vmm = MockVMM::new(ip, vec![], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let eax = vmm
@ -337,7 +325,7 @@ mod tests {
let ip: u64 = 0x1000;
let cpu_id = 0;
let insn = [0x48, 0xc7, 0xc0, 0x44, 0x33, 0x22, 0x11];
let mut vmm = MockVMM::new(ip, hashmap![], None);
let mut vmm = MockVMM::new(ip, vec![], None);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
let rax: u64 = vmm
@ -360,7 +348,7 @@ mod tests {
let insn = [0x88, 0x30];
let mut vmm = MockVMM::new(
ip,
hashmap![Register::RAX => rax, Register::DH => dh.into()],
vec![(Register::RAX, rax), (Register::DH, dh.into())],
None,
);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
@ -383,7 +371,7 @@ mod tests {
let insn = [0x89, 0x30];
let mut vmm = MockVMM::new(
ip,
hashmap![Register::RAX => rax, Register::ESI => esi.into()],
vec![(Register::RAX, rax), (Register::ESI, esi.into())],
None,
);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
@ -407,7 +395,7 @@ mod tests {
let insn = [0x89, 0x3c, 0x05, 0x01, 0x00, 0x00, 0x00];
let mut vmm = MockVMM::new(
ip,
hashmap![Register::RAX => rax, Register::EDI => edi.into()],
vec![(Register::RAX, rax), (Register::EDI, edi.into())],
None,
);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
@ -432,7 +420,7 @@ mod tests {
let insn = [0x8b, 0x40, 0x10];
let mut vmm = MockVMM::new(
ip,
hashmap![Register::RAX => rax],
vec![(Register::RAX, rax)],
Some((rax + displacement, &memory)),
);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
@ -459,7 +447,7 @@ mod tests {
let memory: [u8; 1] = al.to_le_bytes();
let mut vmm = MockVMM::new(
ip,
hashmap![Register::RAX => rax],
vec![(Register::RAX, rax)],
Some((rax + displacement, &memory)),
);
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
@ -488,7 +476,7 @@ mod tests {
0x48, 0xc7, 0xc0, 0x00, 0x01, 0x00, 0x00, // mov rax, 0x100
0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
];
let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory)));
let mut vmm = MockVMM::new(ip, vec![], Some((rax + displacement, &memory)));
assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok());
let rbx: u64 = vmm
@ -516,7 +504,7 @@ mod tests {
0x48, 0x8b, 0x58, 0x10, // mov rbx, qword ptr [rax+10h]
];
let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory)));
let mut vmm = MockVMM::new(ip, vec![], Some((rax + displacement, &memory)));
// Only run the first instruction.
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
@ -549,7 +537,7 @@ mod tests {
0x48, 0xc7, 0xc0, 0x00, 0x02, 0x00, 0x00, // mov rax, 0x200
];
let mut vmm = MockVMM::new(ip, hashmap![], Some((rax + displacement, &memory)));
let mut vmm = MockVMM::new(ip, vec![], Some((rax + displacement, &memory)));
// Run the 2 first instructions.
assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok());

View File

@ -639,7 +639,6 @@ mod mock_vmm {
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState as CpuState};
use crate::arch::x86::gdt::{gdt_entry, segment_from_gdt};
use crate::arch::x86::Exception;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone)]
@ -653,7 +652,7 @@ mod mock_vmm {
pub type MockResult = Result<(), EmulationError<Exception>>;
impl MockVMM {
pub fn new(ip: u64, regs: HashMap<Register, u64>, memory: Option<(u64, &[u8])>) -> MockVMM {
pub fn new(ip: u64, regs: Vec<(Register, u64)>, memory: Option<(u64, &[u8])>) -> MockVMM {
let _ = env_logger::try_init();
let cs_reg = segment_from_gdt(gdt_entry(0xc09b, 0, 0xffffffff), 1);
let ds_reg = segment_from_gdt(gdt_entry(0xc093, 0, 0xffffffff), 2);
@ -761,14 +760,6 @@ mod tests {
use super::*;
use crate::arch::x86::emulator::mock_vmm::*;
macro_rules! hashmap {
($( $key: expr => $val: expr ),*) => {{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key, $val); )*
map
}}
}
#[test]
// Emulate truncated instruction stream, which should cause a fetch.
//
@ -791,7 +782,7 @@ mod tests {
0x48, 0xc7, 0xc0, 0x00, // mov rax, 0x1000 -- Missing bytes: 0x00, 0x10, 0x00, 0x00,
];
let mut vmm = MockVMM::new(ip, hashmap![], Some((ip, &memory)));
let mut vmm = MockVMM::new(ip, vec![], Some((ip, &memory)));
assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok());
let rax: u64 = vmm
@ -828,7 +819,7 @@ mod tests {
0x48, 0x8b, // Truncated mov rbx, qword ptr [rax+10h] -- missing [0x58, 0x10]
];
let mut vmm = MockVMM::new(ip, hashmap![], Some((ip, &memory)));
let mut vmm = MockVMM::new(ip, vec![], Some((ip, &memory)));
assert!(vmm.emulate_insn(cpu_id, &insn, Some(2)).is_ok());
let rbx: u64 = vmm
@ -860,7 +851,7 @@ mod tests {
0x48, 0xc7, 0xc0, 0x00, // mov rax, 0x1000 -- Missing bytes: 0x00, 0x10, 0x00, 0x00,
];
let mut vmm = MockVMM::new(ip, hashmap![], Some((ip, &memory)));
let mut vmm = MockVMM::new(ip, vec![], Some((ip, &memory)));
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_err());
Ok(())