aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
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 /kernel/trace/ftrace.c
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>
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c38
1 files changed, 29 insertions, 9 deletions
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 }