ubuntu18.04环境下编译支持debuginfod的gdb

发布时间 2023-10-14 20:27:59作者: 刘跑跑

ubuntu18.04环境下编译支持debuginfod的gdb

介绍

Ubuntu 22.10 版本才默认安装debuginfod,对于之前的发行版都需要手动配置。gdb从10.1版本才开始支持debuginfod,而Ubuntu旧的发行版里gdb都低于10.1版本。另外,debuginfod被包含在elfutils里面,且从elfutils-0.178版本后才支持,而Ubuntu旧的发行版里elfutils版本都低于0.178,因此需要先源码编译安装高版本elfutils,再编译安装高版本gdb,最终才能实现在Ubuntu旧的发行版中使用支持debuginfod的gdb来调试程序。

注意:gdb-10.1及以后版本要求libdebuginfod >= 0.179,所以elfutils最低版本为0.179。

debuginfod_demo

编译安装elfutils-0.179

  1. 下载elfutils-0.179:
wget https://sourceware.org/elfutils/ftp/0.179/elfutils-0.179.tar.bz2
  1. 解压后, 通过./configure && make && make install编译安装,这里我手动指定了安装路径:
./configure --prefix=/home/geduer/elfutils-0.179
  1. 在configure时会遇到下面报错:
checking for libmicrohttpd... no
checking for libcurl... no
checking for sqlite3... no
checking for libarchive... no
configure: error: C++ compiler or dependencies not found, use --disable-debuginfod to disable.

原因是系统下缺少libmicrohttpd、libcurl 、sqlite3、libarchive这四个依赖库,通过apt来安装这些依赖库,还需要安装对应的dev开发包,所以选择直接安装dev包,默认会把依赖库也安装。

sudo apt-get install libcurl4-openssl-dev
sudo apt-get install libsqlite3-dev
sudo apt-get install libarchive-dev
sudo apt-get install  libmicrohttpd-dev
  1. 安装好依赖库后再configure就不报错了,最后会显示elfutils配置清单,可以看到此时已支持Debuginfod特性:
        elfutils: 0.179 (eu_version: 179)
......
  OTHER FEATURES
......
    Debuginfod client/server support   : yes
......
  1. 最后把自定义的安装路径添加到系统环境变量里,这样启动gdb时才能识别到debuginfod库。
export PATH=/home/geduer/elfutils-0.179/bin:$PATH
export LD_LIBRARY_PATH=/home/geduer/elfutils-0.179/lib:$LD_LIBRARY_PATH

编译安装gdb-13.1

  1. 下载源码
wget https://ftp.gnu.org/gnu/gdb/gdb-13.1.tar.gz
  1. 编译安装
./configure --prefix=/home/geduer/gdb/install --enable-tui --with-debuginfod
make && make install

虽然已经安装了debuginfod,但是gdb编译还是同样报错:

checking for aarch64-unknown-linux-gnu-pkg-config... /usr/bin/aarch64-unknown-linux-gnu-pkg-config
checking pkg-config is at least version 0.9.0... yes
checking whether to use debuginfod... yes
checking for libdebuginfod >= 0.179... no
configure: error: "--with-debuginfod was given, but libdebuginfod is missing or unusable."

排查发现,gdb编译时识别到--with-debuginfod选项后,会通过pkg-config工具来查找debuginfod依赖库。pkg-config是通过查找后缀名为pc的配置文件判断依赖库是否存在,结果没找到libdebuginfod.pc文件,就认为缺少debuginfod库。可以从gdb/configure里截取相关命令来手动检测:

