aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs777
1 files changed, 412 insertions, 365 deletions
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
}