読者です 読者をやめる 読者になる 読者になる

テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

kpatchの仕組み

この前のYLUGで日立の平松氏が以下のような発表をしていた. 彼は今kpatchに注目している.

http://www.slideshare.net/mhiramat/ylug-110th-reading-kpatch

kpatchはftraceの機能を使っている. kpatchは「関数を, 修正済関数に実行時に置き換える」機能を提供する.

完全に理解したわけではないが, 理解を適当に列挙する.

  • ftrace_opsのフラグになんちゃらREGSを設定すると, 「pt_regsを使うコールバックにジャンプせよ」ということになる. FTRACE_REGS_ADDRにこのアドレスが入っている. アドレスには, ftrace_regs_callerという関数がある.

  • 以下のコードは, x86のものであり, 何をしているのかどこで呼ばれるのかも分からないが, コメントだけは役に立つので抜粋した. 共通部のコードでは, __ftrace_replace_codeの中で, REGSが指定されているかどうかでftrace_modify_callを呼ぶアドレスを決定している.

/*
 * If the record has the FTRACE_FL_REGS set, that means that it
 * wants to convert to a callback that saves all regs. If FTRACE_FL_REGS
 * is not not set, then it wants to convert to the normal callback.
 */
static unsigned long get_ftrace_addr(struct dyn_ftrace *rec)
{
        if (rec->flags & FTRACE_FL_REGS)
                return (unsigned long)FTRACE_REGS_ADDR;
        else
                return (unsigned long)FTRACE_ADDR;
}
  • たぶん, ftrace_opsっていうのは, mcountから飛んだ先で呼ばれるftraceの共通部の処理であろう.
  • kpatchは, ftrace_opsのfunc部分で, pt_regsに新しいアドレスを保存する. これがkpatch_ftrace_handler
  • ftrace_regs_callerでまずpt_regsがレジスタに保存され, ftrace_regs_callが呼ばれる. ここでpt_regsに格納されている新しいアドレスを使ってスタック上に戻り番地を上書きする(古い関数は二度と呼ばないようにするため).

まとめ

  1. mcountからftraceの世界にジャンプする.
  2. そこでftrace_opsの情報に応じて関数単位の書換を行う.
  3. kpatchは, REGSを指定してftraceの「pt_regsを使ったアドレス書換処理」を利用することによって, ftraceの世界を抜けたあとに新しい関数に飛ぶ.
  4. (ちなみに)(たぶん)通常はftrace_callが呼ばれて, トレース収集が行われる. こちらは戻り番地書換でなくて, call命令(kpatchを当てたわけではなくて, 今ある関数に戻らないといけない).

ftrace_callerとftrace_callの実装はこんな感じ(x86/kernel/entry_64.S)

NTRY(ftrace_caller)
        /* Check if tracing was disabled (quick check) */
        cmpl $0, function_trace_stop
        jne  ftrace_stub

        ftrace_caller_setup
        /* regs go into 4th parameter (but make it NULL) */
        movq $0, %rcx

GLOBAL(ftrace_call)
        call ftrace_stub

        MCOUNT_RESTORE_FRAME
ftrace_return:

ということでftrace/kpatchマスターとなった.

広告を非表示にする