TopC++ 入門 › 実践 › gdb デバッグ

C++ での gdb デバッグ入門

SEGV やハングの原因特定は gdb(Linux) / lldb(macOS) の出番。この 1 ページで「落ちた → 30 秒で原因の行を特定」までできるようになります。

1. ビルド時に -g を忘れない

$ g++ -std=c++17 -Wall -g -O0 main.cpp -o app # デバッグ用 $ g++ -std=c++17 -O2 -g main.cpp -o app # 最適化+行情報(Prod)

-g でシンボル/行番号情報が埋め込まれます。-O2 との併用も可能ですが、最適化で変数が消えたり inline されたりするので、まずは -O0 で追うのが楽。

2. 最短の使い方(対話モード)

$ gdb ./app (gdb) run # 実行 Program received signal SIGSEGV, ... (gdb) bt # バックトレース #0 process(0x0) at main.cpp:42 #1 loop() at main.cpp:28 #2 main() at main.cpp:10 (gdb) frame 0 # 0 番目のフレームへ (gdb) list # 周辺のコードを表示 (gdb) print p # 変数 p を表示 $1 = 0x0 # ← nullptr 確定!

SEGV → runbtframe Nprint 変数。この 4 ステップで多くのクラッシュは解明できます。

3. ブレークポイント

(gdb) break main.cpp:42 # 行番号 (gdb) break my_class::method # 関数名(オーバーロードは番号選択) (gdb) condition 1 i==100 # 条件付き(i が 100 の時だけ止まる) (gdb) continue # 再開 (gdb) next # 1 行実行(関数は stepover) (gdb) step # 1 行実行(関数に入る) (gdb) finish # 現関数から脱出するまで実行

C++ メソッドは class::name の形で指定。テンプレートは具体化された名前を指定するので break func<int>

4. STL コンテナの中身を見る

素の gdb だと std::vector の中身が _M_start = 0x5555... のように暗号的に表示されます。pretty-printer を入れると {1, 2, 3} と人間可読に。

# ~/.gdbinit に追記 python import sys sys.path.insert(0, '/usr/share/gcc/python') from libstdcxx.v6.printers import register_libstdcxx_printers register_libstdcxx_printers(None) end

Ubuntu なら apt install libstdc++6-dbg で入る。Mac では lldb が最初から std::vector を可読表示します。

5. コアダンプから解析

$ ulimit -c unlimited # core ファイル生成を許可 $ ./app Segmentation fault (core dumped) $ gdb ./app core # 死後解析 (gdb) bt (gdb) thread apply all bt # 全スレッドのトレース

6. マルチスレッドのデバッグ

(gdb) info threads # 全スレッド一覧 (gdb) thread 3 # 3 番のスレッドへ (gdb) bt (gdb) thread apply all bt # 一括で全スレッドのトレース

デッドロックの調査に必須。「全スレッドが同じ mutex で止まっている」等が一目で分かる。

7. よく使うコマンド早見表

コマンド短縮用途
runr実行
break Lb Lブレーク設定
continuec再開
nextn行単位実行(step over)
steps行単位実行(step into)
print xp x変数表示
info localsローカル変数一覧
watch x変数が変わったら停止
quitq終了
GUI で楽をしたい: VS Code + 「C/C++」拡張、または CLion / Qt Creator でほぼ同機能を GUI で使えます。コマンドで動く gdb の知識があると TUI / CI / リモートでも戦える。