概要
BIOSがMBRを読み込んでブートローダが動き出し、カーネルをメモリにロードして/sbin/initが動き出すまでの処理をデバッグするための自分めもめも。そして最近?は/sbin/initからsystemdに置き換わりつつあるらしいので、systemdを導入しているcentOS7を使用してsystemdから各プロセスを起動させる処理もデバッグできたらいいなぁ(でもきっとむり)。カーネル処理をみていくことでそこから色々派生していろんな知識を学べたらいいなぁ。そしてこのデバッグ経験を活かしてDockerなどのコンテナ技術をカーネル(cgroups、systemd)のコードから理解できるようになれればいいなぁ(でもきっとむり)。
スタート地点
どこからデバッグしてみようかなぁと考えた。とりあえずアセンブラ部分はやめておこう後に取っておこうというとでブートローダ(Cの箇所もあるけど)とばし、カーネル処理のアセンブラ箇所(メモリ設定など)をとばしー、なんて思ってたらデバッグのスタート地点は王道のstart_kernelからに決定。ということで今回は環境構築してGDB起動してstart_kernel先頭まで。
カーネル探検(環境構築からstart_kernelまで)
概要
仮想マシン上のCentOS7カーネルをGDBでリモートデバッグする。
準備
- ホストOS
- Cent7
- ゲストOS
- Cent7
- QEMU(2.4.1)
- qemu-system-xxxコマンドは自分でmake && make install
- カーネルver
- 3.10.0-229.el7.x86_64
- Linux Cross Referenceで示すコードは参考までにこのバージョンでないものも示す。
- vmlinux
- カーネルのデバッグ情報(シンボル)が含まれているカーネル。カーネルコンフィグでチェックするか、kernel-debuginfo install kernel-xxxxでバージョン指定して任意のvmllinuxをインストールする。ブートローダーがメモリにロード(解凍したやつ)するvmlinuzはデバッグ情報が含まれていない。
- GDB(gdb-7.6.1-64.el7.x86_64)
- QEMUを使用して64bit版のカーネルをデバッグする場合、CPUを32bitから64bitに移行する箇所でQEMUとGDBの間で不具合がるよう。GDBにパッチをあてる解決が簡単らいいのでパッチをあてる必要がる。パッチのdiff。このdiffの内容がパッチの内容でpatchコマンドでパッチを適用する。
- GDBの最新を自分でビルドして入れるならシステムにncurses-develがないとtuiモードが使えずlayoutコマンドが動作しない。
環境構築
- ホストOS上でデバッグしたいOSを含む仮想マシンを作成(qemu-img、qemu-kvm)
$ qemu-img create -f raw xxx.img 4G
$ qemu-kvm -k ja -m 1024 -localtime -hda xxx.img -net nic,model=e1000 -net user -cdrom xxx.iso -boot d
- 仮想マシンの起動はqemu-system-xxxコマンドを使う。実行するとに色々オプションを指定。-SはGDBが接続するまでOSの起動?を待ってくれるオプション。
$ qemu-system-x86_64 -S -s -snapshot -k ja -m 1024 -localtime -hda xxx.img -net nic,model=e1000 -net user -monitor stdio
- ホストOSからGDBを使ってQEMU上で動作するCentOS7のカーネルに対してリモートアクセスしてカーネル動作をデバッグ
$ gdb vmlinxへのパス
その他:もしゲストOS上と異るバージョンのカーネルをデバッグしたい場合は、カーネルがそのバージョンの仮想マシンを作るか、ホストOS上でカーネルコンパイルして既存の仮想マシンに任意のカーネルバージョンをインストールすればよいみたい(試してない)。
start_kernel表示
アプリケーションをデバッグする場合
- gdb 実行ファイル
カーネルをデバッグする場合
- gdb vmlinux
- (gdb) target remote localhot:1234
- (gdb) b start_kernel
- (gdb) c
- (gdb) layout src
わー、バックトレースやレジスタの中身が分るのねー!スタックの中身もみれるのかな??素敵!