GNU/Linux >> Linux の 問題 >  >> Linux

GDB と QEMU を使用して Linux カーネルをデバッグするには?

試してみます:

(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 -実行可能イメージのみ:https://unix.stackexchange.com/questions/122717/custom-linux-distro-that-runs-just-one-program-nothing-else/238579#238579
  • Busybox インタラクティブ システム:https://unix.stackexchange.com/questions/2692/what-is-the-smallest-possible-linux-implementation/203902#203902

次に、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

関連スレッド:

  • https://sourceware.org/bugzilla/show_bug.cgi?id=13984 は GDB のバグの可能性があります
  • リモート 'g' パケット応答が長すぎます
  • http://wiki.osdev.org/QEMU_and_GDB_in_long_mode osdev.org は、いつものようにこれらの問題の優れた情報源です
  • https://lists.nongnu.org/archive/html/qemu-discuss/2014-10/msg00069.html
  • nokaslr :https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb/421287#421287

既知の制限:

  • Linux カーネルは -O0 をサポートしていません (パッチなしではコンパイルさえしません)。 :Linux カーネルを最適化解除して -O0 でコンパイルする方法
  • GDB 7.11 では、max-completions の後でも、一部の種類のタブ補完でメモリが吹き飛ばされます。 修正:大きなバイナリのタブ完了割り込み そのパッチでカバーされていないいくつかのまれなケースの可能性があります。だから ulimit -Sv 500000 デバッグする前の賢明な行動です。特に file<tab> をタブで完了したときに爆発しました filename の場合 sys_execve の引数 のように:https://stackoverflow.com/a/42290593/895245

こちらもご覧ください:

  • https://github.com/torvalds/linux/blob/v4.9/Documentation/dev-tools/gdb-kernel-debugging.rst 公式 Linux カーネル「ドキュメント」
  • Linux カーネルのライブ デバッグ、その方法と使用するツール

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

Linux
  1. Linuxのwatchコマンドでコマンドとタスクを監視する

  2. gdbを使用してLinuxでCプログラムをデバッグする方法

  3. Linux上のFlatpak:それは何であり、それを使ってアプリをインストールする方法

  1. Linuxスクリプトコマンドを使用してターミナルセッションをキャプチャして出力する方法

  2. Linux – Linuxカーネルはどのようにしてデバイスのメジャー番号とマイナー番号を認識しますか?

  3. QEMU を使用した Linux カーネルのデバッグ

  1. Linuxカーネルをftraceで分析する

  2. Linuxでエイリアスを作成してエイリアスコマンドを使用する方法

  3. OSとLinuxのバージョンを確認する方法