aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_sysprof.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_sysprof.c')
-rw-r--r--kernel/trace/trace_sysprof.c80
1 files changed, 76 insertions, 4 deletions
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c
index ba55b871b3d9..b1137c11ef8b 100644
--- a/kernel/trace/trace_sysprof.c
+++ b/kernel/trace/trace_sysprof.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com> 4 * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
5 * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com> 5 * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
6 * 6 * Copyright (C) 2004, 2005, Soeren Sandmann
7 */ 7 */
8#include <linux/kallsyms.h> 8#include <linux/kallsyms.h>
9#include <linux/debugfs.h> 9#include <linux/debugfs.h>
@@ -11,13 +11,17 @@
11#include <linux/uaccess.h> 11#include <linux/uaccess.h>
12#include <linux/ftrace.h> 12#include <linux/ftrace.h>
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/irq.h>
14#include <linux/fs.h> 15#include <linux/fs.h>
15 16
16#include "trace.h" 17#include "trace.h"
17 18
18static struct trace_array *ctx_trace; 19static struct trace_array *sysprof_trace;
19static int __read_mostly tracer_enabled; 20static int __read_mostly tracer_enabled;
20 21
22/*
23 * 10 msecs for now:
24 */
21static const unsigned long sample_period = 1000000; 25static const unsigned long sample_period = 1000000;
22 26
23/* 27/*
@@ -25,10 +29,78 @@ static const unsigned long sample_period = 1000000;
25 */ 29 */
26static DEFINE_PER_CPU(struct hrtimer, stack_trace_hrtimer); 30static DEFINE_PER_CPU(struct hrtimer, stack_trace_hrtimer);
27 31
32struct stack_frame {
33 const void __user *next_fp;
34 unsigned long return_address;
35};
36
37static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
38{
39 if (!access_ok(VERIFY_READ, fp, sizeof(*frame)))
40 return 0;
41
42 if (__copy_from_user_inatomic(frame, frame_pointer, sizeof(*frame)))
43 return 0;
44
45 return 1;
46}
47
48#define SYSPROF_MAX_ADDRESSES 512
49
50static void timer_notify(struct pt_regs *regs, int cpu)
51{
52 const void __user *frame_pointer;
53 struct trace_array_cpu *data;
54 struct stack_frame frame;
55 struct trace_array *tr;
56 int is_user;
57 int i;
58
59 if (!regs)
60 return;
61
62 tr = sysprof_trace;
63 data = tr->data[cpu];
64 is_user = user_mode(regs);
65
66 if (!current || current->pid == 0)
67 return;
68
69 if (is_user && current->state != TASK_RUNNING)
70 return;
71
72 if (!is_user) {
73 /* kernel */
74 ftrace(tr, data, current->pid, 1, 0);
75 return;
76
77 }
78
79 trace_special(tr, data, 0, current->pid, regs->ip);
80
81 frame_pointer = (void __user *)regs->bp;
82
83 for (i = 0; i < SYSPROF_MAX_ADDRESSES; i++) {
84 if (!copy_stack_frame(frame_pointer, &frame))
85 break;
86 if ((unsigned long)frame_pointer < regs->sp)
87 break;
88
89 trace_special(tr, data, 1, frame.return_address,
90 (unsigned long)frame_pointer);
91 frame_pointer = frame.next_fp;
92 }
93
94 trace_special(tr, data, 2, current->pid, i);
95
96 if (i == SYSPROF_MAX_ADDRESSES)
97 trace_special(tr, data, -1, -1, -1);
98}
99
28static enum hrtimer_restart stack_trace_timer_fn(struct hrtimer *hrtimer) 100static enum hrtimer_restart stack_trace_timer_fn(struct hrtimer *hrtimer)
29{ 101{
30 /* trace here */ 102 /* trace here */
31 panic_timeout++; 103 timer_notify(get_irq_regs(), smp_processor_id());
32 104
33 hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period)); 105 hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period));
34 106
@@ -100,7 +172,7 @@ static notrace void stop_stack_trace(struct trace_array *tr)
100 172
101static notrace void stack_trace_init(struct trace_array *tr) 173static notrace void stack_trace_init(struct trace_array *tr)
102{ 174{
103 ctx_trace = tr; 175 sysprof_trace = tr;
104 176
105 if (tr->ctrl) 177 if (tr->ctrl)
106 start_stack_trace(tr); 178 start_stack_trace(tr);