Edited at

LLDBを使ってCのデバッグをする

More than 3 years have passed since last update.

Macの場合は最初からlldbがあるため、これを使ってデバッグすることができます。

iOSアプリの開発をしているとデバッグに(lldb)とコンソールに出てきますが、まさにこれです。


デバッグの開始

まず、デバッグを開始するためにはcファイルを-gオプションを付けてデバッグ可能な状態でコンパイルしないとなりません。

$ gcc -o hoge -g hoge.c

ちなみにhoge.cの中身はごく簡単にこんな感じ。


hoge.c

#include <stdio.h>


int main(int argc, char **argv) {
char *test = "This is a debug demo.";
char *name = "edo";
int age = 20;

printf("Name: %s, Age: %d\n", name, age);

return 0;
}


そしてこれをコンパイルするとhogeファイルができるのでここからデバッグ開始です。


ファイル名を指定してlldbを起動

lldbの起動にはいくつかあるみたいですが、一番シンプルなのはデバッグ対象のファイルを指定することでしょう。

以下のように、先ほどコンパイルしたファイルを指定して実行してみます。

$ lldb hoge

(lldb) target create "hoge"
Current executable set to 'hoge' (x86_64).
(lldb)

するとlldbが起動して、コマンドを受け付ける状態になります。


実行してみる

現状だとまだlldbが起動しただけなのでプログラムは実行されていません。

そこで、run(あるいはr)とタイプしてプログラムを実行してみます。

すると以下のようになりました。

(lldb) r

Process 93882 launched: '/Path/To/hoge' (x86_64)
Name: edo, Age: 20
Process 93882 exited with status = 0 (0x00000000)
(lldb)


ブレークポイントを設定する

printfの内容もしっかり出力されているのが分かります。

ただこれだけではなにもデバッグになりません。

次はブレークポイントを設定してみます。

(lldb) br set --file hoge.c --line 6

(lldb) br set -f hoge.c -l 6

上記のように、ファイル名と行数を指定してブレークポイントを設定します。

(ちなみにbrbreakpointの省略形です)


省略形でブレークポイントを張る

ちなみに以下のようにすることでもブレークポイントを張ることができます。

(lldb) b hoge.c:8


関数にブレークポイントを張る

fooという関数にブレークポイントを設定する場合は以下のようにします。

(lldb) br set -n foo

(lldb) br set --name foo


ブレークポイントを設定したあと、再度実行してみると以下のように出力され、処理が中断します。

(lldb) r

Process 93890 launched: '/Path/To/hoge' (x86_64)
Process 93890 stopped
* thread #1: tid = 0x53c0ae, 0x0000000100000f23 hoge`main(argc=1, argv=0x00007fff5fbff460) + 51 at hoge.c:6, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000f23 hoge`main(argc=1, argv=0x00007fff5fbff460) + 51 at hoge.c:6
3 int main(int argc, char **argv) {
4 char *test = "This is a debug demo.";
5 char *name = "edo";
-> 6 int age = 20;
7
8 printf("Name: %s, Age: %d\n", name, age);
9
(lldb)

6行目でbreakしているのが分かります。

この状態でコマンドを受け付ける状態になるので、ここから色々なコマンドを実行してデバッグをしていきます。


変数を出力する

poコマンド(Print Objectの略)を使って変数を出力することができます。

(lldb) po name

"edo"


構造体を出力する

pコマンドを使うと構造体名が出力されます。

また、p val[0]と、[0]を指定することで構造体の中身を見ることができます。

(以下は例)

(lldb) p res

(addrinfo *) $12 = 0x00000001003004a0
(lldb) p res[0]
(addrinfo) $13 = {
ai_flags = 0
ai_family = 2
ai_socktype = 1
ai_protocol = 6
ai_addrlen = 16
ai_canonname = 0x0000000000000000
ai_addr = 0x0000000100300460
ai_next = 0x0000000000000000
}


ステップ実行する

ブレークポイントで止めても、処理を進めないと先に進めません。

処理を次に進めるにはn(next)かc(continue)を使って処理を進めます。


スタックトレースを出力する

bt(thread backtrace)コマンドで出力することができます。

(lldb) bt

* thread #1: tid = 0x53d052, 0x0000000100000f2a hoge`main(argc=1, argv=0x00007fff5fbff460) + 58 at hoge.c:8, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000100000f2a hoge`main(argc=1, argv=0x00007fff5fbff460) + 58 at hoge.c:8
frame #1: 0x00007fff8c31e5c9 libdyld.dylib`start + 1


変数の一覧を出力する

現在breakしているフレームで見ている変数の一覧を出力することができます。

(lldb) frame variable

(int) argc = 1
(char **) argv = 0x00007fff5fbff460
(char *) test = 0x0000000100000f6e "This is a debug demo."
(char *) name = 0x0000000100000f84 "edo"
(int) age = 20

ちなみに、以下のようにすることで、該当の変数を出力することもできます。

(lldb) frame variable *argv

(char *) *argv = 0x00007fff5fbff5e0 "/Path/To/hoge"

(lldb) frame variable age
(int) age = 20