2010年03月03日
QEMUにデバッガをつなぐ
今回はQEMUにデバッガをつなぐ話をします。
- QEMUそのものをgdbで追いかける
- QEMU上の仮想マシンにgdbをつなぐ
- QEMUそのものとその上の仮想マシンを同時に2つのgdbで追いかける
QEMUそのものをgdbで追いかける
インストールされたqemu-system-armはシンボル情報が削除されています。(stripped)
$ file /usr/bin/qemu-system-arm /usr/bin/qemu-system-arm: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped
なので、QEMUをソースからビルドして、arm-softmmu ディレクトリにあるqemu-system-armを使います。
$ file obj/arm-softmmu/qemu-system-arm obj/arm-softmmu/qemu-system-arm: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
gdbのインストール
Debian/Ubuntuの場合はapt-getで簡単にインストールできます。
$ sudo apt-get install gdb
Windowsの場合はMinGWのダウンロードサイトの GNU Source-Level Debugger のところから gdb-7.0.1-mingw32-bin.tar.gz をダウンロードしてきてc:\MinGW\の下に展開します。
gdbの起動
通常のQEMUの起動方法で頭に "gdb --args " をつけると楽です。
$ gdb --args qemu-system-arm -M versatilepb -m 256 \ -kernel arch/arm/boot/zImage \ -redir tcp:55555::22 \ -append "root=/dev/nfs rw nfsroot=192.168.xx.xx:/export/debian_lenny_armel/root ip=dhcp "
gdbのプロンプトがでたら r または run と打ち込めばqemuが走り始めます。
コントロールCで強制停止します。
Linuxの場合だと頻繁にSIGUSR1のsignalで止まってしまうので、SIGUSR1を無視するようにカレントディレクトリの.gdbinitに以下を書いておくとよいです。
$ cat .gdbinit handle SIGUSR1 nostop handle SIGUSR1 noprint
(2012.1.16追記)
久しぶりにqemu-1.0で試すと、SIGUSR1でなくSIG38のシグナルが頻繁に入るようになっていました。そこで、.gdbinitは以下のようにしました。
$ cat .gdbinit handle SIG38 nostop handle SIG38 noprint
(2012.1.16追記ここまで。)
Windowsではgdbの起動をシェルスクリプトにしているとコントロールCで、そのシェルスクリプト自体が終了してしまうということが起こりました。コマンドプロンプトから直接gdbを起動するか、またはバッチファイルからgdbを起動するようにすれば、コントロールCでターゲットプログラムを強制停止させることができます。
QEMU上の仮想マシンにgdbをつなぐ
クロス開発でよく使うgdbserverの機能はqemu-system-armに内包されています。クロスのgdb (ARM用ならarm-eabi-gdb)はバイナリパッケージでは用意されていないのでソースからビルドします。
ARM用のクロスgdbのビルド
http://www.gnu.org/software/gdb/
からソースアーカイブをダウンロード。
Linuxでのビルド
$ tar xvf gdb-7.0.1.tar.bz2 $ mkdir obj $ cd obj $ ../gdb-7.0.1/configure --target=arm-eabi $ make $ sudo make install
--prefixを省略すると/usr/localにインストールされます。
WindowsのMSYS環境でのビルド
$ tar xvjf gdb-7.0.1.tar.bz2 $ mkdir obj $ cd obj $ ../gdb-7.0.1/configure --target=arm-eabi --prefix=/mingw $ make $ make install
QEMUの起動
gdbと接続するために -S -gdb tcp::1234 のオプションを追加します。1234はgdbとの通信に使うポート番号です。
(qemu-0.10.xの頃は -S -s -p 1234 でしたが変更されました。)
$ qemu-system-arm \ -S -gdb tcp::1234 \ -M versatilepb -m 256 -kernel arch/arm/boot/zImage \ -redir tcp:55555::22 \ -append "root=/dev/nfs rw nfsroot=192.168.xx.xx:/export/debian_lenny_armel/root ip=dhcp "
起動するとすぐにgdbの接続待ちになります。(-S を省略すると待たずに続行します。)
クロスgdbの起動
$ arm-eabi-gdb vmlinux
vmlinuxはデバッグオプション(-g)をつけてビルドしておく必要があります。
(gdb) target remote localhost:1234 (gdb) c
target remoteでqemuの動いているホストのIPアドレスと先ほどのポート番号を指定します。(arm-eabi-gdbとqemu-system-armが別々のマシンで動いていてもかまいません。)
その後、r(run)でなくてc(continue)でターゲットプログラムを続行します。
QEMUそのものとその上の仮想マシンを同時に2つのgdbで追いかける
上の2つはもちろん重ねて使うことができます。
$ gdb --args qemu-system-arm \ -S -gdb tcp::1234 \ -M versatilepb -m 256 -kernel arch/arm/boot/zImage \ -redir tcp:55555::22 \ -append "root=/dev/nfs rw nfsroot=192.168.xx.xx:/export/debian_lenny_armel/root ip=dhcp "
.
.
One more thing ...
カタログには載せていませんがQEMUにつながるPARTNERは存在します。
(クリックで拡大表示)
AndroidのエミュレータにPARTNERをつなげてdo_execveでブレークしたところ。PARTNERはWindows7で、AndroidエミュレータはUbuntuで動いています。