web-dev-qa-db-ja.com

Linuxカーネルのライブデバッグ、その方法、使用されているツール

最も一般的なものは何ですか?また、Linuxカーネルでライブデバッグを行うために使用される珍しい方法やツールはありませんか?私は、例えばLinusを知っています。 against Linuxカーネルのこの種のデバッグ、またはそれが最も少なかったため、当時はその意味で何も行われていませんでしたが、正直なところ、2000年から多くの時間が経過し、 Linuxプロジェクトに関する考え方が変わりました。また、現時点(ローカルまたはリモート)でLinuxカーネルのライブデバッグを行うために使用されている現在の方法は何ですか?

言及されたテクニックとツールに関するチュートリアルとチュートリアルへの参照は大歓迎です。

52
Shinnok

別のオプションは [〜#〜] ice [〜#〜] /JTAGコントローラーとGDBを使用することです。この「ハードウェア」ソリューションは、特に組み込みシステムで使用され、

しかし、例えばQemuは同様の機能を提供します:

  • 「localhost:1234」でリッスンするgdb「リモート」スタブでqemuを開始します:qemu -s ...

  • 次に、GDBを使用して、デバッグ情報でコンパイルされたカーネルファイルvmlinuxを開きます(カーネルの非最適化について議論する this メーリングリストスレッドを見ることができます)。

  • gDBとQemuを接続します:target remote localhost:1234

  • liveカーネルを参照してください:

    (gdb) where
    #0  cpu_v7_do_idle () at Arch/arm/mm/proc-v7.S:77
    #1  0xc0029728 in Arch_idle () atarm/mach-realview/include/mach/system.h:36
    #2  default_idle () at arm/kernel/process.c:166
    #3  0xc00298a8 in cpu_idle () at Arch/arm/kernel/process.c:199
    #4  0xc00089c0 in start_kernel () at init/main.c:713
    

残念ながら、GDBではこれまでのところユーザー空間のデバッグはできません(タスクリスト情報なし、異なるプロセスコンテキストを表示するためのMMU再プログラミングなしなど)。

  • info threadsは、異なるCPUのリストと状態を提供します

編集:

このPDFで手順の詳細を確認できます。

GDBおよびQEMUを使用したLinuxシステムのデバッグ

28
Kevin

Linuxカーネルのデバッグ中に、デバッガー(KDB、KGDB)、クラッシュ時のダンプ(LKCD)、トレースツールキット(LTT、LTTV、LTTng)、カスタムカーネルインストゥルメント(dprobes、kprobes)などのいくつかのツールを利用できます。次のセクションでは、それらのほとんどを要約しようとしましたが、これらが役立つことを願っています。

[〜#〜] lkcd [〜#〜](Linux Kernel Crash Dump)ツールにより、クラッシュ時にLinuxシステムがメモリの内容を書き込むことができます発生します。これらのログは、クラッシュの根本原因をさらに分析できます。 LKCDに関するリソース

Oopsカーネルが問題を検出すると、Oopsメッセージを出力します。このようなメッセージは、障害ハンドラー(Arch/*/kernel/traps.c)。printkステートメントで使用されているカーネル内の専用リングバッファーOopsには、Oopsで発生した、CPUレジスタの内容、Oopの数、説明、スタックバックトレースなど。カーネルOopに関するリソース

Dynamic Probes は、IBMが開発したLinux用の一般的なデバッグツールの1つです。このツールを使用すると、ユーザー空間とカーネル空間の両方で、システムのほぼすべての場所に「プローブ」を配置できます。プローブは、制御が特定のポイントに到達したときに実行されるコード(特殊なスタック指向言語で記述された)で構成されます。以下にリストされている動的プローブに関するリソース

Linux Trace Toolkit は、カーネルパッチと、カーネル内のイベントのトレースを可能にする関連ユーティリティのセットです。トレースにはタイミング情報が含まれており、特定の期間に発生した事象の合理的に完全な全体像を作成できます。 LTT、LTT Viewer、およびLTT Next Generationのリソース

[〜#〜] memwatch [〜#〜] はオープンソースのメモリエラー検出ツールです。 gccステートメントでMEMWATCHを定義し、コードにヘッダーファイルを追加することで機能します。これにより、メモリリークとメモリ破損を追跡できます。 MEMWATCHに関するリソース

ftrace は、Linuxカーネルに適したトレースフレームワークです。 ftraceは、カーネルの内部操作をトレースします。このツールは、2.6.27のLinuxカーネルに含まれていました。さまざまなトレーサープラグインを使用すると、ftraceは、スケジューリングイベント、割り込み、メモリマップI/O、CPU電力状態の移行、ファイルシステムと仮想化に関連する操作など、さまざまな静的トレースポイントをターゲットにできます。また、カーネル関数呼び出しの動的追跡が利用可能です。オプションで、グロブを使用して関数のサブセットに制限したり、呼び出しグラフを生成してスタックの使用状況を提供したりできます。 https://events.linuxfoundation.org/slides/2010/linuxcon_japan/linuxcon_jp2010_rostedt.pdf でftraceの優れたチュートリアルを見つけることができます。

ltrace はLinuxのデバッグユーティリティであり、ユーザー空間アプリケーションが共有ライブラリに対して行う呼び出しを表示するために使用されます。このツールを使用して、動的ライブラリ関数呼び出しをトレースできます。実行されたプロセスによって呼び出される動的ライブラリ呼び出しと、そのプロセスによって受信される信号をインターセプトして記録します。また、プログラムによって実行されるシステムコールをインターセプトして印刷することもできます。

[〜#〜] kdb [〜#〜]は、Linuxカーネルのカーネル内デバッガーです。 KDBは、単純なシェルスタイルのインターフェイスに従います。これを使用して、メモリ、レジスタ、プロセスリスト、dmesgを検査し、ブレークポイントを設定して特定の場所で停止することもできます。 KDBを介して、ブレークポイントを設定し、いくつかの基本的なカーネル実行制御を実行できます(KDBはソースレベルのデバッガーではありません)。 KDBに関するいくつかの便利なリソース

[〜#〜] kgdb [〜#〜]は、Linuxカーネルのソースレベルデバッガとして使用することを目的としています。 Linuxカーネルをデバッグするためにgdbとともに使用されます。 kgdbを使用するには、2台のマシンが必要です。これらのマシンの1つは開発マシンであり、もう1つはターゲットマシンです。デバッグするカーネルは、ターゲットマシンで実行されます。期待は、gdbを使用してカーネルに「侵入」し、メモリ、変数を検査し、アプリケーション開発者がgdbを使用してアプリケーションをデバッグする方法と同様のコールスタック情報を調べることができることです。カーネルコードにブレークポイントを配置し、制限された実行ステップを実行することができます。 KGDBに関するいくつかの便利なリソース

21

wiki によると、kgdb2.6.26のカーネルにマージされましたが、これは過去数年以内です。 kgdbリモートデバッガー であるため、 カーネルでアクティブ化 してから、何らかの方法でgdbをアタッチします。多くのオプションがあるように思えるので、私は何とか言います- connecting gdb を参照してください。 kgdbが現在ソースツリーにあることを考えると、これが今後使用したいものだと思います。

だから、Linusは譲歩したように見える。しかし、私は彼の議論を強調したい。これはカーネルの土地です。何か問題が発生した場合、segfaultが表示されず、システム全体がダウンするまでのあいまいな問題から何かが取得されます。ここにドラゴンがいます。注意して続行すると、警告が表示されます。

20
user257111

「ライブ」デバッグ用のもう1つの優れたツールは、kprobes/dynamic probeです。

これにより、特定のアドレスが実行されたときに実行される小さなブレークポイントのような小さなモジュールを動的に構築できます。

それらの大きな利点は次のとおりです。

  1. それらはシステムに影響を与えません-つまり、場所がヒットしたとき-コードを実行するだけ-カーネル全体を停止しません。
  2. Kgdbのように相互接続された2つの異なるシステム(ターゲットとデバッグ)は必要ありません

ブレークポイントへのヒット、データ値の確認、変更や上書きなどの確認などを行うのに最適です。「コードをステップスルー」したい場合は、そうしません。

追加-2018:

もう1つの非常に強力な方法は、「動的」プローブなどの多くのツールをロールアップし、他のツール(oprofileなど)を置き換え/非推奨にする「perf」と呼ばれるプログラムです。

特に、perf probeコマンドを使用すると、システムに動的プローブを簡単に作成/追加できます。その後、perf recordはシステムをサンプリングし、perf report(またはperf script)を介したレポートでプローブがヒットしたときに情報(およびバックトレース)を報告できます。カーネルに適切なデバッグシンボルがある場合、カーネルを停止することなく、システムから優れたインテルを取得できます。このツールの詳細については、(Googleまたはシステムで)man perfを実行するか、次のすばらしいページを参照してください。

http://www.brendangregg.com/perf.html

14
Brad

KGDB + QEMUステップバイステップ

KGDBは、ホストGDBからカーネル自体をステップデバッグできるカーネルサブシステムです。

私のQEMU + Buildrootの例は、実際のハードウェアなしでそれを味わう良い方法です: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/1969cd6f8d30dace81d9848c6bacbb8bad9dacd8#kgdb

長所と短所と他の方法:

  • アドバンテージvs QEMU:
    • ハードウェアベンダーはデバイスの正確なソフトウェアモデルをリリースすることを好まないため、多くの場合、デバイスのソフトウェアエミュレーションはありません。
    • qEMUよりも高速な実際のハードウェア
  • 利点対JTAG:追加のJTAGハードウェアは不要で、セットアップが簡単
  • qEMUとJTAGに対するデメリット:視認性が低く、邪魔になります。 KGDBは、ホストと通信できるように動作するカーネルの特定の部分に依存しています。例えばパニックに陥ると、ブートシーケンスを表示できません。

主な手順は次のとおりです。

  1. 次を使用してカーネルをコンパイルします。

    CONFIG_DEBUG_KERNEL=y
    CONFIG_DEBUG_INFO=y
    
    CONFIG_CONSOLE_POLL=y
    CONFIG_KDB_CONTINUE_CATASTROPHIC=0
    CONFIG_KDB_DEFAULT_ENABLE=0x1
    CONFIG_KDB_KEYBOARD=y
    CONFIG_KGDB=y
    CONFIG_KGDB_KDB=y
    CONFIG_KGDB_LOW_LEVEL_TRAP=y
    CONFIG_KGDB_SERIAL_CONSOLE=y
    CONFIG_KGDB_TESTS=y
    CONFIG_KGDB_TESTS_ON_BOOT=n
    CONFIG_MAGIC_SYSRQ=y
    CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
    CONFIG_SERIAL_KGDB_NMI=n
    

    それらのほとんどは必須ではありませんが、これは私がテストしたものです。

  2. QEMUコマンドに追加します。

    -append 'kgdbwait kgdboc=ttyS0,115200' \
    -serial tcp::1234,server,nowait
    
  3. LinuxカーネルソースツリーのルートからGDBを実行します:

    gdb -ex 'file vmlinux' -ex 'target remote localhost:1234'
    
  4. GDBの場合:

    (gdb) c
    

    ブートが完了するはずです。

  5. QEMUの場合:

    echo g > /proc/sysrq-trigger
    

    そしてGDBは壊れるはずです。

  6. これで完了です。通常どおりGDBを使用できます。

    b sys_write
    c
    

Ubuntu 14.04でテスト済み。

KGDB + Raspberry Pi

上記とまったく同じセットアップが、Raspberry Pi 2、Raspbian Jessie 2016-05-27でほとんど機能しました。

PiでQEMUステップを実行することを学ぶ必要があります。これは簡単にグーグル化できます。

  • https://www.raspberrypi.org/documentation/linux/kernel/building.md で説明されているように、構成オプションを追加し、カーネルを再コンパイルしますシンボルをデバッグするため、再コンパイルが必要です。

  • ブートパーティションのcmdline.txtを編集して追加します。

    kgdbwait kgdboc=ttyAMA0,115200
    
  • gdbをシリアルに接続するには:

    arm-linux-gnueabihf-gdb -ex 'file vmlinux' -ex 'target remote /dev/ttyUSB0'
    

    シリアルに慣れていない場合は、これをチェックしてください: https://www.youtube.com/watch?v=da5Q7xL_OTo 必要なのは安価なアダプターだけです このような 。 KGDBを試す前に、シリアルからシェルを取得して、シェルが機能していることを確認してください。

  • 行う:

    echo g | Sudo tee /proc/sysrq-trigger
    

    シリアルはすでにGDBによって取得されているため、SSHセッション内から。

このセットアップでは、sys_writeにブレークポイントを設定し、プログラムの実行を一時停止し、ソースを一覧表示して続行できました。

しかし、時々sys_writenextを実行すると、GDBがハングし、このエラーメッセージを数回出力しました。

Ignoring packet error, continuing...

そのため、セットアップに問題があるかどうか、またはより複雑なRaspbianイメージで何らかのバックグラウンドプロセスが実行しているためにこれが予想されるかどうかはわかりません。

また、Linuxブートオプションでマルチプロセッシングを無効にするように言われましたが、まだ試していません。

実際、冗談は、Linuxが2.2.12以降、xmonカーネル内デバッガーを備えていたということです。ただし、powerpcアーキテクチャーのみです(実際には当時はppcでした)。

これはソースレベルのデバッガーではなく、ほとんど完全にドキュメント化されていませんが、それでもあります。

http://lxr.linux.no/linux-old+v2.2.12/Arch/ppc/xmon/xmon.c#L119

4
mpe

Ubuntu 16.10ホストでテストされたQEMU + GDBの段階的な手順

最初からすぐに始めるために、最小限の完全自動化QEMU + Buildrootの例を作成しました: https://github.com/cirosantilli/linux-kernel-module-cheat 以下で説明します。

まず、ルートファイルシステムrootfs.cpio.gzを取得します。必要な場合は、以下を検討してください。

次に、Linuxカーネルで:

git checkout v4.9
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

別の端末で、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'

完了です!!

カーネルモジュールについては、次を参照してください: LinuxカーネルモジュールをQEMUでデバッグする方法

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

関連するスレッド:

こちらもご覧ください:

既知の制限:

カーネルコードをたくさん書く人として、私はkgdbを使用したことがなく、kprobesなどを使用することはめったにないと言わなければなりません。

多くの場合、戦略的なprintksを投入するのが最善の方法です。最近のカーネルではtrace_printkは、dmesgをスパムせずにそれを行う良い方法です。

3
mpe

ユーザーモードLinux(UML)

https://en.wikipedia.org/wiki/User-mode_Linux

カーネルコードのステップデバッグを可能にする別の仮想化方法。

UMLは非常に独創的です。x86と同様にArchとして実装されますが、低レベルの命令を使用する代わりに、ユーザーランドシステムコールでArch関数を実装します。

その結果、Linuxホスト上でLinuxカーネルコードをユーザーランドプロセスとして実行できるようになります。

最初にrootfsを作成し、次のように実行します。 https://unix.stackexchange.com/questions/73203/how-to-create-rootfs-for-user-mode-linux-on-Fedora-18/372207#372207

um defconfigはデフォルトでCONFIG_DEBUG_INFO=yを設定します(そう、これは開発用です)ので、大丈夫です。

ゲスト:

i=0
while true; do echo $i; i=$(($i+1)); done

別のシェルのホスト:

ps aux | grep ./linux
gdb -pid "$pid"

GDBの場合:

break sys_write
continue
continue

そして今、あなたはGDBからカウントを制御しており、期待どおりにソースを見ることができます。

長所:

  • linuxカーネルのメインラインツリーに完全に含まれる
  • qEMUのフルシステムエミュレーションよりも軽量

短所:

参照: https://unix.stackexchange.com/questions/127829/why-would-someone-want-to-run-usermode-linux-uml

皆さんは間違っています。kgdbは最新のカーネルでもうまく機能します。分割イメージのカーネル構成、ランダム化の最適化に注意する必要があります。

シリアルポート経由のkgdbは役に立たない。なぜなら今日のマザーボードシリアルポートでDB9をサポートするコンピューターはなく、USBシリアルポートはポーリングモードをサポートしていないからである。

新しいゲームはkgdboeで、ログトレースは次のとおりです。

以下はホストマシンです。vmlinuxはターゲットマシンのものです。

root@Thinkpad-T510:~/KGDBOE# gdb vmlinux
Reading symbols from vmlinux...done.
(gdb) target remote udp:192.168.1.22:31337
1077    kernel/debug/debug_core.c: No such file or directory.
(gdb) l oom_kill_process 
828 mm/oom_kill.c: No such file or directory.
(gdb) l oom_kill_process 
828 in mm/oom_kill.c
(gdb) break oom_kill_process
Breakpoint 1 at 0xffffffff8119e0c0: file mm/oom_kill.c, line 833.
(gdb) c
Continuing.
[New Thread 1779]
[New Thread 1782]
[New Thread 1777]
[New Thread 1778]
[New Thread 1780]
[New Thread 1781]
[Switching to Thread 1779]

Thread 388 hit Breakpoint 1, oom_kill_process (oc=0xffffc90000d93ce8, message=0xffffffff82098fbc "Out of memory")
at mm/oom_kill.c:833
833 in mm/oom_kill.c
(gdb) s
834 in mm/oom_kill.c
(gdb) 

ピアターゲットマシンでは、次のようにしてクラッシュを取得し、ホストマシンにキャプチャします。

#swapoff -a
#stress -m 4 --vm-bytes=500m
0
unhmble