この本はOSを自作している方にOSのデバッグ技術を紹介する目的で書かれました。OSを作っていく過程で遭遇しがちな問題を取りあげ,筆者が実践しているデバッグ技術を説明します。バイナリファイルの調べ方,QEMUとGDBの連携のさせ方,OSが再起動してしまうときのバグの調べ方などが主な話題となります。
紙面の都合と筆者のカバー範囲の都合で,この本の主題はx86-64向けのOS開発に絞りました。その中でも64ビットモードの話が多めです。現在も大人気の書籍「30日でできる!OS自作入門」では32ビットモード向けのOSを開発しますから,この本でも多少は32ビットモードの話題を扱います。
x86とx86-64以外のCPUの話題はまったく登場しません。それでも,objdump
やreadelf
,QEMUなどの各種ツールの使い方は応用が効くと思います。また,どこから調べるかという勘は,どのCPU向けの開発であっても共通する部分が多いと思います。
表紙の雀の画像はCapri23autoさん*1によるPixabay*2からのものです。素晴らしい写真を使用料無料で提供していただき感謝です。
主な対象読者は「30日でできる!OS自作入門」や類書を参考にして,x86やx86-64向けのOSを作っている方,これから作ろうとしている方です。シンボルアドレスの調べ方を知りたい,GDBを使ったデバッグ方法を知りたい,EIPの値を手がかりにして調査してみたいなどの要望に答えます。各種のデバッグツールを使いこなしている方には既知の話題ばかりかもしれませんが,ご自身と筆者のデバッグ手法の違いを眺めて楽しむことはできるかもしれません。そして,より良い方法がありましたら筆者に教えていただけませんでしょうか?
この本の内容はx86-64版のUbuntu 18.04で動作確認しています。x86-64マシンであれば,他のLinuxディストリビューションを使っても同様に実験できると思いますが,コマンド名などが異なるかもしれません。WindowsではWSL(Windows Subsystem for Linux)でUbuntuをインストールすれば多くのコマンドはそのまま実行可能できるでしょう。
筆者はTwitterでは@uchan_nosとして活動しています。現在はサイボウズ・ラボ株式会社で自作OSの作成やソフトウェアバグの自動検出手法の研究をしています。これまでの略歴はサイボウズ・ラボのメンバーページ(https://labs.cybozu.co.jp/member/uchan.html)をご覧ください。
2003年,筆者がまだ中学生だったときに国産OS「OSASK」と出会い,そのときから自作OSとずっと関わっています。この本は,そんな筆者が普段使っているデバッグ技法をまとめたものです。筆者がこれまでに出してきた同人誌はBOOTH(https://uchan.booth.pm/)で頒布しています。
この本の中で登場するサンプルコードはOSSとして公開しています。手元にダウンロードする方法を説明します。
サンプルコードのリポジトリはhttps://github.com/uchan-nos/debugging-low-layer-distrib/
です。GitHubのリポジトリをダウンロードする方法は通常,git
clone
で特定のブランチをダウンロードするか,特定のリリースを選択してファイルをダウンロード方法があります。このリポジトリについてはリリースを選んでダウンロードするのがおすすめです。なぜなら,リポジトリ本体にはMikanOSのイメージファイル(mikanos.img)が含まれておらず,git
clone
では取得できないからです。イメージファイルはリリースに含まれます。(イメージファイルの容量が大きくてリポジトリに含められなかったのです)
$ wget https://github.com/uchan-nos/debugging-low-layer-distrib/⏎
archive/v1.0.tar.gz
$ tar xf v1.0.tar.gz
$ cd debugging-low-layer-distrib-1.0
$ wget https://github.com/uchan-nos/debugging-low-layer-distrib/⏎
releases/download/v1.0/mikanos.img
これでサンプルコードとMikanOSのイメージファイルを取得できました。この本の続きをお楽しみください。
筆者は学生への教育にも興味があります。紙面の空きを利用して,中高生,大学生などに適した開発・学習支援制度をいくつかお伝えします。金銭的な支援や学習機会を与えるものですから是非チャレンジしてみてください。
サイボウズ・ラボは2013年から「サイボウズ・ラボユース」*3を開催しています。これは,学生さん(高校生や大学生,大学院生など)を対象とした長期インターン制度で,学生さんの創作活動に対して金銭的および知的支援を行います。学生さんは自分の作りたいものを提案し,アイデアが採択されるとサイボウズ・ラボからアルバイト代が出ます。成果物をオープンソースにすることが条件ですが,著作権などの権利はすべて学生さんに属します。卒論発表に組み込んだり同人誌として売ったりできるということです。
筆者は実際に大学院修士1年のときにこの制度に採択され,修士論文研究で使うソフトウェア“C-Helper”をサイボウズ・ラボユースの支援のもと開発しました。修士論文研究を遂行することでお金がもらえるメリットに加え,サイボウズ・ラボのメンバーと議論できるのは素晴らしい機会でした。具体的にやりたいアイデアがある方にはとってもおすすめの制度です。
セキュリティ・キャンプ全国大会は,22歳以下の中高生や大学生を対象とする合宿形式のイベントです。4泊5日をかけて,各分野の第1線で活躍する講師陣が講義や演習を行います。取り扱う話題は,マルウェアの解析やWebサイトのセキュリティ,インシデントレスポンス等の「情報セキュリティ」と言ったときにぱっと思いつく話題から,プログラミング言語やOSの自作,IoT機器の解析など,実はセキュリティを高めるために必要な知識など,多岐に渡ります。
セキュリティ・キャンプ全国大会は交通費,宿泊費,食費がすべて支給されますから,参加者は無料で講義を受けることができます。同じレベルの講義を社会人向けにやると非常に高額になります。それが無料で受けられるのです。超オトクです。例年夏休み(8月中旬)に開催されるため,授業とは被らないはずです。応募は4月中旬くらいに始まるはずです。是非チャレンジしてみてください。
上記2つは筆者が関わっている制度のため比較的詳しく紹介しました。その他,筆者が関わっていないけど学生さんに利がある制度を2つご紹介します。
2020年11月の下旬から約2ヶ月間,筆者によるx86-64向け自作OSの講義が行われます。場所は東京工業大学大岡山キャンパスで,毎週金曜日午後に開講する予定です。社会人学生(科目等履修生)を大募集します。おそらく,これが最初で最後の筆者による自作OSの講義となりますので,是非受講してください。講義のシラバス案はこちらで紹介しています。https://t.co/wIHo0uES4P?amp=1
社会人の方でも科目等履修生という制度を使って受講できます。自作OSの講義だけを受講する場合の学費は約7万円程度だそうです。詳しくは東京工業大学の「科目等履修生について」をご覧ください。https://www.titech.ac.jp/graduate_school/auditors/auditors.html
問題:ELF形式のファイルelf.oをIntel記法で逆アセンブルしてください。
解答:objdump
コマンドを使うことで逆アセンブルが可能です。
$ objdump -d -M intel elf.o
-d
オプションが逆アセンブルの指示です。-M intel
はIntel記法で逆アセンブル結果を表示する指示です。objdump
はデフォルトでAT&T形式の表示となりますので,お好みの表示で読んでください。
C++で書いたプログラムの識別子はマングルされて読みづらい名前になります。そんなときは-C
オプションでデマングルすれば快適に読めるようになります。
$ objdump -d -M intel -C elf.o
...
0000000000000000 <printk(char const*, ...)>:
0: 55 push rbp
1: 53 push rbx
2: 48 81 ec d8 04 00 00 sub rsp,0x4d8
...
問題:独自形式(HRB形式)のバイナリファイルfoo.hrbを逆アセンブルしてください。
解答:ファイルフォーマットがobjdump
に認識されない場合でも-b binary
オプションを使うことで無理やり逆アセンブルすることが可能です。
$ objdump -D -b binary -m i386 --start-address=0x24 bootpack.hrb
-D
はすべてのセクションを逆アセンブルするオプションです。通常,オブジェクトファイルには機械語の他にヘッダや変数の初期値,デバッグ情報などが含まれています。-d
は機械語のセクションだけを対象にしますが-D
はその他のデータも含め,すべてを無理やり逆アセンブルします。独自形式のバイナリファイルはobjdump
にとってセクション構造が分からないため,-D
で無理やり全セクションを逆アセンブルしなければなりません。
--start-address=0x24
は逆アセンブルの開始アドレスを指定します。独自形式のバイナリファイルの場合はobjdump
が機械語の配置アドレスを認識できないため,開始アドレスと言いつつファイル先頭からのオフセットを指定することになります。上の例ではファイル先頭から0x24=36バイトをスキップするという意味になります。HRB形式(拡張子.hrb
)は「30日でできる!OS自作入門」で登場する実行可能形式で,先頭から36バイトがヘッダ,その直後から機械語が配置されます。
objdump -D
はデフォルトでは保護モード(32ビットモード)として逆アセンブルしてしまいます。x86-64の64ビットモード向けのバイナリを逆アセンブルする場合は-M x86-64
オプションを追加します。
$ objdump -D -b binary -m i386 -M x86-64 asmfunc.bin
なお,-M
に複数のオプションを渡す場合は-M オプション
を複数指定するか,オプションをカンマ区切りで指定します。例えば,64ビットモード向けバイナリをIntel記法で逆アセンブルするには-M intel,x86-64
と書けます。
問題:ELF形式の実行可能ファイルelf.outに含まれるシンボルprintk
のアドレスとサイズを調べてください。
解答:readelf
コマンドに-s
オプションを指定するとシンボルテーブルを表示できます。シンボルテーブルにはファイルに含まれるシンボルのアドレスとサイズが載っています。
$ readelf -s elf.out
...
Symbol table '.symtab' contains 63 entries:
番号: 値 サイズ タイプ Bind Vis 索引名
...
61: 0000000000400540 184 FUNC GLOBAL DEFAULT 12 _Z6printkPKcz
...
printk
というシンボルは,0x400540から配置される184バイトの関数(FUNC)だということが分かります。なお,elf.outはC++のコードから生成した実行可能ファイルですので,名前がマングリングされています。デマングルするにはc++filt
コマンドが便利です。
$ readelf -s elf.out | c++filt
...
61: 0000000000400540 184 FUNC GLOBAL DEFAULT 12 printk(char const*, ...)
...
なお,nm
コマンドを使ってもシンボルアドレスやサイズを調べることができます。nm
はELF以外の形式にも対応しています。