aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock115
-rw-r--r--Cargo.toml9
-rw-r--r--src/main.rs777
3 files changed, 467 insertions, 434 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 01258a3..bed9a70 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "ansi_term"
-version = "0.11.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
@@ -30,15 +30,15 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitvec"
-version = "0.19.5"
+version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
+checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33"
dependencies = [
"funty",
"radium",
@@ -48,9 +48,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "2.33.3"
+version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term",
"atty",
@@ -90,18 +90,18 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "itertools"
-version = "0.10.1"
+version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]]
name = "libc"
-version = "0.2.98"
+version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
+checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "num-traits"
@@ -134,9 +134,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.28"
+version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
+checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid 0.2.2",
]
@@ -152,11 +152,11 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.9"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
dependencies = [
- "proc-macro2 1.0.28",
+ "proc-macro2 1.0.36",
]
[[package]]
@@ -167,19 +167,19 @@ checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]]
name = "serde"
-version = "1.0.127"
+version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
+checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
[[package]]
name = "serde_derive"
-version = "1.0.127"
+version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc"
+checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
dependencies = [
- "proc-macro2 1.0.28",
- "quote 1.0.9",
- "syn 1.0.74",
+ "proc-macro2 1.0.36",
+ "quote 1.0.14",
+ "syn 1.0.84",
]
[[package]]
@@ -201,22 +201,16 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.74"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
+checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
dependencies = [
- "proc-macro2 1.0.28",
- "quote 1.0.9",
+ "proc-macro2 1.0.36",
+ "quote 1.0.14",
"unicode-xid 0.2.2",
]
[[package]]
-name = "take_mut"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
-
-[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -233,9 +227,9 @@ dependencies = [
[[package]]
name = "unicode-width"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
@@ -285,21 +279,11 @@ checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "yaxpeax-6502"
-version = "0.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53afe49cd799784eeefe7108efd48852ea83673d55d98389a563532f05c5ea3"
-dependencies = [
- "take_mut",
- "yaxpeax-arch 0.0.5",
-]
-
-[[package]]
-name = "yaxpeax-arch"
-version = "0.0.5"
+version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6d51fa58dc03a872cf25e864c5edeb57a00a0be1e99112fe9b620eed839f035"
+checksum = "7e89d220a799f57094ad0a58c16b2c3b7730e8f1404665bee5f10e039e7c17c3"
dependencies = [
- "num-traits",
+ "yaxpeax-arch",
]
[[package]]
@@ -318,7 +302,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dd4915314c4ff9cb079acd1ad25245f54b2e651238da929fb79971443ea7834"
dependencies = [
"bitvec",
- "yaxpeax-arch 0.2.7",
+ "serde",
+ "serde_derive",
+ "yaxpeax-arch",
]
[[package]]
@@ -327,7 +313,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94153e4e363dd4b0bea761ce9615647f2a29a9c3d46d3467c776969eb2b4e91c"
dependencies = [
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
[[package]]
@@ -339,8 +325,7 @@ dependencies = [
"itertools",
"num-traits",
"yaxpeax-6502",
- "yaxpeax-arch 0.0.5",
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
"yaxpeax-arm",
"yaxpeax-avr",
"yaxpeax-ia64",
@@ -357,9 +342,11 @@ dependencies = [
[[package]]
name = "yaxpeax-ia64"
version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3ea0f2b5728fb7eb1861532cd755ff7dd993843778d548df70a4aca95f9914e"
dependencies = [
"bitvec",
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
[[package]]
@@ -368,7 +355,7 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cf556f365c2fa2104e4e9a36105d9a2f72085dfd7168c95abf4f0d7cdac0cff"
dependencies = [
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
[[package]]
@@ -380,7 +367,7 @@ dependencies = [
"num-traits",
"serde",
"serde_derive",
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
[[package]]
@@ -390,14 +377,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d83d243a75ff9312b78ef761596cf0bf3b625786176363d65e653a75042873a"
dependencies = [
"num_enum",
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
[[package]]
name = "yaxpeax-msp430"
version = "0.1.1"
dependencies = [
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
[[package]]
@@ -406,7 +393,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15ca63b323712143e563e146af6a3df21fa3c75976985ee7b157470616c15c1e"
dependencies = [
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
[[package]]
@@ -415,16 +402,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64bb0d36fc65721e5919e9febe316ae62cf0ba2510cddb01d1f182ddcc97f84"
dependencies = [
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
[[package]]
name = "yaxpeax-superh"
-version = "0.1.1"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c04d16d2b60e7961ace2b8624c12295e86babb3b8a6615a4238bbb823ba0936e"
+checksum = "8c8cc1c381ba557a8d7e9fdb1399c36e4d9ce5a517b3e2bb504b261012403f4f"
dependencies = [
- "yaxpeax-arch 0.0.5",
+ "yaxpeax-arch",
]
[[package]]
@@ -434,5 +421,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "725dc639f981b8e4c222e96d64f577e2ccb46e908c807418d29b66578f6b34ba"
dependencies = [
"num-traits",
- "yaxpeax-arch 0.2.7",
+ "yaxpeax-arch",
]
diff --git a/Cargo.toml b/Cargo.toml
index 564ce9f..2cc050c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,9 +24,8 @@ itertools = "0.10.1"
# common interfaces for all yaxpeax decoders
yaxpeax-arch-02 = { package = "yaxpeax-arch", version = "0.2.4" , default-features = false, features = ["std"] }
-yaxpeax-arch-01 = { package = "yaxpeax-arch", version = "0.0.5" , default-features = false }
-yaxpeax-arm = { version = "0.2.3", default-features = false, features = ["std"] }
+yaxpeax-arm = { version = "0.2.3" }
yaxpeax-avr = { version = "0.1.0" }
yaxpeax-m16c = { version = "0.1.0" }
yaxpeax-mips = { version = "0.1.0" }
@@ -35,6 +34,6 @@ yaxpeax-lc87 = { version = "1.0.0" }
yaxpeax-pic17 = { version = "0.1.0" }
yaxpeax-pic18 = { version = "0.1.0" }
yaxpeax-x86 = { version = "1.1.3", default-features = false, features = ["fmt", "std"] }
-yaxpeax-ia64 = { version = "0.2.1", path = "/toy/yaxpeax/arch/ia64" }
-yaxpeax-superh = { version = "0.1.0" }
-yaxpeax-6502 = { version = "0.0.1" }
+yaxpeax-ia64 = { version = "0.2.1" }
+yaxpeax-superh = { version = "0.3.0" }
+yaxpeax-6502 = { version = "0.0.2", features = ["std"] }
diff --git a/src/main.rs b/src/main.rs
index 3e9b887..19660b3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,10 +1,10 @@
-use clap::*;
-
use std::fs::File;
-use std::io::Read;
+use std::io::{Read, Write};
+use std::{fmt, io};
use std::collections::BTreeSet;
fn main() {
+ use clap::*;
let _ = include_str!("../Cargo.toml");
let app = app_from_crate!()
.arg(
@@ -15,7 +15,7 @@ fn main() {
.validator(|a| {
if ["x86_64", "x86_32", "x86_16",
"x86:64", "x86:32", "x86:16",
- "ia64", "armv7", "armv7-t", "armv8", "avr", "mips", "msp430",
+ "ia64", "armv7", "armv7-t","armv8", "avr", "mips", "msp430",
"pic17", "pic18", "m16c", "6502", "lc87"].contains(&&a[..]) ||
(["sh", "sh2", "sh3", "sh4", "j2"].contains(
&&a[0..a.find(|c| c == '+' || c == '-').unwrap_or(a.len())]) &&
@@ -81,32 +81,32 @@ fn main() {
};
let verbose = matches.occurrences_of("verbose") > 0;
+ let printer = Printer { stdout: io::stdout(), verbose };
+
match arch_str {
"x86_64" |
- "x86:64" => crate::current_arch::decode_input_with_annotation::<yaxpeax_x86::long_mode::Arch>(&buf, verbose),
+ "x86:64" => arch_02::decode_input_and_annotate::<yaxpeax_x86::long_mode::Arch>(&buf, &printer),
"x86_32" |
- "x86:32" => crate::current_arch::decode_input_with_annotation::<yaxpeax_x86::protected_mode::Arch>(&buf, verbose),
+ "x86:32" => arch_02::decode_input_and_annotate::<yaxpeax_x86::protected_mode::Arch>(&buf, &printer),
"x86_16" |
- "x86:16" => crate::current_arch::decode_input_with_annotation::<yaxpeax_x86::real_mode::Arch>(&buf, verbose),
- // "ia64" => crate::current_arch::decode_input_with_annotation::<yaxpeax_ia64::IA64>(&buf, verbose),
- "ia64" => crate::current_arch::decode_input::<yaxpeax_ia64::IA64>(&buf, verbose),
- "avr" => crate::current_arch::decode_input::<yaxpeax_avr::AVR>(&buf, verbose),
- "armv7" => crate::current_arch::decode_input::<yaxpeax_arm::armv7::ARMv7>(&buf, verbose),
- "armv7-t" => crate::current_arch::decode_armv7_thumb(&buf, verbose),
- "armv8" => crate::current_arch::decode_input::<yaxpeax_arm::armv8::a64::ARMv8>(&buf, verbose),
- "mips" => crate::current_arch::decode_input::<yaxpeax_mips::MIPS>(&buf, verbose),
- // "msp430" => crate::current_arch::decode_input_with_annotation::<yaxpeax_msp430::MSP430>(&buf, verbose),
- "msp430" => crate::current_arch::decode_input::<yaxpeax_msp430::MSP430>(&buf, verbose),
- "pic17" => crate::current_arch::decode_input::<yaxpeax_pic17::PIC17>(&buf, verbose),
- "pic18" => crate::current_arch::decode_input::<yaxpeax_pic18::PIC18>(&buf, verbose),
- "m16c" => crate::current_arch::decode_input::<yaxpeax_m16c::M16C>(&buf, verbose),
- "6502" => crate::legacy_arch::decode_input::<yaxpeax_6502::N6502>(&buf, verbose),
- "lc87" => crate::current_arch::decode_input::<yaxpeax_lc87::LC87>(&buf, verbose),
+ "x86:16" => arch_02::decode_input_and_annotate::<yaxpeax_x86::real_mode::Arch>(&buf, &printer),
+ "ia64" => arch_02::decode_input::<yaxpeax_ia64::IA64>(&buf, &printer),
+ "avr" => arch_02::decode_input::<yaxpeax_avr::AVR>(&buf, &printer),
+ "armv7" => arch_02::decode_input::<yaxpeax_arm::armv7::ARMv7>(&buf, &printer),
+ "armv7-t" => arch_02::decode_armv7_thumb(&buf, &printer),
+ "armv8" => arch_02::decode_input::<yaxpeax_arm::armv8::a64::ARMv8>(&buf, &printer),
+ "mips" => arch_02::decode_input::<yaxpeax_mips::MIPS>(&buf, &printer),
+ "msp430" => arch_02::decode_input_and_annotate::<yaxpeax_msp430::MSP430>(&buf, &printer),
+ "pic17" => arch_02::decode_input::<yaxpeax_pic17::PIC17>(&buf, &printer),
+ "pic18" => arch_02::decode_input::<yaxpeax_pic18::PIC18>(&buf, &printer),
+ "m16c" => arch_02::decode_input::<yaxpeax_m16c::M16C>(&buf, &printer),
+ "6502" => arch_02::decode_input::<yaxpeax_6502::N6502>(&buf, &printer),
+ "lc87" => arch_02::decode_input::<yaxpeax_lc87::LC87>(&buf, &printer),
// "pic24" => decode_input::<yaxpeax_pic24::PIC24>(buf),
other => {
let seg_idx = arch_str.find(|c| c == '+' || c == '-').unwrap_or(arch_str.len());
let wps = |base| with_parsed_superh(base, &arch_str[seg_idx..],
- |decoder| crate::legacy_arch::decode_input_with_decoder::<yaxpeax_superh::SuperH>(decoder, &buf, verbose));
+ |decoder| arch_02::decode_input_with_decoder::<yaxpeax_superh::SuperH>(decoder, &buf, &printer));
match &arch_str[0..seg_idx] {
"sh" => wps(yaxpeax_superh::SuperHDecoder::SH1),
"sh2" => wps(yaxpeax_superh::SuperHDecoder::SH2),
@@ -156,419 +156,466 @@ fn with_parsed_superh<F: FnOnce(yaxpeax_superh::SuperHDecoder)>(
})
}
-// yaxpeax-arch, implemented by all decoders here, is required at incompatible versions by
-// different decoders. implement the actual decode-and-print behavior on both versions of
-// yaxpeax-arch while older decoders are still being updated.
-mod current_arch {
- use yaxpeax_arch_02::{AddressBase, Arch, Decoder, Instruction, LengthedInstruction, Reader, U8Reader};
- use yaxpeax_arch_02::annotation::{AnnotatingDecoder, FieldDescription, VecSink};
- use std::fmt;
- use num_traits::identities::Zero;
-
- fn col2bit(col: usize) -> usize {
- // ia64
- // 127 - col
- // msp430
- /*
- let word = col >> 4;
- let bit = 15 - (col & 0xf);
-
- (word << 4) | bit
- */
- // x86
- let byte = col / 8;
- let bit = (7 - (col % 8));
- let bit = byte * 8 + bit;
- bit
- }
- fn bit2col(bit: usize) -> usize {
- let byte = bit / 8;
- let bit = (7 - (bit % 8));
- let bit = byte * 8 + bit;
- bit
- }
+struct Printer {
+ stdout: io::Stdout,
+ verbose: bool,
+}
- #[derive(Debug)]
- struct BitRange {
- start: u32,
- end: u32,
- lhs: u32,
- rhs: u32,
- }
+impl Printer {
+ // shared generic function to keep display logic consistent regardless of yaxpeax-arch version
+ fn print_instr<I, E>(&self, rest: &[u8], addr: usize, inst_res: Result<InstDetails<I>, E>)
+ where
+ I: fmt::Display + fmt::Debug,
+ E: fmt::Display,
+ {
+ // TODO: lock stdout for the whole time? What if an arch implementation tries to log something?
+ let mut stdout = self.stdout.lock();
+ write!(stdout, "{:#010x}: ", addr).unwrap();
+ match inst_res {
+ Ok(InstDetails { inst_len, well_defined, inst, field_descriptions }) => {
+ writeln!(stdout, "{:14}: {}", hex::encode(&rest[..inst_len]), inst)
+ .unwrap();
+ if self.verbose {
+ if !well_defined {
+ writeln!(stdout, " not well-defined").unwrap();
+ }
- impl BitRange {
- fn across(start: u32, end: u32) -> BitRange {
- let mut lhs = bit2col(start as usize) as u32;
- let mut rhs = bit2col(start as usize) as u32;
- for bit in start..=end {
- lhs = std::cmp::min(lhs, bit2col(bit as usize) as u32);
- rhs = std::cmp::max(rhs, bit2col(bit as usize) as u32);
+ // if we can show detailed information about the instruction's interpretation,
+ // do that. otherwise, debug impl of the instruction and hope for the best.
+ if let Some((mapper, fields)) = field_descriptions {
+ let bits_layout = fmt_field_descriptions(
+ &mapper,
+ &fields,
+ &rest[..inst_len]
+ );
+ write!(stdout, "{}", bits_layout).unwrap();
+ } else {
+ writeln!(stdout, " {:?}", inst).unwrap();
+ }
+ }
+ }
+ Err(e) => {
+ writeln!(stdout, "{}", e).unwrap();
}
- BitRange { start, end, lhs, rhs }
}
}
+}
- struct ItemDescription<A: Arch> where A::Decoder: AnnotatingDecoder<A> {
- ranges: Vec<BitRange>,
- description: <<A as Arch>::Decoder as AnnotatingDecoder<A>>::FieldDescription,
+struct InstDetails<I: fmt::Debug + fmt::Display> {
+ inst_len: usize,
+ well_defined: bool,
+ inst: I,
+ field_descriptions: Option<(BitPosition, Vec<FieldRecord>)>,
+}
+
+// yaxpeax-arch, implemented by all decoders here, may be required at incompatible versions by
+// different decoders if/when a new version releases. implement the actual decode-and-print
+// behavior independent of yaxpeax-arch so decoders using different version can exist in parallel.
+mod arch_02 {
+ use super::Printer;
+ use num_traits::identities::Zero;
+ use std::fmt;
+ use yaxpeax_arch_02::{
+ AddressBase, Arch, Decoder, Instruction, LengthedInstruction, Reader, U8Reader,
+ };
+ use yaxpeax_arch_02::annotation::{AnnotatingDecoder, FieldDescription, VecSink};
+
+ use crate::{FieldRecord, ItemDescription};
+
+
+ pub(crate) fn decode_input<A: Arch>(buf: &[u8], printer: &Printer)
+ where
+ A::Instruction: fmt::Display,
+ for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
+ {
+ decode_input_with_decoder::<A>(A::Decoder::default(), buf, printer);
}
- impl<A: Arch> fmt::Debug for ItemDescription<A> where A::Decoder: AnnotatingDecoder<A> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{{ ranges: {:?}, description: {} }}", &self.ranges, &self.description)
- }
+ pub(crate) fn decode_input_and_annotate<A: Arch + crate::ArchBitMapper>(buf: &[u8], printer: &Printer)
+ where
+ A::Instruction: fmt::Display,
+ A::Decoder: AnnotatingDecoder<A>,
+ for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
+ {
+ decode_input_with_annotation::<A>(A::Decoder::default(), buf, printer);
}
- // spans grouped together in some decoder-specified logical structure by
- // `id`. `id` is a hint that data should be considered related for display
- // purposes.
- struct FieldRecord<A: Arch> where A::Decoder: AnnotatingDecoder<A> {
- // spans grouped together by `FieldDescription` - one field may be
- // described by multiple distinct spans, so those spans are recorded
- // here. elements are ordered by the lowest bit of spans describing an
- // element.
- elements: Vec<ItemDescription<A>>,
- id: u32,
+ pub(crate) fn decode_armv7_thumb(buf: &[u8], printer: &Printer) {
+ let decoder = yaxpeax_arm::armv7::InstDecoder::default_thumb();
+ decode_input_with_decoder::<yaxpeax_arm::armv7::ARMv7>(decoder, buf, printer);
}
- impl<A: Arch> fmt::Debug for FieldRecord<A> where A::Decoder: AnnotatingDecoder<A> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{{ elements: {:?}, id: {} }}", &self.elements, &self.id)
+ pub(crate) fn decode_input_with_decoder<A: Arch>(
+ decoder: A::Decoder,
+ buf: &[u8],
+ printer: &Printer,
+ ) where
+ A::Instruction: fmt::Display,
+ for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
+ {
+ let mut addr = A::Address::zero();
+ while let Some(rest) = buf.get(addr.to_linear()..).filter(|v| !v.is_empty()) {
+ let mut reader = U8Reader::new(rest);
+ let res = decoder.decode(&mut reader);
+ let advance_addr = match &res {
+ Ok(inst) => inst.len(),
+ Err(_) => A::Instruction::min_size(),
+ };
+ let generic_res = res.map(|inst| {
+ crate::InstDetails {
+ inst_len: A::Address::zero().wrapping_offset(inst.len()).to_linear(),
+ well_defined: inst.well_defined(),
+ inst,
+ field_descriptions: None,
+ }
+ });
+ printer.print_instr(rest, addr.to_linear(), generic_res);
+ addr += advance_addr;
}
}
- fn show_field_descriptions<A: Arch>(fields: &[FieldRecord<A>], data: &[u8]) where A::Decoder: AnnotatingDecoder<A> {
- let mut boundaries = [false; 256];
- let mut separators = [false; 256];
- let mut bits = [false; 256];
- let mut rhs = [false; 256];
- let mut lhs = [false; 256];
- let mut field_order: Vec<(usize, usize)> = Vec::new();
- let mut boundary_order: Vec<(usize, usize)> = Vec::new();
-
- for (fi, field) in fields.iter().enumerate() {
- for (ei, element) in field.elements.iter().enumerate() {
- if element.description.is_separator() {
- for (_ri, range) in element.ranges.iter().enumerate() {
- boundaries[range.start as usize + 1] = true;
- boundary_order.push((fi, range.start as usize + 1));
- }
- continue;
- }
- field_order.push((fi, ei));
- for (_ri, range) in element.ranges.iter().enumerate() {
- for i in range.start..=range.end {
- bits[i as usize] = true;
- }
- separators[range.start as usize] = true;
- lhs[range.lhs as usize] = true;
- rhs[range.rhs as usize] = true;
+ fn field_descs_to_record<A: Arch + crate::ArchBitMapper>(sink: VecSink<<A::Decoder as AnnotatingDecoder<A>>::FieldDescription>) -> Vec<FieldRecord> where A::Decoder: AnnotatingDecoder<A> {
+ let mut fields: Vec<FieldRecord> = Vec::new();
+ let bit_mapper = A::mapper();
+
+ use itertools::Itertools;
+ let mut vs = sink.records;
+ vs.sort_by_key(|rec| rec.2.id());
+ for (id, group) in &vs.iter().group_by(|x| x.2.id()) {
+ let mut field = FieldRecord {
+ elements: Vec::new(),
+ id: id,
+ };
+
+ for (desc, spans) in &group.group_by(|x| x.2.to_owned()) {
+ let mut item = ItemDescription {
+ ranges: Vec::new(),
+ description: desc.to_string(),
+ separator: desc.is_separator(),
+ };
+
+ for span in spans {
+ item.ranges.push(crate::BitRange::across(bit_mapper, span.0, span.1));
}
+ field.elements.push(item);
}
+ fields.push(field);
+ }
+
+ fields
+ }
+
+ pub(crate) fn decode_input_with_annotation<A: Arch + crate::ArchBitMapper>(
+ decoder: A::Decoder,
+ buf: &[u8],
+ printer: &Printer,
+ ) where
+ A::Instruction: fmt::Display,
+ A::Decoder: AnnotatingDecoder<A>,
+ for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
+ {
+ let mut addr = A::Address::zero();
+ while let Some(rest) = buf.get(addr.to_linear()..).filter(|v| !v.is_empty()) {
+ let mut sink: VecSink<<A::Decoder as AnnotatingDecoder<A>>::FieldDescription> = VecSink::new();
+ let mut reader = U8Reader::new(rest);
+ let mut inst = A::Instruction::default();
+ let res = decoder.decode_with_annotation(&mut inst, &mut reader, &mut sink);
+ let advance_addr = match &res {
+ Ok(_) => inst.len(),
+ Err(_) => A::Instruction::min_size(),
+ };
+ let generic_res = res.map(|_| {
+ let records = field_descs_to_record::<A>(sink);
+ crate::InstDetails {
+ inst_len: A::Address::zero().wrapping_offset(inst.len()).to_linear(),
+ well_defined: inst.well_defined(),
+ inst,
+ field_descriptions: Some((A::mapper(), records)),
+ }
+ });
+ printer.print_instr(rest, addr.to_linear(), generic_res);
+ addr += advance_addr;
}
- boundary_order.sort_by(|l, r| r.1.cmp(&l.1));
+ }
+}
- // regardless of sections, the left-hand side of the terminal is a free boundary
- lhs[0] = false;
+/// any architecture with an `AnnotatingDecoder` implementation will have annotations reported at
+/// positions of bits in the instruction. `yaxpeax-dis` requires some description of how to convert
+/// between a column and a bit for a given architecture.
+#[derive(Copy, Clone, Debug)]
+struct BitPosition {
+ word_size: usize,
+}
- let mut res = String::new();
- res.push_str(" \n");
+impl BitPosition {
+ fn col2bit(&self, col: usize) -> usize {
+ let word = col / self.word_size;
+ let bit = (self.word_size - 1) - (col % self.word_size);
+ let bit = word * self.word_size + bit;
+ bit
+ }
- let mut fudge_bits = [false; 160];
+ fn bit2col(&self, bit: usize) -> usize {
+ let word = bit / self.word_size;
+ let col = (self.word_size - 1) - (bit % self.word_size);
+ let col = word * self.word_size + col;
+ col
+ }
+}
- for i in 0..160 {
- if (i >> 3) >= data.len() {
- continue;
- }
+const IA64_POSITIONS: BitPosition = BitPosition {
+ word_size: 128
+};
- let mut fudge = false;
+const WORD_POSITIONS: BitPosition = BitPosition {
+ word_size: 16
+};
- if lhs[i] {
- fudge = true;
- }
+const BYTE_POSITIONS: BitPosition = BitPosition {
+ word_size: 8
+};
- if i > 0 && rhs[i - 1] {
- fudge = true;
- }
+trait ArchBitMapper {
+ fn mapper() -> BitPosition;
+}
- if fudge {
- fudge_bits[i] = true;
- }
- }
+impl ArchBitMapper for yaxpeax_x86::real_mode::Arch {
+ fn mapper() -> BitPosition {
+ BYTE_POSITIONS
+ }
+}
- let mut fudge = 0;
- let mut col = [b' '; 160];
+impl ArchBitMapper for yaxpeax_x86::protected_mode::Arch {
+ fn mapper() -> BitPosition {
+ BYTE_POSITIONS
+ }
+}
- for i in 0..160 {
- if (i >> 3) >= data.len() {
- continue;
- }
+impl ArchBitMapper for yaxpeax_x86::long_mode::Arch {
+ fn mapper() -> BitPosition {
+ BYTE_POSITIONS
+ }
+}
- let bit = col2bit(i);
+impl ArchBitMapper for yaxpeax_msp430::MSP430 {
+ fn mapper() -> BitPosition {
+ WORD_POSITIONS
+ }
+}
- if fudge_bits[i] {
- fudge += 1;
- }
+impl ArchBitMapper for yaxpeax_ia64::IA64 {
+ fn mapper() -> BitPosition {
+ IA64_POSITIONS
+ }
+}
- if data[(bit >> 3) as usize] & (1 << (bit as u8 & 7)) != 0 {
- col[i + fudge] = b'1';
- } else {
- col[i + fudge] = b'0';
- }
+#[derive(Debug)]
+struct BitRange {
+ start: u32,
+ end: u32,
+ lhs: u32,
+ rhs: u32,
+}
+
+impl BitRange {
+ fn across(bit_mapper: BitPosition, start: u32, end: u32) -> BitRange {
+ let mut lhs = bit_mapper.bit2col(start as usize) as u32;
+ let mut rhs = bit_mapper.bit2col(start as usize) as u32;
+ for bit in start..=end {
+ lhs = std::cmp::min(lhs, bit_mapper.bit2col(bit as usize) as u32);
+ rhs = std::cmp::max(rhs, bit_mapper.bit2col(bit as usize) as u32);
}
- res.push_str(unsafe { std::str::from_utf8_unchecked(&col) });
- res.push_str("\n");
+ BitRange { start, end, lhs, rhs }
+ }
+}
- for (fi, ei) in field_order.iter() {
- let mut col = [b' '; 160];
+/// a representation of a decoder's `Annotation` type that does not actually reference
+/// `yaxpeax_arch`. this is important so we can have a whole shared display routine reused across
+/// `yaxpeax_arch` versions - there may be more than one in use at a time in `yaxpeax-dis`.
+struct ItemDescription {
+ ranges: Vec<BitRange>,
+ description: String,
+ separator: bool,
+}
- for range in &fields[*fi as usize].elements[*ei as usize].ranges {
- let mut fudge = 0;
+impl fmt::Debug for ItemDescription {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{{ ranges: {:?}, description: {}, separator: {} }}", &self.ranges, &self.description, self.separator)
+ }
+}
- for c in 0..128 {
- let bit = col2bit(c as usize);
+// spans grouped together in some decoder-specified logical structure by
+// `id`. `id` is a hint that data should be considered related for display
+// purposes.
+struct FieldRecord {
+ // spans grouped together by `FieldDescription` - one field may be
+ // described by multiple distinct spans, so those spans are recorded
+ // here. elements are ordered by the lowest bit of spans describing an
+ // element.
+ elements: Vec<ItemDescription>,
+ id: u32,
+}
- if boundaries[c] {
- col[c + fudge] = b'|';
- }
- if fudge_bits[c as usize] {
- fudge += 1;
- }
+impl fmt::Debug for FieldRecord {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{{ elements: {:?}, id: {} }}", &self.elements, &self.id)
+ }
+}
- if bit >= range.start as usize && bit <= range.end as usize {
- let data_bit = data[(bit >> 3) as usize] & (1 << (bit as u8 & 7)) != 0;
- col[c as usize + fudge] = if data_bit { b'1' } else { b'0' };
- }
+fn fmt_field_descriptions(bit_mapper: &BitPosition, fields: &[FieldRecord], data: &[u8]) -> String {
+ let mut boundaries = [false; 256];
+ let mut separators = [false; 256];
+ let mut bits = [false; 256];
+ let mut rhs = [false; 256];
+ let mut lhs = [false; 256];
+ let mut field_order: Vec<(usize, usize)> = Vec::new();
+ let mut boundary_order: Vec<(usize, usize)> = Vec::new();
+
+ for (fi, field) in fields.iter().enumerate() {
+ for (ei, element) in field.elements.iter().enumerate() {
+ if element.separator {
+ for (_ri, range) in element.ranges.iter().enumerate() {
+ boundaries[range.start as usize + 1] = true;
+ boundary_order.push((fi, range.start as usize + 1));
+ }
+ continue;
+ }
+ field_order.push((fi, ei));
+ for (_ri, range) in element.ranges.iter().enumerate() {
+ for i in range.start..=range.end {
+ bits[i as usize] = true;
}
+ separators[range.start as usize] = true;
+ lhs[range.lhs as usize] = true;
+ rhs[range.rhs as usize] = true;
}
+ }
+ }
+ boundary_order.sort_by(|l, r| r.1.cmp(&l.1));
+
+ // regardless of sections, the left-hand side of the terminal is a free boundary
+ lhs[0] = false;
- res.push_str(unsafe { std::str::from_utf8_unchecked(&col[..(data.len() * 8 + 30)]) });
- res.push_str(" ");
- res.push_str(&fields[*fi as usize].elements[*ei as usize].description.to_string());
- res.push_str("\n");
+ let mut res = String::new();
+ res.push_str(" \n");
+
+ let mut fudge_bits = [false; 160];
+
+ for i in 0..160 {
+ if (i >> 3) >= data.len() {
+ continue;
}
- let mut fudge = 0;
- let mut col = [b' '; 160];
+ let mut fudge = false;
- let mut line_end = 0;
- for i in 0..160 {
- if (i >> 3) > data.len() {
- continue;
- }
+ if lhs[i] {
+ fudge = true;
+ }
- if boundaries[i] {
- col[i + fudge] = b'|';
- line_end = i + fudge + 1;
- }
- if fudge_bits[i] {
- fudge += 1;
- }
+ if i > 0 && rhs[i - 1] {
+ fudge = true;
}
- res.push_str(unsafe { std::str::from_utf8_unchecked(&col[..line_end]) });
- res.push_str("\n");
- for (field_index, bit) in boundary_order {
- let mut fudge = 0;
- let mut col = [b' '; 160];
+ if fudge {
+ fudge_bits[i] = true;
+ }
+ }
- for i in 0..160 {
- if (i >> 3) > data.len() {
- continue;
- }
+ let mut fudge = 0;
+ let mut col = [b' '; 160];
- if i == bit {
- res.push_str(unsafe { std::str::from_utf8_unchecked(&col[..i + fudge]) });
- break;
- }
+ for i in 0..160 {
+ if (i >> 3) >= data.len() {
+ continue;
+ }
- if boundaries[i] {
- col[i + fudge] = b'|';
- }
- if fudge_bits[i] {
- fudge += 1;
- }
- }
- use std::fmt::Write;
- let _ = write!(res, "{:?}", fields[field_index].elements[0]);
- res.push_str("\n");
+ let bit = bit_mapper.col2bit(i);
+
+ if fudge_bits[i] {
+ fudge += 1;
}
- println!("{}", res);
+ if data[(bit >> 3) as usize] & (1 << (bit as u8 & 7)) != 0 {
+ col[i + fudge] = b'1';
+ } else {
+ col[i + fudge] = b'0';
+ }
}
+ res.push_str(unsafe { std::str::from_utf8_unchecked(&col) });
+ res.push_str("\n");
- pub(crate) fn decode_armv7_thumb(buf: &[u8], verbose: bool) {
- let mut decoder = <yaxpeax_arm::armv7::ARMv7 as Arch>::Decoder::default();
- decoder.set_thumb_mode(true);
- decode_input_with_decoder::<yaxpeax_arm::armv7::ARMv7>(decoder, buf, verbose);
- }
+ for (fi, ei) in field_order.iter() {
+ let mut col = [b' '; 160];
- pub(crate) fn decode_input<A: Arch>(buf: &[u8], verbose: bool)
- where
- A::Instruction: fmt::Display, for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
- {
- decode_input_with_decoder::<A>(A::Decoder::default(), buf, verbose);
- }
+ for range in &fields[*fi as usize].elements[*ei as usize].ranges {
+ let mut fudge = 0;
- pub(crate) fn decode_input_with_annotation<A: Arch>(buf: &[u8], verbose: bool)
- where
- A::Instruction: fmt::Display, for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
- A::Decoder: AnnotatingDecoder<A>,
- {
- decode_input_with_decoder_and_annotation::<A>(A::Decoder::default(), buf, verbose);
- }
+ for c in 0..128 {
+ let bit = bit_mapper.col2bit(c as usize);
- pub(crate) fn decode_input_with_decoder<A: Arch>(decoder: A::Decoder, buf: &[u8], verbose: bool)
- where
- A::Instruction: fmt::Display, for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
- {
- let start = A::Address::zero();
- let mut addr = start;
- loop {
- let mut reader = U8Reader::new(&buf[addr.to_linear()..]);
- match decoder.decode(&mut reader) {
- Ok(inst) => {
- println!(
- "{:#010x}: {:14}: {}",
- addr.to_linear(),
- hex::encode(
- &buf[addr.to_linear()..]
- [..A::Address::zero().wrapping_offset(inst.len()).to_linear()]
- ),
- inst
- );
- if verbose {
- println!(" {:?}", inst);
- if !inst.well_defined() {
- println!(" not well-defined");
- }
- }
- addr += inst.len();
+ if boundaries[c] {
+ col[c + fudge] = b'|';
}
- Err(e) => {
- println!("{:#010x}: {}", addr.to_linear(), e);
- addr += A::Instruction::min_size();
+ if fudge_bits[c as usize] {
+ fudge += 1;
}
- }
- if addr.to_linear() >= buf.len() {
- break;
- }
- }
- }
- pub(crate) fn decode_input_with_decoder_and_annotation<A: Arch>(decoder: A::Decoder, buf: &[u8], verbose: bool)
- where
- A::Instruction: fmt::Display, for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
- A::Decoder: AnnotatingDecoder<A>,
- {
- let start = A::Address::zero();
- let mut addr = start;
- loop {
- let mut sink: VecSink<<A::Decoder as AnnotatingDecoder<A>>::FieldDescription> = VecSink::new();
- let mut reader = U8Reader::new(&buf[addr.to_linear()..]);
- let mut inst = A::Instruction::default();
- match decoder.decode_with_annotation(&mut inst, &mut reader, &mut sink) {
- Ok(()) => {
- println!(
- "{:#010x}: {:14}: {}",
- addr.to_linear(),
- hex::encode(
- &buf[addr.to_linear()..]
- [..A::Address::zero().wrapping_offset(inst.len()).to_linear()]
- ),
- inst
- );
- if verbose {
- let mut fields: Vec<FieldRecord<A>> = Vec::new();
-
- use itertools::Itertools;
- let mut vs = sink.records;
- vs.sort_by_key(|rec| rec.2.id());
- for (id, group) in &vs.iter().group_by(|x| x.2.id()) {
- let mut field = FieldRecord {
- elements: Vec::new(),
- id: id,
- };
-
- for (desc, spans) in &group.group_by(|x| x.2.to_owned()) {
- let mut item = ItemDescription {
- ranges: Vec::new(),
- description: desc,
- };
-
- for span in spans {
- item.ranges.push(BitRange::across(span.0, span.1));
- }
- field.elements.push(item);
- }
- fields.push(field);
- }
- show_field_descriptions(
- &fields,
- &buf[addr.to_linear()..]
- [..A::Address::zero().wrapping_offset(inst.len()).to_linear()]
- );
- }
- addr += inst.len();
- }
- Err(e) => {
- println!("{:#010x}: {}", addr.to_linear(), e);
- addr += A::Instruction::min_size();
+ if bit >= range.start as usize && bit <= range.end as usize {
+ let data_bit = data[(bit >> 3) as usize] & (1 << (bit as u8 & 7)) != 0;
+ col[c as usize + fudge] = if data_bit { b'1' } else { b'0' };
}
}
- if addr.to_linear() >= buf.len() {
- break;
- }
}
+
+ res.push_str(unsafe { std::str::from_utf8_unchecked(&col[..(data.len() * 8 + 30)]) });
+ res.push_str(" ");
+ res.push_str(&fields[*fi as usize].elements[*ei as usize].description);
+ res.push_str("\n");
}
-}
-mod legacy_arch {
- use yaxpeax_arch_01::{AddressBase, Arch, Decoder, Instruction, LengthedInstruction};
- use std::fmt;
- use num_traits::identities::Zero;
+ let mut fudge = 0;
+ let mut col = [b' '; 160];
- pub(crate) fn decode_input<A: Arch>(buf: &[u8], verbose: bool)
- where
- A::Instruction: fmt::Display,
- {
- decode_input_with_decoder::<A>(A::Decoder::default(), buf, verbose);
+ let mut line_end = 0;
+ for i in 0..160 {
+ if (i >> 3) > data.len() {
+ continue;
+ }
+
+ if boundaries[i] {
+ col[i + fudge] = b'|';
+ line_end = i + fudge + 1;
+ }
+ if fudge_bits[i] {
+ fudge += 1;
+ }
}
+ res.push_str(unsafe { std::str::from_utf8_unchecked(&col[..line_end]) });
+ res.push_str("\n");
- pub(crate) fn decode_input_with_decoder<A: Arch>(decoder: A::Decoder, buf: &[u8], verbose: bool)
- where
- A::Instruction: fmt::Display,
- {
- let start = A::Address::zero();
- let mut addr = start;
- loop {
- match decoder.decode(buf[addr.to_linear()..].iter().cloned()) {
- Ok(inst) => {
- println!(
- "{:#010x}: {:14}: {}",
- addr.to_linear(),
- hex::encode(
- &buf[addr.to_linear()..]
- [..A::Address::zero().wrapping_offset(inst.len()).to_linear()]
- ),
- inst
- );
- if verbose {
- println!(" {:?}", inst);
- if !inst.well_defined() {
- println!(" not well-defined");
- }
- }
- addr += inst.len();
- }
- Err(e) => {
- println!("{:#010x}: {}", addr.to_linear(), e);
- addr += A::Instruction::min_size();
- }
+ for (field_index, bit) in boundary_order {
+ let mut fudge = 0;
+ let mut col = [b' '; 160];
+
+ for i in 0..160 {
+ if (i >> 3) > data.len() {
+ continue;
}
- if addr.to_linear() >= buf.len() {
+
+ if i == bit {
+ res.push_str(unsafe { std::str::from_utf8_unchecked(&col[..i + fudge]) });
break;
}
+
+ if boundaries[i] {
+ col[i + fudge] = b'|';
+ }
+ if fudge_bits[i] {
+ fudge += 1;
+ }
}
+ res.push_str("\n");
}
+
+ res
}