LLVM IR:使用元数据节点识别变量

时间:2016-01-03 15:49:09

标签: c++ llvm llvm-ir

目前我正在开发一种工具,用于识别任意程序上的全局变量和字段变量的加载和存储访问。此外,访问变量应由其源级别名称/标识符标识。 为了实现这一点,我将诊断程序的源代码编译成带有调试信息的LLVM IR。到目前为止,生成的元数据节点包含所需的源级别标识符。但是,我无法与某些LLVM IR标识符和元数据中的信息建立连接。

例如,考虑一个类的satic成员:

 class TestClass {
   public:
    static int Number;
};

相应的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)

在这个受控的例子中,我知道“@ _ZN12TestClass6NumberE”是“Number”的标识符。但是,总的来说,我没有看到如何找出哪个IR标识符对应于哪个元数据。

有人可以帮帮我吗?

1 个答案:

答案 0 :(得分:4)

由于似乎没有人能够很好地解决我的问题,我将告诉我自己处理这个问题的不方便的方法。 LLVM生成的MetaData节点包含有关已定义类型和代码变量的信息。但是,没有关于哪些生成的IR变量对应于哪些源代码变量的信息。 LLVM仅链接IR指令的元数据信息和correspdoning源位置(行和列)。这是有道理的,因为LLVMs元数据的主要任务不是分析而是调试。

但是,所包含的信息并非毫无用处。我对这个问题的解决方案是使用clang AST来分析源代码。在这里,我们获取有关在哪个源位置访问哪个变量的信息。因此,为了在LLVM IR检测期间获取有关源变量标识的信息,我们只需要在clang AST分析期间将源位置映射到源变量标识。作为第二步,我们使用我们以前收集的信息执行IR仪器。当我们在IR中遇到存储或加载指令时,我们在该指令的元数据节点中搜索其相应的源位置。由于我们已将源位置映射到源变量标识,因此我们现在可以轻松访问IR指令的源变量标识。

那么,为什么我不仅仅使用clang AST识别存储和加载变量?因为区分AST中的读写并不是一项简单的任务。 AST可以很容易地告诉您访问变量,但它取决于操作是否读取或写入访问的变量。因此,我必须考虑每个操作/操作符来确定变量是写入/读取还是两者都是。在这方面,LLVM更简单,更低级,因此更不容易出错。此外,实际的仪器(说话代码插入)在AST中比使用LLVM要困难得多。由于这两个原因,我认为结合使用clang AST和LLVM IR仪器是解决我问题的最佳方法。