Skip to content

Commit

Permalink
Merge pull request #305 from das-labor/m4b/cli
Browse files Browse the repository at this point in the history
add CLI component
  • Loading branch information
flanfly authored Jun 25, 2017
2 parents 19a18e1 + 2380117 commit 6153a7f
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 5 deletions.
40 changes: 40 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion analysis/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ use std::collections::HashMap;
use std::fmt::Debug;
use std::iter::FromIterator;
use std::thread;
use std::sync::Arc;

/// Starts disassembling insructions in `region` and puts them into `program`. Returns a stream of
/// of newly discovered functions.
pub fn pipeline<A: Architecture + Debug + 'static>(
program: Program,
program: Arc<Program>,
region: Region,
config: A::Configuration,
) -> Box<Stream<Item = Function, Error = ()> + Send>
Expand Down
11 changes: 11 additions & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,14 @@ authors = ["seu <seu@panopticon.re>"]
name = "panop"

[dependencies]
structopt = "0.0.5"
structopt-derive = "0.0.5"
error-chain = "0.8"
futures = "0.1"
panopticon-core = { path = "../core" }
panopticon-analysis = { path = "../analysis" }
panopticon-amd64 = { path = "../amd64" }
panopticon-avr = { path = "../avr" }
panopticon-graph-algos = { path = "../graph-algos" }
log = "0.3"
env_logger = "0.3"
140 changes: 139 additions & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,141 @@
extern crate structopt;
#[macro_use]
extern crate structopt_derive;
#[macro_use]
extern crate error_chain;
extern crate panopticon_core;
extern crate panopticon_amd64;
extern crate panopticon_avr;
extern crate panopticon_analysis;
extern crate panopticon_graph_algos;
extern crate futures;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::result;
use std::path::Path;
use std::sync::Arc;
use panopticon_core::{Machine, Function, ControlFlowTarget, loader};
use panopticon_amd64 as amd64;
use panopticon_avr as avr;
use panopticon_analysis::pipeline;
use panopticon_graph_algos::{GraphTrait};
use futures::Stream;
use structopt::StructOpt;

mod errors {
error_chain! {
foreign_links {
Panopticon(::panopticon_core::Error);
}
}
}
use errors::*;

#[derive(StructOpt, Debug)]
#[structopt(name = "panop", about = "A libre cross-platform disassembler.")]
struct Args {
/// The specific function to disassemble
#[structopt(short = "f", long = "function", help = "Disassemble the given function")]
function_filter: Option<String>,
/// The binary to disassemble
#[structopt(help = "The binary to disassemble")]
binary: String,
}

fn exists_path_val(filepath: &str) -> result::Result<(), String> {
match Path::new(filepath).is_file() {
true => Ok(()),
false => Err(format!("'{}': no such file", filepath)),
}
}

fn get_entry_point(func: &Function) -> Option<u64> {
if let Some(ref entry) = func.entry_point {
if let Some(&ControlFlowTarget::Resolved(ref bb)) = func.cflow_graph.vertex_label(*entry) {
return Some(bb.area.start);
}
}

None
}

fn disassemble(args: Args) -> Result<()> {
let binary = args.binary;
let filter = args.function_filter;
let (mut proj, machine) = loader::load(Path::new(&binary))?;
let maybe_prog = proj.code.pop();
let reg = proj.data.dependencies.vertex_label(proj.data.root).unwrap().clone();

if let Some(prog) = maybe_prog {
let prog = Arc::new(prog);
let pipe = {
let prog = prog.clone();
match machine {
Machine::Avr => pipeline::<avr::Avr>(prog, reg.clone(), avr::Mcu::atmega103()),
Machine::Ia32 => pipeline::<amd64::Amd64>(prog, reg.clone(), amd64::Mode::Protected),
Machine::Amd64 => pipeline::<amd64::Amd64>(prog, reg.clone(), amd64::Mode::Long),
}
};

info!("disassembly thread started");
match filter {
Some(filter) => {
for function in pipe.wait() {
if let Ok(function) = function {
if filter == function.name {
println!("{}", function.display_with(&prog.clone()));
break;
}
}
}
},
None => {
let mut functions = pipe.wait().filter_map(|function| {
if let Ok(function) = function {
info!("{}",function.uuid);
Some(function)
} else {
None
}
}).collect::<Vec<_>>();

functions.sort_by(|f1, f2| {
use std::cmp::Ordering::*;
let entry1 = get_entry_point(f1);
let entry2 = get_entry_point(f2);
match (entry1, entry2) {
(Some(entry1), Some(entry2)) => entry1.cmp(&entry2),
(Some(_), None) => Greater,
(None, Some(_)) => Less,
(None, None) => Equal,
}
});

for function in functions {
println!("{}", function.display_with(&prog.clone()));
}
}
}
info!("disassembly thread finished");
}
Ok(())
}

fn run(args: Args) -> Result<()> {
exists_path_val(&args.binary)?;
disassemble(args)?;
Ok(())
}

fn main() {
println!("Hello, world!");
env_logger::init().unwrap();
match run(Args::from_args()) {
Ok(()) => {}
Err(s) => {
error!("Error: {}",s);
::std::process::exit(1);
}
}
}
16 changes: 15 additions & 1 deletion core/src/basic_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//! Basic blocks always occupy a continuous byte range.

use {Bound, Mnemonic, Statement};
use {Bound, Mnemonic, Statement, Program};
use std::cmp::{max, min};

/// A basic block: a continiuous sequence of mnemonics without any branches in between.
Expand Down Expand Up @@ -91,6 +91,20 @@ impl BasicBlock {
}
}
}
/// Displays the basic block in disassembly order, in human readable form, and looks up any functions calls in `program`
pub fn display_with(&self, program: &Program) -> String {
let seed = String::new();
let display = self.mnemonics.iter().filter_map(|x| {
if x.opcode.starts_with("__") {
None
} else {
Some(x)
}
}).collect::<Vec<_>>();
display.iter().fold(seed, |acc, ref m| -> String {
format!("{}\n{}", acc, m.display_with(program))
})
}
}

#[cfg(test)]
Expand Down
24 changes: 23 additions & 1 deletion core/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
//! on the front-end.

use {Architecture, BasicBlock, Guard, Mnemonic, Operation, Region, Rvalue, Statement};
use {Architecture, BasicBlock, Guard, Mnemonic, Operation, Region, Rvalue, Statement, Program};

use panopticon_graph_algos::{AdjacencyList, EdgeListGraphTrait, GraphTrait, MutableGraphTrait, VertexListGraphTrait};
use panopticon_graph_algos::adjacency_list::{AdjacencyListEdgeDescriptor, AdjacencyListVertexDescriptor};
Expand Down Expand Up @@ -569,6 +569,28 @@ impl Function {

format!("{}\n}}", ret)
}

/// Displays the function in a human readable format, using `program`
pub fn display_with(&self, program: &Program) -> String {
let mut bbs = self.cflow_graph.vertices().filter_map(|v| {
match self.cflow_graph.vertex_label(v) {
Some(&ControlFlowTarget::Resolved(ref bb)) => {
Some (bb)
},
_ => None
}
}).collect::<Vec<&BasicBlock>>();
bbs.sort_by(|bb1, bb2| bb1.area.start.cmp(&bb2.area.start));
let mut fmt = if let Some(bb) = bbs.first() {
format!("{:0>8x} <{}>:", bb.area.start, self.name)
} else {
format!("{}", self.name)
};
for bb in bbs {
fmt = format!("{}{}", fmt, bb.display_with(program));
}
fmt
}
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 6153a7f

Please sign in to comment.