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 269f50c91bSThomas 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", 439f50c91bSThomas Gleixner stack_trace_nr_entries); 44e3172181SMinchan Kim 459f50c91bSThomas Gleixner for (i = 0; i < stack_trace_nr_entries; i++) { 469f50c91bSThomas 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 56*58fe7a87SSteven Rostedt (VMware) /* 57*58fe7a87SSteven Rostedt (VMware) * The stack tracer looks for a maximum stack at each call from a function. It 58*58fe7a87SSteven Rostedt (VMware) * registers a callback from ftrace, and in that callback it examines the stack 59*58fe7a87SSteven Rostedt (VMware) * size. It determines the stack size from the variable passed in, which is the 60*58fe7a87SSteven Rostedt (VMware) * address of a local variable in the stack_trace_call() callback function. 61*58fe7a87SSteven Rostedt (VMware) * The stack size is calculated by the address of the local variable to the top 62*58fe7a87SSteven Rostedt (VMware) * of the current stack. If that size is smaller than the currently saved max 63*58fe7a87SSteven Rostedt (VMware) * stack size, nothing more is done. 64*58fe7a87SSteven Rostedt (VMware) * 65*58fe7a87SSteven Rostedt (VMware) * If the size of the stack is greater than the maximum recorded size, then the 66*58fe7a87SSteven Rostedt (VMware) * following algorithm takes place. 67*58fe7a87SSteven Rostedt (VMware) * 68*58fe7a87SSteven Rostedt (VMware) * For architectures (like x86) that store the function's return address before 69*58fe7a87SSteven Rostedt (VMware) * saving the function's local variables, the stack will look something like 70*58fe7a87SSteven Rostedt (VMware) * this: 71*58fe7a87SSteven Rostedt (VMware) * 72*58fe7a87SSteven Rostedt (VMware) * [ top of stack ] 73*58fe7a87SSteven Rostedt (VMware) * 0: sys call entry frame 74*58fe7a87SSteven Rostedt (VMware) * 10: return addr to entry code 75*58fe7a87SSteven Rostedt (VMware) * 11: start of sys_foo frame 76*58fe7a87SSteven Rostedt (VMware) * 20: return addr to sys_foo 77*58fe7a87SSteven Rostedt (VMware) * 21: start of kernel_func_bar frame 78*58fe7a87SSteven Rostedt (VMware) * 30: return addr to kernel_func_bar 79*58fe7a87SSteven Rostedt (VMware) * 31: [ do trace stack here ] 80*58fe7a87SSteven Rostedt (VMware) * 81*58fe7a87SSteven Rostedt (VMware) * The save_stack_trace() is called returning all the functions it finds in the 82*58fe7a87SSteven Rostedt (VMware) * current stack. Which would be (from the bottom of the stack to the top): 83*58fe7a87SSteven Rostedt (VMware) * 84*58fe7a87SSteven Rostedt (VMware) * return addr to kernel_func_bar 85*58fe7a87SSteven Rostedt (VMware) * return addr to sys_foo 86*58fe7a87SSteven Rostedt (VMware) * return addr to entry code 87*58fe7a87SSteven Rostedt (VMware) * 88*58fe7a87SSteven Rostedt (VMware) * Now to figure out how much each of these functions' local variable size is, 89*58fe7a87SSteven Rostedt (VMware) * a search of the stack is made to find these values. When a match is made, it 90*58fe7a87SSteven Rostedt (VMware) * is added to the stack_dump_trace[] array. The offset into the stack is saved 91*58fe7a87SSteven Rostedt (VMware) * in the stack_trace_index[] array. The above example would show: 92*58fe7a87SSteven Rostedt (VMware) * 93*58fe7a87SSteven Rostedt (VMware) * stack_dump_trace[] | stack_trace_index[] 94*58fe7a87SSteven Rostedt (VMware) * ------------------ + ------------------- 95*58fe7a87SSteven Rostedt (VMware) * return addr to kernel_func_bar | 30 96*58fe7a87SSteven Rostedt (VMware) * return addr to sys_foo | 20 97*58fe7a87SSteven Rostedt (VMware) * return addr to entry | 10 98*58fe7a87SSteven Rostedt (VMware) * 99*58fe7a87SSteven Rostedt (VMware) * The print_max_stack() function above, uses these values to print the size of 100*58fe7a87SSteven Rostedt (VMware) * each function's portion of the stack. 101*58fe7a87SSteven Rostedt (VMware) * 102*58fe7a87SSteven Rostedt (VMware) * for (i = 0; i < nr_entries; i++) { 103*58fe7a87SSteven Rostedt (VMware) * size = i == nr_entries - 1 ? stack_trace_index[i] : 104*58fe7a87SSteven Rostedt (VMware) * stack_trace_index[i] - stack_trace_index[i+1] 105*58fe7a87SSteven Rostedt (VMware) * print "%d %d %d %s\n", i, stack_trace_index[i], size, stack_dump_trace[i]); 106*58fe7a87SSteven Rostedt (VMware) * } 107*58fe7a87SSteven Rostedt (VMware) * 108*58fe7a87SSteven Rostedt (VMware) * The above shows 109*58fe7a87SSteven Rostedt (VMware) * 110*58fe7a87SSteven Rostedt (VMware) * depth size location 111*58fe7a87SSteven Rostedt (VMware) * ----- ---- -------- 112*58fe7a87SSteven Rostedt (VMware) * 0 30 10 kernel_func_bar 113*58fe7a87SSteven Rostedt (VMware) * 1 20 10 sys_foo 114*58fe7a87SSteven Rostedt (VMware) * 2 10 10 entry code 115*58fe7a87SSteven Rostedt (VMware) * 116*58fe7a87SSteven Rostedt (VMware) * Now for architectures that might save the return address after the functions 117*58fe7a87SSteven Rostedt (VMware) * local variables (saving the link register before calling nested functions), 118*58fe7a87SSteven Rostedt (VMware) * this will cause the stack to look a little different: 119*58fe7a87SSteven Rostedt (VMware) * 120*58fe7a87SSteven Rostedt (VMware) * [ top of stack ] 121*58fe7a87SSteven Rostedt (VMware) * 0: sys call entry frame 122*58fe7a87SSteven Rostedt (VMware) * 10: start of sys_foo_frame 123*58fe7a87SSteven Rostedt (VMware) * 19: return addr to entry code << lr saved before calling kernel_func_bar 124*58fe7a87SSteven Rostedt (VMware) * 20: start of kernel_func_bar frame 125*58fe7a87SSteven Rostedt (VMware) * 29: return addr to sys_foo_frame << lr saved before calling next function 126*58fe7a87SSteven Rostedt (VMware) * 30: [ do trace stack here ] 127*58fe7a87SSteven Rostedt (VMware) * 128*58fe7a87SSteven Rostedt (VMware) * Although the functions returned by save_stack_trace() may be the same, the 129*58fe7a87SSteven Rostedt (VMware) * placement in the stack will be different. Using the same algorithm as above 130*58fe7a87SSteven Rostedt (VMware) * would yield: 131*58fe7a87SSteven Rostedt (VMware) * 132*58fe7a87SSteven Rostedt (VMware) * stack_dump_trace[] | stack_trace_index[] 133*58fe7a87SSteven Rostedt (VMware) * ------------------ + ------------------- 134*58fe7a87SSteven Rostedt (VMware) * return addr to kernel_func_bar | 30 135*58fe7a87SSteven Rostedt (VMware) * return addr to sys_foo | 29 136*58fe7a87SSteven Rostedt (VMware) * return addr to entry | 19 137*58fe7a87SSteven Rostedt (VMware) * 138*58fe7a87SSteven Rostedt (VMware) * Where the mapping is off by one: 139*58fe7a87SSteven Rostedt (VMware) * 140*58fe7a87SSteven Rostedt (VMware) * kernel_func_bar stack frame size is 29 - 19 not 30 - 29! 141*58fe7a87SSteven Rostedt (VMware) * 142*58fe7a87SSteven Rostedt (VMware) * To fix this, if the architecture sets ARCH_RET_ADDR_AFTER_LOCAL_VARS the 143*58fe7a87SSteven Rostedt (VMware) * values in stack_trace_index[] are shifted by one to and the number of 144*58fe7a87SSteven Rostedt (VMware) * stack trace entries is decremented by one. 145*58fe7a87SSteven Rostedt (VMware) * 146*58fe7a87SSteven Rostedt (VMware) * stack_dump_trace[] | stack_trace_index[] 147*58fe7a87SSteven Rostedt (VMware) * ------------------ + ------------------- 148*58fe7a87SSteven Rostedt (VMware) * return addr to kernel_func_bar | 29 149*58fe7a87SSteven Rostedt (VMware) * return addr to sys_foo | 19 150*58fe7a87SSteven Rostedt (VMware) * 151*58fe7a87SSteven Rostedt (VMware) * Although the entry function is not displayed, the first function (sys_foo) 152*58fe7a87SSteven Rostedt (VMware) * will still include the stack size of it. 153*58fe7a87SSteven Rostedt (VMware) */ 1543d9a8072SThomas Gleixner static void check_stack(unsigned long ip, unsigned long *stack) 155e5a81b62SSteven Rostedt { 156e3172181SMinchan Kim unsigned long this_size, flags; unsigned long *p, *top, *start; 1574df29712SSteven Rostedt (Red Hat) static int tracer_frame; 1586aa7de05SMark Rutland int frame_size = READ_ONCE(tracer_frame); 15972ac426aSSteven Rostedt (Red Hat) int i, x; 160e5a81b62SSteven Rostedt 16187889501SSteven Rostedt (Red Hat) this_size = ((unsigned long)stack) & (THREAD_SIZE-1); 162e5a81b62SSteven Rostedt this_size = THREAD_SIZE - this_size; 1634df29712SSteven Rostedt (Red Hat) /* Remove the frame of the tracer */ 1644df29712SSteven Rostedt (Red Hat) this_size -= frame_size; 165e5a81b62SSteven Rostedt 166bb99d8ccSAKASHI Takahiro if (this_size <= stack_trace_max_size) 167e5a81b62SSteven Rostedt return; 168e5a81b62SSteven Rostedt 16981520a1bSSteven Rostedt /* we do not handle interrupt stacks yet */ 17087889501SSteven Rostedt (Red Hat) if (!object_is_on_stack(stack)) 17181520a1bSSteven Rostedt return; 17281520a1bSSteven Rostedt 1731904be1bSSteven Rostedt (Red Hat) /* Can't do this from NMI context (can cause deadlocks) */ 1741904be1bSSteven Rostedt (Red Hat) if (in_nmi()) 1751904be1bSSteven Rostedt (Red Hat) return; 1761904be1bSSteven Rostedt (Red Hat) 177a5e25883SSteven Rostedt local_irq_save(flags); 178d332736dSSteven Rostedt (Red Hat) arch_spin_lock(&stack_trace_max_lock); 179e5a81b62SSteven Rostedt 1804df29712SSteven Rostedt (Red Hat) /* In case another CPU set the tracer_frame on us */ 1814df29712SSteven Rostedt (Red Hat) if (unlikely(!frame_size)) 1824df29712SSteven Rostedt (Red Hat) this_size -= tracer_frame; 1834df29712SSteven Rostedt (Red Hat) 184e5a81b62SSteven Rostedt /* a race could have already updated it */ 185bb99d8ccSAKASHI Takahiro if (this_size <= stack_trace_max_size) 186e5a81b62SSteven Rostedt goto out; 187e5a81b62SSteven Rostedt 188bb99d8ccSAKASHI Takahiro stack_trace_max_size = this_size; 189e5a81b62SSteven Rostedt 1909f50c91bSThomas Gleixner stack_trace_nr_entries = stack_trace_save(stack_dump_trace, 1919f50c91bSThomas Gleixner ARRAY_SIZE(stack_dump_trace) - 1, 1929f50c91bSThomas Gleixner 0); 193e5a81b62SSteven Rostedt 19472ac426aSSteven Rostedt (Red Hat) /* Skip over the overhead of the stack tracer itself */ 1959f50c91bSThomas Gleixner for (i = 0; i < stack_trace_nr_entries; i++) { 19672ac426aSSteven Rostedt (Red Hat) if (stack_dump_trace[i] == ip) 19772ac426aSSteven Rostedt (Red Hat) break; 19872ac426aSSteven Rostedt (Red Hat) } 199d4ecbfc4SSteven Rostedt (Red Hat) 200d4ecbfc4SSteven Rostedt (Red Hat) /* 2016ccd8371SSteven Rostedt * Some archs may not have the passed in ip in the dump. 2026ccd8371SSteven Rostedt * If that happens, we need to show everything. 2036ccd8371SSteven Rostedt */ 2049f50c91bSThomas Gleixner if (i == stack_trace_nr_entries) 2056ccd8371SSteven Rostedt i = 0; 2066ccd8371SSteven Rostedt 2076ccd8371SSteven Rostedt /* 2081b6cced6SSteven Rostedt * Now find where in the stack these are. 2091b6cced6SSteven Rostedt */ 21072ac426aSSteven Rostedt (Red Hat) x = 0; 21187889501SSteven Rostedt (Red Hat) start = stack; 2121b6cced6SSteven Rostedt top = (unsigned long *) 2131b6cced6SSteven Rostedt (((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE); 2141b6cced6SSteven Rostedt 2151b6cced6SSteven Rostedt /* 2161b6cced6SSteven Rostedt * Loop through all the entries. One of the entries may 2171b6cced6SSteven Rostedt * for some reason be missed on the stack, so we may 2181b6cced6SSteven Rostedt * have to account for them. If they are all there, this 2191b6cced6SSteven Rostedt * loop will only happen once. This code only takes place 2201b6cced6SSteven Rostedt * on a new max, so it is far from a fast path. 2211b6cced6SSteven Rostedt */ 2229f50c91bSThomas Gleixner while (i < stack_trace_nr_entries) { 2230a37119dSSteven Rostedt int found = 0; 2241b6cced6SSteven Rostedt 225bb99d8ccSAKASHI Takahiro stack_trace_index[x] = this_size; 2261b6cced6SSteven Rostedt p = start; 2271b6cced6SSteven Rostedt 2289f50c91bSThomas Gleixner for (; p < top && i < stack_trace_nr_entries; p++) { 2296e22c836SYang Shi /* 2306e22c836SYang Shi * The READ_ONCE_NOCHECK is used to let KASAN know that 2316e22c836SYang Shi * this is not a stack-out-of-bounds error. 2326e22c836SYang Shi */ 2336e22c836SYang Shi if ((READ_ONCE_NOCHECK(*p)) == stack_dump_trace[i]) { 23472ac426aSSteven Rostedt (Red Hat) stack_dump_trace[x] = stack_dump_trace[i++]; 235bb99d8ccSAKASHI Takahiro this_size = stack_trace_index[x++] = 2361b6cced6SSteven Rostedt (top - p) * sizeof(unsigned long); 2370a37119dSSteven Rostedt found = 1; 2381b6cced6SSteven Rostedt /* Start the search from here */ 2391b6cced6SSteven Rostedt start = p + 1; 2404df29712SSteven Rostedt (Red Hat) /* 2414df29712SSteven Rostedt (Red Hat) * We do not want to show the overhead 2424df29712SSteven Rostedt (Red Hat) * of the stack tracer stack in the 2434df29712SSteven Rostedt (Red Hat) * max stack. If we haven't figured 2444df29712SSteven Rostedt (Red Hat) * out what that is, then figure it out 2454df29712SSteven Rostedt (Red Hat) * now. 2464df29712SSteven Rostedt (Red Hat) */ 24772ac426aSSteven Rostedt (Red Hat) if (unlikely(!tracer_frame)) { 2484df29712SSteven Rostedt (Red Hat) tracer_frame = (p - stack) * 2494df29712SSteven Rostedt (Red Hat) sizeof(unsigned long); 250bb99d8ccSAKASHI Takahiro stack_trace_max_size -= tracer_frame; 2514df29712SSteven Rostedt (Red Hat) } 2521b6cced6SSteven Rostedt } 2531b6cced6SSteven Rostedt } 2541b6cced6SSteven Rostedt 2550a37119dSSteven Rostedt if (!found) 2561b6cced6SSteven Rostedt i++; 2571b6cced6SSteven Rostedt } 2581b6cced6SSteven Rostedt 259f7edb451SSteven Rostedt (VMware) #ifdef ARCH_FTRACE_SHIFT_STACK_TRACER 260f7edb451SSteven Rostedt (VMware) /* 261f7edb451SSteven Rostedt (VMware) * Some archs will store the link register before calling 262f7edb451SSteven Rostedt (VMware) * nested functions. This means the saved return address 263f7edb451SSteven Rostedt (VMware) * comes after the local storage, and we need to shift 264f7edb451SSteven Rostedt (VMware) * for that. 265f7edb451SSteven Rostedt (VMware) */ 266f7edb451SSteven Rostedt (VMware) if (x > 1) { 267f7edb451SSteven Rostedt (VMware) memmove(&stack_trace_index[0], &stack_trace_index[1], 268f7edb451SSteven Rostedt (VMware) sizeof(stack_trace_index[0]) * (x - 1)); 269f7edb451SSteven Rostedt (VMware) x--; 270f7edb451SSteven Rostedt (VMware) } 271f7edb451SSteven Rostedt (VMware) #endif 272f7edb451SSteven Rostedt (VMware) 2739f50c91bSThomas Gleixner stack_trace_nr_entries = x; 27472ac426aSSteven Rostedt (Red Hat) 275a70857e4SAaron Tomlin if (task_stack_end_corrupted(current)) { 2763d9a8072SThomas Gleixner print_max_stack(); 277e3172181SMinchan Kim BUG(); 278e3172181SMinchan Kim } 279e3172181SMinchan Kim 280e5a81b62SSteven Rostedt out: 281d332736dSSteven Rostedt (Red Hat) arch_spin_unlock(&stack_trace_max_lock); 282a5e25883SSteven Rostedt local_irq_restore(flags); 283e5a81b62SSteven Rostedt } 284e5a81b62SSteven Rostedt 285e5a81b62SSteven Rostedt static void 286a1e2e31dSSteven Rostedt stack_trace_call(unsigned long ip, unsigned long parent_ip, 287a1e2e31dSSteven Rostedt struct ftrace_ops *op, struct pt_regs *pt_regs) 288e5a81b62SSteven Rostedt { 28987889501SSteven Rostedt (Red Hat) unsigned long stack; 290e5a81b62SSteven Rostedt 2915168ae50SSteven Rostedt preempt_disable_notrace(); 292e5a81b62SSteven Rostedt 293e5a81b62SSteven Rostedt /* no atomic needed, we only modify this variable by this cpu */ 2948aaf1ee7SSteven Rostedt (VMware) __this_cpu_inc(disable_stack_tracer); 2958aaf1ee7SSteven Rostedt (VMware) if (__this_cpu_read(disable_stack_tracer) != 1) 296e5a81b62SSteven Rostedt goto out; 297e5a81b62SSteven Rostedt 298b00d607bSSteven Rostedt (VMware) /* If rcu is not watching, then save stack trace can fail */ 299b00d607bSSteven Rostedt (VMware) if (!rcu_is_watching()) 300b00d607bSSteven Rostedt (VMware) goto out; 301b00d607bSSteven Rostedt (VMware) 3024df29712SSteven Rostedt (Red Hat) ip += MCOUNT_INSN_SIZE; 3034df29712SSteven Rostedt (Red Hat) 3044df29712SSteven Rostedt (Red Hat) check_stack(ip, &stack); 305e5a81b62SSteven Rostedt 306e5a81b62SSteven Rostedt out: 3078aaf1ee7SSteven Rostedt (VMware) __this_cpu_dec(disable_stack_tracer); 308e5a81b62SSteven Rostedt /* prevent recursion in schedule */ 3095168ae50SSteven Rostedt preempt_enable_notrace(); 310e5a81b62SSteven Rostedt } 311e5a81b62SSteven Rostedt 312e5a81b62SSteven Rostedt static struct ftrace_ops trace_ops __read_mostly = 313e5a81b62SSteven Rostedt { 314e5a81b62SSteven Rostedt .func = stack_trace_call, 3154740974aSSteven Rostedt .flags = FTRACE_OPS_FL_RECURSION_SAFE, 316e5a81b62SSteven Rostedt }; 317e5a81b62SSteven Rostedt 318e5a81b62SSteven Rostedt static ssize_t 319e5a81b62SSteven Rostedt stack_max_size_read(struct file *filp, char __user *ubuf, 320e5a81b62SSteven Rostedt size_t count, loff_t *ppos) 321e5a81b62SSteven Rostedt { 322e5a81b62SSteven Rostedt unsigned long *ptr = filp->private_data; 323e5a81b62SSteven Rostedt char buf[64]; 324e5a81b62SSteven Rostedt int r; 325e5a81b62SSteven Rostedt 326e5a81b62SSteven Rostedt r = snprintf(buf, sizeof(buf), "%ld\n", *ptr); 327e5a81b62SSteven Rostedt if (r > sizeof(buf)) 328e5a81b62SSteven Rostedt r = sizeof(buf); 329e5a81b62SSteven Rostedt return simple_read_from_buffer(ubuf, count, ppos, buf, r); 330e5a81b62SSteven Rostedt } 331e5a81b62SSteven Rostedt 332e5a81b62SSteven Rostedt static ssize_t 333e5a81b62SSteven Rostedt stack_max_size_write(struct file *filp, const char __user *ubuf, 334e5a81b62SSteven Rostedt size_t count, loff_t *ppos) 335e5a81b62SSteven Rostedt { 336e5a81b62SSteven Rostedt long *ptr = filp->private_data; 337e5a81b62SSteven Rostedt unsigned long val, flags; 338e5a81b62SSteven Rostedt int ret; 339e5a81b62SSteven Rostedt 34022fe9b54SPeter Huewe ret = kstrtoul_from_user(ubuf, count, 10, &val); 34122fe9b54SPeter Huewe if (ret) 342e5a81b62SSteven Rostedt return ret; 343e5a81b62SSteven Rostedt 344a5e25883SSteven Rostedt local_irq_save(flags); 3454f48f8b7SLai Jiangshan 3464f48f8b7SLai Jiangshan /* 3474f48f8b7SLai Jiangshan * In case we trace inside arch_spin_lock() or after (NMI), 3484f48f8b7SLai Jiangshan * we will cause circular lock, so we also need to increase 3498aaf1ee7SSteven Rostedt (VMware) * the percpu disable_stack_tracer here. 3504f48f8b7SLai Jiangshan */ 3518aaf1ee7SSteven Rostedt (VMware) __this_cpu_inc(disable_stack_tracer); 3524f48f8b7SLai Jiangshan 353d332736dSSteven Rostedt (Red Hat) arch_spin_lock(&stack_trace_max_lock); 354e5a81b62SSteven Rostedt *ptr = val; 355d332736dSSteven Rostedt (Red Hat) arch_spin_unlock(&stack_trace_max_lock); 3564f48f8b7SLai Jiangshan 3578aaf1ee7SSteven Rostedt (VMware) __this_cpu_dec(disable_stack_tracer); 358a5e25883SSteven Rostedt local_irq_restore(flags); 359e5a81b62SSteven Rostedt 360e5a81b62SSteven Rostedt return count; 361e5a81b62SSteven Rostedt } 362e5a81b62SSteven Rostedt 363f38f1d2aSSteven Rostedt static const struct file_operations stack_max_size_fops = { 364e5a81b62SSteven Rostedt .open = tracing_open_generic, 365e5a81b62SSteven Rostedt .read = stack_max_size_read, 366e5a81b62SSteven Rostedt .write = stack_max_size_write, 3676038f373SArnd Bergmann .llseek = default_llseek, 368e5a81b62SSteven Rostedt }; 369e5a81b62SSteven Rostedt 370e5a81b62SSteven Rostedt static void * 3712fc5f0cfSLi Zefan __next(struct seq_file *m, loff_t *pos) 372e5a81b62SSteven Rostedt { 3732fc5f0cfSLi Zefan long n = *pos - 1; 374e5a81b62SSteven Rostedt 3759f50c91bSThomas Gleixner if (n >= stack_trace_nr_entries) 376e5a81b62SSteven Rostedt return NULL; 377e5a81b62SSteven Rostedt 3782fc5f0cfSLi Zefan m->private = (void *)n; 3791b6cced6SSteven Rostedt return &m->private; 380e5a81b62SSteven Rostedt } 381e5a81b62SSteven Rostedt 3822fc5f0cfSLi Zefan static void * 3832fc5f0cfSLi Zefan t_next(struct seq_file *m, void *v, loff_t *pos) 3842fc5f0cfSLi Zefan { 3852fc5f0cfSLi Zefan (*pos)++; 3862fc5f0cfSLi Zefan return __next(m, pos); 3872fc5f0cfSLi Zefan } 3882fc5f0cfSLi Zefan 389e5a81b62SSteven Rostedt static void *t_start(struct seq_file *m, loff_t *pos) 390e5a81b62SSteven Rostedt { 391e5a81b62SSteven Rostedt local_irq_disable(); 3924f48f8b7SLai Jiangshan 3938aaf1ee7SSteven Rostedt (VMware) __this_cpu_inc(disable_stack_tracer); 3944f48f8b7SLai Jiangshan 395d332736dSSteven Rostedt (Red Hat) arch_spin_lock(&stack_trace_max_lock); 396e5a81b62SSteven Rostedt 397522a110bSLiming Wang if (*pos == 0) 398522a110bSLiming Wang return SEQ_START_TOKEN; 399522a110bSLiming Wang 4002fc5f0cfSLi Zefan return __next(m, pos); 401e5a81b62SSteven Rostedt } 402e5a81b62SSteven Rostedt 403e5a81b62SSteven Rostedt static void t_stop(struct seq_file *m, void *p) 404e5a81b62SSteven Rostedt { 405d332736dSSteven Rostedt (Red Hat) arch_spin_unlock(&stack_trace_max_lock); 4064f48f8b7SLai Jiangshan 4078aaf1ee7SSteven Rostedt (VMware) __this_cpu_dec(disable_stack_tracer); 4084f48f8b7SLai Jiangshan 409e5a81b62SSteven Rostedt local_irq_enable(); 410e5a81b62SSteven Rostedt } 411e5a81b62SSteven Rostedt 412962e3707SJoe Perches static void trace_lookup_stack(struct seq_file *m, long i) 413e5a81b62SSteven Rostedt { 4141b6cced6SSteven Rostedt unsigned long addr = stack_dump_trace[i]; 415e5a81b62SSteven Rostedt 416962e3707SJoe Perches seq_printf(m, "%pS\n", (void *)addr); 417e5a81b62SSteven Rostedt } 418e5a81b62SSteven Rostedt 419e447e1dfSSteven Rostedt static void print_disabled(struct seq_file *m) 420e447e1dfSSteven Rostedt { 421e447e1dfSSteven Rostedt seq_puts(m, "#\n" 422e447e1dfSSteven Rostedt "# Stack tracer disabled\n" 423e447e1dfSSteven Rostedt "#\n" 424e447e1dfSSteven Rostedt "# To enable the stack tracer, either add 'stacktrace' to the\n" 425e447e1dfSSteven Rostedt "# kernel command line\n" 426e447e1dfSSteven Rostedt "# or 'echo 1 > /proc/sys/kernel/stack_tracer_enabled'\n" 427e447e1dfSSteven Rostedt "#\n"); 428e447e1dfSSteven Rostedt } 429e447e1dfSSteven Rostedt 430e5a81b62SSteven Rostedt static int t_show(struct seq_file *m, void *v) 431e5a81b62SSteven Rostedt { 432522a110bSLiming Wang long i; 4331b6cced6SSteven Rostedt int size; 434e5a81b62SSteven Rostedt 435522a110bSLiming Wang if (v == SEQ_START_TOKEN) { 4361b6cced6SSteven Rostedt seq_printf(m, " Depth Size Location" 4371b6cced6SSteven Rostedt " (%d entries)\n" 4381b6cced6SSteven Rostedt " ----- ---- --------\n", 4399f50c91bSThomas Gleixner stack_trace_nr_entries); 440e447e1dfSSteven Rostedt 441bb99d8ccSAKASHI Takahiro if (!stack_tracer_enabled && !stack_trace_max_size) 442e447e1dfSSteven Rostedt print_disabled(m); 443e447e1dfSSteven Rostedt 4441b6cced6SSteven Rostedt return 0; 4451b6cced6SSteven Rostedt } 4461b6cced6SSteven Rostedt 447522a110bSLiming Wang i = *(long *)v; 448522a110bSLiming Wang 4499f50c91bSThomas Gleixner if (i >= stack_trace_nr_entries) 450e5a81b62SSteven Rostedt return 0; 451e5a81b62SSteven Rostedt 4529f50c91bSThomas Gleixner if (i + 1 == stack_trace_nr_entries) 453bb99d8ccSAKASHI Takahiro size = stack_trace_index[i]; 4541b6cced6SSteven Rostedt else 455bb99d8ccSAKASHI Takahiro size = stack_trace_index[i] - stack_trace_index[i+1]; 4561b6cced6SSteven Rostedt 457bb99d8ccSAKASHI Takahiro seq_printf(m, "%3ld) %8d %5d ", i, stack_trace_index[i], size); 4581b6cced6SSteven Rostedt 4591b6cced6SSteven Rostedt trace_lookup_stack(m, i); 460e5a81b62SSteven Rostedt 461e5a81b62SSteven Rostedt return 0; 462e5a81b62SSteven Rostedt } 463e5a81b62SSteven Rostedt 464f38f1d2aSSteven Rostedt static const struct seq_operations stack_trace_seq_ops = { 465e5a81b62SSteven Rostedt .start = t_start, 466e5a81b62SSteven Rostedt .next = t_next, 467e5a81b62SSteven Rostedt .stop = t_stop, 468e5a81b62SSteven Rostedt .show = t_show, 469e5a81b62SSteven Rostedt }; 470e5a81b62SSteven Rostedt 471e5a81b62SSteven Rostedt static int stack_trace_open(struct inode *inode, struct file *file) 472e5a81b62SSteven Rostedt { 473d8cc1ab7SLi Zefan return seq_open(file, &stack_trace_seq_ops); 474e5a81b62SSteven Rostedt } 475e5a81b62SSteven Rostedt 476f38f1d2aSSteven Rostedt static const struct file_operations stack_trace_fops = { 477e5a81b62SSteven Rostedt .open = stack_trace_open, 478e5a81b62SSteven Rostedt .read = seq_read, 479e5a81b62SSteven Rostedt .llseek = seq_lseek, 480d8cc1ab7SLi Zefan .release = seq_release, 481e5a81b62SSteven Rostedt }; 482e5a81b62SSteven Rostedt 483bbd1d27dSSteven Rostedt (VMware) #ifdef CONFIG_DYNAMIC_FTRACE 484bbd1d27dSSteven Rostedt (VMware) 485d2d45c7aSSteven Rostedt static int 486d2d45c7aSSteven Rostedt stack_trace_filter_open(struct inode *inode, struct file *file) 487d2d45c7aSSteven Rostedt { 4880f179765SSteven Rostedt (VMware) struct ftrace_ops *ops = inode->i_private; 4890f179765SSteven Rostedt (VMware) 4900f179765SSteven Rostedt (VMware) return ftrace_regex_open(ops, FTRACE_ITER_FILTER, 491d2d45c7aSSteven Rostedt inode, file); 492d2d45c7aSSteven Rostedt } 493d2d45c7aSSteven Rostedt 494d2d45c7aSSteven Rostedt static const struct file_operations stack_trace_filter_fops = { 495d2d45c7aSSteven Rostedt .open = stack_trace_filter_open, 496d2d45c7aSSteven Rostedt .read = seq_read, 497d2d45c7aSSteven Rostedt .write = ftrace_filter_write, 498098c879eSSteven Rostedt (Red Hat) .llseek = tracing_lseek, 499d2d45c7aSSteven Rostedt .release = ftrace_regex_release, 500d2d45c7aSSteven Rostedt }; 501d2d45c7aSSteven Rostedt 502bbd1d27dSSteven Rostedt (VMware) #endif /* CONFIG_DYNAMIC_FTRACE */ 503bbd1d27dSSteven Rostedt (VMware) 504f38f1d2aSSteven Rostedt int 505f38f1d2aSSteven Rostedt stack_trace_sysctl(struct ctl_table *table, int write, 5068d65af78SAlexey Dobriyan void __user *buffer, size_t *lenp, 507f38f1d2aSSteven Rostedt loff_t *ppos) 508f38f1d2aSSteven Rostedt { 5093d9a8072SThomas Gleixner int was_enabled; 510f38f1d2aSSteven Rostedt int ret; 511f38f1d2aSSteven Rostedt 512f38f1d2aSSteven Rostedt mutex_lock(&stack_sysctl_mutex); 5133d9a8072SThomas Gleixner was_enabled = !!stack_tracer_enabled; 514f38f1d2aSSteven Rostedt 5158d65af78SAlexey Dobriyan ret = proc_dointvec(table, write, buffer, lenp, ppos); 516f38f1d2aSSteven Rostedt 5173d9a8072SThomas Gleixner if (ret || !write || (was_enabled == !!stack_tracer_enabled)) 518f38f1d2aSSteven Rostedt goto out; 519f38f1d2aSSteven Rostedt 520f38f1d2aSSteven Rostedt if (stack_tracer_enabled) 521f38f1d2aSSteven Rostedt register_ftrace_function(&trace_ops); 522f38f1d2aSSteven Rostedt else 523f38f1d2aSSteven Rostedt unregister_ftrace_function(&trace_ops); 524f38f1d2aSSteven Rostedt out: 525f38f1d2aSSteven Rostedt mutex_unlock(&stack_sysctl_mutex); 526f38f1d2aSSteven Rostedt return ret; 527f38f1d2aSSteven Rostedt } 528f38f1d2aSSteven Rostedt 529762e1207SSteven Rostedt static char stack_trace_filter_buf[COMMAND_LINE_SIZE+1] __initdata; 530762e1207SSteven Rostedt 531f38f1d2aSSteven Rostedt static __init int enable_stacktrace(char *str) 532f38f1d2aSSteven Rostedt { 5333d739c1fSSteven Rostedt (VMware) int len; 5343d739c1fSSteven Rostedt (VMware) 5353d739c1fSSteven Rostedt (VMware) if ((len = str_has_prefix(str, "_filter="))) 5363d739c1fSSteven Rostedt (VMware) strncpy(stack_trace_filter_buf, str + len, COMMAND_LINE_SIZE); 537762e1207SSteven Rostedt 538e05a43b7SSteven Rostedt stack_tracer_enabled = 1; 539f38f1d2aSSteven Rostedt return 1; 540f38f1d2aSSteven Rostedt } 541f38f1d2aSSteven Rostedt __setup("stacktrace", enable_stacktrace); 542f38f1d2aSSteven Rostedt 543e5a81b62SSteven Rostedt static __init int stack_trace_init(void) 544e5a81b62SSteven Rostedt { 545e5a81b62SSteven Rostedt struct dentry *d_tracer; 546e5a81b62SSteven Rostedt 547e5a81b62SSteven Rostedt d_tracer = tracing_init_dentry(); 54814a5ae40SSteven Rostedt (Red Hat) if (IS_ERR(d_tracer)) 549ed6f1c99SNamhyung Kim return 0; 550e5a81b62SSteven Rostedt 5515452af66SFrederic Weisbecker trace_create_file("stack_max_size", 0644, d_tracer, 552bb99d8ccSAKASHI Takahiro &stack_trace_max_size, &stack_max_size_fops); 553e5a81b62SSteven Rostedt 5545452af66SFrederic Weisbecker trace_create_file("stack_trace", 0444, d_tracer, 555e5a81b62SSteven Rostedt NULL, &stack_trace_fops); 556e5a81b62SSteven Rostedt 557bbd1d27dSSteven Rostedt (VMware) #ifdef CONFIG_DYNAMIC_FTRACE 5580c5a9accSZhengyuan Liu trace_create_file("stack_trace_filter", 0644, d_tracer, 5590f179765SSteven Rostedt (VMware) &trace_ops, &stack_trace_filter_fops); 560bbd1d27dSSteven Rostedt (VMware) #endif 561d2d45c7aSSteven Rostedt 562762e1207SSteven Rostedt if (stack_trace_filter_buf[0]) 563762e1207SSteven Rostedt ftrace_set_early_filter(&trace_ops, stack_trace_filter_buf, 1); 564762e1207SSteven Rostedt 565e05a43b7SSteven Rostedt if (stack_tracer_enabled) 566e5a81b62SSteven Rostedt register_ftrace_function(&trace_ops); 567e5a81b62SSteven Rostedt 568e5a81b62SSteven Rostedt return 0; 569e5a81b62SSteven Rostedt } 570e5a81b62SSteven Rostedt 571e5a81b62SSteven Rostedt device_initcall(stack_trace_init); 572