目前,我正在开发一种工具,该工具可以识别负载并存储对任意程序的全局变量和字段变量的访问。此外,应通过其源级别名称/标识符来标识所访问的变量。
为此,我将带有调试信息的被诊断程序的源代码编译为LLVM IR。到目前为止,所生成的元数据节点包含所需的源级别标识符。但是,我无法绘制与某些LLVM IR标识符和元数据中信息的连接。

例如,考虑一个类(class)的重要成员:

 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标识符对应于哪些元数据。

有人可以帮我吗?

最佳答案

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

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

那么,为什么我不仅仅使用clang AST来标识变量的存储和负载?因为区分AST中的读写不是一项简单的任务。 AST可以很容易地告诉您已访问变量,但是取决于操作是读取还是写入访问变量。因此,我将不得不考虑每个单个操作/运算符,以确定该变量是写入/读取还是两者兼有。在这方面,LLVM更简单,更底层,因此更不易出错。此外,与LLVM相比,AST中的实际检测(语音代码插入)要困难得多。由于这两个原因,我相信cAST AST和LLVM IR仪器的组合是解决我的问题的最佳解决方案。

关于c++ - LLVM IR : Identifying Variables with Metadata Nodes,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34578398/

10-11 23:07