diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 777 |
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 } |