gdbによるCプログラムのデバッグ
背景
- IDEの無い環境でプログラムのデバッグが必要になった。
- 対象はLinux上のgccでコンパイルしたプログラム。
- cmakeでビルドしているため、デバッグオプションを適宜設定する必要がある。
cmakeのデバッグ設定
cmake -DCMAKE_BUILD_TYPE=Debug
-
NG: シンボル情報を生成してくれない
(gdb) break main No symbol table is loaded. Use the "file" command.
CMakeLists.txtを編集
-
OK: 以下の一行を追加(なるべく前のほうで)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0")
gdbによるデバッグ例
- デバッグ対象:Anjay
- なんというか、LwM2Mのクライアント実装に興味があったので・・・
- Apache 2.0ライセンスです。
起動・実行・継続・ステップIN・ステップOVER・ステップOUT・終了
-
起動 (プログラム引数を与えて起動)
- プロブラム本体: demo
- プログラム引数1: --server-uri LwM2M Server URL
- プログラム引数2: -e 登録名
$ gdb --args ./demo --server-uri coap://leshan.eclipseprojects.io:5683 -e TETSUO_ANJAY_DEV0 GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> ・・・(snip)
-
実行
(gdb) run Starting program: /home/tetsuo/Anjay/build/output/bin/demo --server-uri coap://leshan.eclipseprojects.io:5683 -e TETSUO_ANJAY_DEV0 ・・・
-
再開
Breakpoint 1, main (argc=5, argv=0x7fffffffe048) at /home/tetsuo/Anjay/demo/demo.c:548 548 int main(int argc, char *argv[]) { (gdb) continue Continuing. 2019-11-18 18:11:26.841555 INFO [anjay] [/home/tetsuo/Anjay/src/anjay_core.c:172]: Initializing Anjay 1.16
-
ステップOVER
- 関数呼び出しの中に入らず、現コードの次のステップに移動します。
- 以下例では関数argv_storeの外側で1ステップ進みます。
(gdb) next
565 for (int fd = 3, maxfd = (int) sysconf(_SC_OPEN_MAX); fd < maxfd; ++fd) {
(gdb) next
566 close(fd);
(gdb) next
565 for (int fd = 3, maxfd = (int) sysconf(_SC_OPEN_MAX); fd < maxfd; ++fd) {
(gdb) next
566 close(fd);
-
ステップIN
- 関数の呼び出しの中に移動します。
- ブレークポイントargv_storeから、関数の中(demo_utils.c:44)に入っていきます。
Breakpoint 2, main (argc=5, argv=0x7fffffffe048) at /home/tetsuo/Anjay/demo/demo.c:594 594 if (argv_store(argc, argv)) { (gdb) step argv_store (argc=5, argv=0x7fffffffe048) at /home/tetsuo/Anjay/demo/demo_utils.c:44 44 AVS_ASSERT(argc >= 0, "unexpected negative value of argc"); (gdb)
- 関数の呼び出しの中に移動します。
-
ステップOUT
- 関数から出て、呼び出し元に戻ります。
- 関数の中(demo_utils.c:44)から、呼び出し元(demo.c:594)に戻ります。
- 関数の戻り値 (Value returned is $1 = 0)が表示されます。
(gdb) step argv_store (argc=5, argv=0x7fffffffe048) at /home/tetsuo/Anjay/demo/demo_utils.c:44 44 AVS_ASSERT(argc >= 0, "unexpected negative value of argc"); (gdb) fin Run till exit from #0 argv_store (argc=5, argv=0x7fffffffe048) at /home/tetsuo/Anjay/demo/demo_utils.c:44 0x0000555555562e4f in main (argc=5, argv=0x7fffffffe048) at /home/tetsuo/Anjay/demo/demo.c:594 594 if (argv_store(argc, argv)) { Value returned is $1 = 0
- 関数から出て、呼び出し元に戻ります。
-
終了
-
(gdb) quit A debugging session is active. Inferior 1 [process 21171] will be killed. Quit anyway? (y or n) y tetsuo@trial19:~/Anjay/build/output/bin$
ブレークポイント
-
ブレークポイント(メソッド名)指定して、実行
(gdb) break main Breakpoint 1 at 0xed72: file /home/tetsuo/Anjay/demo/demo.c, line 548. (gdb) run Starting program: /home/tetsuo/Anjay/build/output/bin/demo --server-uri coap://leshan.eclipseprojects.io:5683 -e TETSUO_ANJAY_DEV0 Breakpoint 1, main (argc=5, argv=0x7fffffffe048) at /home/tetsuo/Anjay/demo/demo.c:548 548 int main(int argc, char *argv[]) {
-
ブレークポイント(行番号)を指定して、継続
(gdb) break demo.c:594 Breakpoint 2 at 0x555555562e38: file /home/tetsuo/Anjay/demo/demo.c, line 594. (gdb) continue Continuing. Breakpoint 2, main (argc=5, argv=0x7fffffffe048) at /home/tetsuo/Anjay/demo/demo.c:594 594 if (argv_store(argc, argv)) {
-
ブレークポイント一覧表示
(gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x0000555555562d72 in main at /home/tetsuo/Anjay/demo/demo.c:548 breakpoint already hit 1 time 2 breakpoint keep y 0x0000555555562e38 in main at /home/tetsuo/Anjay/demo/demo.c:594 breakpoint already hit 1 time
-
現在のブレークポイント(周辺)をソース上で確認
(gdb) list 589 avs_log_set_handler(log_handler); 590 avs_log_set_default_level(AVS_LOG_TRACE); 591 avs_log_set_level(demo, AVS_LOG_DEBUG); 592 avs_log_set_level(anjay_sched, AVS_LOG_DEBUG); 593 594 if (argv_store(argc, argv)) { 595 return -1; 596 } 597 598 cmdline_args_t cmdline_args;
変数の入出力
-
現在の変数の値を出力
(gdb) print argc $9 = 5 (gdb) print argv[0] $10 = 0x7fffffffe387 "/home/tetsuo/Anjay/build/output/bin/demo" (gdb) print argv[1] $11 = 0x7fffffffe3b0 "--server-uri" (gdb) print argv[2] $12 = 0x7fffffffe3bd "coap://leshan.eclipseprojects.io:5683" (gdb) print argv[3] $13 = 0x7fffffffe3e3 "-e" (gdb) print argv[4] $14 = 0x7fffffffe3e6 "TETSUO_ANJAY_DEV0"
-
変数の値を変更
(gdb) print argv[4] $14 = 0x7fffffffe3e6 "TETSUO_ANJAY_DEV0" (gdb) set argv[4] = "HOGEHOGE_DEV1" (gdb) print argv[4] $15 = 0x7ffff7fde940 "HOGEHOGE_DEV1"
その他機能
- バックトレース(コールスタック)
- ブレークポイントから呼び出し元を再帰的に表示
- bt (backtrace)
(gdb) bt
#0 connect_udp_socket (anjay=0x555555802770, connection=0x5555558063d0)
at /home/tetsuo/Anjay/src/servers/connection_udp.c:331
#1 0x00005555555a80c8 in _anjay_connection_internal_bring_online (anjay=0x555555802770, connections=0x5555558063d0,
conn_type=ANJAY_CONNECTION_UDP) at /home/tetsuo/Anjay/src/servers/connections.c:144
#2 0x00005555555a8666 in ensure_socket_connected (anjay=0x555555802770, connections=0x5555558063d0,
conn_type=ANJAY_CONNECTION_UDP, inout_info=0x7fffffff9ad0) at /home/tetsuo/Anjay/src/servers/connections.c:260
#3 0x00005555555a874d in refresh_connection (anjay=0x555555802770, connections=0x5555558063d0,
conn_type=ANJAY_CONNECTION_UDP, inout_info=0x7fffffff9ad0) at /home/tetsuo/Anjay/src/servers/connections.c:280
#4 0x00005555555a8837 in _anjay_connections_refresh (anjay=0x555555802770, connections=0x5555558063d0, security_iid=1,
uri=0x7fffffff9b30, binding_mode=0x7fffffff9c40 "U") at /home/tetsuo/Anjay/src/servers/connections.c:306
#5 0x0000555555586505 in _anjay_active_server_refresh (anjay=0x555555802770, server=0x5555558063c0)
at /home/tetsuo/Anjay/src/servers/server_connections.c:128