Commit b05086c7 authored by Steven Rostedt (Red Hat)'s avatar Steven Rostedt (Red Hat) Committed by Steven Rostedt

ftrace: Add variable ftrace_expected for archs to show expected code

When an anomaly is found while modifying function code, ftrace_bug() is
called which disables the function tracing infrastructure and reports
information about what failed. If the code that is to be replaced does not
match what is expected, then actual code is shown. Currently there is no
arch generic way to show what was expected.

Add a new variable pointer calld ftrace_expected that the arch code can set
to point to what it expected so that ftrace_bug() can report the actual text
as well as the text that was expected to be there.
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 02a392a0
...@@ -105,6 +105,8 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code, ...@@ -105,6 +105,8 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code,
{ {
unsigned char replaced[MCOUNT_INSN_SIZE]; unsigned char replaced[MCOUNT_INSN_SIZE];
ftrace_expected = old_code;
/* /*
* Note: Due to modules and __init, code can * Note: Due to modules and __init, code can
* disappear and change, we need to protect against faulting * disappear and change, we need to protect against faulting
...@@ -154,6 +156,8 @@ int ftrace_make_nop(struct module *mod, ...@@ -154,6 +156,8 @@ int ftrace_make_nop(struct module *mod,
if (addr == MCOUNT_ADDR) if (addr == MCOUNT_ADDR)
return ftrace_modify_code_direct(rec->ip, old, new); return ftrace_modify_code_direct(rec->ip, old, new);
ftrace_expected = NULL;
/* Normal cases use add_brk_on_nop */ /* Normal cases use add_brk_on_nop */
WARN_ONCE(1, "invalid use of ftrace_make_nop"); WARN_ONCE(1, "invalid use of ftrace_make_nop");
return -EINVAL; return -EINVAL;
...@@ -220,6 +224,7 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, ...@@ -220,6 +224,7 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
unsigned long addr) unsigned long addr)
{ {
WARN_ON(1); WARN_ON(1);
ftrace_expected = NULL;
return -EINVAL; return -EINVAL;
} }
...@@ -314,6 +319,8 @@ static int add_break(unsigned long ip, const char *old) ...@@ -314,6 +319,8 @@ static int add_break(unsigned long ip, const char *old)
if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
return -EFAULT; return -EFAULT;
ftrace_expected = old;
/* Make sure it is what we expect it to be */ /* Make sure it is what we expect it to be */
if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0) if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0)
return -EINVAL; return -EINVAL;
...@@ -413,6 +420,8 @@ static int remove_breakpoint(struct dyn_ftrace *rec) ...@@ -413,6 +420,8 @@ static int remove_breakpoint(struct dyn_ftrace *rec)
ftrace_addr = ftrace_get_addr_curr(rec); ftrace_addr = ftrace_get_addr_curr(rec);
nop = ftrace_call_replace(ip, ftrace_addr); nop = ftrace_call_replace(ip, ftrace_addr);
ftrace_expected = nop;
if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0) if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
return -EINVAL; return -EINVAL;
} }
......
...@@ -305,6 +305,12 @@ enum ftrace_bug_type { ...@@ -305,6 +305,12 @@ enum ftrace_bug_type {
}; };
extern enum ftrace_bug_type ftrace_bug_type; extern enum ftrace_bug_type ftrace_bug_type;
/*
* Archs can set this to point to a variable that holds the value that was
* expected at the call site before calling ftrace_bug().
*/
extern const void *ftrace_expected;
void ftrace_bug(int err, struct dyn_ftrace *rec); void ftrace_bug(int err, struct dyn_ftrace *rec);
struct seq_file; struct seq_file;
......
...@@ -1940,7 +1940,7 @@ static int ftrace_hash_ipmodify_update(struct ftrace_ops *ops, ...@@ -1940,7 +1940,7 @@ static int ftrace_hash_ipmodify_update(struct ftrace_ops *ops,
return __ftrace_hash_update_ipmodify(ops, old_hash, new_hash); return __ftrace_hash_update_ipmodify(ops, old_hash, new_hash);
} }
static void print_ip_ins(const char *fmt, unsigned char *p) static void print_ip_ins(const char *fmt, const unsigned char *p)
{ {
int i; int i;
...@@ -1954,6 +1954,7 @@ static struct ftrace_ops * ...@@ -1954,6 +1954,7 @@ static struct ftrace_ops *
ftrace_find_tramp_ops_any(struct dyn_ftrace *rec); ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
enum ftrace_bug_type ftrace_bug_type; enum ftrace_bug_type ftrace_bug_type;
const void *ftrace_expected;
static void print_bug_type(void) static void print_bug_type(void)
{ {
...@@ -2003,6 +2004,10 @@ void ftrace_bug(int failed, struct dyn_ftrace *rec) ...@@ -2003,6 +2004,10 @@ void ftrace_bug(int failed, struct dyn_ftrace *rec)
print_ip_sym(ip); print_ip_sym(ip);
print_ip_ins(" actual: ", (unsigned char *)ip); print_ip_ins(" actual: ", (unsigned char *)ip);
pr_cont("\n"); pr_cont("\n");
if (ftrace_expected) {
print_ip_ins(" expected: ", ftrace_expected);
pr_cont("\n");
}
break; break;
case -EPERM: case -EPERM:
FTRACE_WARN_ON_ONCE(1); FTRACE_WARN_ON_ONCE(1);
......
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