280 likes | 444 Views
Linux Device Driver 輪講 2. デバックのテクニック. ACE suzuk. table of contents. カーネルにおけるデバッグのサポート 表示させてのデバッグ 問い合わせによるデバッグ 観察によるデバッグ システムフォルトのデバッグ デバッガと関連ツール. はじめに. カーネルプログラミング、それ自体がユニークなデバッグ方法への挑戦です カーネルコードをデバッガ上で簡単に実行できない コードをトレースするのも大変. この章では、カーネルコードの表示やエラー追跡に 使えるテクニックを紹介する.
E N D
Linux Device Driver 輪講2. デバックのテクニック ACE suzuk
table of contents • カーネルにおけるデバッグのサポート • 表示させてのデバッグ • 問い合わせによるデバッグ • 観察によるデバッグ • システムフォルトのデバッグ • デバッガと関連ツール
はじめに • カーネルプログラミング、それ自体がユニークなデバッグ方法への挑戦です • カーネルコードをデバッガ上で簡単に実行できない • コードをトレースするのも大変 この章では、カーネルコードの表示やエラー追跡に 使えるテクニックを紹介する
1.カーネルにおけるデバッグのサポート • カーネルのデバッグ機能を有効にする • 通常の製品カーネルでは、デバッグ機能が有効になっていない • カーネル設定ツールの「kernel hackig」メニュー以下を探せ! • CONFIG_DEBUG_KERNEL • カーネルデバッグのフラグ、オンにする • CONFIG_DEBUG_INFO • カーネルに完全なデバッグ情報を含んでビルドする。gdbを使う場合に必用 • CONFIG_DEBUG_STACK_USAGE • カーネルのスタックオーバーフローをチェック
2.表示させてのデバッグ • printkによるメッセージ表示 • デバッグのテクニックとして最も良く使われる方法 • 大きな特徴はログレベルを指定できること • ログレベルマクロは文字列に展開される • KERN_DEBUG • デバッグ用のメッセイー時 • デバッグメッセージ出力デーモン • klogd, syslogd (通常/var/log/messagesに追加) • /proc/sys/kernel/printkにログレベルの設定 • 現在のログレベルなど
コンソールメッセージのリダイレクション • 「別の」仮想ターミナルでメッセージを受け取るには、ioctl(TIOCLINUX)を実行 • ioctlの特別なコマンド • ターミナルIOコマンドの略 仮想ターミナル0番でメッセージを受け取る例 char bytes[2] = {11, 0}; /* 11はコマンド番号 */ ioctl(STDIN_FILENO, TIOCLINUX, bytes);
メッセージを記録する方法 • printk関数は__LOG_BUF_LENバイトの環状バッファにメッセージを出力 • カーネルメッセージを待ち構えている全てのプロセスが目を覚ます • syslogシステムコールの中でスリープ or /proc/kmsgを読んでいる(klogd)プロセス • dmesgコマンドはバッファの内容全体を出力 • klogdがカーネルメッセージを回収してsyslogdに送る • klogdに–fオプションを渡しファイルに書き出せる • 続いてsyslogdが/syslog.confを見てメッセージをどのように処理するかを決定する
メッセージを記録する方法 動作イメージ printk head 1 2 klogd Write Read send mesg ウ 3 z z ホ z syslogd tail
メッセージのオン、オフを切り替える • デバッグメッセージのオン、オフを切り替えることができる • 全てのデバッグメッセージ • 個別のデバッグメッセージ Cプリプロセッサを使い制 DEBUG = y ifreq($(DEBUG), y) DEBUGFLAGS = -O –g –DSCULL_DEBUG else DEBUGFLAGS = -O2 endif CFLAGS += $(DEBFLAGS)
速度の制限 • デバイスの不調など繰り返すメッセージ出力関数 • int printk_ratelimit(void); • いくつ出力されたかを管理する/proc/sys/kernel/printk_ratelimit_burstで調整可能 // how to use if(printk_ratelimit()){ printk(KERN_NOTICE “printer ” }
デバイス番号の表示 • 対象のハードウェアのデバイス番号を表示 • int print_dev_t(char *buffer, dev_t dev); • char *format_dev_t(char *buffer, dev_t dev);
問い合わせによるデバッグ • データをprintkで垂れ流すよりも、ユーザが必要に応じて問い合わせる方が良い • 問い合わせる方法たち • /procファイルシステム • ドライバにioctlを使う • 属性をsysfsでエクスポートする方法(14章で)
/procファイルシステムを使う • /procファイルシステムはカーネルが情報を外部にエクスポートするために使う • /proc/modules:現在ロードされたモジュール • 注意!:新しいコードではsysfsを使うことをお勧めする
/procにファイルを実装する 1/3 • 読み出し専用/procファイルの作成 • <linux/proc_fs.h>をinclude • データ提供関数をドライバに実装 • インタフェース int (*read_proc)(char *page, char **start, off_t offset, int count, int *eof, void *data) • page: データ書き込み先バッファ(1PAGE_SIZE) • start: どこから書き込んだデータが始まるのか
/procにファイルを実装する 2/3 • /procファイルの作成 (scullの例) • create_proc_reawd_entry(“sculmem”, 0, NULL, scull_read_procmem, NULL); • remove_proc_entry(“scullmem”, NULL /*親dir*/); • /procファイルシステムの問題点 • 参照回数をカウントしていない • プロセスが参照中に削除されることがある • モジュールがアンロードされていない間に/procエントリの削除に失敗するとカーネルがクラッシュ • /procエントリは所有者が関連付けられていない、重複名で登録される可能性がある
seq_fileインタフェース • 大きなカーネル仮想ファイルの実装インタフェース • seq_openを使い、/procをseq_fileインタフェースに関連付ける • 単純なiteratorオブジェクトを作成が必要 • <linux/seq_file.h>をinclude • 次の4つのiteratorメソッドを実装 • start, next, stop, show • /procファイルを操作した際に、カーネルから呼ばれる void *next(struct seq_file *sfile, void *v, loff_t *pos);
ioctlメソッドを使う • デバック用のioctlを実装しておくことができる • ドライバの構造体をユーザ空間にコピーできる • /proc読み出しよりも実行が速い
4.観察によるデバッグ • 問題が深刻出ない場合、ユーザ空間のアプリを観察することで対処できる • デバッガによる順次実行 • printf文による出力 • straceの下でのプログラム実行 • Straceとは • ユーザ空間プログラムが発行したシステムコールをすべて表示 • ドライバがシステムコールに応じて正しく実行されているかを確認するために有用 • perror()以上の情報を得られる
5.システムフォルトのデバッグ • できるだけ多くの情報を集めることが重要 • カーネルより吐き出されたメッセージ • CPUダンプも役立つ • システムフォルトやOopsでシステム全体が落ちることはない • プロセスコンテキストに割り当てられたメモリが失われる以外は大丈夫 • 最悪リブートすれば良い
Oopsメッセージ • CPUが特権モードの時にページフォルトが起こったときにOopsメッセージを出力 • 大抵はポインタの取り扱いによるバグ • Oopsへの対処方法 • CPUダンプのEIPを参照する • どこで問題が発生したかを知る • コールスタックから問題箇所に行き着いた経緯を知る
システムのハングアップ • 事前予防による対策 • 要所要所にschedule呼び出しを挿入 • 他のプロセスがCPU時間を奪えるようになる • ドライバのバグによるカーネル空間で無限ループから復帰できる • 事後のデバッグ • コンソールにメッセージ出力 • どこにscheduleを挟めば良いかわからない時 • 偽のハングアップを見破るには時計やシステム不可メータを表示するだけで有効 • キーボードのロックなどにおいてはMagic SysRqKeyが有効
6.デバッガと関連ツール • デバッガを使ったデバッグはとても時間がかかるためできる限り避けるべき • gdbを使う • kdbカーネルデバッガ • kdbdパッチ • ユーザモードLinux • Linux Trace Toolkit • Dynamic Probes
gdbを使う • 実行コマンド • gdb /usr/src/linux/vmlinux /proc/kcore • 制限 • カーネルデータを変更できない • ブレークポイント、ウォッチポイントの設定できない • シングルステップ実行できない • モジュールをテストするのは難しい • 必要とされる能力 • gdbコマンドの使い手 • アセンブリコードを理解できる • ソースと最適化アセンブリを対応付けられる
kdbカーネルデバッガ • 内蔵のカーネルデバッガ(非公式) • ブレークポイントの設置 • スタックトレース
kgdbパッチ • リモートデバッグを可能にするパッチ • テストマシンと、開発用マシンを分けることができる • 2.6で正式にマージされる予定
ユーザモードLinux • ユーザプロセスとしてカーネルを実行 • Linuxシステムコールインタフェースを実装した仮想マシン上で実行される • カーネルのコピーをユーザモードで走らせる • /arch/um以下を使い、Linuxカーネルの独立したポートとして構築 • 異なるハードウェアやソフトウェアを試すことができる • ハードウェアにアクセスできない制限がある
Linux Trace Toolkit(LTT) • カーネルパッチのひとつ • カーネル中のイベントトレース用のユーティリティ • 特定の期間に発生したイベント全体像を取得できる • デバッグや性能上の問題に利用できる
Dynamic Probes • ユーザ空間とカーネル空間の任意のポイントにプローブを設置可能 • プローブの機能 • ユーザ空間に情報を報告 • レジスタを変更す • カーネルの再構築やリブートを行う必要がない