llvm clang AST 介绍

我现在工作中要写个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使用

参考: Introduction to the Clang AST

要解析 LLVM 的抽象语法树(AST),你可以使用 LLVM 提供的工具和库。下面是一个简单的步骤: 1. 首先,确保你已经安装了 LLVM。你可以从 LLVM 官方网站(https://llvm.org/)下载并按照指南进行安装。 2. 使用 Clang 编译器将源代码转换为 LLVM 的中间表示(IR)。可以使用以下命令生成 IR 文件: ``` clang -S -emit-llvm source_code.c -o output.ll ``` 这将把源代码 `source_code.c` 编译为 `output.ll` 的 LLVM IR 文件。 3. 使用 LLVM 提供的库来解析和操作 IR。LLVM 提供了多种编程语言的 API,包括 C++、Python 和 Rust 等。你可以根据自己的喜好选择合适的 API。 在 C++ 中,你可以使用 LLVMC++ API 来解析 AST。以下是一个简单的示例: ```cpp #include <llvm/IR/LLVMContext.h> #include <llvm/IR/Module.h> #include <llvm/IRReader/IRReader.h> #include <llvm/Support/SourceMgr.h> int main() { llvm::LLVMContext context; llvm::SMDiagnostic error; // 从 IR 文件中读取模块 std::unique_ptr<llvm::Module> module = llvm::parseIRFile("output.ll", error, context); if (!module) { // 解析失败 error.print("error", llvm::errs()); return 1; } // 对解析得到的模块进行操作,如遍历函数、基本块等 return 0; } ``` 这个示例使用 LLVM 的 `parseIRFile` 函数从 IR 文件中读取模块,并使用 `LLVMContext` 来创建一个上下文。然后,你可以对模块进行遍历和操作。 请注意,这只是一个简单的示例,你可以根据具体需求进行更复杂的操作。 希望这可以帮助你开始解析 LLVMAST!如有更多问题,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值