xref: /linux-6.15/arch/arc/kernel/stacktrace.c (revision 44c8bb91)
1c08098f2SVineet Gupta /*
2*44c8bb91SVineet Gupta  *	stacktrace.c : stacktracing APIs needed by rest of kernel
3*44c8bb91SVineet Gupta  *			(wrappers over ARC dwarf based unwinder)
4*44c8bb91SVineet Gupta  *
5c08098f2SVineet Gupta  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
6c08098f2SVineet Gupta  *
7c08098f2SVineet Gupta  * This program is free software; you can redistribute it and/or modify
8c08098f2SVineet Gupta  * it under the terms of the GNU General Public License version 2 as
9c08098f2SVineet Gupta  * published by the Free Software Foundation.
10*44c8bb91SVineet Gupta  *
11*44c8bb91SVineet Gupta  *  vineetg: aug 2009
12*44c8bb91SVineet Gupta  *  -Implemented CONFIG_STACKTRACE APIs, primarily save_stack_trace_tsk( )
13*44c8bb91SVineet Gupta  *   for displaying task's kernel mode call stack in /proc/<pid>/stack
14*44c8bb91SVineet Gupta  *  -Iterator based approach to have single copy of unwinding core and APIs
15*44c8bb91SVineet Gupta  *   needing unwinding, implement the logic in iterator regarding:
16*44c8bb91SVineet Gupta  *      = which frame onwards to start capture
17*44c8bb91SVineet Gupta  *      = which frame to stop capturing (wchan)
18*44c8bb91SVineet Gupta  *      = specifics of data structs where trace is saved(CONFIG_STACKTRACE etc)
19*44c8bb91SVineet Gupta  *
20*44c8bb91SVineet Gupta  *  vineetg: March 2009
21*44c8bb91SVineet Gupta  *  -Implemented correct versions of thread_saved_pc() and get_wchan()
22*44c8bb91SVineet Gupta  *
23*44c8bb91SVineet Gupta  *  rajeshwarr: 2008
24*44c8bb91SVineet Gupta  *  -Initial implementation
25c08098f2SVineet Gupta  */
26c08098f2SVineet Gupta 
27c08098f2SVineet Gupta #include <linux/ptrace.h>
28c08098f2SVineet Gupta #include <linux/export.h>
29*44c8bb91SVineet Gupta #include <linux/stacktrace.h>
30*44c8bb91SVineet Gupta #include <linux/kallsyms.h>
31*44c8bb91SVineet Gupta #include <asm/arcregs.h>
32*44c8bb91SVineet Gupta #include <asm/unwind.h>
33*44c8bb91SVineet Gupta #include <asm/switch_to.h>
34*44c8bb91SVineet Gupta 
35*44c8bb91SVineet Gupta /*-------------------------------------------------------------------------
36*44c8bb91SVineet Gupta  *              Unwinder Iterator
37*44c8bb91SVineet Gupta  *-------------------------------------------------------------------------
38*44c8bb91SVineet Gupta  */
39*44c8bb91SVineet Gupta 
40*44c8bb91SVineet Gupta #ifdef CONFIG_ARC_DW2_UNWIND
41*44c8bb91SVineet Gupta 
42*44c8bb91SVineet Gupta static void seed_unwind_frame_info(struct task_struct *tsk,
43*44c8bb91SVineet Gupta 				   struct pt_regs *regs,
44*44c8bb91SVineet Gupta 				   struct unwind_frame_info *frame_info)
45*44c8bb91SVineet Gupta {
46*44c8bb91SVineet Gupta 	if (tsk == NULL && regs == NULL) {
47*44c8bb91SVineet Gupta 		unsigned long fp, sp, blink, ret;
48*44c8bb91SVineet Gupta 		frame_info->task = current;
49*44c8bb91SVineet Gupta 
50*44c8bb91SVineet Gupta 		__asm__ __volatile__(
51*44c8bb91SVineet Gupta 			"mov %0,r27\n\t"
52*44c8bb91SVineet Gupta 			"mov %1,r28\n\t"
53*44c8bb91SVineet Gupta 			"mov %2,r31\n\t"
54*44c8bb91SVineet Gupta 			"mov %3,r63\n\t"
55*44c8bb91SVineet Gupta 			: "=r"(fp), "=r"(sp), "=r"(blink), "=r"(ret)
56*44c8bb91SVineet Gupta 		);
57*44c8bb91SVineet Gupta 
58*44c8bb91SVineet Gupta 		frame_info->regs.r27 = fp;
59*44c8bb91SVineet Gupta 		frame_info->regs.r28 = sp;
60*44c8bb91SVineet Gupta 		frame_info->regs.r31 = blink;
61*44c8bb91SVineet Gupta 		frame_info->regs.r63 = ret;
62*44c8bb91SVineet Gupta 		frame_info->call_frame = 0;
63*44c8bb91SVineet Gupta 	} else if (regs == NULL) {
64*44c8bb91SVineet Gupta 
65*44c8bb91SVineet Gupta 		frame_info->task = tsk;
66*44c8bb91SVineet Gupta 
67*44c8bb91SVineet Gupta 		frame_info->regs.r27 = KSTK_FP(tsk);
68*44c8bb91SVineet Gupta 		frame_info->regs.r28 = KSTK_ESP(tsk);
69*44c8bb91SVineet Gupta 		frame_info->regs.r31 = KSTK_BLINK(tsk);
70*44c8bb91SVineet Gupta 		frame_info->regs.r63 = (unsigned int)__switch_to;
71*44c8bb91SVineet Gupta 
72*44c8bb91SVineet Gupta 		/* In the prologue of __switch_to, first FP is saved on stack
73*44c8bb91SVineet Gupta 		 * and then SP is copied to FP. Dwarf assumes cfa as FP based
74*44c8bb91SVineet Gupta 		 * but we didn't save FP. The value retrieved above is FP's
75*44c8bb91SVineet Gupta 		 * state in previous frame.
76*44c8bb91SVineet Gupta 		 * As a work around for this, we unwind from __switch_to start
77*44c8bb91SVineet Gupta 		 * and adjust SP accordingly. The other limitation is that
78*44c8bb91SVineet Gupta 		 * __switch_to macro is dwarf rules are not generated for inline
79*44c8bb91SVineet Gupta 		 * assembly code
80*44c8bb91SVineet Gupta 		 */
81*44c8bb91SVineet Gupta 		frame_info->regs.r27 = 0;
82*44c8bb91SVineet Gupta 		frame_info->regs.r28 += 64;
83*44c8bb91SVineet Gupta 		frame_info->call_frame = 0;
84*44c8bb91SVineet Gupta 
85*44c8bb91SVineet Gupta 	} else {
86*44c8bb91SVineet Gupta 		frame_info->task = tsk;
87*44c8bb91SVineet Gupta 
88*44c8bb91SVineet Gupta 		frame_info->regs.r27 = regs->fp;
89*44c8bb91SVineet Gupta 		frame_info->regs.r28 = regs->sp;
90*44c8bb91SVineet Gupta 		frame_info->regs.r31 = regs->blink;
91*44c8bb91SVineet Gupta 		frame_info->regs.r63 = regs->ret;
92*44c8bb91SVineet Gupta 		frame_info->call_frame = 0;
93*44c8bb91SVineet Gupta 	}
94*44c8bb91SVineet Gupta }
95*44c8bb91SVineet Gupta 
96*44c8bb91SVineet Gupta #endif
97*44c8bb91SVineet Gupta 
98*44c8bb91SVineet Gupta static noinline unsigned int
99*44c8bb91SVineet Gupta arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
100*44c8bb91SVineet Gupta 		int (*consumer_fn) (unsigned int, void *), void *arg)
101*44c8bb91SVineet Gupta {
102*44c8bb91SVineet Gupta #ifdef CONFIG_ARC_DW2_UNWIND
103*44c8bb91SVineet Gupta 	int ret = 0;
104*44c8bb91SVineet Gupta 	unsigned int address;
105*44c8bb91SVineet Gupta 	struct unwind_frame_info frame_info;
106*44c8bb91SVineet Gupta 
107*44c8bb91SVineet Gupta 	seed_unwind_frame_info(tsk, regs, &frame_info);
108*44c8bb91SVineet Gupta 
109*44c8bb91SVineet Gupta 	while (1) {
110*44c8bb91SVineet Gupta 		address = UNW_PC(&frame_info);
111*44c8bb91SVineet Gupta 
112*44c8bb91SVineet Gupta 		if (address && __kernel_text_address(address)) {
113*44c8bb91SVineet Gupta 			if (consumer_fn(address, arg) == -1)
114*44c8bb91SVineet Gupta 				break;
115*44c8bb91SVineet Gupta 		}
116*44c8bb91SVineet Gupta 
117*44c8bb91SVineet Gupta 		ret = arc_unwind(&frame_info);
118*44c8bb91SVineet Gupta 
119*44c8bb91SVineet Gupta 		if (ret == 0) {
120*44c8bb91SVineet Gupta 			frame_info.regs.r63 = frame_info.regs.r31;
121*44c8bb91SVineet Gupta 			continue;
122*44c8bb91SVineet Gupta 		} else {
123*44c8bb91SVineet Gupta 			break;
124*44c8bb91SVineet Gupta 		}
125*44c8bb91SVineet Gupta 	}
126*44c8bb91SVineet Gupta 
127*44c8bb91SVineet Gupta 	return address;		/* return the last address it saw */
128*44c8bb91SVineet Gupta #else
129*44c8bb91SVineet Gupta 	/* On ARC, only Dward based unwinder works. fp based backtracing is
130*44c8bb91SVineet Gupta 	 * not possible (-fno-omit-frame-pointer) because of the way function
131*44c8bb91SVineet Gupta 	 * prelogue is setup (callee regs saved and then fp set and not other
132*44c8bb91SVineet Gupta 	 * way around
133*44c8bb91SVineet Gupta 	 */
134*44c8bb91SVineet Gupta 	pr_warn("CONFIG_ARC_DW2_UNWIND needs to be enabled\n");
135*44c8bb91SVineet Gupta 	return 0;
136*44c8bb91SVineet Gupta 
137*44c8bb91SVineet Gupta #endif
138*44c8bb91SVineet Gupta }
139*44c8bb91SVineet Gupta 
140*44c8bb91SVineet Gupta /*-------------------------------------------------------------------------
141*44c8bb91SVineet Gupta  * callbacks called by unwinder iterator to implement kernel APIs
142*44c8bb91SVineet Gupta  *
143*44c8bb91SVineet Gupta  * The callback can return -1 to force the iterator to stop, which by default
144*44c8bb91SVineet Gupta  * keeps going till the bottom-most frame.
145*44c8bb91SVineet Gupta  *-------------------------------------------------------------------------
146*44c8bb91SVineet Gupta  */
147*44c8bb91SVineet Gupta 
148*44c8bb91SVineet Gupta /* Call-back which plugs into unwinding core to dump the stack in
149*44c8bb91SVineet Gupta  * case of panic/OOPs/BUG etc
150*44c8bb91SVineet Gupta  */
151*44c8bb91SVineet Gupta static int __print_sym(unsigned int address, void *unused)
152*44c8bb91SVineet Gupta {
153*44c8bb91SVineet Gupta 	__print_symbol("  %s\n", address);
154*44c8bb91SVineet Gupta 	return 0;
155*44c8bb91SVineet Gupta }
156*44c8bb91SVineet Gupta 
157*44c8bb91SVineet Gupta #ifdef CONFIG_STACKTRACE
158*44c8bb91SVineet Gupta 
159*44c8bb91SVineet Gupta /* Call-back which plugs into unwinding core to capture the
160*44c8bb91SVineet Gupta  * traces needed by kernel on /proc/<pid>/stack
161*44c8bb91SVineet Gupta  */
162*44c8bb91SVineet Gupta static int __collect_all(unsigned int address, void *arg)
163*44c8bb91SVineet Gupta {
164*44c8bb91SVineet Gupta 	struct stack_trace *trace = arg;
165*44c8bb91SVineet Gupta 
166*44c8bb91SVineet Gupta 	if (trace->skip > 0)
167*44c8bb91SVineet Gupta 		trace->skip--;
168*44c8bb91SVineet Gupta 	else
169*44c8bb91SVineet Gupta 		trace->entries[trace->nr_entries++] = address;
170*44c8bb91SVineet Gupta 
171*44c8bb91SVineet Gupta 	if (trace->nr_entries >= trace->max_entries)
172*44c8bb91SVineet Gupta 		return -1;
173*44c8bb91SVineet Gupta 
174*44c8bb91SVineet Gupta 	return 0;
175*44c8bb91SVineet Gupta }
176*44c8bb91SVineet Gupta 
177*44c8bb91SVineet Gupta static int __collect_all_but_sched(unsigned int address, void *arg)
178*44c8bb91SVineet Gupta {
179*44c8bb91SVineet Gupta 	struct stack_trace *trace = arg;
180*44c8bb91SVineet Gupta 
181*44c8bb91SVineet Gupta 	if (in_sched_functions(address))
182*44c8bb91SVineet Gupta 		return 0;
183*44c8bb91SVineet Gupta 
184*44c8bb91SVineet Gupta 	if (trace->skip > 0)
185*44c8bb91SVineet Gupta 		trace->skip--;
186*44c8bb91SVineet Gupta 	else
187*44c8bb91SVineet Gupta 		trace->entries[trace->nr_entries++] = address;
188*44c8bb91SVineet Gupta 
189*44c8bb91SVineet Gupta 	if (trace->nr_entries >= trace->max_entries)
190*44c8bb91SVineet Gupta 		return -1;
191*44c8bb91SVineet Gupta 
192*44c8bb91SVineet Gupta 	return 0;
193*44c8bb91SVineet Gupta }
194*44c8bb91SVineet Gupta 
195*44c8bb91SVineet Gupta #endif
196*44c8bb91SVineet Gupta 
197*44c8bb91SVineet Gupta static int __get_first_nonsched(unsigned int address, void *unused)
198*44c8bb91SVineet Gupta {
199*44c8bb91SVineet Gupta 	if (in_sched_functions(address))
200*44c8bb91SVineet Gupta 		return 0;
201*44c8bb91SVineet Gupta 
202*44c8bb91SVineet Gupta 	return -1;
203*44c8bb91SVineet Gupta }
204c08098f2SVineet Gupta 
205c08098f2SVineet Gupta /*-------------------------------------------------------------------------
206c08098f2SVineet Gupta  *              APIs expected by various kernel sub-systems
207c08098f2SVineet Gupta  *-------------------------------------------------------------------------
208c08098f2SVineet Gupta  */
209c08098f2SVineet Gupta 
210c08098f2SVineet Gupta noinline void show_stacktrace(struct task_struct *tsk, struct pt_regs *regs)
211c08098f2SVineet Gupta {
212*44c8bb91SVineet Gupta 	pr_info("\nStack Trace:\n");
213*44c8bb91SVineet Gupta 	arc_unwind_core(tsk, regs, __print_sym, NULL);
214c08098f2SVineet Gupta }
215c08098f2SVineet Gupta EXPORT_SYMBOL(show_stacktrace);
216c08098f2SVineet Gupta 
217c08098f2SVineet Gupta /* Expected by sched Code */
218c08098f2SVineet Gupta void show_stack(struct task_struct *tsk, unsigned long *sp)
219c08098f2SVineet Gupta {
220c08098f2SVineet Gupta 	show_stacktrace(tsk, NULL);
221c08098f2SVineet Gupta }
222c08098f2SVineet Gupta 
223c08098f2SVineet Gupta /* Expected by Rest of kernel code */
224c08098f2SVineet Gupta void dump_stack(void)
225c08098f2SVineet Gupta {
226c08098f2SVineet Gupta 	show_stacktrace(NULL, NULL);
227c08098f2SVineet Gupta }
228c08098f2SVineet Gupta EXPORT_SYMBOL(dump_stack);
229c08098f2SVineet Gupta 
230c08098f2SVineet Gupta /* Another API expected by schedular, shows up in "ps" as Wait Channel
231c08098f2SVineet Gupta  * Ofcourse just returning schedule( ) would be pointless so unwind until
232c08098f2SVineet Gupta  * the function is not in schedular code
233c08098f2SVineet Gupta  */
234c08098f2SVineet Gupta unsigned int get_wchan(struct task_struct *tsk)
235c08098f2SVineet Gupta {
236*44c8bb91SVineet Gupta 	return arc_unwind_core(tsk, NULL, __get_first_nonsched, NULL);
237c08098f2SVineet Gupta }
238*44c8bb91SVineet Gupta 
239*44c8bb91SVineet Gupta #ifdef CONFIG_STACKTRACE
240*44c8bb91SVineet Gupta 
241*44c8bb91SVineet Gupta /*
242*44c8bb91SVineet Gupta  * API required by CONFIG_STACKTRACE, CONFIG_LATENCYTOP.
243*44c8bb91SVineet Gupta  * A typical use is when /proc/<pid>/stack is queried by userland
244*44c8bb91SVineet Gupta  */
245*44c8bb91SVineet Gupta void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
246*44c8bb91SVineet Gupta {
247*44c8bb91SVineet Gupta 	arc_unwind_core(tsk, NULL, __collect_all_but_sched, trace);
248*44c8bb91SVineet Gupta }
249*44c8bb91SVineet Gupta 
250*44c8bb91SVineet Gupta void save_stack_trace(struct stack_trace *trace)
251*44c8bb91SVineet Gupta {
252*44c8bb91SVineet Gupta 	arc_unwind_core(current, NULL, __collect_all, trace);
253*44c8bb91SVineet Gupta }
254*44c8bb91SVineet Gupta #endif
255