diff options
-rw-r--r-- | arch/powerpc/kernel/ftrace.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/ftrace.c | 2 | ||||
-rw-r--r-- | include/linux/ftrace.h | 4 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 38 |
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 { | |||
263 | int ftrace_arch_code_modify_prepare(void); | 263 | int ftrace_arch_code_modify_prepare(void); |
264 | int ftrace_arch_code_modify_post_process(void); | 264 | int ftrace_arch_code_modify_post_process(void); |
265 | 265 | ||
266 | void ftrace_bug(int err, unsigned long ip); | 266 | struct dyn_ftrace; |
267 | |||
268 | void ftrace_bug(int err, struct dyn_ftrace *rec); | ||
267 | 269 | ||
268 | struct seq_file; | 270 | struct 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 | ||
1741 | static struct ftrace_ops * | ||
1742 | ftrace_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 | */ |
1753 | void ftrace_bug(int failed, unsigned long ip) | 1756 | void 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 | ||
1780 | static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update) | 1803 | static 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) | |||
2179 | static int | 2202 | static int |
2180 | ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec) | 2203 | ftrace_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 | } |