ふつうのLinuxプログラミングをやってみる その7-3 gdb




有名な本らしいので買ってみました
<a target="_blank" href="https://www.amazon.co.jp/gp/product/4797328355/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4797328355&linkCode=as2&tag=lespacetranqu-22&linkId=b690c3257ff896f2239f1107e5bf95a4">ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道</a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=lespacetranqu-22&l=am2&o=9&a=4797328355" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
<a target="_blank" href="https://www.amazon.co.jp/gp/product/B075ST51Y5/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B075ST51Y5&linkCode=as2&tag=lespacetranqu-22&linkId=aa0915aa60afe5a385a365f9059a2877">ふつうのLinuxプログラミング 第2版　Linuxの仕組みから学べるgccプログラミングの王道</a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=lespacetranqu-22&l=am2&o=9&a=B075ST51Y5" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />


> ふつうのLinuxプログラミングをやってみる その１
https://qiita.com/uturned0/items/b9ae846f2aff5865c074
ふつうのLinuxプログラミングをやってみる その2
https://qiita.com/uturned0/items/56beac990cdd6f1059ed
ふつうのLinuxプログラミングをやってみる その3
https://qiita.com/uturned0/items/675092da8aa89c4b1ff0
その４
https://qiita.com/uturned0/items/8f5765cfc0f0be8a1981
その５
https://qiita.com/uturned0/items/ab97deb489c994a836da
その６
https://qiita.com/uturned0/items/b7df48e87ae9170f3698
その７
https://qiita.com/uturned0/items/263151cf7c83bff7fac1
その７−３
https://qiita.com/uturned0/items/3fbf3ed6bb2a47325f59
その８，９
https://qiita.com/uturned0/items/3d8314095c45aa0bf920

---

うわっ。前回の記事が 2020/10 で、いま 2022/01 。1年以上放置してたのか自分・・・・びっくりたまげたわ・・・・。



公式sourceはこちら
https://github.com/aamine/stdlinux2-source

# gdb　とは

C-langの開発で使うデバッガ。

# 前準備
1. macの場合、できない場合がある
素直にvagrantでやりました。cent7.古い。
https://gist.github.com/kujiy/fdd73d6f200cfff8e067682f6b6a7848

```
wget https://gist.githubusercontent.com/kujiy/fdd73d6f200cfff8e067682f6b6a7848/raw/7fcadaf0bc43b9ace23ef620c2049962a77a97bc/Vagrantfile
# 共有フォルダ(synced_folder) 書き換えて
vim Vagrantfile
vagrant up
vagrant ssh node1
```

（ひとりごと）vmに入れるとIDEからremote debugになるから面倒なのよね・・


2.bugがあるコードを作る

まずbugありの　head3.c を流す。

sourceはここから
https://github.com/aamine/stdlinux2-source

この 15行目の `n:` を `n` にしてbugを埋め込む

```C
    while ((opt = getopt(argc, argv, "n")) != -1) {
```


# gdbを使うには

1. install

結構大変だった

```ruby
sudo yum install -y gdb
sudo debuginfo-install -y glibc-2.17-325.el7_9.x86_64
```


2. compile時に特別なオプション `-g` が必要


```ruby
$ gcc -Wall -g -o head stdlinux2-source/head3.c 
```

3. 起動

```ruby
gdb ./head

....

(gdb)   ←これが出れば成功
```

ここで、引数にファイル名を渡しているので、今後はファイル名を省略してｇｄｂ専用のコマンドを実行していく。
このフィアル名＝コマンド名になる

実行。コマンド名部分は除き、optionだけ書いていく

```ruby
run -n 5 /etc/os-release  
  ↑ runをheadと読み替えれば head -n 5 /etc/os-release になる
```

エラーが出る

```ruby

(gdb) run -n 5 /etc/os-release
Starting program: /repos/futu/head -n 5 /etc/os-release

Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group=<optimized out>, loc=0x7ffff7dd5060 <_nl_global_locale>) at ../stdlib/strtol_l.c:293
293       while (ISSPACE (*s))

```

エラーをおこした関数 `__GI_____strtol_l_internal` がわかるがそんなコード書いてない。 strtol_l.c の中のエラー。誰がこれを呼んだか探す



## backtrace

backtraceを使うとエラーになるまでの流れが見える

