分析函数调用关系图(call graph)的几种方法

2023-05-16

绘制函数调用关系图对理解大型程序大有帮助。我想大家都有过一边读源码(并在头脑中维护一个调用栈),一边在纸上画函数调用关系,然后整理成图的经历。如果运气好一点,借助调试器的单步跟踪功能和call stack窗口,能节约一些脑力。不过如果要分析的是脚本语言的代码,那多半只好老老实实用第一种方法了。如果在读代码之前,手边就有一份调用图,岂不妙哉?下面举出我知道的几种免费的分析C/C++函数调用关系的工具。

函数调用关系图(call graph)是图(graph),而且是有向图,多半还是无环图(无圈图)——如果代码中没有直接或间接的递归的话。Graphviz是专门绘制有向图和无向图的工具,所以很多call graph分析工具都以它为后端(back end)。那么前端呢?就看各家各显神通了。

调用图的分析分析大致可分为“静态”和“动态”两种,所谓静态分析是指在不运行待分析的程序的前提下进行分析,那么动态分析自然就是记录程序实际运行时的函数调用情况了。

静态分析又有两种方法,一是分析源码,二是分析编译后的目标文件。

分析源码获得的调用图的质量取决于分析工具对编程语言的理解程度,比如能不能找出正确的C++重载函数。Doxygen是源码文档化工具,也能绘制调用图,它似乎是自己分析源码获得函数调用关系的。GNU cflow也是类似的工具,不过它似乎偏重分析流程图(flowchart)。

对编程语言的理解程度最好的当然是编译器了,所以有人想出给编译器打补丁,让它在编译时顺便记录函数调用关系。CodeViz (其灵感来自Martin Devera (Devik) 的工具)就属于此类,它(1.0.9版)给GCC 3.4.1打了个补丁。另外一个工具egypt的思路更巧妙,不用大动干戈地给编译器打补丁,而是让编译器自己dump出调用关系,然后分析分析,交给Graphviz去绘图。不过也有人另起炉灶,自己写个C语言编译器(ncc),专门分析调用图,勇气可嘉。不如要是对C++语言也这么干,成本不免太高了。分析C++的调用图,还是借助编译器比较实在。

分析目标文件听起来挺高深,其实不然,反汇编的工作交给binutils的objdump去做,只要分析一下反汇编出来的文本文件就行了。下面是Cygwin下objdump -d a.exe的部分结果:

00401050 <_main>:
  401050:       55                      push   %ebp
  401051:       89 e5                   mov    %esp,%ebp
  401053:       83 ec 18                sub    $0x18,%esp
   ......
 40107a:       c7 44 24 04 00 20 40    movl   $0x402000,0x4(%esp)
  401081:       00
  401082:       c7 04 24 02 20 40 00    movl   $0x402002,(%esp)
  401089:       e8 f2 00 00 00          call   401180 <_fopen>

从中可以看出,main()调用了fopen()。CodeViz带有分析目标文件的功能。

动态分析是在程序运行时记录函数的调用,然后整理成调用图。与静态分析相比,它能获得更多的信息,比如函数调用的先后顺序和次数;不过也有一定的缺点,比如程序中语句的某些分支可能没有执行到,这些分支中调用的函数自然就没有记录下来。

动态分析也有两种方法,一是借助gprof的call graph功能(参数-q),二是利用GCC的 -finstrument-functions 参数。

gprof生成的输出如下:

index % time    self  children    called     name
                0.00    0.00       4/4           foo [4]
[3]      0.0    0.00    0.00       4         bar [3]
-----------------------------------------------
                0.00    0.00       1/2           init [5]
                0.00    0.00       1/2           main [45]
[4]      0.0    0.00    0.00       2         foo [4]
                0.00    0.00       4/4           bar [3]
-----------------------------------------------
                0.00    0.00       1/1           main [45]
[5]      0.0    0.00    0.00       1         init [5]
                0.00    0.00       1/2           foo [4]
-----------------------------------------------

从中可以看出,bar()被foo()调用了4次,foo()被init()和main()各调用了一次,init()被main()调用了一次。用Perl脚本分析gprof的输出,生成Graphviz的dot输入,就能绘制call graph了。这样的脚本不止一个人写过:http://www.graphviz.org/Resources.php,http://www.ioplex.com/~miallen/。

GCC的-finstrument-functions 参数的作用是在程序中加入hook,让它在每次进入和退出函数的时候分别调用下面这两个函数:

void __cyg_profile_func_enter( void *func_address, void *call_site )
                                __attribute__ ((no_instrument_function));

void __cyg_profile_func_exit ( void *func_address, void *call_site )
                                __attribute__ ((no_instrument_function));

当然,这两个函数本身不能被钩住(使用no_instrument_function这个__attribute__),不然就反反复复万世不竭了:) 这里获得的是函数地址,需要用binutils中的addr2line这个小工具转换为函数名,如果是C++函数,还要用c++filt进行name demangle。具体方法在《用Graphviz 可视化函数调用》中有详细介绍,这里不再赘述。

从适应能力上看,源码分析法是最强的,即便源码中有语法错,头文件不全也没关系,它照样能分析个八九不离十。而基于编译器的分析法对源码的要求要高一些,至少能编译通过(gcc 参数 -c)——能产生object file,不一定要链接得到可执行文件。这至少要求源码没有语法错,其中调用的函数不一定有定义(definition),但要有声明(declaration),也就是说头文件要齐全。当然,真的不全也没关系,自己放几个函数声明在前面就能糊弄编译器:) 至于动态分析,要求最高——程序需得运行起来。如果你要分析的是操作系统中某一部分,比如内存管理或网络协议栈,那么这里提到的两种动态分析法恐怕都不适用了。

我发现前面列举的所有免费工具几乎都和GCC、GNU Binutils脱不了干系。这里在把它们整理一下,用Graphviz绘成图:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

