yaxpeax_arch/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3
4#[cfg(feature = "alloc")]
5extern crate alloc;
6
7use core::fmt::{self, Debug, Display};
8use core::hash::Hash;
9
10#[cfg(feature="use-serde")]
11#[macro_use] extern crate serde_derive;
12#[cfg(feature="use-serde")]
13use serde::{Serialize, Deserialize};
14
15mod address;
16pub use address::{Address, AddressBase, AddressDiff, AddressDiffAmount, AddressDisplay};
17pub use address::{AddressDisplayUsize, AddressDisplayU64, AddressDisplayU32, AddressDisplayU16};
18#[cfg(feature="address-parse")]
19pub use address::AddrParse;
20
21pub mod annotation;
22
23#[deprecated(since="0.3.0", note="yaxpeax_arch::color conflates output mechanism and styling, leaving it brittle and overly-restrictive. see `yaxpeax_arch::color_new`, which will replace `color` in a future version.")]
24mod color;
25#[allow(deprecated)] // allow exporting the deprecated items here to not break downstreams even further...
26pub use color::{Colorize, NoColors, YaxColors};
27#[cfg(feature="color-new")]
28pub mod color_new;
29
30pub mod display;
31
32mod reader;
33pub use reader::{Reader, ReaderBuilder, ReadError, U8Reader, U16le, U16be, U32le, U32be, U64le, U64be};
34
35pub mod safer_unchecked;
36
37pub mod testkit;
38
39/// the minimum set of errors a `yaxpeax-arch` disassembler may produce.
40///
41/// it is permissible for an implementer of `DecodeError` to have items that return `false` for
42/// all these functions; decoders are permitted to error in way that `yaxpeax-arch` does not know
43/// about.
44pub trait DecodeError: PartialEq + Display + Debug + Send + Sync + 'static {
45    /// did the decoder fail because it reached the end of input?
46    fn data_exhausted(&self) -> bool;
47    /// did the decoder error because the instruction's opcode is invalid?
48    ///
49    /// this may not be a sensical question for some instruction sets - `bad_opcode` should
50    /// generally indicate an issue with the instruction itself. this is in contrast to one
51    /// specific operand being invalid for the instruction, or some other issue to do with decoding
52    /// data beyond the top-level instruction. the "opcode"/"operand" distinction is often fuzzy
53    /// and left as best-effort for decoder implementers.
54    fn bad_opcode(&self) -> bool;
55    /// did the decoder error because an operand of the instruction to decode is invalid?
56    ///
57    /// similar to [`DecodeError::bad_opcode`], this is a subjective distinction and best-effort on
58    /// the part of implementers.
59    fn bad_operand(&self) -> bool;
60    /// a human-friendly description of this decode error.
61    fn description(&self) -> &'static str;
62}
63
64/// a minimal enum implementing `DecodeError`. this is intended to be enough for a low effort,
65/// low-fidelity error taxonomy, without boilerplate of a `DecodeError` implementation.
66#[derive(Debug, PartialEq, Eq, Copy, Clone)]
67pub enum StandardDecodeError {
68    ExhaustedInput,
69    InvalidOpcode,
70    InvalidOperand,
71}
72
73/// a slightly less minimal enum `DecodeError`. similar to `StandardDecodeError`, this is an
74/// anti-boilerplate measure. it additionally provides `IncompleteDecoder`, making it suitable to
75/// represent error kinds for decoders that are ... not yet complete.
76#[derive(Debug, PartialEq, Eq, Copy, Clone)]
77pub enum StandardPartialDecoderError {
78    ExhaustedInput,
79    InvalidOpcode,
80    InvalidOperand,
81    IncompleteDecoder,
82}
83
84#[cfg(feature = "std")]
85extern crate std;
86#[cfg(feature = "std")]
87impl std::error::Error for StandardDecodeError {
88    fn description(&self) -> &str {
89        <Self as DecodeError>::description(self)
90    }
91}
92#[cfg(feature = "std")]
93impl std::error::Error for StandardPartialDecoderError {
94    fn description(&self) -> &str {
95        <Self as DecodeError>::description(self)
96    }
97}
98
99impl fmt::Display for StandardDecodeError {
100    fn fmt(&self, f:  &mut fmt::Formatter) -> fmt::Result {
101        f.write_str(self.description())
102    }
103}
104
105impl fmt::Display for StandardPartialDecoderError {
106    fn fmt(&self, f:  &mut fmt::Formatter) -> fmt::Result {
107        f.write_str(self.description())
108    }
109}
110
111impl DecodeError for StandardDecodeError {
112    fn data_exhausted(&self) -> bool { *self == StandardDecodeError::ExhaustedInput }
113    fn bad_opcode(&self) -> bool { *self == StandardDecodeError::InvalidOpcode }
114    fn bad_operand(&self) -> bool { *self == StandardDecodeError::InvalidOperand }
115    fn description(&self) -> &'static str {
116        match self {
117            StandardDecodeError::ExhaustedInput => "exhausted input",
118            StandardDecodeError::InvalidOpcode => "invalid opcode",
119            StandardDecodeError::InvalidOperand => "invalid operand",
120        }
121    }
122}
123
124impl DecodeError for StandardPartialDecoderError {
125    fn data_exhausted(&self) -> bool { *self == StandardPartialDecoderError::ExhaustedInput }
126    fn bad_opcode(&self) -> bool { *self == StandardPartialDecoderError::InvalidOpcode }
127    fn bad_operand(&self) -> bool { *self == StandardPartialDecoderError::InvalidOperand }
128    fn description(&self) -> &'static str {
129        match self {
130            StandardPartialDecoderError::ExhaustedInput => "exhausted input",
131            StandardPartialDecoderError::InvalidOpcode => "invalid opcode",
132            StandardPartialDecoderError::InvalidOperand => "invalid operand",
133            StandardPartialDecoderError::IncompleteDecoder => "incomplete decoder",
134        }
135    }
136}
137
138/*
139#[derive(Copy, Clone)]
140struct NoDescription {}
141
142impl fmt::Display for NoDescription {
143    fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
144        Ok(())
145    }
146}
147*/
148
149/// an interface to decode [`Arch::Instruction`] words from a reader of [`Arch::Word`]s. errors are
150/// the architecture-defined [`DecodeError`] implemention.
151pub trait Decoder<A: Arch + ?Sized> {
152    /// decode one instruction for this architecture from the [`crate::Reader`] of this
153    /// architecture's `Word`.
154    fn decode<T: Reader<A::Address, A::Word>>(&self, words: &mut T) -> Result<A::Instruction, A::DecodeError> {
155        let mut inst = A::Instruction::default();
156        self.decode_into(&mut inst, words).map(|_: ()| inst)
157    }
158
159    /// decode one instruction for this architecture from the [`crate::Reader`] of this
160    /// architecture's `Word`, writing into the provided `inst`.
161    ///
162    /// SAFETY:
163    ///
164    /// while `inst` MUST be left in a state that does not violate Rust's safety guarantees,
165    /// implementers are NOT obligated to leave `inst` in a semantically meaningful state if
166    /// decoding fails. if `decode_into` returns an error, callers may find contradictory and
167    /// useless information in `inst`, as well as *stale data* from whatever was passed in.
168    fn decode_into<T: Reader<A::Address, A::Word>>(&self, inst: &mut A::Instruction, words: &mut T) -> Result<(), A::DecodeError>;
169}
170
171#[cfg(feature = "use-serde")]
172pub trait AddressBounds: Address + Debug + Hash + PartialEq + Eq + Serialize + for<'de> Deserialize<'de> {}
173#[cfg(not(feature = "use-serde"))]
174pub trait AddressBounds: Address + Debug + Hash + PartialEq + Eq {}
175
176#[cfg(feature = "use-serde")]
177impl<T> AddressBounds for T where T: Address + Debug + Hash + PartialEq + Eq + Serialize + for<'de> Deserialize<'de> {}
178#[cfg(not(feature = "use-serde"))]
179impl<T> AddressBounds for T where T: Address + Debug + Hash + PartialEq + Eq {}
180
181#[cfg(feature = "std")]
182/// this is not a particularly interesting trait. it just exists to add a `std::error::Error`
183/// bound onto `DecodeError` for `std` builds.
184pub trait DecodeErrorBounds: std::error::Error + DecodeError {}
185#[cfg(feature = "std")]
186impl<T: std::error::Error + DecodeError> DecodeErrorBounds for T {}
187#[cfg(not(feature = "std"))]
188/// this is not a particularly interesting trait. it just exists to add a `std::error::Error`
189/// bound onto `DecodeError` for `std` builds.
190pub trait DecodeErrorBounds: DecodeError {}
191#[cfg(not(feature = "std"))]
192impl<T: DecodeError> DecodeErrorBounds for T {}
193
194
195/// a collection of associated type parameters that constitute the definitions for an instruction
196/// set. `Arch` provides an `Instruction` and its associated `Operand`s, which is guaranteed to be
197/// decodable by this `Arch::Decoder`. `Arch::Decoder` can always be constructed with a `Default`
198/// implementation, and decodes from a `Reader<Arch::Address, Arch::Word>`.
199///
200/// `Arch` is suitable as the foundational trait to implement more complex logic on top of; for
201/// example, it would be entirely expected to have a
202/// ```text
203/// pub fn emulate<A: Arch, E: Emulator<A>>(
204///     reader: &mut Reader<A::Address, A::Word>,
205///     emu: &mut E
206/// ) -> Result<A::Address, DecodeOrEvaluationError>;
207/// ```
208///
209/// in some library built on top of `yaxpeax-arch`.
210pub trait Arch {
211    type Word: Debug + Display + PartialEq + Eq;
212    type Address: AddressBounds;
213    type Instruction: Instruction + LengthedInstruction<Unit=AddressDiff<Self::Address>> + Debug + Default + Sized;
214    type DecodeError: DecodeErrorBounds + Debug + Display;
215    type Decoder: Decoder<Self> + Default;
216    type Operand;
217}
218
219/// instructions have lengths, and minimum possible sizes for advancing a decoder on error.
220///
221/// unfortunately, this means calling `x.len()` for some `Arch::Instruction` requires importing
222/// this trait. sorry.
223pub trait LengthedInstruction {
224    type Unit;
225    /// the length, in terms of `Unit`, of this instruction. because `Unit` will be a diff of an
226    /// architecture's `Address` type, this almost always is a number of bytes. implementations
227    /// should indicate if this is ever not the case.
228    fn len(&self) -> Self::Unit;
229    /// the length, in terms of `Unit`, of the shortest possible instruction in a given
230    /// architecture.. because `Unit` will be a diff of an architecture's `Address` type, this
231    /// almost always is a number of bytes. implementations should indicate if this is ever not the
232    /// case.
233    fn min_size() -> Self::Unit;
234}
235
236pub trait Instruction {
237    fn well_defined(&self) -> bool;
238}
239
240#[allow(deprecated)]
241#[deprecated(since="0.3.0", note="ShowContextual ties YaxColors and fmt::Write in a way that only sometimes composes. simultaneously, it is too generic on Ctx, making it difficult to implement and use. it will be revisited in the future.")]
242pub trait ShowContextual<Addr, Ctx: ?Sized, T: fmt::Write, Y: YaxColors> {
243    fn contextualize(&self, colors: &Y, address: Addr, context: Option<&Ctx>, out: &mut T) -> fmt::Result;
244}
245
246/*
247impl <C: ?Sized, T: fmt::Write, U: Colorize<T>> ShowContextual<C, T> for U {
248    fn contextualize(&self, colors: Option<&ColorSettings>, context: Option<&C>, out: &mut T) -> fmt::Result {
249        self.colorize(colors, out)
250    }
251}
252*/