[PATCH v6 5/7] arm64: ftrace: Add dynamic ftrace support
AKASHI Takahiro
takahiro.akashi at linaro.org
Fri Mar 14 01:28:52 EDT 2014
Thank you for you clarification, Steven.
-Takahiro AKASHI
On 03/14/2014 03:33 AM, Steven Rostedt wrote:
> On Thu, 2014-03-13 at 18:10 +0000, Will Deacon wrote:
>>
>>> +#else /* CONFIG_DYNAMIC_FTRACE */
>>> +/*
>>> + * _mcount() is used to build the kernel with -pg option, but all the branch
>>> + * instructions to _mcount() are replaced to NOP initially at kernel start up,
>>> + * and later on, NOP to branch to ftrace_caller() when enabled or branch to
>>> + * NOP when disabled per-function base.
>>> + */
>>> +ENTRY(_mcount)
>>> + ret
>>> +ENDPROC(_mcount)
>>
>> Judging by your comment then, this should never be called. Is that right? If
>> so, we could add a BUG-equivalent so we know if we missed an mcount during
>> patching.
>
> Actually, it can be called before the change to nops are done in early
> boot. This is done very early, but everything before ftrace_init() in
> init/main.c can still call _mcount.
>
>
>>> + /*
>>> + * Note:
>>> + * Due to modules and __init, code can disappear and change,
>>> + * we need to protect against faulting as well as code changing.
>>> + * We do this by aarch64_insn_*() which use the probe_kernel_*().
>>> + *
>>> + * No lock is held here because all the modifications are run
>>> + * through stop_machine().
>>> + */
>>> + if (validate) {
>>> + if (aarch64_insn_read((void *)pc, &replaced))
>>> + return -EFAULT;
>>> +
>>> + if (replaced != old)
>>> + return -EINVAL;
>>> + }
>>> + if (aarch64_insn_patch_text_nosync((void *)pc, new))
>>> + return -EPERM;
>>
>> I think you're better off propagating the errors here, rather than
>> overriding them with EFAULT/EINVAL/EPERM.
>
> The ftrace generic code expects to see these specific errors. Look at
> ftrace_bug() in kernel/trace/ftrace.c.
>
>>
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/*
>>> + * Replace tracer function in ftrace_caller()
>>> + */
>>> +int ftrace_update_ftrace_func(ftrace_func_t func)
>>> +{
>>> + unsigned long pc;
>>> + unsigned int new;
>>> +
>>> + pc = (unsigned long)&ftrace_call;
>>> + new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func, true);
>>> +
>>> + return ftrace_modify_code(pc, 0, new, false);
>>> +}
>>> +
>>> +/*
>>> + * Turn on the call to ftrace_caller() in instrumented function
>>> + */
>>> +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
>>> +{
>>> + unsigned long pc = rec->ip;
>>> + unsigned int old, new;
>>> +
>>> + old = aarch64_insn_gen_nop();
>>> + new = aarch64_insn_gen_branch_imm(pc, addr, true);
>>> +
>>> + return ftrace_modify_code(pc, old, new, true);
>>> +}
>>> +
>>> +/*
>>> + * Turn off the call to ftrace_caller() in instrumented function
>>> + */
>>> +int ftrace_make_nop(struct module *mod,
>>> + struct dyn_ftrace *rec, unsigned long addr)
>>> +{
>>> + unsigned long pc = rec->ip;
>>> + unsigned int old, new;
>>> +
>>> + old = aarch64_insn_gen_branch_imm(pc, addr, true);
>>> + new = aarch64_insn_gen_nop();
>>> +
>>> + return ftrace_modify_code(pc, old, new, true);
>>> +}
>>> +
>>> +int __init ftrace_dyn_arch_init(void *data)
>>> +{
>>> + *(unsigned long *)data = 0;
>>> +
>>> + return 0;
>>> +}
>>> +#endif /* CONFIG_DYNAMIC_FTRACE */
>>> +
>>> #ifdef CONFIG_FUNCTION_GRAPH_TRACER
>>> /*
>>> * function_graph tracer expects ftrace_return_to_handler() to be called
>>> @@ -61,4 +144,34 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
>>> return;
>>> }
>>> }
>>> +
>>> +#ifdef CONFIG_DYNAMIC_FTRACE
>>> +/*
>>> + * Turn on/off the call to ftrace_graph_caller() in ftrace_caller()
>>> + * depending on @enable.
>>> + */
>>> +static int ftrace_modify_graph_caller(bool enable)
>>> +{
>>> + unsigned long pc = (unsigned long)&ftrace_graph_call;
>>> + unsigned int branch, nop, old, new;
>>> +
>>> + branch = aarch64_insn_gen_branch_imm(pc,
>>> + (unsigned long)ftrace_graph_caller, false);
>>> + nop = aarch64_insn_gen_nop();
>>> + old = enable ? nop : branch;
>>> + new = enable ? branch : nop;
>>> +
>>> + return ftrace_modify_code(pc, old, new, true);
>>
>> You could rewrite this as:
>>
>> if (enable)
>> return ftrace_modify_code(pc, nop, branch, true);
>> else
>> return ftrace_modify_code(pc, branch, nop, true);
>>
>> which I find easier to read.
>
> Heh, maybe that could be updated in other archs too. I'll have to think
> about that one.
>
> -- Steve
>
>
More information about the linux-arm-kernel
mailing list