Ubuntu 19.04: デバッグシンボルでパッケージをデバッグする

dbgsymパッケージを導入してパッケージをGDBでデバッグします。

1 dbgsymパッケージ用リポジトリの追加

dbgsymパッケージはddebs.ubuntu.comで公開されています。 ddebs.ubuntu.comをリポジトリに追加します。

$ U=http://ddebs.ubuntu.com
$ D=$(lsb_release -cs)
$ cat <<EOF | sudo tee /etc/apt/sources.list.d/ddebs.list
deb ${U} ${D} main restricted universe multiverse
#deb ${U} ${D}-security main restricted universe multiverse
deb ${U} ${D}-updates main restricted universe multiverse
deb ${U} ${D}-proposed main restricted universe multiverse
EOF

GPGキーをインポートします。

$ wget -O - http://ddebs.ubuntu.com/dbgsym-release-key.asc | \
sudo apt-key add -

リポジトリのデータベースを更新します。

$ sudo apt update -y

2 dbgsymパッケージのインストール

dbgsymがついたパッケージがデバッグシンボルを含むパッケージです。

<package>-dbgsym

この記事ではbashのデバッグシンボルを取得します。

$ sudo apt install -y bash-dbgsym
$ dpkg -L bash-dbgsym
/.
/usr
/usr/lib
/usr/lib/debug
/usr/lib/debug/.build-id
/usr/lib/debug/.build-id/16
/usr/lib/debug/.build-id/16/ef52e314889583b73f26a98eed260667fb1ed8.debug
/usr/lib/debug/.build-id/60
/usr/lib/debug/.build-id/60/88017e1b386d955ce384f28b0bc642d5f6a38d.debug
/usr/share
/usr/share/doc
/usr/share/doc/bash-dbgsym

なお、デバッグシンボルの場所を指定しなくともGDBは自動的に /usr/lib/debugへデバッグシンボルを探しに行きます。

3 デバッグするパッケージのソースコードをダウンロード

Ubuntuはデフォルトでソースコード用のリポジトリを無効にしているので、ソースコード用のリポジトリを有効にします。すでに有効にしている場合は不要です。

deb-srcを有効にします。

$ grep '^deb ' /etc/apt/sources.list | \
  sed 's/^deb /deb-src /g' | \
  sudo tee /etc/apt/sources.list.d/deb-src.list
$ sudo apt update  -y

dpkg-sourceコマンドが必要になるのでdpkg-devパッケージをインストールします。

$ sudo apt install -y dpkg-dev

デバッグするパッケージのソースコードを取得します。

$ mkdir <package>
$ cd <package>
$ apt source <package>

この記事ではbashのソースコードを取得します。 bash-5.0ディレクトリがソースツリーです。

$ mkdir ~/bash
$ cd ~/bash
$ apt source bash
$ ls
bash-5.0                 bash_5.0-3ubuntu1.1.debian.tar.xz
bash_5.0-3ubuntu1.1.dsc  bash_5.0.orig.tar.xz

4 GDBのインストール

gdbをインストールします。

$ sudo apt install -y gdb

5 パッケージのデバッグ

GDBにコマンドとソースコードの場所を指定することで、GDBのシェルが起動します。

$ gdb <command> --directory /path/to/source
<snip>
(gdb)

bashをデバッグする場合は以下のとおりです。

$ gdb bash --directory ~/bash/bash-5.0/
<snip>
(gdb) b main
Breakpoint 1 at 0x2de30: file .././shell.c, line 364.
(gdb) r
Starting program: /usr/bin/bash

Breakpoint 1, main (argc=1, argv=0x7fffffffe3b8, env=0x7fffffffe3c8) at
.././shell.c:364
364     {
(gdb) l
359     int
360     main (argc, argv, env)
361          int argc;
362          char **argv, **env;
363     #endif /* !NO_MAIN_ENV_ARG */
364     {
365       register int i;
366       int code, old_errexit_flag;
367     #if defined (RESTRICTED_SHELL)
368       int saverst;

なお、la srcだとソースコードの追跡が容易です。

(gdb) la src

0001_gdb-la-src.png