目前我正在开发一种工具,用于识别任意程序上的全局变量和字段变量的加载和存储访问.此外,访问变量应由其源级别名称/标识符标识.为了实现这一点,我将诊断程序的源代码编译成带有调试信息的LLVM IR.到目前为止,生成的元数据节点包含所需的源级别标识符.但是,我无法绘制与某些LLVM IR标识符和元数据中的信息的连接.
例如,考虑一个类的satic成员:
class TestClass {
public:
static int Number;
};
Run Code Online (Sandbox Code Playgroud)
相应的LLVM IR如下所示:
@_ZN12TestClass6NumberE = external global i32, align 4
...
!15 = !DIDerivedType(tag: DW_TAG_member, name: "Number", scope: !"_ZTS12TestClass", file: !12, line: 5, baseType: !16, flags: DIFlagPublic | DIFlagStaticMember)
Run Code Online (Sandbox Code Playgroud)
在这个受控的例子中,我知道"@ _ZN12TestClass6NumberE"是"Number"的标识符.但是,总的来说,我没有看到如何找出哪个IR标识符对应于哪个元数据.
有人可以帮帮我吗?
由于似乎没有人对我的问题有一个好的解决方案,我将告诉我自己的不方便的方法来处理这个问题。LLVM 生成的元数据节点包含有关代码的已定义类型和变量的信息。但是,没有关于哪些生成的 IR 变量对应于哪些源代码变量的信息。LLVM 仅将 IR 指令的元数据信息与相应的源位置(行和列)链接起来。这是有道理的,因为 LLVM 元数据的主要任务不是分析而是调试。
尽管如此,所包含的信息并非无用。我解决这个问题的方法是使用clang AST来分析源代码。在这里,我们获得有关在哪个源位置访问哪个变量的信息。因此,为了在 LLVM IR 检测期间获取有关源变量标识的信息,我们只需在 clang AST 分析期间将源位置映射到源变量标识即可。第二步,我们使用之前收集的信息执行红外检测。当我们在IR中遇到存储或加载指令时,我们在该指令的元数据节点中搜索其相应的源位置。由于我们已将源位置映射到源变量标识,因此我们现在可以轻松访问 IR 指令的源变量标识。
那么,为什么我不只使用 clang AST 来识别变量的存储和加载呢?因为区分 AST 中的读取和写入并不是一项简单的任务。AST 可以很容易地告诉你一个变量被访问了,但这取决于所访问的变量是读取还是写入的操作。因此,我必须考虑每一个操作/运算符来确定变量是否被写入/读取或两者都被写入/读取。LLVM 在这方面更简单、更底层,因此更不容易出错。此外,与 LLVM 相比,AST 中的实际检测(即代码插入)要困难得多。由于这两个原因,我相信 clang AST 和 LLVM IR 仪器的组合是解决我的问题的最佳解决方案。
| 归档时间: |
|
| 查看次数: |
618 次 |
| 最近记录: |