LoginSignup
4
1

More than 1 year has passed since last update.

M1 Macでソースコードを見ながら「ゼロからのOS自作入門」のデバッグをする。

Last updated at Posted at 2021-12-09

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というファイル構成です。)

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を押せば、デバッグできます。
Screen Shot 2021-12-09 at 22.02.30.png
アセンブリが続くので、コンティニューして、main.cppのブレイクポイントまで行くと、デバッグの時間です🎉
Screen Shot 2021-12-09 at 21.57.16.png

感想

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を使わない方法になりました。

最後になりますが、面白い本を書いてくださりありがとうございます!

4
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1