一、 编译LLVM debug版本
调试LLVM代码需要基于debug版本,编译LLVM时,将build type设为Debug即可: cmake -DCMAKE_BUILD_TYPE=Debug ... ...
二、GDB调试
- 调试OPT
reference:Debugging an llvm pass with gdb - Stack Overflow
所有的LLVM pass都使用opt运行。pass被编译成共享的目标文件(*.so)。因此,文件在build/lib中,然后由opt工具加载。为了调试或逐步完成这个过程,我们必须在LLVM开始执行so文件之前停止它,因为没有办法在共享对象文件中放置断点。相反,我们可以在代码中在调用pass之前放一个断点。
下面根据以下步骤在llvm/lib/IR/Pass.cpp中设置断点:
1. gdb opt
若非可debug版本,会报“no debugging symbols found”。
2. 设置断点
现在我们需要在Pass.cpp中的void Pass::preparePassManager(PMStack &)方法中设置一个断点。这可能是第一个(或第一批)涉及到加载传递的方法。
在gdb命令行输入:break llvm::Pass::preparePassManager
3. 运行pass
run `opt -load=/pathTo/LLVMHello.so -hello < /pathTo/your.bc > /dev/null`
- 调试Clang
reference: gdb调试llvm源码_当格子衫爱上Helloworld的博客-CSDN博客_llvm gdb
1. gdb clang
2. 设置gdb调试参数,调试运行。
-
set follow-fork-mode mode
,mode = child|parent,程序在执行fork系统调用后,继续执行父进程,还是调试子进程。 - set args,设置gdb调试参数,通过"clang ... -v"打印编译时参数。
- b main,在clang工具链main函数设置断点(clang/tools/driver/driver.cpp)。
三、LLVM LLVM_DEBUG(原DEBUG)宏
编写Pass时,可以借助DEBUG宏添加调试代码,这些代码只有在工具命令行加入“-debug”选项时才会执行。
1. DEBUG宏定义
llvm/include/llvm/Support/Debug.h
2. Clang和opt工具使能DEBUG宏
参考: LLVM Programmer’s Manual — LLVM 16.0.0git documentation
- opt
例如:
LLVM_DEBUG(dbgs() << "I am here!\n");
Then you can run your pass like this:
$ opt < a.bc > /dev/null -mypass <no output> $ opt < a.bc > /dev/null -mypass -debug I am here! 注: 若提示“Unknown command line argument '-debug'”,检查是否使用NDEBUG宏构建的llvm(则-debug不存在)
- Clang
通过Clang调试Pass时,需要使能LLVM的DEBUG()宏,Clang控制LLVM的参数,前面都需要加“-mllvm”:
-mllvm -debug
-mllvm -debug-only=<DEBUG_TYPE>