配置 Linux 下的 C++ 标准库调试环境

在 Linux 下调试时,我发现没法跟踪到 C++ 标准库里面去,难以理解标准库的精确行为。今天,花了点力气,全部都配置出来了。做点笔记,既自己总结一下,也希望能对别人(主要对 Linux 下的中高级 C++ 开发者)有用。

我的环境是 Ubuntu Linux 24.04 LTS(以下简称为 Ubuntu 24.04),架构为 x86-64。其原理应当也适用于其他 Linux 环境,但文中的命令仅在 Ubuntu 24.04 下调试通过,路径也多半只对当前版本/平台有效。

更新:又在 Ubuntu Linux 22.04 LTS 上配置了一下。参考配置见结尾。

安装 gdb-dashboard

我一直在使用 gdb-dashboard,它是一个非常有用的 GDB 配置文件,还同时提供了在 ~/gdbinit.d/ 目录下存放额外配置项的能力。我这边的配置,也是假设已经安装了 gdb-dashboard。

根据官方说明,我们可以直接使用下面的命令进行安装:

wget -P ~ https://github.com/cyrus-and/gdb-dashboard/raw/master/.gdbinit

为了能够高亮显示源代码,gdb-dashboard 建议用户安装 Pygments。跟作者建议的方式不同,我们在 Ubuntu 上一般通过以下命令来安装:

sudo apt install python3-pygments

配置标准库的调试符号和源码

现在我们已经可以看到一个更加直观的调试界面,部分截图如下:

gdb-dashboard 里的 hello world

目前,GDB 已经支持自动下载调试信息。但我们尝试一下就会发现,我们还是没法跟踪到 libstdc++ 库内部去(如这里的 operator<<)。手工配置仍然需要。

因为 Ubuntu 24.04 默认安装的 libstdc++ 版本是 14(可以用 apt list libstdc++6 命令查看),我们需要安装相应版本的调试符号和源代码(debian/rules 解包源码,并对源码打补丁):

sudo apt install libstdc++6-14-dbg gcc-14-source
cd /usr/src/gcc-14
sudo debian/rules patch

类似地,可以把 C 标准库的调试符号和源代码也安装一下(此处似乎源码包里已有所有需要的补丁):

sudo apt install libc6-dbg glibc-source
cd /usr/src/glibc
sudo tar xf glibc-2.39.tar.xz

我们现在也需要配置一下 GDB 了。我们可以直接创建 ~/.gdbinit.d 目录,然后在其中创建一个 gdb-settings 文件,最初的内容可以是:

set debuginfod enabled off

set env LD_LIBRARY_PATH /usr/lib/x86_64-linux-gnu/debug:${LD_LIBRARY_PATH}
set auto-load safe-path /usr/lib/x86_64-linux-gnu/debug/

python sys.path.insert(0, "/usr/share/gcc/python");

既然自己加调试符号,我们就把自动下载调试符号的设置关了,调试时更加快捷,可避免网络延迟(把这行删掉可恢复默认行为,或把 off 改成 on 来每次自动下载)。然后我们设置环境变量 LD_LIBRARY_PATH,把调试库所在的目录加进去。我们需要设置 safe-path,允许该目录下的 Python 代码执行。最后,执行该代码会需要我们设置 Python 路径,否则会有报错。

在这样设置以后,我们就能够跟踪到标准库里面去了。但麻烦的是,调试符号里的路径跟我们现在的机器上的路径常常不一致,因此虽然有符号能跟踪进去,但却会找不到合适的文件。这时候,需要一点耐心,把报告没找到的路径跟机器上的实际代码路径匹配起来,然后用 GDB 命令设置它们之间的关联。这是我目前环境里的设置(供参考):

set substitute-path /build/gcc-14-ig5ci0/gcc-14-14.2.0/build/x86_64-linux-gnu/libstdc++-v3/include /usr/include/c++/14
set substitute-path /build/gcc-14-ig5ci0/gcc-14-14.2.0 /usr/src/gcc-14
set substitute-path ../../../../../../src/libstdc++-v3 /usr/src/gcc-14/src/libstdc++-v3
set substitute-path ../../../../../src/libstdc++-v3 /usr/src/gcc-14/src/libstdc++-v3
set substitute-path ../../../../src/libstdc++-v3 /usr/src/gcc-14/src/libstdc++-v3

directory /usr/src/glibc/glibc-2.39

完全成功之后,我们应当看到能够跟踪到标准库的代码里去了。下图展示我们跟踪进了 Hello World 里的 operator<<

成功跟踪进 libstdc++

gdb-dashboard 的进一步设置

