使用LLVM检测C / C ++代码

我想写一个LLVM传递来检测每个内存访问。 这是我想要做的。

给定任何C / C ++程序(如下面给出的那样),我试图在每次读取/写入/写入内存的指令之前和之后插入对某些函数的调用。 例如,考虑下面的C ++程序(Account.cpp)

#include  class Account { int balance; public: Account(int b) { balance = b; } ~Account(){ } int read() { int r; r = balance; return r; } void deposit(int n) { balance = balance + n; } void withdraw(int n) { int r = read(); balance = r - n; } }; int main () { Account* a = new Account(10); a->deposit(1); a->withdraw(2); delete a; } 

所以在仪器之后我的程序应该是这样的:

 #include  class Account { int balance; public: Account(int b) { balance = b; } ~Account(){ } 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; } 

其中foo()可以是任何函数,比如获取当前系统时间或递增计数器……等等。

请给我举例(源代码,教程等)以及如何运行它的步骤。 我已经阅读了关于如何在http://llvm.org/docs/WritingAnLLVMPass.html上提供LLVM Pass的教程,但是无法弄清楚如何为上述问题写一个传递。

尝试这样的事情:(你需要填写空白并使迭代器循环工作,尽管插入了项目)

 class ThePass : public llvm::BasicBlockPass { public: ThePass() : BasicBlockPass() {} virtual bool runOnBasicBlock(llvm::BasicBlock &bb); }; bool ThePass::runOnBasicBlock(BasicBlock &bb) { bool retval = false; for (BasicBlock::iterator bbit = bb.begin(), bbie = bb.end(); bbit != bbie; ++bbit) { // Make loop work given updates Instruction *i = bbit; CallInst * beforeCall = // INSERT THIS beforeCall->insertBefore(i); if (!i->isTerminator()) { CallInst * afterCall = // INSERT THIS afterCall->insertAfter(i); } } return retval; } 

希望这可以帮助!

我对LLVM不太熟悉,但我对GCC(及其插件机制)更熟悉,因为我是GCC MELT的主要作者(扩展GCC的高级域特定语言,顺便说一下你可以用于你的问题)。 因此,我将尝试回答一般性问题。

您应该首先知道为什么要调整编译器(或静态分析器)。 这是一个有价值的目标,但它确实有缺点(特别是,在您的C ++程序中重新定义一些运算符或其他构造)。

扩展编译器(无论是GCC还是LLVM或其他东西)的要点是你很可能应该处理它的所有内部表示(你可能不能跳过它的一部分,除非你有一个非常狭窄的定义问题)。 对于GCC来说,它意味着处理100多种Tree-s和近20种Gimple-s:在GCC中端,tree-s代表操作数和声明,gimple -s代表指令。 这种方法的优点是,一旦完成,您的扩展应该能够处理编译器可接受的任何软件。 缺点是编译器的内部表示的复杂性(这可以通过编译器接受的C&C ++源语言的定义的复杂性,以及它们产生的目标机器代码的复杂性以及通过增加的距离来解释。源语言和目标语言之间)。

因此,攻击一般编译器(无论是GCC还是LLVM),还是静态分析器(如Frama-C),是一项相当大的任务(超过一个月的工作,而不是几天)。 要只处理像你所展示的微小的C ++程序,它是不值得的。 但是,如果你明白处理大型源代码软件库,那绝对值得努力。

问候