diff options
| -rw-r--r-- | CHANGELOG | 17 | ||||
| -rw-r--r-- | Cargo.toml | 5 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | src/address/mod.rs | 218 | ||||
| -rw-r--r-- | src/lib.rs | 8 | ||||
| -rw-r--r-- | tests/lib.rs | 12 | 
6 files changed, 252 insertions, 10 deletions
| diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..741cf88 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,17 @@ +## 0.0.4 + +add `AddressDiff`. `LengthedInstruction::len` now return `AddressDiff`. the length of an instruction is the difference between two addresses, not itself an address. + +## 0.0.3 + +`ColorSettings` gets a default impl + +## 0.0.2 + +add `AddressDisplay` to provide a usable interface to display `Address` implementors. + +at the same time, remove `Address::stringy()`. it was a very bad interface, and will not be missed. + +## 0.0.1 + +history starts here @@ -7,12 +7,13 @@ keywords = ["disassembly", "disassembler"]  license = "0BSD"  name = "yaxpeax-arch"  repository = "https://git.iximeow.net/yaxpeax-arch/" -version = "0.0.3" +version = "0.0.4"  [dependencies]  "num-traits" = { version = "0.2", default-features = false }  "termion" = { version = "1.4.0", optional = true }  "serde" = { version = "1.0", optional = true } +"serde_derive" = { version = "1.0", optional = true }  [profile.release]  lto = true @@ -22,7 +23,7 @@ default = ["use-serde", "colors", "address-parse"]  # enables the (optional) use of Serde for bounds on  # Arch and Arch::Address -use-serde = ["serde"] +use-serde = ["serde", "serde_derive"]  colors = ["termion"] @@ -35,4 +35,4 @@ the canonical copy of `yaxpeax-arch` is at [https://git.iximeow.net/yaxpeax-arch  `yaxpeax-arch` is also mirrored on GitHub at [https://www.github.com/iximeow/yaxpeax-x86](https://www.github.com/iximeow/yaxpeax-arch).  ### ! user beware ! -these interfaces will almost certainly move and change. the version number is `0.0.1` and i mean it with every fiber of my being. +these interfaces will almost certainly move and change. the version number is `0.0.4` and i mean it with every fiber of my being. 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<A: AddressBase + core::fmt::Debug>(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<T: AddressDiffAmount> { +    // 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<A: AddressBase + core::fmt::Debug>(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<T: AddressDiffAmount> { +    amount: T, +} + +impl<T: AddressDiffAmount> AddressDiff<T> { +    pub fn from_const(amount: T) -> Self { +        AddressDiff { amount } +    } +} + +impl<T: AddressDiffAmount + fmt::Debug> fmt::Debug for AddressDiff<T> { +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        write!(f, "AddressDiff({:?})", self.amount) +    } +} + +impl<T: AddressDiffAmount> AddressDiff<T> { +    pub fn one() -> Self { +        AddressDiff { +            amount: T::one(), +        } +    } + +    pub fn zero() -> Self { +        AddressDiff { +            amount: T::zero(), +        } +    } +} + +impl Sub<AddressDiff<u16>> for u16 { +    type Output = Self; + +    fn sub(self, other: AddressDiff<Self>) -> Self::Output { +        self - other.amount +    } +} + +impl Sub<AddressDiff<u32>> for u32 { +    type Output = Self; + +    fn sub(self, other: AddressDiff<Self>) -> Self::Output { +        self - other.amount +    } +} + +impl Sub<AddressDiff<u64>> for u64 { +    type Output = Self; + +    fn sub(self, other: AddressDiff<Self>) -> Self::Output { +        self - other.amount +    } +} + +impl Sub<AddressDiff<usize>> for usize { +    type Output = Self; + +    fn sub(self, other: AddressDiff<Self>) -> Self::Output { +        self - other.amount +    } +} + +impl Add<AddressDiff<u16>> for u16 { +    type Output = Self; + +    fn add(self, other: AddressDiff<Self>) -> Self::Output { +        self + other.amount +    } +} + +impl Add<AddressDiff<u32>> for u32 { +    type Output = Self; + +    fn add(self, other: AddressDiff<Self>) -> Self::Output { +        self + other.amount +    } +} + +impl Add<AddressDiff<u64>> for u64 { +    type Output = Self; + +    fn add(self, other: AddressDiff<Self>) -> Self::Output { +        self + other.amount +    } +} + +impl Add<AddressDiff<usize>> for usize { +    type Output = Self; + +    fn add(self, other: AddressDiff<Self>) -> Self::Output { +        self + other.amount +    } +} + +impl SubAssign<AddressDiff<u16>> for u16 { +    fn sub_assign(&mut self, other: AddressDiff<Self>) { +        *self -= other.amount; +    } +} + +impl SubAssign<AddressDiff<u32>> for u32 { +    fn sub_assign(&mut self, other: AddressDiff<Self>) { +        *self -= other.amount; +    } +} + +impl SubAssign<AddressDiff<u64>> for u64 { +    fn sub_assign(&mut self, other: AddressDiff<Self>) { +        *self -= other.amount; +    } +} + +impl SubAssign<AddressDiff<usize>> for usize { +    fn sub_assign(&mut self, other: AddressDiff<Self>) { +        *self -= other.amount; +    } +} + +impl AddAssign<AddressDiff<u16>> for u16 { +    fn add_assign(&mut self, other: AddressDiff<Self>) { +        *self += other.amount; +    } +} + +impl AddAssign<AddressDiff<u32>> for u32 { +    fn add_assign(&mut self, other: AddressDiff<Self>) { +        *self += other.amount; +    } +} + +impl AddAssign<AddressDiff<u64>> for u64 { +    fn add_assign(&mut self, other: AddressDiff<Self>) { +        *self += other.amount; +    } +} + +impl AddAssign<AddressDiff<usize>> for usize { +    fn add_assign(&mut self, other: AddressDiff<Self>) { +        *self += other.amount; +    } +} +  pub trait AddressBase where Self:      AddressDisplay +      Copy + Clone + Sized + Hash +      Ord + Eq + PartialEq + Bounded + -    Add<Output=Self> + Sub<Output=Self> + -    AddAssign + SubAssign + +    Add<AddressDiff<Self>, Output=Self> + Sub<AddressDiff<Self>, Output=Self> + +    AddAssign<AddressDiff<Self>> + SubAssign<AddressDiff<Self>> +      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<AddressDiff<Self>> { +        Some(AddressDiff { amount: self.wrapping_sub(other) }) +    } + +    fn wrapping_offset(&self, other: AddressDiff<Self>) -> Self { +        self.wrapping_add(&other.amount) +    } + +    fn checked_offset(&self, other: AddressDiff<Self>) -> Option<Self> { +        self.checked_add(&other.amount) +    }  }  #[cfg(all(feature="use-serde", feature="address-parse"))] @@ -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<Inst> 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<Unit=Self::Address> + Debug + Default; +    type Instruction: Instruction + LengthedInstruction<Unit=AddressDiff<Self::Address>> + Debug + Default;      type DecodeError: DecodeError + Debug + Display;      type Decoder: Decoder<Self::Instruction, Error=Self::DecodeError> + 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<Unit=Self::Address> + Debug + Default; +    type Instruction: Instruction + LengthedInstruction<Unit=AddressDiff<Self::Address>> + Debug + Default;      type DecodeError: DecodeError + Debug + Display;      type Decoder: Decoder<Self::Instruction, Error=Self::DecodeError> + Default;      type Operand; diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 0000000..15477f7 --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,12 @@ +#![no_std] + +use yaxpeax_arch::AddressBase; + +#[test] +fn test_u16() { +    for l in 0..100 { +        for r in 0..=core::u16::MAX { +            assert_eq!(r.wrapping_offset(l.diff(&r).expect("u16 addresses always have valid diffs")), l); +        } +    } +} | 