$ /usr/bin/aarch64-unknown-linux-gnu-pkg-config --exists --print-errors "libdebuginfod >= 0.179"
Package libdebuginfod was not found in the pkg-config search path.
Perhaps you should add the directory containing `libdebuginfod.pc'
to the PKG_CONFIG_PATH environment variable
No package 'libdebuginfod' found

然后到debuginfod安装目录查找一下,发现配置文件路径为:lib/pkgconfig/libdebuginfod.pc。最后需要把包含的libdebuginfod.pc路径导入到环境变量PKG_CONFIG_LIBDIR

export PKG_CONFIG_LIBDIR=/home/geduer/elfutils-0.179/lib/pkgconfig

注意:如果把libdebuginfod.pc路径导入到环境变量PKG_CONFIG_PATH,结果还是会识别不到。查pkg-config手册发现PKG_CONFIG_LIBDIR比PKG_CONFIG_PATH优先级更高,PKG_CONFIG_PATH只是附加一个搜索路径,PKG_CONFIG_LIBDIR则是覆盖默认的搜索路径。如果嫌配置麻烦,可以在安装elfutils时,选择默认安装路径,即/usr/local目录,pkg-config默认会搜索/usr/local目录。

可以通过下面命令测试下是否能成功搜索到pc配置文件(echo $?结果为0表示执行结果正确,为1表示错误):

pkg-config --exists libdebuginfod
echo $?
0

debuginfod的使用方法

配置debuginfod服务器地址

首先配置debuginfod服务器地址 https://debuginfod.ubuntu.com ,将其添加到~/.bashrc里:

export DEBUGINFOD_URLS="https://debuginfod.ubuntu.com"

当使用gdb调试程序时,会通过http远程访问debuginfod服务器,根据程序唯一的build-id下载对应的调试符号和源文件(前提时服务器里有对应的符号文件和源码包)到本地~/.cache/debuginfod_client目录。

gdb中debuginfod命令

启动gdb-13.1,通过命令show debuginfod查看debuginfod配置,主要包括三个配置:

  • 每次启动gdb会主动询问是否开启debuginfod功能,可以把命令set debuginfod enabled on添加到~/.gdbinit里永久开启;
  • 设置debuginfod服务器地址,不同发行版厂商会维护自己的debuginfod服务器。
  • 打开debuginfod运行时的详细输出信息,可以通过命令set debuginfod verbose 0关闭符号下载过程信息打印。
(gdb) show debuginfod 
debuginfod enabled:  Debuginfod functionality is currently set to "ask".
debuginfod urls:  Debuginfod URLs are currently set to:
https://debuginfod.ubuntu.com
debuginfod verbose:  Debuginfod verbose output is set to 1.

gdb里和debuginfod相关的命令如下,主要用来设置和显示上述的三个配置。

(gdb) apropos debuginfod
set debuginfod -- Set debuginfod options.
set debuginfod enabled -- Set whether to use debuginfod.
set debuginfod urls -- Set the list of debuginfod server URLs.
set debuginfod verbose -- Set verbosity of debuginfod output.
show debuginfod -- Show debuginfod options.
show debuginfod enabled -- Show whether to use debuginfod.
show debuginfod urls -- Show the list of debuginfod server URLs.
show debuginfod verbose -- Show debuginfod debugging.
(gdb)

使用演示

  1. 通过gdb调试git,启动后输入y启用debuginfod后便自动下载调试符号:
geduer@gdk8:~/gdb/install/bin$ ./gdb /usr/bin/git -q
Reading symbols from /usr/bin/git...
This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
Downloading separate debug info for /usr/bin/git
[####################################                                    ]  32% (4.19 M)
  1. 下载完后会自动读取符号文件,设置main断点后提示源码下载失败,这因为debuginfod是新特性,所以debuginfod服务器里对旧版Ubuntu的调试符号和源码支持不够完善,这里需要我们自己手动下载源码,并添加到gdb源码搜索路径里:
   Reading symbols from /home/geduer/.cache/debuginfod_client/f1b3574e4c6c4600819de4fe860b1912235a8be3/debuginfo...                     
   (gdb) b main
   Download failed: Invalid argument.  Continuing without source file ./common-main.c.
   Breakpoint 1 at 0x17108: file common-main.c, line 27.
   (gdb) !sudo apt source git
Reading package lists... Done
NOTICE: 'git' packaging is maintained in the 'Git' version control system at:
https://repo.or.cz/r/git/debian.git/
Please use:
git clone https://repo.or.cz/r/git/debian.git/
to retrieve the latest (possibly unreleased) updates to the package.
Skipping already downloaded file 'git_2.17.1-1ubuntu0.18.dsc'
Skipping already downloaded file 'git_2.17.1.orig.tar.xz'
Skipping already downloaded file 'git_2.17.1-1ubuntu0.18.debian.tar.xz'
Need to get 0 B of source archives.
Skipping unpack of already unpacked source in git-2.17.1
(gdb) directory git-2.17.1/
Source directories searched: /home/geduer/gdb/install/bin/git-2.17.1:$cdir:$cwd
  1. 开始调试运行程序,debuginfod会自动判断下载的其他依赖库的调试符号:
(gdb) run
Starting program: /usr/bin/git 
Downloading separate debug info for /lib/ld-linux-aarch64.so.1
Downloading separate debug info for system-supplied DSO at 0x7ff7ffc000 
Downloading separate debug info for /lib/aarch64-linux-gnu/libpcre.so.3                   Downloading separate debug info for /lib/aarch64-linux-gnu/libz.so.1                     Downloading separate debug info for /lib/aarch64-linux-gnu/libpthread.so.0               [Thread debugging using libthread_db enabled]                                             Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1".
Downloading separate debug info for /lib/aarch64-linux-gnu/libc.so.6

Breakpoint 1, main (argc=1, argv=0x7ffffff3d8) at common-main.c:27
warning: Source file is more recent than executable.
27	{
(gdb) l
22		sigprocmask(SIG_UNBLOCK, &unblock, NULL);
23		signal(SIGPIPE, SIG_DFL);
24	}
25	
26	int main(int argc, const char **argv)
27	{
28		/*
29		 * Always open file descriptors 0/1/2 to avoid clobbering files
30		 * in die().  It also avoids messing up when the pipes are dup'ed
31		 * onto stdin/stdout/stderr in the child processes we spawn.
  1. 还可以根据源文件和行号设置断点,注意自己下载的源码和系统下的二进制可能不是完全匹配,基于符号调试时可能源码行号对应信息有偏移误差,自行诊断:
(gdb) b git.c:666
Breakpoint 2 at 0x555556d49c: file git.c, line 666.
(gdb) c
Continuing.

Breakpoint 2, cmd_main (argc=<optimized out>, argc@entry=1, argv=<optimized out>, argv@entry=0x7ffffff3d8) at git.c:666
warning: Source file is more recent than executable.
666			commit_pager_choice();
(gdb) n
667			printf("usage: %s\n\n", git_usage_string);
(gdb) p git_usage_string
$2 = 0x55556f8870 <git_usage_string> "git [--version] [--help] [-C <path>] [-c <name>=<value>]\n", ' ' <repeats 11 times>, "[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n", ' ' <repeats 11 times>, "[-p | --paginate | --no-pager] [--no-replace-objects] [--"...
(gdb) n
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

668			list_common_cmds_help();
(gdb)

Ubuntu 22.xx安装方法

Ubuntu22.xx 版本系统仓库里有debuginfod,可以直接apt安装:

sudo apt install debuginfod

然后在~/.bashrc里配置服务器地址即可:

export DEBUGINFOD_URLS="https://debuginfod.ubuntu.com"

Ubuntu 23.xx最新版本自带的gdb版本为13.1,默认支持debuginfod,可以无需任何操作即可使用。