Hatena::ブログ(Diary)

へにゃぺんて@日々勉強のまとめ

2015-09-06

Kprobesの使い方

Kprobesは、レジスタ情報ダンプなど任意の処理を、アセンブラの命令単位で実行できる機能です。


利用するにはカーネルモジュールを作成する必要はありますが、

カーネルの再ビルド無しで、カーネル内のすべての命令をデバッグできます。




なお以降の説明は、Linux 3.14.51で確認したものです。

また、debugfsのマウントポイントを<debugfs>で略記しています。


◆ 参考: debugfsのマウント方法

(マウントポイント /sys/kernel/debug の場合)

sudo mount -t debugfs none /sys/kernel/debug

カーネルコンフィギュレーション

以下を有効化してください。

  • General setup
    • [*] Kprobes <- 有効化

また、カーネルソース内にKprobesのサンプルコードがあります。

これもカーネルビルド時にビルドされるよう、有効化します。

  • Kernel hacking
    • [*] Sample kernel code <- 有効化
        • <M> Build kprobes examples -- loadable modules only <- 有効化

Kprobesの使い方

Kprobesを使用するために行うことは以下の2つです。

1. kprobe構造体の変数を定義して値を設定

2. 1.で定義した変数をregister_kprobe関数でKprobesの枠組みに登録


1. で以下の情報をkprobe構造体に登録することで、任意の命令で任意の処理を行わせることができます。

  • デバッグ対象の命令
  • デバッグ対象の命令に到達した時、呼ばれるハンドラのアドレス
    • 「命令実行前」・「命令実行後」・「fault時」の3つを指定できる

上述したとおり、サンプルコードがありますので、

ここではサンプルコードを参照しながら説明します。


◆ サンプルコードの場所


まず、サンプルコードが何をするものかというと、

システムコール"fork"の処理を行うdo_fork関数の最初の命令をデバッグ対象として、

この命令の実行前・実行後・fault時に、レジスタ情報とアドレスをダンプさせています。


サンプルコードでkprobeの定義と登録を行っている箇所は以下のとおりです。

/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
	.symbol_name	= "do_fork",
};

static int __init kprobe_init(void)
{
	int ret;
	kp.pre_handler = handler_pre;
	kp.post_handler = handler_post;
	kp.fault_handler = handler_fault;

	ret = register_kprobe(&kp);
	if (ret < 0) {
		printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
		return ret;
	}
	printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);
	return 0;
}

まず、kprobe構造体のグローバル変数kpの定義で、

symbol_nameに初期値として"do_fork"を設定しており、

オフセット(offsetメンバー)には何も設定していないので、

do_fork関数の最初の命令がKprobeの対象となります。


そして、モジュールのinit処理(kprobe_init関数)で、

  • pre_handler : 命令実行前ハンドラ
  • post_handler : 命令実行後ハンドラ
  • fault_handler : faultハンドラ

関数ポインタを設定しています。


"handler_pre"、"handler_post"、"handler_fault"は関数として

サンプルコード内で定義されています。


サンプルコードでのこれらのハンドラ内の処理は、

どれも「printk()でアドレスとレジスタ情報ダンプ」のみなので、

命令実行前ハンドラの"handler_pre"のみ紹介します。

/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
	printk(KERN_INFO "pre_handler: p->addr = 0x%p, ip = %lx,"
			" flags = 0x%lx\n",
		p->addr, regs->ip, regs->flags);

	/* A dump_stack() here will give a stack backtrace */
	return 0;
}

アーキテクチャ判別のifdefと、x86以外の処理は削除しました


ハンドラには

引数で渡されます。

サンプルコードでは、これらの情報をダンプしています。


カーネルビルド時にサンプルコードのカーネルモジュールは、

以下の場所に生成されます。


このカーネルモジュールをinsmodでカーネルインストールすれば、

今回のKprobesを使用したサンプルの動作を確認できます。

$ sudo insmod kprobe_example.ko

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/cupnes/20150906/1441494952
リンク元