更快的调用图生成回溯?
Faster backtrace for call graph generation?
我使用以下方法生成调用图。
https://github.com/tarun27sh/gdb_graphs
但是 gdb 被回溯显着 (x100) 减慢了。有没有更快的方法来生成调用图?
因为你 post 这个问题在 SO 上并用 llvm 标记,我认为这意味着你正在寻找使用 LLVM 的编程解决方案。
编写一个 pass,转换程序中的每个函数,以便在每次调用之前添加三个新指令。像这样:
struct RecordCallGraph : public PassInfoMixin<RecordCallGraph> {
RecordCallGraph() = default;
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
};
您需要实施 运行(),这大约需要 15 行代码。扫描函数中的基本块,检查每条指令是否isa<CallBase>
,如果是,则在CallBase之前插入一点额外的代码。 (CallBase 是调用函数的指令的基础 class。)您插入对新函数的调用,void emitTraceInfo(char* caller, char* called)
或类似的东西。由于 LLVM IR 是类型安全的,因此您需要将调用者 (&F
) 和被调用函数 (callBase->getCalledValue()
) 转换为适合您的函数的正确类型(示例中的 char*
)。
获得该转换的最简单方法可能是 CastInst::Create(CastInst::BitCast, &F, charStarType, "", callBase)
,它会创建一个从 &F
到 charStarType
的新转换,并将其插入紧接在 callBase
之前。
最后,您必须将新的 emitTraceInfo
和 link 实施到程序中。每次一个函数调用另一个函数时都会调用它,并且可以记录调用。你会发现它比 gdb 快一百倍。最慢的部分可能是将 16 多个字节写入文件。
Is there a much faster way to generate call graphs?
当然有(为此使用GDB是完全不合适的)。
最简单的解决方案是使用GCC -finstrument-functions
在每个函数入口和出口处插入一个调用,并在这些"injected" 函数中实现数据收集。有一个例子 here.
我使用以下方法生成调用图。
https://github.com/tarun27sh/gdb_graphs
但是 gdb 被回溯显着 (x100) 减慢了。有没有更快的方法来生成调用图?
因为你 post 这个问题在 SO 上并用 llvm 标记,我认为这意味着你正在寻找使用 LLVM 的编程解决方案。
编写一个 pass,转换程序中的每个函数,以便在每次调用之前添加三个新指令。像这样:
struct RecordCallGraph : public PassInfoMixin<RecordCallGraph> {
RecordCallGraph() = default;
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
};
您需要实施 运行(),这大约需要 15 行代码。扫描函数中的基本块,检查每条指令是否isa<CallBase>
,如果是,则在CallBase之前插入一点额外的代码。 (CallBase 是调用函数的指令的基础 class。)您插入对新函数的调用,void emitTraceInfo(char* caller, char* called)
或类似的东西。由于 LLVM IR 是类型安全的,因此您需要将调用者 (&F
) 和被调用函数 (callBase->getCalledValue()
) 转换为适合您的函数的正确类型(示例中的 char*
)。
获得该转换的最简单方法可能是 CastInst::Create(CastInst::BitCast, &F, charStarType, "", callBase)
,它会创建一个从 &F
到 charStarType
的新转换,并将其插入紧接在 callBase
之前。
最后,您必须将新的 emitTraceInfo
和 link 实施到程序中。每次一个函数调用另一个函数时都会调用它,并且可以记录调用。你会发现它比 gdb 快一百倍。最慢的部分可能是将 16 多个字节写入文件。
Is there a much faster way to generate call graphs?
当然有(为此使用GDB是完全不合适的)。
最简单的解决方案是使用GCC -finstrument-functions
在每个函数入口和出口处插入一个调用,并在这些"injected" 函数中实现数据收集。有一个例子 here.