LoginSignup
2
2

More than 3 years have passed since last update.

SystemTapのクロス開発環境での使い方

Posted at

TL;DR

SystemTapをクロス開発環境でビルドして使う方法のメモ。

  • stapコマンドをホストPC用にコンパイル
  • staprunコマンドをターゲット用にコンパイル
  • stapコマンドでsystemtapスクリプトから.koファイルをビルド
    (クロスコンパイラ、ターゲットのLinuxカーネルビルドツリーが必要)
  • .koファイルをターゲットにインストールし、staprunコマンドでload -> probe実行

PC等のセルフホスト環境では、stapコマンドはSystemTapのフロントエンドコマンドとして、ビルドからloadまでワンストップで実行してくれる。
クロス開発の場合、通常ビルドはホストPCで、.koファイルのloadはターゲットで実行しなければならない。
このようなケースのために、load等のランタイム処理はstaprunコマンドに分離してくれているので、staprunコマンドのみクロスコンパイルすればよい。
そのためのconfigureオプションとして、--disable-translatorが用意されている。

SystemTapとは

独自スクリプト言語で記述したprobe処理を、ローダブルカーネルモジュールにビルドしてloadすることで、カーネルを再ビルドすること無くカーネルを動的に解析するための仕組み。
kprobeをDSLで抽象度を上げたもの、と考えると理解しやすいかも。

よく比較されるものとして、perf, ftrace, eBPFなどがある。(比較表)

PC等のセルフホスト環境では、stapコマンドはSystemTapのフロントエンドコマンドとして、ビルドからprobeまでワンストップで実行してくれる。
stapコマンドは下記5個のpassからなる。(man stap(1) #PROCESSING)

  • Pass 1. parse
    stpスクリプトから、コメントの除去、();の付与、$1など引数の置換などを行う。
    Cプログラムのビルドプロセスにおけるプリプロセスに近い。

  • Pass 2. elaborate
    kernelのデバッグシンボルから、スクリプト内で参照するシンボルが解決可能か確認する。
    不要なコードの削除など、最適化も行う。
    ただし、あくまでもstpスクリプトレベルでの最適化。

  • Pass 3. translate
    stpスクリプトをC言語に変換する。
    併せてビルドに必要なMakefileも作成する。

  • Pass 4. compile
    .cファイルをビルドし、.koファイルを生成する。

  • Pass 5. run
    .koファイルをinsmodし、probeした結果を取得して標準出力 or ファイルに出力する。
    実際にはstapコマンドはこの処理を、staprunコマンドに委譲している。

クロス開発環境で考えると、Pass 1〜4はホストPCで実施可能。
Pass 5はターゲット上での実行しなければならない。

QEMU(aarch64)上のlinux上でSystemTapを使うまでの手順

  • Host PC : Ubunt 16.04 (x86_64)
  • buildroot : 2019.02.4
  • linux : 4.19.16
  • qemu : 4.0.0
  • systemtap : 4.1

1. QEMUをコンパイル

特別な手順はなし。

wget https://download.qemu.org/qemu-4.0.0.tar.bz2
tar xf qemu-4.0.0.tar.bz2
mkdir -p build-qemu-4.0.0
cd build-qemu-4.0.0
../qemu-4.0.0/configure --target-list=aarch64-softmmu
make -j$(getconf _NPROCESSORS_ONLN)
cd ..

2. buildrootでターゲットのlinux / rootfsをコンパイル

wget https://buildroot.org/downloads/buildroot-2019.02.4.tar.bz2
tar xf buildroot-2019.02.4.tar.bz2
cd buildroot-2019.02.4

buildrootのconfigを変更。
SystemTap観点で追加が必要なのはELFUTILSぐらい。
あとは効率化のためのCCACHEやsshのためのDROPBEARなど。

configs/qemu_aarch64_virt_defconfig
--- qemu_aarch64_virt_defconfig.org 2019-08-17 13:03:12.239335388 +0900
+++ qemu_aarch64_virt_defconfig 2019-08-17 13:03:44.551346868 +0900
@@ -21,3 +21,14 @@
 BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
 BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/aarch64-virt/linux.config"
 BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
+
+BR2_CCACHE=y
+BR2_TOOLCHAIN_BUILDROOT_WCHAR=y
+BR2_TOOLCHAIN_BUILDROOT_CXX=y
+BR2_TARGET_GENERIC_ROOT_PASSWD="password"
+BR2_PACKAGE_STRACE=y
+BR2_PACKAGE_STRESS=y
+BR2_PACKAGE_OPENSSL=y
+BR2_PACKAGE_ELFUTILS=y
+BR2_PACKAGE_DROPBEAR=y
+# BR2_PACKAGE_DROPBEAR_SMALL is not set

linuxのconfigも変更。
SystemTapを使うためには、RELAY, KPROBE, DEBUG_INFO, DEBUG_KERNELの追加が必要だった。
GDB_SCRIPTSFUNCTION_TRACERはおまけ。

board/qemu/aarch64-virt/linux.config
--- linux.config.org    2019-08-17 13:08:45.843587678 +0900
+++ linux.config    2019-08-17 13:10:14.427693496 +0900
@@ -4,7 +4,9 @@
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_TASKSTATS=y
 CONFIG_SCHED_AUTOGROUP=y
+CONFIG_RELAY=y
 CONFIG_PROFILING=y
+CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_BLK_DEV_BSGLIB=y
@@ -52,3 +54,7 @@
 CONFIG_EXT4_FS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_DEBUG_INFO=y
+CONFIG_GDB_SCRIPTS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_FUNCTION_TRACER=y
make qemu_aarch64_virt_defconfig
make BR2_JLEVEL=$(getconf _NPROCESSORS_ONLN)
cd ..

公式Wikiで指定されているカーネルコンフィグは以下の通り。
CONFIG_DEBUG_INFO_SPLITのみnなので注意。

CONFIG_DEBUG_INFO=y        # stpスクリプトで参照するシンボルを解決するために必要。
CONFIG_KPROBES=y           # Kernel空間をprobeするための仕組み。SystemTapはバックエンドでkprobeが使われているため必須。
CONFIG_RELAY=y             # CPUごとのカーネルバッファをユーザ空間に見せるための仕組み。probe結果の出力に使われている。
CONFIG_DEBUG_FS=y          # 上記relay fileはdebugfs(/sys/kernel/debug/systemtap/)上に作られる。
CONFIG_MODULES=y           # SystemTap(kprobe)はLoadable Kernel Moduleにprobe処理を入れることでkernel空間を盗み見る。
CONFIG_MODULE_UNLOAD=y     # 同上。
CONFIG_UPROBES=y           # kprobesのUser空間版。User空間のprobeもするためには必要。
CONFIG_DEBUG_INFO_SPLIT=n  # stapはsplit debug infoに対応していないので、無効にする必要がある。

3. stapコマンドをホストPC用にコンパイル

stapコマンドはホストPC用なので、普通にビルドすればいい。
手元の環境ではlibdw-devパッケージが必要だった。

sudo apt install libdw-dev

wget https://sourceware.org/systemtap/ftp/releases/systemtap-4.1.tar.gz
tar xf systemtap-4.1.tar.gz
mkdir -p build-host-systemtap-4.1/
cd build-host-systemtap-4.1
../systemtap-4.1/configure --prefix=${PWD}/destdir
make -j$(getconf _NPROCESSORS_ONLN)
make install
cd ..

4. staprunコマンドをターゲット用にコンパイル

続いて、staprunコマンドをターゲット用にコンパイルする。
基本的には通常のクロスコンパイルだが、stapコマンドが不要なので--disable-translatorオプションをつけておく。

ここではまとめてインストールしているが、個別でインストールする場合はstaprunだけでなくstapioも必要なので注意。
stapiostaprunから更にフォークされる。
/sys/kernel/debug/systemtap/${MOD_NAME}/trace${CPU_ID}からデータを読み出し、標準出力 or ファイルに出力する。

export PATH=${PWD}/buildroot-2019.02.4/output/host/bin/:${PATH}
mkdir -p build-aarch64-systemtap-4.1
cd build-aarch64-systemtap-4.1
../systemtap-4.1/configure \
  --host=aarch64-buildroot-linux-uclibc \
  --with-sysroot=${PWD}/../buildroot-2019.02.4/output/staging \
  --disable-docs \
  --disable-http \
  --disable-server \
  --disable-translator \
  --disable-ssp
make -j$(getconf _NPROCESSORS_ONLN)
DESTDIR=${PWD}/../buildroot-2019.02.4/output/target/ make install
cd ..

staprunコマンドがbuildrootのrootfsにインストールされたので、イメージを再生成する。

make -C buildroot-2019.02.4/ BR2_JLEVEL=$(getconf _NPROCESSORS_ONLN)

5. stapコマンドで.koファイルをビルド

PC用でも同じだが、任意のSystemTapスクリプトをビルドするためには、
stapdevグループとstapusrグループの両方のメンバーである必要がある。(man stap(1) #PERMIMSSIONS)

sudo adduser $(whoami) stapdev
sudo adduser $(whoami) stapusr

下記コマンドで、stap_hello_world.koが生成される。

export PATH=${PWD}/buildroot-2019.02.4/output/host/bin/:${PATH}
build-host-systemtap-4.1/destdir/bin/stap \
  -a arm64 \
  -B CROSS_COMPILE=aarch64-buildroot-linux-uclibc- \
  -r ${PWD}/buildroot-2019.02.4/output/build/linux-4.19.16/ \
  -e 'probe begin { log ("hello " . k) exit () } global k="world" ' \
  -m stap_hello_world

6. qemuの起動

起動時のオプションはbuildroot-2019.02.4/board/qemu/aarch64-virt/readme.txtを参考にする。
sshで接続用にTCPポートのフォワードだけ追加している。

build-qemu-4.0.0/aarch64-softmmu/qemu-system-aarch64 \
  -M virt \
  -cpu cortex-a53 \
  -nographic \
  -smp 1 \
  -kernel buildroot-2019.02.4/output/images/Image \
  -append "rootwait root=/dev/vda console=ttyAMA0" \
  -netdev user,id=eth0,hostfwd=tcp::10022-:22 \
  -device virtio-net-device,netdev=eth0 \
  -drive file=buildroot-2019.02.4/output/images/rootfs.ext4,if=none,format=raw,id=hd0 \
  -device virtio-blk-device,drive=hd0 \
  -gdb tcp::4321

7. staprunコマンドでprobe実行

めでたしめでたし。

# scp -P 10022 stap_hello_world.ko root@localhost:
# ssh -p10022 root@localhost /usr/local/bin/staprun stap_hello_world.ko
hello world
# ssh -p10022 root@localhost /usr/local/bin/staprun stap_hello_world.ko k=hoge
hello hoge

参考

SystemTap公式
man stap(1)
man staprun(8)
SystemTap公式git README
SystemTap公式Wiki Using systemtap with self-built kernels
SystemTap公式Wiki CrossCompiling
SystemTap公式Wiki 比較表
Brendan Gregg's Blog Choosing a Linux Tracer (2015)
睡眠不足 perf, ftraceのしくみ

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2