Ubuntu 16.04: FuchsiaをQEMUで動かす

FuchsiaをビルドしてQEMUのGDB-stubでデバッグします。2016年8月現在、arm32はspin_lockでデッドロックしてるようで、途中で止まります。

1 QEMUで動かす

magenta/docs/getting_started.mdに記載されています。

1.1 ダウンロード

Fuchsiaをダウンロードします。

$ git clone https://fuchsia.googlesource.com/magenta

1.2 ビルドに必要なパッケージ

Fuchsiaのビルドに必要なパッケージをインストールします。

$ sudo apt install -y texinfo libglib2.0-dev autoconf libtool \
libsdl-dev build-essential

1.3 クロスツールチェイン

クロスツールチェインをダウンロードします。

$ ./scripts/download-toolchain

prebuilt/downloadsに配置されます。

$ ls prebuilt/downloads/
aarch64-elf-5.3.0-Linux-x86_64    arm-eabi-Linux-x86_64.tar.bz2
aarch64-elf-Linux-x86_64.stamp    x86_64-elf-5.3.0-Linux-x86_64
aarch64-elf-Linux-x86_64.tar.bz2  x86_64-elf-Linux-x86_64.stamp
arm-eabi-5.3.0-Linux-x86_64       x86_64-elf-Linux-x86_64.tar.bz2

このツールチェインに含まれるGDBはlayoutコマンドが無効となっているので、GDB用にツールチェインをビルドします。2時間ほどかかります。

$ sudo apt build-dep -y gcc gdb
$ git clone https://fuchsia.googlesource.com/third_party/gcc_none_toolchains
$ cd gcc_none_toolchains
$ ./doit -a 'arm aarch64 x86_64' -f
$ cd ..

1.4 ビルド

ターゲットとなるボードをmakeで指定します。数分で完了します。

$ make <target>

build-<target>に作成されます。

build-<target>

この記事ではmagenta-pc-x86-64を指定します。

$ make magenta-pc-x86-64

<target>の一覧は以下のとおりです。<target>を省略した場合はmagenta-pc-x86-64となります。

$ make list
List of all buildable projects: (look in project/ directory)
qemu-virt-a53-test
rpi3-test
magenta-pc-x86-64
pc-x86-64-test
magenta-qemu-arm32
pc-x86-test
qemu-virt-a15-test
magenta-qemu-arm64

1.5 QEMU

aptでインストールしても良いのですが、Fuchsiaのリポジトリで用意しているQEMUは若干パッチを当てているようなのでビルドしてインストールします。

$ sudo apt build-dep -y qemu
$ git clone https://fuchsia.googlesource.com/third_party/qemu
$ mkdir qemu.build
$ cd qemu.build
$ ../qemu/configure --target-list=arm-softmmu,aarch64-softmmu,x86_64-softmmu
$ make && sudo make install

QEMUを起動します。

$ ./scripts/run-magenta-x86-64

使用できる引数は以下のとおりです。

$ ./scripts/run-magenta-x86-64 -h
help:
-a <arch>           : arm32, arm64, or x86-64
-b                  : build first
-c                  : add item to kernel commandline
-d                  : run with emulated disk
-g                  : use graphical console
-k                  : use KVM
-m <memory in MB>   : default 512MB
-n                  : run with emulated nic
-N                  : run with emulated nic via tun/tap
-o <dir>            : build directory
-r                  : run release build
-u                  : use uniprocessor
-v                  : use vnc based display
-x <bootfs>         : add eXtra bootfs
-h for help
all arguments after -- are passed to qemu directly

2 GDB-stubでデバッグする

GDBでカーネルとuappのコードを追跡できるようにします。

2.1 QEMU

qemu-system-xxxコマンドを直接実行しても良いのですが、以下の様にスクリプトを変更します。

