基于gcc plugin机制,编译源码时在每个函数前插入一条指令,打印当前的调用栈,省去了修改源码的时间
在学习开源库时,想了解它的调用流程,可以使用valgrind的callgrind功能。这里介绍另一种方法,gcc有一种plugin机制,可以利用这种机制在编译源码时,在函数中插入call指令,调用自己的api调用,咱们在这个函数中调用libunwind获取调用栈信息.
可以参考 基于torch_dispatch机制生成Megatron-DeepSpeed调用关系图 生成整个工程的调用关系图
一.安装依赖
gcc --version
#gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
apt install gcc-11-plugin-dev
apt install libunwind-dev -y
二.gcc插件源码
cat > gcc_backtrace_plugin.c <<-'EOF'
#include <gcc-plugin.h>
#include <plugin-version.h>
#include <tree.h>
#include <context.h>
#include <tree-pass.h>
#include <function.h>
#include <gimple.h>
#include <gimple-iterator.h>
#include <basic-block.h>
#include <diagnostic.h>
int plugin_is_GPL_compatible;
namespace {
const pass_data print_backtrace_pass_data = {
GIMPLE_PASS, // 传递类型
"insert_print_backtrace_pass", // 传递名
OPTGROUP_NONE, // 优化组
TV_NONE, // 计时器变量
PROP_gimple_any, // 所需属性
0, // 提供属性
0, // 清理属性
0, // 可见性标志
};
struct print_backtrace_pass : gimple_opt_pass {
print_backtrace_pass(gcc::context *ctx)
: gimple_opt_pass(print_backtrace_pass_data, ctx)
{
}
unsigned int execute(function *fun) override;
};
}
unsigned int print_backtrace_pass::execute(function *fun) {
basic_block bb;
gimple_stmt_iterator gsi;
gimple *call_stmt;
tree print_backtrace_fn = NULL;
tree void_type = void_type_node;
tree char_ptr_type = build_pointer_type(char_type_node);
tree fntype = build_function_type(void_type