ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

使用GDB调试一个out-of-tree的 LLVM Pass

2022-06-12 15:03:00  阅读:256  来源: 互联网

标签:LegacyHelloWorld LLVM run tree 0000000000000000 llvm Pass debug


 

使用GDB调试一个out-of-tree的 LLVM Pass

 

时间:20220611,版本:V0.1

作者:robotech_erx

1.Introduction

环境:

Ubuntu 20.04 桌面版

LLVM 13.0.1 github下载的pre-build版本。Release配置的,没有调试符号。

GDB  9.2  (Ubuntu 9.2-0ubuntu1~20.04.1,系统自带的版本)

 

LLVM里编写Pass的时候,可以放到llvm源码目录下,也可以放到源码目录之外单独编译,即所谓的out-of-tree编译。Out-of-tree的方式能够保持LLVM自己的源码整洁。本文介绍怎样调试一个out-of-tree的Pass。

如果直接以Debug方式编译LLVM,需要的内存和硬盘空间都很恐怖。所以这里的LLVM是release编译的(从 github下载的pre-build版本),没有源码。但是Pass的代码是Debug的,能够单步调试。

测试的Pass代码来自于github上的llvm-tutor项目。

2.Release的opt加载debug的pass

能。至少在13.0.1这个版本里是可以的。

