kakts-log

programming について調べたことを整理していきます

【独習アセンブラ 4.5デバッガによるトレース】apple silicon macのローカルでgdbの代わりにlldbを使ったトレースの実行方法

概要

「独習アセンブラ」を読んでアセンブラを学んでいて、apple silicon(arm)のmacのローカル環境でコード書いてデバッグしています。

4.5「デバッガによるトレース」 で、gdbを使ってcのソースコードコンパイルした実行ファイルをもとにトレースを行いますが、arm版macでは書籍の内容の通りにトレースができませんでした。
arm版macではデバッグに使うgdbをインストールするのが面倒なので、本とは違う方法でデバッグする方法を模索し、lldbというデバッガを使ってうまいことできそうだったのでその手順をまとめます。
低レイヤーに関する理解が曖昧で、独学で学習を進めながらまとめている状態で、所々用語が間違っているかもですがご容赦ください。

前提

  • OS: macOS Monterey 12.5
  • Chip: Apple M1(Arm)
  • lldb: lldb-1316.0.9.46 Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)
  • gcc,clang: Apple clang version 13.1.6 (clang-1316.0.21.2.5) Target: arm64-apple-darwin21.6.0 Thread model: posix

手順

lldbの確認

lldbは元々インストールされていたのですが、念のため使えることを確認します。

which lldb
/usr/bin/lldb

lldb --version
lldb-1316.0.9.46
Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)

# lldbも実行できることを確認
lldb
(lldb) 

テスト用のCプログラムを作成する

「独習アセンブラ」のサポートページに記載されている、サンプルコードの通りに作成します。

github.com

ここでは、add.c という名前で保存します。

/**
 * 4.5.1 Cからアセンブリ言語への変換確認用
 */
int main(void) {
    register int i, j;
    i = 123;
    i = i + 1;
    j = 456;
    j = i + j;
    return j;
}

add.cのコンパイル

本に記載されている通りにgccコンパイルする場合、問題なく実行ファイルaddを生成できますが、lldbでのブレークポイントのセットの時にno locations (pending)というエラーが出てしまいます。

# コンパイルしてaddに実行ファイルを出力
gcc -fno-pic -fomit-frame-pointer -o add add.c;

# lldbによるデバッグ実行
# ここでは試しにadd.cの12行目にブレークポイントを貼ります。
(lldb) breakpoint set --file add.c --line 12
Breakpoint 1: no locations (pending).
WARNING:  Unable to resolve breakpoint to any actual locations.

gccでは -gを指定して、デバッグ可能な状態でコンパイルする必要があり、上記のgccコマンドに-gを追加することで問題なくブレークポイントをセットできました。

gcc --help
...
  -g                      Generate source-level debug information

qiita.com

# -gを追加してデバッグを有効にしたうえでコンパイル
gcc -g -fno-pic -fomit-frame-pointer -o add add.c;

# lldbを実行し、ブレークポイントを12, 13, 14行目に貼る。
lldb add
(lldb) target create "add"
Current executable set to '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64).
(lldb) breakpoint set --file add.c --line 12
Breakpoint 1: where = add`main + 40 at add.c:12:9, address = 0x0000000100003f30
(lldb) breakpoint set --file add.c --line 13
Breakpoint 2: where = add`main + 56 at add.c:13:23, address = 0x0000000100003f40
(lldb) breakpoint set --file add.c --line 14
Breakpoint 3: where = add`main + 84 at add.c:14:12, address = 0x0000000100003f5c
(lldb) r
Process 26586 launched: '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64)
Process 26586 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100003f30 add`main at add.c:12:9
   9        i = 123;
   10       i = i + 1;
   11       j = 456;
-> 12       j = i + j;
   13       printf("j: %d\n", j);
   14       return j;
   15   }
Target 0: (add) stopped.

補足
上記のブレークポイントに関するエラーについて色々調べたところ、gccでなくclangでも同じ感じでコンパイルできます。 github.com

clang -g -O0 add.c -o add -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer

gccの方では -fomit-frame-pointer をつけていましたが、clangでもgcc-fomit-frame-pointer と同じ設定をするには、 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointerの両方を指定する必要があるとのことだったのでそのまま指定しています。

stackoverflow.com

The problem ended up being that, on x86-64 Linux at least, Clang requires both -fno-omit-frame-pointer and -mno-omit-leaf-frame-pointer in order to get the same behavior that gcc gives with only -fno-omit-frame-pointer. See this LLVM bug: "Need both -fno-omit-frame-pointer and -mno-omit-leaf-frame-pointer to get a fp on linux on a leaf function"

これで一通り下記のことができるようになりました。 - lldbによるデバッグができる状態でコンパイルする - lldbで実行ファイルに対してブレークポイントを貼る

lldbによるデバッグ

前項でかるく説明しましたが、lldbによるデバッグを実行します。
ここではcのソースコードの所定の行にブレークポイントを貼り、デバッグモードで実行し、それぞれのブレークポイントで下記の内容を確認します。
- 実行ファイルから逆アセンブルし、アセンブリコードレベルでのデバッグ
- レジスターの内容の確認

前述でやったのと同じ感じで、lldbを起動し、ブレークポイントを張っていきます。

# lldbを実行し、ブレークポイントを12, 13, 14行目に貼る。
lldb add
(lldb) target create "add"
Current executable set to '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64).
(lldb) breakpoint set --file add.c --line 12
Breakpoint 1: where = add`main + 40 at add.c:12:9, address = 0x0000000100003f30
(lldb) breakpoint set --file add.c --line 13
Breakpoint 2: where = add`main + 56 at add.c:13:23, address = 0x0000000100003f40
(lldb) breakpoint set --file add.c --line 14
Breakpoint 3: where = add`main + 84 at add.c:14:12, address = 0x0000000100003f5c
(lldb) r
Process 26586 launched: '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64)
Process 26586 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100003f30 add`main at add.c:12:9
   9        i = 123;
   10       i = i + 1;
   11       j = 456;
-> 12       j = i + j;
   13       printf("j: %d\n", j);
   14       return j;
   15   }
Target 0: (add) stopped.

ブレークポイントを貼る

下記のように、breakpoint set を使って、ソースコードのファイルと行数を指定してブレークポイントを貼ることができます。

breakpoint set --file add.c --line 12

breakpoinは、エイリアスとしてb でも使えます。
使い方は、help bで見ることができ、上記と同じ内容でもっと簡潔に書くことができます。

breakpoint        -- Commands for operating on breakpoints (see 'help b' for shorthand.)
(lldb) help b
Set a breakpoint using one of several shorthand formats.  Expects 'raw' input (see 'help raw-input'.)

Syntax: 
_regexp-break <filename>:<linenum>:<colnum>
              main.c:12:21          // Break at line 12 and column 21 of main.c

下記のように簡単に書けます。

(lldb) b add.c:12
Breakpoint 7: where = add`main + 40 at add.c:12:9, address = 0x0000000100003f30
(lldb) b add.c:13
Breakpoint 8: where = add`main + 56 at add.c:13:23, address = 0x0000000100003f40
(lldb) b add.c:14
Breakpoint 9: where = add`main + 84 at add.c:14:12, address = 0x0000000100003f5c

デバッグの実行

ここで、ブレークポイントを設定したので、デバッグの実行をしていきます。 rを使ってデバッグ実行を開始できます。

  r         -- Launch the executable in the debugger.

ブレークポイントを貼った状態で実行します。

# ブレークポイント
...
(lldb) b add.c:14
Breakpoint 11: where = add`main + 84 at add.c:14:12, address = 0x0000000100003f5c

# デバッグ実行
(lldb) r
There is a running process, kill it and restart?: [Y/n] y
Process 27285 exited with status = 9 (0x00000009) 
Process 27388 launched: '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64)
Process 27388 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 4.1 7.1
    frame #0: 0x0000000100003f30 add`main at add.c:12:9
   9           i = 123;
   10          i = i + 1;
   11          j = 456;
-> 12       j = i + j;
   13          printf("j: %d\n", j);
   14          return j;
   15      }
Target 0: (add) stopped.
(lldb) 

12, 13 ,14行目に貼っているので、最初のブレークポイントで止まっている状態です。

レジスターの状態の確認

この状態で、register read を実行することで、ブレークポイントで止まっている位置でのレジスタの状態を確認できます。 ここでは先ほどと重複しますが、 12行目でのレジスタの状態を確認しています。
11行目で j = 456 となっていますが、x8のレジスタにjにセットされている456(16進数で1C8)の値があることが確認できます。

(lldb) r
There is a running process, kill it and restart?: [Y/n] y
Process 27285 exited with status = 9 (0x00000009) 
Process 27388 launched: '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64)
Process 27388 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 4.1 7.1
    frame #0: 0x0000000100003f30 add`main at add.c:12:9
   9           i = 123;
   10          i = i + 1;
   11          j = 456;
-> 12       j = i + j;
   13          printf("j: %d\n", j);
   14          return j;
   15      }
Target 0: (add) stopped.
(lldb) register read
General Purpose Registers:
        x0 = 0x0000000000000001
        x1 = 0x000000016fdff538
        x2 = 0x000000016fdff548
        x3 = 0x000000016fdff6b0
        x4 = 0x0000000000000000
        x5 = 0x0000000000000000
        x6 = 0x0000000000000000
        x7 = 0x0000000000000000
        x8 = 0x00000000000001c8 # <- ここで456の値がセットされている。
        x9 = 0x0000000000000002
       x10 = 0x0000000000000000
       x11 = 0x0000000000000002
       x12 = 0x0000000000000002
       x13 = 0x0000000000000000
       x14 = 0x0000000000000008
       x15 = 0x0000000000000000
       x16 = 0x0000000300033088
       x17 = 0x6ae100016fdfe7d0
       x18 = 0x0000000000000000
       x19 = 0x00000001000c0060
       x20 = 0x0000000100003f08  add`main at add.c:7
       x21 = 0x000000010006c070  dyld`dyld4::sConfigBuffer
       x22 = 0x0000000000000000
       x23 = 0x0000000000000000
       x24 = 0x0000000000000000
       x25 = 0x0000000000000000
       x26 = 0x0000000000000000
       x27 = 0x0000000000000000
       x28 = 0x0000000000000000
        fp = 0x000000016fdff510
        lr = 0x000000010001108c  dyld`start + 520
        sp = 0x000000016fdff3a0
        pc = 0x0000000100003f30  add`main + 40 at add.c:12:9
      cpsr = 0x60001000

実行中プログラムを逆アセンブルしたアセンブルコードを表示する

先ほどはcのソースファイルレベルでどこでブレークされているかを確認できましたが、この実行ファイルを逆アセンブリしたアセンブルコードレベルでどの状態にいるかを確認できます。
lldbのdi コマンドで確認ができます。

  di        -- Disassemble specified instructions in the current target.  Defaults to the current function
               for the current thread and stack frame.

ここでアセンブリコードを確認します。

(lldb) di
add`main:
    0x100003f08 <+0>:  sub    sp, sp, #0x30
    0x100003f0c <+4>:  stp    x29, x30, [sp, #0x20]
    0x100003f10 <+8>:  str    wzr, [sp, #0x1c]
    0x100003f14 <+12>: mov    w8, #0x7b
    0x100003f18 <+16>: str    w8, [sp, #0x18]
    0x100003f1c <+20>: ldr    w8, [sp, #0x18]
    0x100003f20 <+24>: add    w8, w8, #0x1
    0x100003f24 <+28>: str    w8, [sp, #0x18]
    0x100003f28 <+32>: mov    w8, #0x1c8
    0x100003f2c <+36>: str    w8, [sp, #0x14]
->  0x100003f30 <+40>: ldr    w8, [sp, #0x18]
    0x100003f34 <+44>: ldr    w9, [sp, #0x14]
    0x100003f38 <+48>: add    w8, w8, w9
    0x100003f3c <+52>: str    w8, [sp, #0x14]
    0x100003f40 <+56>: ldr    w9, [sp, #0x14]
    0x100003f44 <+60>: mov    x8, x9
    0x100003f48 <+64>: adrp   x0, 0
    0x100003f4c <+68>: add    x0, x0, #0xf78            ; "j: %d\n"
    0x100003f50 <+72>: mov    x9, sp
    0x100003f54 <+76>: str    x8, [x9]
    0x100003f58 <+80>: bl     0x100003f6c               ; symbol stub for: printf
    0x100003f5c <+84>: ldr    w0, [sp, #0x14]
    0x100003f60 <+88>: ldp    x29, x30, [sp, #0x20]
    0x100003f64 <+92>: add    sp, sp, #0x30
    0x100003f68 <+96>: ret    
(lldb) 

lldb上では 左側に-> が表示されている行が、現在のプログラムの位置となります。

ソースコード上の位置と、アセンブリコードの位置を確認してみます。 cでは、 j = i + j という処理をしているところとなります。

-> 12         j = i + j;

ここでは、ldrというオペコードで、w8, w9にそれぞれi と jの値を読み込み、add w8, w8, w9 で、w8とw9の値を足した結果をw8レジスタに格納することで j = i + j の処理を表しています。

->  0x100003f30 <+40>: ldr    w8, [sp, #0x18]
    0x100003f34 <+44>: ldr    w9, [sp, #0x14]
    0x100003f38 <+48>: add    w8, w8, w9

メモとして、オペコードは下記のページで確認できます。 - ARM LDR - ARM ADD

ここで、ブレークポイントで止まった箇所で下記2つを確認できました。 - ブレークポイントでのレジスタの状態 - 実行ファイルを逆アセンブルし、アセンブリコードレベルでどの処理を実行しているかの確認

次のブレークポイントまで処理を進める。

ここからは、次のブレークポイントへ処理を進めていきます。
下記の2つの方法で処理を進めることができます。

1.next, n : ソースコードレベルで次のブレークポイントまで進める(Cのソースコードの行数ごとに進める)
2. nexti , ni : 実際のアセンブリコードレベルで次のブレークポイントまで進める

  n         -- Source level single step, stepping over calls.  Defaults to current thread unless specified.
  next      -- Source level single step, stepping over calls.  Defaults to current thread unless specified.
  nexti     -- Instruction level single step, stepping over calls.  Defaults to current thread unless
               specified.
  ni        -- Instruction level single step, stepping over calls.  Defaults to current thread unless
               specified.

2では、前項で説明したように、1で設定したCのソースコードの各行ごとに、アセンブリコードでは複数の処理となる可能性があるため、アセンブリコードレベルで1つ1つ処理を進めていく形になります。
例: 前項でj = i + j という行は、アセンブリコードレベルではldr, ldr, add と3つのオペコードに分割されているため3ステップになること。

ここではアセンブリコードレベルで、どのように処理を進むかを確認したいため、12行目のj = i + j が終わるところまでnextiを実行して1つずつ処理を進めていきます。

(lldb) nexti
Process 27388 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over
    frame #0: 0x0000000100003f34 add`main at add.c:12:13
   9           i = 123;
   10          i = i + 1;
   11          j = 456;
-> 12       j = i + j;
   13          printf("j: %d\n", j);
   14          return j;
   15      }
Target 0: (add) stopped.
(lldb) di
add`main:
    0x100003f08 <+0>:  sub    sp, sp, #0x30
    0x100003f0c <+4>:  stp    x29, x30, [sp, #0x20]
    0x100003f10 <+8>:  str    wzr, [sp, #0x1c]
    0x100003f14 <+12>: mov    w8, #0x7b
    0x100003f18 <+16>: str    w8, [sp, #0x18]
    0x100003f1c <+20>: ldr    w8, [sp, #0x18]
    0x100003f20 <+24>: add    w8, w8, #0x1
    0x100003f24 <+28>: str    w8, [sp, #0x18]
    0x100003f28 <+32>: mov    w8, #0x1c8
    0x100003f2c <+36>: str    w8, [sp, #0x14]
    0x100003f30 <+40>: ldr    w8, [sp, #0x18]
->  0x100003f34 <+44>: ldr    w9, [sp, #0x14]
    0x100003f38 <+48>: add    w8, w8, w9
    0x100003f3c <+52>: str    w8, [sp, #0x14]
    0x100003f40 <+56>: ldr    w9, [sp, #0x14]
    0x100003f44 <+60>: mov    x8, x9
    0x100003f48 <+64>: adrp   x0, 0
    0x100003f4c <+68>: add    x0, x0, #0xf78            ; "j: %d\n"
    0x100003f50 <+72>: mov    x9, sp
    0x100003f54 <+76>: str    x8, [x9]
    0x100003f58 <+80>: bl     0x100003f6c               ; symbol stub for: printf
    0x100003f5c <+84>: ldr    w0, [sp, #0x14]
    0x100003f60 <+88>: ldp    x29, x30, [sp, #0x20]
    0x100003f64 <+92>: add    sp, sp, #0x30
    0x100003f68 <+96>: ret    
(lldb) register read
General Purpose Registers:
        x0 = 0x0000000000000001
        x1 = 0x000000016fdff538
        x2 = 0x000000016fdff548
        x3 = 0x000000016fdff6b0
        x4 = 0x0000000000000000
        x5 = 0x0000000000000000
        x6 = 0x0000000000000000
        x7 = 0x0000000000000000
        x8 = 0x000000000000007c
        x9 = 0x0000000000000002
       x10 = 0x0000000000000000
       x11 = 0x0000000000000002
       x12 = 0x0000000000000002
       x13 = 0x0000000000000000
       x14 = 0x0000000000000008
       x15 = 0x0000000000000000
       x16 = 0x0000000300033088
       x17 = 0x6ae100016fdfe7d0
       x18 = 0x0000000000000000
       x19 = 0x00000001000c0060
       x20 = 0x0000000100003f08  add`main at add.c:7
       x21 = 0x000000010006c070  dyld`dyld4::sConfigBuffer
       x22 = 0x0000000000000000
       x23 = 0x0000000000000000
       x24 = 0x0000000000000000
       x25 = 0x0000000000000000
       x26 = 0x0000000000000000
       x27 = 0x0000000000000000
       x28 = 0x0000000000000000
        fp = 0x000000016fdff510
        lr = 0x000000010001108c  dyld`start + 520
        sp = 0x000000016fdff3a0
        pc = 0x0000000100003f34  add`main + 44 at add.c:12:13
      cpsr = 0x60001000

(lldb) nexti
Process 27388 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over
    frame #0: 0x0000000100003f38 add`main at add.c:12:11
   9           i = 123;
   10          i = i + 1;
   11          j = 456;
-> 12       j = i + j;
   13          printf("j: %d\n", j);
   14          return j;
   15      }
Target 0: (add) stopped.
(lldb) di
add`main:
    0x100003f08 <+0>:  sub    sp, sp, #0x30
    0x100003f0c <+4>:  stp    x29, x30, [sp, #0x20]
    0x100003f10 <+8>:  str    wzr, [sp, #0x1c]
    0x100003f14 <+12>: mov    w8, #0x7b
    0x100003f18 <+16>: str    w8, [sp, #0x18]
    0x100003f1c <+20>: ldr    w8, [sp, #0x18]
    0x100003f20 <+24>: add    w8, w8, #0x1
    0x100003f24 <+28>: str    w8, [sp, #0x18]
    0x100003f28 <+32>: mov    w8, #0x1c8
    0x100003f2c <+36>: str    w8, [sp, #0x14]
    0x100003f30 <+40>: ldr    w8, [sp, #0x18]
    0x100003f34 <+44>: ldr    w9, [sp, #0x14]
->  0x100003f38 <+48>: add    w8, w8, w9
    0x100003f3c <+52>: str    w8, [sp, #0x14]
    0x100003f40 <+56>: ldr    w9, [sp, #0x14]
    0x100003f44 <+60>: mov    x8, x9
    0x100003f48 <+64>: adrp   x0, 0
    0x100003f4c <+68>: add    x0, x0, #0xf78            ; "j: %d\n"
    0x100003f50 <+72>: mov    x9, sp
    0x100003f54 <+76>: str    x8, [x9]
    0x100003f58 <+80>: bl     0x100003f6c               ; symbol stub for: printf
    0x100003f5c <+84>: ldr    w0, [sp, #0x14]
    0x100003f60 <+88>: ldp    x29, x30, [sp, #0x20]
    0x100003f64 <+92>: add    sp, sp, #0x30
    0x100003f68 <+96>: ret    
(lldb) register read
General Purpose Registers:
        x0 = 0x0000000000000001
        x1 = 0x000000016fdff538
        x2 = 0x000000016fdff548
        x3 = 0x000000016fdff6b0
        x4 = 0x0000000000000000
        x5 = 0x0000000000000000
        x6 = 0x0000000000000000
        x7 = 0x0000000000000000
        x8 = 0x000000000000007c
        x9 = 0x00000000000001c8
       x10 = 0x0000000000000000
       x11 = 0x0000000000000002
       x12 = 0x0000000000000002
       x13 = 0x0000000000000000
       x14 = 0x0000000000000008
       x15 = 0x0000000000000000
       x16 = 0x0000000300033088
       x17 = 0x6ae100016fdfe7d0
       x18 = 0x0000000000000000
       x19 = 0x00000001000c0060
       x20 = 0x0000000100003f08  add`main at add.c:7
       x21 = 0x000000010006c070  dyld`dyld4::sConfigBuffer
       x22 = 0x0000000000000000
       x23 = 0x0000000000000000
       x24 = 0x0000000000000000
       x25 = 0x0000000000000000
       x26 = 0x0000000000000000
       x27 = 0x0000000000000000
       x28 = 0x0000000000000000
        fp = 0x000000016fdff510
        lr = 0x000000010001108c  dyld`start + 520
        sp = 0x000000016fdff3a0
        pc = 0x0000000100003f38  add`main + 48 at add.c:12:11
      cpsr = 0x60001000

(lldb) nexti
Process 27388 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over
    frame #0: 0x0000000100003f3c add`main at add.c:12:7
   9           i = 123;
   10          i = i + 1;
   11          j = 456;
-> 12       j = i + j;
   13          printf("j: %d\n", j);
   14          return j;
   15      }
Target 0: (add) stopped.
(lldb) register read
General Purpose Registers:
        x0 = 0x0000000000000001
        x1 = 0x000000016fdff538
        x2 = 0x000000016fdff548
        x3 = 0x000000016fdff6b0
        x4 = 0x0000000000000000
        x5 = 0x0000000000000000
        x6 = 0x0000000000000000
        x7 = 0x0000000000000000
        x8 = 0x0000000000000244
        x9 = 0x00000000000001c8
       x10 = 0x0000000000000000
       x11 = 0x0000000000000002
       x12 = 0x0000000000000002
       x13 = 0x0000000000000000
       x14 = 0x0000000000000008
       x15 = 0x0000000000000000
       x16 = 0x0000000300033088
       x17 = 0x6ae100016fdfe7d0
       x18 = 0x0000000000000000
       x19 = 0x00000001000c0060
       x20 = 0x0000000100003f08  add`main at add.c:7
       x21 = 0x000000010006c070  dyld`dyld4::sConfigBuffer
       x22 = 0x0000000000000000
       x23 = 0x0000000000000000
       x24 = 0x0000000000000000
       x25 = 0x0000000000000000
       x26 = 0x0000000000000000
       x27 = 0x0000000000000000
       x28 = 0x0000000000000000
        fp = 0x000000016fdff510
        lr = 0x000000010001108c  dyld`start + 520
        sp = 0x000000016fdff3a0
        pc = 0x0000000100003f3c  add`main + 52 at add.c:12:7
      cpsr = 0x60001000

(lldb) nexti
Process 27388 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 5.1 8.1
    frame #0: 0x0000000100003f40 add`main at add.c:13:23
   10          i = i + 1;
   11          j = 456;
   12          j = i + j;
-> 13       printf("j: %d\n", j);
   14          return j;
   15      }
