【问题标题】:Visualisation of the memory layout of C structsC 结构的内存布局的可视化
【发布时间】:2016-03-11 09:32:40
【问题描述】:

我目前正在开发一个与其他汇编代码大量交互的 C 项目。我们正在对我们正在使用的控制块和结构进行自制的可视化,我正在锁定一个关于如何自动化这个过程的过程。

由于我们对每个汇编控制块都有一个等效的 C 结构体,并且我们正在为一种非常罕见的架构进行编程,因此最简单的方法可能是可视化 C 结构体。

我或多或少地在寻找一种从 TCP wiki 页面自动获取图形的方法,例如“用于校验和计算的 TCP 伪标头 (IPv6)”:

TCP pseudo-header for checksum computation (IPv6)

遗憾的是,我还没有找到任何能够从 C 头文件生成此类可视化的开源工具。有没有办法在不手动编写的情况下生成这样的图像或 html 表示形式?

编辑:感谢 Alexey Frunze 的想法,使用实用程序 pahole 可以从目标文件的 DWARF 部分中提取所有使用的结构的真实内存布局。

【问题讨论】:

    标签: c parsing struct visualization declaration


    【解决方案1】:

    其中一种方法是使用这些结构编译 C 代码,并从对象/可执行文件的调试信息中提取结构信息。否则,您正在寻找/制作结构解析器或破解 clang。

    UPD:没试过,不过有pycparser,可能有用。

    【讨论】:

    • 从生成的调试信息中提取结构布局是一个有趣的想法,尤其是因为您应该也能够获取位域的布局信息。但令我惊讶的是,这个要求似乎如此罕见,以至于没有可用的公共工具。
    • @FrederikHartmann 问题是你需要一个几乎完整的编译器前端来解析代码,然后编译器特定的功能之间存在/曾经有相当多的变化,这意味着你会仍然需要以某种方式预处理源代码(即删除不支持的编译指示和其他非标准的东西、gcc 属性等)。所以,几乎总是会有一些限制,除非你按照语言标准编写代码。最重要的是,您有各种特定于编译器的命令行选项会影响对齐。因此,很难制作出一款好的通用工具。
    • 是的,你是对的。获得此功能的唯一故障保存方法可能是由编译器生成它。 Clang 有一些关于 C++ 对象的东西。也许我可以让这个运行。 eli.thegreenplace.net/2012/12/17/…
    【解决方案2】:

    某些 C 聚合(structunion、数组)的布局是实现特定的,因为 data structure alignment 约束(您的特定 ABI 需要)。

    您可以使用调试器(例如gdbptype 命令)。请注意,ddd 有一个图形显示。

    如果您有许多 结构,您可以考虑使用MELT 自定义您的GCC 编译器。您将开发特定的 MELT 扩展来显示布局。这可能需要数周时间(因为您需要了解一些 GCC 内部结构)。

    【讨论】:

    • 当然,但是如果我们避免使用位域(这对于保存布局来说是一团糟),您可以通过指定对齐方式或通过#pragma pack 为给定结构生成布局
    • 但该布局仍然是特定于实现的。
    • 我不认为布局是特定于实现的,如果我们能够保证没有填充发生,因为结构中元素的顺序不是特定于实现的,只有填充。
    • x86-64 Linux 系统的布局与 ARMv7 Android 系统不同(特别是因为sizeof(long) 可能不同)
    【解决方案3】:

    我正在开发一个 C 工具箱,除其他外,它可以绘制任何复杂的 C 类型的图表。它在使用“-g”编译的代码中导入和理解 Dwarf 信息,并且可以以“点”格式转储您想要的任何内容(可以通过任意数量的工具显示。)

    (它也是一种编程语言,使用这种 Dwarf 理解能力直接访问库/程序内部,在运行时使用零胶水代码或链接。)

    见:https://github.com/jasonnyberg/j2/wiki/Diagramming-C-types-using-j2

    j2系统可以读取和理解Dwarf信息;作为调试功能,它还可以将您选择的项目以“点”语言的形式转储,从而允许以图形形式显示类型信息层次结构。 “stack”函数在解释器的顶层堆栈中显示项目,也将这些项目转储到 /tmp/VMRES_STACK.dot。

    要绘制一个项目,只需按名称引用它(如果它不在堆栈上),然后使用“stack!”调用堆栈函数。 (它通过名称引用函数“stack”,然后通过“!”运算符对其进行评估。)

    一旦您运行了解释器(请参阅上面的链接了解解释器本身以及转储结构图的实际示例运行),您只需要 A)“导入”库:

    j2> loadlib([test/build/libtestlib.so]) @testlib
    

    然后 B) 引用您导入的结构(将其添加到解释器的堆栈中):

    j2> testlib.teststruct
    

    最后,C) 显示堆栈(以文本形式,作为副作用,生成文件 /tmp/VMRES_STACK.dot):

    j2> stack!
    

    /tmp/VMRES_STACK.dot 中包含的图形可以通过许多 graphviz/dot 查看器中的任何一个来显示,例如 xdot:

    bash> xdot /tmp/VMRES_STACK.dot
    

    xdot /tmp/VMRES_STACK.dot

    【讨论】:

      猜你喜欢
      • 2014-09-23
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 2015-06-30
      相关资源
      最近更新 更多