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