pcode 0.1.3

Pure Rust implementation of a p-code disassembler and lifter.
Documentation
mod logger;
mod sleigh;
mod arch;
mod sla_parser;
mod symbol_resolver;
mod pcode_builder;
mod disassembler;

extern crate bitvec;
extern crate nom;

use crate::sla_parser::*;
use crate::disassembler::Disassembler;

use std::io::{Read, Write};
use std::time::Instant;
use std::fs::File;

#[cfg(feature = "bin")]
use object::{Object, ObjectSection, SectionKind};

#[cfg(feature = "bin")]
use clap::Parser;

fn parse_hex(s: &str) -> Result<u64, String> {
    Ok(u64hex(s))
}

#[cfg(feature = "bin")]
#[derive(Parser, Debug, Default)]
struct Args {
    #[arg(short, long, value_parser = parse_hex)]
    start_addr: Option<u64>,

    #[arg(short, long, value_parser = parse_hex)]
    end_addr: Option<u64>,

    #[arg(short, long)]
    num: Option<u64>,

    #[arg(short, long)]
    time: bool,

    #[arg(short, long)]
    language_id: String,

    #[arg(short, long)]
    compiler_id: String,

    #[arg(short, long)]
    file_name: String,

    #[arg(short = 'm', long = "log")]
    log_modules: Vec<String>,

    #[arg(long = "print_asm")]
    print_asm: bool,

    #[arg(long = "print_pcode")]
    print_pcode: bool,
}

#[cfg(feature = "bin")]
fn main() {
    let args = Args::parse();

    let lang_id = args.language_id.clone();
    let comp_id = args.compiler_id.clone();

    let mut file = File::open(&args.file_name).unwrap();
    let mut bytes = vec![];
    file.read_to_end(&mut bytes).unwrap();

    let start = Instant::now();
    let print_time = args.time;
    let num = args.num;

    let mut disasm = Disassembler::new(lang_id, comp_id, num, &args.log_modules);

    let obj = object::File::parse(&*bytes).unwrap();
    let mut num_bytes = 0;
    let mut num_insns = 0;

    let mut start_addr = args.start_addr.unwrap_or(u64::MAX);
    let end_addr = args.end_addr.unwrap_or(u64::MAX);
    let max_insns = args.num.unwrap_or(u64::MAX);

    let print_progress = !(args.print_asm || args.print_pcode) && args.log_modules.is_empty();

    'outer: for section in obj.sections() {
        if section.kind() == SectionKind::Text {
            let mut addr = section.address();
            let size = section.size();

            if let Some((off, _)) = section.file_range() {
                let mut start = off as usize;
                let end = (off + size) as usize;

                if start_addr != u64::MAX {
                    if start_addr < addr || start_addr >= (addr + size) {
                        continue;
                    }

                    let delta = start_addr - addr;
                    start += delta as usize;
                    addr += delta;
                    start_addr = addr + size;
                }

                const NUM_TICKS: usize = 30;
                let mut prev_num_ticks = 0;

                if print_progress {
                    print!("[{}]", ".".repeat(NUM_TICKS));
                    std::io::stdout().flush().unwrap();
                }

                for insn in disasm.disassemble(&bytes[start..end], addr) {
                    num_insns += 1;
                    num_bytes += insn.length as usize;

                    if print_progress {
                        let num_ticks = (((insn.address.offset - addr) as f64 / (end - start) as f64) * (NUM_TICKS as f64)) as usize;
                        if num_ticks != prev_num_ticks {
                            print!("\x1b[2K\r[{}{}]", "+".repeat(num_ticks), ".".repeat(NUM_TICKS - num_ticks));
                            std::io::stdout().flush().unwrap();
                            prev_num_ticks = num_ticks;
                        }
                    }

                    if args.print_asm {
                        println!("0x{:x}: {}", insn.address.offset, insn.asm);
                    }

                    if args.print_pcode {
                        for op in &insn.ops {
                            println!("    {}: {}", op.seq, op);
                        }
                    }

                    if num_insns > max_insns || (end_addr != u64::MAX && insn.address.offset >= end_addr) {
                        break 'outer;
                    }
                }

                if print_progress {
                    println!();
                }
            }
        }
    }

    if print_time {
        println!(
            "Disassembled {} bytes ({} instructions) in {}s",
            num_bytes, 
            num_insns,
            ((Instant::now() - start).as_millis() as f64) / 1000.0
        );
    }
}