diff options
| -rw-r--r-- | arch/x86/kernel/ftrace.c | 9 | ||||
| -rw-r--r-- | include/linux/ftrace.h | 6 | ||||
| -rw-r--r-- | kernel/trace/ftrace.c | 9 | 
3 files changed, 22 insertions, 2 deletions
| diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 311bcf338f07..909da012406d 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -105,6 +105,8 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code,  {  	unsigned char replaced[MCOUNT_INSN_SIZE]; +	ftrace_expected = old_code; +  	/*  	 * Note: Due to modules and __init, code can  	 *  disappear and change, we need to protect against faulting @@ -154,6 +156,8 @@ int ftrace_make_nop(struct module *mod,  	if (addr == MCOUNT_ADDR)  		return ftrace_modify_code_direct(rec->ip, old, new); +	ftrace_expected = NULL; +  	/* Normal cases use add_brk_on_nop */  	WARN_ONCE(1, "invalid use of ftrace_make_nop");  	return -EINVAL; @@ -220,6 +224,7 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,  				 unsigned long addr)  {  	WARN_ON(1); +	ftrace_expected = NULL;  	return -EINVAL;  } @@ -314,6 +319,8 @@ static int add_break(unsigned long ip, const char *old)  	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))  		return -EFAULT; +	ftrace_expected = old; +  	/* Make sure it is what we expect it to be */  	if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0)  		return -EINVAL; @@ -413,6 +420,8 @@ static int remove_breakpoint(struct dyn_ftrace *rec)  		ftrace_addr = ftrace_get_addr_curr(rec);  		nop = ftrace_call_replace(ip, ftrace_addr); +		ftrace_expected = nop; +  		if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)  			return -EINVAL;  	} diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 870c8eea38cd..134f8d45b35b 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -305,6 +305,12 @@ enum 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);  struct seq_file; diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index b95efcac9dfe..7870c03b4c4d 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1940,7 +1940,7 @@ static int ftrace_hash_ipmodify_update(struct ftrace_ops *ops,  	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; @@ -1954,6 +1954,7 @@ static struct ftrace_ops *  ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);  enum ftrace_bug_type ftrace_bug_type; +const void *ftrace_expected;  static void print_bug_type(void)  { @@ -2001,8 +2002,12 @@ void ftrace_bug(int failed, struct dyn_ftrace *rec)  		FTRACE_WARN_ON_ONCE(1);  		pr_info("ftrace failed to modify ");  		print_ip_sym(ip); -		print_ip_ins(" actual: ", (unsigned char *)ip); +		print_ip_ins(" actual:   ", (unsigned char *)ip);  		pr_cont("\n"); +		if (ftrace_expected) { +			print_ip_ins(" expected: ", ftrace_expected); +			pr_cont("\n"); +		}  		break;  	case -EPERM:  		FTRACE_WARN_ON_ONCE(1); | 
