xref: /linux-6.15/kernel/trace/trace_stack.c (revision 58fe7a87)
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