Help us understand the problem. What is going on with this article?

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

More than 5 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
edo_m18
現在はUnity ARエンジニア。 主にARのコンテンツ制作をしています。 最近は機械学習にも興味が出て勉強中です。 Unityに関するブログは別で書いています↓ https://edom18.hateblo.jp/
http://edom18.hateblo.jp/
unity-game-dev-guild
趣味・仕事問わずUnityでゲームを作っている開発者のみで構成されるオンラインコミュニティです。Unityでゲームを開発・運用するにあたって必要なあらゆる知見を共有することを目的とします。
https://unity-game-dev-guild.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away