aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/oprofile
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/oprofile')
-rw-r--r--arch/x86/oprofile/backtrace.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index d640a86198b1..2d49d4e19a36 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -14,6 +14,7 @@
14#include <asm/ptrace.h> 14#include <asm/ptrace.h>
15#include <asm/uaccess.h> 15#include <asm/uaccess.h>
16#include <asm/stacktrace.h> 16#include <asm/stacktrace.h>
17#include <linux/compat.h>
17 18
18static void backtrace_warning_symbol(void *data, char *msg, 19static void backtrace_warning_symbol(void *data, char *msg,
19 unsigned long symbol) 20 unsigned long symbol)
@@ -48,6 +49,55 @@ static struct stacktrace_ops backtrace_ops = {
48 .walk_stack = print_context_stack, 49 .walk_stack = print_context_stack,
49}; 50};
50 51
52#ifdef CONFIG_COMPAT
53static struct stack_frame_ia32 *
54dump_user_backtrace_32(struct stack_frame_ia32 *head)
55{
56 struct stack_frame_ia32 bufhead[2];
57 struct stack_frame_ia32 *fp;
58
59 /* Also check accessibility of one struct frame_head beyond */
60 if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
61 return NULL;
62 if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
63 return NULL;
64
65 fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
66
67 oprofile_add_trace(bufhead[0].return_address);
68
69 /* frame pointers should strictly progress back up the stack
70 * (towards higher addresses) */
71 if (head >= fp)
72 return NULL;
73
74 return fp;
75}
76
77static inline int
78x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
79{
80 struct stack_frame_ia32 *head;
81
82 /* User process is 32-bit */
83 if (!current || !test_thread_flag(TIF_IA32))
84 return 0;
85
86 head = (struct stack_frame_ia32 *) regs->bp;
87 while (depth-- && head)
88 head = dump_user_backtrace_32(head);
89
90 return 1;
91}
92
93#else
94static inline int
95x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
96{
97 return 0;
98}
99#endif /* CONFIG_COMPAT */
100
51static struct stack_frame *dump_user_backtrace(struct stack_frame *head) 101static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
52{ 102{
53 struct stack_frame bufhead[2]; 103 struct stack_frame bufhead[2];
@@ -81,6 +131,9 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth)
81 return; 131 return;
82 } 132 }
83 133
134 if (x86_backtrace_32(regs, depth))
135 return;
136
84 while (depth-- && head) 137 while (depth-- && head)
85 head = dump_user_backtrace(head); 138 head = dump_user_backtrace(head);
86} 139}