使用SciTools understand批量生成程序调用图
注 :本文为原创内容,部分图片/文字引用自官方文档/软件,如有侵权请联系作者进行删除。
1,导言
understand作为一款优秀的源码静态分析工具,能够非常方便地生成各类调用关系图,比如实体调用关系、方法调用/被调用链、程序流程图等等。
但是在阅读一个复杂项目的源代码时,每每遇到复杂的函数的时候都需要手动打开相关图形进行查看函数调用关系,实属麻烦。还好,understand提供了接口文件,能够让我们自己编写脚本文件来批量生成各种图形文件。
本文的重点不在于介绍understand软件的用法,并且假设你已经能够较为熟练地使用understand进行代码分析,并拥有基本的问题解决能力和代码编写能力。
2,接口文件
本文主要介绍windows下python接口的使用教程,除了python接口之外,understand还提供了java、perl和c的接口,由于python简单易用,因此本文使用python进行编码(关键是笔者也不会java和perl╮(╯_╰)╭。。。 )。
understand软件的接口说明文档(及教程)的存放地址为安装目录SciTools下的doc\manuals文件夹内,图示2.1~2.3为python文件夹内的understand.html文件的部分内容。
2.1 类和方法的描述:
![](https://i-blog.csdnimg.cn/blog_migrate/f07344e6bea892f404387348194cf90e.png#pic_center)
图2.1是understand模块类和方法的罗列,我们在编写python代码以实现绘图功能的时候,主要用到了understand.open(),understand.Db,understand.Ent这几个对象,具体内容请查看understand.html文件。
2.2 示例:
![](https://i-blog.csdnimg.cn/blog_migrate/3934376697df59de118494ee61b76b51.png#pic_center)
图2.2是文档给出的几个简单代码示例。
2.3 绘图方法
![](https://i-blog.csdnimg.cn/blog_migrate/14be0b24422337206b3d8f95c3329d9e.png#pic_center)
图2.3.1是绘图中最关键的方法draw()的用法介绍,从这段描述可以知道,方法draw的第一个参数graph为需要绘制的图形的类型,参数名必须与understand软件中存在的参数一致(不需要代码和软件配置的一致),可配置的参数如图2.3.2红框所示:
![](https://i-blog.csdnimg.cn/blog_migrate/5d91c17d01c2bf6501ac95179d3934bf.png#pic_center)
方法draw的第二个参数filename为所生成图片的名称,第三个参数(可选)为该类型图形的具体参数,参数名必须与understand软件中存在的参数一致(不需要代码和软件配置的一致),且必须以“name=value”的形式对方法传参,可配置的参数如图2.3.3所示:
![](https://i-blog.csdnimg.cn/blog_migrate/ad5298b832b80c74c482634f9bc310c5.png#pic_center)
2.4 实例
综上,方法draw的调用可编写为:
func.draw("Control Flow", file, " Collapse=On; \
Comments=On; \
Entity Name=On; \
Filter=On; \
Labels=On; \
Passive=On; \
Source Code=On ")
这里对象func为understand.Ent类型,完整代码请看 这里。
3,环境搭建
3.1,Python环境搭建:
略(笔者使用的Anaconda)
3.2,Qt环境搭建:
略(笔者使用的Qt5.4,不过好像不安装Qt也是可以的? )
3.3,添加环境变量
使用python调用understand的接口时,需要将understand提供的相关文件添加到windows环境变量中,如下图3.3.1和图3.3.2所示:
![](https://i-blog.csdnimg.cn/blog_migrate/b65520ff8f15147518614d54cc5824dc.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/106157dbb72e3ba6690d733e6bfa04a5.png#pic_center)
图3.3.1为understand命令行运行所需环境变量,在Path中进行添加,此变量在python中import understand模块时需要用到。
图3.3.2为生成图形时调用到的Qt相关的动态库文件。
4,脚本编写
在编写python代码之前,还需要相关文件,如图4.1所示:
第一项为python代码文件。
第二项为understand udb数据文件,也即是understand的工程文件,需要注意的是,在使用python处理该udb文件前,该udb文件应该处于已分析完成的状态。
第三项为understand提供的接口文件,位于目录SciTools\bin\pc-win64\Python\understand.pyd建议此三个文件放到一起进行执行。
附上笔者编写的一段简单代码,用于批量生成Control Flow图和Butterfly图:
注:
- 此代码自动识别本级目录和上级目录的udb文件(只限于一个udb文件)。
- 代码运行时windows显示设置缩放请设置为100%,否则可能会出现生成图片排版内容异常的问题。
import understand
import os
import glob
from pathlib import Path
workspace = os.path.abspath('./')#获取工作目录路径
files_list=glob.glob("*.udb")#获取工作目录udb文件
if(len(files_list) > 1):
print("工作目录文件数量过多")
os._exit(0)
elif (len(files_list) == 1):
db = understand.open(files_list[0])#在工作目录打开udb
else:
os.chdir('../')#切换到上级目录
files_list=glob.glob("*.udb")#获取上级目录udb文件
if(len(files_list) > 1):
print("上级目录文件数量过多")
os._exit(0)
elif (len(files_list) == 1):
db = understand.open(files_list[0])#在上级目录打开udb
else:
print("无文件")
os._exit(0)
os.chdir(workspace)#切换回工作目录
#创建流程图
my_file = Path("./Control_Flow")
if my_file.is_dir():
print("流程图目录已存在")
else:
os.makedirs('./Control_Flow')#创建流程图文件夹
os.chdir('./Control_Flow')#切换到子目录
for func in db.ents("function"):
file = "cf_" + func.name() + ".png"
print(func.longname(),"->",file)
try:
func.draw("Control Flow", file, " Collapse=On; \
Comments=On; \
Entity Name=On; \
Filter=On; \
Labels=On; \
Passive=On; \
Source Code=On ")
except:
print("流程图创建失败")
os.chdir('../')#完成后切换回工作目录
#创建Butterfly图
my_file = Path("./Butterfly")
if my_file.is_dir():
print("Butterfly图目录已存在")
else:
os.makedirs('./Butterfly')#创建Butterfly文件夹
os.chdir('./Butterfly')#切换到子目录
for func in db.ents("function"):
file = "bf_" + func.name() + ".png"
print(func.longname(),"->",file)
try:
func.draw("Butterfly", file, " Call Depth=10; \
Callby Depth=10; \
File Name=Shortname; \
Intrinsic Functions=On; \
Name=Shortname; \
Random Edge Color=On; \
Unresolved=On; \
Virtual Calls=On; ")
except:
print("Butterfly图创建失败")
os.chdir('../')#完成后切换回工作目录
2020.8.29
by:Rei_ikari