基于clang的程序分析
2020.09.16
编译LLVM
CMake参数
-DLLVM_ENABLE_PROJECT="clang"
将clang模块也编译进去-DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10
用clang去编译整个项目,比gcc快-DCMAKE_BUILD_TYPE=Release
如果内存不够,用Release版本比Debug版本快
编译插件
将插件目录加入clang/examples
目录下,并添加到CMakeLists.txt中
CmakeLists.txt:
+add_subdirectory(MyPlugin)
编译
cmake -G "Unix Makefiles" ...
make MyPlugin
使用插件
clang++ Xclang -load -Xclang ../build/lib/MyPlugin.so -Xclang -add-plugin -Xclang my-plugin-name test.cpp
clang
主要是前端部分,预处理和AST构建
clang和llvm的使用场景
- clang:简单代码阅读即可解决的问题
- llvm:需要数据流/控制流分析解决的问题
clang-tutor
HelloWorld
-
translation unit:
input source file and all header files that it includes ,直接或间接都行,一个cpp文件,以及那些#include包括的文件为翻译单元
-
c++ record declaration:
struct/union/class
Clang AST
一般在translation unit中top-level declaration总是translation unit declaration
//+--function declaration 'f'
//|
int f(int x) { //--------------------------------------+
int result = (x / 42);//declaration statement |----compound statement
return result;//return statement | body of 'f'
} //---------------------------------------------------+
AST Context
所有关于AST translation unit的信息保存在ASTContext
类中
重要成员函数getTranslationUnitDecl
,获取顶层结构
AST Node
如果要traverse整个AST
-
从
TranslationUnitDecl
开始,然后不停的循环遍历,可以借助RecursiveASTVistor
-
Clang AST中最基本的node是
Stmt
和Decl
,以及Expr
RecursiveASTVisitor
实现一个类,继承RecursiveASTVisitor
,可以从AST获取相关信息
该类提供一个hooks方法
bool VisitNodeType(NodeType *)
[Node]可以是AST中各类nodes
node类型之间关系可以查看clang/Basic/
下的.td
文件,例如clang\Basic\DeclNodes.td
重写该方法可以自己拿到对应的类型,进行处理
编写插件
加入编译目录
在clang/example
目录下,新增插件名的文件夹,并将插件目录添加到该目录下的CmakeLists.txt
文件下
+ add_subdirectory(MyPluginDirName)
新建CMakeLists.txt
文件
add_llvm_library(PrintMacros MODULE PrintMacros.cpp PLUGIN_TOOL clang)
if(LLVM_ENABLE_PLUGINS AND (WIN32 OR CYGWIN))
set(LLVM_LINK_COMPONENTS
Support
)
clang_target_link_libraries(PrintMacros PRIVATE
clangAST
clangBasic
clangFrontend
clangLex
)
endif()
新建MyPlugin.cpp
文件
- 新建类继承
PluginASTAction
类,并重写CreateASTConsumer
和ParseArgs
两个函数 - 新建类继承
ASTConsumer
类,重写HandleTranslationUnit
方法等 - 新建类继承
RecursiveASTVisitor
类,重写VisitXXXDecl
方法,可以对不同的Node进行处理,XXX即为Node的类型名称 - 新建类继承
PPCallbacks
类,介入预处理结束后的调用过程