Loading arch/sh/kernel/ftrace.c +30 −30 Original line number Original line Diff line number Diff line /* /* * Copyright (C) 2008 Matt Fleming <mjf@gentoo.org> * Copyright (C) 2008 Matt Fleming <matt@console-pimps.org> * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org> * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org> * * * Code for replacing ftrace calls with jumps. * Code for replacing ftrace calls with jumps. Loading @@ -19,29 +19,36 @@ #include <asm/ftrace.h> #include <asm/ftrace.h> #include <asm/cacheflush.h> #include <asm/cacheflush.h> static unsigned char ftrace_nop[] = { 0x09, 0x00, /* nop */ 0x09, 0x00, /* nop */ }; static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE]; static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE]; unsigned char *ftrace_nop_replace(void) static unsigned char ftrace_nop[4]; /* * If we're trying to nop out a call to a function, we instead * place a call to the address after the memory table. * * 8c011060 <a>: * 8c011060: 02 d1 mov.l 8c01106c <a+0xc>,r1 * 8c011062: 22 4f sts.l pr,@-r15 * 8c011064: 02 c7 mova 8c011070 <a+0x10>,r0 * 8c011066: 2b 41 jmp @r1 * 8c011068: 2a 40 lds r0,pr * 8c01106a: 09 00 nop * 8c01106c: 68 24 .word 0x2468 <--- ip * 8c01106e: 1d 8c .word 0x8c1d * 8c011070: 26 4f lds.l @r15+,pr <--- ip + MCOUNT_INSN_SIZE * * We write 0x8c011070 to 0x8c01106c so that on entry to a() we branch * past the _mcount call and continue executing code like normal. */ static unsigned char *ftrace_nop_replace(unsigned long ip) { { __raw_writel(ip + MCOUNT_INSN_SIZE, ftrace_nop); return ftrace_nop; return ftrace_nop; } } static int is_sh_nop(unsigned char *ip) static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) { return strncmp(ip, ftrace_nop, sizeof(ftrace_nop)); } unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) { { /* Place the address in the memory table. */ /* Place the address in the memory table. */ if (addr == CALLER_ADDR) __raw_writel(addr + MCOUNT_INSN_OFFSET, ftrace_replaced_code); else __raw_writel(addr, ftrace_replaced_code); __raw_writel(addr, ftrace_replaced_code); /* /* Loading @@ -51,7 +58,7 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) return ftrace_replaced_code; return ftrace_replaced_code; } } int ftrace_modify_code(unsigned long ip, unsigned char *old_code, static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, unsigned char *new_code) unsigned char *new_code) { { unsigned char replaced[MCOUNT_INSN_SIZE]; unsigned char replaced[MCOUNT_INSN_SIZE]; Loading @@ -66,13 +73,6 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code, * kstop_machine, or before SMP starts. * kstop_machine, or before SMP starts. */ */ /* * If we're trying to nop out a call to a function, we instead * place a call to the address after the memory table. */ if (is_sh_nop(new_code) == 0) __raw_writel(ip + MCOUNT_INSN_SIZE, (unsigned long)new_code); /* read the text we want to modify */ /* read the text we want to modify */ if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) return -EFAULT; return -EFAULT; Loading @@ -92,13 +92,13 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code, int ftrace_update_ftrace_func(ftrace_func_t func) int ftrace_update_ftrace_func(ftrace_func_t func) { { unsigned long ip = (unsigned long)(&ftrace_call); unsigned long ip = (unsigned long)(&ftrace_call) + MCOUNT_INSN_OFFSET; unsigned char old[MCOUNT_INSN_SIZE], *new; unsigned char old[MCOUNT_INSN_SIZE], *new; memcpy(old, (unsigned char *)(ip + MCOUNT_INSN_OFFSET), MCOUNT_INSN_SIZE); memcpy(old, (unsigned char *)ip, MCOUNT_INSN_SIZE); new = ftrace_call_replace(ip, (unsigned long)func); new = ftrace_call_replace(ip, (unsigned long)func); return ftrace_modify_code(ip + MCOUNT_INSN_OFFSET, old, new); return ftrace_modify_code(ip, old, new); } } int ftrace_make_nop(struct module *mod, int ftrace_make_nop(struct module *mod, Loading @@ -108,7 +108,7 @@ int ftrace_make_nop(struct module *mod, unsigned long ip = rec->ip; unsigned long ip = rec->ip; old = ftrace_call_replace(ip, addr); old = ftrace_call_replace(ip, addr); new = ftrace_nop_replace(); new = ftrace_nop_replace(ip); return ftrace_modify_code(rec->ip, old, new); return ftrace_modify_code(rec->ip, old, new); } } Loading @@ -118,7 +118,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) unsigned char *new, *old; unsigned char *new, *old; unsigned long ip = rec->ip; unsigned long ip = rec->ip; old = ftrace_nop_replace(); old = ftrace_nop_replace(ip); new = ftrace_call_replace(ip, addr); new = ftrace_call_replace(ip, addr); return ftrace_modify_code(rec->ip, old, new); return ftrace_modify_code(rec->ip, old, new); Loading Loading
arch/sh/kernel/ftrace.c +30 −30 Original line number Original line Diff line number Diff line /* /* * Copyright (C) 2008 Matt Fleming <mjf@gentoo.org> * Copyright (C) 2008 Matt Fleming <matt@console-pimps.org> * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org> * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org> * * * Code for replacing ftrace calls with jumps. * Code for replacing ftrace calls with jumps. Loading @@ -19,29 +19,36 @@ #include <asm/ftrace.h> #include <asm/ftrace.h> #include <asm/cacheflush.h> #include <asm/cacheflush.h> static unsigned char ftrace_nop[] = { 0x09, 0x00, /* nop */ 0x09, 0x00, /* nop */ }; static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE]; static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE]; unsigned char *ftrace_nop_replace(void) static unsigned char ftrace_nop[4]; /* * If we're trying to nop out a call to a function, we instead * place a call to the address after the memory table. * * 8c011060 <a>: * 8c011060: 02 d1 mov.l 8c01106c <a+0xc>,r1 * 8c011062: 22 4f sts.l pr,@-r15 * 8c011064: 02 c7 mova 8c011070 <a+0x10>,r0 * 8c011066: 2b 41 jmp @r1 * 8c011068: 2a 40 lds r0,pr * 8c01106a: 09 00 nop * 8c01106c: 68 24 .word 0x2468 <--- ip * 8c01106e: 1d 8c .word 0x8c1d * 8c011070: 26 4f lds.l @r15+,pr <--- ip + MCOUNT_INSN_SIZE * * We write 0x8c011070 to 0x8c01106c so that on entry to a() we branch * past the _mcount call and continue executing code like normal. */ static unsigned char *ftrace_nop_replace(unsigned long ip) { { __raw_writel(ip + MCOUNT_INSN_SIZE, ftrace_nop); return ftrace_nop; return ftrace_nop; } } static int is_sh_nop(unsigned char *ip) static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) { return strncmp(ip, ftrace_nop, sizeof(ftrace_nop)); } unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) { { /* Place the address in the memory table. */ /* Place the address in the memory table. */ if (addr == CALLER_ADDR) __raw_writel(addr + MCOUNT_INSN_OFFSET, ftrace_replaced_code); else __raw_writel(addr, ftrace_replaced_code); __raw_writel(addr, ftrace_replaced_code); /* /* Loading @@ -51,7 +58,7 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) return ftrace_replaced_code; return ftrace_replaced_code; } } int ftrace_modify_code(unsigned long ip, unsigned char *old_code, static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, unsigned char *new_code) unsigned char *new_code) { { unsigned char replaced[MCOUNT_INSN_SIZE]; unsigned char replaced[MCOUNT_INSN_SIZE]; Loading @@ -66,13 +73,6 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code, * kstop_machine, or before SMP starts. * kstop_machine, or before SMP starts. */ */ /* * If we're trying to nop out a call to a function, we instead * place a call to the address after the memory table. */ if (is_sh_nop(new_code) == 0) __raw_writel(ip + MCOUNT_INSN_SIZE, (unsigned long)new_code); /* read the text we want to modify */ /* read the text we want to modify */ if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) return -EFAULT; return -EFAULT; Loading @@ -92,13 +92,13 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code, int ftrace_update_ftrace_func(ftrace_func_t func) int ftrace_update_ftrace_func(ftrace_func_t func) { { unsigned long ip = (unsigned long)(&ftrace_call); unsigned long ip = (unsigned long)(&ftrace_call) + MCOUNT_INSN_OFFSET; unsigned char old[MCOUNT_INSN_SIZE], *new; unsigned char old[MCOUNT_INSN_SIZE], *new; memcpy(old, (unsigned char *)(ip + MCOUNT_INSN_OFFSET), MCOUNT_INSN_SIZE); memcpy(old, (unsigned char *)ip, MCOUNT_INSN_SIZE); new = ftrace_call_replace(ip, (unsigned long)func); new = ftrace_call_replace(ip, (unsigned long)func); return ftrace_modify_code(ip + MCOUNT_INSN_OFFSET, old, new); return ftrace_modify_code(ip, old, new); } } int ftrace_make_nop(struct module *mod, int ftrace_make_nop(struct module *mod, Loading @@ -108,7 +108,7 @@ int ftrace_make_nop(struct module *mod, unsigned long ip = rec->ip; unsigned long ip = rec->ip; old = ftrace_call_replace(ip, addr); old = ftrace_call_replace(ip, addr); new = ftrace_nop_replace(); new = ftrace_nop_replace(ip); return ftrace_modify_code(rec->ip, old, new); return ftrace_modify_code(rec->ip, old, new); } } Loading @@ -118,7 +118,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) unsigned char *new, *old; unsigned char *new, *old; unsigned long ip = rec->ip; unsigned long ip = rec->ip; old = ftrace_nop_replace(); old = ftrace_nop_replace(ip); new = ftrace_call_replace(ip, addr); new = ftrace_call_replace(ip, addr); return ftrace_modify_code(rec->ip, old, new); return ftrace_modify_code(rec->ip, old, new); Loading