2015/05/23

64bit 版 xv6 を gdb で追う

前回 にも xv6 を読もう、ということで Mac に環境を構築したのですが、 swetland さんによる 64bit 版の xv6 があるみたいで、そっちも読めるようにしたログ。


環境
  • Host
    • Mac OSX Yosemite 10.10.3
    • Vagrant 1.7.2
    • VirtualBox 4.3.26
  • Guest
    • Ubuntu 14.04 on vagrant (chef/ubuntu-14.04)
    • qemu 1.7.91
    • gcc 4.8.2
    • gdb-multiarch 7.7


ブートの流れと gdb で素直に追えない理由

64bit 版の boot loader は memory space を 16 -> 32 -> 64 と拡張しながら起動していくみたいです
切り替えの際に命令セットが変わるので、 16bit(i8086) で attach していた gdb で b main して continute しても main で止まらなかったり、アーキテクチャの設定を間違えると gdb が文句を言ったりします。
この問題は swetland さんの xv6 の README.64bit にも書かれていて、
* gdb pukes when qemu switches from 32bit to 64bit mode
  * this made debugging the mode change entertaining
  * for now attach gdb after the switch
とのこと。
要は切り替えると gdb がダメになるので、切り替えた後に attach しなよ、と。
この切り替えポイントと gdb の attach をどうするか格闘したログ


16bit -> 32bit

boot 部分はアセンブラで直書きされているのでその辺りを読む。

out/bootblock.asm にある
ff 53 1c                call   *0x1c(%ebx)
でどうやら 16bit -> 32bit している様子。
なのでこの命令がある 0x7dc1 に break を置く。
ここは起動直後の gdb での continue で止まる。
stepi すると 0x00100020 に飛ぶ。

ちなみに 0x00100020  は mboot_entry ってやつで、ページテーブルの初期化とかしてるみたいです。
これで 32bit になったので 64bit に飛ぶところを探す。


32bit -> 64bit

メモリが32bitになったので 0x1000a4 とかが指定できる。
64bit mode にしてる部分は out/kernel.asm の
# shift to 64bit segment
 ljmp $8,$(entry64low - mboot_header + mboot_load_addr)
のところみたいです。
私の環境のアドレスだと 0x1000a4 。
ここから stepi すると
Remote 'g' packet reply is too long: 000200000000000000000.....
と言われて gdb で操作できなくなる。
直前に set architecture i386:x86-64 とかしてもダメ。
ということで、 16 -> 32 した gdb はそのままで新しい gdb を上げる。
新しい gdb で symbol-file と set arch してから target remote すると gdb を待つ状態になるので、古い gdb で continue してエラーが出てから quit 。
古い gdb は落ちて新しいの 64bit で繋がるので、これで b main とかが効くようになります。


Ubuntu 14.04 に環境を作る

  • sudo apt-get install -y gcc git qemu gdb-multiarch vim zsh
  • git clone https://github.com/swetland/xv6.git xv6-64bit
とか。
Makefile の QEMU を qemu-system-x86_64 にして、64bit build の時は X64 って環境変数を作る。
gdb で debug する時は tool/gdbinit.tmpl の symbol-file kernel を symbol-file/kernel.elf にする。
あとは
  • make 
  • make qemu-nox-gdb
してから gdb-multiarch でいけます。
最初の gdb-multiarch の .gdbinit は
echo + target remote localhost:25900\ntarget remote localhost:25900
echo + symbol-file out/kernel.elf\nsymbol-file out/kernel.elf
break *0x7dc1continuestepibreak *0x1000a4
echo + please attach another gdb.\n
とか。32bit mode での最後の ljmp までは2つめの gdb-multiarch でいけます。
2つ目の gdb-multiarch の .gdbinit は
set architecture i386:x86-64:intel
echo + target remote localhost:25900\ntarget remote localhost:25900
echo + symbol-file out/kernel.elf\nsymbol-file out/kernel.elf

とか。 2つ目を接続してから1つ目を continue すると良い。

xv6 を fork してみる

結局やることは
  • .gdbinit の書き換え
  • 16 -> 32 bit 版 gdb 用 .gdbinit
  • 32 -> 64 bit 版 gdb 用 .gdbinit
  • QEMU の設定
  • X64 を設定
とか沢山あったので、 fork してみました
3つ shell を上げて
  • (1) make
  • (1) make qemu-nox-gdb
  • (2) gdb-multiarch -x .gdbinit64 
    • please attach another gdb と出たら
  • (3) gdb-multiarch -x .gdbinit64-2
  • (2) continue
  • (2) exit
    • すると (3) の gdb が繋がるので
  • (3) b main
  • (3) continue
    • とかができます。
(3) の gdb の attach 時に 'Bogus trace status reply from target: PacketSize=1000' と出る場合もありますが、もう一度  $ gdb-multiarch -x .gdbinit64-2 すると繋がります。

メモリがきちんと64bitになっていればok。
The target architecture is assumed to be i386:x86-64:intel+ target remote localhost:259000x00000000001000e0 in ?? ()+ symbol-file out/kernel.elf(gdb) 
とかですね。
あとは main から読むなりなんなりできます。



コマンドまとめ

vagrant 上の Ubuntu 14.04 にて 3 つ shell を上げます。それぞれが(1), (2), (3) です。

(1) $ sudo apt-get install -y gcc git qemu gdb-multiarch vim zsh
(1) $ git clone https://github.com/atton-/xv6.git xv6-64bit
(1,2,3) $ cd xv6-64bit
(1) $ make
(1) $ make qemu-nox-gdb
(2) $ gdb-multiarch -x .gdbinit64
    please attach と出たら
(3) $ gdb-multiarch -x .gdbinit64-2
(2) $ continue
    して Remote 'g' packet reply is too long: 000200000000000000000.....
    と言われると思うので(2) の gdb を落とす
(3) $ b main
(3) $ continue
    main で止まります。
(3) の attach に失敗したら (3) をもう一度  gdb-multiarch -x .gdbinit64-2  で上げると良いはずです。

1 件のコメント:

  1. Thanks for your sharing! I merged your GDB work to my Xv6 source tree: https://github.com/jserv/xv6-x86_64 .

    返信削除