call graph using python and cscope

R

Roland Puntaier

"""
Sometimes it is nice to have the data used by cscope accessible in a
programatic way.
The following python script extract the "functions called" information
from cscope (function: callGraph)
and produced an html file from them.

from csCallGraph import *
acg=callGraph(entryFun,workingDir)

entryFun is the function to start with (e.g. main)
workingDir is the directory where cscope.out is located

As a script it can be called like:
csCallGraph main > myprogram.html
"""

import subprocess , os, sys

def functionsCalled(entryFun,workingDir):
cmd = "cscope -d -l -L -2%s"%entryFun
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True,
cwd=workingDir)
csoutput= process.stdout.read()
del process
cslines=[arr.strip().split(' ') for arr in csoutput.split('\n') if
len(arr.split(' '))>1]
funsCalled={}
for fl in cslines:
if funsCalled.has_key(fl[0]):
funsCalled[fl[0]]|=set([fl[1]])
else:
funsCalled[fl[0]]=set([fl[1]])
allFuns=set(map(lambda x:x[1],cslines))
return (allFuns,funsCalled)

def callGraph(entryFun,workingDir,cg={}):
if not cg.has_key(entryFun):
allFuns,funsCalled=functionsCalled(entryFun,workingDir)
cg[entryFun]=funsCalled
for af in allFuns:
cg=callGraph(af,workingDir,cg)
return cg

def textCallGraph(acg):
innerFuns=[(f,d,len(reduce(lambda x,y:x|y,d.values()))) for f,d in
acg.items() if len(d)>0 ]
leafFuns=[(f,d,0) for f,d in acg.items() if not len(d)>0 ]
innerFuns.sort(lambda x,y: y[2]-x[2])
innerLen=len(innerFuns)
leafLen=len(leafFuns)
title=lambda aFun: '\n' + aFun + '\n' + '-'*len(aFun)
def ff(aFun,funsCalled):
fileFuns=zip(funsCalled.keys(),[' '+',\n '.join(funsCalledInFile)
for funsCalledInFile in funsCalled.values()])
funIn=lambda f: '\n%s in '%f
return title(aFun) + funIn(aFun) + funIn(aFun).join(map(lambda
x:'%s:\n%s'%(x[0],x[1]),fileFuns))
strInner='\n'.join([ff(f[0],f[1]) for f in innerFuns])
strLeaves='\n'.join(map(lambda x:title(x[0]),leafFuns))
return strInner+'\n'+strLeaves

def funWeights(acg):
funWeights=dict([(f,reduce(lambda x,y:x|y,d.values())) for f,d in
acg.items() if len(d)>0 ]+
[(f,[]) for f,d in acg.items() if not len(d)>0 ])
weights={}
def calcWeights(af):
if not weights.has_key(af):
subFuns=funWeights[af]
weights[af]=1
for f in subFuns:
calcWeights(f)
weights[af]+=weights[f]
for af in funWeights.keys(): calcWeights(af)
return weights

def htmlCallGraph(acg):
funW=funWeights(acg)
innerFuns=[(f,d,funW[f]) for f,d in acg.items() if len(d)>0 ]
leafFuns=[(f,d,0) for f,d in acg.items() if not len(d)>0 ]
#innerFuns.sort(lambda x,y: y[2]-x[2]))
def cfun(a,b):
if b > a:
return 1
elif b < a:
return -1
return 0
innerFuns.sort(lambda x,y: cfun(x[2],y[2]))
innerLen=len(innerFuns)
leafLen=len(leafFuns)
funDict=dict(zip(map(lambda x:x[0],innerFuns)+map(lambda
x:x[0],leafFuns),range(innerLen+leafLen)))
title=lambda aFun: '<hr><h4><a name=#f%i'%funDict[aFun]+'>' + aFun + '
(%i)'%funW[aFun] + '</a></h4>\n'
def ff(aFun,funsCalled):
fun=lambda y:'<a href=#f%i'%funDict[y]+'
style="text-decoration:none">'+y+'</a>'
fileFuns=zip(funsCalled.keys(),[',\n'.join(map(fun,funsCalledInFile))
for funsCalledInFile in funsCalled.values()])
funIn=lambda f: '<br><em>%s</em> in '%f
return title(aFun) + funIn(aFun) + funIn(aFun).join(map(lambda
x:'%s:\n%s'%(x[0],x[1]),fileFuns))
strInner='\n'.join([ff(f[0],f[1]) for f in innerFuns])
strLeaves='\n'.join(map(lambda x:title(x[0]),leafFuns))
return '<html>\n<body>\n'+strInner+'\n'+strLeaves+"</body>\n</html>\n"

if __name__ == '__main__':
if len(sys.argv) < 2:
print 'Usage: csGragh.py entryFunction'
sys.exit()
entryFun=sys.argv[1]
workingDir=os.getcwd()
acg=callGraph(entryFun,workingDir)
print htmlCallGraph(acg)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top