summaryrefslogtreecommitdiff
path: root/python/examples/export-svg.py
diff options
context:
space:
mode:
authorJordan Wiens <jordan@psifertex.com>2016-06-01 04:51:14 -0400
committerJordan Wiens <jordan@psifertex.com>2016-06-01 04:51:14 -0400
commit16a07a7b7a5fe7acf172c8f5eedd5d9898645e22 (patch)
treef0a92f32a812e050c11cd97bf5f86163be0c35e3 /python/examples/export-svg.py
parent4dc7c3041e7c95e373b55dbb27b1861e82976fc0 (diff)
stylized svg and start of tooltips
Diffstat (limited to 'python/examples/export-svg.py')
-rwxr-xr-xpython/examples/export-svg.py108
1 files changed, 78 insertions, 30 deletions
diff --git a/python/examples/export-svg.py b/python/examples/export-svg.py
index e00b651f..ad3a3dd7 100755
--- a/python/examples/export-svg.py
+++ b/python/examples/export-svg.py
@@ -1,16 +1,34 @@
from binaryninja import *
-import os
+import os,sys
+
+escape_table = {
+ "&": "&#38;",
+ "'": "&#39;",
+ ">": "&#62;",
+ "<": "&#60;",
+ '"': "&#34;",
+ ' ': "&#160;",
+}
+
+def escape(string):
+ return ''.join(escape_table.get(i,i) for i in string)
def save_svg(bv,function):
filename = bv.file.filename.split(os.sep)[-1]
- outputfile = os.environ['HOME'] + os.sep + 'binaryninja-{filename}-{function}.svg'.format(filename=filename,function=function.symbol.name)
- try:
- output = open(outputfile,'w')
- output.write(render_svg(function))
- output.close()
- except:
- print "Unexpected error:", sys.exc_info()[0]
- raise
+ outputfile = os.path.join(os.path.expanduser('~'), 'binaryninja-{filename}-{function}.html'.format(filename=filename,function=function.symbol.name))
+ content = render_svg(function)
+ output = open(outputfile,'w')
+ output.write(content)
+ output.close()
+ #os.system('open %s' % outputfile)
+
+def instruction_data_flow(function,address):
+ ''' TODO: Extract data flow information '''
+ length = function.view.get_instruction_length(function.arch,address)
+ bytes = function.view.read(address, length)
+ hex = bytes.encode('hex')
+ padded = ' '.join([hex[i:i+2] for i in range(0, len(hex), 2)])
+ return 'Opcode: {bytes}'.format(bytes=padded)
def render_svg(function):
graph = function.create_graph()
@@ -19,44 +37,71 @@ def render_svg(function):
ratio = 0.54
widthconst = int(heightconst*ratio)
- output = '''<?xml version="1.0" standalone="no"?>
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="{width}" height="{height}" viewBox="0 0 {width} {height}">
+ output = '''<html><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}">
<defs>
<style type="text/css"><![CDATA[
@import url(https://fonts.googleapis.com/css?family=Source+Code+Pro);
+ svg {{
+ background-color: rgb(42, 42, 42);
+ }}
+ .basicblock {{
+ fill: rgb(74, 74, 74);
+ stroke: rgb(224, 224, 224);
+ }}
.edge {{
fill: none;
- stroke-width: 3
+ stroke-width: 2px;
}}
.UnconditionalBranch {{
- stroke: blue;
- color: blue;
+ stroke: rgb(128, 198, 233);
+ color: rgb(128, 198, 233);
}}
.FalseBranch {{
- stroke: red;
- color: red;
+ stroke: rgb(222, 143, 151);
+ color: rgb(222, 143, 151);
}}
.TrueBranch {{
- stroke: green;
- color: green;
+ stroke: rgb(162, 217, 175);
+ color: rgb(162, 217, 175);
}}
.arrow {{
- stroke-width: 3;
+ stroke-width: 1;
fill: currentColor;
}}
text {{
font-family: 'Source Code Pro';
font-size: 9pt;
+ fill: rgb(224, 224, 224);
+ }}
+ .CodeSymbolToken {{
+ fill: rgb(128, 198, 223);
+ }}
+ .TextToken {{
+ fill: rgb(224, 224, 224);
+ }}
+ .PossibleAddressToken {{
+ fill: rgb(162, 217, 175);
+ }}
+ .RegisterToken {{
+ fill: rgb(237, 223, 179);
+ }}
+ .InstructionToken {{
+ fill: rgb(224, 224, 224);
+ }}
+ .AnnotationToken {{
+ fill: rgb(218, 196, 209);
+ }}
+ .ImportToken {{
+ fill: rgb(237, 189, 129);
}}
]]></style>
- <marker id="arrow-TrueBranch" class="arrow TrueBranch" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto">
+ <marker id="arrow-TrueBranch" class="arrow TrueBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
- <marker id="arrow-FalseBranch" class="arrow FalseBranch" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto">
+ <marker id="arrow-FalseBranch" class="arrow FalseBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
- <marker id="arrow-UnconditionalBranch" class="arrow UnconditionalBranch" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto">
+ <marker id="arrow-UnconditionalBranch" class="arrow UnconditionalBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
@@ -74,9 +119,9 @@ def render_svg(function):
height = int((block.height) * heightconst)
#Render block
- output += ' <g id="basicblock{i}" class="basicblock">\n'
- output += ' <title>Basic Block {i}</title>\n'
- output += ' <rect style="fill:grey;stroke:black;" x="{x}" y="{y}" height="{height}" width="{width}"/>\n'.format(i=i,x=x,y=y,width=width,height=height)
+ output += ' <g id="basicblock{i}">\n'.format(i=i)
+ output += ' <title>Basic Block {i}</title>\n'.format(i=i)
+ output += ' <rect class="basicblock" x="{x}" y="{y}" height="{height}" width="{width}"/>\n'.format(x=x,y=y,width=width,height=height)
#Render instructions, unfortunately tspans don't allow copying/pasting more
#than one line at a time, need SVG 1.2 textarea tags for that it looks like
@@ -84,9 +129,12 @@ def render_svg(function):
output += ' <text x="{x}" y="{y}">\n'.format(x=x,y=y + (i + 1) * heightconst)
for i,line in enumerate(block.lines):
output += ' <tspan id="{address}" x="{x}" y="{y}">'.format(x=x,y=y + (i + 0.7) * heightconst,address=hex(line.address)[:-1])
+ hover = instruction_data_flow(function, line.address)
+ output += '<title>{hover}</title>'.format(hover=hover)
for token in line.tokens:
- output+='<tspan class="{tokentype}">{text}</tspan>'.format(text=token.text,tokentype=token.type)
- output += ' </tspan>\n'
+ # TODO: add hover for hex, function, and reg tokens
+ output+='<tspan class="{tokentype}">{text}</tspan>'.format(text=escape(token.text),tokentype=token.type)
+ output += '</tspan>\n'
output += ' </text>\n'
output += ' </g>\n'
@@ -100,7 +148,7 @@ def render_svg(function):
edges += ' <polyline class="edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format(type=edge.type,points=points)
output += ' ' + edges + '\n'
output += ' </g>\n'
- output += '</svg>'
+ output += '</svg></html>'
return output
-PluginCommand.register_for_function("Export to SVG", "Exports an SVG to your home folder for the given function", save_svg)
+PluginCommand.register_for_function("Export to SVG", "Exports an SVG of the current function to your home folder.", save_svg)