みつきんのメモ

組み込みエンジニアです。Interface誌で「My オリジナルLinuxの作り方」連載中

Yocto Zephyrのアプリケーションをqemu + gdbでデバッグ

はじめに

Yocto ProjectでビルドしたZephyrのアプリケーション(elf)をqemugdbデバッグしてみる。

環境

下記で作成した環境をベースに作業する

gdb-multiarch

使用するgdbUbuntu 20.04でaptで導入可能なgdb-multiarch

$ sudo apt install gdb-multiarch

runqemuについて

bitbakeでZephyrアプリケーションをビルドすると、下記のコマンドでqemuを使用してアプリケーションを実行することができる。

$ runqemu

bitbake同様に下記を実行して環境変数を設定しておく必要がある。

$ source poky/oe-init-build-env build

runqemuqemuを実行するためのラッパスクリプトで、実行するelfのパスや環境変数、必要なオプションなどを自動的にqemuに渡してくれるようになっている。

下記のようにすると追加で任意にパラメータをqemuに渡すことができる。

$ runqemu qemuparams='-serial mon:stdio'

runqemuの詳しい使い方は下記のように調べることができる。

$ runqemu --help

Usage: you can run this script with any valid combination
of the following environment variables (in any order):
  KERNEL - the kernel image file to use
  BIOS - the bios image file to use
  ROOTFS - the rootfs image file or nfsroot directory to use
  DEVICE_TREE - the device tree blob to use
  MACHINE - the machine name (optional, autodetected from KERNEL filename if unspecified)
  Simplified QEMU command-line options can be passed with:
    nographic - disable video console
    novga - Disable VGA emulation completely
    sdl - choose the SDL UI frontend
    gtk - choose the Gtk UI frontend
    gl - enable virgl-based GL acceleration (also needs gtk or sdl options)
    gl-es - enable virgl-based GL acceleration, using OpenGL ES (also needs gtk or sdl options)
    egl-headless - enable headless EGL output; use vnc (via publicvnc option) or spice to see it
    serial - enable a serial console on /dev/ttyS0
    serialstdio - enable a serial console on the console (regardless of graphics mode)
    slirp - enable user networking, no root privileges is required
    snapshot - don't write changes to back to images
    kvm - enable KVM when running x86/x86_64 (VT-capable CPU required)
    kvm-vhost - enable KVM with vhost when running x86/x86_64 (VT-capable CPU required)
    publicvnc - enable a VNC server open to all hosts
    audio - enable audio
    [*/]ovmf* - OVMF firmware file or base name for booting with UEFI
  tcpserial=<port> - specify tcp serial port number
  qemuparams=<xyz> - specify custom parameters to QEMU
  bootparams=<xyz> - specify custom kernel parameters during boot
  help, -h, --help: print this text
  -d, --debug: Enable debug output
  -q, --quiet: Hide most output except error messages

Examples:
  runqemu
  runqemu qemuarm
  runqemu tmp/deploy/images/qemuarm
  runqemu tmp/deploy/images/qemux86/<qemuboot.conf>
  runqemu qemux86-64 core-image-sato ext4
  runqemu qemux86-64 wic-image-minimal wic
  runqemu path/to/bzImage-qemux86.bin path/to/nfsrootdir/ serial
  runqemu qemux86 iso/hddimg/wic.vmdk/wic.vhd/wic.vhdx/wic.qcow2/wic.vdi/ramfs/cpio.gz...
  runqemu qemux86 qemuparams="-m 256"
  runqemu qemux86 bootparams="psplash=false"
  runqemu path/to/<image>-<machine>.wic
  runqemu path/to/<image>-<machine>.wic.vmdk
  runqemu path/to/<image>-<machine>.wic.vhdx
  runqemu path/to/<image>-<machine>.wic.vhd

qemugdb serverとして実行する

qemuqemu上で実行中のelfをデバッグするために、gdb serverのプロトコル喋れるようになっている。 (厳密には多分いろいろ違うと思うけど、とりあえず。)

runqemuに下記のオプションをつけて実行すると、elfの先頭でブレーク状態に、localhostの1234ポートで接続できるようになる。

$ runqemu qemuparams="-S -s"
runqemu - INFO - Running bitbake -e ...
runqemu - INFO - Continuing with the following parameters:
KERNEL: [/home/mickey/work/yocto/x86-hardknott/mb-hardknott/build/tmp/deploy/images/microbit-v1/my-app.elf]
MACHINE: [microbit-v1]
FSTYPE: [elf]
ROOTFS: [/home/mickey/work/yocto/x86-hardknott/mb-hardknott/build/tmp/deploy/images/microbit-v1/my-app-image-microbit-v1.elf]
CONFFILE: [/home/mickey/work/yocto/x86-hardknott/mb-hardknott/build/tmp/deploy/images/microbit-v1/my-app-image-microbit-v1.qemuboot.conf]

runqemu - INFO - Running /home/mickey/work/yocto/x86-hardknott/mb-hardknott/build/tmp/work/x86_64-linux/qemu-helper-native/1.0-r1/recipe-sysroot-native/usr/bin/qemu-system-arm    -nographic -vga none  -machine microbit -cpu cortex-m0 -m 256  -s -S -serial mon:vc -serial null  -kernel /home/mickey/work/yocto/x86-hardknott/mb-hardknott/build/tmp/deploy/images/microbit-v1/my-app.elf -append '  mem=256M  '

この状態で、別の端末を開き下記のように実行する

$ cd tmp/deploy/images/microbit-v1/
$ gdb-multiarch my-app.elf

するとgdbのプロンプトが表示されるので下記のように入力する。

(gdb) target remote :1234

これでqemuに接続される。

下記のようにしてmain関数にブレークを貼る。

(gdb) b main

実行してみる。

(gdb) c
Continuing.

Breakpoint 1, main ()
    at /home/mickey/work/yocto/x86-hardknott/mb-hardknott/build/tmp/work/cortexm0-poky-eabi/my-app/2.5.0+gitAUTOINC+fe7c2efca8_c3bd2094f9-r0/my-app/src/main.c:10
10      printk("Hello My Application World! %s\n", CONFIG_BOARD);

きちんとmain関数でブレークすることが確認できた。

まとめ

YoctoでビルドしたZephyrアプリケーションのelfをqemu + gdbデバッグできることを確認した。

meta-armでmicrobit-v1のマシン定義をした人が丁寧にqemu対応のための設定も作り込んでくれているため、 micro:bit向けのelfをqemu向けにリビルドすることなくqemu + gdbデバッグができるようになっている。

BSP次第だが、Yoctoではこういうこともできるのがおもしろい。

(おまけ) micro:bitのrunqemuのための設定

meta-arm/conf/machine/microbit-v1.confの下記の部分。

runqemuで呼び出されるqemu-systemや、それに渡されるオプションを定義している。

# For runqemu
QB_SYSTEM_NAME = "qemu-system-arm"
QB_MACHINE = "-machine microbit"
QB_CPU = "-cpu cortex-m0"
QB_OPT_APPEND = "-nographic -vga none"
QB_RNG = ""