静态ftrace

上面章节主要描述的是动态ftrace,在早期还有静态ftrace。区别主要如下:
- 动态ftrace与静态ftrace在编译参数方面静态编译使用的是参数“-pg”,而动态使用的是fpatchable-function-entry。
- 工具链使能“-pg”参数时,会在每个函数体前面插入_mcount函数。而动态ftrace会在函数入口(函数准备阶段前)插入nop指令。
- 静态ftrace插入的_mcout直到代码运行期间一直存在,而动态ftrace在不使能tracer是nop指令,动态ftrace可以动态的修改代码。
内核编译时,使能CONFIG_FUNCTION_TRACER时会启动该参数编译,在kernel目录下的Makefile可以看到。

# The arch Makefiles can override CC_FLAGS_FTRACE. We may also append it later.
ifdef CONFIG_FUNCTION_TRACER
  CC_FLAGS_FTRACE := -pg
endif

基本原理

void ftrace_stub(void)
    {
        return;
    }

    void mcount(void)
    {
        /* save any bare state needed in order to do initial checking */

        extern void (*ftrace_trace_function)(unsigned long, unsigned long);
        if (ftrace_trace_function != ftrace_stub)
            goto do_trace;
        ① 如果用户定义了trace函数,那么就跳转到do_trace,执行ftrace_trace_function。否则什么都不做,直接返回。
        /* restore any bare state */

        return;

    do_trace:

        /* save all state needed by the ABI (see paragraph above) */

        unsigned long frompc = ...;
        unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE;
        ftrace_trace_function(frompc, selfpc);
        ② 跳转执行ftrace_trace_function
        /* restore all state needed by the ABI */
    }

编译完成插桩点

静态ftrace

通过反汇编objdump -D vmlinux > log后查看_mcount被插入到了vfs_read中,插入的位置在函数准备阶段之后,函数体内容之前。系统运行时,可以使用gdb 查看汇编指令,与上面基本一致。

静态ftrace

我们接着再查看以下_mcount的实现,如下

静态ftrace