aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-10-24 17:56:04 -0400
committerSteven Rostedt <rostedt@goodmis.org>2014-11-11 12:42:13 -0500
commit4fd3279b48605ae3ea509b9b2c02e46aa0975930 (patch)
treef2f16efc4dab8233fe7285b764bde556d65dcde2
parent12cce594fa8f12e002e7eb5d10141853c1e6a112 (diff)
ftrace: Add more information to ftrace_bug() output
With the introduction of the dynamic trampolines, it is useful that if things go wrong that ftrace_bug() produces more information about what the current state is. This can help debug issues that may arise. Ftrace has lots of checks to make sure that the state of the system it touchs is exactly what it expects it to be. When it detects an abnormality it calls ftrace_bug() and disables itself to prevent any further damage. It is crucial that ftrace_bug() produces sufficient information that can be used to debug the situation. Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Borislav Petkov <bp@suse.de> Tested-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Tested-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--arch/powerpc/kernel/ftrace.c2
-rw-r--r--arch/x86/kernel/ftrace.c2
-rw-r--r--include/linux/ftrace.h4
-rw-r--r--kernel/trace/ftrace.c38
4 files changed, 34 insertions, 12 deletions
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 390311c0f03d..e66af6d265e8 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -449,7 +449,7 @@ void ftrace_replace_code(int enable)
449 rec = ftrace_rec_iter_record(iter); 449 rec = ftrace_rec_iter_record(iter);
450 ret = __ftrace_replace_code(rec, enable); 450 ret = __ftrace_replace_code(rec, enable);
451 if (ret) { 451 if (ret) {
452 ftrace_bug(ret, rec->ip); 452 ftrace_bug(ret, rec);
453 return; 453 return;
454 } 454 }
455 } 455 }
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 4cfeca6ffe11..1aea94d336c7 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -583,7 +583,7 @@ void ftrace_replace_code(int enable)
583 583
584 remove_breakpoints: 584 remove_breakpoints:
585 pr_warn("Failed on %s (%d):\n", report, count); 585 pr_warn("Failed on %s (%d):\n", report, count);
586 ftrace_bug(ret, rec ? rec->ip : 0); 586 ftrace_bug(ret, rec);
587 for_ftrace_rec_iter(iter) { 587 for_ftrace_rec_iter(iter) {
588 rec = ftrace_rec_iter_record(iter); 588 rec = ftrace_rec_iter_record(iter);
589 /* 589 /*
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 06e3ca5a5083..619e37cc17fd 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -263,7 +263,9 @@ struct ftrace_func_command {
263int ftrace_arch_code_modify_prepare(void); 263int ftrace_arch_code_modify_prepare(void);
264int ftrace_arch_code_modify_post_process(void); 264int ftrace_arch_code_modify_post_process(void);
265 265
266void ftrace_bug(int err, unsigned long ip); 266struct dyn_ftrace;
267
268void ftrace_bug(int err, struct dyn_ftrace *rec);
267 269
268struct seq_file; 270struct seq_file;
269 271
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index eab3123a1fbe..4043332f6720 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1738,10 +1738,13 @@ static void print_ip_ins(const char *fmt, unsigned char *p)
1738 printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]); 1738 printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
1739} 1739}
1740 1740
1741static struct ftrace_ops *
1742ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
1743
1741/** 1744/**
1742 * ftrace_bug - report and shutdown function tracer 1745 * ftrace_bug - report and shutdown function tracer
1743 * @failed: The failed type (EFAULT, EINVAL, EPERM) 1746 * @failed: The failed type (EFAULT, EINVAL, EPERM)
1744 * @ip: The address that failed 1747 * @rec: The record that failed
1745 * 1748 *
1746 * The arch code that enables or disables the function tracing 1749 * The arch code that enables or disables the function tracing
1747 * can call ftrace_bug() when it has detected a problem in 1750 * can call ftrace_bug() when it has detected a problem in
@@ -1750,8 +1753,10 @@ static void print_ip_ins(const char *fmt, unsigned char *p)
1750 * EINVAL - if what is read at @ip is not what was expected 1753 * EINVAL - if what is read at @ip is not what was expected
1751 * EPERM - if the problem happens on writting to the @ip address 1754 * EPERM - if the problem happens on writting to the @ip address
1752 */ 1755 */
1753void ftrace_bug(int failed, unsigned long ip) 1756void ftrace_bug(int failed, struct dyn_ftrace *rec)
1754{ 1757{
1758 unsigned long ip = rec ? rec->ip : 0;
1759
1755 switch (failed) { 1760 switch (failed) {
1756 case -EFAULT: 1761 case -EFAULT:
1757 FTRACE_WARN_ON_ONCE(1); 1762 FTRACE_WARN_ON_ONCE(1);
@@ -1763,7 +1768,7 @@ void ftrace_bug(int failed, unsigned long ip)
1763 pr_info("ftrace failed to modify "); 1768 pr_info("ftrace failed to modify ");
1764 print_ip_sym(ip); 1769 print_ip_sym(ip);
1765 print_ip_ins(" actual: ", (unsigned char *)ip); 1770 print_ip_ins(" actual: ", (unsigned char *)ip);
1766 printk(KERN_CONT "\n"); 1771 pr_cont("\n");
1767 break; 1772 break;
1768 case -EPERM: 1773 case -EPERM:
1769 FTRACE_WARN_ON_ONCE(1); 1774 FTRACE_WARN_ON_ONCE(1);
@@ -1775,6 +1780,24 @@ void ftrace_bug(int failed, unsigned long ip)
1775 pr_info("ftrace faulted on unknown error "); 1780 pr_info("ftrace faulted on unknown error ");
1776 print_ip_sym(ip); 1781 print_ip_sym(ip);
1777 } 1782 }
1783 if (rec) {
1784 struct ftrace_ops *ops = NULL;
1785
1786 pr_info("ftrace record flags: %lx\n", rec->flags);
1787 pr_cont(" (%ld)%s", ftrace_rec_count(rec),
1788 rec->flags & FTRACE_FL_REGS ? " R" : " ");
1789 if (rec->flags & FTRACE_FL_TRAMP_EN) {
1790 ops = ftrace_find_tramp_ops_any(rec);
1791 if (ops)
1792 pr_cont("\ttramp: %pS",
1793 (void *)ops->trampoline);
1794 else
1795 pr_cont("\ttramp: ERROR!");
1796
1797 }
1798 ip = ftrace_get_addr_curr(rec);
1799 pr_cont(" expected tramp: %lx\n", ip);
1800 }
1778} 1801}
1779 1802
1780static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update) 1803static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
@@ -2097,7 +2120,7 @@ void __weak ftrace_replace_code(int enable)
2097 do_for_each_ftrace_rec(pg, rec) { 2120 do_for_each_ftrace_rec(pg, rec) {
2098 failed = __ftrace_replace_code(rec, enable); 2121 failed = __ftrace_replace_code(rec, enable);
2099 if (failed) { 2122 if (failed) {
2100 ftrace_bug(failed, rec->ip); 2123 ftrace_bug(failed, rec);
2101 /* Stop processing */ 2124 /* Stop processing */
2102 return; 2125 return;
2103 } 2126 }
@@ -2179,17 +2202,14 @@ struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter)
2179static int 2202static int
2180ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec) 2203ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
2181{ 2204{
2182 unsigned long ip;
2183 int ret; 2205 int ret;
2184 2206
2185 ip = rec->ip;
2186
2187 if (unlikely(ftrace_disabled)) 2207 if (unlikely(ftrace_disabled))
2188 return 0; 2208 return 0;
2189 2209
2190 ret = ftrace_make_nop(mod, rec, MCOUNT_ADDR); 2210 ret = ftrace_make_nop(mod, rec, MCOUNT_ADDR);
2191 if (ret) { 2211 if (ret) {
2192 ftrace_bug(ret, ip); 2212 ftrace_bug(ret, rec);
2193 return 0; 2213 return 0;
2194 } 2214 }
2195 return 1; 2215 return 1;
@@ -2633,7 +2653,7 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
2633 if (ftrace_start_up && cnt) { 2653 if (ftrace_start_up && cnt) {
2634 int failed = __ftrace_replace_code(p, 1); 2654 int failed = __ftrace_replace_code(p, 1);
2635 if (failed) 2655 if (failed)
2636 ftrace_bug(failed, p->ip); 2656 ftrace_bug(failed, p);
2637 } 2657 }
2638 } 2658 }
2639 } 2659 }