use alloc::{borrow::Cow, vec::Vec};
use capstone::{InsnGroupId, InsnGroupType};
#[cfg_attr(target_arch = "aarch64", path = "arm_util/encoding_aarch64.rs")]
#[cfg_attr(
all(target_arch = "arm", not(thumb_mode)),
path = "arm_util/encoding_arm.rs"
)]
#[cfg_attr(
all(target_arch = "arm", thumb_mode),
path = "arm_util/encoding_thumb.rs"
)]
pub mod encoding;
pub fn has_unsupported_insn_group(groups: &[InsnGroupId]) -> bool {
const UNSUPPORTED_GROUPS: &[InsnGroupType::Type] = &[
InsnGroupType::CS_GRP_INVALID,
InsnGroupType::CS_GRP_JUMP,
InsnGroupType::CS_GRP_CALL,
InsnGroupType::CS_GRP_RET,
InsnGroupType::CS_GRP_INT,
InsnGroupType::CS_GRP_IRET,
InsnGroupType::CS_GRP_PRIVILEGE,
InsnGroupType::CS_GRP_BRANCH_RELATIVE,
];
groups
.iter()
.any(|g| UNSUPPORTED_GROUPS.contains(&(g.0 as InsnGroupType::Type)))
}
#[derive(Debug, Clone, Copy)]
pub struct EncodingError;
impl From<()> for EncodingError {
fn from(_value: ()) -> Self {
EncodingError
}
}
impl From<EncodingError> for JitError {
fn from(_value: EncodingError) -> Self {
JitError::EncodingError
}
}
pub struct CowBuffer<'a> {
orig_bytes: &'a [u8],
new_bytes: Vec<u8>,
num_copied: usize,
}
impl<'a> CowBuffer<'a> {
pub fn new(orig_bytes: &'a [u8]) -> Self {
Self {
orig_bytes,
new_bytes: Vec::new(),
num_copied: 0,
}
}
pub fn into_bytes(mut self) -> Cow<'a, [u8]> {
if self.new_bytes.is_empty() {
self.orig_bytes.into()
}
else {
self.new_bytes.extend_from_slice(&self.orig_bytes[self.num_copied..]);
self.new_bytes.into()
}
}
#[allow(unused)]
pub fn new_bytes(&self) -> &[u8] {
&self.new_bytes
}
pub fn new_bytes_mut(&mut self) -> &mut Vec<u8> {
&mut self.new_bytes
}
pub fn copy_up_to(&mut self, offset: usize) {
debug_assert!(offset >= self.num_copied && offset <= self.orig_bytes.len());
if self.new_bytes.is_empty() {
self.new_bytes = Vec::with_capacity(self.orig_bytes.len())
}
let new_num_copied = offset.min(self.orig_bytes.len());
self.new_bytes
.extend_from_slice(&self.orig_bytes[self.num_copied..new_num_copied]);
self.num_copied = new_num_copied;
}
pub fn append(&mut self, offset: usize, bytes: &[u8]) -> usize {
if !bytes.is_empty() {
self.copy_up_to(offset);
}
let bytes_offset = self.new_bytes.len();
self.new_bytes.extend_from_slice(bytes);
bytes_offset
}
#[allow(unused)]
pub fn ignore(&mut self, offset: usize, count: usize) -> usize {
debug_assert!(offset + count <= self.orig_bytes.len());
self.copy_up_to(offset);
self.num_copied += count;
self.new_bytes.len()
}
#[allow(unused)]
pub fn replace(&mut self, offset: usize, bytes: &[u8]) -> usize {
debug_assert!(offset + bytes.len() <= self.orig_bytes.len());
let bytes_offset = self.append(offset, bytes);
self.num_copied += bytes.len();
bytes_offset
}
}
macro_rules! bitflags {
($($(#[$attrs:meta])* $v:vis struct $name:ident: $t:ty {
$(
$(#[signed($signed_ty:ty)])?
$fvis:vis
$getter:ident $($setter:ident $($try_setter:ident)?)? :
$start:literal .. $end:literal
),*$(,)?
})+) => { $(
$(#[$attrs])*
#[derive(Clone, Copy)]
#[repr(transparent)]
$v struct $name($t);
#[allow(unused)]
impl $name {
pub const fn from_raw(val: $t) -> Self {
Self(val)
}
pub const fn to_raw(self) -> $t {
self.0
}
$(
$crate::safe_jit::arm_util::bitflags_field! {
($t, $($signed_ty)?) $fvis $getter $($setter $($try_setter)?)?: $start .. $end
}
)*
}
impl ::core::fmt::Debug for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct(stringify!($name))
$(.field(stringify!($getter), &crate::safe_jit::arm_util::FmtDecBin(self.$getter())))*
.finish()
}
}
)+ };
}
macro_rules! bitflags_field {
( ($t:ty,)
$fvis:vis
$getter:ident $($setter:ident $($try_setter:ident)?)? :
$start:literal .. $end:literal
) => {
$fvis fn $getter(&self) -> $t {
const SIZE: u32 = $end - $start;
const SIZE_MASK: $t = ((1u128 << SIZE) - 1) as $t;
(self.0 >> $start) & SIZE_MASK
}
$(
$fvis fn $setter(&mut self, val: $t) {
const SIZE: u32 = $end - $start;
const SIZE_MASK: $t = ((1u128 << SIZE) - 1) as $t;
const MASK: $t = SIZE_MASK << ($start as u32);
self.0 = (self.0 & !MASK) | ((val & SIZE_MASK) << $start);
}
$($fvis fn $try_setter(&mut self, val: $t) -> Result<(), ()> {
const SIZE: u32 = $end - $start;
const SIZE_MASK: $t = ((1u128 << SIZE) - 1) as $t;
const MASK: $t = SIZE_MASK << ($start as u32);
if val > SIZE_MASK {
return Err(())
}
self.0 = (self.0 & !MASK) | ((val & SIZE_MASK) << $start);
Ok(())
})?
)?
};
( ($t:ty, $signed_ty:ty)
$fvis:vis
$getter:ident $($setter:ident $($try_setter:ident)?)? :
$start:literal .. $end:literal
) => {
$fvis fn $getter(&self) -> $signed_ty {
const BITS: u32 = 8 * ::core::mem::size_of::<$signed_ty>() as u32;
const LSHIFT: u32 = BITS - $end;
const RSHIFT: u32 = LSHIFT + $start;
(self.0 as $signed_ty) << LSHIFT >> RSHIFT
}
$(
$fvis fn $setter(&mut self, val: $signed_ty) {
const SIZE: u32 = $end - $start;
const SIZE_MASK: $t = ((1u128 << SIZE) - 1) as $t;
const MASK: $t = SIZE_MASK << ($start as u32);
self.0 = (self.0 & !MASK) | ((val as $t & SIZE_MASK) << $start);
}
$($fvis fn $try_setter(&mut self, val: $signed_ty) -> Result<(), ()> {
const SIZE: u32 = $end - $start;
const SIZE_MASK: $t = ((1u128 << SIZE) - 1) as $t;
const MASK: $t = SIZE_MASK << ($start as u32);
let extra_bits = val >> SIZE;
if extra_bits != -1 && extra_bits != 0 {
return Err(())
}
self.0 = (self.0 & !MASK) | ((val as $t & SIZE_MASK) << $start);
Ok(())
})?
)?
};
}
pub(crate) use bitflags;
pub(crate) use bitflags_field;
use crate::safe_jit::JitError;
#[allow(unused)]
pub(crate) struct FmtDecBin<T>(pub T);
impl<T: ::core::fmt::Display + ::core::fmt::Binary> ::core::fmt::Debug for FmtDecBin<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_fmt(format_args!("{0} (0b{0:b})", self.0))
}
}