代码之家  ›  专栏  ›  技术社区  ›  frans

如何从二进制中的给定符号获取调用方图

  •  1
  • frans  · 技术社区  · 7 年前

    这个问题与 a question I've asked earlier this day :我想知道是否可以从给定的函数(或符号名,例如从 nm ), 即使感兴趣的函数不是“我的”源代码的一部分(例如,位于库中,例如。 malloc() )

    例如知道在哪里 malloc 正在我的程序中使用 foo 我将首先查找符号名:

    nm foo | grep malloc
             U malloc@@GLIBC_2.2.5
    

    然后运行一个工具(它可能需要我的程序或某些编译器工件的特殊编译/链接版本):

     find_usages foo-with-debug-symbols "malloc@@GLIBC_2.2.5"
    

    它将生成一个(文本)调用方图,然后我可以进一步处理。

    阅读 this question 我发现 radare2 这似乎完成了几乎所有你能想象到的事情,但不知怎的,我还没有设法从给定的符号生成调用方图。。

    进展

    使用 radare2 我已经设法产生了 dot 可执行文件中的调用方图,但仍缺少某些内容。我正在编译下面的C++程序,我非常肯定必须使用它 马洛克() new :

    #include <string>
    
    int main() {
      auto s = std::string("hello");
      s += " welt";
      return 0;
    }
    

    我用静态库编译它,以确保我要分析的所有调用都可以在二进制文件中找到:

    g++ foo.cpp -static
    

    通过跑步 nm a.out | grep -E "_Znwm|_Znam|_Znwj|_Znaj|_ZdlPv|_ZdaPv|malloc|free" 你可以看到很多用于内存分配的符号。

    现在我跑 雷达2 在可执行文件上:

    r2 -qAc 'agCd' a.out > callgraph.dot
    

    有一个小剧本(灵感来自 this answer )我正在从任何包含“sym.operatornew”的符号中寻找调用路径,但似乎没有!

    有办法确保 全部的 生成从/到调用图所需的信息 任何 在二进制文件中调用哪个get函数?

    有没有更好的方法来运行radare2?看起来不同的调用图可视化类型提供了不同的信息-例如,ascii art生成器确实为点生成器未提供的符号提供了名称,而点生成器则提供了有关调用的更多详细信息。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Basile Starynkevitch    7 年前

    一般来说,您不能提取 准确的 来自二进制的控制流图,因为 indirect jumps and calls 在那里。一个机器代码间接调用正在跳转到某个寄存器的内容中,您不能 可靠的 估计寄存器可以接受的所有值(这样做可以证明与 halting problem ).

    有没有办法确保生成调用图所需的所有信息从/到在二进制文件中调用get的任何函数?

    ,和 这个问题相当于停止问题 ,所以永远不会有一个确定的方法来获得调用图(以完整和合理的方式)。

    C++编译器会(通常)为虚函数调用生成间接跳跃(它们通过 vtable )可能在使用共享库时 How To Write Shared Libraries 更多信息请参阅纸张)。

    调查一下 BINSEC 工具(由CEA、LIST和INRIA的同事开发),至少可以找到参考文献。

    如果您真的想在C++源代码中找到大多数(但不是全部)动态内存分配,则可以使用静态源代码分析(如 Frama-C Frama-Clang )和其他工具,但它们不是银弹。

    记住,分配函数 malloc operator new 可以放在函数指针位置(C++代码可能有一些) allocator 埋在某处,那么你很可能 间接的 打电话给 马洛克 )

    也许你可以花几个月的时间来写你自己的 GCC plugin 找电话 马洛克 优化后 在GCC编译器内部(但请注意,GCC插件绑定到一个特定版本的GCC)。我不确定这是否值得努力。我的旧(过时,未维护) GCC MELT 项目 was 能够找到呼叫 马洛克 尺寸超过某个给定常数。或许至少在2019年底或更晚些时候-我的继任者项目( bismon ,资金来源 CHARIOT H2020项目)可能已经足够成熟,可以帮助您。

    还要记住,GCC能够进行与 马洛克 . 尝试编译以下C代码

    //file mallfree.c
    #include <stdlib.h>
    int weirdsum(int x, int y) {
      int*ar2 = malloc(2*sizeof(int));
      ar2[0] = x; ar2[1] = y;
      int r = ar2[0] + ar2[1];
      free (ar2);
      return r;
    }
    

    具有 gcc -S -fverbose-asm -O3 mallfree.c . 你会看到 mallfree.s 汇编程序文件不包含对 马洛克 或者去 free . 这种优化是由 As-if rule 这对于优化C++标准的大多数用法是非常有用的。 containers .

    所以 你想要的是 不简单 即使是明显的“简单”C++代码 不可能的 在一般情况下)。

    如果你想编写一个GCC插件,并有超过一年的时间花在这个问题上(或可能支付至少50万),请与我联系。另见 https://xkcd.com/1425/ (你的问题是 几乎不可能 一个)。

    当然,顺便说一句,您真正关心的是 优化 代码(你真的想要 inlining dead code elimination ,GCC在 -O3 -O2 ). 当GCC根本没有优化时(例如 -O0 这是隐式优化,它会做很多“无用”的动态内存分配,特别是用C++代码(使用C++标准库)。另见CPPCon2017:Matt Godbolt 我的编译器最近为我做了什么?打开编译器的盖子 talk .