gdb-dashboard 的显示虽然美观,但内容往往有点太多,尤其不方便在 IDE 里调试使用。我们可以用过下面两种方式来进行定制。

首先,我们可以默认不显示 dashboard,这可以使用下面的设置(建议放到 ~/gdbinit.d/gdb-settings 里):

dashboard -enabled off

此时,如果我们需要 dashboard 显示,可以在 GDB 里使用 dashboard 命令进行单次显示,或者使用 dashboard -enabled on 命令恢复成每次执行命令之后都显示。你可以会希望有个在命令行上快速启用 dashboard 的别名(一般加到 ~/.bashrc 里):

alias gdb-dashboard='gdb -ex "dashboard -enabled on"'

gdb-dashboard 提供了很多命令(可在 GDB 运行时使用 help dashboard 来查看),其中包括配置某个模块(汇编、断点、表达式、寄存器、源代码等)的显示与否。比如,运行 dashboard register 在寄存器显示打开时可以将其关闭,再运行一次则重新打开。

又如,因为 GNU 风格的代码使用宽度为 8 的 tab,我们自己代码如果不使用 tab 的话(推荐用空格,不用 tab),就应该让 gdb-dashboard 显示时认为 tab 的宽度是 8(顺便说一下,我看到过很多“不正确”的显示 libstdc++ 源码的截图,原因就是因为 tab 的宽度设置错误)。上面的截图已经有了正确的设置,而没有设置正确的话,代码会像下面这样子:

错误的 tab 设置

我们可以使用下面的命令来设置,显示就会正常了:

dashboard source -style tab-size 8

当显示的内容比较合乎我们的意图时,我们可以把这个当前配置保存下来,比如:

dashboard -configuration ~/.gdbinit.d/dashboard-configuration

这样,~/.gdbinit.d/dashboard-configuration 里存的是 gdb-dashboard 能自动保存的内容,而 ~/gdbinit.d/gdb-settings 里则保存我们需要手工配置的内容。

下面是我的 gdb-settings 里面的完整内容(供参考):

set debuginfod enabled off

set env LD_LIBRARY_PATH /usr/lib/x86_64-linux-gnu/debug:${LD_LIBRARY_PATH}
set auto-load safe-path /usr/lib/x86_64-linux-gnu/debug/

python sys.path.insert(0, "/usr/share/gcc/python");

set substitute-path /build/gcc-14-ig5ci0/gcc-14-14.2.0/build/x86_64-linux-gnu/libstdc++-v3/include /usr/include/c++/14
set substitute-path /build/gcc-14-ig5ci0/gcc-14-14.2.0 /usr/src/gcc-14
set substitute-path ../../../../../../src/libstdc++-v3 /usr/src/gcc-14/src/libstdc++-v3
set substitute-path ../../../../../src/libstdc++-v3 /usr/src/gcc-14/src/libstdc++-v3
set substitute-path ../../../../src/libstdc++-v3 /usr/src/gcc-14/src/libstdc++-v3

directory /usr/src/glibc/glibc-2.39

dashboard -enabled off

Ubuntu Linux 22.04 LTS 上的配置

我在 22.04 上也成功进行了配置。下面是变化点。

gcc 和 glibc 的版本变化:

sudo apt install libstdc++6-12-dbg gcc-12-source
cd /usr/src/gcc-12
sudo debian/rules patch
sudo apt install libc6-dbg glibc-source
cd /usr/src/glibc
sudo tar xf glibc-2.35.tar.xz

gdb-settings 里的路径有变化,下面是修改后的完整版本:

set env LD_LIBRARY_PATH /usr/lib/x86_64-linux-gnu/debug:${LD_LIBRARY_PATH}
set auto-load safe-path /usr/lib/x86_64-linux-gnu/debug/

python sys.path.insert(0, "/usr/share/gcc/python");

set substitute-path /build/gcc-12-ALHxjy/gcc-12-12.3.0/build/x86_64-linux-gnu/libstdc++-v3/include /usr/include/c++/12
set substitute-path /build/gcc-12-ALHxjy/gcc-12-12.3.0 /usr/src/gcc-12
set substitute-path ../../../../../../src/libstdc++-v3 /usr/src/gcc-12/src/libstdc++-v3
set substitute-path ../../../../../src/libstdc++-v3 /usr/src/gcc-12/src/libstdc++-v3
set substitute-path ../../../../src/libstdc++-v3 /usr/src/gcc-12/src/libstdc++-v3

directory /usr/src/glibc/glibc-2.35

dashboard -enabled off

好,我的笔记就到这里了。希望这个笔记也能对你有用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值