分析函数调用关系图(call graph)的几种方法 的相关文章

  • 虚拟现实的起源、发展、爆发与沉淀

    虚拟现实的三生三世 闲来无事翻篇外文 xff0c 本博主并非故意蹭热点 xff08 奸笑 xff09 xff0c 结尾我会细说为何是三生三世 xff0c 不是五生五世 xff1a 虚拟现实远早于这个概念被创造和形式化之前 在这篇描写虚拟现实
  • UCOS消息队列的使用【转】

    UCOS消息队列的使用 转 收藏 消息队列的使用 1 需在以下文件中配置如下内容 OS CFG H OS MAX QS N 你需要的值 根据需要自己配置 define OS Q EN 1 Enable 1 or Disable 0 code
  • to_string函数的用法

    to string 函数 xff1a 将数字常量转换为字符串 xff0c 返回值为转换完毕的字符串 头文件 xff1a include lt string gt string s 61 to string i 将整数i转换为字符串表示形式
  • EKF2学习之控制融合模式

    By snowpang 2017 8 10 1 存储控制状态值 xff0c 并开启状态变化检测 control status value bitmask containing filter control status union filt
  • 经典算法 (四) 桶排序

    时隔一年 xff0c 小葵花课堂再次开课 xff0c 这次开课不会像之前那样很早就停课了 xff0c 在此给大家道个歉 xff1a 对不起 嘻嘻 又到了毕业季了 xff0c 废话不多说 xff0c 继续我们的算法学习 一丶算法描述 桶排序
  • 程序调试记录(纯自用)

    Stack类测试 xff1a 在测试Stck类型的变量内容是否正确时 xff0c 经常会通过把所有值pop出来输出的方法 xff0c 这样容易造成一个问题就是 xff0c 栈已经被弄空了 xff0c 以后再用的时候就会是一个空栈 所以 xf
  • vector详解

    引言 emmm 这篇博客写作的缘由其实就是我在日常使用vector的时候发现对vector并不怎么了解所以决定写这篇博客的 写这篇博客 xff0c 我参考了vector C 43 43 Reference中的内容 xff0c 及侯捷先生的
  • Eigen快速入门

    Eigen快速入门 一个简单的例子 span class hljs preprocessor include lt iostream gt span span class hljs preprocessor include 34 Eigen
  • PX4 的 ECL EKF 公式推导及代码解析

    原创作者 USRL所长 64 CSDN 文章来源 https blog csdn net u010307048 article details 100553475 如需转载联系联系原创作者 作者整理的内容如下 xff0c 干货很多 xff0
  • git fatal: The remote end hung up unexpectedly错误解决方法

    在使用git更新或提交项目时候出现 34 fatal The remote end hung up unexpectedly 34 原因是推送的文件太大 那就简单了 xff0c 要么是缓存不够 xff0c 要么是网络不行 xff0c 要么墙
  • 公开课精华|机器人的带约束轨迹规划

    本文章总结于大疆前技术总监 xff0c 目前在卡内基梅隆大学读博的杨硕博士在深蓝学院的关于机器人的带约束轨迹规划的公开课演讲内容 全文约5000字 笔者不是机器人领域的 xff0c 因此特地去了解了一下杨硕博士 xff0c 深感佩服 xff
  • 自动驾驶的重要一环:谈谈感知前沿技术

    本文总结于Waymo研发经理周寅于2021年8月29日在深蓝学院的讲座 讲座内容主要包括自动驾驶系统的总览 xff0c 自动驾驶感知的介绍 xff0c 以及感知的前沿动态和总结 1 自动驾驶系统总览 关于自动驾驶系统 目前主流的L4级别自动
  • 论文精读 | slam中姿态估计的图优化方法比较

    一 摘要 对于位置环境中的自主导航问题 xff0c 同步定位与建图 Simultaneous localization and mapping SLAM 是一个非常重要的工具框架 根据SLAM字面含义可以得知 xff0c 获取正确的环境表征
  • 自动驾驶中的多种卡尔曼滤波算法及推导详解,值得一读!

    鉴于卡尔曼滤波算在多传感器融合系统中使用的普遍性 xff0c 本文将单独就卡尔曼滤波算法及自动驾驶中常用的改进卡尔曼滤波算法进行详细介绍 首先介绍卡尔曼滤波的基本方法 xff0c 然后介绍针对非线性系统改进的扩展卡尔曼滤波 xff0c 最后
  • 入门ROS其实也没有那么难!

    作者 xff1a Tassel 相信提出这个问题的小伙伴已经对ROS有一定的了解 xff0c 但不管是出于工程应用还是理论学习 xff0c 我们都有必要谈谈ROS的概念 xff0c 从概念去理解ROS ROS xff08 机器人操作系统 x
  • 论SLAM技术发展趋势

    2018年7月底 xff0c 深蓝学院发起并承办了 第一届全国SLAM技术论坛 浙江大学章国锋老师 香港科技大学沈劭劼老师 上海交通大学邹丹平老师 中科院自动化所申抒含老师在 圆桌论坛 xff1a SLAM技术发展趋势 上分享了SLAM技术
  • 华清远见嵌入式学习每周汇总

    每周学习总结 第一周数据结构Makefile的编写顺序表链表 xff08 含约瑟夫环之选猴王 xff09 Joseph circle 本周总结 第二周栈队列树二叉树二叉树的创建 本周总结 IO进程标准IO2 题目要求 xff1a 编程读写一
  • 注意项:dockerFile中安装常用的运维工具

    自己打镜像的时候 xff0c 如果依赖的基础镜像中没有一些常用的Linux运维工具 xff0c 需要自己记得提前安装一下 xff0c 免得线上出现问题需要排查时才发现没有工具 一些常用的如下 RUN yum install y telnet
  • Ubuntu16.04安装ROS kinetic

    ROS kinetic官网 xff1a http wiki ros org kinetic Installation Ubuntu 1 配置Ubuntu的资源库 xff1a 34 restricted 34 xff0c 34 univers
  • 鼠标光标变成了一个点

    今天使用华为云桌面 xff08 内部系统是win7 xff09 xff0c 鼠标光标悬停在普通文本上就变成了一个 不容易发现的点 xff0c 用起来很不方便 xff0c 如图 xff1a 可通过修改鼠标指针颜色和大小来调整解决 xff08

