aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace_sysprof.c89
1 files changed, 80 insertions, 9 deletions
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c
index 76dd953eeccd..ebcb66d054cc 100644
--- a/kernel/trace/trace_sysprof.c
+++ b/kernel/trace/trace_sysprof.c
@@ -14,6 +14,8 @@
14#include <linux/irq.h> 14#include <linux/irq.h>
15#include <linux/fs.h> 15#include <linux/fs.h>
16 16
17#include <asm/stacktrace.h>
18
17#include "trace.h" 19#include "trace.h"
18 20
19static struct trace_array *sysprof_trace; 21static struct trace_array *sysprof_trace;
@@ -52,6 +54,77 @@ static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
52 return ret; 54 return ret;
53} 55}
54 56
57struct backtrace_info {
58 struct trace_array_cpu *data;
59 struct trace_array *tr;
60 int pos;
61};
62
63static void
64backtrace_warning_symbol(void *data, char *msg, unsigned long symbol)
65{
66 /* Ignore warnings */
67}
68
69static void backtrace_warning(void *data, char *msg)
70{
71 /* Ignore warnings */
72}
73
74static int backtrace_stack(void *data, char *name)
75{
76 /* Don't bother with IRQ stacks for now */
77 return -1;
78}
79
80static void backtrace_address(void *data, unsigned long addr, int reliable)
81{
82 struct backtrace_info *info = data;
83
84 if (info->pos < sample_max_depth && reliable) {
85 __trace_special(info->tr, info->data, 1, addr, 0);
86
87 info->pos++;
88 }
89}
90
91const static struct stacktrace_ops backtrace_ops = {
92 .warning = backtrace_warning,
93 .warning_symbol = backtrace_warning_symbol,
94 .stack = backtrace_stack,
95 .address = backtrace_address,
96};
97
98static struct pt_regs *
99trace_kernel(struct pt_regs *regs, struct trace_array *tr,
100 struct trace_array_cpu *data)
101{
102 struct backtrace_info info;
103 unsigned long bp;
104 char *user_stack;
105 char *stack;
106
107 info.tr = tr;
108 info.data = data;
109 info.pos = 1;
110
111 __trace_special(info.tr, info.data, 1, regs->ip, 0);
112
113 stack = ((char *)regs + sizeof(struct pt_regs));
114#ifdef CONFIG_FRAME_POINTER
115 bp = regs->bp;
116#else
117 bp = 0;
118#endif
119
120 dump_trace(NULL, regs, (void *)stack, bp, &backtrace_ops, &info);
121
122 /* Now trace the user stack */
123 user_stack = ((char *)current->thread.sp0 - sizeof(struct pt_regs));
124
125 return (struct pt_regs *)user_stack;
126}
127
55static void timer_notify(struct pt_regs *regs, int cpu) 128static void timer_notify(struct pt_regs *regs, int cpu)
56{ 129{
57 struct trace_array_cpu *data; 130 struct trace_array_cpu *data;
@@ -74,17 +147,15 @@ static void timer_notify(struct pt_regs *regs, int cpu)
74 if (is_user && current->state != TASK_RUNNING) 147 if (is_user && current->state != TASK_RUNNING)
75 return; 148 return;
76 149
77 if (!is_user) { 150 __trace_special(tr, data, 0, 0, current->pid);
78 /* kernel */
79 ftrace(tr, data, current->pid, 1, 0);
80 return;
81 151
82 } 152 if (!is_user)
83 153 regs = trace_kernel(regs, tr, data);
84 __trace_special(tr, data, 0, current->pid, regs->ip);
85 154
86 fp = (void __user *)regs->bp; 155 fp = (void __user *)regs->bp;
87 156
157 __trace_special(tr, data, 2, regs->ip, 0);
158
88 for (i = 0; i < sample_max_depth; i++) { 159 for (i = 0; i < sample_max_depth; i++) {
89 frame.next_fp = 0; 160 frame.next_fp = 0;
90 frame.return_address = 0; 161 frame.return_address = 0;
@@ -93,12 +164,12 @@ static void timer_notify(struct pt_regs *regs, int cpu)
93 if ((unsigned long)fp < regs->sp) 164 if ((unsigned long)fp < regs->sp)
94 break; 165 break;
95 166
96 __trace_special(tr, data, 1, frame.return_address, 167 __trace_special(tr, data, 2, frame.return_address,
97 (unsigned long)fp); 168 (unsigned long)fp);
98 fp = frame.next_fp; 169 fp = frame.next_fp;
99 } 170 }
100 171
101 __trace_special(tr, data, 2, current->pid, i); 172 __trace_special(tr, data, 3, current->pid, i);
102 173
103 /* 174 /*
104 * Special trace entry if we overflow the max depth: 175 * Special trace entry if we overflow the max depth: