diff options
| -rw-r--r-- | Cargo.lock | 115 | ||||
| -rw-r--r-- | Cargo.toml | 9 | ||||
| -rw-r--r-- | src/main.rs | 777 | 
3 files changed, 467 insertions, 434 deletions
| @@ -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",  ] @@ -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  } | 
