From 9523d4408ad1dc8f5658ed27c772ae68c829d792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Wed, 6 Jan 2021 19:53:22 +0100 Subject: add superh Made slightly less pretty by the many silicon- and run-time features of most SuperH processors --- Cargo.lock | 10 ++++++++ Cargo.toml | 1 + README.md | 2 +- src/main.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89b12e1..9d68d4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -341,6 +341,7 @@ dependencies = [ "yaxpeax-msp430", "yaxpeax-pic17", "yaxpeax-pic18", + "yaxpeax-superh", "yaxpeax-x86", ] @@ -407,6 +408,15 @@ dependencies = [ ] [[package]] +name = "yaxpeax-superh" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02789f779dd874674062a7407a1faadcb4dbbb70b313b465a2bdbb562bb4d1f7" +dependencies = [ + "yaxpeax-arch", +] + +[[package]] name = "yaxpeax-x86" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 4552fc6..692655e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,4 @@ yaxpeax-pic17 = { version = "0.0.3" } yaxpeax-pic18 = { version = "0.0.3" } yaxpeax-x86 = { version = "0.1.2" } yaxpeax-ia64 = { version = "0.1.1" } +yaxpeax-superh = { version = "0.1.0" } diff --git a/README.md b/README.md index cd8f7a9..3df0fac 100644 --- a/README.md +++ b/README.md @@ -24,4 +24,4 @@ or `yaxdis -a ia64 e38000000061e200000042c0e1803080`, producing: `yaxdis` also takes a `-v` flag to emit more verbose information (really, a `Debug` display of decoded instructions). ## supported architectures / ! user beware ! -`yaxdis` should support all architectures listed in the [yaxpeax-arch readme](https://git.iximeow.net/yaxpeax-arch/). that is currently `x86_64`, `armv7`, `armv8`, `mips`, `msp430`, `pic17`, `pic18`, `m16c`, `avr`, and `ia64`. specific levels of support and stability vary, beware. +`yaxdis` should support all architectures listed in the [yaxpeax-arch readme](https://git.iximeow.net/yaxpeax-arch/). that is currently `x86_64`, `armv7`, `armv8`, `mips`, `msp430`, `pic17`, `pic18`, `m16c`, `avr`, `ia64`, and `sh`/`sh2`/`j2`/`sh3`/`sh4`. specific levels of support and stability vary, beware. diff --git a/src/main.rs b/src/main.rs index 732f747..99d7ad3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use num_traits::identities::Zero; use std::fmt; use std::fs::File; use std::io::Read; +use std::collections::BTreeSet; fn main() { let _ = include_str!("../Cargo.toml"); @@ -15,10 +16,21 @@ fn main() { .short("a") .long("--architecture") .takes_value(true) - .possible_values(&[ - "x86_64", "x86:32", "ia64", "armv7", "armv8", "avr", "mips", "msp430", "pic17", - "pic18", "m16c", - ]) + .validator(|a| { + if ["x86_64", "x86:32", "ia64", "armv7", "armv8", "avr", "mips", "msp430", + "pic17", "pic18", "m16c"].contains(&&a[..]) || + (["sh", "sh2", "sh3", "sh4", "j2"].contains( + &&a[0..a.find(|c| c == '+' || c == '-').unwrap_or(a.len())]) && + a.split(|c| c == '+' || c == '-').skip(1).all( + |f| ["be", "mmu", "fpu", "f64", "j2"].contains(&f))) { + Ok(()) + } else { + Err("possible values: x86_64, x86:32, ia64, armv7, armv8, avr, mips, \ + msp430, pic17, pic18, m16c, \ + {sh{,2,3,4},j2}[[+-]{be,mmu,fpu,f64,j2}]*" + .to_string()) + } + }) .help("architecture to disassemble input as."), ) .arg( @@ -85,16 +97,69 @@ fn main() { "m16c" => decode_input::(&buf, verbose), // "pic24" => decode_input::(buf), other => { - println!("unsupported architecture: {}", 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| decode_input_with_decoder::(decoder, &buf, verbose)); + match &arch_str[0..seg_idx] { + "sh" => wps(yaxpeax_superh::SuperHDecoder::SH1), + "sh2" => wps(yaxpeax_superh::SuperHDecoder::SH2), + "sh3" => wps(yaxpeax_superh::SuperHDecoder::SH3), + "sh4" => wps(yaxpeax_superh::SuperHDecoder::SH4), + "j2" => wps(yaxpeax_superh::SuperHDecoder::J2), + _ => println!("unsupported architecture: {}", other), + } } } } +fn with_parsed_superh( + mut based_on: yaxpeax_superh::SuperHDecoder, mut from: &str, func: F +) { + let mut features = based_on.features.iter().copied().collect::>(); + + while !from.is_empty() { + // This would be Not Trash if split_inclusive were stable; alas + let op = from.chars().next().unwrap(); + from = &from[1..]; + + let next_feat_idx = from.find(|c| c == '+' || c == '-').unwrap_or(from.len()); + let feat = &from[0..next_feat_idx]; + from = &from[next_feat_idx..]; + + match (op, feat) { + ('+', "be") => based_on.little_endian = false, + ('-', "be") => based_on.little_endian = true, + ('+', "f64") => based_on.fpscr_sz = true, + ('-', "f64") => based_on.fpscr_sz = false, + + ('+', "mmu") => { features.insert(yaxpeax_superh::SuperHFeature::MMU); }, + ('-', "mmu") => { features.remove(&yaxpeax_superh::SuperHFeature::MMU); }, + ('+', "fpu") => { features.insert(yaxpeax_superh::SuperHFeature::FPU); }, + ('-', "fpu") => { features.remove(&yaxpeax_superh::SuperHFeature::FPU); }, + ('+', "j2") => { features.insert(yaxpeax_superh::SuperHFeature::J2); }, + ('-', "j2") => { features.remove(&yaxpeax_superh::SuperHFeature::J2); }, + + pair => panic!("Who is {:?} and why was it not caught at parse time?", pair), + } + } + + func(yaxpeax_superh::SuperHDecoder { + features: &features.into_iter().collect::>()[..], + ..based_on + }) +} + fn decode_input(buf: &[u8], verbose: bool) where A::Instruction: fmt::Display, { - let decoder = A::Decoder::default(); + decode_input_with_decoder::(A::Decoder::default(), buf, verbose); +} + +fn decode_input_with_decoder(decoder: A::Decoder, buf: &[u8], verbose: bool) +where + A::Instruction: fmt::Display, +{ let start = A::Address::zero(); let mut addr = start; loop { -- cgit v1.1