1
2
3
4
5
6#include <linux/sched/task_stack.h>
7#include <linux/stacktrace.h>
8#include <linux/kallsyms.h>
9#include <linux/seq_file.h>
10#include <linux/spinlock.h>
11#include <linux/uaccess.h>
12#include <linux/ftrace.h>
13#include <linux/module.h>
14#include <linux/sysctl.h>
15#include <linux/init.h>
16
17#include <asm/setup.h>
18
19#include "trace.h"
20
21#define STACK_TRACE_ENTRIES 500
22
23static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES];
24static unsigned stack_trace_index[STACK_TRACE_ENTRIES];
25
26static unsigned int stack_trace_nr_entries;
27static unsigned long stack_trace_max_size;
28static arch_spinlock_t stack_trace_max_lock =
29 (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
30
31DEFINE_PER_CPU(int, disable_stack_tracer);
32static DEFINE_MUTEX(stack_sysctl_mutex);
33
34int stack_tracer_enabled;
35
36static void print_max_stack(void)
37{
38 long i;
39 int size;
40
41 pr_emerg(" Depth Size Location (%d entries)\n"
42 " ----- ---- --------\n",
43 stack_trace_nr_entries);
44
45 for (i = 0; i < stack_trace_nr_entries; i++) {
46 if (i + 1 == stack_trace_nr_entries)
47 size = stack_trace_index[i];
48 else
49 size = stack_trace_index[i] - stack_trace_index[i+1];
50
51 pr_emerg("%3ld) %8d %5d %pS\n", i, stack_trace_index[i],
52 size, (void *)stack_dump_trace[i]);
53 }
54}
55
56static void check_stack(unsigned long ip, unsigned long *stack)
57{
58 unsigned long this_size, flags; unsigned long *p, *top, *start;
59 static int tracer_frame;
60 int frame_size = READ_ONCE(tracer_frame);
61 int i, x;
62
63 this_size = ((unsigned long)stack) & (THREAD_SIZE-1);
64 this_size = THREAD_SIZE - this_size;
65
66 this_size -= frame_size;
67
68 if (this_size <= stack_trace_max_size)
69 return;
70
71
72 if (!object_is_on_stack(stack))
73 return;
74
75
76 if (in_nmi())
77 return;
78
79 local_irq_save(flags);
80 arch_spin_lock(&stack_trace_max_lock);
81
82
83 if (unlikely(!frame_size))
84 this_size -= tracer_frame;
85
86
87 if (this_size <= stack_trace_max_size)
88 goto out;
89
90 stack_trace_max_size = this_size;
91
92 stack_trace_nr_entries = stack_trace_save(stack_dump_trace,
93 ARRAY_SIZE(stack_dump_trace) - 1,
94 0);
95
96
97 for (i = 0; i < stack_trace_nr_entries; i++) {
98 if (stack_dump_trace[i] == ip)
99 break;
100 }
101
102
103
104
105
106 if (i == stack_trace_nr_entries)
107 i = 0;
108
109
110
111
112 x = 0;
113 start = stack;
114 top = (unsigned long *)
115 (((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE);
116
117
118
119
120
121
122
123
124 while (i < stack_trace_nr_entries) {
125 int found = 0;
126
127 stack_trace_index[x] = this_size;
128 p = start;
129
130 for (; p < top && i < stack_trace_nr_entries; p++) {
131
132
133
134
135 if ((READ_ONCE_NOCHECK(*p)) == stack_dump_trace[i]) {
136 stack_dump_trace[x] = stack_dump_trace[i++];
137 this_size = stack_trace_index[x++] =
138 (top - p) * sizeof(unsigned long);
139 found = 1;
140
141 start = p + 1;
142
143
144
145
146
147
148
149 if (unlikely(!tracer_frame)) {
150 tracer_frame = (p - stack) *
151 sizeof(unsigned long);
152 stack_trace_max_size -= tracer_frame;
153 }
154 }
155 }
156
157 if (!found)
158 i++;
159 }
160
161 stack_trace_nr_entries = x;
162
163 if (task_stack_end_corrupted(current)) {
164 print_max_stack();
165 BUG();
166 }
167
168 out:
169 arch_spin_unlock(&stack_trace_max_lock);
170 local_irq_restore(flags);
171}
172
173static void
174stack_trace_call(unsigned long ip, unsigned long parent_ip,
175 struct ftrace_ops *op, struct pt_regs *pt_regs)
176{
177 unsigned long stack;
178
179 preempt_disable_notrace();
180
181
182 __this_cpu_inc(disable_stack_tracer);
183 if (__this_cpu_read(disable_stack_tracer) != 1)
184 goto out;
185
186
187 if (!rcu_is_watching())
188 goto out;
189
190 ip += MCOUNT_INSN_SIZE;
191
192 check_stack(ip, &stack);
193
194 out:
195 __this_cpu_dec(disable_stack_tracer);
196
197 preempt_enable_notrace();
198}
199
200static struct ftrace_ops trace_ops __read_mostly =
201{
202 .func = stack_trace_call,
203 .flags = FTRACE_OPS_FL_RECURSION_SAFE,
204};
205
206static ssize_t
207stack_max_size_read(struct file *filp, char __user *ubuf,
208 size_t count, loff_t *ppos)
209{
210 unsigned long *ptr = filp->private_data;
211 char buf[64];
212 int r;
213
214 r = snprintf(buf, sizeof(buf), "%ld\n", *ptr);
215 if (r > sizeof(buf))
216 r = sizeof(buf);
217 return simple_read_from_buffer(ubuf, count, ppos, buf, r);
218}
219
220static ssize_t
221stack_max_size_write(struct file *filp, const char __user *ubuf,
222 size_t count, loff_t *ppos)
223{
224 long *ptr = filp->private_data;
225 unsigned long val, flags;
226 int ret;
227
228 ret = kstrtoul_from_user(ubuf, count, 10, &val);
229 if (ret)
230 return ret;
231
232 local_irq_save(flags);
233
234
235
236
237
238
239 __this_cpu_inc(disable_stack_tracer);
240
241 arch_spin_lock(&stack_trace_max_lock);
242 *ptr = val;
243 arch_spin_unlock(&stack_trace_max_lock);
244
245 __this_cpu_dec(disable_stack_tracer);
246 local_irq_restore(flags);
247
248 return count;
249}
250
251static const struct file_operations stack_max_size_fops = {
252 .open = tracing_open_generic,
253 .read = stack_max_size_read,
254 .write = stack_max_size_write,
255 .llseek = default_llseek,
256};
257
258static void *
259__next(struct seq_file *m, loff_t *pos)
260{
261 long n = *pos - 1;
262
263 if (n >= stack_trace_nr_entries)
264 return NULL;
265
266 m->private = (void *)n;
267 return &m->private;
268}
269
270static void *
271t_next(struct seq_file *m, void *v, loff_t *pos)
272{
273 (*pos)++;
274 return __next(m, pos);
275}
276
277static void *t_start(struct seq_file *m, loff_t *pos)
278{
279 local_irq_disable();
280
281 __this_cpu_inc(disable_stack_tracer);
282
283 arch_spin_lock(&stack_trace_max_lock);
284
285 if (*pos == 0)
286 return SEQ_START_TOKEN;
287
288 return __next(m, pos);
289}
290
291static void t_stop(struct seq_file *m, void *p)
292{
293 arch_spin_unlock(&stack_trace_max_lock);
294
295 __this_cpu_dec(disable_stack_tracer);
296
297 local_irq_enable();
298}
299
300static void trace_lookup_stack(struct seq_file *m, long i)
301{
302 unsigned long addr = stack_dump_trace[i];
303
304 seq_printf(m, "%pS\n", (void *)addr);
305}
306
307static void print_disabled(struct seq_file *m)
308{
309 seq_puts(m, "#\n"
310 "# Stack tracer disabled\n"
311 "#\n"
312 "# To enable the stack tracer, either add 'stacktrace' to the\n"
313 "# kernel command line\n"
314 "# or 'echo 1 > /proc/sys/kernel/stack_tracer_enabled'\n"
315 "#\n");
316}
317
318static int t_show(struct seq_file *m, void *v)
319{
320 long i;
321 int size;
322
323 if (v == SEQ_START_TOKEN) {
324 seq_printf(m, " Depth Size Location"
325 " (%d entries)\n"
326 " ----- ---- --------\n",
327 stack_trace_nr_entries);
328
329 if (!stack_tracer_enabled && !stack_trace_max_size)
330 print_disabled(m);
331
332 return 0;
333 }
334
335 i = *(long *)v;
336
337 if (i >= stack_trace_nr_entries)
338 return 0;
339
340 if (i + 1 == stack_trace_nr_entries)
341 size = stack_trace_index[i];
342 else
343 size = stack_trace_index[i] - stack_trace_index[i+1];
344
345 seq_printf(m, "%3ld) %8d %5d ", i, stack_trace_index[i], size);
346
347 trace_lookup_stack(m, i);
348
349 return 0;
350}
351
352static const struct seq_operations stack_trace_seq_ops = {
353 .start = t_start,
354 .next = t_next,
355 .stop = t_stop,
356 .show = t_show,
357};
358
359static int stack_trace_open(struct inode *inode, struct file *file)
360{
361 return seq_open(file, &stack_trace_seq_ops);
362}
363
364static const struct file_operations stack_trace_fops = {
365 .open = stack_trace_open,
366 .read = seq_read,
367 .llseek = seq_lseek,
368 .release = seq_release,
369};
370
371#ifdef CONFIG_DYNAMIC_FTRACE
372
373static int
374stack_trace_filter_open(struct inode *inode, struct file *file)
375{
376 struct ftrace_ops *ops = inode->i_private;
377
378 return ftrace_regex_open(ops, FTRACE_ITER_FILTER,
379 inode, file);
380}
381
382static const struct file_operations stack_trace_filter_fops = {
383 .open = stack_trace_filter_open,
384 .read = seq_read,
385 .write = ftrace_filter_write,
386 .llseek = tracing_lseek,
387 .release = ftrace_regex_release,
388};
389
390#endif
391
392int
393stack_trace_sysctl(struct ctl_table *table, int write,
394 void __user *buffer, size_t *lenp,
395 loff_t *ppos)
396{
397 int was_enabled;
398 int ret;
399
400 mutex_lock(&stack_sysctl_mutex);
401 was_enabled = !!stack_tracer_enabled;
402
403 ret = proc_dointvec(table, write, buffer, lenp, ppos);
404
405 if (ret || !write || (was_enabled == !!stack_tracer_enabled))
406 goto out;
407
408 if (stack_tracer_enabled)
409 register_ftrace_function(&trace_ops);
410 else
411 unregister_ftrace_function(&trace_ops);
412 out:
413 mutex_unlock(&stack_sysctl_mutex);
414 return ret;
415}
416
417static char stack_trace_filter_buf[COMMAND_LINE_SIZE+1] __initdata;
418
419static __init int enable_stacktrace(char *str)
420{
421 int len;
422
423 if ((len = str_has_prefix(str, "_filter=")))
424 strncpy(stack_trace_filter_buf, str + len, COMMAND_LINE_SIZE);
425
426 stack_tracer_enabled = 1;
427 return 1;
428}
429__setup("stacktrace", enable_stacktrace);
430
431static __init int stack_trace_init(void)
432{
433 struct dentry *d_tracer;
434
435 d_tracer = tracing_init_dentry();
436 if (IS_ERR(d_tracer))
437 return 0;
438
439 trace_create_file("stack_max_size", 0644, d_tracer,
440 &stack_trace_max_size, &stack_max_size_fops);
441
442 trace_create_file("stack_trace", 0444, d_tracer,
443 NULL, &stack_trace_fops);
444
445#ifdef CONFIG_DYNAMIC_FTRACE
446 trace_create_file("stack_trace_filter", 0644, d_tracer,
447 &trace_ops, &stack_trace_filter_fops);
448#endif
449
450 if (stack_trace_filter_buf[0])
451 ftrace_set_early_filter(&trace_ops, stack_trace_filter_buf, 1);
452
453 if (stack_tracer_enabled)
454 register_ftrace_function(&trace_ops);
455
456 return 0;
457}
458
459device_initcall(stack_trace_init);
460