Commit 24a1bdc3 authored by Anton Blanchard's avatar Anton Blanchard

powerpc/ftrace: Fix ABIv2 issues with __ftrace_make_call

__ftrace_make_call assumed ABIv1 TOC stack offsets, so it
broke on ABIv2.

While we are here, we can simplify the instruction modification
code. Since we always update one instruction there is no need to
probe_kernel_write and flush_icache_range, just use patch_branch.
Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
parent 62c9da6a
...@@ -292,19 +292,24 @@ static int ...@@ -292,19 +292,24 @@ static int
__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{ {
unsigned int op[2]; unsigned int op[2];
unsigned long ip = rec->ip; void *ip = (void *)rec->ip;
/* read where this goes */ /* read where this goes */
if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2)) if (probe_kernel_read(op, ip, sizeof(op)))
return -EFAULT; return -EFAULT;
/* /*
* It should be pointing to two nops or * We expect to see:
* b +8; ld r2,40(r1) *
* b +8
* ld r2,XX(r1)
*
* The load offset is different depending on the ABI. For simplicity
* just mask it out when doing the compare.
*/ */
if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) && if ((op[0] != 0x48000008) || ((op[1] & 0xffff00000) != 0xe8410000)) {
((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) { printk(KERN_ERR "Unexpected call sequence: %x %x\n",
printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]); op[0], op[1]);
return -EINVAL; return -EINVAL;
} }
...@@ -314,23 +319,16 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ...@@ -314,23 +319,16 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
return -EINVAL; return -EINVAL;
} }
/* create the branch to the trampoline */ /* Ensure branch is within 24 bits */
op[0] = create_branch((unsigned int *)ip, if (create_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
rec->arch.mod->arch.tramp, BRANCH_SET_LINK); printk(KERN_ERR "Branch out of range");
if (!op[0]) {
printk(KERN_ERR "REL24 out of range!\n");
return -EINVAL; return -EINVAL;
} }
/* ld r2,40(r1) */ if (patch_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
op[1] = 0xe8410028; printk(KERN_ERR "REL24 out of range!\n");
return -EINVAL;
pr_devel("write to %lx\n", rec->ip); }
if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2))
return -EPERM;
flush_icache_range(ip, ip + 8);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment