From 7f1d77d0c32c6570b426f52cb71acad1fc7c581a Mon Sep 17 00:00:00 2001 From: Noa <33094578+coolreader18@users.noreply.github.com> Date: Tue, 14 Dec 2021 12:59:49 -0800 Subject: Deduplicate display logic --- src/main.rs | 179 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 94 insertions(+), 85 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0c6a5fc..fe531dd 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( @@ -81,29 +81,31 @@ 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::(&buf, verbose), + "x86:64" => crate::current_arch::decode_input::(&buf, &printer), "x86_32" | - "x86:32" => crate::current_arch::decode_input::(&buf, verbose), + "x86:32" => crate::current_arch::decode_input::(&buf, &printer), "x86_16" | - "x86:16" => crate::current_arch::decode_input::(&buf, verbose), - "ia64" => crate::current_arch::decode_input::(&buf, verbose), - "avr" => crate::current_arch::decode_input::(&buf, verbose), - "armv7" => crate::current_arch::decode_input::(&buf, verbose), - "armv8" => crate::current_arch::decode_input::(&buf, verbose), - "mips" => crate::current_arch::decode_input::(&buf, verbose), - "msp430" => crate::current_arch::decode_input::(&buf, verbose), - "pic17" => crate::current_arch::decode_input::(&buf, verbose), - "pic18" => crate::current_arch::decode_input::(&buf, verbose), - "m16c" => crate::current_arch::decode_input::(&buf, verbose), - "6502" => crate::legacy_arch::decode_input::(&buf, verbose), - "lc87" => crate::current_arch::decode_input::(&buf, verbose), + "x86:16" => crate::current_arch::decode_input::(&buf, &printer), + "ia64" => crate::current_arch::decode_input::(&buf, &printer), + "avr" => crate::current_arch::decode_input::(&buf, &printer), + "armv7" => crate::current_arch::decode_input::(&buf, &printer), + "armv8" => crate::current_arch::decode_input::(&buf, &printer), + "mips" => crate::current_arch::decode_input::(&buf, &printer), + "msp430" => crate::current_arch::decode_input::(&buf, &printer), + "pic17" => crate::current_arch::decode_input::(&buf, &printer), + "pic18" => crate::current_arch::decode_input::(&buf, &printer), + "m16c" => crate::current_arch::decode_input::(&buf, &printer), + "6502" => crate::legacy_arch::decode_input::(&buf, &printer), + "lc87" => crate::current_arch::decode_input::(&buf, &printer), // "pic24" => decode_input::(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::(decoder, &buf, verbose)); + |decoder| crate::legacy_arch::decode_input_with_decoder::(decoder, &buf, &printer)); match &arch_str[0..seg_idx] { "sh" => wps(yaxpeax_superh::SuperHDecoder::SH1), "sh2" => wps(yaxpeax_superh::SuperHDecoder::SH2), @@ -153,6 +155,39 @@ fn with_parsed_superh( }) } +struct Printer { + stdout: io::Stdout, + verbose: bool, +} + +impl Printer { + // shared generic function to keep display logic consistent regardless of yaxpeax-arch version + fn print_instr(&self, rest: &[u8], addr: usize, x: Result<(usize, bool, 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 x { + Ok((inst_len, well_defined, inst)) => { + writeln!(stdout, "{:14}: {}", hex::encode(&rest[..inst_len]), inst) + .unwrap(); + if self.verbose { + writeln!(stdout, " {:?}", inst).unwrap(); + if !well_defined { + writeln!(stdout, " not well-defined").unwrap(); + } + } + } + Err(e) => { + writeln!(stdout, "{}", e).unwrap(); + } + } + } +} + // 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. @@ -160,49 +195,36 @@ mod current_arch { use yaxpeax_arch_02::{AddressBase, Arch, Decoder, Instruction, LengthedInstruction, Reader, U8Reader}; use std::fmt; use num_traits::identities::Zero; + use super::Printer; - pub(crate) fn decode_input(buf: &[u8], verbose: bool) + pub(crate) fn decode_input(buf: &[u8], printer: &Printer) where A::Instruction: fmt::Display, for<'data> U8Reader<'data>: Reader, { - decode_input_with_decoder::(A::Decoder::default(), buf, verbose); + decode_input_with_decoder::(A::Decoder::default(), buf, printer); } - pub(crate) fn decode_input_with_decoder(decoder: A::Decoder, buf: &[u8], verbose: bool) + pub(crate) fn decode_input_with_decoder(decoder: A::Decoder, buf: &[u8], printer: &Printer) where A::Instruction: fmt::Display, for<'data> U8Reader<'data>: Reader, { - 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(); - } - Err(e) => { - println!("{:#010x}: {}", addr.to_linear(), e); - addr += A::Instruction::min_size(); - } - } - if addr.to_linear() >= buf.len() { - break; - } + 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| { + ( + A::Address::zero().wrapping_offset(inst.len()).to_linear(), + inst.well_defined(), + inst, + ) + }); + printer.print_instr(rest, addr.to_linear(), generic_res); + addr += advance_addr; } } } @@ -211,48 +233,35 @@ mod legacy_arch { use yaxpeax_arch_01::{AddressBase, Arch, Decoder, Instruction, LengthedInstruction}; use std::fmt; use num_traits::identities::Zero; + use super::Printer; - pub(crate) fn decode_input(buf: &[u8], verbose: bool) + pub(crate) fn decode_input(buf: &[u8], printer: &Printer) where A::Instruction: fmt::Display, { - decode_input_with_decoder::(A::Decoder::default(), buf, verbose); + decode_input_with_decoder::(A::Decoder::default(), buf, printer); } - pub(crate) fn decode_input_with_decoder(decoder: A::Decoder, buf: &[u8], verbose: bool) + pub(crate) fn decode_input_with_decoder(decoder: A::Decoder, buf: &[u8], printer: &Printer) 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(); - } - } - if addr.to_linear() >= buf.len() { - break; - } + let mut addr = A::Address::zero(); + while let Some(rest) = buf.get(addr.to_linear()..).filter(|v| !v.is_empty()) { + let res = decoder.decode(rest.iter().copied()); + let advance_addr = match &res { + Ok(inst) => inst.len(), + Err(_) => A::Instruction::min_size(), + }; + let generic_res = res.map(|inst| { + ( + A::Address::zero().wrapping_offset(inst.len()).to_linear(), + inst.well_defined(), + inst, + ) + }); + printer.print_instr(rest, addr.to_linear(), generic_res); + addr += advance_addr; } } } -- cgit v1.1