Skip to content
Snippets Groups Projects
Commit d01e5cd4 authored by Per Lindgren's avatar Per Lindgren
Browse files

full integration

parent f9c62bc8
No related branches found
No related tags found
No related merge requests found
...@@ -6,3 +6,8 @@ edition = "2018" ...@@ -6,3 +6,8 @@ edition = "2018"
[dependencies] [dependencies]
libc = "0.2.43" libc = "0.2.43"
pest = "2.0.2"
pest_derive = "2.0.1"
stack-sizes = "0.1.0"
rustc-demangle = "0.1.9"
petgraph = "0.4.13"
...@@ -4,6 +4,30 @@ use std::io::{self, Read, Write}; ...@@ -4,6 +4,30 @@ use std::io::{self, Read, Write};
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::{env, str}; use std::{env, str};
#[macro_use]
extern crate pest_derive;
extern crate rustc_demangle;
extern crate stack_sizes;
use pest::Parser;
use rustc_demangle::demangle;
use std::fs::File;
use petgraph::{
algo::is_cyclic_directed,
dot::{Config, Dot},
graph::NodeIndex,
visit::DfsPostOrder,
Graph, Incoming,
};
use std::collections::hash_map::HashMap;
use std::fmt;
#[derive(Parser)]
#[grammar = "ident.pest"]
struct IdentParser;
#[derive(Debug)] #[derive(Debug)]
struct Out { struct Out {
hash: Option<String>, hash: Option<String>,
...@@ -47,6 +71,112 @@ fn parse_out(out_str: &str) -> Out { ...@@ -47,6 +71,112 @@ fn parse_out(out_str: &str) -> Out {
out out
} }
struct Node {
name: String,
local_stack: u32,
call_stack: u32,
}
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:#}\\n stack local = {}, call = {}",
demangle(&self.name),
self.local_stack,
self.call_stack
)
}
}
fn new_node(
hm: &mut HashMap<String, NodeIndex<u32>>,
g: &mut Graph<Node, ()>,
s: String,
v: u32,
) -> NodeIndex<u32> {
let n = Node {
name: s.to_string(),
local_stack: v,
call_stack: v,
};
let i = g.add_node(n);
hm.insert(s, i);
i
}
fn add_edge<'a>(
hm: &mut HashMap<String, NodeIndex<u32>>,
g: &mut Graph<Node, ()>,
from: &str,
to: &str,
) {
let i_from = hm.get(from).expect("from not found");
if let Some(i_to) = hm.get(to) {
g.add_edge(*i_from, *i_to, ());
}
}
fn read_elf(path: &str, buffer: &mut Vec<u8>) {
let mut elf = File::open(path).expect(format!("error opening '{}'", path).as_str());
elf.read_to_end(buffer)
.expect(format!("error opening '{}'", path).as_str());
}
fn parse_elf<'a>(
hm: &mut HashMap<String, NodeIndex<u32>>,
g: &mut Graph<Node, ()>,
path: &str,
vec: &'a mut Vec<u8>,
) {
read_elf(path, vec);
// read and analyse stack-sizes of elf
let ss = stack_sizes::analyze(&vec).expect("error analysing elf");
if let Some(v32) = ss.left() {
// put into graph
for s in v32.iter() {
let d_name = s.name().to_string(); // format!("{:#}", demangle(s.name()));
let _ = new_node(hm, g, d_name, s.stack() as u32);
}
} else {
panic!("64 bit elfs not supported");
}
}
fn parse_callgraph(hm: &mut HashMap<String, NodeIndex<u32>>, g: &mut Graph<Node, ()>, input: &str) {
let functions = IdentParser::parse(Rule::ident_list, &input)
.unwrap_or_else(|e| panic!("parse error {}", e));
for f in functions {
match f.as_rule() {
Rule::fun => {
let mut p = f.into_inner();
let mut i = p.next().unwrap().into_inner();
let from = i.next().unwrap().into_inner();
for c in p {
match c.as_rule() {
Rule::callext => {}
Rule::callfun => {
let mut p = c.into_inner();
p.next().unwrap();
let to = p.next().unwrap().into_inner().as_str().to_string();
add_edge(hm, g, from.as_str(), to.as_str());
}
_ => panic!("internal error"),
}
}
}
Rule::null => (),
Rule::EOI => (),
_ => {
panic!("internal error");
}
}
}
}
fn main() { fn main() {
println!("start sub command"); println!("start sub command");
// first argument is the path to this binary; the second argument is always "call-stack" -- both can // first argument is the path to this binary; the second argument is always "call-stack" -- both can
...@@ -107,26 +237,61 @@ fn main() { ...@@ -107,26 +237,61 @@ fn main() {
let mut s = String::new(); let mut s = String::new();
write!( write!(
&mut s, &mut s,
"{}/{}{}.ll", "{}/{}{}",
out.out_dir.expect("--out-dir missing"), out.out_dir.expect("--out-dir missing"),
out.crate_name.expect("--crate-name missing"), out.crate_name.expect("--crate-name missing"),
out.hash.expect("extra-filename missing") out.hash.expect("extra-filename missing")
) )
.expect("internal error"); .expect("internal error");
println!("s: {}", s); let mut ir = s.clone();
write!(&mut ir, ".ll").expect("internal error");
println!("s: {}", ir);
let mut c = Command::new("opt"); let mut c = Command::new("opt");
c.arg("-analyze") c.arg("-analyze")
.arg("-print-callgraph") .arg("-print-callgraph")
.arg(s) .arg(ir)
.output() .output()
.expect("failed to execute process"); .expect("failed to execute process");
let dump = c.output().expect("failed to execute process"); let dump = c.output().expect("failed to execute process");
println!("{:?}", dump); //println!("{:?}", dump);
println!("{:?}", dump.status); println!("\nstatus: {:?}", dump.status);
println!("{:?}", str::from_utf8(&dump.stdout).unwrap()); println!("\nstdout: {:?}", str::from_utf8(&dump.stdout).unwrap());
println!("{:?}", str::from_utf8(&dump.stderr).unwrap()); println!("\nstderr: {:?}", str::from_utf8(&dump.stderr).unwrap());
let mut g = Graph::<_, ()>::new();
let mut hm = HashMap::new();
let mut buffer = Vec::new();
println!("elf = {}", &s);
parse_elf(&mut hm, &mut g, &s, &mut buffer);
parse_callgraph(&mut hm, &mut g, &str::from_utf8(&dump.stderr).unwrap());
if is_cyclic_directed(&g) {
println!("/* warning, cyclic graph */");
}
let mut v = Vec::new();
for ext in g.externals(Incoming) {
v.push(ext);
}
let mut dfs = DfsPostOrder::empty(&g);
while let Some(ext) = v.pop() {
dfs.move_to(ext);
while let Some(node) = dfs.next(&g) {
// use a detached neighbors walker
let mut edges = g.neighbors_directed(node, Incoming).detach();
while let Some(to) = edges.next_node(&g) {
g[to].call_stack = g[to].call_stack.max(g[to].local_stack + g[node].call_stack);
}
}
}
println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));
// let hello = c.stdout(); // let hello = c.stdout();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment