lldbでLLVMプログラムをデバッグする
2021-02-28
TechRust + LLVMで自作プログラミング言語Shiikaを作っているのだが、開発中に遭遇するエラーには以下の種類がある。
- rustcがエラーを吐く(=.rsに問題がある)。
- rustcは通ったが、Shiikaのエラーが出る(=.skに問題があるorバグで問題があると誤判定している)。
- rustcは通ったが、llcがエラーを吐く(=.llの生成に問題がある)。
- llcが実行ファイルを生成したが、実行すると期待通りに動かない。
一番面倒なのはもちろん最後のケースだが、これもさらにいくつかの種類に分けられる。
- 期待通りに動かないが、最後まで実行はできる(=Shiikaで書いたプログラムに間違いがある)。
- 最後まで実行できず、途中で落ちてしまう。
前者は普通にShiikaのpメソッドとかでデバッグするだけだが、後者は.llの生成に問題があり、しかもllcがエラーを検知できないというケース。こういうときはlldbを使う。
lldb
lldb examples/a.sk.out
みたいにして起動。run
で実行するとこんな感じの情報が出る。
(lldb) run
Process 56119 launched: '/Users/yhara/Dropbox/proj/shiika/examples/a.sk.out' (x86_64)
expected 99
i: 1 j: 4
Process 56119 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
frame #0: 0x0000000100010422 a.sk.out`lambda_31 + 818
a.sk.out`lambda_31:
-> 0x100010422 <+818>: ud2
0x100010424 <+820>: nopw %cs:(%rax,%rax)
0x10001042e <+830>: nop
a.sk.out`main:
0x100010430 <+0>: pushq %rax
bt
でバックトレースを表示できる。
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
* frame #0: 0x0000000100010422 a.sk.out`lambda_31 + 818
frame #1: 0x00000001000064e3 a.sk.out`Array#each + 259
frame #2: 0x000000010000ce32 a.sk.out`lambda_30 + 290
frame #3: 0x000000010000e0cb a.sk.out`lambda_21 + 139
frame #4: 0x00000001000064e3 a.sk.out`Array#each + 259
frame #5: 0x00000001000073dc a.sk.out`Array#map + 268
frame #6: 0x0000000100001466 a.sk.out`Meta:A#return_from_block + 262
frame #7: 0x000000010000ff3a a.sk.out`user_main + 650
frame #8: 0x0000000100010440 a.sk.out`main + 16
frame #9: 0x00007fff6d3e3cc9 libdyld.dylib`start + 1
ということで.llの@lambda_31
のところを見てみると、unreachable命令のところに到達してしまっていることがわかった。