Loading arch/arm/kernel/entry-common.S +12 −0 Original line number Diff line number Diff line Loading @@ -183,12 +183,24 @@ ENDPROC(ret_from_fork) ftrace_call\suffix: bl ftrace_stub #ifdef CONFIG_FUNCTION_GRAPH_TRACER .globl ftrace_graph_call\suffix ftrace_graph_call\suffix: mov r0, r0 #endif mcount_exit .endm .macro __ftrace_graph_caller sub r0, fp, #4 @ &lr of instrumented routine (&parent) #ifdef CONFIG_DYNAMIC_FTRACE @ called from __ftrace_caller, saved in mcount_enter ldr r1, [sp, #16] @ instrumented routine (func) #else @ called from __mcount, untouched in lr mov r1, lr @ instrumented routine (func) #endif sub r1, r1, #MCOUNT_INSN_SIZE mov r2, fp @ frame pointer bl prepare_ftrace_return Loading arch/arm/kernel/ftrace.c +64 −5 Original line number Diff line number Diff line Loading @@ -60,9 +60,9 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) } #endif /* construct a branch (BL) instruction to addr */ #ifdef CONFIG_THUMB2_KERNEL static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, bool link) { unsigned long s, j1, j2, i1, i2, imm10, imm11; unsigned long first, second; Loading @@ -84,15 +84,22 @@ static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) j2 = (!i2) ^ s; first = 0xf000 | (s << 10) | imm10; second = 0xd000 | (j1 << 13) | (j2 << 11) | imm11; second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11; if (link) second |= 1 << 14; return (second << 16) | first; } #else static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, bool link) { unsigned long opcode = 0xea000000; long offset; if (link) opcode |= 1 << 24; offset = (long)addr - (long)(pc + 8); if (unlikely(offset < -33554432 || offset > 33554428)) { /* Can't generate branches that far (from ARM ARM). Ftrace Loading @@ -104,10 +111,15 @@ static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) offset = (offset >> 2) & 0x00ffffff; return 0xeb000000 | offset; return opcode | offset; } #endif static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) { return ftrace_gen_branch(pc, addr, true); } static int ftrace_modify_code(unsigned long pc, unsigned long old, unsigned long new) { Loading Loading @@ -226,4 +238,51 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, *parent = old; } } #ifdef CONFIG_DYNAMIC_FTRACE extern unsigned long ftrace_graph_call; extern unsigned long ftrace_graph_call_old; extern void ftrace_graph_caller_old(void); static int __ftrace_modify_caller(unsigned long *callsite, void (*func) (void), bool enable) { unsigned long caller_fn = (unsigned long) func; unsigned long pc = (unsigned long) callsite; unsigned long branch = ftrace_gen_branch(pc, caller_fn, false); unsigned long nop = 0xe1a00000; /* mov r0, r0 */ unsigned long old = enable ? nop : branch; unsigned long new = enable ? branch : nop; return ftrace_modify_code(pc, old, new); } static int ftrace_modify_graph_caller(bool enable) { int ret; ret = __ftrace_modify_caller(&ftrace_graph_call, ftrace_graph_caller, enable); #ifdef CONFIG_OLD_MCOUNT if (!ret) ret = __ftrace_modify_caller(&ftrace_graph_call_old, ftrace_graph_caller_old, enable); #endif return ret; } int ftrace_enable_ftrace_graph_caller(void) { return ftrace_modify_graph_caller(true); } int ftrace_disable_ftrace_graph_caller(void) { return ftrace_modify_graph_caller(false); } #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ Loading
arch/arm/kernel/entry-common.S +12 −0 Original line number Diff line number Diff line Loading @@ -183,12 +183,24 @@ ENDPROC(ret_from_fork) ftrace_call\suffix: bl ftrace_stub #ifdef CONFIG_FUNCTION_GRAPH_TRACER .globl ftrace_graph_call\suffix ftrace_graph_call\suffix: mov r0, r0 #endif mcount_exit .endm .macro __ftrace_graph_caller sub r0, fp, #4 @ &lr of instrumented routine (&parent) #ifdef CONFIG_DYNAMIC_FTRACE @ called from __ftrace_caller, saved in mcount_enter ldr r1, [sp, #16] @ instrumented routine (func) #else @ called from __mcount, untouched in lr mov r1, lr @ instrumented routine (func) #endif sub r1, r1, #MCOUNT_INSN_SIZE mov r2, fp @ frame pointer bl prepare_ftrace_return Loading
arch/arm/kernel/ftrace.c +64 −5 Original line number Diff line number Diff line Loading @@ -60,9 +60,9 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) } #endif /* construct a branch (BL) instruction to addr */ #ifdef CONFIG_THUMB2_KERNEL static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, bool link) { unsigned long s, j1, j2, i1, i2, imm10, imm11; unsigned long first, second; Loading @@ -84,15 +84,22 @@ static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) j2 = (!i2) ^ s; first = 0xf000 | (s << 10) | imm10; second = 0xd000 | (j1 << 13) | (j2 << 11) | imm11; second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11; if (link) second |= 1 << 14; return (second << 16) | first; } #else static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, bool link) { unsigned long opcode = 0xea000000; long offset; if (link) opcode |= 1 << 24; offset = (long)addr - (long)(pc + 8); if (unlikely(offset < -33554432 || offset > 33554428)) { /* Can't generate branches that far (from ARM ARM). Ftrace Loading @@ -104,10 +111,15 @@ static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) offset = (offset >> 2) & 0x00ffffff; return 0xeb000000 | offset; return opcode | offset; } #endif static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) { return ftrace_gen_branch(pc, addr, true); } static int ftrace_modify_code(unsigned long pc, unsigned long old, unsigned long new) { Loading Loading @@ -226,4 +238,51 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, *parent = old; } } #ifdef CONFIG_DYNAMIC_FTRACE extern unsigned long ftrace_graph_call; extern unsigned long ftrace_graph_call_old; extern void ftrace_graph_caller_old(void); static int __ftrace_modify_caller(unsigned long *callsite, void (*func) (void), bool enable) { unsigned long caller_fn = (unsigned long) func; unsigned long pc = (unsigned long) callsite; unsigned long branch = ftrace_gen_branch(pc, caller_fn, false); unsigned long nop = 0xe1a00000; /* mov r0, r0 */ unsigned long old = enable ? nop : branch; unsigned long new = enable ? branch : nop; return ftrace_modify_code(pc, old, new); } static int ftrace_modify_graph_caller(bool enable) { int ret; ret = __ftrace_modify_caller(&ftrace_graph_call, ftrace_graph_caller, enable); #ifdef CONFIG_OLD_MCOUNT if (!ret) ret = __ftrace_modify_caller(&ftrace_graph_call_old, ftrace_graph_caller_old, enable); #endif return ret; } int ftrace_enable_ftrace_graph_caller(void) { return ftrace_modify_graph_caller(true); } int ftrace_disable_ftrace_graph_caller(void) { return ftrace_modify_graph_caller(false); } #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */