From f7449a21140c109567fa6c756dab2b1b0711a414 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 3 May 2020 12:29:24 -0700 Subject: add AddressDiff, CHANGELOG, and bump to 0.0.4 --- src/address/mod.rs | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 8 +- 2 files changed, 219 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/address/mod.rs b/src/address/mod.rs index edda85d..d3f5113 100644 --- a/src/address/mod.rs +++ b/src/address/mod.rs @@ -10,17 +10,227 @@ use num_traits::{Bounded, WrappingAdd, WrappingSub, CheckedAdd, CheckedSub}; #[cfg(feature="use-serde")] use serde::{Deserialize, Serialize}; +#[cfg(feature="use-serde")] +pub trait AddressDiffAmount: Copy + Clone + PartialEq + PartialOrd + Eq + Ord + identities::Zero + identities::One + Serialize + for<'de> Deserialize<'de> {} +#[cfg(not(feature="use-serde"))] +pub trait AddressDiffAmount: Copy + Clone + PartialEq + PartialOrd + Eq + Ord + identities::Zero + identities::One {} + +impl AddressDiffAmount for u64 {} +impl AddressDiffAmount for u32 {} +impl AddressDiffAmount for u16 {} +impl AddressDiffAmount for usize {} + +/// a struct describing the differece between some pair of `A: Address`. this is primarily useful +/// in describing the size of an instruction, or the relative offset of a branch. +/// +/// for any address type `A`, the following must hold: +/// ```rust +/// use yaxpeax_arch::AddressBase; +/// fn diff_check(left: A, right: A) { +/// let diff = left.diff(&right); +/// if let Some(offset) = diff { +/// assert_eq!(left.wrapping_offset(offset), right); +/// } +/// } +/// ``` +/// +/// which is to say, `yaxpeax` assumes associativity holds when `diff` yields a `Some`. +#[cfg(feature="use-serde")] +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] +pub struct AddressDiff { + // the AddressDiffAmount trait fools `Deserialize`'s proc macro, so we have to explicitly write + // the bound serde should use. + #[serde(bound(deserialize = "T: AddressDiffAmount"))] + amount: T, +} +/// a struct describing the differece between some pair of `A: Address`. this is primarily useful +/// in describing the size of an instruction, or the relative offset of a branch. +/// +/// for any address type `A`, the following must hold: +/// ```rust +/// use yaxpeax_arch::AddressBase; +/// fn diff_check(left: A, right: A) { +/// let diff = left.diff(&right); +/// if let Some(offset) = diff { +/// assert_eq!(left.wrapping_offset(offset), right); +/// } +/// } +/// ``` +/// +/// which is to say, `yaxpeax` assumes associativity holds when `diff` yields a `Some`. +#[cfg(not(feature="use-serde"))] +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] +pub struct AddressDiff { + amount: T, +} + +impl AddressDiff { + pub fn from_const(amount: T) -> Self { + AddressDiff { amount } + } +} + +impl fmt::Debug for AddressDiff { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "AddressDiff({:?})", self.amount) + } +} + +impl AddressDiff { + pub fn one() -> Self { + AddressDiff { + amount: T::one(), + } + } + + pub fn zero() -> Self { + AddressDiff { + amount: T::zero(), + } + } +} + +impl Sub> for u16 { + type Output = Self; + + fn sub(self, other: AddressDiff) -> Self::Output { + self - other.amount + } +} + +impl Sub> for u32 { + type Output = Self; + + fn sub(self, other: AddressDiff) -> Self::Output { + self - other.amount + } +} + +impl Sub> for u64 { + type Output = Self; + + fn sub(self, other: AddressDiff) -> Self::Output { + self - other.amount + } +} + +impl Sub> for usize { + type Output = Self; + + fn sub(self, other: AddressDiff) -> Self::Output { + self - other.amount + } +} + +impl Add> for u16 { + type Output = Self; + + fn add(self, other: AddressDiff) -> Self::Output { + self + other.amount + } +} + +impl Add> for u32 { + type Output = Self; + + fn add(self, other: AddressDiff) -> Self::Output { + self + other.amount + } +} + +impl Add> for u64 { + type Output = Self; + + fn add(self, other: AddressDiff) -> Self::Output { + self + other.amount + } +} + +impl Add> for usize { + type Output = Self; + + fn add(self, other: AddressDiff) -> Self::Output { + self + other.amount + } +} + +impl SubAssign> for u16 { + fn sub_assign(&mut self, other: AddressDiff) { + *self -= other.amount; + } +} + +impl SubAssign> for u32 { + fn sub_assign(&mut self, other: AddressDiff) { + *self -= other.amount; + } +} + +impl SubAssign> for u64 { + fn sub_assign(&mut self, other: AddressDiff) { + *self -= other.amount; + } +} + +impl SubAssign> for usize { + fn sub_assign(&mut self, other: AddressDiff) { + *self -= other.amount; + } +} + +impl AddAssign> for u16 { + fn add_assign(&mut self, other: AddressDiff) { + *self += other.amount; + } +} + +impl AddAssign> for u32 { + fn add_assign(&mut self, other: AddressDiff) { + *self += other.amount; + } +} + +impl AddAssign> for u64 { + fn add_assign(&mut self, other: AddressDiff) { + *self += other.amount; + } +} + +impl AddAssign> for usize { + fn add_assign(&mut self, other: AddressDiff) { + *self += other.amount; + } +} + pub trait AddressBase where Self: AddressDisplay + Copy + Clone + Sized + Hash + Ord + Eq + PartialEq + Bounded + - Add + Sub + - AddAssign + SubAssign + + Add, Output=Self> + Sub, Output=Self> + + AddAssign> + SubAssign> + WrappingAdd + WrappingSub + CheckedAdd + CheckedSub + - Hash + - identities::One + identities::Zero { + identities::Zero + + AddressDiffAmount + + Hash { fn to_linear(&self) -> usize; + + /// compute the `AddressDiff` beetween `self` and `other`. + /// + /// may return `None` if the two addresses aren't comparable. for example, if a pair of + /// addresses are a data-space address and code-space address, there may be no scalar that can + /// describe the difference between them. + fn diff(&self, other: &Self) -> Option> { + Some(AddressDiff { amount: self.wrapping_sub(other) }) + } + + fn wrapping_offset(&self, other: AddressDiff) -> Self { + self.wrapping_add(&other.amount) + } + + fn checked_offset(&self, other: AddressDiff) -> Option { + self.checked_add(&other.amount) + } } #[cfg(all(feature="use-serde", feature="address-parse"))] diff --git a/src/lib.rs b/src/lib.rs index 17115af..76de58c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,8 @@ use core::hash::Hash; extern crate num_traits; #[cfg(feature="use-serde")] extern crate serde; +#[cfg(feature="use-serde")] +#[macro_use] extern crate serde_derive; #[cfg(feature="colors")] extern crate termion; @@ -17,7 +19,7 @@ extern crate termion; use serde::{Serialize, Deserialize}; mod address; -pub use address::{Address, AddressBase, AddressDisplay}; +pub use address::{Address, AddressBase, AddressDiff, AddressDiffAmount, AddressDisplay}; pub use address::{AddressDisplayUsize, AddressDisplayU64, AddressDisplayU32, AddressDisplayU16}; #[cfg(feature="address-parse")] pub use address::AddrParse; @@ -50,7 +52,7 @@ pub trait Decoder where Inst: Sized + Default { #[cfg(feature="use-serde")] pub trait Arch { type Address: Address + Debug + Hash + PartialEq + Eq + Serialize + for<'de> Deserialize<'de>; - type Instruction: Instruction + LengthedInstruction + Debug + Default; + type Instruction: Instruction + LengthedInstruction> + Debug + Default; type DecodeError: DecodeError + Debug + Display; type Decoder: Decoder + Default; type Operand; @@ -59,7 +61,7 @@ pub trait Arch { #[cfg(not(feature="use-serde"))] pub trait Arch { type Address: Address + Debug + Hash + PartialEq + Eq; - type Instruction: Instruction + LengthedInstruction + Debug + Default; + type Instruction: Instruction + LengthedInstruction> + Debug + Default; type DecodeError: DecodeError + Debug + Display; type Decoder: Decoder + Default; type Operand; -- cgit v1.1