gdbを使ってCのデバッグを行うメモ

## 概要

こちらの記事（[低レイヤを知りたい人のためのCコンパイラ作成入門](https://www.sigbus.info/compilerbook/)）を読んで、コンパイラについて勉強中です。
最終的にはごくごく簡単なパーサとごくごく簡単な言語を実装して、Unity上でVM的に簡単なコマンドを外部から与えられる環境が作れたらいいなーと思っております。

さて、上記記事のコンパイラ実装はC言語が使われています。
ステップバイステップで分かりやすいのですが、若干端折られている箇所があり、そこを想像で埋めて実装していたら変なエラーが出てきたのでデバッグを行う必要があり、そのための`gdb`の諸々をメモっていこうと思います。

**※ なので、随時更新予定。**


## gdbのインストール

今回、実装にあたってはアセンブラの出力とそれをアセンブルして実際に実行するまでを確認する必要があるため、WindowsでLinuxが使える環境（Windows Subsystem for Linux - WSL）を整えてから実装を開始しています。
その関係で、Visual StudioなどWindows側で実装が行えず、サブシステムを利用しているので`gdb`自体も別途インストールしました。


### gdbのTUIモードをオンのものをインストールする

TUIモードとは、`Text User Interface`の略で、以下のような見た目の`gdb`を起動することができます。
![TUI Mode gdb](https://qiita-image-store.s3.amazonaws.com/0/5616/f4bebeb0-a077-4356-3581-f0ed874cd9d2.png)
最初、`gdb`のサイトから最新版を落としてきてインストールしたのですが、いわゆるIDEのように、ブレークした箇所を追いながら見ていくモード（`TUI Mode`）がオンにできず、結局以下の記事を参考にして改めてインストールしたところ無事に動作させることができました。

- [With option -tui, GDB exits with 'TUI mode is not allowed' - Stack Overflow](https://stackoverflow.com/questions/37856059/with-option-tui-gdb-exits-with-tui-mode-is-not-allowed)

回答に書かれている内容を引用させてもらうと、以下のように実行することでインストールすることができます。

```console
$ apt-get build-dep gdb
$ apt-get source gdb
$ cd gdb-7.7.1 # 適宜、DLされたバージョンに置き換えてください
$ ./configure --enable-tui=yes
$ make
# grab a coffee
$ sudo make install
```

全然関係ないけど、英語のこういうコメント好きｗ（`# grab a coffee`）

さらに、そのままインストールすると以下のようなエラーが出てしまいました。

```console
You must put some 'source' URIs in your sources.list
```

以下の記事を参考に、`apt`を`update`したら無事にインストールできるようになりました。

- [Ubuntu 16.04: apt sourceでソースコードをダウンロードする](https://www.hiroom2.com/2016/07/14/ubuntu-16-04-apt-source%E3%81%A7%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%81%99%E3%82%8B/)

```console
$ sudo su -c "grep '^deb ' /etc/apt/sources.list | \
sed 's/^deb/deb-src/g' > /etc/apt/sources.list.d/deb-src.list"
```

```console
$ sudo apt update -y
```


--------------------------------------------

#### いちおうメモ

基本的には上で紹介した記事を参考にインストールできると思いますが、自分が最初に参考にした記事もメモのため残しておこうと思います。

インストールについては以下の記事を参考にさせていただきました。

- [[Linux] デバッグ用にgdb をインストールしてみた。](http://hirozak.www2.jp/linux_gdb_install/)

また、WSL自体のセットアップはこちらを参考にさせていただきました。

- [Windows Subsystem for Linuxをインストールしてみよう！](https://qiita.com/Aruneko/items/c79810b0b015bebf30bb)

--------------------------------------------



## デバッグ情報込みでコンパイルする

`gcc`など、C言語をコンパイルする際にデバッグ可能な情報を付与した状態でコンパイルしないとデバッグが行えません。
`gcc`では以下のようにすることでデバッグ用の情報（シンボル情報など）を付与してコンパイルします。

```console
$ gcc -g -O0 hoge.c
```

これで、デバッグ情報付きの`a.out`ファイルが生成されるので、これを`gdb`から実行してやることでデバッグが可能となります。


## gdbからアプリを実行する

`gdb`からアプリを実行するには以下のように実行します。

```console
$ gdb a.out
```

ここの`a.out`はコンパイルされた実行ファイルを指定します。（`gcc`ではファイル名を指定しないと`a.out`という名前でファイルが生成される）

また、冒頭で紹介した`TUI`モードをオンにして起動する場合は引数`-tui`を付与して実行します。

```console
$ gdb -tui a.out
```

試しに、参考にさせていただいているコンパイラ（`9cc`）のデバッグを実行してみると以下のようになります。

```console
# a.outが生成される
$ gcc -g -O0 9cc.c
```

```console
$ gdb -tui a.out
```

これを実行すると以下のような画面になります。
![TUIを実行した状態](https://qiita-image-store.s3.amazonaws.com/0/5616/4e965605-2ac7-748a-c518-d6b60be4e2a5.png)

この状態でブレークポイントを設定し、

```console
(gdb) b main
```

実際に実行すると、

```console
(gdb) run '(1+2)'
```

`main`関数でbreakするのが分かります。

![main関数でbreak](https://qiita-image-store.s3.amazonaws.com/0/5616/fdc920d2-7535-ad6e-9cf4-b0ba823f5da3.png)

あとは、下で紹介するコマンドを利用して1行（あるいは関数ごと）に、つまりIDEで普段見るような形でデバッグを続けることができます。


## gdbコマンド集

`gdb`では以下のコマンドを利用してステップ実行や、現在の変数の状態確認などを行っていきます。


### ブレイク関連

| コマンド | 説明 |
|:-:|:-:|
| b [関数名] | [関数名]に対してブレイクポイントを貼る  |
| b [ファイル名]:[行数] | デバッグ対象Cファイルの、[行数]位置にブレイクポイントを貼る  |
| w [変数名]  | [変数名]にウォッチポイントを設定  |
| i b  | ブレイクポイント一覧を表示  |
| d [no]  |  番号に対応するブレイクポイントを削除  |


### 実行関連

| コマンド | 説明 |
|:-:|:-:|
| n  | ステップ実行（1行ずつ実行。stepover）  |
| s  | ステップ実行（1行ずつ実行。stepin）  |
| c  | 次のブレイクポイントまで処理を実行  |
| f  |  現在の関数を抜けるまで処理を実行 |
| u  | 現在のループを抜けるまで処理を実行  |



## その他参考記事

- [gcc+gdbによるプログラムのデバッグ 第1回 ステップ実行、変数の操作、ブレークポイント](https://rat.cis.k.hosei.ac.jp/article/devel/debugongccgdb1.html)