aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2022-04-24 17:39:21 -0700
committeriximeow <me@iximeow.net>2022-04-24 19:22:52 -0700
commit2097524c851b15e89091fd3775817a06f0eeae4f (patch)
treee3c175856fcde170db91474ec580b549f97f8ad7 /src
parente80b5622ec956a92f24ce6487fb0d76e9c541515 (diff)
fix a few issues preventing no-std builds from ... building
this includes a `Makefile` that exercises the various crate configs. most annoyingly, several doc comments needed to grow `#[cfg(feature="fmt")]` blocks so docs continue to build with that feature enabled or disabled. carved out a way to run exhaustive tests; they should be written as `#[ignore]`, and then the makefile will run even ignored tests on the expectation that this will run the exhaustive (but slower) suite. exhaustive tests are not yet written. they'll probably involve spanning 4 byte sequences from 0 to 2^32-1.
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs19
-rw-r--r--src/long_mode/mod.rs75
-rw-r--r--src/protected_mode/mod.rs75
-rw-r--r--src/real_mode/mod.rs74
4 files changed, 149 insertions, 94 deletions
diff --git a/src/lib.rs b/src/lib.rs
index b8bd4f7..9825fd2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,7 @@
//!
//! let inst = decoder.decode_slice(&[0x33, 0xc0]).unwrap();
//!
+//! #[cfg(features="fmt")]
//! assert_eq!("xor eax, eax", inst.to_string());
//! ```
//!
@@ -31,13 +32,16 @@
//!
//! let inst = decoder.decode_slice(&[0x33, 0x01]).unwrap();
//!
+//! #[cfg(features="fmt")]
//! assert_eq!("xor eax, dword [rcx]", inst.to_string());
//!
//! assert_eq!(Operand::Register(RegSpec::eax()), inst.operand(0));
+//! #[cfg(features="fmt")]
//! assert_eq!("eax", inst.operand(0).to_string());
//! assert_eq!(Operand::RegDeref(RegSpec::rcx()), inst.operand(1));
//!
//! // an operand in isolation does not know the size of memory it references, if any
+//! #[cfg(features="fmt")]
//! assert_eq!("[rcx]", inst.operand(1).to_string());
//!
//! // and for memory operands, the size must be read from the instruction itself:
@@ -45,6 +49,7 @@
//! assert_eq!("dword", mem_size.size_name());
//!
//! // `MemoryAccessSize::size_name()` is how its `Display` impl works, as well:
+//! #[cfg(features="fmt")]
//! assert_eq!("dword", mem_size.to_string());
//! ```
//!
@@ -54,12 +59,23 @@
//! mod decoder {
//! use yaxpeax_arch::{Arch, AddressDisplay, Decoder, Reader, ReaderBuilder};
//!
+//! // have to play some games so this example works right even without `fmt` enabled!
+//! #[cfg(feature="fmt")]
+//! trait InstBound: std::fmt::Display {}
+//! #[cfg(not(feature="fmt"))]
+//! trait InstBound {}
+//!
+//! #[cfg(feature="fmt")]
+//! impl <T: std::fmt::Display> InstBound for T {}
+//! #[cfg(not(feature="fmt"))]
+//! impl <T> InstBound for T {}
+//!
//! pub fn decode_stream<
//! 'data,
//! A: yaxpeax_arch::Arch,
//! U: ReaderBuilder<A::Address, A::Word>,
//! >(data: U) where
-//! A::Instruction: std::fmt::Display,
+//! A::Instruction: InstBound,
//! {
//! let mut reader = ReaderBuilder::read_from(data);
//! let mut address: A::Address = reader.total_offset();
@@ -69,6 +85,7 @@
//! loop {
//! match decode_res {
//! Ok(ref inst) => {
+//! #[cfg(feature="fmt")]
//! println!("{}: {}", address.show(), inst);
//! decode_res = decoder.decode(&mut reader);
//! address = reader.total_offset();
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index d2cb2f7..6475d4e 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -888,11 +888,13 @@ const REGISTER_CLASS_NAMES: &[&'static str] = &[
/// }
///
/// if let Operand::Register(regspec) = instruction.operand(0) {
+/// #[cfg(feature="fmt")]
/// println!("first operand is {}", regspec);
/// show_register_class_info(regspec.class());
/// }
///
/// if let Operand::Register(regspec) = instruction.operand(1) {
+/// #[cfg(feature="fmt")]
/// println!("first operand is {}", regspec);
/// show_register_class_info(regspec.class());
/// }
@@ -7422,43 +7424,54 @@ impl InnerDescription {
}
}
-impl fmt::Display for InnerDescription {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- InnerDescription::RexPrefix(bits) => {
- write!(f, "rex prefix: {}{}{}{}",
- if bits & 0x8 != 0 { "w" } else { "-" },
- if bits & 0x4 != 0 { "r" } else { "-" },
- if bits & 0x2 != 0 { "x" } else { "-" },
- if bits & 0x1 != 0 { "b" } else { "-" },
- )
- }
- InnerDescription::SegmentPrefix(segment) => {
- write!(f, "segment override: {}", segment)
- }
- InnerDescription::Misc(text) => {
- f.write_str(text)
- }
- InnerDescription::Number(text, num) => {
- write!(f, "{}: {:#x}", text, num)
- }
- InnerDescription::Opcode(opc) => {
- write!(f, "opcode `{}`", opc)
- }
- InnerDescription::OperandCode(OperandCodeWrapper { code }) => {
- write!(f, "operand code `{:?}`", code)
- }
- InnerDescription::RegisterNumber(name, num, reg) => {
- write!(f, "`{}` (`{}` selects register number {})", reg, name, num)
+cfg_if::cfg_if! {
+ if #[cfg(feature="fmt")] {
+ impl fmt::Display for InnerDescription {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ InnerDescription::RexPrefix(bits) => {
+ write!(f, "rex prefix: {}{}{}{}",
+ if bits & 0x8 != 0 { "w" } else { "-" },
+ if bits & 0x4 != 0 { "r" } else { "-" },
+ if bits & 0x2 != 0 { "x" } else { "-" },
+ if bits & 0x1 != 0 { "b" } else { "-" },
+ )
+ }
+ InnerDescription::SegmentPrefix(segment) => {
+ write!(f, "segment override: {}", segment)
+ }
+ InnerDescription::Misc(text) => {
+ f.write_str(text)
+ }
+ InnerDescription::Number(text, num) => {
+ write!(f, "{}: {:#x}", text, num)
+ }
+ InnerDescription::Opcode(opc) => {
+ write!(f, "opcode `{}`", opc)
+ }
+ InnerDescription::OperandCode(OperandCodeWrapper { code }) => {
+ write!(f, "operand code `{:?}`", code)
+ }
+ InnerDescription::RegisterNumber(name, num, reg) => {
+ write!(f, "`{}` (`{}` selects register number {})", reg, name, num)
+ }
+ InnerDescription::Boundary(desc) => {
+ write!(f, "{}", desc)
+ }
+ }
}
- InnerDescription::Boundary(desc) => {
- write!(f, "{}", desc)
+ }
+ } else {
+ impl fmt::Display for InnerDescription {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("non-fmt build")
}
}
}
}
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature="fmt", derive(Debug))]
+#[derive(Clone, PartialEq, Eq)]
pub struct FieldDescription {
desc: InnerDescription,
id: u32,
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index 0a6fcf8..dd63d32 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -833,11 +833,13 @@ const REGISTER_CLASS_NAMES: &[&'static str] = &[
/// }
///
/// if let Operand::Register(regspec) = instruction.operand(0) {
+/// #[cfg(feature="fmt")]
/// println!("first operand is {}", regspec);
/// show_register_class_info(regspec.class());
/// }
///
/// if let Operand::Register(regspec) = instruction.operand(1) {
+/// #[cfg(feature="fmt")]
/// println!("first operand is {}", regspec);
/// show_register_class_info(regspec.class());
/// }
@@ -7386,7 +7388,8 @@ fn read_0f3a_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord {
};
}
-/// the actual description for a selection of bits involved in decoding an [`long_mode::Instruction`].
+/// the actual description for a selection of bits involved in decoding a
+/// [`protected_mode::Instruction`].
///
/// some prefixes are only identified as an `InnerDescription::Misc` string, while some are full
/// `InnerDescription::SegmentPrefix(Segment)`. generally, strings should be considered unstable
@@ -7439,37 +7442,47 @@ impl InnerDescription {
}
}
-impl fmt::Display for InnerDescription {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- InnerDescription::RexPrefix(bits) => {
- write!(f, "rex prefix: {}{}{}{}",
- if bits & 0x8 != 0 { "w" } else { "-" },
- if bits & 0x4 != 0 { "r" } else { "-" },
- if bits & 0x2 != 0 { "x" } else { "-" },
- if bits & 0x1 != 0 { "b" } else { "-" },
- )
- }
- InnerDescription::SegmentPrefix(segment) => {
- write!(f, "segment override: {}", segment)
- }
- InnerDescription::Misc(text) => {
- f.write_str(text)
- }
- InnerDescription::Number(text, num) => {
- write!(f, "{}: {:#x}", text, num)
- }
- InnerDescription::Opcode(opc) => {
- write!(f, "opcode `{}`", opc)
- }
- InnerDescription::OperandCode(OperandCodeWrapper { code }) => {
- write!(f, "operand code `{:?}`", code)
- }
- InnerDescription::RegisterNumber(name, num, reg) => {
- write!(f, "`{}` (`{}` selects register number {})", reg, name, num)
+cfg_if::cfg_if! {
+ if #[cfg(feature = "fmt")] {
+ impl fmt::Display for InnerDescription {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ InnerDescription::RexPrefix(bits) => {
+ write!(f, "rex prefix: {}{}{}{}",
+ if bits & 0x8 != 0 { "w" } else { "-" },
+ if bits & 0x4 != 0 { "r" } else { "-" },
+ if bits & 0x2 != 0 { "x" } else { "-" },
+ if bits & 0x1 != 0 { "b" } else { "-" },
+ )
+ }
+ InnerDescription::SegmentPrefix(segment) => {
+ write!(f, "segment override: {}", segment)
+ }
+ InnerDescription::Misc(text) => {
+ f.write_str(text)
+ }
+ InnerDescription::Number(text, num) => {
+ write!(f, "{}: {:#x}", text, num)
+ }
+ InnerDescription::Opcode(opc) => {
+ write!(f, "opcode `{}`", opc)
+ }
+ InnerDescription::OperandCode(OperandCodeWrapper { code }) => {
+ write!(f, "operand code `{:?}`", code)
+ }
+ InnerDescription::RegisterNumber(name, num, reg) => {
+ write!(f, "`{}` (`{}` selects register number {})", reg, name, num)
+ }
+ InnerDescription::Boundary(desc) => {
+ write!(f, "{}", desc)
+ }
+ }
}
- InnerDescription::Boundary(desc) => {
- write!(f, "{}", desc)
+ }
+ } else {
+ impl fmt::Display for InnerDescription {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("non-fmt build")
}
}
}
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index 4b8ad6d..d7fda17 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -833,11 +833,13 @@ const REGISTER_CLASS_NAMES: &[&'static str] = &[
/// }
///
/// if let Operand::Register(regspec) = instruction.operand(0) {
+/// #[cfg(feature="fmt")]
/// println!("first operand is {}", regspec);
/// show_register_class_info(regspec.class());
/// }
///
/// if let Operand::Register(regspec) = instruction.operand(1) {
+/// #[cfg(feature="fmt")]
/// println!("first operand is {}", regspec);
/// show_register_class_info(regspec.class());
/// }
@@ -7388,7 +7390,7 @@ fn read_0f3a_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord {
};
}
-/// the actual description for a selection of bits involved in decoding an [`long_mode::Instruction`].
+/// the actual description for a selection of bits involved in decoding a [`real_mode::Instruction`].
///
/// some prefixes are only identified as an `InnerDescription::Misc` string, while some are full
/// `InnerDescription::SegmentPrefix(Segment)`. generally, strings should be considered unstable
@@ -7441,37 +7443,47 @@ impl InnerDescription {
}
}
-impl fmt::Display for InnerDescription {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- InnerDescription::RexPrefix(bits) => {
- write!(f, "rex prefix: {}{}{}{}",
- if bits & 0x8 != 0 { "w" } else { "-" },
- if bits & 0x4 != 0 { "r" } else { "-" },
- if bits & 0x2 != 0 { "x" } else { "-" },
- if bits & 0x1 != 0 { "b" } else { "-" },
- )
- }
- InnerDescription::SegmentPrefix(segment) => {
- write!(f, "segment override: {}", segment)
- }
- InnerDescription::Misc(text) => {
- f.write_str(text)
- }
- InnerDescription::Number(text, num) => {
- write!(f, "{}: {:#x}", text, num)
- }
- InnerDescription::Opcode(opc) => {
- write!(f, "opcode `{}`", opc)
- }
- InnerDescription::OperandCode(OperandCodeWrapper { code }) => {
- write!(f, "operand code `{:?}`", code)
- }
- InnerDescription::RegisterNumber(name, num, reg) => {
- write!(f, "`{}` (`{}` selects register number {})", reg, name, num)
+cfg_if::cfg_if! {
+ if #[cfg(feature = "fmt")] {
+ impl fmt::Display for InnerDescription {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ InnerDescription::RexPrefix(bits) => {
+ write!(f, "rex prefix: {}{}{}{}",
+ if bits & 0x8 != 0 { "w" } else { "-" },
+ if bits & 0x4 != 0 { "r" } else { "-" },
+ if bits & 0x2 != 0 { "x" } else { "-" },
+ if bits & 0x1 != 0 { "b" } else { "-" },
+ )
+ }
+ InnerDescription::SegmentPrefix(segment) => {
+ write!(f, "segment override: {}", segment)
+ }
+ InnerDescription::Misc(text) => {
+ f.write_str(text)
+ }
+ InnerDescription::Number(text, num) => {
+ write!(f, "{}: {:#x}", text, num)
+ }
+ InnerDescription::Opcode(opc) => {
+ write!(f, "opcode `{}`", opc)
+ }
+ InnerDescription::OperandCode(OperandCodeWrapper { code }) => {
+ write!(f, "operand code `{:?}`", code)
+ }
+ InnerDescription::RegisterNumber(name, num, reg) => {
+ write!(f, "`{}` (`{}` selects register number {})", reg, name, num)
+ }
+ InnerDescription::Boundary(desc) => {
+ write!(f, "{}", desc)
+ }
+ }
}
- InnerDescription::Boundary(desc) => {
- write!(f, "{}", desc)
+ }
+ } else {
+ impl fmt::Display for InnerDescription {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("non-fmt build")
}
}
}