Understand分析完项目后,可以把函数之间的调用和被调用关系直接画成图,用来查入口函数、追踪多层调用链,或者判断某个函数改动后会影响哪些位置。调用关系图显示不完整时,先不要把问题归到图形界面上,因为图中的连线来自项目数据库里的实体和引用记录。源码解析不完整、宏定义不对、头文件缺失,都会让原本存在的函数调用没有进入分析结果。
一、Understand怎么生成调用关系图
Understand可以从单个函数、文件、类等不同对象打开调用关系图。只想追某个函数时,直接从源码打开会更方便;想看一个文件内部或整个模块的调用关系,可以从文件和Architecture层级继续分析。
1、查看某个函数调用了哪些函数
①在Understand中打开目标源码文件。
②找到准备分析的函数,把光标放到函数名称上。
③右键函数,选择【Graphical Views】。
④选择【Calls】,生成当前函数向外调用的关系图。
⑤图中根节点就是当前函数,向外连接的节点表示它调用的其他函数。
⑥想继续查看下一层调用时,展开对应节点。
⑦调用层级比较多时,在图形工具栏中调整【Depth】,减少一次显示的层数。
⑧选中图里的某个函数节点,可以继续打开源码或查看该函数的信息。
例如要分析main后面会进入哪些初始化函数,可以直接对main生成【Calls】图,再逐层展开,不用手工在源码中来回搜索函数名称。
2、反向查看函数被哪些位置调用
排查公共函数、接口函数时,反向关系通常更有用。
①在源码中找到目标函数。
②右键选择【Graphical Views】→【Called By】。
③查看直接调用当前函数的上层函数。
④继续展开调用者,可以向上追踪多级调用。
⑤调用节点很多时,调整【Depth】控制显示层级。
⑥双击某个调用节点,跳到对应实体。
⑦还想核对具体引用位置时,右键函数选择【View Information】。
⑧在【Information Browser】中展开【Called By】,继续查看对应调用关系。
【Information Browser】里的调用信息和调用关系图使用的是同一套项目分析数据。图上少了一条调用关系时,可以在这里先确认数据库里有没有识别到这次调用。
3、同时查看上游和下游调用
想知道一个函数“谁调用了它”和“它又调用了谁”,可以直接使用双向图。
①选中目标函数。
②进入【Graphical Views】。
③选择【Butterfly】。
④查看根节点左侧或一侧的调用来源。
⑤查看另一侧的下级调用目标。
⑥分别调整两侧的显示深度。
⑦节点过多时,在【Variant】中查看当前实体可用的图形变体。
⑧需要较简洁的调用树时,可切换到【Simplified】一类可用变体。
文件、类或Architecture也可以使用【Calls&Called By】查看内部调用关系,适合从模块层级观察代码连接情况。
二、Understand调用关系图显示不完整如何处理
调用图少节点、少连线,先检查项目数据库有没有把对应函数解析完整。C/C++项目里,Include、Macro和真实构建参数对调用结果影响比较明显。
1、检查缺失的头文件
①找到图中缺少关系的函数。
②在源码中确认这次函数调用确实存在。
③进入【Project】→【Improve Project Accuracy】。
④打开【Missing Includes】。
⑤查看当前项目有没有未找到的头文件。
⑥找到头文件实际所在目录。
⑦进入【Project】→【Configure Project】中的C++配置。
⑧把缺失的Include目录加入项目。
⑨保存配置后重新Analyze。
⑩再次打开原来的【Calls】或【Called By】图检查结果。
头文件里的函数声明没有被识别时,调用点可能只能留下未解析实体,图形自然不会按预期连接到真实函数。
2、检查条件编译宏
有些调用只在特定编译条件下存在。Understand使用的宏配置和真实工程不一致时,看到的代码路径也会不同。
①进入【Project】→【Improve Project Accuracy】。
②打开【Undefined Macros】。
③找到影响当前源码条件编译的宏。
④对照原工程编译参数,确认宏名称和取值。
⑤进入项目的C++配置区域补充对应Macros。
⑥检查平台宏、功能开关和产品配置宏有没有填错。
⑦保存后重新分析项目。
⑧重新生成调用关系图。
例如某段函数调用位于#ifdef控制区域里,而当前项目没有定义对应宏,这段代码在Understand分析时可能处于非活动状态,调用边也不会出现在图里。
3、重新导入实际构建参数
手工补了不少Include和Macro,结果仍然缺关系,可以改用工程真实编译信息。
①确认项目当前能够正常构建。
②CMake工程先生成【compile_commands.json】。
③进入Understand项目配置,重新导入对应编译数据库。
④检查导入的源文件范围。
⑤核对Include路径和Macros。
⑥确认导入的是当前实际使用的构建配置。
⑦重新执行项目分析。
⑧再检查缺失函数的【Calls】和【Called By】关系。
Understand的C/C++严格分析依赖真实编译环境。编译数据库能够带入具体源码文件、头文件搜索路径和宏设置,比人工逐项补参数更容易和原工程保持一致。
三、调用图仍然缺少关系怎么继续排查
项目配置已经修过,但少数调用仍然没有出现时,可以进一步检查调用形式、分析状态和图形显示范围。函数指针、虚函数以及跨语言调用的呈现方式和普通直接调用并不完全相同。
1、先在Information Browser确认数据库记录
①选中缺少关系的函数。
②右键选择【View Information】。
③展开【Calls】,查看目标函数是否存在。
④反向检查时展开【Called By】。
⑤如果这里也没有目标函数,继续检查项目解析配置。
⑥如果这里已经存在,而图里没有显示,检查图形的【Depth】和当前【Variant】。
⑦重新打开图,观察节点是否恢复。
图形只是把数据库里的关系画出来,所以Information Browser很适合拿来判断问题在“分析数据”还是“图形显示”。
2、检查函数指针和虚函数调用
①定位缺少关系的调用语句。
②确认调用是不是经由函数指针完成。
③C++项目再检查目标函数是不是virtual函数。
④打开对应函数的【Called By】图。
⑤查看是否出现多个可能调用目标。
⑥结合类层级和实际对象类型判断这些候选关系。
⑦若实体本身显示为Undefined,返回项目配置继续修解析问题。
动态调用在静态分析里可能对应多个候选目标,图形不会按照一次实际运行结果只画一条线路。分析这类代码时,要结合函数指针赋值、继承关系和实际构建条件一起看。
3、重新分析变化过的源码
①源码只改动少量文件时执行【Analyze Changed Files】。
②Include、Macro或构建配置改动较多时重新执行完整Analyze。
③等待分析结束后查看项目错误信息。
④确认缺失头文件和未定义实体数量已经减少。
⑤重新打开目标函数。
⑥生成新的【Calls】【Called By】或【Butterfly】图。
⑦选一组源码中已经确认存在的调用做交叉核对。
总结
Understand调用关系图是否完整,和项目源码能不能被正确解析有直接关系。图里缺少节点或调用边时,除了检查显示层级,还要看项目数据库里的函数实体和引用是否已经建立。对于宏较多、构建参数复杂的C/C++工程,把分析环境和真实编译环境对齐后,调用关系通常会更接近源码实际结构。如需进一步了解Understand调用关系图、函数引用分析与项目解析异常排查方法,欢迎联系咨询。