C++ 仪表化C/C++;使用LLVM的代码

C++ 仪表化C/C++;使用LLVM的代码,c++,llvm,static-analysis,clang,instrumentation,C++,Llvm,Static Analysis,Clang,Instrumentation,我刚刚读到了LLVM项目,它可以用来使用LLVM前端的analyzer Clang对C/C++代码进行静态分析。我想知道是否有可能使用LLVM提取源代码中对内存的所有访问(变量,本地和全局) LLVM中是否存在任何内置库,我可以使用它来提取这些信息。 如果没有,请建议我如何编写函数来实现相同的功能。(现有的源代码、参考、教程、示例…) 我的想法是,我会首先将源代码转换为LLVMBC,然后使用仪器对其进行分析,但不知道确切的方法 我试图弄清楚我应该使用哪个IR(Clang的抽象语法树(AST)或

我刚刚读到了LLVM项目,它可以用来使用LLVM前端的analyzer Clang对C/C++代码进行静态分析。我想知道是否有可能使用LLVM提取源代码中对内存的所有访问(变量,本地和全局)

LLVM中是否存在任何内置库,我可以使用它来提取这些信息。 如果没有,请建议我如何编写函数来实现相同的功能。(现有的源代码、参考、教程、示例…) 我的想法是,我会首先将源代码转换为LLVMBC,然后使用仪器对其进行分析,但不知道确切的方法


我试图弄清楚我应该使用哪个IR(Clang的抽象语法树(AST)或LLVM的SSA中间表示法(IR)),但无法真正弄清楚应该使用哪个IR。 这就是我要做的。 给定任何C/C++程序(如下面给出的程序),我试图在每个读写内存的指令之前和之后插入对某个函数的调用。例如,考虑下面的C++程序(Cuth.CPP)

#包括
类别帐户{
国际收支平衡;
公众:
帐户(内部b){
平衡=b;
}
int read(){
INTR;
r=平衡;
返回r;
}
无效存款(int n){
平衡=平衡+n;
}
撤销无效(int n){
int r=read();
平衡=r-n;
}
};
int main(){
账户*a=新账户(10);
a->存款(1);
a->撤回(2);
删除一条;
}
因此,插装之后,我的程序应该如下所示:

#include <stdio.h>

class Account {
  int balance;

public:
  Account(int b) {
    balance = b;
  }

  int read() {
    int r;
    foo();
    r = balance;
    foo();
    return r;
  }

  void deposit(int n) {
    foo();
    balance = balance + n;
    foo();
  }

  void withdraw(int n) {
    foo();
    int r = read();
    foo();
    foo();
    balance = r - n;
    foo();
  }
};

int main () {
  Account* a = new Account(10);
  a->deposit(1);
  a->withdraw(2);
  delete a;
}
#包括
类别帐户{
国际收支平衡;
公众:
帐户(内部b){
平衡=b;
}
int read(){
INTR;
foo();
r=平衡;
foo();
返回r;
}
无效存款(int n){
foo();
平衡=平衡+n;
foo();
}
撤销无效(int n){
foo();
int r=read();
foo();
foo();
平衡=r-n;
foo();
}
};
int main(){
账户*a=新账户(10);
a->存款(1);
a->撤回(2);
删除一条;
}
其中foo()可以是任何函数,如获取当前系统时间或增加计数器。。等等。我知道,要插入上述函数,我必须首先获取IR,然后在IR上运行一个插入传递,该传递将把此类调用插入IR,但我真的不知道如何实现它。请给我举个例子说明如何去做

我也明白,一旦我将程序编译成IR,就很难在我的原始程序和插入指令的IR之间获得1:1的映射。因此,是否有可能将IR中所做的更改(由于仪器)反映到原始程序中


为了开始学习LLVM过程以及如何自己创建一个过程,我查看了一个过程示例,该过程将运行时检查添加到LLVM IR加载和存储,即安全代码的加载/存储检测过程(and)。但我想不出怎么办这个通行证。请告诉我如何在某个程序上运行此通行证的步骤,例如上面的Account.cpp。

由于两天后您的问题没有答案,我将提供他的一个稍微但并非完全离题的答案

作为LLVM的替代,对于C程序的静态分析,可以考虑编写插件。

为C函数计算输入列表的现有插件需要访问函数体中的每个左值。这在文件src/inout/inputs.ml中实现。实现很短(复杂性在于其他插件向这个插件提供结果,例如解析指针),并且可以用作您自己插件的框架

框架提供了抽象语法树的访问者。为了对左值进行特殊处理,只需定义相应的方法。输入插件的核心是方法定义:

method vlval lv = ...
以下是输入插件的功能示例:

int a, b, c, d, *p;

main(){
  p = &a;
  b = c + *p;
}
main()
的输入计算如下:

$ frama-c -input t.c
...
[inout] Inputs for function main:
          a; c; p;

可以找到有关编写Frama-C插件的更多信息。

首先,您必须决定是使用clang还是LLVM。它们都在不同的数据结构上运行,各有优缺点

根据您对问题的稀疏描述,我建议您在LLVM中进行优化。使用IR将使清理、分析和注入代码变得更加容易,因为这正是它的设计初衷。缺点是您的项目将依赖于LLVM,这对您来说可能是个问题,也可能不是问题。您可以使用C后端输出结果,但人工无法使用

使用优化过程时的另一个重要缺点是,您还将丢失原始源代码中的所有符号。即使
Value
类(稍后将详细介绍)有一个
getName
方法,您也应该永远不要依赖它来包含任何有意义的内容。这是为了帮助你调试你的通行证,而不是别的

您还必须对编译器有基本的了解。例如,这是一个有点需要知道和。幸运的是,它们不是很难学习或理解的概念(维基百科的文章应该足够了)

在开始编码之前,您首先需要阅读一些内容,因此这里有几个链接可以帮助您开始:

  • :LLVM的快速体系结构概述。这将让您对正在使用的工具以及LLVM是否适合您有一个很好的了解

  • :您可以在这里找到下面的所有链接以及更多链接。如果我遗漏了什么,请参考这个

  • :这是您将要操作的LLVM IR的完整描述。这门语言相对简单,所以没有太多东西要学

  • :快速概述
    $ frama-c -input t.c
    ...
    [inout] Inputs for function main:
              a; c; p;