#M1 Macでgdbが使えなくて困っている人向けの記事
現在(2021/12/06)、gdbはM1 Macに対応していないようでインストールできません。そのため、lldbを使ってデバッグします。terminalやVS Codeでソースコードを見ながらデバッグできます。
デバッグの手順は[launching-a-locally-built-process-on-the-remote-machine]にも書いてあります。
M1 Macでqemu-system-x86_64を動かし、その上でmikanosを起動しています。
Docker環境ではありません。
mikanosのMakefile等の環境構築はここを参考にしてください。
qemu-system-x86_64の起動は著者が公開している、run_qemu.shを利用ます。
$QEMU_OPTS
という環境変数を読み込んでいるので、ターミナルや~/.zshrc
で環境変数をセットします。
export QEMU_OPTS="-gdb tcp::12345 -S"
-Sでデバッガが接続するまで、qemuを止めることができます。
環境変数をセットしたら、run_qemu.shを実行して、qemu-system-x86_64を起動します。
その後、別のターミナルでkernelフォルダに移動して、次のような順番でコマンドを叩いていけば、ソースコードを見ながらデバッグできるようになります。
lldb
file kernel.elf
gdb-remote localhost:12345
breakpoint set --name KernelMainNewStack
c
章が進んでいなくて、main.cppのエントリポイントがKernelMainの場合は、KernelMainNewStackではなく、KernelMainを指定してください。
実際の画面はこんな感じです。
hoge@hogeAir kernel % lldb
(lldb) file kernel.elf
Current executable set to '/Users/hoge/workspace/mymikanos/kernel/kernel.elf' (x86_64).
(lldb) gdb-remote localhost:12345
Process 1 stopped
* thread #1, stop reason = signal SIGTRAP
frame #0: 0x000000000000fff0
-> 0xfff0: addb %al, (%rax)
0xfff2: addb %al, (%rax)
0xfff4: addb %al, (%rax)
0xfff6: addb %al, (%rax)
(lldb) breakpoint set --name KernelMainNewStack
Breakpoint 1: where = kernel.elf`::KernelMainNewStack(const FrameBufferConfig &, const MemoryMap &) + 19 at main.cpp:136:43, address = 0x0000000000105833
(lldb) c
Process 1 resuming
Process 1 stopped
* thread #1, stop reason = breakpoint 1.1
frame #0: 0x0000000000105833 kernel.elf`::KernelMainNewStack(frame_buffer_config_ref=0x000000003feac7e0, memory_map_ref=0x000000003feac8f0) at main.cpp:136:43
133 KernelMainNewStack(const FrameBufferConfig &frame_buffer_config_ref,
134 const MemoryMap &memory_map_ref)
135 {
-> 136 FrameBufferConfig frame_buffer_config{frame_buffer_config_ref};
137 MemoryMap memory_map{memory_map_ref};
138
139 switch (frame_buffer_config.pixel_format)
(lldb)
lldbを起動してから実行するコマンドを、テキストファイルに書いて、それをlldb起動時に指定することもできます。リモート接続等の毎回やる作業を自動化できます。
例えば、lldb.txtに次のようにコマンドを書いて、
file kernel.elf
gdb-remote localhost:12345
breakpoint set --name KernelMainNewStack
このようにファイル指定できます。
lldb -s ./lldb.txt
lldbのコマンドはこの辺りが参考になるかもしれません。
lldb で使えるコマンド一覧
VS Codeでデバッグする方法
まず、CodeLLDBをインストールします。
公式サイトを参考にlaunch.jsonに次のように記述していきます。(自分はmikanosフォルダをvscodeで開いてるので、mikanos/.vscode/launch.jsonというファイル構成です。)
{
"version": "0.2.0",
"configurations": [
{
"name": "remote launch",
"type": "lldb",
"request": "custom",
"targetCreateCommands": ["target create ${fileDirname}/kernel.elf"],
"processCreateCommands": ["gdb-remote localhost:12345"],
}
]
}
上記と同じように環境変数を設定してrun_qemu.shを起動します。
その後、main.cppに適当にブレイクポイントを設定してF5を押せば、デバッグできます。
アセンブリが続くので、コンティニューして、main.cppのブレイクポイントまで行くと、デバッグの時間です🎉
感想
lldbのコマンドを知ってしまえば簡単なんですが、英語力の問題か想像以上に時間がかかってしまいました。
Testing LLDB using QEMUという記事もあったのですが、Ubuntuを動かしたりしているので、自作OSのデバッグに利用したい場合はどうすればいいんだろうかと思ってしましました。今思うと、launching-a-locally-built-process-on-the-remote-machineを初手で試してみるのが正解ぽいでした。
qemuの起動時に./disk.imgを指定して、lldbの起動時にもkernel.elfを指定する必要があるのが、少し不思議です。自動で決定されないのかとうい気持ちになります。
lldbのことをよくわかっていないので、便利になるカスタム等あったら教えてください!
後は、プログラムをバグらせて、頻繁にKernelMainNewStackに飛ばされています。現状適当に当たりをつけたり、ブレークポイント2分探索してるんですが、いい感じにデバッグする方法ないんですかね。
ちなみにDockerの利用を検討したんですが、makeが遅かったり、mount: ./mnt: mount failed: Operation not permitted.
のエラーが消せなかったり、qemu起動時のstart pxe over ipv4
のエラーが消せなかったのでDockerを使わない方法になりました。
最後になりますが、面白い本を書いてくださりありがとうございます!