- GUIでLinuxカーネルをデバッグ実行するにはどうすればいいのだろう?
今回はLinuxカーネルをGUIデバッグする手順について解説します。
注意事項
- Ubunt 14.04.5 LTS、Linux kernel version4.5で構築する場合を例とします。
- ホストOSはWindows10 64bit版を前提とします。
目次
用意するもの
用意するものは以下の通りです。
LinuxカーネルをGUIデバッグする手順
LinuxカーネルをGUIデバッグする手順は次の通りです。
- CygwinをホストOSにインストール
- VMWareをホストOSにインストール
- UbuntuインストールイメージでVMWare仮想環境を作成
- Linuxカーネルの最適化オプションを外す
- LinuxカーネルをUbuntu上でビルド
- ビルド時のソースコードをホストOSの任意の場所に格納
- DS5をホストOSにインストール
- DS5のデバッグ用プロジェクト作成
- DS5のプロジェクトを実行してアタッチ
- カーネルモジュールもデバッグできるようにする
順番に見ていきましょう。
①CygwinをホストOSにインストール
DS5のプロジェクトからCygwinのgdbを起動し、VMWareで起動しているLinuxにアタッチするためにCygwinが必要です。
ホストOSにCygwinをインストールするため、<https://www.cygwin.com/>からsetup-x86_64.exeをダウンロードして実行します。
「Install form Internet」を選択します。
Cygwinのインストールフォルダを指定します。
インストール用一時ファイルの作成場所を指定します。
「Direct Connection」を選択します。
Cygwinパッケージ取得元のサーバーを指定します。
特にどのサーバーでもいいみたいですが、サーバーごとにインストール速度が変わるようです。
インストールするパッケージを選択します。
gdbが含まれている「Devel」を"Default"→"Install"に変更します。
それ以外は"Default"のままでよいです。
パッケージのインストールが完了するまで待ちます。
パッケージのインストールが完了すれば以下の画面が表示されます。
最後に、ホストOSの環境変数にCygwinのパスを追加します。
②VMWareをホストOSにインストール
以下のサイトで「VMware Workstation Player」をダウンロードし、ホストOSにインストールします。
<https://www.vmware.com/jp/products/workstation-player.html>
③UbuntuインストールイメージでVMWare仮想環境を作成
以下の手順に基づき、UbuntuインストールイメージでVMWare仮想環境を作成します。
Ubuntuインストールイメージをダウンロード
以下のサイトで「日本語版 Ubuntuインストールイメージ(iso)」をダウンロードします。
<https://www.ubuntulinux.jp/products/JA-Localized/download>
Ubuntuをインストール
VMWareを起動し、「新しい仮想マシンの作成」を選択します。
そして、「インストーラ ディスク イメージ ファイル」でダウンロードしたUbuntuインストールイメージを選択します。
仮想マシン設定
メモリは1GB以上、ハードディスクは30GB以上に設定していれば問題ないでしょう。
プロセッサは、以下のように「プロセッサ コアの数:1」に設定します。
プロセッサ コアの数を2以上にしてしまうと、ステップ実行した時、別のプロセッサで動いているプロセスの実行箇所にいきなり飛んだりしてしまいます。
④Linuxカーネルの最適化オプションを外す
「linux-4.5.tar.gz」などで検索し、Linuxカーネルソースコード一式をダウンロードしましょう。
例えば、以下のミラーサイトにlinux-4.5.tar.gzが格納されています。
<http://ftp.riken.jp/Linux/kernel.org/linux/kernel/v4.x/linux-4.5.tar.gz>
linux-4.5.tar.gzを解凍するため、仮想環境(Ubuntu OS)を起動してログインし、/usr/srcの直下にlinux-4.5.tar.gzを格納します。
そして、ターミナルを開きます。
まず、スーパーユーザーでログインします。
sudo su
linux-4.5.tar.gzを解凍します。
cd /usr/src
tar -xvzf linux-4.5.tar.gz
そして、以下のコマンドを実施し、Makefileに定義されている最適化オプションを外します。
cd linux-4.5
find ./ -type f -name Makefile|xargs -n 1 sed -i.bak -e "s/-g -O2/-g3 -O0/g"
なお、最適化オプションを外した状態でLinuxカーネルをビルドすると、コンパイルエラーが出る場合があります。
最適化オプションを外したことが原因である可能性が高いので、コンパイルエラーが出た箇所だけ最適化オプションを追加して再ビルドしましょう。
たとえば、コンパイルエラー箇所の先頭と末尾に以下のコードを追加します。
/* add O1 option start */
#pragma GCC push_options
#pragma GCC optimize ("O1")
// コンパイルエラーが出た関数、またはファイル全体を囲む。
#pragma GCC pop_options
/* add O1 option end */
⑤LinuxカーネルをUbuntu上でビルド
Linuxのビルドに必要となるパッケージをインストールします。
apt-get install -y build-essential kernel-package libssl-dev ncurses-dev libncurses-dev fakeroot dpkg-dev
現在のLinuxカーネルと同じバージョンでビルドする場合、以下のコマンドを実行して設定ファイルを現在の設定で上書きします。
cp -vi /boot/config-`uname -r` .config
カーネルの設定を変えたい場合は、以下のコマンドを実行して設定を変更します。
※詳細は「https://www.itmedia.co.jp/help/tips/linux/l0347.html」を参照。
make menuconfig
Linuxカーネルをビルドします。
(環境によってはかなり時間がかかります)
time fakeroot make-kpkg --initrd kernel-image kernel-headers
Linuxカーネルのビルドが完了したら、以下のコマンドを実行して次回起動時にビルドしたLinuxカーネルが動作するようにします。
cd ../
dpkg -i linux-headers-4.5.0_4.5.0-10.00.Custom_i386.deb
dpkg -i linux-image-4.5.0_4.5.0-10.00.Custom_i386.deb
Linuxを再起動します。
reboot
Linuxの再起動後、「uname」コマンドを実行してビルドしたLinuxで動作しているかを確認します。
実行例
root@ubuntu:~# uname -a
Linux ubuntu 4.5.0 #21 SMP Mon Feb 19 02:07:45 AEDT 2018 i686 i686 i686 GNU/Linux
⑥ビルド時のソースコードをホストOSの任意の場所に格納
ビルド時のLinuxカーネルのソースコードを、ビルドしてできたvmlinuxファイルと一緒にホストOSの任意の場所に格納します。
もし、フォルダのサイズが10GB以上など大きすぎる場合は、以下のコマンドで一時ファイルの「.oファイル」を削除しておきましょう。
find /usr/src/linux-4.5 -type f|grep ".*\.o$" |xargs -I {} rm -f {}
⑦DS5をホストOSにインストール
ARM Development Studio 5 (DS- 5) Community Edition(CE)をダウンロードし、ホストOSにインストールします。
<https://developer.arm.com/tools-and-software/embedded/legacy-tools/ds-5-development-studio/downloads>
ライセンス(無料)の設定
(設定しなくても問題ないかもしれませんが)ライセンス(無料)の設定手順を解説します。
まず、以下にアクセスし、画面右側に表示されている「Activation Code」を控えておきます。
次に、DS5を起動し、「ヘルプ」→「ARM License Manager」を選択します。
ARM License Manager画面が表示されるので、「ライセンスの追加」を選択します。
ライセンスタイプは「ライセンスファイル、ライセンスサーバ、シリアル番号、またはアクティブ化コードの使用」を選択します。
アクティブ化コードを指定します。
ネットワークインターフェースを選択します。
開発者のアカウント情報を設定して「終了」を選択すると、ライセンスが生成されます。
アカウントがない場合は、下図の「アカウントがない場合は、ここをクリックして作成してください。」のリンクから無料で作成できます。
ライセンスの生成が完了すると、下図のようにライセンスが登録された状態になります。
⑧DS5のデバッグ用プロジェクト作成
DS5で「実行」→「デバッグの構成」を選択します。
以下のデバッグ構成画面が表示されますので、「C/C++ リモート・アプリケーション」をダブルクリックして新規構成を作成します。
作成した新規構成の「メインタブ」→「C/C++ アプリケーション:」に、Linuxカーネルのビルドにより作成された「vmlinux」への絶対パスを設定します。
「デバッガータブ」→「メインタブ」に遷移し、以下を設定します。
- GDBデバッガー:gdb
- GDBコマンド・ファイル:.gdbinit
「デバッガータブ」→「接続タブ」に遷移し、以下を設定します。
- ホスト名またはIPアドレス:localhost
- ポート番号:後述
ポート番号には、仮想マシン(vmxファイル)の起動時、仮想マシンと同じ階層に出力される「vmware.log」の「VMWare Player is listening for debug connection on port <ポート番号>」の値(下図の赤文字)を設定します。
⑨DS5のプロジェクトを実行してアタッチ
仮想マシンを起動し、仮想環境上でUbuntu OSが起動した状態にしておきます。
DS5のプロジェクトを実行するために、「実行」→「デバッグの構成」→「<作成したデバッグ構成名称>」→「デバッグ」を選択すれば、仮想環境上のUbunt OS(Linuxカーネル部分)にアタッチします。
2回目以降は、下図のように「実行」→「デバッグ履歴」→「<作成したデバッグ構成名称>」を選択すればよいです。
ただ、初めはソースファイルのパスを登録していない状態のため、アタッチしても「ソースが見つかりませんでした」という警告が表示されるはずです。
ソースファイルをデバッグ構成に追加するため、「ソース・ルックアップ・パスの編集」を選択します。
「追加」を選択します。
「パス・マッピング」を選択します。
「追加」を選択し、「コンパイル・パス:」にビルド時のソースファイル格納フォルダパス、「ローカル・ファイル・システム・パス:」にホストOSにコピーしたソースファイル格納フォルダパスを指定します。
ブレークポイントを設定したい場合は、ブレークしたい行の行番号左側を右クリックし、「ブレークポイント型」を「C/C++ ブレークポイント」に設定しておきます。
その後、デバッグを一時停止した状態で任意の場所にブレークポイントを貼れば、デバッグ再開後、その処理が実行されたタイミングでブレークします。
DS5では、ステップ実行時に以下の情報を確認できます。
- レジスタ
- 変数
- メモリ
- コールスタック
- 逆アセンブル
ステップ実行をしていくと、以下の「レジスタ」「変数」表示のように、変更された設定値がピンク背景になります。
また、下図右下のように、メモリの現在設定値を表示できます。
下図では、スタックポインタ($esp)の位置のメモリ設定値を表示しています。
なお、下図赤枠の「命令ステップ・モード」を選択状態にすると、C言語の命令単位ではなく、アセンブラ言語の命令単位でステップ実行できます。
⑩カーネルモジュールもステップ実行できるようにする
カーネルモジュール(koファイル)もステップ実行できるようにしたい場合は以下の設定を行います。
まず、DS5でデバッグ中のプロジェクトを一時停止します。
そして、DS5のデバッグコンソールで以下のコマンドを実行します。
add-symbol-file <ホストOS上のkoファイルの絶対パス> <ロードされたkoモジュールの番地(0x・・・)>
koモジュールの番地には、下図の例のように「/proc/modules」に定義されているkoモジュールに紐づく値(仮想アドレス空間にロードされたkoモジュールの番地)を設定します。
もし、ステップ実行したいkoモジュールが複数ある場合、以下の手順でもよいです。
- 「.gdbinit」ファイルにkoモジュールのシンボル読み込み処理を記述する。
- DS5のbinフォルダ(下図参照)の下に「.gdbinit」ファイルを格納する。
- DS5でデバッグ用プロジェクトを実行する。
ただし、仮想アドレス空間にロードされるkoモジュールの番地は、Linuxを再起動するたびに変化してしまいます。
このため、「.gdbinit」ファイルの中身を自動で作成するツールを自作し、Linuxの起動時に「.gdbinit」ファイルを作成する仕組みを入れておく方がよいです。
例えば、「/etc/rc.local」に自作したツールの起動処理を追記すれば、起動時に「.gdbinit」ファイルが作成できます。
まとめ
LinuxカーネルをGUIデバッグする手順について解説しました。
一度GUIのデバッグ環境を作ってしまえばLinuxカーネルのデバッグが楽になります。
LinuxカーネルをデバッグしながらOSがどのように動いているかを理解していきましょう。