@@ -31,6 +31,17 @@
#ifdef CONFIG_DYNAMIC_FTRACE
+#define PATCH_INSN_OR_GOTO(addr, instr, label) \
+do { \
+ int rc = patch_instruction((unsigned int *)(addr), instr); \
+ if (rc) { \
+ pr_err("%s:%d Error patching instruction at 0x%pK (%pS): %d\n", \
+ __func__, __LINE__, \
+ (void *)(addr), (void *)(addr), rc); \
+ goto label; \
+ } \
+} while (0)
+
/*
* We generally only have a single long_branch tramp and at most 2 or 3 plt
* tramps generated. But, we don't use the plt tramps currently. We also allot
@@ -78,10 +89,12 @@ ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
}
/* replace the text with the new text */
- if (patch_instruction((unsigned int *)ip, new))
- return -EPERM;
+ PATCH_INSN_OR_GOTO(ip, new, patch_err);
return 0;
+
+patch_err:
+ return -EPERM;
}
/*
@@ -204,12 +217,12 @@ __ftrace_make_nop(struct module *mod,
}
#endif /* CONFIG_MPROFILE_KERNEL */
- if (patch_instruction((unsigned int *)ip, pop)) {
- pr_err("Patching NOP failed.\n");
- return -EPERM;
- }
+ PATCH_INSN_OR_GOTO(ip, pop, patch_err);
return 0;
+
+patch_err:
+ return -EPERM;
}
#else /* !PPC64 */
@@ -276,10 +289,12 @@ __ftrace_make_nop(struct module *mod,
op = PPC_INST_NOP;
- if (patch_instruction((unsigned int *)ip, op))
- return -EPERM;
+ PATCH_INSN_OR_GOTO(ip, op, patch_err);
return 0;
+
+patch_err:
+ return -EPERM;
}
#endif /* PPC64 */
#endif /* CONFIG_MODULES */
@@ -322,7 +337,7 @@ static int add_ftrace_tramp(unsigned long tramp)
*/
static int setup_mcount_compiler_tramp(unsigned long tramp)
{
- int i, op;
+ unsigned int i, op;
unsigned long ptr;
static unsigned long ftrace_plt_tramps[NUM_FTRACE_TRAMPS];
@@ -366,16 +381,14 @@ static int setup_mcount_compiler_tramp(unsigned long tramp)
#else
ptr = ppc_global_function_entry((void *)ftrace_caller);
#endif
- if (!create_branch((void *)tramp, ptr, 0)) {
+ op = create_branch((void *)tramp, ptr, 0);
+ if (!op) {
pr_debug("%ps is not reachable from existing mcount tramp\n",
(void *)ptr);
return -1;
}
- if (patch_branch((unsigned int *)tramp, ptr, 0)) {
- pr_debug("REL24 out of range!\n");
- return -1;
- }
+ PATCH_INSN_OR_GOTO(tramp, op, patch_err);
if (add_ftrace_tramp(tramp)) {
pr_debug("No tramp locations left\n");
@@ -383,6 +396,9 @@ static int setup_mcount_compiler_tramp(unsigned long tramp)
}
return 0;
+
+patch_err:
+ return -EPERM;
}
static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)
@@ -416,12 +432,12 @@ static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)
}
}
- if (patch_instruction((unsigned int *)ip, PPC_INST_NOP)) {
- pr_err("Patching NOP failed.\n");
- return -EPERM;
- }
+ PATCH_INSN_OR_GOTO(ip, PPC_INST_NOP, patch_err);
return 0;
+
+patch_err:
+ return -EPERM;
}
int ftrace_make_nop(struct module *mod,
@@ -557,17 +573,18 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
}
/* Ensure branch is within 24 bits */
- if (!create_branch(ip, tramp, BRANCH_SET_LINK)) {
+ op[0] = create_branch(ip, tramp, BRANCH_SET_LINK);
+ if (!op[0]) {
pr_err("Branch out of range\n");
return -EINVAL;
}
- if (patch_branch(ip, tramp, BRANCH_SET_LINK)) {
- pr_err("REL24 out of range!\n");
- return -EINVAL;
- }
+ PATCH_INSN_OR_GOTO(ip, op[0], patch_err);
return 0;
+
+patch_err:
+ return -EPERM;
}
#else /* !CONFIG_PPC64: */
@@ -603,10 +620,12 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
pr_devel("write to %lx\n", rec->ip);
- if (patch_instruction((unsigned int *)ip, op))
- return -EPERM;
+ PATCH_INSN_OR_GOTO(ip, op, patch_err);
return 0;
+
+patch_err:
+ return -EPERM;
}
#endif /* CONFIG_PPC64 */
#endif /* CONFIG_MODULES */
@@ -650,12 +669,18 @@ static int __ftrace_make_call_kernel(struct dyn_ftrace *rec, unsigned long addr)
return -EINVAL;
}
- if (patch_branch(ip, tramp, BRANCH_SET_LINK)) {
- pr_err("Error patching branch to ftrace tramp!\n");
+ op = create_branch(ip, tramp, BRANCH_SET_LINK);
+ if (!op) {
+ pr_err("Branch out of range\n");
return -EINVAL;
}
+ PATCH_INSN_OR_GOTO(ip, op, patch_err);
+
return 0;
+
+patch_err:
+ return -EPERM;
}
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
@@ -748,10 +773,8 @@ __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
/* The new target may be within range */
if (test_24bit_addr(ip, addr)) {
/* within range */
- if (patch_branch((unsigned int *)ip, addr, BRANCH_SET_LINK)) {
- pr_err("REL24 out of range!\n");
- return -EINVAL;
- }
+ op = create_branch((unsigned int *)ip, addr, BRANCH_SET_LINK);
+ PATCH_INSN_OR_GOTO(ip, op, patch_err);
return 0;
}
@@ -776,17 +799,18 @@ __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
}
/* Ensure branch is within 24 bits */
- if (!create_branch((unsigned int *)ip, tramp, BRANCH_SET_LINK)) {
+ op = create_branch((unsigned int *)ip, tramp, BRANCH_SET_LINK);
+ if (!op) {
pr_err("Branch out of range\n");
return -EINVAL;
}
- if (patch_branch((unsigned int *)ip, tramp, BRANCH_SET_LINK)) {
- pr_err("REL24 out of range!\n");
- return -EINVAL;
- }
+ PATCH_INSN_OR_GOTO(ip, op, patch_err);
return 0;
+
+patch_err:
+ return -EPERM;
}
#endif
Introduce a macro PATCH_INSN_OR_GOTO() to simplify instruction patching, and to make the error messages more uniform and useful: - print an error message that includes the original return value - print the function name and line numbers, so that the offending location is clear - goto a label which always return -EPERM, which ftrace_bug() expects for proper error handling Also eliminate use of patch_branch() since most such uses already call create_branch() for error checking before patching. Instead, use the return value from create_branch() with PATCH_INSN_OR_GOTO(). Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> --- arch/powerpc/kernel/trace/ftrace.c | 96 +++++++++++++++++++----------- 1 file changed, 60 insertions(+), 36 deletions(-)