xref: /linux-6.15/arch/arc/kernel/stacktrace.c (revision 4d369680)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c08098f2SVineet Gupta /*
344c8bb91SVineet Gupta  *	stacktrace.c : stacktracing APIs needed by rest of kernel
444c8bb91SVineet Gupta  *			(wrappers over ARC dwarf based unwinder)
544c8bb91SVineet Gupta  *
6c08098f2SVineet Gupta  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
7c08098f2SVineet Gupta  *
844c8bb91SVineet Gupta  *  vineetg: aug 2009
944c8bb91SVineet Gupta  *  -Implemented CONFIG_STACKTRACE APIs, primarily save_stack_trace_tsk( )
1044c8bb91SVineet Gupta  *   for displaying task's kernel mode call stack in /proc/<pid>/stack
1144c8bb91SVineet Gupta  *  -Iterator based approach to have single copy of unwinding core and APIs
1244c8bb91SVineet Gupta  *   needing unwinding, implement the logic in iterator regarding:
1344c8bb91SVineet Gupta  *      = which frame onwards to start capture
1444c8bb91SVineet Gupta  *      = which frame to stop capturing (wchan)
1544c8bb91SVineet Gupta  *      = specifics of data structs where trace is saved(CONFIG_STACKTRACE etc)
1644c8bb91SVineet Gupta  *
1744c8bb91SVineet Gupta  *  vineetg: March 2009
1842a20f86SKees Cook  *  -Implemented correct versions of thread_saved_pc() and __get_wchan()
1944c8bb91SVineet Gupta  *
2044c8bb91SVineet Gupta  *  rajeshwarr: 2008
2144c8bb91SVineet Gupta  *  -Initial implementation
22c08098f2SVineet Gupta  */
23c08098f2SVineet Gupta 
24c08098f2SVineet Gupta #include <linux/ptrace.h>
25c08098f2SVineet Gupta #include <linux/export.h>
2644c8bb91SVineet Gupta #include <linux/stacktrace.h>
2744c8bb91SVineet Gupta #include <linux/kallsyms.h>
28b17b0153SIngo Molnar #include <linux/sched/debug.h>
29b17b0153SIngo Molnar 
3044c8bb91SVineet Gupta #include <asm/arcregs.h>
3144c8bb91SVineet Gupta #include <asm/unwind.h>
32*4d369680SVineet Gupta #include <asm/stacktrace.h>
3344c8bb91SVineet Gupta #include <asm/switch_to.h>
3444c8bb91SVineet Gupta 
3544c8bb91SVineet Gupta /*-------------------------------------------------------------------------
3644c8bb91SVineet Gupta  *              Unwinder Iterator
3744c8bb91SVineet Gupta  *-------------------------------------------------------------------------
3844c8bb91SVineet Gupta  */
3944c8bb91SVineet Gupta 
4044c8bb91SVineet Gupta #ifdef CONFIG_ARC_DW2_UNWIND
4144c8bb91SVineet Gupta 
42e42404faSVineet Gupta static int
seed_unwind_frame_info(struct task_struct * tsk,struct pt_regs * regs,struct unwind_frame_info * frame_info)43e42404faSVineet Gupta seed_unwind_frame_info(struct task_struct *tsk, struct pt_regs *regs,
4444c8bb91SVineet Gupta 		       struct unwind_frame_info *frame_info)
4544c8bb91SVineet Gupta {
46f737561cSVineet Gupta 	if (regs) {
47f737561cSVineet Gupta 		/*
48f737561cSVineet Gupta 		 * Asynchronous unwinding of intr/exception
49f737561cSVineet Gupta 		 *  - Just uses the pt_regs passed
50f737561cSVineet Gupta 		 */
51f737561cSVineet Gupta 		frame_info->task = tsk;
52f737561cSVineet Gupta 
53f737561cSVineet Gupta 		frame_info->regs.r27 = regs->fp;
54f737561cSVineet Gupta 		frame_info->regs.r28 = regs->sp;
55f737561cSVineet Gupta 		frame_info->regs.r31 = regs->blink;
56f737561cSVineet Gupta 		frame_info->regs.r63 = regs->ret;
57f737561cSVineet Gupta 		frame_info->call_frame = 0;
58f737561cSVineet Gupta 	} else if (tsk == NULL || tsk == current) {
593a51d50fSVineet Gupta 		/*
603a51d50fSVineet Gupta 		 * synchronous unwinding (e.g. dump_stack)
613a51d50fSVineet Gupta 		 *  - uses current values of SP and friends
623a51d50fSVineet Gupta 		 */
6344c8bb91SVineet Gupta 		unsigned long fp, sp, blink, ret;
6444c8bb91SVineet Gupta 		frame_info->task = current;
6544c8bb91SVineet Gupta 
6644c8bb91SVineet Gupta 		__asm__ __volatile__(
6744c8bb91SVineet Gupta 			"mov %0,r27\n\t"
6844c8bb91SVineet Gupta 			"mov %1,r28\n\t"
6944c8bb91SVineet Gupta 			"mov %2,r31\n\t"
7044c8bb91SVineet Gupta 			"mov %3,r63\n\t"
7144c8bb91SVineet Gupta 			: "=r"(fp), "=r"(sp), "=r"(blink), "=r"(ret)
7244c8bb91SVineet Gupta 		);
7344c8bb91SVineet Gupta 
7444c8bb91SVineet Gupta 		frame_info->regs.r27 = fp;
7544c8bb91SVineet Gupta 		frame_info->regs.r28 = sp;
7644c8bb91SVineet Gupta 		frame_info->regs.r31 = blink;
7744c8bb91SVineet Gupta 		frame_info->regs.r63 = ret;
7844c8bb91SVineet Gupta 		frame_info->call_frame = 0;
79f737561cSVineet Gupta 	} else {
803a51d50fSVineet Gupta 		/*
81e42404faSVineet Gupta 		 * Asynchronous unwinding of a likely sleeping task
82e42404faSVineet Gupta 		 *  - first ensure it is actually sleeping
83e42404faSVineet Gupta 		 *  - if so, it will be in __switch_to, kernel mode SP of task
84e42404faSVineet Gupta 		 *    is safe-kept and BLINK at a well known location in there
853a51d50fSVineet Gupta 		 */
8644c8bb91SVineet Gupta 
87b03fbd4fSPeter Zijlstra 		if (task_is_running(tsk))
88e42404faSVineet Gupta 			return -1;
89e42404faSVineet Gupta 
9044c8bb91SVineet Gupta 		frame_info->task = tsk;
9144c8bb91SVineet Gupta 
9213648b01SVineet Gupta 		frame_info->regs.r27 = TSK_K_FP(tsk);
9313648b01SVineet Gupta 		frame_info->regs.r28 = TSK_K_ESP(tsk);
9413648b01SVineet Gupta 		frame_info->regs.r31 = TSK_K_BLINK(tsk);
9544c8bb91SVineet Gupta 		frame_info->regs.r63 = (unsigned int)__switch_to;
9644c8bb91SVineet Gupta 
9744c8bb91SVineet Gupta 		/* In the prologue of __switch_to, first FP is saved on stack
9844c8bb91SVineet Gupta 		 * and then SP is copied to FP. Dwarf assumes cfa as FP based
9944c8bb91SVineet Gupta 		 * but we didn't save FP. The value retrieved above is FP's
10044c8bb91SVineet Gupta 		 * state in previous frame.
10144c8bb91SVineet Gupta 		 * As a work around for this, we unwind from __switch_to start
10244c8bb91SVineet Gupta 		 * and adjust SP accordingly. The other limitation is that
10344c8bb91SVineet Gupta 		 * __switch_to macro is dwarf rules are not generated for inline
10444c8bb91SVineet Gupta 		 * assembly code
10544c8bb91SVineet Gupta 		 */
10644c8bb91SVineet Gupta 		frame_info->regs.r27 = 0;
10716f9afe6SVineet Gupta 		frame_info->regs.r28 += 60;
10844c8bb91SVineet Gupta 		frame_info->call_frame = 0;
10944c8bb91SVineet Gupta 
11044c8bb91SVineet Gupta 	}
111e42404faSVineet Gupta 	return 0;
11244c8bb91SVineet Gupta }
11344c8bb91SVineet Gupta 
11444c8bb91SVineet Gupta #endif
11544c8bb91SVineet Gupta 
1163a51d50fSVineet Gupta notrace noinline unsigned int
arc_unwind_core(struct task_struct * tsk,struct pt_regs * regs,int (* consumer_fn)(unsigned int,void *),void * arg)11744c8bb91SVineet Gupta arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
11844c8bb91SVineet Gupta 		int (*consumer_fn) (unsigned int, void *), void *arg)
11944c8bb91SVineet Gupta {
12044c8bb91SVineet Gupta #ifdef CONFIG_ARC_DW2_UNWIND
121328d2168SVineet Gupta 	int ret = 0, cnt = 0;
12244c8bb91SVineet Gupta 	unsigned int address;
12344c8bb91SVineet Gupta 	struct unwind_frame_info frame_info;
12444c8bb91SVineet Gupta 
125e42404faSVineet Gupta 	if (seed_unwind_frame_info(tsk, regs, &frame_info))
126e42404faSVineet Gupta 		return 0;
12744c8bb91SVineet Gupta 
12844c8bb91SVineet Gupta 	while (1) {
12944c8bb91SVineet Gupta 		address = UNW_PC(&frame_info);
13044c8bb91SVineet Gupta 
131def32fadSVineet Gupta 		if (!address || !__kernel_text_address(address))
132def32fadSVineet Gupta 			break;
133def32fadSVineet Gupta 
13444c8bb91SVineet Gupta 		if (consumer_fn(address, arg) == -1)
13544c8bb91SVineet Gupta 			break;
13644c8bb91SVineet Gupta 
13744c8bb91SVineet Gupta 		ret = arc_unwind(&frame_info);
138def32fadSVineet Gupta 		if (ret)
13944c8bb91SVineet Gupta 			break;
140def32fadSVineet Gupta 
141def32fadSVineet Gupta 		frame_info.regs.r63 = frame_info.regs.r31;
142328d2168SVineet Gupta 
143328d2168SVineet Gupta 		if (cnt++ > 128) {
144328d2168SVineet Gupta 			printk("unwinder looping too long, aborting !\n");
145328d2168SVineet Gupta 			return 0;
146328d2168SVineet Gupta 		}
14744c8bb91SVineet Gupta 	}
14844c8bb91SVineet Gupta 
14944c8bb91SVineet Gupta 	return address;		/* return the last address it saw */
15044c8bb91SVineet Gupta #else
15144c8bb91SVineet Gupta 	/* On ARC, only Dward based unwinder works. fp based backtracing is
15244c8bb91SVineet Gupta 	 * not possible (-fno-omit-frame-pointer) because of the way function
15382a42305SChangcheng Deng 	 * prologue is setup (callee regs saved and then fp set and not other
15444c8bb91SVineet Gupta 	 * way around
15544c8bb91SVineet Gupta 	 */
1569bd54517SAlexey Brodkin 	pr_warn_once("CONFIG_ARC_DW2_UNWIND needs to be enabled\n");
15744c8bb91SVineet Gupta 	return 0;
15844c8bb91SVineet Gupta 
15944c8bb91SVineet Gupta #endif
16044c8bb91SVineet Gupta }
16144c8bb91SVineet Gupta 
16244c8bb91SVineet Gupta /*-------------------------------------------------------------------------
16344c8bb91SVineet Gupta  * callbacks called by unwinder iterator to implement kernel APIs
16444c8bb91SVineet Gupta  *
16544c8bb91SVineet Gupta  * The callback can return -1 to force the iterator to stop, which by default
16644c8bb91SVineet Gupta  * keeps going till the bottom-most frame.
16744c8bb91SVineet Gupta  *-------------------------------------------------------------------------
16844c8bb91SVineet Gupta  */
16944c8bb91SVineet Gupta 
17044c8bb91SVineet Gupta /* Call-back which plugs into unwinding core to dump the stack in
17144c8bb91SVineet Gupta  * case of panic/OOPs/BUG etc
17244c8bb91SVineet Gupta  */
__print_sym(unsigned int address,void * arg)1738ca4d199SDmitry Safonov static int __print_sym(unsigned int address, void *arg)
17444c8bb91SVineet Gupta {
1758ca4d199SDmitry Safonov 	const char *loglvl = arg;
1768ca4d199SDmitry Safonov 
1778ca4d199SDmitry Safonov 	printk("%s  %pS\n", loglvl, (void *)address);
17844c8bb91SVineet Gupta 	return 0;
17944c8bb91SVineet Gupta }
18044c8bb91SVineet Gupta 
18144c8bb91SVineet Gupta #ifdef CONFIG_STACKTRACE
18244c8bb91SVineet Gupta 
18344c8bb91SVineet Gupta /* Call-back which plugs into unwinding core to capture the
18444c8bb91SVineet Gupta  * traces needed by kernel on /proc/<pid>/stack
18544c8bb91SVineet Gupta  */
__collect_all(unsigned int address,void * arg)18644c8bb91SVineet Gupta static int __collect_all(unsigned int address, void *arg)
18744c8bb91SVineet Gupta {
18844c8bb91SVineet Gupta 	struct stack_trace *trace = arg;
18944c8bb91SVineet Gupta 
19044c8bb91SVineet Gupta 	if (trace->skip > 0)
19144c8bb91SVineet Gupta 		trace->skip--;
19244c8bb91SVineet Gupta 	else
19344c8bb91SVineet Gupta 		trace->entries[trace->nr_entries++] = address;
19444c8bb91SVineet Gupta 
19544c8bb91SVineet Gupta 	if (trace->nr_entries >= trace->max_entries)
19644c8bb91SVineet Gupta 		return -1;
19744c8bb91SVineet Gupta 
19844c8bb91SVineet Gupta 	return 0;
19944c8bb91SVineet Gupta }
20044c8bb91SVineet Gupta 
__collect_all_but_sched(unsigned int address,void * arg)20144c8bb91SVineet Gupta static int __collect_all_but_sched(unsigned int address, void *arg)
20244c8bb91SVineet Gupta {
20344c8bb91SVineet Gupta 	struct stack_trace *trace = arg;
20444c8bb91SVineet Gupta 
20544c8bb91SVineet Gupta 	if (in_sched_functions(address))
20644c8bb91SVineet Gupta 		return 0;
20744c8bb91SVineet Gupta 
20844c8bb91SVineet Gupta 	if (trace->skip > 0)
20944c8bb91SVineet Gupta 		trace->skip--;
21044c8bb91SVineet Gupta 	else
21144c8bb91SVineet Gupta 		trace->entries[trace->nr_entries++] = address;
21244c8bb91SVineet Gupta 
21344c8bb91SVineet Gupta 	if (trace->nr_entries >= trace->max_entries)
21444c8bb91SVineet Gupta 		return -1;
21544c8bb91SVineet Gupta 
21644c8bb91SVineet Gupta 	return 0;
21744c8bb91SVineet Gupta }
21844c8bb91SVineet Gupta 
21944c8bb91SVineet Gupta #endif
22044c8bb91SVineet Gupta 
__get_first_nonsched(unsigned int address,void * unused)22144c8bb91SVineet Gupta static int __get_first_nonsched(unsigned int address, void *unused)
22244c8bb91SVineet Gupta {
22344c8bb91SVineet Gupta 	if (in_sched_functions(address))
22444c8bb91SVineet Gupta 		return 0;
22544c8bb91SVineet Gupta 
22644c8bb91SVineet Gupta 	return -1;
22744c8bb91SVineet Gupta }
228c08098f2SVineet Gupta 
229c08098f2SVineet Gupta /*-------------------------------------------------------------------------
230c08098f2SVineet Gupta  *              APIs expected by various kernel sub-systems
231c08098f2SVineet Gupta  *-------------------------------------------------------------------------
232c08098f2SVineet Gupta  */
233c08098f2SVineet Gupta 
show_stacktrace(struct task_struct * tsk,struct pt_regs * regs,const char * loglvl)2348ca4d199SDmitry Safonov noinline void show_stacktrace(struct task_struct *tsk, struct pt_regs *regs,
2358ca4d199SDmitry Safonov 			      const char *loglvl)
236c08098f2SVineet Gupta {
2378ca4d199SDmitry Safonov 	printk("%s\nStack Trace:\n", loglvl);
2388ca4d199SDmitry Safonov 	arc_unwind_core(tsk, regs, __print_sym, (void *)loglvl);
239c08098f2SVineet Gupta }
240c08098f2SVineet Gupta EXPORT_SYMBOL(show_stacktrace);
241c08098f2SVineet Gupta 
242c08098f2SVineet Gupta /* Expected by sched Code */
show_stack(struct task_struct * tsk,unsigned long * sp,const char * loglvl)2439cb8f069SDmitry Safonov void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
2448ca4d199SDmitry Safonov {
2458ca4d199SDmitry Safonov 	show_stacktrace(tsk, NULL, loglvl);
2468ca4d199SDmitry Safonov }
2478ca4d199SDmitry Safonov 
248c08098f2SVineet Gupta /* Another API expected by schedular, shows up in "ps" as Wait Channel
249c08098f2SVineet Gupta  * Of course just returning schedule( ) would be pointless so unwind until
250c08098f2SVineet Gupta  * the function is not in schedular code
251c08098f2SVineet Gupta  */
__get_wchan(struct task_struct * tsk)25242a20f86SKees Cook unsigned int __get_wchan(struct task_struct *tsk)
253c08098f2SVineet Gupta {
25444c8bb91SVineet Gupta 	return arc_unwind_core(tsk, NULL, __get_first_nonsched, NULL);
255c08098f2SVineet Gupta }
25644c8bb91SVineet Gupta 
25744c8bb91SVineet Gupta #ifdef CONFIG_STACKTRACE
25844c8bb91SVineet Gupta 
25944c8bb91SVineet Gupta /*
26044c8bb91SVineet Gupta  * API required by CONFIG_STACKTRACE, CONFIG_LATENCYTOP.
26144c8bb91SVineet Gupta  * A typical use is when /proc/<pid>/stack is queried by userland
26244c8bb91SVineet Gupta  */
save_stack_trace_tsk(struct task_struct * tsk,struct stack_trace * trace)26344c8bb91SVineet Gupta void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
26444c8bb91SVineet Gupta {
2650dafafc3SVineet Gupta 	/* Assumes @tsk is sleeping so unwinds from __switch_to */
26644c8bb91SVineet Gupta 	arc_unwind_core(tsk, NULL, __collect_all_but_sched, trace);
26744c8bb91SVineet Gupta }
26844c8bb91SVineet Gupta 
save_stack_trace(struct stack_trace * trace)26944c8bb91SVineet Gupta void save_stack_trace(struct stack_trace *trace)
27044c8bb91SVineet Gupta {
2710dafafc3SVineet Gupta 	/* Pass NULL for task so it unwinds the current call frame */
2720dafafc3SVineet Gupta 	arc_unwind_core(NULL, NULL, __collect_all, trace);
27344c8bb91SVineet Gupta }
2748f146d02SChen Gang EXPORT_SYMBOL_GPL(save_stack_trace);
27544c8bb91SVineet Gupta #endif
276