随机推荐

  • opencv--颜色物体追踪 图片的形态学处理函数

    目录 一 主要函数介绍 1 cv2 erode 2 cv2 dilate 3 cv2 findContours 4 cv2 circle 5 cv2 line 二 代码 这里首先确定是否安装imutils库 xff0c 这个库能让调整大小或
  • 使用可视化的Docker进行自动化测试

    01 前言 顺着docker的发展 xff0c 很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试 xff0c 这篇文章主要讲述我们在docker中使用浏览器进行自动化测试如果可以实现可视化 xff0c 同时可
  • 固定翼飞机的一些记录——(1)IMU

    一 IMU 1 什么是IMU IMU Inertial Measurement Unit xff0c 惯性测量单元 一般一个IMU由三个单轴的加速度计和三个单轴的陀螺组成 1 1 加速度计的工作原理 Fig 1 加速度工作原理图 加速度计的
  • 遇到 definition duplicated 怎麼辦

    net 4 0 in IIS7 中有一個 known issue xff1a 就是 xff0c 在deploy之後會發生section定義重複的問題 解決這個問題的最好方法就是 把webconfig中的這段代碼註釋掉 This error
  • Docker容器学习二之镜像

    一 镜像 Docker可以把我们的应用打包成一个可移植的镜像 xff0c 也可以拉取打包好的镜像来共自己使用 xff0c 那么也会存在一个存放docker镜像的仓库 一个官方的镜像仓库地址 https hub docker com xff0
  • 【STM32】 HAL库+STM32CubeMX 系列教学

    HAL库简介 STM32 HAL固件库是Hardware Abstraction Layer的缩写 xff0c 中文名称是 xff1a 硬件抽象层 HAL库是ST公司为STM32的MCU最新推出的抽象层嵌入式软件 xff0c 为更方便的实现
  • 什么程度才算精通 Linux?

    本文选自 攻克 Linux 系统编程 作者 宇文拓 责编 林瑟 Linux 的优秀之处自然不必多说 如果将操作系统比作一辆汽车 xff0c 那 Linux 就是一辆性能出色的多功能越野车 xff0c 上山下海飞天无所不能 如果你拥有了它 x
  • Makefile初级语法1

    Makefile基本规则 基本规则如下 xff1a target target dependent command command前必须是TAB 语法示例分析 xff1a helloworld o main o print hello o
  • RealSense T265环境配置

    RealSense T265环境配置 二进制安装SDK2 0 官网的指导 https www intelrealsense com https github com IntelRealSense librealsense blob deve
  • COMTool安装测试

    COMTool安装测试 没错 xff0c 这又是GitHub上的一个开源项目 xff0c 我几乎又折腾了一下午 xff0c 依旧没有成功 好看实用跨平台带图形界面无广告串口调试助手 网络调试助手 终端工具 COMTool https git
  • opencv imread 函数读取CV_16UC1的png图片

    opencv 2 4 11中imread读取图片有三种方式 xff1a CV LOAD IMAGE UNCHANGED lt 0 loads the image as is including the alpha channel if pr
  • Docker: Ubuntu使用VNC运行基于Docker容器里的桌面系统

    xff08 由于看到的出处不是原作者 xff0c 还请原作者看到后及时说明出处 xff09 https hub docker com r dorowu ubuntu desktop lxde vnc https github com fcw
  • 三菱IPM驱动芯片PSS15S92\PSS20S92分析

    三菱IPM驱动芯片分析 三菱PSS15S92 PSS20S92 IPM功率模块资料 电机驱动方案 60 300V STM32驱动无刷电机 60 300V高压无刷电机驱动电路参考电路图及PCB www cirmall com circuit
  • PCAP01 PCAP02 PCAP04芯片配置程序及代码

    PCAP01 PCAP02 PCAP04芯片配置程序及代码 www cirmall com circuit 23606
  • 正点原子STM32F405RG飞控 二层板低成本(原理图+PCB+程序)

    正点原子STM32F405RG飞控 二层板低成本 xff08 原理图 43 PCB 43 程序 xff09 www cirmall com circuit 18606
  • px4 pixhawk2.4.6 2.4.8 px4fmu bootload 和 烧写详细说明文档

    www cirmall com circuit 23428
  • xv7011 xv7021(手册+原理图+代码stm32)

    需要的可以去电路城下载程序和PCB www cirmall com circuit 23605
  • openmv4 MT9V034

    www cirmall com circuit 24049
  • 安装aptitude

    aptitude 与 apt get 一样 xff0c 是 Debian 及其衍生系统中功能极其强大的包管理工具 与 apt get 不同的是 xff0c aptitude 在处理依赖问题上更佳一些 举例来说 xff0c aptitude
  • 分析函数调用关系图(call graph)的几种方法

    绘制函数调用关系图对理解大型程序大有帮助 我想大家都有过一边读源码 xff08 并在头脑中维护一个调用栈 xff09 xff0c 一边在纸上画函数调用关系 xff0c 然后整理成图的经历 如果运气好一点 xff0c 借助调试器的单步跟踪功能