Commit eb7b5159 authored by Gaurav Kukreja's avatar Gaurav Kukreja

Implemented draw_cfg.py using graphviz to generate graphs

Signed-off-by: Gaurav Kukreja's avatarGaurav Kukreja <gaurav@gauravk.in>
parent ff4c6e4b
...@@ -31,6 +31,10 @@ class BasicBlock: ...@@ -31,6 +31,10 @@ class BasicBlock:
self.nestingLevel = -1 self.nestingLevel = -1
self.hasConditionalExec = 0 self.hasConditionalExec = 0
def mapISCTo(self, blockInd):
# ISC Blocks will map to only one block in Obj
self.mapsTo = [blockInd]
class ControlFlowGraph: class ControlFlowGraph:
def __init__(self, listBlocks, listEdges): def __init__(self, listBlocks, listEdges):
......
#-----------------------------------------------------------------
# draw_cfg.py : This program generates the .dot file used by graphviz tool, to
# generate the graphs
#-----------------------------------------------------------------
import sys
import re
from optparse import OptionParser
from enum import Enum
import logging
from subprocess import call
from cfg_isc import parse_isc
from cfg_binary import parse_binary
from cfg import *
re_sourceFileName = re.compile("(\w*/)*(\w*).(\w*)")
colorUnmapped = "white"
listColorsMapped = ["aquamarine4",
"bisque3",
"blue1",
"brown",
"cadetblue",
"chartreuse",
"coral",
"cyan3",
"darkgoldenrod3",
"darkorchid1",
"darkslateblue",
"deeppink1",
"firebrick4",
"darkgreen",
"firebrick1",
"darkorange2",
"yellow",
"turquoise2",
"pink1",
"palegreen2",
"navy",
"maroon2",
"indigo",
"olivedrab3"]
class FileType(Enum):
min_invalid = 0
objdump = 1
cSource = 2
def draw_cfg(function, outputPath=None):
sourceFileName = function.fileName
m = re_sourceFileName.match(sourceFileName)
if m is not None:
if m.group(3) == "objdump":
fileType = FileType.objdump
fileNamePrefix = "obj_"+m.group(2)+"_"+function.functionName
elif m.group(3) == "c":
fileType = FileType.cSource
fileNamePrefix = "isc_"+m.group(2)+"_"+function.functionName
else:
logging.error("\t %s: File Type could not be identified." % sourceFileName)
logging.error("File Extension must contain \"objdump\" or \"c\"")
return -1
else:
logging.error("File Name could not be understood!")
return -1
if not outputPath:
outputPath = "/tmp/"
dotFileName = outputPath + fileNamePrefix + ".dot"
psFileName = outputPath + fileNamePrefix + ".ps"
dotFile = open(dotFileName, "w")
dotFile.write("digraph "+fileNamePrefix+" {\n")
i = 0
for block in function.cfg.listBlocks:
dotFile.write("\t")
dotFile.write(block.name)
if fileType == FileType.cSource:
if block.mapsTo:
colorName = listColorsMapped[block.mapsTo[0]]
else:
colorName = colorUnmapped
elif fileType == FileType.objdump:
colorName = listColorsMapped[i]
else:
colorName = colorUnmapped
dotFile.write(" [")
dotFile.write("fillcolor="+colorName+", style=filled")
dotFile.write("]")
dotFile.write(";")
dotFile.write("\n")
i = i + 1
for edge in function.cfg.listEdges:
dotFile.write("\t")
dotFile.write(function.cfg.listBlocks[edge.fromBlockIndex].name+
" -> "+
function.cfg.listBlocks[edge.toBlockIndex].name + ";")
dotFile.write("\n")
for i in range(len(function.cfg.listBlocks)):
blockAtNestingLevelFound = 0
dotFile.write("\t{rank=same; ")
for block in function.cfg.listBlocks:
if block.nestingLevel == i:
dotFile.write(block.name+" ")
blockAtNestingLevelFound = 1
dotFile.write("}\n")
if blockAtNestingLevelFound == 0:
break
dotFile.write("}\n")
dotFile.close()
call(args=["dot", "-Tps", dotFileName, "-o", psFileName])
return psFileName
def main(listInputFileNames, outputPath=None):
listFunctions = []
for fileName in listInputFileNames:
m = re_sourceFileName.match(fileName)
if m is not None:
if m.group(3) == "objdump":
(retListFunctions, retLineForAddress) = parse_binary(fileName)
listFunctions = listFunctions + retListFunctions
elif m.group(3) == "c":
listFunctions = listFunctions + parse_isc(fileName)
else:
logging.error("\t %s: File Type could not be identified." % sourceFileName)
logging.error("File Extension must contain \"objdump\" or \"c\"")
return -1
else:
logging.error("File Name could not be understood!")
return -1
for function in listFunctions:
psFileName = draw_cfg(function, outputPath=outputPath)
call(args=["evince", psFileName])
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
optparser = OptionParser()
optparser.add_option("-i", "--input", action="append", dest="listInputFileNames",
type="string", help="Input File Name to draw CFG for",
metavar="FILENAME")
optparser.add_option("-p", "--output_path", action="store", dest="outputPath",
type="string", help="Path of directory to store output files in",
metavar="OUTPUT_PATH")
(options, args) = optparser.parse_args()
if not options.listInputFileNames:
optparser.error("Input Files not provided!")
listInputFileNames = options.listInputFileNames
outputPath = options.outputPath
main(listInputFileNames, outputPath=outputPath)
\ No newline at end of file
...@@ -8,7 +8,8 @@ from PyQt4 import QtGui, QtCore ...@@ -8,7 +8,8 @@ from PyQt4 import QtGui, QtCore
from cfg_binary import parse_binary, print_debug_binary from cfg_binary import parse_binary, print_debug_binary
from cfg_isc import parse_isc, print_debug_isc from cfg_isc import parse_isc, print_debug_isc
from display_cfg import display_cfgs # from display_cfg import display_cfgs
from draw_cfg import draw_cfg
###################################################### ######################################################
## Global Variables ## Global Variables
...@@ -156,7 +157,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -156,7 +157,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
# If both blocks return, mapping found! # If both blocks return, mapping found!
if (blockISC.isReturning == 1 and blockObj.isReturning == 1): if (blockISC.isReturning == 1 and blockObj.isReturning == 1):
logging.debug("\t %s::%s Both blocks return! Matched!" % (blockISC.name, blockObj.name)) logging.debug("\t %s::%s Both blocks return! Matched!" % (blockISC.name, blockObj.name))
blockISC.mapsTo.append(blockIndObj) # blockISC.mapsTo.append(blockIndObj)
blockISC.mapISCTo(blockIndObj)
blockObj.mapsTo.append(blockIndISC) blockObj.mapsTo.append(blockIndISC)
return 0 return 0
...@@ -168,7 +170,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -168,7 +170,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
if (succBlockObj.isReturning == 1): if (succBlockObj.isReturning == 1):
logging.debug("/t ISC:%s returns, and is mapped to both OBJ:%s and OBJ:%s" logging.debug("/t ISC:%s returns, and is mapped to both OBJ:%s and OBJ:%s"
% (blockISC.name, blockObj.name, succBlockObj.name)) % (blockISC.name, blockObj.name, succBlockObj.name))
blockISC.mapsTo.append(blockIndObj) #blockISC.mapsTo.append(blockIndObj)
blockISC.mapISCTo(blockIndObj)
blockObj.mapsTo.append(blockIndISC) blockObj.mapsTo.append(blockIndISC)
succBlockObj.mapsTo.append(blockIndISC) succBlockObj.mapsTo.append(blockIndISC)
return 0 return 0
...@@ -184,9 +187,11 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -184,9 +187,11 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
if (succBlockISC.isReturning == 1): if (succBlockISC.isReturning == 1):
logging.debug("/t OBJ:%s returns, and is mapped to ISC:%s" logging.debug("/t OBJ:%s returns, and is mapped to ISC:%s"
% (blockObj.name, succBlockISC.name)) % (blockObj.name, succBlockISC.name))
blockISC.mapsTo.append(blockIndObj) # blockISC.mapsTo.append(blockIndObj)
succBlockISC.mapsTo.append(blockIndObj) blockISC.mapISCTo(blockIndObj)
blockObj.mapsTo.append(blockIndISC) # succBlockISC.mapsTo.append(blockIndObj)
succBlockISC.mapISCTo(blockIndObj)
blockObj.mapsTo.append(listSuccBlocksISC[0])
return 0 return 0
else: else:
# Mapping not found! # Mapping not found!
...@@ -267,7 +272,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -267,7 +272,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
logging.debug("\t %s::%s Back Edge Found through split block in ISC!" % logging.debug("\t %s::%s Back Edge Found through split block in ISC!" %
(blockISC.name, blockObj.name)) (blockISC.name, blockObj.name))
# Match current ISC block (split block) to predecessor of current Obj Block # Match current ISC block (split block) to predecessor of current Obj Block
blockISC.mapsTo.append(mappingStackObj[-1][0]) # blockISC.mapsTo.append(mappingStackObj[-1][0])
blockISC.mapISCTo(mappingStackObj[-1][0])
# TODO: Is there something else to do here? # TODO: Is there something else to do here?
return 0 return 0
else: else:
...@@ -344,9 +350,12 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -344,9 +350,12 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
if (mapping(cfgISC, succ2BlockIndISC, cfgObj, blockIndObj, mergedLevelsISC + 1) == 0): if (mapping(cfgISC, succ2BlockIndISC, cfgObj, blockIndObj, mergedLevelsISC + 1) == 0):
logging.debug("\t\t\t %s::%s Mapping Found (CondExec: Case 1)!" % logging.debug("\t\t\t %s::%s Mapping Found (CondExec: Case 1)!" %
(blockISC.name, blockObj.name)) (blockISC.name, blockObj.name))
blockISC.mapsTo.append(blockIndObj) # blockISC.mapsTo.append(blockIndObj)
cfgISC.listBlocks[succ1BlockIndISC].mapsTo.append(blockIndObj) blockISC.mapISCTo(blockIndObj)
cfgISC.listBlocks[succ2BlockIndISC].mapsTo.append(blockIndObj) # cfgISC.listBlocks[succ1BlockIndISC].mapsTo.append(blockIndObj)
cfgISC.listBlocks[succ1BlockIndISC].mapISCTo(blockIndObj)
# cfgISC.listBlocks[succ2BlockIndISC].mapsTo.append(blockIndObj)
cfgISC.listBlocks[succ2BlockIndISC].mapISCTo(blockIndObj)
blockObj.mapsTo.append(blockIndISC) blockObj.mapsTo.append(blockIndISC)
mappingStackISC.pop() mappingStackISC.pop()
mappingStackISC.pop() mappingStackISC.pop()
...@@ -367,10 +376,14 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -367,10 +376,14 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
cfgObj, blockIndObj, mergedLevelsISC + 2) == 0): cfgObj, blockIndObj, mergedLevelsISC + 2) == 0):
logging.debug("\t\t\t %s::%s Mapping Found (CondExec: Case 2)!" % logging.debug("\t\t\t %s::%s Mapping Found (CondExec: Case 2)!" %
(blockISC.name, blockObj.name)) (blockISC.name, blockObj.name))
blockISC.mapsTo.append(blockIndObj) # blockISC.mapsTo.append(blockIndObj)
cfgISC.listBlocks[succ1BlockIndISC].mapsTo.append(blockIndObj) # cfgISC.listBlocks[succ1BlockIndISC].mapsTo.append(blockIndObj)
cfgISC.listBlocks[succ2BlockIndISC].mapsTo.append(blockIndObj) # cfgISC.listBlocks[succ2BlockIndISC].mapsTo.append(blockIndObj)
cfgISC.listBlocks[succSucc1BlockIndISC].mapsTo.append(blockIndObj) # cfgISC.listBlocks[succSucc1BlockIndISC].mapsTo.append(blockIndObj)
blockISC.mapISCTo(blockIndObj)
cfgISC.listBlocks[succ1BlockIndISC].mapISCTo(blockIndObj)
cfgISC.listBlocks[succ2BlockIndISC].mapISCTo(blockIndObj)
cfgISC.listBlocks[succSucc1BlockIndISC].mapISCTo(blockIndObj)
blockObj.mapsTo.append(blockIndISC) blockObj.mapsTo.append(blockIndISC)
mappingStackISC.pop() mappingStackISC.pop()
mappingStackISC.pop() mappingStackISC.pop()
...@@ -394,10 +407,17 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -394,10 +407,17 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
if cfgObj.listBlocks[succBlockIndObj].mapsTo: if cfgObj.listBlocks[succBlockIndObj].mapsTo:
if succBlockIndISC in cfgObj.listBlocks[succBlockIndObj].mapsTo: if succBlockIndISC in cfgObj.listBlocks[succBlockIndObj].mapsTo:
# Both have already been mapped. # Both have already been mapped.
logging.debug("\t\t %s::%s DFT: Successor blocks %s::%s have already been mapped to each other!" %
(blockISC.name, blockObj.name,
cfgISC.listBlocks[succBlockIndISC].name,
cfgObj.listBlocks[succBlockIndObj].name))
succBlockISCMatchFoundUsingDFT = 1 succBlockISCMatchFoundUsingDFT = 1
break # to continue matching the next successor in ISC break # to continue matching the next successor in ISC
else: else:
# Obj has been mapped to some other node. logging.debug("\t\t %s::%s DFT: Successor blocks Obj:%s have already been mapped to some other ISC block than current ISC:%s!" %
(blockISC.name, blockObj.name,
cfgObj.listBlocks[succBlockIndObj].name,
cfgISC.listBlocks[succBlockIndISC].name))
continue continue
else: else:
# Obj blocked hasn't yet been mapped. Try mapping # Obj blocked hasn't yet been mapped. Try mapping
...@@ -410,7 +430,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -410,7 +430,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
if (mapping(cfgISC, succBlockIndISC, if (mapping(cfgISC, succBlockIndISC,
cfgObj, succBlockIndObj, cfgObj, succBlockIndObj,
mergedLevelsISC) == 0): mergedLevelsISC) == 0):
cfgISC.listBlocks[succBlockIndISC].mapsTo.append(succBlockIndObj) # cfgISC.listBlocks[succBlockIndISC].mapsTo.append(succBlockIndObj)
cfgISC.listBlocks[succBlockIndISC].mapISCTo(succBlockIndObj)
cfgObj.listBlocks[succBlockIndObj].mapsTo.append(succBlockIndISC) cfgObj.listBlocks[succBlockIndObj].mapsTo.append(succBlockIndISC)
mappingStackISC.pop() mappingStackISC.pop()
mappingStackObj.pop() mappingStackObj.pop()
...@@ -437,7 +458,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC): ...@@ -437,7 +458,8 @@ def mapping(cfgISC, blockIndISC, cfgObj, blockIndObj, mergedLevelsISC):
if allSuccBlocksISCMatchingFound == 1: if allSuccBlocksISCMatchingFound == 1:
# Mapping was found for each successor block of blockISC # Mapping was found for each successor block of blockISC
blockISC.mapsTo.append(blockIndObj) # blockISC.mapsTo.append(blockIndObj)
blockISC.mapISCTo(blockIndObj)
blockObj.mapsTo.append(blockIndISC) blockObj.mapsTo.append(blockIndISC)
return 0 return 0
else: else:
...@@ -546,10 +568,6 @@ def map_cfg(listISCFileNames, listObjdumpFileNames, listBinaryFileNames): ...@@ -546,10 +568,6 @@ def map_cfg(listISCFileNames, listObjdumpFileNames, listBinaryFileNames):
logging.error("*** Stack is not empty after mapping function returns ***") logging.error("*** Stack is not empty after mapping function returns ***")
printDebugMapCFG(listISCFunctions, listObjdumpFunctions, gdbMapping) printDebugMapCFG(listISCFunctions, listObjdumpFunctions, gdbMapping)
#
for funcISC in listISCFunctions:
funcObj = find(lambda fn: fn.functionName == funcISC.functionName, listObjdumpFunctions)
display_cfgs(app, funcISC.cfg, funcObj.cfg, "%s" % funcISC.functionName)
return listISCFunctions, listObjdumpFunctions return listISCFunctions, listObjdumpFunctions
...@@ -570,6 +588,10 @@ if __name__ == "__main__": ...@@ -570,6 +588,10 @@ if __name__ == "__main__":
type="string", dest="listBinaryFileNames", type="string", dest="listBinaryFileNames",
help="Binary Filename. For multiple files, use -b <filename> multiple times.", help="Binary Filename. For multiple files, use -b <filename> multiple times.",
metavar="FILE") metavar="FILE")
optparser.add_option("-p", "--output_path", action="store",
type="string", dest="outputPath",
help="Output path to store graphs generated.",
metavar="PATH")
(options, args) = optparser.parse_args() (options, args) = optparser.parse_args()
...@@ -579,6 +601,16 @@ if __name__ == "__main__": ...@@ -579,6 +601,16 @@ if __name__ == "__main__":
listISCFileNames = options.listISCFileNames listISCFileNames = options.listISCFileNames
listObjdumpFileNames = options.listObjdumpFileNames listObjdumpFileNames = options.listObjdumpFileNames
listBinaryFileNames = options.listBinaryFileNames listBinaryFileNames = options.listBinaryFileNames
outputPath = options.outputPath
(listISCFunctions, listObjdumpFunctions) = map_cfg(listISCFileNames, listObjdumpFileNames, listBinaryFileNames)
for funcISC in listISCFunctions:
funcObj = find(lambda fn: fn.functionName == funcISC.functionName, listObjdumpFunctions)
# display_cfgs(app, funcISC.cfg, funcObj.cfg, "%s" % funcISC.functionName)
psISCFileName = draw_cfg(funcISC, outputPath)
psObjFileName = draw_cfg(funcObj, outputPath)
call(args = ["evince", psISCFileName, psObjFileName])
map_cfg(listISCFileNames, listObjdumpFileNames, listBinaryFileNames)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment