dot/
dot.rs

1// Copyright © 2020-2021 Keegan Saunders
2//
3// Permission to use, copy, modify, and/or distribute this software for
4// any purpose with or without fee is hereby granted.
5//
6// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
7// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
8// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
9// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
10// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
11// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
12// OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
13//
14
15use indexmap::map::Values;
16use std::{env, str};
17use vtil_parser::{dump::dump_instr, BasicBlock, Result, Routine, Vip};
18
19fn escape(data: String) -> String {
20    data.replace("&", "&")
21        .replace("\"", """)
22        .replace("'", "'")
23        .replace("<", "&lt;")
24        .replace(">", "&gt;")
25        .replace("|", "\\|")
26}
27
28fn dump_routine(basic_blocks: Values<Vip, BasicBlock>) {
29    println!("digraph G {{");
30
31    for basic_block in basic_blocks {
32        let pc = basic_block.vip.0;
33
34        println!(
35            r#"vip_{0:x} [
36    shape="Mrecord"
37    fontname="Courier New"
38    label=<
39        <table border="0" cellborder="0" cellpadding="3">
40            <tr><td align="center" colspan="2" bgcolor="grey">{0:x}</td></tr>"#,
41            pc
42        );
43
44        for instr in &basic_block.instructions {
45            let mut buffer = Vec::<u8>::new();
46            dump_instr(&mut buffer, instr).unwrap();
47            println!(
48                r#"            <tr><td align="left">{}</td></tr>"#,
49                escape(str::from_utf8(&buffer).unwrap().to_string())
50            );
51        }
52
53        println!(
54            r#"        </table>
55    >
56];"#
57        );
58
59        let successors = &basic_block.next_vip;
60        if successors.len() == 2 {
61            println!(
62                r#"vip_{:x} -> vip_{:x} [color="green"];"#,
63                pc, successors[0].0
64            );
65            println!(
66                r#"vip_{:x} -> vip_{:x} [color="red"];"#,
67                pc, successors[1].0
68            );
69        } else {
70            for successor in successors {
71                println!(r#"vip_{:x} -> vip_{:x} [color="blue"];"#, pc, successor.0);
72            }
73        }
74    }
75
76    println!("}}");
77}
78
79fn main() -> Result<()> {
80    let mut argv = env::args();
81    let routine = Routine::from_path(argv.nth(1).unwrap())?;
82    dump_routine(routine.explored_blocks.values());
83    Ok(())
84}