【问题标题】:Faster backtrace for call graph generation?调用图生成的更快回溯?
【发布时间】:2019-01-22 04:14:28
【问题描述】:

我使用以下方法来生成调用图。

https://github.com/tarun27sh/gdb_graphs

但是 gdb 被回溯显着减慢(x100)。有没有更快的方法来生成调用图?

【问题讨论】:

    标签: debugging gdb llvm backtrace call-graph


    【解决方案1】:

    有没有更快的方法来生成调用图?

    当然有(为此使用 GDB 是完全不合适的)。

    最简单的解决方案是使用GCC-finstrument-functions在每个函数入口和出口处插入一个调用,并在这些“注入”的函数中实现数据收集。有一个例子here

    【讨论】:

    • 这个例子使用了不可读的函数指针。如何使用可读的函数名?
    • @user1424739 “要了解地址,可以使用“addr2line”工具”的哪一部分你不明白?
    • 我使用 Mac。我不认为 Mac 上很好地支持 binutils。
    • @user1424739 Google 搜索表明 Mac OSX 有一个 atos 工具,它提供了等效的功能。
    • 函数名可以用dladdr解析:cmdlinelinux.blogspot.com/2020/01/…
    【解决方案2】:

    既然您在 SO 上发布了这个问题并用 llvm 标记它,我认为这意味着您正在寻找使用 LLVM 的编程解决方案。

    编写一个转换程序中每个函数的过程,以便在每次调用之前添加三个新指令。像这样的:

    struct RecordCallGraph : public PassInfoMixin<RecordCallGraph> {
      RecordCallGraph() = default;
      PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
    };
    

    您需要实现 run(),这将是大约 15 行代码。扫描函数中的基本块,检查每条指令是否isa&lt;CallBase&gt;,如果是,则在CallBase之前插入一点额外的代码。 (CallBase 是调用函数的指令的基类。)您插入一个对新函数的调用,void emitTraceInfo(char* caller, char* called) 或类似的东西。由于 LLVM IR 是类型安全的,因此您需要将调用者 (&amp;F) 和被调用函数 (callBase-&gt;getCalledValue()) 转换为函数的正确类型(示例中为 char*)。

    获得该演员表的最简单方法可能是CastInst::Create(CastInst::BitCast, &amp;F, charStarType, "", callBase),它会创建一个从&amp;FcharStarType 的新演员表,并将其插入到callBase 之前。

    最后,您必须实现新的emitTraceInfo 并将其链接到程序中。每次一个函数调用另一个函数时都会调用它,并且可以记录调用。你会发现它比 gdb 快一百倍。最慢的部分可能是将 16 多个字节写入文件。

    【讨论】:

    • 我可以直接将代码插入到从bitcode转换的ll文件中。 IR 汇编语言中的代码是什么?另外,如何在代码块级别而不是函数级别进行跟踪?谢谢。
    • 两个bitcast 指令和一个call,每个都有两个参数。当然,所有六个参数都取决于环境。
    • 我不确定新的循环管理器是否像旧的那样支持基本的块传递,我从来没有尝试过这样做,但是在给定的块上循环很容易Function&amp;F:for(auto &amp; b : F.getBasicBlockList()) {…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2018-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多