diff --git a/scripts/run-magenta b/scripts/run-magenta
index 555c64d..e1102ae 100755
--- a/scripts/run-magenta
+++ b/scripts/run-magenta
@@ -22,6 +22,7 @@ function HELP {
     echo "-u                  : use uniprocessor"
     echo "-v                  : use vnc based display"
     echo "-x <bootfs>         : add eXtra bootfs"
+    echo "-G <port>           : gdb port"
     echo "-h for help"
     echo "all arguments after -- are passed to qemu directly"
     exit 1
@@ -43,8 +44,9 @@ RELEASE=0
 VNC=0
 INITRD=
 CMDLINE=""
+GDBPORT=""

-while getopts a:Abc:dgkm:nNo:ruvx:h FLAG; do
+while getopts a:Abc:dgkm:nNo:ruvx:G:h FLAG; do
     case $FLAG in
         a) ARCH=$OPTARG;;
         A) AUDIO=1;;
@@ -61,6 +63,7 @@ while getopts a:Abc:dgkm:nNo:ruvx:h FLAG; do
         u) UP=1;;
         v) VNC=1;;
         x) INITRD=$OPTARG;;
+        G) GDBPORT=$OPTARG;;
         h) HELP;;
         \?)
             echo unrecognized option
@@ -189,6 +192,11 @@ if [ "$INITRD" != "" ]; then
     ARGS+=" -initrd $INITRD"
 fi

+# gdb port
+if [ "$GDBPORT" != "" ]; then
+    ARGS+=" -gdb $GDBPORT -S"
+fi
+
 # run qemu
 echo $QEMU $ARGS -append "$CMDLINE" $@
 $QEMU $ARGS -append "$CMDLINE" $@

QEMUを起動します。

$ ./scripts/run-magenta-x86-64 -G tcp::10000

2.2 GDB

x86_64-elf-5.3.0-Linux-x86_64/bin/x86_64-elf-gdbだと以下のエラーが出てしまいます。

Remote 'g' packet reply is too long: 000000000...

Ubuntu 16.04のgdb64ならば出ないのでそちらを使います。

$ sudo apt install -y gdb64

以下のスクリプトを用います。

$ cat gdb.x
symbol-file build-magenta-pc-x86-64/magenta.elf
set architecture i386:x86-64
target remote localhost:10000
b lk_main
la src
c

GDBを起動します。

$ gdb64 -x gdb.x

scripts/run-magenta-arm64の場合は、先ほどビルドしたgcc_none_toolchains/aarch64-elf-5.3.0-Linux-x86_64/bin/aarch64-elf-gdbを使います。scripts/run-magenta-arm32も同様です。

2.3 実行結果

アーキテクチャ固有のアセンブラが実行された後、共通部分のlk_main関数が実行されます。

kernel/arch/xxx/xxx/start.S -> lk_main at kernel/top/main.c

以下のようにlk_mainでbreakしています。

0001_break-lk_main.png

2.4 GDB-stubでuserbootをデバッグする

userbootはカーネルからユーザアプリケーションへ制御を切り替えるプログラムです。Linuxのinitに近いものです。

bootstrap2 (kernel) -> userboot_init (kernel) -> userboot (uapp) -> ... -> bin/mxsh (uapp)

userboot (uapp)がロードされるアドレスはログ出力されます。

[00001.069] K userboot: userboot-code    0x2000 @ [0x1002000,0x1004000)

add-symbol-fileでuserboot (uapp)をロードします。

$ cat gdb.x
symbol-file build-magenta-pc-x86-64/magenta.elf
set architecture i386:x86-64
target remote localhost:10000
add-symbol-file build-magenta-pc-x86-64/uapp/userboot/libuserboot.so 0x1002000
b _start
la src
c

先ほどと同様にQEMUとGDBを起動すると、以下のようにuserboot (uapp)の_start関数でbreakされました。

0002_break-userboot.png

bin/devmgr (uapp)もロードアドレスが割り出せれば追跡可能だと思います(割り出せてないので未確認)。