我现在工作中要写个fuzz引擎,语法分析部分用到了clang的接口,打算写一些博客记录绍下,ast(抽象语法树),libtooling接口的使用等等
llvm clang AST 介绍
Clang的AST与其他一些编译器生成的AST不同,它与书写的C++代码和C++标准非常相似。例如,括号表达式和编译时常量在AST中以未简化的形式存在。这使得Clang的AST非常适合重构工具。
所有Clang AST节点的文档可以通过生成的Doxygen访问。Doxygen在线文档也被您喜欢的搜索引擎索引,因此通常搜索clang和AST节点的类名就可以找到您要查找的类的doxygen文档(例如,搜索:clang ParenExpr)
检查AST (抽象语法树)
了解AST结构,对于调试、性能优化、代码分析和重构等方面都非常有帮助
生成AST结构命令
命令1(常用)
clang -Xclang -ast-dump -fsyntax-only test.cc
命令2(ast结构更精确)
conmmand_json.cc里的编译命令 + -Xclang -ast-dump -fsyntax-only
以上2种方式生成ast语法树都可以 下面是生成ast的结构
$ cat test.cc
int f(int x) {
int result = (x / 42);
return result;
}
# Clang by default is a frontend for many tools; -Xclang is used to pass
# options directly to the C++ frontend.
$ clang -Xclang -ast-dump -fsyntax-only test.cc
TranslationUnitDecl 0x5aea0d0 <<invalid sloc>>
... cutting out internal declarations of clang ...
`-FunctionDecl 0x5aeab50 <test.cc:1:1, line:4:1> f 'int (int)'
|-ParmVarDecl 0x5aeaa90 <line:1:7, col:11> x 'int'
`-CompoundStmt 0x5aead88 <col:14, line:4:1>
|-DeclStmt 0x5aead10 <line:2:3, col:24>
| `-VarDecl 0x5aeac10 <col:3, col:23> result 'int'
| `-ParenExpr 0x5aeacf0 <col:16, col:23> 'int'
| `-BinaryOperator 0x5aeacc8 <col:17, col:21> 'int' '/'
| |-ImplicitCastExpr 0x5aeacb0 <col:17> 'int' <LValueToRValue>
| | `-DeclRefExpr 0x5aeac68 <col:17> 'int' lvalue ParmVar 0x5aeaa90 'x' 'int'
| `-IntegerLiteral 0x5aeac90 <col:21> 'int' 42
`-ReturnStmt 0x5aead68 <line:3:3, col:10>
`-ImplicitCastExpr 0x5aead50 <col:10> 'int' <LValueToRValue>
`-DeclRefExpr 0x5aead28 <col:10> 'int' lvalue Var 0x5aeac10 'result' 'int'
在翻译单元中,最顶层的声明总是翻译单元声明。在这个例子中,我们第一个用户编写的声明是函数“f”的声明。函数“f”的主体是一个复合语句,其子节点包括一个声明语句,用于声明我们的结果变量,以及一个返回语句
AST Context
所有关于翻译单元AST的信息都被封装在ASTContext类中。它允许从getTranslationUnitDecl开始遍历整个翻译单元,或者访问Clang为解析的翻译单元提供的标识符表。
AST Nodes
Clang的AST节点是基于一个没有共同祖先的类层次结构建模的。相反,有多个更大的层次结构用于基本节点类型,如Decl和Stmt。许多重要的AST节点派生自Type、Decl、DeclContext或Stmt,有些类同时从Decl和DeclContext派生。
AST中也有大量不属于更大层次结构的节点,它们只能从特定的其他节点访问,如CXXBaseSpecifier。
因此,要遍历完整的AST,需要从TranslationUnitDecl开始,然后递归遍历从该节点可以到达的所有内容 - 这些信息必须为每个特定的节点类型编码。这个算法在RecursiveASTVisitor中编码。请参阅RecursiveASTVisitor教程。
在Clang AST中,两个最基本的节点是语句(Stmt)和声明(Decl)。请注意,在Clang的AST中,表达式(Expr)也被视为语句。
后面文章会介绍下 llvm的编译 RecursiveASTVisitor使用 LibASTMatchers使用