静态分析C语言生成函数调用关系的利器——GCC

这篇具有很好参考价值的文章主要介绍了静态分析C语言生成函数调用关系的利器——GCC。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在《静态分析C语言生成函数调用关系的利器——cally和egypt》中我们介绍了如何使用GCC生成RTL文件,然后再借助cally和egypt来分析出调用关系的方法。GCC自身有命令可以生成代码内部的调用关系,即-fcallgraph-info参数。

Makes the compiler output callgraph information for the program, on a per-object-file basis. The information is generated in the common VCG format.

gcc some.c -fcallgraph-info

它会生成后缀是ci的VCG格式文件。然后我们使用graph-easy将其转换为dot格式,最后使用graphviz将其绘制出来。
我们还是以libevent的为例。

准备工作

graph-easy 用于将vcg文件转换为dot格式

sudo apt install libgraph-easy-perl

因为脚本是Python写的,且会依赖第三方库,于是会使用《管理Python虚拟环境的脚本》介绍的工具构建一个虚拟环境并安装相应依赖。

source env.sh init
soure env.sh enter
source env.sh install pydot

GCC生成单文件调用关系VCG

gcc `find . -regextype posix-extended -regex '^./[^/]*\.c$' ! -name 'wepoll.c' ! -name 'win32select.c' ! -name 'evthread_win32.c' ! -name 'buffer_iocp.c' ! -name 'bufferevent_async.c' ! -name 'arc4random.c' ! -name 'event_iocp.c' ! -name 'bufferevent_mbedtls.c'` \
 ./test/test-time.c \
 -I./build/include/ -I./include -I./ \
 -L./build/lib/ -lcrypto -lssl \
 -DLITTLE_ENDIAN -D__clang__ \
 -UD_WIN32 -UDMBEDTLS_SSL_RENEGOTIATION \
 -fcallgraph-info

静态分析C语言生成函数调用关系的利器——GCC,IT项目研发过程中的利器,c语言,开发语言

将VCG转为Dot

graph-easy a-test-time.ci --as_dot > a-test-time.dot

绘制图片

dot -Grankdir=LR -T png a-test-time.dot -o test_time.png  

静态分析C语言生成函数调用关系的利器——GCC,IT项目研发过程中的利器,c语言,开发语言

绘制全景图

因为GCC生成VCG文件只是针对单个文件的,不能构成全景图。这个时候就需要我们自己手撸一点代码,让这些信息合并。

import pydot

class CallgraphInfoCombiner(object):
    def __init__(self, dot_folder, function_name, output_file) -> None:
        self._dot_folder = dot_folder
        self._funciont_name = function_name
        self._output_file = output_file
        self._callee = dict()
        self._graph = pydot.Dot("callgraph-info-combiner", graph_type="graph", bgcolor="white")
        pass
    
    def analyze(self, include_private=False):
        for file in os.listdir(self._dot_folder):
            self._read_dot(self._dot_folder + "/" + file)
            
        nodes_in_graph = set()
        if self._funciont_name in self._callee:
            self._add_node_and_edge(self._funciont_name, nodes_in_graph, include_private)
        self._graph.write_dot(self._output_file + ".dot")
        self._graph.write_png(self._output_file + ".png")
        
    def _add_node_and_edge(self, node_name, nodes_in_graph, include_private=False):
        if include_private and node_name.startswith('"') and node_name.endswith('"'):
            return
        
        if node_name not in nodes_in_graph:
            print("add node: " + node_name)
            self._graph.add_node(pydot.Node(node_name))
            nodes_in_graph.add(node_name)
            
        if node_name in self._callee:
            for callee in self._callee[node_name]:
                if include_private == False and callee.startswith('"') and callee.endswith('"'):
                    continue
        
                if callee not in nodes_in_graph:
                    self._add_node_and_edge(callee, nodes_in_graph, include_private)
                self._graph.add_edge(pydot.Edge(node_name, callee))
                print("add edge: " + node_name + " -> " + callee)
        
    
    def _read_dot(self, dot_file):
        graphs = pydot.graph_from_dot_file(dot_file)
        for graph in graphs:                    
            for edge in graph.get_edges():
                if edge.get_source() in self._callee:
                    self._callee[edge.get_source()].add(edge.get_destination())
                else:
                    self._callee[edge.get_source()] = {edge.get_destination()}

上面的代码会分析DOT文件,所以在使用前需要将VCG转换成DOT文件。

import os
import sys
import subprocess

class Vcg2Dot(object):
    def __init__(self, vcg_file, dot_file):
        self.vcg_file = vcg_file
        self.dot_file = dot_file

    def vcg_to_dot(self):
        print("graph-easy --input=" + self.vcg_file + " -as=dot --output=" + self.dot_file)
        subprocess.run("graph-easy --input=" + self.vcg_file + " -as=dot --output=" + self.dot_file, shell=True)
        
class VcgFiles2Dot(object):
    def __init__(self, vcg_folder, dot_folder):
        self.vcg_folder = vcg_folder
        self.dot_folder = dot_folder

    def vcg_to_dot(self):
        if not os.path.exists(self.dot_folder):
            os.makedirs(self.dot_folder)
        
        for file in os.listdir(self.vcg_folder):
            vcg_to_dot = Vcg2Dot(self.vcg_folder + file, self.dot_folder + file + ".dot")
            vcg_to_dot.vcg_to_dot()

