# asm control flow grpah domator tree
要做靜態分析要找出相似的basic block想以肉眼進行判斷 ,我們進一步透過tarjan-algorithm找出支配樹的節點,意味者可以找到cfg裡面的loop.
https://www.geeksforgeeks.org/tarjan-algorithm-find-strongly-connected-components/
![](https://i.imgur.com/7ddciYx.png)
主要做了一個bb index 的mapping ,再傳遞給寫好的tarjan演算法即可找出cfg裡的loop
# tarjan
重新讓這演算法可以紀錄答案到list
```python
#This class represents an directed graph
# using adjacency list representation
class Graph:
def __init__(self,vertices,):
#No. of vertices
self.V= vertices
self.ans = []
# default dictionary to store graph
self.graph = defaultdict(list)
self.Time = 0
# function to add an edge to graph
def addEdge(self,u,v):
self.graph[u].append(v)
'''A recursive function that find finds and prints strongly connected
components using DFS traversal
u --> The vertex to be visited next
disc[] --> Stores discovery times of visited vertices
low[] -- >> earliest visited vertex (the vertex with minimum
discovery time) that can be reached from subtree
rooted with current vertex
st -- >> To store all the connected ancestors (could be part
of SCC)
stackMember[] --> bit/index array for faster check whether
a node is in stack
'''
def SCCUtil(self,u, low, disc, stackMember, st):
# Initialize discovery time and low value
disc[u] = self.Time
low[u] = self.Time
self.Time += 1
stackMember[u] = True
st.append(u)
# Go through all vertices adjacent to this
for v in self.graph[u]:
# If v is not visited yet, then recur for it
if disc[v] == -1 :
self.SCCUtil(v, low, disc, stackMember, st)
# Check if the subtree rooted with v has a connection to
# one of the ancestors of u
# Case 1 (per above discussion on Disc and Low value)
low[u] = min(low[u], low[v])
elif stackMember[v] == True:
'''Update low value of 'u' only if 'v' is still in stack
(i.e. it's a back edge, not cross edge).
Case 2 (per above discussion on Disc and Low value) '''
low[u] = min(low[u], disc[v])
# head node found, pop the stack and print an SCC
w = -1 #To store stack extracted vertices
anscell = []
if low[u] == disc[u]:
while w != u:
w = st.pop()
print (w, end=" ")
anscell.append(w)
stackMember[w] = False
self.ans.append(anscell)
print()
#The function to do DFS traversal.
# It uses recursive SCCUtil()
def SCC(self):
# Mark all the vertices as not visited
# and Initialize parent and visited,
# and ap(articulation point) arrays
disc = [-1] * (self.V)
low = [-1] * (self.V)
stackMember = [False] * (self.V)
st =[]
# Call the recursive helper function
# to find articulation points
# in DFS tree rooted with vertex 'i'
time_disc=[]
for i in range(self.V):
if disc[i] == -1:
self.SCCUtil(i, low, disc, stackMember, st)
time_disc.append([i,disc[i]])
for x in time_disc:
print(x)
print("time")
```
# cfg5
這邊注意
```
if(jkey>cur_bb_index):
tarjans.addEdge(key, jkey)
```
我故意讓當前節點jump 只能大於目前節點,類似強迫cfg只能往下走,這樣 tarjan 就不會把整個fucntion當成連通(一組解)
```python=
def draw_cfg5(function_name,get_print_list, view):
dot=None
dot2=None
index =0
dot = Digraph(name=function_name, comment=function_name, engine='dot')
dot2 = Digraph(name=function_name, comment=function_name, engine='dot')
# dot.graph_attr['rankdir'] = 'LR'
dot.attr('graph', label=function_name)
dot2.attr('graph', label=function_name)
total_node =0
index =0
cur_bb_index=0
for get_child in get_print_list:
for address, basic_block in get_child[1].items():
key = str(address)
graph[key] =[]
total_node+=1
for basic_block in get_child[1].values():
bb_index_mapping[str(cur_bb_index)] =str(basic_block.key)
cur_bb_index+=1
cur_bb_index=0
break
cur_bb_index=0
tarjansans=[]
# Create a graph given in the above diagram
tarjans = Graph(total_node)
for get_child in get_print_list:
for basic_block in get_child[1].values():
if basic_block.jump_edge:
key=0
jkey=0
nojkey=0
if basic_block.no_jump_edge is not None:
for x in bb_index_mapping:
if(bb_index_mapping[x] == str(basic_block.key)):
key=int(x)
elif(bb_index_mapping[x] == str(basic_block.no_jump_edge)):
nojkey=int(x)
tarjans.addEdge(key, nojkey)
for x in bb_index_mapping:
if(bb_index_mapping[x] == str(basic_block.key)):
key=int(x)
elif(bb_index_mapping[x] == str(basic_block.jump_edge)):
jkey=int(x)
if(jkey>cur_bb_index):
tarjans.addEdge(key, jkey)
elif basic_block.no_jump_edge:
key=0
nojkey=0
for x in bb_index_mapping:
if(bb_index_mapping[x] == str(basic_block.key)):
key=int(x)
elif(bb_index_mapping[x] == str(basic_block.no_jump_edge)):
nojkey=int(x)
tarjans.addEdge(key, nojkey)
cur_bb_index=0
break
print ("SSC in first graph ")
tarjans.SCC()
print(total_node)
print ("tarjans")
count_tarjans_ans_index=0
for x in tarjans.ans:
if(len (x)>2):
count_tarjans_ans_index+=1
green = Color("green")
colors = list(green.range_to(Color("blue"),count_tarjans_ans_index+1))
for get_child in get_print_list:
for address, basic_block in get_child[1].items():
key = str(address)
newkey =""
tarjankey=0
find =0
for x in bb_index_mapping:
if(bb_index_mapping[x] == str(basic_block.key)):
tarjankey=int(x)
break
count_tarjans_ans_index=0
for x in tarjans.ans:
if(len (x)>2):
if(tarjankey in x):
find=1
print("tarjanskey:"+str(tarjankey))
break
count_tarjans_ans_index+=1
if(find==0):
dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor="white")
else:
dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str(colors[count_tarjans_ans_index]))
for basic_block in get_child[1].values():
if basic_block.jump_edge:
if basic_block.no_jump_edge is not None:
dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge))
elif basic_block.no_jump_edge:
dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
break
if view:
dot.format = 'gv'
with tempfile.NamedTemporaryFile(mode='w+b', prefix=function_name) as filename:
# dot.view(filename.name)
print(f'Opening a file {filename.name}.{dot.format} with default viewer. Don\'t forget to delete it later.')
else:
dot.format = 'svg'
dot.render(filename=function_name, cleanup=True)
print(f'Saved CFG to a file {function_name}.{dot.format}')
replaceline_0(f'{function_name}.{dot.format}', f'back{function_name}.{dot.format}')
redundant(f'back{function_name}.{dot.format}', f'new{function_name}.{dot.format}')
# replaceline(f'back{function_name}.{dot.format}', f'new{function_name}.{dot.format}')
print(f'Saved new CFG to a file new{function_name}.{dot.format}')
```
結果呈現
![](https://i.imgur.com/7haeJbu.png)
,確實可以找loop的開頭與結尾,這項功能應該又可以衍生出更多的演算法可以做靜態分析,知道某些區間可能有unrooling loop..。