PostgreSQL をハックする際は,通常,コンパイラの最適化レベルを落とし,デバッグ情報を付けてコンパイルする. デバッグ用の PostgreSQL をビルドする際に configure に指定されるオプションは,デバッグを有効化する --enable-debug,実行時のエラーチェックを有効化する --enable-cassert,そして,ヘッダーファイルの変更に対して,関連するすべてのコードをリビルドするオプション --enable-depend である. --enable-cassert--enable-depend はコンパイラとは無関係なオプションであるから,--enable-debug を中心に見ていく.

環境

  • PostgreSQL 12.1
  • GCC 9.2.0
  • Clang 9.0.0

デバッグ情報を付加する

configure ファイル の以下の箇所にあるように,--enable-debug はコンパイラに -g オプションを渡してデバッグ情報をバイナリに含める.

# supply -g if --enable-debug
if test "$enable_debug" = yes && test "$ac_cv_prog_cc_g" = yes; then
  CFLAGS="$CFLAGS -g"
fi

if test "$enable_debug" = yes && test "$ac_cv_prog_cxx_g" = yes; then
  CXXFLAGS="$CXXFLAGS -g"
fi

configure にデバッグ用のオプションを設定した時に, CFLAG がどのように変化するかを調べてみた. Clang と GCC の場合でそれぞれ調査した.

$ ../configure CC=/usr/local/opt/llvm/bin/clang
(snip)
configure: using CFLAGS=-Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -Wno-unused-command-line-argument -O2
(snip)
$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang
(snip)
configure: using CFLAGS=-Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -Wno-unused-command-line-argument -g -O2
(snip)
$ ../configure CC=/usr/local/bin/gcc-9
(snip)
configure: using CFLAGS=-Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-format-truncation -Wno-stringop-truncation -O2
(snip)
$ ../configure --enable-debug CC=/usr/local/bin/gcc-9
(snip)
configure: using CFLAGS=-Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-format-truncation -Wno-stringop-truncation -g -O2
(snip)

Clang の場合と GCC の場合で他のオプションに変化があった. Clang 特有のオプションとして -Wno-unused-command-line-argument, GCC 特有のオプションとして -fexcess-precision=standard-Wno-format-truncation-Wno-stringop-truncation が加えられていることがわかる. いずれもデバッグには関係のないオプションなので,ここでは詳細を割愛する.

Clang と GCC で --enable-debug を指定した場合とそうでない場合の違いは,想定どおり -g が加えられるかどうかのみである.

-g オプションがどれくらいデバッグ情報を加えるのか,バイナリサイズを見て調べてみる.

まずは Clang の場合.

$ ../configure CC=/usr/local/opt/llvm/bin/clang
$ make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  7128656 Dec 17 00:48 src/backend/postgres
$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang
$ make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  8228384 Dec 17 01:02 src/backend/postgres

次に,GCC の場合.

$ ../configure CC=/usr/local/bin/gcc-9
$ make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  8581088 Dec 17 01:07 src/backend/postgres
$ ../configure --enable-debug CC=/usr/local/bin/gcc-9
$ make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  10078728 Dec 17 01:15 src/backend/postgres

全体的に,GCC でコンパイルしたバイナリと比較して,Clang でコンパイルしたものの方がサイズが小さくなった. -g オプションを入れてコンパイルすると,いずれのコンパイラを使った場合も 10-20% 程度バイナリサイズが増加した.

Clang におけるデバッグ情報の制御

Clang の公式ドキュメントには「コンパイルオプションに -g を指定すると完全なデバッグ情報が生成されるようになる」とある1

$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang
(snip)
configure: using CFLAGS=-Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -Wno-unused-command-line-argument -g -O2
(snip)
$ make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  8228384 Dec 17 01:02 src/backend/postgres
$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang CFLAGS=
(snip)
configure: using CFLAGS=-Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -Wno-unused-command-line-argument -g
(snip)
$  make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  11378704 Dec 17 01:38 src/backend/postgres

興味深いのは,--enable-debug を指定した場合と --enable-debugCFLAGS= の両方を指定した場合でバイナリのサイズが異なることである. configure により設定されるコンパイラオプションを比較してみると,-O2 が設定されるか否かの違いであることがわかる.

Clang の公式ドキュメントから以下のことがいえる.

  • マクロ情報を含めるには CFLAGS-fdebug-macro を指定する
  • DWARF 形式のデバッグ情報を含めるには CFLAGS-ggdb-glldb を指定する
  • -g-ggdb にはレベル 0–3 を設定することができる2

実際にこれらのオプションを加えてみた結果が以下のとおり. いずれの場合でもバイナリサイズに変化せず,-g オプションが完全なデバッグ情報を付加することがわかる.

$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang CFLAGS='-fdebug-macro'
$ make -j12
$ ls -l src/backend/postgres                 
-rwxr-xr-x  1 sira  staff  11378704 Dec 17 01:42 src/backend/postgres
$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang CFLAGS='-ggdb'
$ make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  11378704 Dec 17 01:45 src/backend/postgres
$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang CFLAGS='-glldb'
$ make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  11378704 Dec 17 01:52 src/backend/postgres
$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang CFLAGS='-g3'
$  make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  11378704 Dec 17 01:55 src/backend/postgres
$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang CFLAGS='-ggdb3'
$  make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  11378704 Dec 17 02:01 src/backend/postgres
$ ../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang CFLAGS='-g3 -fdebug-macro -glldb -ggdb3'
$  make -j12
$ ls -l src/backend/postgres
-rwxr-xr-x  1 sira  staff  11378704 Dec 17 02:07 src/backend/postgres

Clang で完全なデバッグ情報を生成するための configure オプションは次のようになる.

../configure --enable-debug CC=/usr/local/opt/llvm/bin/clang

GCC におけるデバッグ情報の制御

GCC では -g オプションでデバッグ情報を付加することができる3. GDB のための追加のデバッグ情報を付加するには,-ggdb を指定する. これらのオプションにはレベルを 1–3 で指定することができる. レベルを指定しない場合に設定されるデフォルトのレベルは 2 である.

PostgreSQL の configure が生成したコンパイルオプションは -g なので,マクロのデバッグ情報を含むより詳細なデバッグ情報が欲しい場合は -g3 を指定する.

脚注