aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/oprofile/backtrace.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/x86/oprofile/backtrace.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'arch/x86/oprofile/backtrace.c')
-rw-r--r--arch/x86/oprofile/backtrace.c83
1 files changed, 59 insertions, 24 deletions
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index 3855096c59b8..a5b64ab4cd6e 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -14,17 +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 17#include <linux/compat.h>
18static void backtrace_warning_symbol(void *data, char *msg,
19 unsigned long symbol)
20{
21 /* Ignore warnings */
22}
23
24static void backtrace_warning(void *data, char *msg)
25{
26 /* Ignore warnings */
27}
28 18
29static int backtrace_stack(void *data, char *name) 19static int backtrace_stack(void *data, char *name)
30{ 20{
@@ -41,21 +31,17 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
41} 31}
42 32
43static struct stacktrace_ops backtrace_ops = { 33static struct stacktrace_ops backtrace_ops = {
44 .warning = backtrace_warning,
45 .warning_symbol = backtrace_warning_symbol,
46 .stack = backtrace_stack, 34 .stack = backtrace_stack,
47 .address = backtrace_address, 35 .address = backtrace_address,
48 .walk_stack = print_context_stack, 36 .walk_stack = print_context_stack,
49}; 37};
50 38
51struct frame_head { 39#ifdef CONFIG_COMPAT
52 struct frame_head *bp; 40static struct stack_frame_ia32 *
53 unsigned long ret; 41dump_user_backtrace_32(struct stack_frame_ia32 *head)
54} __attribute__((packed));
55
56static struct frame_head *dump_user_backtrace(struct frame_head *head)
57{ 42{
58 struct frame_head bufhead[2]; 43 struct stack_frame_ia32 bufhead[2];
44 struct stack_frame_ia32 *fp;
59 45
60 /* Also check accessibility of one struct frame_head beyond */ 46 /* Also check accessibility of one struct frame_head beyond */
61 if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) 47 if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
@@ -63,20 +49,66 @@ static struct frame_head *dump_user_backtrace(struct frame_head *head)
63 if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) 49 if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
64 return NULL; 50 return NULL;
65 51
66 oprofile_add_trace(bufhead[0].ret); 52 fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
53
54 oprofile_add_trace(bufhead[0].return_address);
55
56 /* frame pointers should strictly progress back up the stack
57 * (towards higher addresses) */
58 if (head >= fp)
59 return NULL;
60
61 return fp;
62}
63
64static inline int
65x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
66{
67 struct stack_frame_ia32 *head;
68
69 /* User process is 32-bit */
70 if (!current || !test_thread_flag(TIF_IA32))
71 return 0;
72
73 head = (struct stack_frame_ia32 *) regs->bp;
74 while (depth-- && head)
75 head = dump_user_backtrace_32(head);
76
77 return 1;
78}
79
80#else
81static inline int
82x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
83{
84 return 0;
85}
86#endif /* CONFIG_COMPAT */
87
88static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
89{
90 struct stack_frame bufhead[2];
91
92 /* Also check accessibility of one struct stack_frame beyond */
93 if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
94 return NULL;
95 if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
96 return NULL;
97
98 oprofile_add_trace(bufhead[0].return_address);
67 99
68 /* frame pointers should strictly progress back up the stack 100 /* frame pointers should strictly progress back up the stack
69 * (towards higher addresses) */ 101 * (towards higher addresses) */
70 if (head >= bufhead[0].bp) 102 if (head >= bufhead[0].next_frame)
71 return NULL; 103 return NULL;
72 104
73 return bufhead[0].bp; 105 return bufhead[0].next_frame;
74} 106}
75 107
76void 108void
77x86_backtrace(struct pt_regs * const regs, unsigned int depth) 109x86_backtrace(struct pt_regs * const regs, unsigned int depth)
78{ 110{
79 struct frame_head *head = (struct frame_head *)frame_pointer(regs); 111 struct stack_frame *head = (struct stack_frame *)frame_pointer(regs);
80 112
81 if (!user_mode_vm(regs)) { 113 if (!user_mode_vm(regs)) {
82 unsigned long stack = kernel_stack_pointer(regs); 114 unsigned long stack = kernel_stack_pointer(regs);
@@ -86,6 +118,9 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth)
86 return; 118 return;
87 } 119 }
88 120
121 if (x86_backtrace_32(regs, depth))
122 return;
123
89 while (depth-- && head) 124 while (depth-- && head)
90 head = dump_user_backtrace(head); 125 head = dump_user_backtrace(head);
91} 126}