-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathdisplay_extension.py
More file actions
271 lines (229 loc) · 9.55 KB
/
display_extension.py
File metadata and controls
271 lines (229 loc) · 9.55 KB
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# Copyright (C) 2021 Aurore Fass
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# Additional permission under GNU GPL version 3 section 7
#
# If you modify this Program, or any covered work, by linking or combining it with
# graphviz (or a modified version of that library), containing parts covered by the
# terms of The Common Public License, the licensors of this Program grant you
# additional permission to convey the resulting work.
"""
Display an Extension Dependence Graph (EDG) using the graphviz library.
"""
import copy
import graphviz
import pdg_js.node as _node
def append_leaf_attr(node, graph):
"""
Append the leaf's attribute to the graph in graphviz format.
-------
Parameters:
- node: Node
Node.
- graph: Digraph/Graph
Graph object. Be careful it is mutable.
"""
if node.is_leaf():
leaf_id = str(node.id) + 'leaf_'
graph.attr('node', style='filled', color='white', fillcolor='white')
graph.attr('edge', color='grey', style='tapered')
got_attr, node_attributes = node.get_node_attributes()
if got_attr: # Got attributes
leaf_attr = str(node_attributes)
graph.node(leaf_id, leaf_attr)
graph.edge(str(node.id), leaf_id)
def produce_ast(ast_nodes, attributes, graph=graphviz.Digraph(comment='AST representation')):
"""
Produce an AST in graphviz format.
-------
Parameters:
- ast_nodes: Node
Output of ast_to_ast_nodes(<ast>, ast_nodes=Node('Program')).
- graph: Graph
Graph object. Be careful it is mutable.
- attributes: bool
Whether to display the leaf attributes or not.
-------
Returns:
- graph
graphviz formatted graph.
"""
graph.attr('node', color='black', style='filled', fillcolor='lightgoldenrodyellow')
graph.attr('edge', color='black')
graph.node(str(ast_nodes.id), ast_nodes.name)
for child in ast_nodes.children:
graph.attr('node', color='black', style='filled', fillcolor='lightgoldenrodyellow')
graph.attr('edge', color='black')
graph.edge(str(ast_nodes.id), str(child.id))
produce_ast(child, attributes, graph)
if attributes:
append_leaf_attr(child, graph)
return graph
def draw_ast(ast_nodes, attributes=False, save_path=None):
"""
Plot an AST.
-------
Parameters:
- ast_nodes: Node
Output of ast_to_ast_nodes(<ast>, ast_nodes=Node('Program')).
- save_path: str
Path of the file to store the AST in.
- attributes: bool
Whether to display the leaf attributes or not. Default: False.
"""
dot = produce_ast(ast_nodes, attributes)
if save_path is None:
dot.view()
else:
dot.render(save_path, view=False)
graphviz.render(filepath=save_path, engine='dot', format='eps')
dot.clear()
def cfg_type_node(child):
""" Different form according to statement node or not. """
if isinstance(child, _node.Statement) or child.is_comment():
return ['box', 'mediumblue', 'lightblue', 'dotted']
return ['ellipse', 'black', 'lightgoldenrodyellow', 'bold']
def produce_cfg_one_child(child, data_flow, attributes,
graph=graphviz.Digraph(comment='Control flow representation')):
"""
Produce a CFG in graphviz format.
-------
Parameters:
- child: Node
Node to begin with.
- data_flow: bool
Whether to display the data flow or not. Default: False.
- attributes: bool
Whether to display the leaf attributes or not.
- graph: Digraph
Graph object. Be careful it is mutable.
-------
Returns:
- graph
graphviz formatted graph.
"""
type_node = cfg_type_node(child)
graph.attr('node', shape=type_node[0], style='filled', color=type_node[1],
fillcolor=type_node[2])
graph.attr('edge', color=type_node[1], style=type_node[3])
graph.node(str(child.id), child.name)
for child_statement_dep in child.statement_dep_children:
child_statement = child_statement_dep.extremity
type_node = cfg_type_node(child_statement)
graph.attr('node', shape=type_node[0], color=type_node[1], fillcolor=type_node[2])
graph.attr('edge', color=type_node[1], style=type_node[3])
graph.edge(str(child.id), str(child_statement.id), label=child_statement_dep.label)
produce_cfg_one_child(child_statement, data_flow=data_flow, attributes=attributes,
graph=graph)
if attributes:
append_leaf_attr(child_statement, graph)
if isinstance(child, _node.Statement):
for child_cf_dep in child.control_dep_children:
child_cf = child_cf_dep.extremity
type_node = cfg_type_node(child_cf)
graph.attr('node', shape=type_node[0], color=type_node[1], fillcolor=type_node[2])
graph.attr('edge', color='mediumblue', style=type_node[3])
graph.edge(str(child.id), str(child_cf.id), label=str(child_cf_dep.label))
produce_cfg_one_child(child_cf, data_flow=data_flow, attributes=attributes, graph=graph)
if attributes:
append_leaf_attr(child_cf, graph)
if data_flow:
graph.attr('edge', color='darkorange', style='dashed')
if isinstance(child, _node.Identifier):
for child_data_dep in child.data_dep_children:
child_data = child_data_dep.extremity
type_node = cfg_type_node(child)
graph.attr('node', shape=type_node[0], color=type_node[1], fillcolor=type_node[2])
graph.edge(str(child.id), str(child_data.id), label=child_data_dep.label)
# No call to the func as already recursive for data/statmt dep on the same nodes
# logging.info("Data dependency on the variable " + child_data.attributes['name'])
graph.attr('edge', color='deepskyblue', style='dashed')
if hasattr(child, 'fun_param_parents'): # Function parameters flow
for child_param in child.fun_param_parents:
type_node = cfg_type_node(child)
graph.attr('node', shape=type_node[0], color=type_node[1], fillcolor=type_node[2])
graph.edge(str(child.id), str(child_param.id), label='param')
return graph
def draw_cfg(cfg_nodes, attributes=False, save_path=None):
"""
Plot a CFG.
-------
Parameters:
- cfg_nodes: Node
Output of produce_cfg(ast_to_ast_nodes(<ast>, ast_nodes=Node('Program'))).
- save_path: str
Path of the file to store the CFG in.
- attributes: bool
Whether to display the leaf attributes or not. Default: False.
"""
dot = graphviz.Digraph()
for child in cfg_nodes.children:
dot = produce_cfg_one_child(child=child, data_flow=False, attributes=attributes)
if save_path is None:
dot.view()
else:
dot.render(save_path, view=False)
graphviz.render(filepath=save_path, engine='dot', format='eps')
dot.clear()
def draw_pdg(dfg_nodes, attributes=False, save_path=None):
"""
Plot a PDG.
-------
Parameters:
- dfg_nodes: Node
Output of produce_dfg(produce_cfg(ast_to_ast_nodes(<ast>, ast_nodes=Node('Program')))).
- save_path: str
Path of the file to store the PDG in.
- attributes: bool
Whether to display the leaf attributes or not. Default: False.
"""
dot = graphviz.Digraph()
for child in dfg_nodes.children:
dot = produce_cfg_one_child(child=child, data_flow=True, attributes=attributes)
if save_path is None:
dot.view()
else:
dot.render(save_path, view=False)
graphviz.render(filepath=save_path, engine='dot', format='eps')
dot.clear()
def draw_extensions(pdg_cs, pdg_bp, graph, attributes=True, save_path=None):
"""
Display the Extension Dependence Graph (EDG). No links CS/BP yet.
-------
Parameters:
- pdg_cs: Node
PDG of the content script.
- pdg_bp: Node
PDG of the background page.
- graph: graphviz object
Graph object.
- save_path: str
Path of the file to store the EDG in.
- attributes: bool
Whether to display the leaf attributes or not. Default: True.
"""
dot = graphviz.Digraph()
pdg_extension = copy.copy(pdg_cs.children)
pdg_extension.extend(pdg_bp.children)
for node in pdg_extension:
dot = produce_cfg_one_child(child=node, data_flow=True, graph=graph, attributes=attributes)
try:
if save_path is None:
dot.view()
else:
dot.render(save_path, view=False)
graphviz.render(filepath=save_path, engine='dot', format='eps')
dot.clear()
except:
pass