然后我们只要针对这个脚本传vcg文件目录、起始函数和输出的文件名,即可整合出调用关系。

python callgraph-info-combiner.py ./sample/ci/ main libevent

静态分析C语言生成函数调用关系的利器——GCC,IT项目研发过程中的利器,c语言,开发语言
局部图如下
静态分析C语言生成函数调用关系的利器——GCC,IT项目研发过程中的利器,c语言,开发语言

代码

https://github.com/f304646673/tools/tree/main/callgraph-info-combiner文章来源地址https://www.toymoban.com/news/detail-824946.html

参考资料

  • https://gcc.gnu.org/onlinedocs/gcc/Developer-Options.html
  • https://pypi.org/project/pydot/

到了这里,关于静态分析C语言生成函数调用关系的利器——GCC的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言,Linux,静态库编写方法,makefile与shell脚本的关系。

    静态库编写: 编写.o文件 gcc -c( 小写) seqlist.c(需要和头文件、main.c文件在同一文件目录下) libs.a- 去掉lib与.a剩下的为库的名称‘s’。 -ls 是指库名为s。 -L 库的路径。 makefile文件编写: 这个是编译后的文件,app文件为编译后的二进制文件。      makefile与shell脚本关系 shell 脚

    2024年02月12日
    浏览(36)
  • 1762_gcc编译c语言makefile自动生成工具的Perl实现

    全部学习汇总: GreyZhang/g_makefile: Learn makefile from all kinds of tutorials on the web. Happy hacking and let\\\'s find an common way so we may don\\\'t need to touch makefile code any more! (github.com)          前阵子实现了一个CodeWarrior嵌入式开发环境的自动编译环境,用的基本上是Python。说起来,我觉得那个环

    2024年02月12日
    浏览(75)
  • unity的函数生命周期以及静态生成方法

    前段时间毕业了,到处跑着玩,玩傻了之后入职了又摸了一个多月鱼~收收心了,近期的学习计划是下半年入门图形学,九月中旬把线性代数学完,所以unity和游戏开发的文章还是很少更新了,等后期学习图形学再慢慢更新和学习记录吧,中间工作中遇到的一些问题还是会记录

    2024年02月03日
    浏览(39)
  • 【C语言】getchar和putchar函数详解:字符输入输出的利器

    目录 📌getchar函数 ▪️ 函数原型: ▪️ 目的: ▪️ 返回值: ▪️ 用法: 📌putchar函数 ▪️ 函数原型: ▪️ 目的: ▪️ 参数: ▪️ 返回值: ▪️用法: 📌实例 ▪️ 输入密码并确认流程 📌总结 getchar 和 putchar 是两个标准 C 库函数,用于 C 编程中的输入和输

    2024年02月16日
    浏览(41)
  • 第49讲:Python函数调用解析:传参方式、实参与形参关系、多返回值示例

    调用函数时,需要传递实际参数到函数里的形参中,可以根据每个形参在所有形参中的位置,从而传递实参到对应位置的形参中。 位置实参指的就是,将实参作为变量值赋值给对应位置的形参变量,例如第一个形参变量,调用函数时传入的第一个实参就会赋值给函数中的第一

    2024年02月09日
    浏览(49)
  • ffmpeg.c源码与函数关系分析

    FFmpeg 是一个可以处理音视频的软件,功能非常强大,主要包括,编解码转换,封装格式转换,滤镜特效。 FFmpeg支持各种网络协议,支持 RTMP ,RTSP,HLS 等高层协议的推拉流,也支持更底层的TCP/UDP 协议推拉流。 FFmpeg 可以在 Windows,Linux,Mac,iOS,Android等操作系统上运行。 F

    2024年02月14日
    浏览(34)
  • C语言 静态库和动态库生成

    使用ar命令 ar命令用于创建和管理静态库。下面是使用ar命令生成静态库的步骤: ./main: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory 执行直接报错了,说明系统没有找到库位置 而动态库的搜索路径搜索的先后顺序是: 1.编译目标代码时指

    2024年02月08日
    浏览(36)
  • c语言中指针与函数的关系

    2024年02月05日
    浏览(37)
  • 【ES】笔记-生成器函数与调用

    function* 这种声明方式 (function后跟一个星号)会定义一个生成器函数 (generator function),它返回一个 Generator 对象。 如何调用呢?先看下里面的内容 返回一个这个生成器的 迭代器 ( iterator )对象。 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function* 语法

    2024年02月10日
    浏览(36)
  • 【库函数】Linux下动态库.so和静态库.a的生成和使用

    目录 🌞1. Linux下静态库和动态库的基本概念 🌞2. 动态库 🌊2.1 动态库如何生成 🌍2.1.1 文件详情 🌍2.1.2 编译生成动态库 🌊2.2 动态库如何使用 🌍2.2.1 案例 🌍2.2.2 动态库错误记录 🌞3. 静态库 🌊3.1 静态库如何生成 🌍3.1.1 文件详情 🌍3.1.2 编译生成动态库 🌊3.2 静态库如

    2024年04月25日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包