131 lines
3.8 KiB
Rust
131 lines
3.8 KiB
Rust
use std::io::Write;
|
|
use std::ops::Range;
|
|
use std::str::FromStr;
|
|
use std::sync::atomic::{AtomicU32, Ordering};
|
|
use std::sync::Arc;
|
|
use std::time::{Duration, Instant};
|
|
|
|
use ppc750cl::formatter::FormattedIns;
|
|
use ppc750cl::Ins;
|
|
|
|
fn main() {
|
|
let matches = clap::Command::new("ppc750cl-fuzz")
|
|
.version("0.2.0")
|
|
.about("Complete \"fuzzer\" for ppc750cl disassembler")
|
|
.arg(
|
|
clap::Arg::new("threads")
|
|
.short('t')
|
|
.long("--threads")
|
|
.takes_value(true)
|
|
.help("Number of threads to use (default num CPUs)"),
|
|
)
|
|
.get_matches();
|
|
|
|
let threads = match matches.value_of("threads") {
|
|
Some(t) => u32::from_str(t).expect("invalid threads flag"),
|
|
None => num_cpus::get() as u32,
|
|
};
|
|
let start = Instant::now();
|
|
let fuzzer = MultiFuzzer::new(threads);
|
|
fuzzer.run();
|
|
println!("Finished in {:.2}s", start.elapsed().as_secs_f32());
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
struct MultiFuzzer {
|
|
threads: Vec<Fuzzer>,
|
|
}
|
|
|
|
impl MultiFuzzer {
|
|
fn new(num_threads: u32) -> Self {
|
|
assert_ne!(num_threads, 0);
|
|
let mut threads = Vec::<Fuzzer>::with_capacity(num_threads as usize);
|
|
let part_size = 0xFFFF_FFFF / num_threads;
|
|
let mut offset = 0u32;
|
|
loop {
|
|
let next_offset = match offset.checked_add(part_size) {
|
|
None => break,
|
|
Some(v) => v,
|
|
};
|
|
threads.push(Fuzzer::new(offset..next_offset));
|
|
offset = next_offset;
|
|
}
|
|
threads.last_mut().unwrap().range.end = 0xFFFF_FFFF;
|
|
Self { threads }
|
|
}
|
|
|
|
fn dispatch_progress_monitor(&self) {
|
|
let this = self.clone();
|
|
std::thread::spawn(move || {
|
|
let mut last = 0u32;
|
|
loop {
|
|
std::thread::sleep(Duration::from_secs(1));
|
|
let mut now = 0u32;
|
|
for thread in &this.threads {
|
|
now += thread.counter.load(Ordering::Relaxed) - thread.range.start;
|
|
}
|
|
let per_second = now - last;
|
|
last = now;
|
|
let progress = 100f32 * ((now as f32) / (0x1_0000_0000u64 as f32));
|
|
println!("{}/s\t{:05.2}%\tn=0x{:08x}", per_second, progress, now);
|
|
}
|
|
});
|
|
}
|
|
|
|
fn run(&self) {
|
|
self.dispatch_progress_monitor();
|
|
let handles: Vec<_> = self.threads.iter().map(|t| t.dispatch()).collect();
|
|
for handle in handles {
|
|
// TODO This doesn't panic immediately, since we'll block on thread zero
|
|
// for most of the time.
|
|
handle.join().expect("thread panicked");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
struct Fuzzer {
|
|
range: Range<u32>,
|
|
counter: Arc<AtomicU32>,
|
|
}
|
|
|
|
impl Fuzzer {
|
|
fn new(range: Range<u32>) -> Self {
|
|
Self {
|
|
range,
|
|
counter: Arc::new(AtomicU32::new(0)),
|
|
}
|
|
}
|
|
|
|
fn dispatch(&self) -> std::thread::JoinHandle<()> {
|
|
let mut devnull = DevNull;
|
|
|
|
let counter = Arc::clone(&self.counter);
|
|
let range = self.range.clone();
|
|
std::thread::spawn(move || {
|
|
for x in range.clone() {
|
|
let ins = Ins::new(x, 0x8000_0000);
|
|
writeln!(&mut devnull, "{}", FormattedIns(ins)).unwrap();
|
|
if x % (1 << 19) == 0 {
|
|
counter.store(x, Ordering::Relaxed);
|
|
}
|
|
}
|
|
counter.store(range.end, Ordering::Relaxed);
|
|
})
|
|
}
|
|
}
|
|
|
|
struct DevNull;
|
|
|
|
impl std::io::Write for DevNull {
|
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
|
buf.iter().for_each(|b| unsafe {
|
|
std::ptr::read_volatile(b);
|
|
});
|
|
Ok(buf.len())
|
|
}
|
|
fn flush(&mut self) -> std::io::Result<()> {
|
|
Ok(())
|
|
}
|
|
}
|