|
第5回 crashコマンドによるダンプ解析(1) |
|
|
|
helpサブコマンド |
|
今回より、crashコマンドを使用して、ダンプの解析方法を解説していきます。本講座は、ダンプの解析方法を解説するのが目的であり、crashコマンドの解説をすることが目的ではありませんので、crashコマンドの機能について網羅的に解説することはしません。crashコマンドの機能については、helpサブコマンド(以下、単にコマンド)を実行すると一覧が出てくるので参考にしてください。
|
|
|
|
helpコマンドでは、各コマンドの詳細な説明や使用例を見ることができます。本講座で出てきたコマンドについても、適宜、helpコマンドで詳細を確認するようにしてください。
|
|
|
|
|
|
カーネルのデータの内容確認 |
|
それでは、いよいよお待ちかねのダンプ解析に入ります。まず最初は、カーネルのデータの内容を確認する方法について見ていきます。
メモリの内容を見るには、rdコマンドを使用します。一例として、変数num_physpagesの値を確かめて見ましょう。変数のアドレスは、symコマンドで分かります。rdコマンドの引数には、仮想アドレスを指定します。-pオプションを使用して、物理アドレスの指定をすることも可能ですが、実際の解析において、物理アドレスの参照が必要なケースはあまり多くないと思います。rdコマンドの引数には、シンボル名を直接指定することもできます。
|
|
【 変数の値の参照例 】
crash> sym
num_physpages
c0793684 (B)
num_physpages
crash> rd c0793684
c0793684:
0003fe70
p...
crash> rd -p
0x793684
793684:
0003fe70
p...
crash> rd
num_physpages
c0793684:
0003fe70
p...
crash> |
|
|
|
|
|
|
構造体の内容 |
|
構造体の内容も見てみましょう。一例として、変数mem_mapからポイントされるpage構造体(配列の先頭要素)を見てみます。rdコマンドでワード数を指定すれば、メモリの内容をいくらでも見れます。ソースコードと照らし合わせればメンバの値が確認できます。実は、構造体の形は、わざわざソースコードを見なくてもstructコマンドで分かります。これだけでもずいぶんありがたいことですが、なんと、structコマンドでアドレスを指定すれば、メンバの値を自動的に整形して出してくれます。
|
|
|
|
筆者のように、ノートに一生懸命【図1】のような絵を描いて、16進ダンプで解析を行っていた世代の人間にとっては、ありがたすぎて涙が出てくるくらい便利です。今では、task_struct構造体のように殺人的に巨大な構造体もありますから、このような機能がなければ生きていけません。余談ですが、筆者はソースコードの解析を行う際もcrashコマンドを実行して、structコマンドを使うことがよくあります。ヘッダファイルを確認するよりもその方が楽ですから。
|
|
|
|
カーネル仮想領域 |
|
カーネルの仮想アドレスを指定して、データの内容を見てきましたが、これまでのところ、ストレートマップ領域にあるデータだけでした(すなわち、0xc0000000を引けば物理アドレスに変換できます)。カーネル仮想領域(vmalloc領域)にあるデータについても見てみましょう。下の例は、scsi_modカーネルモジュールに対するmodule構造体の内容を見てみたものです。このように問題なく見れました。
|
|
|
|
第3回の講座で解説したように、ダンプの中のデータは物理アドレスでアクセスします。つまり、crashコマンドの中で仮想アドレスから物理アドレスへの変換が行われていることを意味します。仮想アドレスから物理アドレスへの変換は、mm_struct構造体init_mmのpgdメンバが示すページテーブルを追うことによって行うことができます。init_mmは、ストレートマップ領域にあり、ページテーブルの内容は物理アドレスですから、init_mmのアドレスさえ分かっていばいいわけです。仮想アドレスから物理アドレスへの変換の様子は、vtopコマンドの出力により伺い知ることができます。
|
|
【 vtopコマンドの表示例 】
crash> struct
mm_struct.pgd
init_mm
pgd =
0xc0712000,
crash> vtop f891fa00
VIRTUAL
PHYSICAL
f891fa00
3fa54a00
PAGE DIRECTORY:
c0712000
PGD: c0712f88
=> 98f8067
PMD: c0712f88
=> 98f8067
PTE:
98f847c => 3fa54163
PAGE: 3fa54000
PTE
PHYSICAL FLAGS
3fa54163
3fa54000 (PRESENT|RW|ACCESSED|DIRTY|GLOBAL)
PAGE
PHYSICAL
MAPPING
INDEX CNT FLAGS
c97f4a80
3fa54000
-------
----- 1
c0000000
crash> |
|
|
|
|
|
|
カーネルモジュールの情報 |
|
さて、structコマンドで、構造体の内容を自動的に表示してくれることが分かりましたが、構造体の形式についてはどこから情報を得ているのでしょうか。それは、crashコマンドの引数で指定したvmlinuxの中に入っているデバッグ情報から得ています。vmlinuxはカーネル本体ですが、カーネルモジュールの情報は入っていません。カーネルモジュール内で使用されている構造体については、きちんと表示できるのでしょうか。試しにscsiドライバ(scsi_modカーネルモジュール)で使用されている構造体について見てみましょう。
|
|
crash> struct
scsi_cmnd
struct: invalid data
structure reference:
scsi_cmnd
crash> |
|
|
|
|
残念ながら、失敗しました。これは、scsi_modカーネルモジュールのデバッグ情報がないためで、当然と言えば当然の結果です。ダンプ採取時点でロードされていたカーネルモジュールの一覧は、modコマンドで得ることができます。
|
|
|
|
カーネルモジュールのデバッグ情報を得るためには、デバッグ情報付きのカーネルモジュール(すなわち、コンパイル時に-gオプション付きでビルドされたカーネルモジュール)をmodコマンドの-sオプションを使用して読み込みます。
|
|
|
|
上の【 mod -s コマンド実行例 1 】
で使用しているscsi_mod.ko.debugは、カーネルのdegubinfoパッケージ
(kernel-debuginfo-common-2.6.18-8.el5.i686.rpm、
kernel-PAE-debuginfo-2.6.18-8.el5.i686.rpm)
をインストールして得られたものです。実は、カーネルのdebuginfoパッケージがインストールされていれば、modコマンドの-Sオプションでロードされているすべてのモジュールに対して、一発で読み込みを行ってくれます。
|
|
|
|
目的のカーネルモジュールのデバッグ情報が読み込まれれば、カーネルモジュール内の構造体についてもstructコマンドで表示できるようになります。先ほど失敗したscsi_cmnd構造体についても、以下のとおりです。
|
|
crash> struct
scsi_cmnd
struct scsi_cmnd {
struct scsi_device
*device;
struct list_head
list;
struct list_head
eh_entry;
int eh_eflags;
void (*done)(struct
scsi_cmnd *);
long unsigned int
serial_number;
long unsigned int
jiffies_at_alloc;
int retries;
int allowed;
int
timeout_per_command;
unsigned char
cmd_len;
enum
dma_data_direction
sc_data_direction;
unsigned char
cmnd[16];
unsigned int
request_bufflen;
struct timer_list
eh_timeout;
void *request_buffer;
short unsigned int
use_sg;
short unsigned int
sglist_len;
unsigned int
underflow;
unsigned int
transfersize;
int resid;
struct request
*request;
unsigned char
sense_buffer[96];
void (*scsi_done)(struct
scsi_cmnd *);
struct scsi_pointer
SCp;
unsigned char *host_scribble;
int result;
unsigned char tag;
long unsigned int
pid;
}
SIZE: 280
crash> |
|
|
|
|
例えば、独自のカーネルモジュールを開発してロードしているようなケースでは、modコマンドの-sオプションで個別に読み込むことになります。crashでダンプ解析することを想定して、最初から-g付きでビルドしておくとよいでしょう。
今回は、ダンプに格納されたメモリの内容を見る方法について説明しました。基本的には、これだけ知っているだけで、ダンプを解析して障害原因の調査ができるはずです。もちろん、カーネルそのものが分かっていることは前提ではありますが。
次回は、解析作業における手間を軽減するための技を紹介していきたいと思っています。
|
|
|
|
戻る 次回へ続く |