gdb prettp printer加载原理
背景
如何在你还记得这两张图,那么就好办了,来自 01_gdb容器可视化概论:
如果你不清楚这两张图的含义,请查看: 01_gdb容器可视化概论
pretty printer 加载方式
我们使用系统 gdb 对项目进行调试,然后来到调试控制台,我们可以看到如下信息,gdb在加载动态库:
Breakpoint 1, main (argc=2, argv=0x7fffffffdca8) at /home/haorui/haorui/web_tc/src/main.cpp:14
14 int main(int argc, char** argv) {
Loaded '/lib/x86_64-linux-gnu/libpthread.so.0'. Symbols loaded.
Loaded '/usr/lib/x86_64-linux-gnu/libstdc++.so.6'. Symbols loaded.
Loaded '/lib/x86_64-linux-gnu/libm.so.6'. Symbols loaded.
Loaded '/lib/x86_64-linux-gnu/libgcc_s.so.1'. Symbols loaded.
Loaded '/lib/x86_64-linux-gnu/libc.so.6'. Symbols loaded.
Execute debugger commands using "-exec <command>", for example "-exec info registers" will list registers in use (when GDB is the debugger)
我们可以暂时记一下,这里面有依据 Loaded '/usr/lib/x86_64-linux-gnu/libstdc++.so.6'. Symbols loaded.
。
然后我开启讲解一下 gdb 加载插件的六种方式吧,说是 pretty printer
并不是特别好,应该称之为插件,这里使用 auto-load
,你可以看到以下的内容:
gdb-scripts: Auto-loading of canned sequences of commands scripts is on.
libthread-db: Auto-loading of inferior specific libthread_db is on.
local-gdbinit: Auto-loading of .gdbinit script from current directory is on.
python-scripts: Auto-loading of Python scripts is on.
safe-path: List of directories from which it is safe to auto-load files is $debugdir:$datadir/auto-load.
scripts-directory: List of directories from which to load auto-loaded scripts is $debugdir:$datadir/auto-load.
我个人会了解的也只有
gdb-scripts
、local-gdbinit
、safe-path
,其中safe-path
应该是最合理的解决方案了。
以上就是 gdb 加载插件的六种途径,像网上大多使用的基本是通过 local-gdbinit
的方式加载插件,而 ubuntu 则是使用 safe-path
加载插件。
auto load
顾名思义就是自动加载,不需要你人为地加载,我们可以使用 info auto-load
查看已经加载的插件,打印出来的内容如下:
gdb-scripts: No auto-load scripts.
libthread-db: No auto-loaded libthread-db.
local-gdbinit: Local .gdbinit file was not found.
python-scripts:
Loaded Script
Yes /usr/share/gdb/auto-load/lib/x86_64-linux-gnu/libpthread-2.27.so-gdb.py
Yes /usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25-gdb.py
这两个动态库是我程序中使用的,你可以看看这个目录下是不是有一个 auto load
的文件夹,如下:
这里简单地解释一下其加载规则,直接在下图中给出了,以加载 /usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25-gdb.py
为例:
这里给出原理是因为我怕你直接 copy 这个给远程调试的 gdb 使用了,它们是不能混用的,当然你说改一改能不能用,答案是可以的;但是我看了一下,有点难改,改了一下午没搞定,就换方案了。
但是本地 gdb 是有效果的,比如我把这个 auto-load 拷贝给我源码编译本地调试用的 gdb ,那么应该可以做到容器的可视化。
远程调试 gdb pretty printer 配置
虽说我们知道本地或者系统的 gdb 可以通过 auto-load
的方式自动加载 pretty printer
记载对应的 printer
,但是你也要明白 auto-load
是不能够混用的。
但是巧就是巧了,基本所有的库的 py 脚本都写得一样,我们看看 libstdc++.so.6.0.25-gdb.py
这个脚本是怎么写的吧,其中关键四行:
# Call a function as a plain import would not execute body of the included file
# on repeated reloads of this object file.
from libstdcxx.v6 import register_libstdcxx_printers
register_libstdcxx_printers(gdb.current_objfile())
这其实就是你在其他博客哪里看到开启 gdb pretty printers 的方式。
我们看到了自动加载的脚本是如何加载的,那虽然自动不了,但是我可以手动加嘛,这是小问题,使用 local-gdbinit
这种方式实现,你在你的 ~
目录的 share
下 touch .gdbinit
,然后在其中添加:
python
import sys
# 借用 ubuntu 系统自带的,按照自己的填写
sys.path.insert(0, '/usr/share/gcc-8/python/libstdcxx/v6')
sys.path.insert(0, '/usr/share/gcc-8/python')
# 修改成你自己安装的 gdb 路径
sys.path.insert(0, '/home/haorui/tools/arm-hisiv600-linux-gdb/share/gdb/python')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
然后我们远程调试看看效果,如下:
可以看到 165 of 165 printers enabled
, 不是 171 ,少了 6 个是来自线程库的。
不过原理懂了,那就可以改嘛,小问题,利用 source
一脚把 py 脚本提起来:
source /usr/share/gdb/auto-load/lib/x86_64-linux-gnu/libpthread-2.27.so-gdb.py
python
import sys
sys.path.insert(0, '/usr/share/gcc-8/python/libstdcxx/v6')
sys.path.insert(0, '/usr/share/gcc-8/python')
sys.path.insert(0, '/home/haorui/tools/arm-hisiv600-linux-gdb/share/gdb/python')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
171,一个不多一个不少,说明什么呢,我们可以从 auto-load 里面去偷脚本,虽然它们可能不是通用的,但是绝大部分是通用的;而 auto-load 里面的文件大多数都是安装库的时候自动装上去的,也就是 auto-load 中的文件不是一成不变的。
同时研究其 py 脚本的实现,你可以实现自己的 printer, 还是有很多地方需要这个东西的。
总结
其实这是一篇比较不严谨的文章,毕竟我才刚刚接触 gdb 命令行工具,而且我也不打算继续深入,毕竟对我没什么太大的实际价值,我要找的东西已经找齐了;但是对你而言可能不够,你可以阅读一个 GDB 参考手册, 下载一份还是挺有价值的,这些东西都可以在里面找到答案。