私はカーネル開発が初めてなので、QEMUとgdbを使用してLinuxカーネルを実行/デバッグする方法を知りたいです。私は実際にロバート・ラブの本を読んでいますが、残念ながらカーネルを実行またはデバッグするための適切なツールをインストールする方法について読者を助けません...だから私はこのチュートリアルに従うことでした http:// opensourceforu .efytimes.com/2011/02/kernel-development-debugging-using-Eclipse / 。カーネルで開発するためにIDEとしてEclipseを使用していますが、最初にQEMU/gdbで動作するようにしたかったです。
1)でカーネルをコンパイルするには:
make defconfig (then setting the CONFIG_DEBUG_INFO=y in the .config)
make -j4
2)コンパイルが終了したら、次を使用してQemuを実行します。
qemu-system-x86_64 -s -S /dev/zero -kernel /Arch/x86/boot/bzImage
「停止」状態でカーネルを起動します
3)したがって、gdbを使用する必要があります。次のコマンドを試します。
gdb ./vmlinux
正しく実行しますが...どうすればいいのかわかりません...デバッグ。
だから私の質問は次のとおりです。Qemuでカーネルを実行し、デバッガーをそれに接続し、カーネル開発で私の生活を楽にするためにそれらを連携させるにはどうすればよいですか。
私が試してみたい:
(gdb) target remote localhost:1234
(gdb) continue
'-s'オプションを使用すると、qemuはポートtcp :: 1234でリッスンし、同じマシン上にいる場合はlocalhost:1234として接続できます。 Qemuの '-S'オプションは、continueコマンドを与えるまでQemuの実行を停止させます。
最善の方法は、まともなGDBチュートリアルを見て、自分のやっていることを理解することです。 これ とてもいい感じです。
Ubuntu 16.10ホストでテストされたステップバイステップ手順
すぐにゼロから始めるために、最小の完全自動化QEMU + Buildrootの例を以下で作成しました: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/c7bbc6029af7f4fab0a23a380d1607df0b2a3701/gdb-step -debugging.md 主な手順は次のとおりです。
まず、ルートファイルシステムrootfs.cpio.gz
を取得します。必要な場合は、以下を検討してください。
init
- only実行可能イメージ: https://unix.stackexchange.com/questions/122717/custom-linux-distro-that-runs-just-one-program-nothing-else/238579#238579次に、Linuxカーネルで:
git checkout v4.15
make mrproper
make x86_64_defconfig
cat <<EOF >.config-fragment
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_GDB_SCRIPTS=y
EOF
./scripts/kconfig/merge_config.sh .config .config-fragment
make -j"$(nproc)"
qemu-system-x86_64 -kernel Arch/x86/boot/bzImage \
-initrd rootfs.cpio.gz -S -s \
-append nokaslr
別の端末で、Linuxカーネルツリー内から、start_kernel
からデバッグを開始すると仮定します。
gdb \
-ex "add-auto-load-safe-path $(pwd)" \
-ex "file vmlinux" \
-ex 'set Arch i386:x86-64:intel' \
-ex 'target remote localhost:1234' \
-ex 'break start_kernel' \
-ex 'continue' \
-ex 'disconnect' \
-ex 'set Arch i386:x86-64' \
-ex 'target remote localhost:1234'
完了です!!
カーネルモジュールについては、以下を参照してください: QEMUを使用してLinuxカーネルモジュールをデバッグする方法
Ubuntu 14.04、GDB 7.7.1では、hbreak
が必要でしたが、break
ソフトウェアブレークポイントは無視されました。 16.10ではもうそうではありません。参照: https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944
厄介なdisconnect
とその後に来るのは、エラーを回避することです。
Remote 'g' packet reply is too long: 000000000000000017d11000008ef4810120008000000000fdfb8b07000000000d352828000000004040010000000000903fe081ffffffff883fe081ffffffff00000000000e0000ffffffffffe0ffffffffffff07ffffffffffffffff9fffff17d11000008ef4810000000000800000fffffffff8ffffffffff0000ffffffff2ddbf481ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
関連するスレッド:
nokaslr
: https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb/421287#421287既知の制限:
-O0
をサポートしていません(そして、パッチなしでもコンパイルしません): Linuxカーネルを最適化せずに-O0でコンパイルする方法は?max-completions
修正後でも、いくつかのタイプのタブ補完でメモリを消費します: 大きなバイナリのタブ補完割り込み 。したがって、ulimit -Sv 500000
はデバッグ前の賢明なアクションです。タブがfile<tab>
のfilename
引数に対してsys_execve
を完了したときに具体的に爆発しました: https://stackoverflow.com/a/42290593/895245こちらもご覧ください:
BjoernIDの答えは、私にとっては本当にうまくいきませんでした。最初の継続後、ブレークポイントに到達せず、割り込み時に次のような行が表示されます。
0x0000000000000000 in ?? ()
(gdb) break rapl_pmu_init
Breakpoint 1 at 0xffffffff816631e7
(gdb) c
Continuing.
^CRemote 'g' packet reply is too long: 08793000000000002988d582000000002019[..]
これは異なるCPUモード(BIOSのリアルモードとLinuxの起動時のロングモード)に関係があると思います。とにかく、解決策は、待機せずに最初にQEMUを実行することです(つまり、-S
):
qemu-system-x86_64 -enable-kvm -kernel Arch/x86/boot/bzImage -cpu SandyBridge -s
私の場合、起動中に何かを壊す必要があったため、数秒後にgdbコマンドを実行しました。もっと時間があれば(例えば、手動でロードされたモジュールをデバッグする必要がある場合)、タイミングは重要ではありません。
gdb
を使用すると、起動時に実行するコマンドを指定できます。これにより、自動化が少し簡単になります。 QEMU(これは既に開始されているはずです)に接続し、関数を中断して実行を継続するには、次を使用します:
gdb -ex 'target remote localhost:1234' -ex 'break rapl_pmu_init' -ex c ./vmlinux
Gdbを使用してvmlinux exeを起動しようとすると、gdbで最初に行うことはcmdの発行です。
(gdb)ターゲットリモートlocalhost:1234
(gdb)start_kernelを破る
(継続する)
これにより、start_kernelでカーネルが破損します。
私にとって、カーネルをデバッグするための最良のソリューションは、Eclipse環境からgdbを使用することです。リモートデバッグセクションで、gdbに適切なポートを設定する必要があります(qemu起動文字列で指定したポートと同じでなければなりません)。マニュアルは次のとおりです。 http://www.sw-at.com/blog/2011/02/11/linux-kernel-development-and-debugging-using-Eclipse-cdt/
Linuxシステムでは、vmlinuxは静的にリンクされた実行可能ファイルであり、ELF、COFF、a.outなど、Linuxでサポートされているオブジェクトファイル形式の1つにLinuxカーネルが含まれています。 vmlinuxファイルは、カーネルデバッグ、シンボルテーブル生成、またはその他の操作に必要な場合がありますが、マルチブートヘッダー、ブートセクター、およびセットアップルーチンを追加して、オペレーティングシステムカーネルとして使用する前にブート可能にする必要があります。
この初期ルートファイルシステムのイメージは、Linuxブートローダーがコンピューターのブートファームウェアにアクセスできる場所に保存する必要があります。これは、ルートファイルシステム自体、光ディスク上のブートイメージ、ローカルディスク上の小さなパーティション(通常ext4またはFATファイルシステムを使用するブートパラティション)、またはTFTPサーバー(イーサネットからブートできるシステム上)です。 )。
Linuxカーネルのコンパイル
このシリーズを適用してカーネルをビルドし、CONFIG_DEBUG_INFOを有効にします(ただし、CONFIG_DEBUG_INFO_REDUCEDはオフのままにします)
GDBとQemuをインストールする
Sudo pacman -S gdb qemu
Initramfsを作成する
#!/bin/bash
# Os : Arch Linux
# Kernel : 5.0.3
INIT_DIR=$(pwd)
BBOX_URL="https://busybox.net/downloads/busybox-1.30.1.tar.bz2"
BBOX_FILENAME=$(basename ${BBOX_URL})
BBOX_DIRNAME=$(basename ${BBOX_FILENAME} ".tar.bz2")
RAM_FILENAME="${INIT_DIR}/initramfs.cpio.gz"
function download_busybox {
wget -c ${BBOX_URL} 2>/dev/null
}
function compile_busybox {
tar xvf ${BBOX_FILENAME} && cd "${INIT_DIR}/${BBOX_DIRNAME}/"
echo "[*] Settings > Build options > Build static binary (no shared libs)"
echo "[!] Please enter to continue"
read tmpvar
make menuconfig && make -j2 && make install
}
function config_busybox {
cd "${INIT_DIR}/${BBOX_DIRNAME}/"
rm -rf initramfs/ && cp -rf _install/ initramfs/
rm -f initramfs/linuxrc
mkdir -p initramfs/{dev,proc,sys}
Sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} initramfs/dev/
cat > "${INIT_DIR}/${BBOX_DIRNAME}/initramfs/init" << EOF
#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys
exec /sbin/init
EOF
chmod a+x initramfs/init
cd "${INIT_DIR}/${BBOX_DIRNAME}/initramfs/"
find . -print0 | cpio --null -ov --format=newc | gzip -9 > "${RAM_FILENAME}"
echo "[*] output: ${RAM_FILENAME}"
}
download_busybox
compile_busybox
config_busybox
Qemuを使用したLinuxカーネルの起動
#!/bin/bash
KER_FILENAME="/home/debug/Projects/kernelbuild/linux-5.0.3/Arch/x86/boot/bzImage"
RAM_FILENAME="/home/debug/Projects/kerneldebug/initramfs.cpio.gz"
qemu-system-x86_64 -s -kernel "${KER_FILENAME}" -initrd "${RAM_FILENAME}" -nographic -append "console=ttyS0"
$ ./qemuboot_vmlinux.sh
SeaBIOS (version 1.12.0-20181126_142135-anatol)
iPXE (http://ipxe.org) 00:03.0 C980 PCI2.10 PnP PMM+07F92120+07EF2120 C980
Booting from ROM...
Probing EDD (edd=off to disable)... o
[ 0.019814] Spectre V2 : Spectre mitigation: LFENCE not serializing, switching to generic retpoline
can't run '/etc/init.d/rcS': No such file or directory
Please press Enter to activate this console.
/ # uname -a
Linux archlinux 5.0.3 #2 SMP PREEMPT Mon Mar 25 10:27:13 CST 2019 x86_64 GNU/Linux
/ #
GDBを使用したLinuxカーネルのデバッグ
~/Projects/kernelbuild/linux-5.0.3 ➭ gdb vmlinux
...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0xffffffff89a4b852 in ?? ()
(gdb) break start_kernel
Breakpoint 1 at 0xffffffff826ccc08
(gdb)
Display all 190 possibilities? (y or n)
(gdb) info functions
All defined functions:
Non-debugging symbols:
0xffffffff81000000 _stext
0xffffffff81000000 _text
0xffffffff81000000 startup_64
0xffffffff81000030 secondary_startup_64
0xffffffff810000e0 verify_cpu
0xffffffff810001e0 start_cpu0
0xffffffff810001f0 __startup_64
0xffffffff81000410 pvh_start_xen
0xffffffff81001000 hypercall_page
0xffffffff81001000 xen_hypercall_set_trap_table
0xffffffff81001020 xen_hypercall_mmu_update
0xffffffff81001040 xen_hypercall_set_gdt
0xffffffff81001060 xen_hypercall_stack_switch
0xffffffff81001080 xen_hypercall_set_callbacks
0xffffffff810010a0 xen_hypercall_fpu_taskswitch
0xffffffff810010c0 xen_hypercall_sched_op_compat
0xffffffff810010e0 xen_hypercall_platform_op