1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2e5a81b62SSteven Rostedt /* 3e5a81b62SSteven Rostedt * Copyright (C) 2008 Steven Rostedt <[email protected]> 4e5a81b62SSteven Rostedt * 5e5a81b62SSteven Rostedt */ 668db0cf1SIngo Molnar #include <linux/sched/task_stack.h> 7e5a81b62SSteven Rostedt #include <linux/stacktrace.h> 8e5a81b62SSteven Rostedt #include <linux/kallsyms.h> 9e5a81b62SSteven Rostedt #include <linux/seq_file.h> 10e5a81b62SSteven Rostedt #include <linux/spinlock.h> 11e5a81b62SSteven Rostedt #include <linux/uaccess.h> 12e5a81b62SSteven Rostedt #include <linux/ftrace.h> 13e5a81b62SSteven Rostedt #include <linux/module.h> 14f38f1d2aSSteven Rostedt #include <linux/sysctl.h> 15e5a81b62SSteven Rostedt #include <linux/init.h> 16762e1207SSteven Rostedt 17762e1207SSteven Rostedt #include <asm/setup.h> 18762e1207SSteven Rostedt 19e5a81b62SSteven Rostedt #include "trace.h" 20e5a81b62SSteven Rostedt 213d9a8072SThomas Gleixner #define STACK_TRACE_ENTRIES 500 221b6cced6SSteven Rostedt 233d9a8072SThomas Gleixner static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES]; 243d9a8072SThomas Gleixner static unsigned stack_trace_index[STACK_TRACE_ENTRIES]; 253d9a8072SThomas Gleixner 26*9f50c91bSThomas Gleixner static unsigned int stack_trace_nr_entries; 273d9a8072SThomas Gleixner static unsigned long stack_trace_max_size; 283d9a8072SThomas Gleixner static arch_spinlock_t stack_trace_max_lock = 29edc35bd7SThomas Gleixner (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; 30e5a81b62SSteven Rostedt 318aaf1ee7SSteven Rostedt (VMware) DEFINE_PER_CPU(int, disable_stack_tracer); 32f38f1d2aSSteven Rostedt static DEFINE_MUTEX(stack_sysctl_mutex); 33f38f1d2aSSteven Rostedt 34f38f1d2aSSteven Rostedt int stack_tracer_enabled; 35e5a81b62SSteven Rostedt 363d9a8072SThomas Gleixner static void print_max_stack(void) 37e3172181SMinchan Kim { 38e3172181SMinchan Kim long i; 39e3172181SMinchan Kim int size; 40e3172181SMinchan Kim 41e3172181SMinchan Kim pr_emerg(" Depth Size Location (%d entries)\n" 42e3172181SMinchan Kim " ----- ---- --------\n", 43*9f50c91bSThomas Gleixner stack_trace_nr_entries); 44e3172181SMinchan Kim 45*9f50c91bSThomas Gleixner for (i = 0; i < stack_trace_nr_entries; i++) { 46*9f50c91bSThomas Gleixner if (i + 1 == stack_trace_nr_entries) 47bb99d8ccSAKASHI Takahiro size = stack_trace_index[i]; 48e3172181SMinchan Kim else 49bb99d8ccSAKASHI Takahiro size = stack_trace_index[i] - stack_trace_index[i+1]; 50e3172181SMinchan Kim 51bb99d8ccSAKASHI Takahiro pr_emerg("%3ld) %8d %5d %pS\n", i, stack_trace_index[i], 52e3172181SMinchan Kim size, (void *)stack_dump_trace[i]); 53e3172181SMinchan Kim } 54e3172181SMinchan Kim } 55e3172181SMinchan Kim 563d9a8072SThomas Gleixner static void check_stack(unsigned long ip, unsigned long *stack) 57e5a81b62SSteven Rostedt { 58e3172181SMinchan Kim unsigned long this_size, flags; unsigned long *p, *top, *start; 594df29712SSteven Rostedt (Red Hat) static int tracer_frame; 606aa7de05SMark Rutland int frame_size = READ_ONCE(tracer_frame); 6172ac426aSSteven Rostedt (Red Hat) int i, x; 62e5a81b62SSteven Rostedt 6387889501SSteven Rostedt (Red Hat) this_size = ((unsigned long)stack) & (THREAD_SIZE-1); 64e5a81b62SSteven Rostedt this_size = THREAD_SIZE - this_size; 654df29712SSteven Rostedt (Red Hat) /* Remove the frame of the tracer */ 664df29712SSteven Rostedt (Red Hat) this_size -= frame_size; 67e5a81b62SSteven Rostedt 68bb99d8ccSAKASHI Takahiro if (this_size <= stack_trace_max_size) 69e5a81b62SSteven Rostedt return; 70e5a81b62SSteven Rostedt 7181520a1bSSteven Rostedt /* we do not handle interrupt stacks yet */ 7287889501SSteven Rostedt (Red Hat) if (!object_is_on_stack(stack)) 7381520a1bSSteven Rostedt return; 7481520a1bSSteven Rostedt 751904be1bSSteven Rostedt (Red Hat) /* Can't do this from NMI context (can cause deadlocks) */ 761904be1bSSteven Rostedt (Red Hat) if (in_nmi()) 771904be1bSSteven Rostedt (Red Hat) return; 781904be1bSSteven Rostedt (Red Hat) 79a5e25883SSteven Rostedt local_irq_save(flags); 80d332736dSSteven Rostedt (Red Hat) arch_spin_lock(&stack_trace_max_lock); 81e5a81b62SSteven Rostedt 824df29712SSteven Rostedt (Red Hat) /* In case another CPU set the tracer_frame on us */ 834df29712SSteven Rostedt (Red Hat) if (unlikely(!frame_size)) 844df29712SSteven Rostedt (Red Hat) this_size -= tracer_frame; 854df29712SSteven Rostedt (Red Hat) 86e5a81b62SSteven Rostedt /* a race could have already updated it */ 87bb99d8ccSAKASHI Takahiro if (this_size <= stack_trace_max_size) 88e5a81b62SSteven Rostedt goto out; 89e5a81b62SSteven Rostedt 90bb99d8ccSAKASHI Takahiro stack_trace_max_size = this_size; 91e5a81b62SSteven Rostedt 92*9f50c91bSThomas Gleixner stack_trace_nr_entries = stack_trace_save(stack_dump_trace, 93*9f50c91bSThomas Gleixner ARRAY_SIZE(stack_dump_trace) - 1, 94*9f50c91bSThomas Gleixner 0); 95e5a81b62SSteven Rostedt 9672ac426aSSteven Rostedt (Red Hat) /* Skip over the overhead of the stack tracer itself */ 97*9f50c91bSThomas Gleixner for (i = 0; i < stack_trace_nr_entries; i++) { 9872ac426aSSteven Rostedt (Red Hat) if (stack_dump_trace[i] == ip) 9972ac426aSSteven Rostedt (Red Hat) break; 10072ac426aSSteven Rostedt (Red Hat) } 101d4ecbfc4SSteven Rostedt (Red Hat) 102d4ecbfc4SSteven Rostedt (Red Hat) /* 1036ccd8371SSteven Rostedt * Some archs may not have the passed in ip in the dump. 1046ccd8371SSteven Rostedt * If that happens, we need to show everything. 1056ccd8371SSteven Rostedt */ 106*9f50c91bSThomas Gleixner if (i == stack_trace_nr_entries) 1076ccd8371SSteven Rostedt i = 0; 1086ccd8371SSteven Rostedt 1096ccd8371SSteven Rostedt /* 1101b6cced6SSteven Rostedt * Now find where in the stack these are. 1111b6cced6SSteven Rostedt */ 11272ac426aSSteven Rostedt (Red Hat) x = 0; 11387889501SSteven Rostedt (Red Hat) start = stack; 1141b6cced6SSteven Rostedt top = (unsigned long *) 1151b6cced6SSteven Rostedt (((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE); 1161b6cced6SSteven Rostedt 1171b6cced6SSteven Rostedt /* 1181b6cced6SSteven Rostedt * Loop through all the entries. One of the entries may 1191b6cced6SSteven Rostedt * for some reason be missed on the stack, so we may 1201b6cced6SSteven Rostedt * have to account for them. If they are all there, this 1211b6cced6SSteven Rostedt * loop will only happen once. This code only takes place 1221b6cced6SSteven Rostedt * on a new max, so it is far from a fast path. 1231b6cced6SSteven Rostedt */ 124*9f50c91bSThomas Gleixner while (i < stack_trace_nr_entries) { 1250a37119dSSteven Rostedt int found = 0; 1261b6cced6SSteven Rostedt 127bb99d8ccSAKASHI Takahiro stack_trace_index[x] = this_size; 1281b6cced6SSteven Rostedt p = start; 1291b6cced6SSteven Rostedt 130*9f50c91bSThomas Gleixner for (; p < top && i < stack_trace_nr_entries; p++) { 1316e22c836SYang Shi /* 1326e22c836SYang Shi * The READ_ONCE_NOCHECK is used to let KASAN know that 1336e22c836SYang Shi * this is not a stack-out-of-bounds error. 1346e22c836SYang Shi */ 1356e22c836SYang Shi if ((READ_ONCE_NOCHECK(*p)) == stack_dump_trace[i]) { 13672ac426aSSteven Rostedt (Red Hat) stack_dump_trace[x] = stack_dump_trace[i++]; 137bb99d8ccSAKASHI Takahiro this_size = stack_trace_index[x++] = 1381b6cced6SSteven Rostedt (top - p) * sizeof(unsigned long); 1390a37119dSSteven Rostedt found = 1; 1401b6cced6SSteven Rostedt /* Start the search from here */ 1411b6cced6SSteven Rostedt start = p + 1; 1424df29712SSteven Rostedt (Red Hat) /* 1434df29712SSteven Rostedt (Red Hat) * We do not want to show the overhead 1444df29712SSteven Rostedt (Red Hat) * of the stack tracer stack in the 1454df29712SSteven Rostedt (Red Hat) * max stack. If we haven't figured 1464df29712SSteven Rostedt (Red Hat) * out what that is, then figure it out 1474df29712SSteven Rostedt (Red Hat) * now. 1484df29712SSteven Rostedt (Red Hat) */ 14972ac426aSSteven Rostedt (Red Hat) if (unlikely(!tracer_frame)) { 1504df29712SSteven Rostedt (Red Hat) tracer_frame = (p - stack) * 1514df29712SSteven Rostedt (Red Hat) sizeof(unsigned long); 152bb99d8ccSAKASHI Takahiro stack_trace_max_size -= tracer_frame; 1534df29712SSteven Rostedt (Red Hat) } 1541b6cced6SSteven Rostedt } 1551b6cced6SSteven Rostedt } 1561b6cced6SSteven Rostedt 1570a37119dSSteven Rostedt if (!found) 1581b6cced6SSteven Rostedt i++; 1591b6cced6SSteven Rostedt } 1601b6cced6SSteven Rostedt 161*9f50c91bSThomas Gleixner stack_trace_nr_entries = x; 16272ac426aSSteven Rostedt (Red Hat) 163a70857e4SAaron Tomlin if (task_stack_end_corrupted(current)) { 1643d9a8072SThomas Gleixner print_max_stack(); 165e3172181SMinchan Kim BUG(); 166e3172181SMinchan Kim } 167e3172181SMinchan Kim 168e5a81b62SSteven Rostedt out: 169d332736dSSteven Rostedt (Red Hat) arch_spin_unlock(&stack_trace_max_lock); 170a5e25883SSteven Rostedt local_irq_restore(flags); 171e5a81b62SSteven Rostedt } 172e5a81b62SSteven Rostedt 173e5a81b62SSteven Rostedt static void 174a1e2e31dSSteven Rostedt stack_trace_call(unsigned long ip, unsigned long parent_ip, 175a1e2e31dSSteven Rostedt struct ftrace_ops *op, struct pt_regs *pt_regs) 176e5a81b62SSteven Rostedt { 17787889501SSteven Rostedt (Red Hat) unsigned long stack; 178e5a81b62SSteven Rostedt 1795168ae50SSteven Rostedt preempt_disable_notrace(); 180e5a81b62SSteven Rostedt 181e5a81b62SSteven Rostedt /* no atomic needed, we only modify this variable by this cpu */ 1828aaf1ee7SSteven Rostedt (VMware) __this_cpu_inc(disable_stack_tracer); 1838aaf1ee7SSteven Rostedt (VMware) if (__this_cpu_read(disable_stack_tracer) != 1) 184e5a81b62SSteven Rostedt goto out; 185e5a81b62SSteven Rostedt 186b00d607bSSteven Rostedt (VMware) /* If rcu is not watching, then save stack trace can fail */ 187b00d607bSSteven Rostedt (VMware) if (!rcu_is_watching()) 188b00d607bSSteven Rostedt (VMware) goto out; 189b00d607bSSteven Rostedt (VMware) 1904df29712SSteven Rostedt (Red Hat) ip += MCOUNT_INSN_SIZE; 1914df29712SSteven Rostedt (Red Hat) 1924df29712SSteven Rostedt (Red Hat) check_stack(ip, &stack); 193e5a81b62SSteven Rostedt 194e5a81b62SSteven Rostedt out: 1958aaf1ee7SSteven Rostedt (VMware) __this_cpu_dec(disable_stack_tracer); 196e5a81b62SSteven Rostedt /* prevent recursion in schedule */ 1975168ae50SSteven Rostedt preempt_enable_notrace(); 198e5a81b62SSteven Rostedt } 199e5a81b62SSteven Rostedt 200e5a81b62SSteven Rostedt static struct ftrace_ops trace_ops __read_mostly = 201e5a81b62SSteven Rostedt { 202e5a81b62SSteven Rostedt .func = stack_trace_call, 2034740974aSSteven Rostedt .flags = FTRACE_OPS_FL_RECURSION_SAFE, 204e5a81b62SSteven Rostedt }; 205e5a81b62SSteven Rostedt 206e5a81b62SSteven Rostedt static ssize_t 207e5a81b62SSteven Rostedt stack_max_size_read(struct file *filp, char __user *ubuf, 208e5a81b62SSteven Rostedt size_t count, loff_t *ppos) 209e5a81b62SSteven Rostedt { 210e5a81b62SSteven Rostedt unsigned long *ptr = filp->private_data; 211e5a81b62SSteven Rostedt char buf[64]; 212e5a81b62SSteven Rostedt int r; 213e5a81b62SSteven Rostedt 214e5a81b62SSteven Rostedt r = snprintf(buf, sizeof(buf), "%ld\n", *ptr); 215e5a81b62SSteven Rostedt if (r > sizeof(buf)) 216e5a81b62SSteven Rostedt r = sizeof(buf); 217e5a81b62SSteven Rostedt return simple_read_from_buffer(ubuf, count, ppos, buf, r); 218e5a81b62SSteven Rostedt } 219e5a81b62SSteven Rostedt 220e5a81b62SSteven Rostedt static ssize_t 221e5a81b62SSteven Rostedt stack_max_size_write(struct file *filp, const char __user *ubuf, 222e5a81b62SSteven Rostedt size_t count, loff_t *ppos) 223e5a81b62SSteven Rostedt { 224e5a81b62SSteven Rostedt long *ptr = filp->private_data; 225e5a81b62SSteven Rostedt unsigned long val, flags; 226e5a81b62SSteven Rostedt int ret; 227e5a81b62SSteven Rostedt 22822fe9b54SPeter Huewe ret = kstrtoul_from_user(ubuf, count, 10, &val); 22922fe9b54SPeter Huewe if (ret) 230e5a81b62SSteven Rostedt return ret; 231e5a81b62SSteven Rostedt 232a5e25883SSteven Rostedt local_irq_save(flags); 2334f48f8b7SLai Jiangshan 2344f48f8b7SLai Jiangshan /* 2354f48f8b7SLai Jiangshan * In case we trace inside arch_spin_lock() or after (NMI), 2364f48f8b7SLai Jiangshan * we will cause circular lock, so we also need to increase 2378aaf1ee7SSteven Rostedt (VMware) * the percpu disable_stack_tracer here. 2384f48f8b7SLai Jiangshan */ 2398aaf1ee7SSteven Rostedt (VMware) __this_cpu_inc(disable_stack_tracer); 2404f48f8b7SLai Jiangshan 241d332736dSSteven Rostedt (Red Hat) arch_spin_lock(&stack_trace_max_lock); 242e5a81b62SSteven Rostedt *ptr = val; 243d332736dSSteven Rostedt (Red Hat) arch_spin_unlock(&stack_trace_max_lock); 2444f48f8b7SLai Jiangshan 2458aaf1ee7SSteven Rostedt (VMware) __this_cpu_dec(disable_stack_tracer); 246a5e25883SSteven Rostedt local_irq_restore(flags); 247e5a81b62SSteven Rostedt 248e5a81b62SSteven Rostedt return count; 249e5a81b62SSteven Rostedt } 250e5a81b62SSteven Rostedt 251f38f1d2aSSteven Rostedt static const struct file_operations stack_max_size_fops = { 252e5a81b62SSteven Rostedt .open = tracing_open_generic, 253e5a81b62SSteven Rostedt .read = stack_max_size_read, 254e5a81b62SSteven Rostedt .write = stack_max_size_write, 2556038f373SArnd Bergmann .llseek = default_llseek, 256e5a81b62SSteven Rostedt }; 257e5a81b62SSteven Rostedt 258e5a81b62SSteven Rostedt static void * 2592fc5f0cfSLi Zefan __next(struct seq_file *m, loff_t *pos) 260e5a81b62SSteven Rostedt { 2612fc5f0cfSLi Zefan long n = *pos - 1; 262e5a81b62SSteven Rostedt 263*9f50c91bSThomas Gleixner if (n >= stack_trace_nr_entries) 264e5a81b62SSteven Rostedt return NULL; 265e5a81b62SSteven Rostedt 2662fc5f0cfSLi Zefan m->private = (void *)n; 2671b6cced6SSteven Rostedt return &m->private; 268e5a81b62SSteven Rostedt } 269e5a81b62SSteven Rostedt 2702fc5f0cfSLi Zefan static void * 2712fc5f0cfSLi Zefan t_next(struct seq_file *m, void *v, loff_t *pos) 2722fc5f0cfSLi Zefan { 2732fc5f0cfSLi Zefan (*pos)++; 2742fc5f0cfSLi Zefan return __next(m, pos); 2752fc5f0cfSLi Zefan } 2762fc5f0cfSLi Zefan 277e5a81b62SSteven Rostedt static void *t_start(struct seq_file *m, loff_t *pos) 278e5a81b62SSteven Rostedt { 279e5a81b62SSteven Rostedt local_irq_disable(); 2804f48f8b7SLai Jiangshan 2818aaf1ee7SSteven Rostedt (VMware) __this_cpu_inc(disable_stack_tracer); 2824f48f8b7SLai Jiangshan 283d332736dSSteven Rostedt (Red Hat) arch_spin_lock(&stack_trace_max_lock); 284e5a81b62SSteven Rostedt 285522a110bSLiming Wang if (*pos == 0) 286522a110bSLiming Wang return SEQ_START_TOKEN; 287522a110bSLiming Wang 2882fc5f0cfSLi Zefan return __next(m, pos); 289e5a81b62SSteven Rostedt } 290e5a81b62SSteven Rostedt 291e5a81b62SSteven Rostedt static void t_stop(struct seq_file *m, void *p) 292e5a81b62SSteven Rostedt { 293d332736dSSteven Rostedt (Red Hat) arch_spin_unlock(&stack_trace_max_lock); 2944f48f8b7SLai Jiangshan 2958aaf1ee7SSteven Rostedt (VMware) __this_cpu_dec(disable_stack_tracer); 2964f48f8b7SLai Jiangshan 297e5a81b62SSteven Rostedt local_irq_enable(); 298e5a81b62SSteven Rostedt } 299e5a81b62SSteven Rostedt 300962e3707SJoe Perches static void trace_lookup_stack(struct seq_file *m, long i) 301e5a81b62SSteven Rostedt { 3021b6cced6SSteven Rostedt unsigned long addr = stack_dump_trace[i]; 303e5a81b62SSteven Rostedt 304962e3707SJoe Perches seq_printf(m, "%pS\n", (void *)addr); 305e5a81b62SSteven Rostedt } 306e5a81b62SSteven Rostedt 307e447e1dfSSteven Rostedt static void print_disabled(struct seq_file *m) 308e447e1dfSSteven Rostedt { 309e447e1dfSSteven Rostedt seq_puts(m, "#\n" 310e447e1dfSSteven Rostedt "# Stack tracer disabled\n" 311e447e1dfSSteven Rostedt "#\n" 312e447e1dfSSteven Rostedt "# To enable the stack tracer, either add 'stacktrace' to the\n" 313e447e1dfSSteven Rostedt "# kernel command line\n" 314e447e1dfSSteven Rostedt "# or 'echo 1 > /proc/sys/kernel/stack_tracer_enabled'\n" 315e447e1dfSSteven Rostedt "#\n"); 316e447e1dfSSteven Rostedt } 317e447e1dfSSteven Rostedt 318e5a81b62SSteven Rostedt static int t_show(struct seq_file *m, void *v) 319e5a81b62SSteven Rostedt { 320522a110bSLiming Wang long i; 3211b6cced6SSteven Rostedt int size; 322e5a81b62SSteven Rostedt 323522a110bSLiming Wang if (v == SEQ_START_TOKEN) { 3241b6cced6SSteven Rostedt seq_printf(m, " Depth Size Location" 3251b6cced6SSteven Rostedt " (%d entries)\n" 3261b6cced6SSteven Rostedt " ----- ---- --------\n", 327*9f50c91bSThomas Gleixner stack_trace_nr_entries); 328e447e1dfSSteven Rostedt 329bb99d8ccSAKASHI Takahiro if (!stack_tracer_enabled && !stack_trace_max_size) 330e447e1dfSSteven Rostedt print_disabled(m); 331e447e1dfSSteven Rostedt 3321b6cced6SSteven Rostedt return 0; 3331b6cced6SSteven Rostedt } 3341b6cced6SSteven Rostedt 335522a110bSLiming Wang i = *(long *)v; 336522a110bSLiming Wang 337*9f50c91bSThomas Gleixner if (i >= stack_trace_nr_entries) 338e5a81b62SSteven Rostedt return 0; 339e5a81b62SSteven Rostedt 340*9f50c91bSThomas Gleixner if (i + 1 == stack_trace_nr_entries) 341bb99d8ccSAKASHI Takahiro size = stack_trace_index[i]; 3421b6cced6SSteven Rostedt else 343bb99d8ccSAKASHI Takahiro size = stack_trace_index[i] - stack_trace_index[i+1]; 3441b6cced6SSteven Rostedt 345bb99d8ccSAKASHI Takahiro seq_printf(m, "%3ld) %8d %5d ", i, stack_trace_index[i], size); 3461b6cced6SSteven Rostedt 3471b6cced6SSteven Rostedt trace_lookup_stack(m, i); 348e5a81b62SSteven Rostedt 349e5a81b62SSteven Rostedt return 0; 350e5a81b62SSteven Rostedt } 351e5a81b62SSteven Rostedt 352f38f1d2aSSteven Rostedt static const struct seq_operations stack_trace_seq_ops = { 353e5a81b62SSteven Rostedt .start = t_start, 354e5a81b62SSteven Rostedt .next = t_next, 355e5a81b62SSteven Rostedt .stop = t_stop, 356e5a81b62SSteven Rostedt .show = t_show, 357e5a81b62SSteven Rostedt }; 358e5a81b62SSteven Rostedt 359e5a81b62SSteven Rostedt static int stack_trace_open(struct inode *inode, struct file *file) 360e5a81b62SSteven Rostedt { 361d8cc1ab7SLi Zefan return seq_open(file, &stack_trace_seq_ops); 362e5a81b62SSteven Rostedt } 363e5a81b62SSteven Rostedt 364f38f1d2aSSteven Rostedt static const struct file_operations stack_trace_fops = { 365e5a81b62SSteven Rostedt .open = stack_trace_open, 366e5a81b62SSteven Rostedt .read = seq_read, 367e5a81b62SSteven Rostedt .llseek = seq_lseek, 368d8cc1ab7SLi Zefan .release = seq_release, 369e5a81b62SSteven Rostedt }; 370e5a81b62SSteven Rostedt 371bbd1d27dSSteven Rostedt (VMware) #ifdef CONFIG_DYNAMIC_FTRACE 372bbd1d27dSSteven Rostedt (VMware) 373d2d45c7aSSteven Rostedt static int 374d2d45c7aSSteven Rostedt stack_trace_filter_open(struct inode *inode, struct file *file) 375d2d45c7aSSteven Rostedt { 3760f179765SSteven Rostedt (VMware) struct ftrace_ops *ops = inode->i_private; 3770f179765SSteven Rostedt (VMware) 3780f179765SSteven Rostedt (VMware) return ftrace_regex_open(ops, FTRACE_ITER_FILTER, 379d2d45c7aSSteven Rostedt inode, file); 380d2d45c7aSSteven Rostedt } 381d2d45c7aSSteven Rostedt 382d2d45c7aSSteven Rostedt static const struct file_operations stack_trace_filter_fops = { 383d2d45c7aSSteven Rostedt .open = stack_trace_filter_open, 384d2d45c7aSSteven Rostedt .read = seq_read, 385d2d45c7aSSteven Rostedt .write = ftrace_filter_write, 386098c879eSSteven Rostedt (Red Hat) .llseek = tracing_lseek, 387d2d45c7aSSteven Rostedt .release = ftrace_regex_release, 388d2d45c7aSSteven Rostedt }; 389d2d45c7aSSteven Rostedt 390bbd1d27dSSteven Rostedt (VMware) #endif /* CONFIG_DYNAMIC_FTRACE */ 391bbd1d27dSSteven Rostedt (VMware) 392f38f1d2aSSteven Rostedt int 393f38f1d2aSSteven Rostedt stack_trace_sysctl(struct ctl_table *table, int write, 3948d65af78SAlexey Dobriyan void __user *buffer, size_t *lenp, 395f38f1d2aSSteven Rostedt loff_t *ppos) 396f38f1d2aSSteven Rostedt { 3973d9a8072SThomas Gleixner int was_enabled; 398f38f1d2aSSteven Rostedt int ret; 399f38f1d2aSSteven Rostedt 400f38f1d2aSSteven Rostedt mutex_lock(&stack_sysctl_mutex); 4013d9a8072SThomas Gleixner was_enabled = !!stack_tracer_enabled; 402f38f1d2aSSteven Rostedt 4038d65af78SAlexey Dobriyan ret = proc_dointvec(table, write, buffer, lenp, ppos); 404f38f1d2aSSteven Rostedt 4053d9a8072SThomas Gleixner if (ret || !write || (was_enabled == !!stack_tracer_enabled)) 406f38f1d2aSSteven Rostedt goto out; 407f38f1d2aSSteven Rostedt 408f38f1d2aSSteven Rostedt if (stack_tracer_enabled) 409f38f1d2aSSteven Rostedt register_ftrace_function(&trace_ops); 410f38f1d2aSSteven Rostedt else 411f38f1d2aSSteven Rostedt unregister_ftrace_function(&trace_ops); 412f38f1d2aSSteven Rostedt out: 413f38f1d2aSSteven Rostedt mutex_unlock(&stack_sysctl_mutex); 414f38f1d2aSSteven Rostedt return ret; 415f38f1d2aSSteven Rostedt } 416f38f1d2aSSteven Rostedt 417762e1207SSteven Rostedt static char stack_trace_filter_buf[COMMAND_LINE_SIZE+1] __initdata; 418762e1207SSteven Rostedt 419f38f1d2aSSteven Rostedt static __init int enable_stacktrace(char *str) 420f38f1d2aSSteven Rostedt { 4213d739c1fSSteven Rostedt (VMware) int len; 4223d739c1fSSteven Rostedt (VMware) 4233d739c1fSSteven Rostedt (VMware) if ((len = str_has_prefix(str, "_filter="))) 4243d739c1fSSteven Rostedt (VMware) strncpy(stack_trace_filter_buf, str + len, COMMAND_LINE_SIZE); 425762e1207SSteven Rostedt 426e05a43b7SSteven Rostedt stack_tracer_enabled = 1; 427f38f1d2aSSteven Rostedt return 1; 428f38f1d2aSSteven Rostedt } 429f38f1d2aSSteven Rostedt __setup("stacktrace", enable_stacktrace); 430f38f1d2aSSteven Rostedt 431e5a81b62SSteven Rostedt static __init int stack_trace_init(void) 432e5a81b62SSteven Rostedt { 433e5a81b62SSteven Rostedt struct dentry *d_tracer; 434e5a81b62SSteven Rostedt 435e5a81b62SSteven Rostedt d_tracer = tracing_init_dentry(); 43614a5ae40SSteven Rostedt (Red Hat) if (IS_ERR(d_tracer)) 437ed6f1c99SNamhyung Kim return 0; 438e5a81b62SSteven Rostedt 4395452af66SFrederic Weisbecker trace_create_file("stack_max_size", 0644, d_tracer, 440bb99d8ccSAKASHI Takahiro &stack_trace_max_size, &stack_max_size_fops); 441e5a81b62SSteven Rostedt 4425452af66SFrederic Weisbecker trace_create_file("stack_trace", 0444, d_tracer, 443e5a81b62SSteven Rostedt NULL, &stack_trace_fops); 444e5a81b62SSteven Rostedt 445bbd1d27dSSteven Rostedt (VMware) #ifdef CONFIG_DYNAMIC_FTRACE 4460c5a9accSZhengyuan Liu trace_create_file("stack_trace_filter", 0644, d_tracer, 4470f179765SSteven Rostedt (VMware) &trace_ops, &stack_trace_filter_fops); 448bbd1d27dSSteven Rostedt (VMware) #endif 449d2d45c7aSSteven Rostedt 450762e1207SSteven Rostedt if (stack_trace_filter_buf[0]) 451762e1207SSteven Rostedt ftrace_set_early_filter(&trace_ops, stack_trace_filter_buf, 1); 452762e1207SSteven Rostedt 453e05a43b7SSteven Rostedt if (stack_tracer_enabled) 454e5a81b62SSteven Rostedt register_ftrace_function(&trace_ops); 455e5a81b62SSteven Rostedt 456e5a81b62SSteven Rostedt return 0; 457e5a81b62SSteven Rostedt } 458e5a81b62SSteven Rostedt 459e5a81b62SSteven Rostedt device_initcall(stack_trace_init); 460