-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.html
173 lines (150 loc) · 6.29 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Assembly CFG example</title>
<script src='../dist/iife/asmcfg.js'></script>
<style>
/* Style node contents via the .node class */
.node {
white-space: nowrap;
font-family: Courier;
cursor: pointer;
}
/* Style node bounding rectangle */
.node rect {
stroke: #333;
fill: #fff;
stroke-width: 1.5px;
}
/* Style edges */
.edgePath path.path {
stroke: #333;
stroke-width: 1.5px;
fill: none;
}
#container {
display: flex;
flex-direction: row;
width: 100%;
height: 600px;
}
#code-view {
flex: 1;
border: 1px solid #999;
resize: none;
overflow: scroll;
margin: 0;
}
#svg-graph {
flex: 1;
border: 1px solid #999;
overflow: hidden;
outline: none;
}
</style>
</head>
<body>
<h1>Assembly CFG example</h1>
<div>
<label>
File:
<select id="example-file">
<option selected value="files/example-msvc.asm">example-msvc.asm</option>
<option value="files/example-clang.s">example-clang.s</option>
<option value="files/example-gcc.s">example-gcc.s</option>
<option value="files/trivial-clang.s" selected>trivial-clang.s</option>
</select>
</label>
<label>
Function:
<select id="function-name">
</select>
</label>
<label>
Highlight true/false branches: <input id="true-false-branches" checked type="checkbox">
</label>
</div>
<div id="container">
<pre id="code-view"></pre>
<svg id="svg-graph">
<g />
</svg>
</div>
<script>
// Global holding all functions parsed from the selected assembly file.
// See setExample().
let functions = null;
// Get all DOM elements into local variable for easier access
let exampleFile = document.querySelector("#example-file");
let functionName = document.querySelector("#function-name");
let codeView = document.querySelector("#code-view");
let svgGraph = document.querySelector("#svg-graph");
let trueFalseBranches = document.querySelector("#true-false-branches");
// IF the user selected a different file, set it as the current example
exampleFile.addEventListener("change", () => setExample(exampleFile.value));
// If the user selected a different function, render it
functionName.addEventListener("change", () => renderFunction(functions[Number.parseInt(functionName.value)]));
// If the user (un-)checked the true/false branches checkbox, re-render the function
trueFalseBranches.addEventListener("change", () => renderFunction(functions[Number.parseInt(functionName.value)]));
async function setExample(url) {
// Fetch the example file from the url and populate the code view
let response = await fetch(url);
if (!response.ok) throw new Error("Couldn't download example " + url);
let code = await response.text();
codeView.innerText = code;
// Parse the file contents into a list of functions. Each function
// is a graph
functions = asmcfg.parse(code);
// Populate the function select box with available function names
functionName.innerHTML = "";
for (let i = 0; i < functions.length; i++) {
let option = document.createElement("option");
option.innerText = functions[i].name;
option.value = i;
functionName.appendChild(option);
}
// Render the first function
renderFunction(functions[0]);
};
async function renderFunction(func) {
// Render the function to the SVG element
if (!trueFalseBranches.checked) {
// Simple case, styling is done via CSS
await asmcfg.renderSvg(func, svgGraph);
} else {
// Complex case, styling is done by modifying graphlib nodes and edges.
// See https://dagrejs.github.io/project/dagre-d3/latest/demo/style-attrs.html
let graph = await asmcfg.renderGraphlib(func);
let edges = graph.edges();
for (let i = 0; i < edges.length; i++) {
let edge = edges[i];
let fromNode = func.nodes[edge.v];
let toNode = func.nodes[edge.w];
// Highlight edges green or red, based on whether they are a result of a taken
// conditional jump (green), or a fall through (red). To determine this, we
// check if the last line of the "from" node has the label of the "to" node.
if (toNode.label) {
if (fromNode.lines.length > 0 && fromNode.lines[fromNode.lines.length - 1].indexOf(toNode.label) >= 0)
graph.setEdge(edge.v, edge.w, { style: "stroke: #00aa00" });
else
graph.setEdge(edge.v, edge.w, { style: "stroke: #aa0000" });
} else {
graph.setEdge(edge.v, edge.w, { style: "stroke: #aa0000" });
}
}
// Render the styled graphlib graph to the SVG element.
await asmcfg.renderSvgFromGraphlib(graph, svgGraph);
}
// Enable panning and zooming on the SVG element's root group
asmcfg.makeInteractive(svgGraph.querySelector("g"), func, (lineStart, lineEnd, node, func) => {
let message = `Clicked node of ${func.name}, lines ${lineStart}-${lineEnd}\n\n${node.lines.join("\n")}`;
alert(message);
});
}
setExample(exampleFile.value)
</script>
</body>
</html>