use crate::{
arch_info::{self, amd64, arm64},
Error, Result,
};
use indexmap::map::IndexMap;
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{convert::TryInto, fmt};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ArchitectureIdentifier {
Amd64,
Arm64,
Virtual,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
pub struct Header {
pub arch_id: ArchitectureIdentifier,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Vip(pub u64);
impl Vip {
pub fn invalid() -> Vip {
Vip(!0)
}
}
bitflags! {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RegisterFlags: u64 {
const VIRTUAL = 0;
const PHYSICAL = 1 << 0;
const LOCAL = 1 << 1;
const FLAGS = 1 << 2;
const STACK_POINTER = 1 << 3;
const IMAGE_BASE = 1 << 4;
const VOLATILE = 1 << 5;
const READONLY = 1 << 6;
const UNDEFINED = 1 << 7;
const INTERNAL = 1 << 8;
const SPECIAL = Self::FLAGS.bits | Self::STACK_POINTER.bits | Self::IMAGE_BASE.bits | Self::UNDEFINED.bits;
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy)]
pub struct RegisterDesc {
pub flags: RegisterFlags,
pub combined_id: u64,
pub bit_count: i32,
pub bit_offset: i32,
}
pub(crate) const LOCAL_ID_MASK: u64 = 0x00ffffffffffffff;
macro_rules! dr {
($arch_id:expr, $name:ident, $id:expr, $offset:expr, $count:expr, $doc:expr) => {
#[doc = $doc]
#[doc = " register"]
pub const $name: RegisterDesc = RegisterDesc {
flags: RegisterFlags::PHYSICAL,
combined_id: (($arch_id as u64) << 56) | $id,
bit_count: $count * 8,
bit_offset: $offset * 8,
};
};
($name:ident, $id:expr, $offset:expr, $count:expr) => {
dr!($name, $id, $offset, $count, stringify!($name));
};
}
macro_rules! dr_amd64 {
($name:ident, $id:expr, $offset:expr, $count:expr) => {
dr!(
ArchitectureIdentifier::Amd64,
$name,
$id,
$offset,
$count,
stringify!($name)
);
};
}
macro_rules! dr_arm64 {
($name:ident, $id:expr, $offset:expr, $count:expr) => {
dr!(
ArchitectureIdentifier::Arm64,
$name,
$id,
$offset,
$count,
stringify!($name)
);
};
}
impl RegisterDesc {
pub const UNDEFINED: RegisterDesc = RegisterDesc {
flags: RegisterFlags::from_bits_truncate(
RegisterFlags::VOLATILE.bits() | RegisterFlags::UNDEFINED.bits(),
),
combined_id: 0,
bit_count: 64,
bit_offset: 0,
};
pub const IMGBASE: RegisterDesc = RegisterDesc {
flags: RegisterFlags::from_bits_truncate(
RegisterFlags::READONLY.bits() | RegisterFlags::IMAGE_BASE.bits(),
),
combined_id: 0,
bit_count: 64,
bit_offset: 0,
};
pub const FLAGS: RegisterDesc = RegisterDesc {
flags: RegisterFlags::from_bits_truncate(
RegisterFlags::PHYSICAL.bits() | RegisterFlags::FLAGS.bits(),
),
combined_id: 0,
bit_count: 64,
bit_offset: 0,
};
pub const SP: RegisterDesc = RegisterDesc {
flags: RegisterFlags::from_bits_truncate(
RegisterFlags::PHYSICAL.bits() | RegisterFlags::STACK_POINTER.bits(),
),
combined_id: 0,
bit_count: 64,
bit_offset: 0,
};
dr_amd64!(X86_REG_RAX, amd64::X86_REG_RAX, 0, 8);
dr_amd64!(X86_REG_EAX, amd64::X86_REG_RAX, 0, 4);
dr_amd64!(X86_REG_AX, amd64::X86_REG_RAX, 0, 2);
dr_amd64!(X86_REG_AH, amd64::X86_REG_RAX, 1, 1);
dr_amd64!(X86_REG_AL, amd64::X86_REG_RAX, 0, 1);
dr_amd64!(X86_REG_RBX, amd64::X86_REG_RBX, 0, 8);
dr_amd64!(X86_REG_EBX, amd64::X86_REG_RBX, 0, 4);
dr_amd64!(X86_REG_BX, amd64::X86_REG_RBX, 0, 2);
dr_amd64!(X86_REG_BH, amd64::X86_REG_RBX, 1, 1);
dr_amd64!(X86_REG_BL, amd64::X86_REG_RBX, 0, 1);
dr_amd64!(X86_REG_RCX, amd64::X86_REG_RCX, 0, 8);
dr_amd64!(X86_REG_ECX, amd64::X86_REG_RCX, 0, 4);
dr_amd64!(X86_REG_CX, amd64::X86_REG_RCX, 0, 2);
dr_amd64!(X86_REG_CH, amd64::X86_REG_RCX, 1, 1);
dr_amd64!(X86_REG_CL, amd64::X86_REG_RCX, 0, 1);
dr_amd64!(X86_REG_RDX, amd64::X86_REG_RDX, 0, 8);
dr_amd64!(X86_REG_EDX, amd64::X86_REG_RDX, 0, 4);
dr_amd64!(X86_REG_DX, amd64::X86_REG_RDX, 0, 2);
dr_amd64!(X86_REG_DH, amd64::X86_REG_RDX, 1, 1);
dr_amd64!(X86_REG_DL, amd64::X86_REG_RDX, 0, 1);
dr_amd64!(X86_REG_RDI, amd64::X86_REG_RDI, 0, 8);
dr_amd64!(X86_REG_EDI, amd64::X86_REG_RDI, 0, 4);
dr_amd64!(X86_REG_DI, amd64::X86_REG_RDI, 0, 2);
dr_amd64!(X86_REG_DIL, amd64::X86_REG_RDI, 0, 1);
dr_amd64!(X86_REG_RSI, amd64::X86_REG_RSI, 0, 8);
dr_amd64!(X86_REG_ESI, amd64::X86_REG_RSI, 0, 4);
dr_amd64!(X86_REG_SI, amd64::X86_REG_RSI, 0, 2);
dr_amd64!(X86_REG_SIL, amd64::X86_REG_RSI, 0, 1);
dr_amd64!(X86_REG_RBP, amd64::X86_REG_RBP, 0, 8);
dr_amd64!(X86_REG_EBP, amd64::X86_REG_RBP, 0, 4);
dr_amd64!(X86_REG_BP, amd64::X86_REG_RBP, 0, 2);
dr_amd64!(X86_REG_BPL, amd64::X86_REG_RBP, 0, 1);
dr_amd64!(X86_REG_RSP, amd64::X86_REG_RSP, 0, 8);
dr_amd64!(X86_REG_ESP, amd64::X86_REG_RSP, 0, 4);
dr_amd64!(X86_REG_SP, amd64::X86_REG_RSP, 0, 2);
dr_amd64!(X86_REG_SPL, amd64::X86_REG_RSP, 0, 1);
dr_amd64!(X86_REG_R8, amd64::X86_REG_R8, 0, 8);
dr_amd64!(X86_REG_R8D, amd64::X86_REG_R8, 0, 4);
dr_amd64!(X86_REG_R8W, amd64::X86_REG_R8, 0, 2);
dr_amd64!(X86_REG_R8B, amd64::X86_REG_R8, 0, 1);
dr_amd64!(X86_REG_R9, amd64::X86_REG_R9, 0, 8);
dr_amd64!(X86_REG_R9D, amd64::X86_REG_R9, 0, 4);
dr_amd64!(X86_REG_R9W, amd64::X86_REG_R9, 0, 2);
dr_amd64!(X86_REG_R9B, amd64::X86_REG_R9, 0, 1);
dr_amd64!(X86_REG_R10, amd64::X86_REG_R10, 0, 8);
dr_amd64!(X86_REG_R10D, amd64::X86_REG_R10, 0, 4);
dr_amd64!(X86_REG_R10W, amd64::X86_REG_R10, 0, 2);
dr_amd64!(X86_REG_R10B, amd64::X86_REG_R10, 0, 1);
dr_amd64!(X86_REG_R11, amd64::X86_REG_R11, 0, 8);
dr_amd64!(X86_REG_R11D, amd64::X86_REG_R11, 0, 4);
dr_amd64!(X86_REG_R11W, amd64::X86_REG_R11, 0, 2);
dr_amd64!(X86_REG_R11B, amd64::X86_REG_R11, 0, 1);
dr_amd64!(X86_REG_R12, amd64::X86_REG_R12, 0, 8);
dr_amd64!(X86_REG_R12D, amd64::X86_REG_R12, 0, 4);
dr_amd64!(X86_REG_R12W, amd64::X86_REG_R12, 0, 2);
dr_amd64!(X86_REG_R12B, amd64::X86_REG_R12, 0, 1);
dr_amd64!(X86_REG_R13, amd64::X86_REG_R13, 0, 8);
dr_amd64!(X86_REG_R13D, amd64::X86_REG_R13, 0, 4);
dr_amd64!(X86_REG_R13W, amd64::X86_REG_R13, 0, 2);
dr_amd64!(X86_REG_R13B, amd64::X86_REG_R13, 0, 1);
dr_amd64!(X86_REG_R14, amd64::X86_REG_R14, 0, 8);
dr_amd64!(X86_REG_R14D, amd64::X86_REG_R14, 0, 4);
dr_amd64!(X86_REG_R14W, amd64::X86_REG_R14, 0, 2);
dr_amd64!(X86_REG_R14B, amd64::X86_REG_R14, 0, 1);
dr_amd64!(X86_REG_R15, amd64::X86_REG_R15, 0, 8);
dr_amd64!(X86_REG_R15D, amd64::X86_REG_R15, 0, 4);
dr_amd64!(X86_REG_R15W, amd64::X86_REG_R15, 0, 2);
dr_amd64!(X86_REG_R15B, amd64::X86_REG_R15, 0, 1);
dr_amd64!(X86_REG_EFLAGS, amd64::X86_REG_EFLAGS, 0, 8);
dr_arm64!(ARM64_REG_X0, arm64::ARM64_REG_X0, 0, 8);
dr_arm64!(ARM64_REG_W0, arm64::ARM64_REG_X0, 0, 4);
dr_arm64!(ARM64_REG_X1, arm64::ARM64_REG_X1, 0, 8);
dr_arm64!(ARM64_REG_W1, arm64::ARM64_REG_X1, 0, 4);
dr_arm64!(ARM64_REG_X2, arm64::ARM64_REG_X2, 0, 8);
dr_arm64!(ARM64_REG_W2, arm64::ARM64_REG_X2, 0, 4);
dr_arm64!(ARM64_REG_X3, arm64::ARM64_REG_X3, 0, 8);
dr_arm64!(ARM64_REG_W3, arm64::ARM64_REG_X3, 0, 4);
dr_arm64!(ARM64_REG_X4, arm64::ARM64_REG_X4, 0, 8);
dr_arm64!(ARM64_REG_W4, arm64::ARM64_REG_X4, 0, 4);
dr_arm64!(ARM64_REG_X5, arm64::ARM64_REG_X5, 0, 8);
dr_arm64!(ARM64_REG_W5, arm64::ARM64_REG_X5, 0, 4);
dr_arm64!(ARM64_REG_X6, arm64::ARM64_REG_X6, 0, 8);
dr_arm64!(ARM64_REG_W6, arm64::ARM64_REG_X6, 0, 4);
dr_arm64!(ARM64_REG_X7, arm64::ARM64_REG_X7, 0, 8);
dr_arm64!(ARM64_REG_W7, arm64::ARM64_REG_X7, 0, 4);
dr_arm64!(ARM64_REG_X8, arm64::ARM64_REG_X8, 0, 8);
dr_arm64!(ARM64_REG_W8, arm64::ARM64_REG_X8, 0, 4);
dr_arm64!(ARM64_REG_X9, arm64::ARM64_REG_X9, 0, 8);
dr_arm64!(ARM64_REG_W9, arm64::ARM64_REG_X9, 0, 4);
dr_arm64!(ARM64_REG_X10, arm64::ARM64_REG_X10, 0, 8);
dr_arm64!(ARM64_REG_W10, arm64::ARM64_REG_X10, 0, 4);
dr_arm64!(ARM64_REG_X11, arm64::ARM64_REG_X11, 0, 8);
dr_arm64!(ARM64_REG_W11, arm64::ARM64_REG_X11, 0, 4);
dr_arm64!(ARM64_REG_X12, arm64::ARM64_REG_X12, 0, 8);
dr_arm64!(ARM64_REG_W12, arm64::ARM64_REG_X12, 0, 4);
dr_arm64!(ARM64_REG_X13, arm64::ARM64_REG_X13, 0, 8);
dr_arm64!(ARM64_REG_W13, arm64::ARM64_REG_X13, 0, 4);
dr_arm64!(ARM64_REG_X14, arm64::ARM64_REG_X14, 0, 8);
dr_arm64!(ARM64_REG_W14, arm64::ARM64_REG_X14, 0, 4);
dr_arm64!(ARM64_REG_X15, arm64::ARM64_REG_X15, 0, 8);
dr_arm64!(ARM64_REG_W15, arm64::ARM64_REG_X15, 0, 4);
dr_arm64!(ARM64_REG_X16, arm64::ARM64_REG_X16, 0, 8);
dr_arm64!(ARM64_REG_W16, arm64::ARM64_REG_X16, 0, 4);
dr_arm64!(ARM64_REG_X17, arm64::ARM64_REG_X17, 0, 8);
dr_arm64!(ARM64_REG_W17, arm64::ARM64_REG_X17, 0, 4);
dr_arm64!(ARM64_REG_X18, arm64::ARM64_REG_X18, 0, 8);
dr_arm64!(ARM64_REG_W18, arm64::ARM64_REG_X18, 0, 4);
dr_arm64!(ARM64_REG_X19, arm64::ARM64_REG_X19, 0, 8);
dr_arm64!(ARM64_REG_W19, arm64::ARM64_REG_X19, 0, 4);
dr_arm64!(ARM64_REG_X20, arm64::ARM64_REG_X20, 0, 8);
dr_arm64!(ARM64_REG_W20, arm64::ARM64_REG_X20, 0, 4);
dr_arm64!(ARM64_REG_X21, arm64::ARM64_REG_X21, 0, 8);
dr_arm64!(ARM64_REG_W21, arm64::ARM64_REG_X21, 0, 4);
dr_arm64!(ARM64_REG_X22, arm64::ARM64_REG_X22, 0, 8);
dr_arm64!(ARM64_REG_W22, arm64::ARM64_REG_X22, 0, 4);
dr_arm64!(ARM64_REG_X23, arm64::ARM64_REG_X23, 0, 8);
dr_arm64!(ARM64_REG_W23, arm64::ARM64_REG_X23, 0, 4);
dr_arm64!(ARM64_REG_X24, arm64::ARM64_REG_X24, 0, 8);
dr_arm64!(ARM64_REG_W24, arm64::ARM64_REG_X24, 0, 4);
dr_arm64!(ARM64_REG_X25, arm64::ARM64_REG_X25, 0, 8);
dr_arm64!(ARM64_REG_W25, arm64::ARM64_REG_X25, 0, 4);
dr_arm64!(ARM64_REG_X26, arm64::ARM64_REG_X26, 0, 8);
dr_arm64!(ARM64_REG_W26, arm64::ARM64_REG_X26, 0, 4);
dr_arm64!(ARM64_REG_X27, arm64::ARM64_REG_X27, 0, 8);
dr_arm64!(ARM64_REG_W27, arm64::ARM64_REG_X27, 0, 4);
dr_arm64!(ARM64_REG_X28, arm64::ARM64_REG_X28, 0, 8);
dr_arm64!(ARM64_REG_W28, arm64::ARM64_REG_X28, 0, 4);
dr_arm64!(ARM64_REG_X29, arm64::ARM64_REG_X29, 0, 8);
dr_arm64!(ARM64_REG_FP, arm64::ARM64_REG_X29, 0, 8);
dr_arm64!(ARM64_REG_W29, arm64::ARM64_REG_X29, 0, 4);
dr_arm64!(ARM64_REG_X30, arm64::ARM64_REG_X30, 0, 8);
dr_arm64!(ARM64_REG_LR, arm64::ARM64_REG_X30, 0, 8);
dr_arm64!(ARM64_REG_W30, arm64::ARM64_REG_X30, 0, 4);
dr_arm64!(ARM64_REG_XZR, arm64::ARM64_REG_XZR, 0, 8);
dr_arm64!(ARM64_REG_WZR, arm64::ARM64_REG_XZR, 0, 4);
dr_arm64!(ARM64_REG_SP, arm64::ARM64_REG_SP, 0, 8);
dr_arm64!(ARM64_REG_WSP, arm64::ARM64_REG_SP, 0, 4);
dr_arm64!(ARM64_REG_NZCV, arm64::ARM64_REG_NZCV, 0, 8);
pub fn local_id(&self) -> u64 {
self.combined_id & LOCAL_ID_MASK
}
pub fn arch_id(&self) -> ArchitectureIdentifier {
match (self.combined_id & !LOCAL_ID_MASK) >> 56 {
0 => ArchitectureIdentifier::Amd64,
1 => ArchitectureIdentifier::Arm64,
_ => ArchitectureIdentifier::Virtual,
}
}
pub fn size(&self) -> usize {
(self.bit_count as usize + 7) / 8
}
}
impl fmt::Display for RegisterDesc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut prefix = String::new();
if self.flags.contains(RegisterFlags::VOLATILE) {
prefix = "?".to_string();
}
if self.flags.contains(RegisterFlags::READONLY) {
prefix += "&&";
}
let mut suffix = String::new();
if self.bit_offset != 0 {
suffix = format!("@{}", self.bit_offset);
}
if self.bit_count != 64 {
suffix.push_str(&format!(":{}", self.bit_count));
}
if self.flags.contains(RegisterFlags::INTERNAL) {
write!(f, "{}sr{}{}", prefix, self.local_id(), suffix)?;
return Ok(());
} else if self.flags.contains(RegisterFlags::UNDEFINED) {
write!(f, "{}UD{}", prefix, suffix)?;
return Ok(());
} else if self.flags.contains(RegisterFlags::FLAGS) {
write!(f, "{}$flags{}", prefix, suffix)?;
return Ok(());
} else if self.flags.contains(RegisterFlags::STACK_POINTER) {
write!(f, "{}$sp{}", prefix, suffix)?;
return Ok(());
} else if self.flags.contains(RegisterFlags::IMAGE_BASE) {
write!(f, "{}base{}", prefix, suffix)?;
return Ok(());
} else if self.flags.contains(RegisterFlags::LOCAL) {
write!(f, "{}t{}{}", prefix, self.local_id(), suffix)?;
return Ok(());
}
if self.flags.contains(RegisterFlags::PHYSICAL) {
match self.arch_id() {
ArchitectureIdentifier::Amd64 => {
write!(
f,
"{}{}{}",
prefix,
arch_info::amd64::REGISTER_NAME_MAPPING[self.local_id() as usize],
suffix
)?;
return Ok(());
}
ArchitectureIdentifier::Arm64 => {
write!(
f,
"{}{}{}",
prefix,
arch_info::arm64::REGISTER_NAME_MAPPING[self.local_id() as usize],
suffix
)?;
return Ok(());
}
_ => {}
}
}
write!(f, "{}vr{}{}", prefix, self.local_id(), suffix)?;
Ok(())
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct RoutineConvention {
pub volatile_registers: Vec<RegisterDesc>,
pub param_registers: Vec<RegisterDesc>,
pub retval_registers: Vec<RegisterDesc>,
pub frame_register: RegisterDesc,
pub shadow_space: u64,
pub purge_stack: bool,
}
#[derive(Clone, Copy)]
pub(crate) union Immediate {
pub(crate) u64: u64,
pub(crate) i64: i64,
}
impl Immediate {
pub(crate) fn u64(&self) -> u64 {
unsafe { self.u64 }
}
pub(crate) fn set_u64(&mut self, imm: u64) {
self.u64 = imm;
}
pub(crate) fn i64(&self) -> i64 {
unsafe { self.i64 }
}
pub(crate) fn set_i64(&mut self, imm: i64) {
self.i64 = imm;
}
}
#[cfg(feature = "serde")]
impl Serialize for Immediate {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_i64(self.i64())
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Immediate {
fn deserialize<D>(deserializer: D) -> std::result::Result<Immediate, D::Error>
where
D: Deserializer<'de>,
{
Ok(Immediate {
i64: i64::deserialize(deserializer)?,
})
}
}
impl fmt::Debug for Immediate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Immediate")
.field("u64", &self.u64())
.field("i64", &self.i64())
.finish()
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy)]
pub struct ImmediateDesc {
pub(crate) value: Immediate,
pub bit_count: u32,
}
impl From<i64> for ImmediateDesc {
fn from(imm: i64) -> ImmediateDesc {
ImmediateDesc::new_signed(imm, 64)
}
}
impl From<u64> for ImmediateDesc {
fn from(imm: u64) -> ImmediateDesc {
ImmediateDesc::new(imm, 64)
}
}
impl From<i32> for ImmediateDesc {
fn from(imm: i32) -> ImmediateDesc {
ImmediateDesc::new_signed(imm, 32)
}
}
impl From<u32> for ImmediateDesc {
fn from(imm: u32) -> ImmediateDesc {
ImmediateDesc::new(imm, 32)
}
}
impl From<i16> for ImmediateDesc {
fn from(imm: i16) -> ImmediateDesc {
ImmediateDesc::new_signed(imm, 16)
}
}
impl From<u16> for ImmediateDesc {
fn from(imm: u16) -> ImmediateDesc {
ImmediateDesc::new(imm, 16)
}
}
impl From<i8> for ImmediateDesc {
fn from(imm: i8) -> ImmediateDesc {
ImmediateDesc::new_signed(imm, 8)
}
}
impl From<u8> for ImmediateDesc {
fn from(imm: u8) -> ImmediateDesc {
ImmediateDesc::new(imm, 8)
}
}
impl ImmediateDesc {
pub fn new<T: Into<u64>>(value: T, bit_count: u32) -> ImmediateDesc {
ImmediateDesc {
value: Immediate { u64: value.into() },
bit_count,
}
}
pub fn new_signed<T: Into<i64>>(value: T, bit_count: u32) -> ImmediateDesc {
ImmediateDesc {
value: Immediate { i64: value.into() },
bit_count,
}
}
pub fn u64(&self) -> u64 {
self.value.u64()
}
pub fn set_u64(&mut self, imm: u64) {
self.value.set_u64(imm);
}
pub fn i64(&self) -> i64 {
self.value.i64()
}
pub fn set_i64(&mut self, imm: i64) {
self.value.set_i64(imm);
}
pub fn size(&self) -> usize {
(self.bit_count as usize + 7) / 8
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy)]
pub enum Operand {
ImmediateDesc(ImmediateDesc),
RegisterDesc(RegisterDesc),
}
impl From<i64> for Operand {
fn from(imm: i64) -> Operand {
Operand::ImmediateDesc(imm.into())
}
}
impl From<u64> for Operand {
fn from(imm: u64) -> Operand {
Operand::ImmediateDesc(imm.into())
}
}
impl From<i32> for Operand {
fn from(imm: i32) -> Operand {
Operand::ImmediateDesc(imm.into())
}
}
impl From<u32> for Operand {
fn from(imm: u32) -> Operand {
Operand::ImmediateDesc(imm.into())
}
}
impl From<i16> for Operand {
fn from(imm: i16) -> Operand {
Operand::ImmediateDesc(imm.into())
}
}
impl From<u16> for Operand {
fn from(imm: u16) -> Operand {
Operand::ImmediateDesc(imm.into())
}
}
impl From<i8> for Operand {
fn from(imm: i8) -> Operand {
Operand::ImmediateDesc(imm.into())
}
}
impl From<u8> for Operand {
fn from(imm: u8) -> Operand {
Operand::ImmediateDesc(imm.into())
}
}
impl Operand {
pub fn size(&self) -> usize {
match self {
Operand::ImmediateDesc(i) => i.size(),
Operand::RegisterDesc(r) => r.size(),
}
}
}
impl From<RegisterDesc> for Operand {
fn from(register_desc: RegisterDesc) -> Self {
Operand::RegisterDesc(register_desc)
}
}
impl From<ImmediateDesc> for Operand {
fn from(immediate_desc: ImmediateDesc) -> Self {
Operand::ImmediateDesc(immediate_desc)
}
}
impl<'a, 'b> TryInto<&'b ImmediateDesc> for &'a Operand
where
'a: 'b,
{
type Error = Error;
fn try_into(self) -> Result<&'a ImmediateDesc> {
match self {
Operand::ImmediateDesc(ref i) => Ok(i),
_ => Err(Error::OperandTypeMismatch),
}
}
}
impl<'a, 'b> TryInto<&'b RegisterDesc> for &'a Operand
where
'a: 'b,
{
type Error = Error;
fn try_into(self) -> Result<&'a RegisterDesc> {
match self {
Operand::RegisterDesc(r) => Ok(r),
_ => Err(Error::OperandTypeMismatch),
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
pub struct Instruction {
pub op: Op,
pub vip: Vip,
pub sp_offset: i64,
pub sp_index: u32,
pub sp_reset: bool,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
pub enum Op {
Mov(Operand, Operand),
Movsx(Operand, Operand),
Str(Operand, Operand, Operand),
Ldd(Operand, Operand, Operand),
Neg(Operand),
Add(Operand, Operand),
Sub(Operand, Operand),
Mul(Operand, Operand),
Mulhi(Operand, Operand),
Imul(Operand, Operand),
Imulhi(Operand, Operand),
Div(Operand, Operand, Operand),
Rem(Operand, Operand, Operand),
Idiv(Operand, Operand, Operand),
Irem(Operand, Operand, Operand),
Popcnt(Operand),
Bsf(Operand),
Bsr(Operand),
Not(Operand),
Shr(Operand, Operand),
Shl(Operand, Operand),
Xor(Operand, Operand),
Or(Operand, Operand),
And(Operand, Operand),
Ror(Operand, Operand),
Rol(Operand, Operand),
Tg(Operand, Operand, Operand),
Tge(Operand, Operand, Operand),
Te(Operand, Operand, Operand),
Tne(Operand, Operand, Operand),
Tl(Operand, Operand, Operand),
Tle(Operand, Operand, Operand),
Tug(Operand, Operand, Operand),
Tuge(Operand, Operand, Operand),
Tul(Operand, Operand, Operand),
Tule(Operand, Operand, Operand),
Ifs(Operand, Operand, Operand),
Js(Operand, Operand, Operand),
Jmp(Operand),
Vexit(Operand),
Vxcall(Operand),
Nop,
Sfence,
Lfence,
Vemit(Operand),
Vpinr(Operand),
Vpinw(Operand),
Vpinrm(Operand, Operand, Operand),
Vpinwm(Operand, Operand, Operand),
}
impl Op {
pub fn name(&self) -> &'static str {
match self {
Op::Mov(_, _) => "mov",
Op::Movsx(_, _) => "movsx",
Op::Str(_, _, _) => "str",
Op::Ldd(_, _, _) => "ldd",
Op::Neg(_) => "neg",
Op::Add(_, _) => "add",
Op::Sub(_, _) => "sub",
Op::Mul(_, _) => "mul",
Op::Mulhi(_, _) => "mulhi",
Op::Imul(_, _) => "imul",
Op::Imulhi(_, _) => "imulhi",
Op::Div(_, _, _) => "div",
Op::Rem(_, _, _) => "rem",
Op::Idiv(_, _, _) => "idiv",
Op::Irem(_, _, _) => "irem",
Op::Popcnt(_) => "popcnt",
Op::Bsf(_) => "bsf",
Op::Bsr(_) => "bsr",
Op::Not(_) => "not",
Op::Shr(_, _) => "shr",
Op::Shl(_, _) => "shl",
Op::Xor(_, _) => "xor",
Op::Or(_, _) => "or",
Op::And(_, _) => "and",
Op::Ror(_, _) => "ror",
Op::Rol(_, _) => "rol",
Op::Tg(_, _, _) => "tg",
Op::Tge(_, _, _) => "tge",
Op::Te(_, _, _) => "te",
Op::Tne(_, _, _) => "tne",
Op::Tl(_, _, _) => "tl",
Op::Tle(_, _, _) => "tle",
Op::Tug(_, _, _) => "tug",
Op::Tuge(_, _, _) => "tuge",
Op::Tul(_, _, _) => "tul",
Op::Tule(_, _, _) => "tule",
Op::Ifs(_, _, _) => "ifs",
Op::Js(_, _, _) => "js",
Op::Jmp(_) => "jmp",
Op::Vexit(_) => "vexit",
Op::Vxcall(_) => "vxcall",
Op::Nop => "nop",
Op::Sfence => "sfence",
Op::Lfence => "lfence",
Op::Vemit(_) => "vemit",
Op::Vpinr(_) => "vpinr",
Op::Vpinw(_) => "vpinw",
Op::Vpinrm(_, _, _) => "vpinrm",
Op::Vpinwm(_, _, _) => "vpinwm",
}
}
pub fn operands(&self) -> Vec<&Operand> {
match *self {
Op::Nop | Op::Sfence | Op::Lfence => vec![],
Op::Neg(ref op1)
| Op::Popcnt(ref op1)
| Op::Bsf(ref op1)
| Op::Bsr(ref op1)
| Op::Not(ref op1)
| Op::Jmp(ref op1)
| Op::Vexit(ref op1)
| Op::Vxcall(ref op1)
| Op::Vemit(ref op1)
| Op::Vpinr(ref op1)
| Op::Vpinw(ref op1) => vec![op1],
Op::Mov(ref op1, ref op2)
| Op::Movsx(ref op1, ref op2)
| Op::Add(ref op1, ref op2)
| Op::Sub(ref op1, ref op2)
| Op::Mul(ref op1, ref op2)
| Op::Mulhi(ref op1, ref op2)
| Op::Imul(ref op1, ref op2)
| Op::Imulhi(ref op1, ref op2)
| Op::Shr(ref op1, ref op2)
| Op::Shl(ref op1, ref op2)
| Op::Xor(ref op1, ref op2)
| Op::Or(ref op1, ref op2)
| Op::And(ref op1, ref op2)
| Op::Ror(ref op1, ref op2)
| Op::Rol(ref op1, ref op2) => vec![op1, op2],
Op::Str(ref op1, ref op2, ref op3)
| Op::Ldd(ref op1, ref op2, ref op3)
| Op::Div(ref op1, ref op2, ref op3)
| Op::Rem(ref op1, ref op2, ref op3)
| Op::Idiv(ref op1, ref op2, ref op3)
| Op::Irem(ref op1, ref op2, ref op3)
| Op::Tg(ref op1, ref op2, ref op3)
| Op::Tge(ref op1, ref op2, ref op3)
| Op::Te(ref op1, ref op2, ref op3)
| Op::Tne(ref op1, ref op2, ref op3)
| Op::Tl(ref op1, ref op2, ref op3)
| Op::Tle(ref op1, ref op2, ref op3)
| Op::Tug(ref op1, ref op2, ref op3)
| Op::Tuge(ref op1, ref op2, ref op3)
| Op::Tul(ref op1, ref op2, ref op3)
| Op::Tule(ref op1, ref op2, ref op3)
| Op::Ifs(ref op1, ref op2, ref op3)
| Op::Js(ref op1, ref op2, ref op3)
| Op::Vpinrm(ref op1, ref op2, ref op3)
| Op::Vpinwm(ref op1, ref op2, ref op3) => vec![op1, op2, op3],
}
}
pub fn operands_mut(&mut self) -> Vec<&mut Operand> {
match *self {
Op::Nop | Op::Sfence | Op::Lfence => vec![],
Op::Neg(ref mut op1)
| Op::Popcnt(ref mut op1)
| Op::Bsf(ref mut op1)
| Op::Bsr(ref mut op1)
| Op::Not(ref mut op1)
| Op::Jmp(ref mut op1)
| Op::Vexit(ref mut op1)
| Op::Vxcall(ref mut op1)
| Op::Vemit(ref mut op1)
| Op::Vpinr(ref mut op1)
| Op::Vpinw(ref mut op1) => vec![op1],
Op::Mov(ref mut op1, ref mut op2)
| Op::Movsx(ref mut op1, ref mut op2)
| Op::Add(ref mut op1, ref mut op2)
| Op::Sub(ref mut op1, ref mut op2)
| Op::Mul(ref mut op1, ref mut op2)
| Op::Mulhi(ref mut op1, ref mut op2)
| Op::Imul(ref mut op1, ref mut op2)
| Op::Imulhi(ref mut op1, ref mut op2)
| Op::Shr(ref mut op1, ref mut op2)
| Op::Shl(ref mut op1, ref mut op2)
| Op::Xor(ref mut op1, ref mut op2)
| Op::Or(ref mut op1, ref mut op2)
| Op::And(ref mut op1, ref mut op2)
| Op::Ror(ref mut op1, ref mut op2)
| Op::Rol(ref mut op1, ref mut op2) => vec![op1, op2],
Op::Str(ref mut op1, ref mut op2, ref mut op3)
| Op::Ldd(ref mut op1, ref mut op2, ref mut op3)
| Op::Div(ref mut op1, ref mut op2, ref mut op3)
| Op::Rem(ref mut op1, ref mut op2, ref mut op3)
| Op::Idiv(ref mut op1, ref mut op2, ref mut op3)
| Op::Irem(ref mut op1, ref mut op2, ref mut op3)
| Op::Tg(ref mut op1, ref mut op2, ref mut op3)
| Op::Tge(ref mut op1, ref mut op2, ref mut op3)
| Op::Te(ref mut op1, ref mut op2, ref mut op3)
| Op::Tne(ref mut op1, ref mut op2, ref mut op3)
| Op::Tl(ref mut op1, ref mut op2, ref mut op3)
| Op::Tle(ref mut op1, ref mut op2, ref mut op3)
| Op::Tug(ref mut op1, ref mut op2, ref mut op3)
| Op::Tuge(ref mut op1, ref mut op2, ref mut op3)
| Op::Tul(ref mut op1, ref mut op2, ref mut op3)
| Op::Tule(ref mut op1, ref mut op2, ref mut op3)
| Op::Ifs(ref mut op1, ref mut op2, ref mut op3)
| Op::Js(ref mut op1, ref mut op2, ref mut op3)
| Op::Vpinrm(ref mut op1, ref mut op2, ref mut op3)
| Op::Vpinwm(ref mut op1, ref mut op2, ref mut op3) => vec![op1, op2, op3],
}
}
pub fn is_volatile(&self) -> bool {
matches!(
self,
Op::Sfence
| Op::Lfence
| Op::Vemit(_)
| Op::Vpinr(_)
| Op::Vpinw(_)
| Op::Vpinrm(_, _, _)
| Op::Vpinwm(_, _, _)
)
}
pub fn is_branching(&self) -> bool {
matches!(
self,
Op::Js(_, _, _) | Op::Jmp(_) | Op::Vexit(_) | Op::Vxcall(_)
)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
pub struct BasicBlock {
pub vip: Vip,
pub sp_offset: i64,
pub sp_index: u32,
pub last_temporary_index: u32,
pub instructions: Vec<Instruction>,
pub prev_vip: Vec<Vip>,
pub next_vip: Vec<Vip>,
}
impl BasicBlock {
pub fn tmp(&mut self, bit_count: i32) -> RegisterDesc {
let reg = RegisterDesc {
flags: RegisterFlags::LOCAL,
combined_id: self.last_temporary_index as u64,
bit_count,
bit_offset: 0,
};
self.last_temporary_index += 1;
reg
}
pub fn is_complete(&self) -> bool {
let instructions = &self.instructions;
!instructions.is_empty() && instructions[instructions.len() - 1].op.is_branching()
}
pub fn fork(&mut self, entry: Vip) -> BasicBlock {
assert!(self.is_complete());
assert!(entry != Vip::invalid());
let basic_block = BasicBlock {
vip: entry,
sp_offset: 0,
sp_index: 0,
last_temporary_index: 0,
instructions: vec![],
prev_vip: vec![self.vip],
next_vip: vec![],
};
self.next_vip.push(entry);
basic_block
}
}
pub type SubroutineConvention = RoutineConvention;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
pub struct Routine {
pub header: Header,
pub vip: Vip,
pub routine_convention: RoutineConvention,
pub subroutine_convention: SubroutineConvention,
pub spec_subroutine_conventions: Vec<SubroutineConvention>,
pub explored_blocks: IndexMap<Vip, BasicBlock>,
}