```js
(gdb) backtrace
#0  __GI_____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group=<optimized out>, loc=0x7ffff7dd5060 <_nl_global_locale>) at ../stdlib/strtol_l.c:293
#1  0x00000000004008b2 in main (argc=4, argv=0x7fffffffe428) at stdlinux2-source/head3.c:18
```

最後の行を読み解くと `head3.cの 18行目` ってことがわかる

## Debugしてみよう！！！

### frame

みたいエラーの行頭は `#1` なので 1　を指定


```j
(gdb) frame 1
#1  0x00000000004008b2 in main (argc=4, argv=0x7fffffffe428) at stdlinux2-source/head3.c:18
18                  nlines = atol(optarg);
```

この 2行目が、プログラムが止まった場所（本では "実行中の場所" とよんでいる）。たしかに `nlines = ...` はソース中に存在します。18行目だね。
「18行目を実行したら、エラーになった。その場所で止まった。19行目には行けなかった。だから18行目にstayしてます。」この状態。


###  list
list を叩くともっと広くコードを見れる。ただ現在行にマークとかないので、行数は脳内に記憶しておく（今回は18行目）

```c
(gdb) list
13          long nlines = DEFAULT_N_LINES;
14      
15          while ((opt = getopt(argc, argv, "n")) != -1) {
16              switch (opt) {
17              case 'n':
18                  nlines = atol(optarg);
19                  break;
20              case '?':
21                  fprintf(stderr, "Usage: %s [-n LINES] [file...]\n", argv[0]);
22                  exit(1);
```

### print

ここからはプログラマの推測が入っていきます。経験が物を言う時間。

 `nlines = atol(optarg);` を実行してエラーになるということは、きっと `atol(optarg);` に問題がある。

 `optarg` に何が渡されてきたか調べるのが `print`


```j
(gdb) print optarg
$1 = 0x0
```

0x0 や 0 は、つまり NULLらしい。

次の推測をします。

optargがNULLってことは、それを作る `getopt()` が適切な値を作ってないってことです。ってわけで、あとは `getopt()` を疑って、原因（今回は "n"ではなく "n:" にする）を探しましょう、というのが、本の内容でした。

うーん。なるほど。まあ、そうか。getopt()は現状エラー出してないし、そうなるか。なるほど。

名言： debuggerができることは、エラーの行数と、変数の中身を見せるところまで。


文字数まで教えてくれるdebuggerけっこう当たり前だと思ってたけど、gdbはそうじゃないっぽいかな。


### continue
いま、debuggerはエラーが起こった行で一時停止してます。ステップ実行中みたいな。これを強制的に最後まで進ませると、当然エラーなので、プログラムが終了します。最後まで実行させるのが continue(cont, c でも動く）。IDEの F9 ですね

```c
(gdb) continue
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
```

そしたら ctrl + D とかで quit して、gdb はおわり。


### breakpoint

ここは本に書いてなかったけどざっくり試した


```c
# 12行目にbreakpoint
(gdb)  break 12

# main()に
(gdb)  break main
```

b は `b` で省略可能

breakpointおいたら、実行

```j
(gdb) run -n 5 /etc/os-release
```

ちゃんと止まりました

```ruby
Starting program: /repos/futu/head -n 5 /etc/os-release

Breakpoint 1, main (argc=4, argv=0x7fffffffe428) at stdlinux2-source/head3.c:13
13          long nlines = DEFAULT_N_LINES;
```

こっからは s, n, c でステップ実行していく

- `s` : 1行進む(IDEのF7) (step in)
- `n` : 関数実行(IDEのF8) (step over)
- `c` : 最後まで実行(IDEのF9 (cont, continueと同義) 


詳細ref. https://condor.depaul.edu/glancast/373class/docs/gdb.html

ソースが広く見たくなったら list する。変数みたくなったら print する。

なるほど！！！



# ついに gdb をマスターした！！







---

この本を読みながらやってます

<a target="_blank" href="https://www.amazon.co.jp/gp/product/4797328355/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4797328355&linkCode=as2&tag=lespacetranqu-22&linkId=b690c3257ff896f2239f1107e5bf95a4">ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道</a>
<a target="_blank" href="https://www.amazon.co.jp/gp/product/B075ST51Y5/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B075ST51Y5&linkCode=as2&tag=lespacetranqu-22&linkId=aa0915aa60afe5a385a365f9059a2877">ふつうのLinuxプログラミング 第2版　Linuxの仕組みから学べるgccプログラミングの王道</a>