一开始,没有试一下就搜索,看到网上有文章说是不能加载的(https://www.leadroyal.cn/p/1014/)。看下原因是因为LLVM_ABI_BREAKING_CHECKS的原因,Debug和Release的采用了不同的配置。

官网上的解释是:LLVM_ABI_BREAKING_CHECKS:STRING

Used to decide if LLVM should be built with ABI breaking checks or not. Allowed values are WITH_ASSERTS (default), FORCE_ON and FORCE_OFF. WITH_ASSERTS turns on ABI breaking checks in an assertion enabled build. FORCE_ON (FORCE_OFF) turns them on (off) irrespective of whether normal (NDEBUG-based) assertions are enabled or not. A version of LLVM built with ABI breaking checks is not ABI compatible with a version built without it.

Release编译的版本里这个配置是FORCE_OFF,而debug的是打开的,所以release的 opt加载debug的opt会有问题。(貌似跟这个配置相关的还有另一个:LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING,相关信息请自行搜索)

原以为使用编译Pass的时候修改这个配置跟llvm opt 一样就可以了。但是发现不设置这个也能成功加载。

 

使用Debug配置编译llvm tutor的HelloWorld pass:

$export LLVM_DIR=/home/jack/worktable/llvm1301
$mkdir build
$cd build
$cmake -DLT_LLVM_INSTALL_DIR=$LLVM_DIR ../HelloWorld/
$make
$cmake -DLT_LLVM_INSTALL_DIR=$LLVM_DIR -DCMAKE_BUILD_TYPE=debug ../HelloWorld/

使用objdump 查看:已经有了信息:

$ objdump -h libHelloWorld.so

libHelloWorld.so:     file format elf64-x86-64

Sections:
Idx Name         Size      VMA        LMA       File off  Algn
  省略....
 26 .bss        00000090  0000000000019860  0000000000019860  00018850  2**5     ALLOC
 27 .comment      0000002b  0000000000000000  0000000000000000  00018850  2**0    CONTENTS, READONLY
 28 .debug_aranges    00000ee0  0000000000000000  0000000000000000  0001887b  2**0    CONTENTS, READONLY, DEBUGGING, OCTETS
 29 .debug_info     000e78dd  0000000000000000  0000000000000000  0001975b  2**0   CONTENTS, READONLY, DEBUGGING, OCTETS
 30 .debug_abbrev     00002027  0000000000000000  0000000000000000  00101038  2**0    CONTENTS, READONLY, DEBUGGING, OCTETS
 31 .debug_line     000037fb  0000000000000000  0000000000000000  0010305f  2**0     CONTENTS, READONLY, DEBUGGING, OCTETS
 32 .debug_str     002a6b1d  0000000000000000  0000000000000000  0010685a  2**0  CONTENTS, READONLY, DEBUGGING, OCTETS
 33 .debug_ranges     00000f00  0000000000000000  0000000000000000  003ad377  2**0   CONTENTS, READONLY, DEBUGGING, OCTETS

注意debug开头的各个section,调试信息都写进去了。GDB加载一下,也显示符号成功读取。使用opt加载运行:

$LLVM_DIR/bin/opt  -enable-new-pm=0    -load ./libHelloWorld.so -legacy-hello-world  input_for_hello.ll -o /dev/null

成功显示运行结果。

 

Opt是没有调试信息的release版本:

jack@jack-VirtualBox:~/worktable/llvm1301/bin$ gdb opt

...

GEF for linux ready, type `gef' to start, `gef config' to configure

96 commands loaded for GDB 9.2 using Python engine 3.8

Reading symbols from opt...

(No debugging symbols found in opt)

 

所以release版的opt是能够加载debug的pass的。接下来就好办了。

 

3.断点调试

官网文档上(https://llvm.org/docs/WritingAnLLVMPass.html)说的是可以再llvm::PassManager::run函数上下断点,然后加载pass。但是官网文档可能有点旧了,这个函数不存在了:

gef➤  break llvm::PassManager::run

Function "llvm::PassManager::run" not defined.

查找相关函数:

gef➤  info functions PassManager::run

All functions matching regular expression "PassManager::run":

Non-debugging symbols:

0x0000000001637ac0  (anonymous namespace)::CGPassManager::runOnModule(llvm::Module&)
0x00000000016f3b00  llvm::LPPassManager::runOnFunction(llvm::Function&)
0x000000000175dca0  llvm::RGPassManager::runOnFunction(llvm::Function&)
0x0000000001d7f6f0  llvm::FPPassManager::runOnFunction(llvm::Function&)
0x0000000001d86610  llvm::legacy::FunctionPassManager::run(llvm::Function&)
0x0000000001d868d0  llvm::FPPassManager::runOnModule(llvm::Module&)
0x0000000001d86c30  llvm::legacy::PassManager::run(llvm::Module&)

貌似现在这个函数现在是llvm::legacy::PassManager::run

gef➤  b llvm::legacy::PassManager::run

Breakpoint 1 at 0x1d86c30

 

但其实GDB是能够在未加载的文件(so)上下断点的,可以直接在pass代码中的函数上下断点的。

GDB查看所有的符号:

gef➤  info functions

All defined functions:

File /home/jack/worktable/llvm-tutor-main/HelloWorld/HelloWorld.cpp:

73: llvm::PassPluginLibraryInfo getHelloWorldPluginInfo();
92: llvm::PassPluginLibraryInfo llvmGetPassPluginInfo();
54: static bool (anonymous namespace)::HelloWorld::isRequired();
46: static llvm::PreservedAnalyses (anonymous namespace)::HelloWorld::run(llvm::Function&, llvm::FunctionAnalysisManager&);
60: static void (anonymous namespace)::LegacyHelloWorld::LegacyHelloWorld();
62: static bool (anonymous namespace)::LegacyHelloWorld::runOnFunction(llvm::Function&);
58: static void (anonymous namespace)::LegacyHelloWorld::~LegacyHelloWorld();
37: static void (anonymous namespace)::visitor(llvm::Function&);
static void _GLOBAL__sub_I_HelloWorld.cpp(void);
static void __static_initialization_and_destruction_0(int, int);

(符号非常多,只截取HelloWorld.cpp的)

 

可以在在LegacyHelloWorld::runOnFunction上下断点,在GDB里set confirm on打开未加载符号的询问,默认关闭了:

gef➤  b LegacyHelloWorld::runOnFunction
Function "LegacyHelloWorld::runOnFunction" not defined.
gef➤  set confirm on  
gef➤  b LegacyHelloWorld::runOnFunction
Function "LegacyHelloWorld::runOnFunction" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (LegacyHelloWorld::LegacyHelloWorld) pending.

gef➤  run -enable-new-pm=0    -load /home/jack/worktable/llvm-tutor-main/build/libHelloWorld.so -legacy-hello-world  /home/jack/worktable/llvm-tutor-main/build/input_for_hello.ll -o /dev/null

 

后面就是单步的调试了。

参考:

https://www.leadroyal.cn/p/1014/

https://llvm.org/docs/WritingAnLLVMPass.html#using-gdb-with-dynamically-loaded-passes

 

标签:LegacyHelloWorld,LLVM,run,tree,0000000000000000,llvm,Pass,debug
来源: https://www.cnblogs.com/robotech/p/16367989.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有