Target 0: (add) stopped.
(lldb) di
add`main:
    0x100003f08 <+0>:  sub    sp, sp, #0x30
    0x100003f0c <+4>:  stp    x29, x30, [sp, #0x20]
    0x100003f10 <+8>:  str    wzr, [sp, #0x1c]
    0x100003f14 <+12>: mov    w8, #0x7b
    0x100003f18 <+16>: str    w8, [sp, #0x18]
    0x100003f1c <+20>: ldr    w8, [sp, #0x18]
    0x100003f20 <+24>: add    w8, w8, #0x1
    0x100003f24 <+28>: str    w8, [sp, #0x18]
    0x100003f28 <+32>: mov    w8, #0x1c8
    0x100003f2c <+36>: str    w8, [sp, #0x14]
    0x100003f30 <+40>: ldr    w8, [sp, #0x18]
    0x100003f34 <+44>: ldr    w9, [sp, #0x14]
    0x100003f38 <+48>: add    w8, w8, w9
    0x100003f3c <+52>: str    w8, [sp, #0x14]
->  0x100003f40 <+56>: ldr    w9, [sp, #0x14]
    0x100003f44 <+60>: mov    x8, x9
    0x100003f48 <+64>: adrp   x0, 0
    0x100003f4c <+68>: add    x0, x0, #0xf78            ; "j: %d\n"
    0x100003f50 <+72>: mov    x9, sp
    0x100003f54 <+76>: str    x8, [x9]
    0x100003f58 <+80>: bl     0x100003f6c               ; symbol stub for: printf
    0x100003f5c <+84>: ldr    w0, [sp, #0x14]
    0x100003f60 <+88>: ldp    x29, x30, [sp, #0x20]
    0x100003f64 <+92>: add    sp, sp, #0x30
    0x100003f68 <+96>: ret    
(lldb) di
add`main:
    0x100003f08 <+0>:  sub    sp, sp, #0x30
    0x100003f0c <+4>:  stp    x29, x30, [sp, #0x20]
    0x100003f10 <+8>:  str    wzr, [sp, #0x1c]
    0x100003f14 <+12>: mov    w8, #0x7b
    0x100003f18 <+16>: str    w8, [sp, #0x18]
    0x100003f1c <+20>: ldr    w8, [sp, #0x18]
    0x100003f20 <+24>: add    w8, w8, #0x1
    0x100003f24 <+28>: str    w8, [sp, #0x18]
    0x100003f28 <+32>: mov    w8, #0x1c8
    0x100003f2c <+36>: str    w8, [sp, #0x14]
    0x100003f30 <+40>: ldr    w8, [sp, #0x18]
    0x100003f34 <+44>: ldr    w9, [sp, #0x14]
    0x100003f38 <+48>: add    w8, w8, w9
    0x100003f3c <+52>: str    w8, [sp, #0x14]
->  0x100003f40 <+56>: ldr    w9, [sp, #0x14]
    0x100003f44 <+60>: mov    x8, x9
    0x100003f48 <+64>: adrp   x0, 0
    0x100003f4c <+68>: add    x0, x0, #0xf78            ; "j: %d\n"
    0x100003f50 <+72>: mov    x9, sp
    0x100003f54 <+76>: str    x8, [x9]
    0x100003f58 <+80>: bl     0x100003f6c               ; symbol stub for: printf
    0x100003f5c <+84>: ldr    w0, [sp, #0x14]
    0x100003f60 <+88>: ldp    x29, x30, [sp, #0x20]
    0x100003f64 <+92>: add    sp, sp, #0x30
    0x100003f68 <+96>: ret    
(lldb) register read
General Purpose Registers:
        x0 = 0x0000000000000001
        x1 = 0x000000016fdff538
        x2 = 0x000000016fdff548
        x3 = 0x000000016fdff6b0
        x4 = 0x0000000000000000
        x5 = 0x0000000000000000
        x6 = 0x0000000000000000
        x7 = 0x0000000000000000
        x8 = 0x0000000000000244
        x9 = 0x00000000000001c8
       x10 = 0x0000000000000000
       x11 = 0x0000000000000002
       x12 = 0x0000000000000002
       x13 = 0x0000000000000000
       x14 = 0x0000000000000008
       x15 = 0x0000000000000000
       x16 = 0x0000000300033088
       x17 = 0x6ae100016fdfe7d0
       x18 = 0x0000000000000000
       x19 = 0x00000001000c0060
       x20 = 0x0000000100003f08  add`main at add.c:7
       x21 = 0x000000010006c070  dyld`dyld4::sConfigBuffer
       x22 = 0x0000000000000000
       x23 = 0x0000000000000000
       x24 = 0x0000000000000000
       x25 = 0x0000000000000000
       x26 = 0x0000000000000000
       x27 = 0x0000000000000000
       x28 = 0x0000000000000000
        fp = 0x000000016fdff510
        lr = 0x000000010001108c  dyld`start + 520
        sp = 0x000000016fdff3a0
        pc = 0x0000000100003f40  add`main + 56 at add.c:13:23
      cpsr = 0x60001000

ここで、途中のところでレジスタのところを抜粋すると、 x80x7c(10進数で124)x90x1c8(10進数で456 となっていることがわかります。

...
        x8 = 0x000000000000007c
        x9 = 0x00000000000001c8
...

そして、j = i + j の計算が終わると、x8にその計算結果である0x244(10進数でいうと580)が格納されているのがわかります。
オペコードaddにより、x8の値のみ変わりますが、x9の値は変更がないのでそのままとなっていることが確認できます。

        x8 = 0x0000000000000244
        x9 = 0x00000000000001c8

今回やっていないこと

今回はlldbの使い方の簡単な整理が目的のため、下記の項目については取り掛かっていないですが、別途時間があればまとめようかと思います。