-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcfg.py
71 lines (59 loc) · 2.06 KB
/
cfg.py
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
import json
import sys
"""
Build a list of basic blocks from the instructions of a function
Returns a dictionary mapping a block's heading label to it corresopnding block
"""
def block(fn):
# Store all labeled blocks
blocks = {}
label_order = ["start"]
# Traverse each block and add it
curr_label = "start"
curr = []
for insn in fn["instrs"]:
#End block if it is a label or a terminator
if "label" in insn:
label_order.append(insn["label"])
if curr != []:
blocks[curr_label] = curr
curr_label = insn["label"] # Update new label
curr = []
elif "op" in insn and insn["op"] in ["jmp", "br"]:
curr.append(insn)
blocks[curr_label] = curr
curr = []
# If not, continue to build up block
else:
curr.append(insn)
blocks[curr_label] = curr
return blocks, label_order
""" Build a control-flow graph mapping labels to labels. """
def gen_cfg(blocked, labels):
# Store dictionary form of CFG
graph = {lbl : [] for lbl in blocked}
# If block ends with a jump or branch, add those neighbors; otherwise just add the chronological next neighbor
for key in blocked:
if blocked[key]:
move = blocked[key][-1]
if 'op' in move and move['op'] in ['jmp', 'br']:
for neighbor in move['labels']:
graph[key].append(neighbor)
else:
idx = labels.index(key)
if idx < len(labels)-1:
graph[key].append(labels[labels.index(key)+1])
return graph
def main():
if len(sys.argv) < 2:
print("Usage: python bril_cfg.py <bril_json_file>")
sys.exit(1)
with open(sys.argv[1], "r") as f:
bril_program = json.load(f)
for function in bril_program['functions']:
print(f"\nFunction: @{function['name']}")
blocks, labels = block(function)
cfg = gen_cfg(blocks, labels)
print(cfg)
if __name__ == "__main__":
main()