xref: /linux-6.15/kernel/stacktrace.c (revision e9b98e16)
18637c099SIngo Molnar /*
28637c099SIngo Molnar  * kernel/stacktrace.c
38637c099SIngo Molnar  *
48637c099SIngo Molnar  * Stack trace management functions
58637c099SIngo Molnar  *
68637c099SIngo Molnar  *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <[email protected]>
78637c099SIngo Molnar  */
88637c099SIngo Molnar #include <linux/sched.h>
99212ddb5SIngo Molnar #include <linux/kernel.h>
109984de1aSPaul Gortmaker #include <linux/export.h>
118637c099SIngo Molnar #include <linux/kallsyms.h>
128637c099SIngo Molnar #include <linux/stacktrace.h>
138637c099SIngo Molnar 
14*e9b98e16SThomas Gleixner /**
15*e9b98e16SThomas Gleixner  * stack_trace_print - Print the entries in the stack trace
16*e9b98e16SThomas Gleixner  * @entries:	Pointer to storage array
17*e9b98e16SThomas Gleixner  * @nr_entries:	Number of entries in the storage array
18*e9b98e16SThomas Gleixner  * @spaces:	Number of leading spaces to print
19*e9b98e16SThomas Gleixner  */
20*e9b98e16SThomas Gleixner void stack_trace_print(unsigned long *entries, unsigned int nr_entries,
21*e9b98e16SThomas Gleixner 		       int spaces)
228637c099SIngo Molnar {
23*e9b98e16SThomas Gleixner 	unsigned int i;
248637c099SIngo Molnar 
25*e9b98e16SThomas Gleixner 	if (WARN_ON(!entries))
26bfeeeeb9SJohannes Berg 		return;
27bfeeeeb9SJohannes Berg 
28*e9b98e16SThomas Gleixner 	for (i = 0; i < nr_entries; i++)
29*e9b98e16SThomas Gleixner 		printk("%*c%pS\n", 1 + spaces, ' ', (void *)entries[i]);
30*e9b98e16SThomas Gleixner }
31*e9b98e16SThomas Gleixner EXPORT_SYMBOL_GPL(stack_trace_print);
32*e9b98e16SThomas Gleixner 
33*e9b98e16SThomas Gleixner void print_stack_trace(struct stack_trace *trace, int spaces)
34*e9b98e16SThomas Gleixner {
35*e9b98e16SThomas Gleixner 	stack_trace_print(trace->entries, trace->nr_entries, spaces);
368637c099SIngo Molnar }
378594698eSIngo Molnar EXPORT_SYMBOL_GPL(print_stack_trace);
388637c099SIngo Molnar 
39*e9b98e16SThomas Gleixner /**
40*e9b98e16SThomas Gleixner  * stack_trace_snprint - Print the entries in the stack trace into a buffer
41*e9b98e16SThomas Gleixner  * @buf:	Pointer to the print buffer
42*e9b98e16SThomas Gleixner  * @size:	Size of the print buffer
43*e9b98e16SThomas Gleixner  * @entries:	Pointer to storage array
44*e9b98e16SThomas Gleixner  * @nr_entries:	Number of entries in the storage array
45*e9b98e16SThomas Gleixner  * @spaces:	Number of leading spaces to print
46*e9b98e16SThomas Gleixner  *
47*e9b98e16SThomas Gleixner  * Return: Number of bytes printed.
48*e9b98e16SThomas Gleixner  */
49*e9b98e16SThomas Gleixner int stack_trace_snprint(char *buf, size_t size, unsigned long *entries,
50*e9b98e16SThomas Gleixner 			unsigned int nr_entries, int spaces)
519a92a6ceSJoonsoo Kim {
52*e9b98e16SThomas Gleixner 	unsigned int generated, i, total = 0;
539a92a6ceSJoonsoo Kim 
54*e9b98e16SThomas Gleixner 	if (WARN_ON(!entries))
559a92a6ceSJoonsoo Kim 		return 0;
569a92a6ceSJoonsoo Kim 
57*e9b98e16SThomas Gleixner 	for (i = 0; i < nr_entries && size; i++) {
58bfeda41dSOmar Sandoval 		generated = snprintf(buf, size, "%*c%pS\n", 1 + spaces, ' ',
59*e9b98e16SThomas Gleixner 				     (void *)entries[i]);
609a92a6ceSJoonsoo Kim 
619a92a6ceSJoonsoo Kim 		total += generated;
629a92a6ceSJoonsoo Kim 		if (generated >= size) {
639a92a6ceSJoonsoo Kim 			buf += size;
649a92a6ceSJoonsoo Kim 			size = 0;
659a92a6ceSJoonsoo Kim 		} else {
669a92a6ceSJoonsoo Kim 			buf += generated;
679a92a6ceSJoonsoo Kim 			size -= generated;
689a92a6ceSJoonsoo Kim 		}
699a92a6ceSJoonsoo Kim 	}
709a92a6ceSJoonsoo Kim 
719a92a6ceSJoonsoo Kim 	return total;
729a92a6ceSJoonsoo Kim }
73*e9b98e16SThomas Gleixner EXPORT_SYMBOL_GPL(stack_trace_snprint);
74*e9b98e16SThomas Gleixner 
75*e9b98e16SThomas Gleixner int snprint_stack_trace(char *buf, size_t size,
76*e9b98e16SThomas Gleixner 			struct stack_trace *trace, int spaces)
77*e9b98e16SThomas Gleixner {
78*e9b98e16SThomas Gleixner 	return stack_trace_snprint(buf, size, trace->entries,
79*e9b98e16SThomas Gleixner 				   trace->nr_entries, spaces);
80*e9b98e16SThomas Gleixner }
819a92a6ceSJoonsoo Kim EXPORT_SYMBOL_GPL(snprint_stack_trace);
829a92a6ceSJoonsoo Kim 
839212ddb5SIngo Molnar /*
84af085d90SJosh Poimboeuf  * Architectures that do not implement save_stack_trace_*()
85af085d90SJosh Poimboeuf  * get these weak aliases and once-per-bootup warnings
86c624d33fSMasami Hiramatsu  * (whenever this facility is utilized - for example by procfs):
879212ddb5SIngo Molnar  */
889212ddb5SIngo Molnar __weak void
899212ddb5SIngo Molnar save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
909212ddb5SIngo Molnar {
919212ddb5SIngo Molnar 	WARN_ONCE(1, KERN_INFO "save_stack_trace_tsk() not implemented yet.\n");
929212ddb5SIngo Molnar }
93c624d33fSMasami Hiramatsu 
94c624d33fSMasami Hiramatsu __weak void
95c624d33fSMasami Hiramatsu save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
96c624d33fSMasami Hiramatsu {
97c624d33fSMasami Hiramatsu 	WARN_ONCE(1, KERN_INFO "save_stack_trace_regs() not implemented yet.\n");
98c624d33fSMasami Hiramatsu }
99af085d90SJosh Poimboeuf 
100af085d90SJosh Poimboeuf __weak int
101af085d90SJosh Poimboeuf save_stack_trace_tsk_reliable(struct task_struct *tsk,
102af085d90SJosh Poimboeuf 			      struct stack_trace *trace)
103af085d90SJosh Poimboeuf {
104af085d90SJosh Poimboeuf 	WARN_ONCE(1, KERN_INFO "save_stack_tsk_reliable() not implemented yet.\n");
105af085d90SJosh Poimboeuf 	return -ENOSYS;
106af085d90SJosh Poimboeuf }
107*e9b98e16SThomas Gleixner 
108*e9b98e16SThomas Gleixner /**
109*e9b98e16SThomas Gleixner  * stack_trace_save - Save a stack trace into a storage array
110*e9b98e16SThomas Gleixner  * @store:	Pointer to storage array
111*e9b98e16SThomas Gleixner  * @size:	Size of the storage array
112*e9b98e16SThomas Gleixner  * @skipnr:	Number of entries to skip at the start of the stack trace
113*e9b98e16SThomas Gleixner  *
114*e9b98e16SThomas Gleixner  * Return: Number of trace entries stored
115*e9b98e16SThomas Gleixner  */
116*e9b98e16SThomas Gleixner unsigned int stack_trace_save(unsigned long *store, unsigned int size,
117*e9b98e16SThomas Gleixner 			      unsigned int skipnr)
118*e9b98e16SThomas Gleixner {
119*e9b98e16SThomas Gleixner 	struct stack_trace trace = {
120*e9b98e16SThomas Gleixner 		.entries	= store,
121*e9b98e16SThomas Gleixner 		.max_entries	= size,
122*e9b98e16SThomas Gleixner 		.skip		= skipnr + 1,
123*e9b98e16SThomas Gleixner 	};
124*e9b98e16SThomas Gleixner 
125*e9b98e16SThomas Gleixner 	save_stack_trace(&trace);
126*e9b98e16SThomas Gleixner 	return trace.nr_entries;
127*e9b98e16SThomas Gleixner }
128*e9b98e16SThomas Gleixner EXPORT_SYMBOL_GPL(stack_trace_save);
129*e9b98e16SThomas Gleixner 
130*e9b98e16SThomas Gleixner /**
131*e9b98e16SThomas Gleixner  * stack_trace_save_tsk - Save a task stack trace into a storage array
132*e9b98e16SThomas Gleixner  * @task:	The task to examine
133*e9b98e16SThomas Gleixner  * @store:	Pointer to storage array
134*e9b98e16SThomas Gleixner  * @size:	Size of the storage array
135*e9b98e16SThomas Gleixner  * @skipnr:	Number of entries to skip at the start of the stack trace
136*e9b98e16SThomas Gleixner  *
137*e9b98e16SThomas Gleixner  * Return: Number of trace entries stored
138*e9b98e16SThomas Gleixner  */
139*e9b98e16SThomas Gleixner unsigned int stack_trace_save_tsk(struct task_struct *task,
140*e9b98e16SThomas Gleixner 				  unsigned long *store, unsigned int size,
141*e9b98e16SThomas Gleixner 				  unsigned int skipnr)
142*e9b98e16SThomas Gleixner {
143*e9b98e16SThomas Gleixner 	struct stack_trace trace = {
144*e9b98e16SThomas Gleixner 		.entries	= store,
145*e9b98e16SThomas Gleixner 		.max_entries	= size,
146*e9b98e16SThomas Gleixner 		.skip		= skipnr + 1,
147*e9b98e16SThomas Gleixner 	};
148*e9b98e16SThomas Gleixner 
149*e9b98e16SThomas Gleixner 	save_stack_trace_tsk(task, &trace);
150*e9b98e16SThomas Gleixner 	return trace.nr_entries;
151*e9b98e16SThomas Gleixner }
152*e9b98e16SThomas Gleixner 
153*e9b98e16SThomas Gleixner /**
154*e9b98e16SThomas Gleixner  * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array
155*e9b98e16SThomas Gleixner  * @regs:	Pointer to pt_regs to examine
156*e9b98e16SThomas Gleixner  * @store:	Pointer to storage array
157*e9b98e16SThomas Gleixner  * @size:	Size of the storage array
158*e9b98e16SThomas Gleixner  * @skipnr:	Number of entries to skip at the start of the stack trace
159*e9b98e16SThomas Gleixner  *
160*e9b98e16SThomas Gleixner  * Return: Number of trace entries stored
161*e9b98e16SThomas Gleixner  */
162*e9b98e16SThomas Gleixner unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store,
163*e9b98e16SThomas Gleixner 				   unsigned int size, unsigned int skipnr)
164*e9b98e16SThomas Gleixner {
165*e9b98e16SThomas Gleixner 	struct stack_trace trace = {
166*e9b98e16SThomas Gleixner 		.entries	= store,
167*e9b98e16SThomas Gleixner 		.max_entries	= size,
168*e9b98e16SThomas Gleixner 		.skip		= skipnr,
169*e9b98e16SThomas Gleixner 	};
170*e9b98e16SThomas Gleixner 
171*e9b98e16SThomas Gleixner 	save_stack_trace_regs(regs, &trace);
172*e9b98e16SThomas Gleixner 	return trace.nr_entries;
173*e9b98e16SThomas Gleixner }
174*e9b98e16SThomas Gleixner 
175*e9b98e16SThomas Gleixner #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE
176*e9b98e16SThomas Gleixner /**
177*e9b98e16SThomas Gleixner  * stack_trace_save_tsk_reliable - Save task stack with verification
178*e9b98e16SThomas Gleixner  * @tsk:	Pointer to the task to examine
179*e9b98e16SThomas Gleixner  * @store:	Pointer to storage array
180*e9b98e16SThomas Gleixner  * @size:	Size of the storage array
181*e9b98e16SThomas Gleixner  *
182*e9b98e16SThomas Gleixner  * Return:	An error if it detects any unreliable features of the
183*e9b98e16SThomas Gleixner  *		stack. Otherwise it guarantees that the stack trace is
184*e9b98e16SThomas Gleixner  *		reliable and returns the number of entries stored.
185*e9b98e16SThomas Gleixner  *
186*e9b98e16SThomas Gleixner  * If the task is not 'current', the caller *must* ensure the task is inactive.
187*e9b98e16SThomas Gleixner  */
188*e9b98e16SThomas Gleixner int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store,
189*e9b98e16SThomas Gleixner 				  unsigned int size)
190*e9b98e16SThomas Gleixner {
191*e9b98e16SThomas Gleixner 	struct stack_trace trace = {
192*e9b98e16SThomas Gleixner 		.entries	= store,
193*e9b98e16SThomas Gleixner 		.max_entries	= size,
194*e9b98e16SThomas Gleixner 	};
195*e9b98e16SThomas Gleixner 	int ret = save_stack_trace_tsk_reliable(tsk, &trace);
196*e9b98e16SThomas Gleixner 
197*e9b98e16SThomas Gleixner 	return ret ? ret : trace.nr_entries;
198*e9b98e16SThomas Gleixner }
199*e9b98e16SThomas Gleixner #endif
200*e9b98e16SThomas Gleixner 
201*e9b98e16SThomas Gleixner #ifdef CONFIG_USER_STACKTRACE_SUPPORT
202*e9b98e16SThomas Gleixner /**
203*e9b98e16SThomas Gleixner  * stack_trace_save_user - Save a user space stack trace into a storage array
204*e9b98e16SThomas Gleixner  * @store:	Pointer to storage array
205*e9b98e16SThomas Gleixner  * @size:	Size of the storage array
206*e9b98e16SThomas Gleixner  *
207*e9b98e16SThomas Gleixner  * Return: Number of trace entries stored
208*e9b98e16SThomas Gleixner  */
209*e9b98e16SThomas Gleixner unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
210*e9b98e16SThomas Gleixner {
211*e9b98e16SThomas Gleixner 	struct stack_trace trace = {
212*e9b98e16SThomas Gleixner 		.entries	= store,
213*e9b98e16SThomas Gleixner 		.max_entries	= size,
214*e9b98e16SThomas Gleixner 	};
215*e9b98e16SThomas Gleixner 
216*e9b98e16SThomas Gleixner 	save_stack_trace_user(&trace);
217*e9b98e16SThomas Gleixner 	return trace.nr_entries;
218*e9b98e16SThomas Gleixner }
219*e9b98e16SThomas Gleixner #endif /* CONFIG_USER_STACKTRACE_SUPPORT */
220