On Wed, 10 Jan 2018 15:38:10 +0800 Alan Kao <noner...@gmail.com> wrote:
> +static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, > + bool enable) > +{ > + unsigned int offset = (unsigned int)(target - hook_pos); > + unsigned int auipc_call = to_auipc_insn(offset); > + unsigned int jalr_call = to_jalr_insn(offset); > + unsigned int calls[2] = {auipc_call, jalr_call}; > + unsigned int nops[2] = {NOP4, NOP4}; > + int ret = 0; > + > + /* when ftrace_make_nop is called */ > + if (!enable) > + ret = ftrace_check_current_call(hook_pos, calls); > + > + if (ret) > + goto out; > + > + /* replace the auipc-jalr pair at once */ > + ret = probe_kernel_write((void *)hook_pos, enable ? calls : nops, > + MCOUNT_INSN_SIZE); > + if (ret) You don't want to return the return of probe_kernel_write() here. For ftrace bug to work properly, if a fail to write occurs, you need to return -EPERM. -- Steve > + goto out; > + > + smp_mb(); > + flush_icache_range((void *)hook_pos, (void *)hook_pos + > MCOUNT_INSN_SIZE); > + > +out: > + return ret; > +} > + > +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) > +{ > + int ret = ftrace_check_current_call(rec->ip, NULL); > + > + if (ret) > + return ret; > + > + return __ftrace_modify_call(rec->ip, addr, true); > +} > + > +int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, > + unsigned long addr) > +{ > + return __ftrace_modify_call(rec->ip, addr, false); > +} > + > +int ftrace_update_ftrace_func(ftrace_func_t func) > +{ > + int ret = __ftrace_modify_call((unsigned long)&ftrace_call, > + (unsigned long)func, true); > + if (!ret) { > + ret = __ftrace_modify_call((unsigned long)&ftrace_regs_call, > + (unsigned long)func, true); > + } > + > + return ret; > +} > + > +int __init ftrace_dyn_arch_init(void) > +{ > + return 0; > +} > +#endif