gdbによるCプログラムのデバッグ

# 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](https://github.com/AVSystem/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の外側で１ステップ進みます。

```
    (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

```