powerpc: ftrace, use create_branch

Impact: clean up

Paul Mackerras pointed out that the code to determine if the branch
can reach the destination is incorrect. Michael Ellerman suggested
to pull out the code from create_branch and use that.

Simply using create_branch is probably the best.

Reported-by: Michael Ellerman <michael@ellerman.id.au>
Reported-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Steven Rostedt 2008-11-25 14:06:19 -08:00 committed by Ingo Molnar
parent ec682cef2d
commit 0029ff8752

View file

@ -114,19 +114,9 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
*/ */
static int test_24bit_addr(unsigned long ip, unsigned long addr) static int test_24bit_addr(unsigned long ip, unsigned long addr)
{ {
long diff;
/* /* use the create_branch to verify that this offset can be branched */
* Can we get to addr from ip in 24 bits? return create_branch((unsigned int *)ip, addr, 0);
* (26 really, since we mulitply by 4 for 4 byte alignment)
*/
diff = addr - ip;
/*
* Return true if diff is less than 1 << 25
* and greater than -1 << 26.
*/
return (diff < (1 << 25)) && (diff > (-1 << 26));
} }
static int is_bl_op(unsigned int op) static int is_bl_op(unsigned int op)
@ -134,11 +124,6 @@ static int is_bl_op(unsigned int op)
return (op & 0xfc000003) == 0x48000001; return (op & 0xfc000003) == 0x48000001;
} }
static int test_offset(unsigned long offset)
{
return (offset + 0x2000000 > 0x3ffffff) || ((offset & 3) != 0);
}
static unsigned long find_bl_target(unsigned long ip, unsigned int op) static unsigned long find_bl_target(unsigned long ip, unsigned int op)
{ {
static int offset; static int offset;
@ -151,12 +136,6 @@ static unsigned long find_bl_target(unsigned long ip, unsigned int op)
return ip + (long)offset; return ip + (long)offset;
} }
static unsigned int branch_offset(unsigned long offset)
{
/* return "bl ip+offset" */
return 0x48000001 | (offset & 0x03fffffc);
}
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
static int static int
__ftrace_make_nop(struct module *mod, __ftrace_make_nop(struct module *mod,
@ -402,7 +381,6 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{ {
unsigned int op[2]; unsigned int op[2];
unsigned long ip = rec->ip; unsigned long ip = rec->ip;
unsigned long offset;
/* read where this goes */ /* read where this goes */
if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2)) if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2))
@ -424,17 +402,14 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
return -EINVAL; return -EINVAL;
} }
/* now calculate a jump to the ftrace caller trampoline */ /* create the branch to the trampoline */
offset = rec->arch.mod->arch.tramp - ip; op[0] = create_branch((unsigned int *)ip,
rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
if (test_offset(offset)) { if (!op[0]) {
printk(KERN_ERR "REL24 %li out of range!\n", printk(KERN_ERR "REL24 out of range!\n");
(long int)offset);
return -EINVAL; return -EINVAL;
} }
/* Set to "bl addr" */
op[0] = branch_offset(offset);
/* ld r2,40(r1) */ /* ld r2,40(r1) */
op[1] = 0xe8410028; op[1] = 0xe8410028;
@ -453,7 +428,6 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{ {
unsigned int op; unsigned int op;
unsigned long ip = rec->ip; unsigned long ip = rec->ip;
unsigned long offset;
/* read where this goes */ /* read where this goes */
if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE)) if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
@ -471,18 +445,14 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
return -EINVAL; return -EINVAL;
} }
/* now calculate a jump to the ftrace caller trampoline */ /* create the branch to the trampoline */
offset = rec->arch.mod->arch.tramp - ip; op = create_branch((unsigned int *)ip,
rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
if (test_offset(offset)) { if (!op) {
printk(KERN_ERR "REL24 %li out of range!\n", printk(KERN_ERR "REL24 out of range!\n");
(long int)offset);
return -EINVAL; return -EINVAL;
} }
/* Set to "bl addr" */
op = branch_offset(offset);
DEBUGP("write to %lx\n", rec->ip); DEBUGP("write to %lx\n", rec->ip);
if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))