Blame view

kernel/stacktrace.c 9.67 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
8637c0990   Ingo Molnar   [PATCH] lockdep: ...
2
3
4
5
6
7
8
  /*
   * kernel/stacktrace.c
   *
   * Stack trace management functions
   *
   *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
   */
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
9
10
  #include <linux/sched/task_stack.h>
  #include <linux/sched/debug.h>
8637c0990   Ingo Molnar   [PATCH] lockdep: ...
11
  #include <linux/sched.h>
9212ddb5e   Ingo Molnar   stacktrace: provi...
12
  #include <linux/kernel.h>
9984de1a5   Paul Gortmaker   kernel: Map most ...
13
  #include <linux/export.h>
8637c0990   Ingo Molnar   [PATCH] lockdep: ...
14
15
  #include <linux/kallsyms.h>
  #include <linux/stacktrace.h>
e9b98e162   Thomas Gleixner   stacktrace: Provi...
16
17
18
19
20
21
  /**
   * stack_trace_print - Print the entries in the stack trace
   * @entries:	Pointer to storage array
   * @nr_entries:	Number of entries in the storage array
   * @spaces:	Number of leading spaces to print
   */
a29704216   Bart Van Assche   stacktrace: Const...
22
  void stack_trace_print(const unsigned long *entries, unsigned int nr_entries,
e9b98e162   Thomas Gleixner   stacktrace: Provi...
23
  		       int spaces)
8637c0990   Ingo Molnar   [PATCH] lockdep: ...
24
  {
e9b98e162   Thomas Gleixner   stacktrace: Provi...
25
  	unsigned int i;
8637c0990   Ingo Molnar   [PATCH] lockdep: ...
26

e9b98e162   Thomas Gleixner   stacktrace: Provi...
27
  	if (WARN_ON(!entries))
bfeeeeb99   Johannes Berg   stacktrace: don't...
28
  		return;
e9b98e162   Thomas Gleixner   stacktrace: Provi...
29
30
31
32
33
  	for (i = 0; i < nr_entries; i++)
  		printk("%*c%pS
  ", 1 + spaces, ' ', (void *)entries[i]);
  }
  EXPORT_SYMBOL_GPL(stack_trace_print);
e9b98e162   Thomas Gleixner   stacktrace: Provi...
34
35
36
37
38
39
40
41
42
43
  /**
   * stack_trace_snprint - Print the entries in the stack trace into a buffer
   * @buf:	Pointer to the print buffer
   * @size:	Size of the print buffer
   * @entries:	Pointer to storage array
   * @nr_entries:	Number of entries in the storage array
   * @spaces:	Number of leading spaces to print
   *
   * Return: Number of bytes printed.
   */
a29704216   Bart Van Assche   stacktrace: Const...
44
  int stack_trace_snprint(char *buf, size_t size, const unsigned long *entries,
e9b98e162   Thomas Gleixner   stacktrace: Provi...
45
  			unsigned int nr_entries, int spaces)
9a92a6ce6   Joonsoo Kim   stacktrace: intro...
46
  {
e9b98e162   Thomas Gleixner   stacktrace: Provi...
47
  	unsigned int generated, i, total = 0;
9a92a6ce6   Joonsoo Kim   stacktrace: intro...
48

e9b98e162   Thomas Gleixner   stacktrace: Provi...
49
  	if (WARN_ON(!entries))
9a92a6ce6   Joonsoo Kim   stacktrace: intro...
50
  		return 0;
e9b98e162   Thomas Gleixner   stacktrace: Provi...
51
  	for (i = 0; i < nr_entries && size; i++) {
bfeda41d0   Omar Sandoval   stacktrace, lockd...
52
53
  		generated = snprintf(buf, size, "%*c%pS
  ", 1 + spaces, ' ',
e9b98e162   Thomas Gleixner   stacktrace: Provi...
54
  				     (void *)entries[i]);
9a92a6ce6   Joonsoo Kim   stacktrace: intro...
55
56
  
  		total += generated;
9a92a6ce6   Joonsoo Kim   stacktrace: intro...
57
58
59
60
61
62
63
64
65
66
67
  		if (generated >= size) {
  			buf += size;
  			size = 0;
  		} else {
  			buf += generated;
  			size -= generated;
  		}
  	}
  
  	return total;
  }
e9b98e162   Thomas Gleixner   stacktrace: Provi...
68
  EXPORT_SYMBOL_GPL(stack_trace_snprint);
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  #ifdef CONFIG_ARCH_STACKWALK
  
  struct stacktrace_cookie {
  	unsigned long	*store;
  	unsigned int	size;
  	unsigned int	skip;
  	unsigned int	len;
  };
  
  static bool stack_trace_consume_entry(void *cookie, unsigned long addr,
  				      bool reliable)
  {
  	struct stacktrace_cookie *c = cookie;
  
  	if (c->len >= c->size)
  		return false;
  
  	if (c->skip > 0) {
  		c->skip--;
  		return true;
  	}
  	c->store[c->len++] = addr;
  	return c->len < c->size;
  }
  
  static bool stack_trace_consume_entry_nosched(void *cookie, unsigned long addr,
  					      bool reliable)
  {
  	if (in_sched_functions(addr))
  		return true;
  	return stack_trace_consume_entry(cookie, addr, reliable);
  }
  
  /**
   * stack_trace_save - Save a stack trace into a storage array
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   * @skipnr:	Number of entries to skip at the start of the stack trace
   *
   * Return: Number of trace entries stored.
   */
  unsigned int stack_trace_save(unsigned long *store, unsigned int size,
  			      unsigned int skipnr)
  {
  	stack_trace_consume_fn consume_entry = stack_trace_consume_entry;
  	struct stacktrace_cookie c = {
  		.store	= store,
  		.size	= size,
  		.skip	= skipnr + 1,
  	};
  
  	arch_stack_walk(consume_entry, &c, current, NULL);
  	return c.len;
  }
  EXPORT_SYMBOL_GPL(stack_trace_save);
  
  /**
   * stack_trace_save_tsk - Save a task stack trace into a storage array
   * @task:	The task to examine
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   * @skipnr:	Number of entries to skip at the start of the stack trace
   *
   * Return: Number of trace entries stored.
   */
  unsigned int stack_trace_save_tsk(struct task_struct *tsk, unsigned long *store,
  				  unsigned int size, unsigned int skipnr)
  {
  	stack_trace_consume_fn consume_entry = stack_trace_consume_entry_nosched;
  	struct stacktrace_cookie c = {
  		.store	= store,
  		.size	= size,
b0c51f158   Jiri Slaby   stacktrace: Don't...
141
142
  		/* skip this function if they are tracing us */
  		.skip	= skipnr + !!(current == tsk),
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  	};
  
  	if (!try_get_task_stack(tsk))
  		return 0;
  
  	arch_stack_walk(consume_entry, &c, tsk, NULL);
  	put_task_stack(tsk);
  	return c.len;
  }
  
  /**
   * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array
   * @regs:	Pointer to pt_regs to examine
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   * @skipnr:	Number of entries to skip at the start of the stack trace
   *
   * Return: Number of trace entries stored.
   */
  unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store,
  				   unsigned int size, unsigned int skipnr)
  {
  	stack_trace_consume_fn consume_entry = stack_trace_consume_entry;
  	struct stacktrace_cookie c = {
  		.store	= store,
  		.size	= size,
  		.skip	= skipnr,
  	};
  
  	arch_stack_walk(consume_entry, &c, current, regs);
  	return c.len;
  }
  
  #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE
  /**
   * stack_trace_save_tsk_reliable - Save task stack with verification
   * @tsk:	Pointer to the task to examine
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   *
   * Return:	An error if it detects any unreliable features of the
   *		stack. Otherwise it guarantees that the stack trace is
   *		reliable and returns the number of entries stored.
   *
   * If the task is not 'current', the caller *must* ensure the task is inactive.
   */
  int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store,
  				  unsigned int size)
  {
  	stack_trace_consume_fn consume_entry = stack_trace_consume_entry;
  	struct stacktrace_cookie c = {
  		.store	= store,
  		.size	= size,
  	};
  	int ret;
  
  	/*
  	 * If the task doesn't have a stack (e.g., a zombie), the stack is
  	 * "reliably" empty.
  	 */
  	if (!try_get_task_stack(tsk))
  		return 0;
  
  	ret = arch_stack_walk_reliable(consume_entry, &c, tsk);
  	put_task_stack(tsk);
7eaf51a2e   Joe Lawrence   stacktrace: Unbre...
208
  	return ret ? ret : c.len;
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  }
  #endif
  
  #ifdef CONFIG_USER_STACKTRACE_SUPPORT
  /**
   * stack_trace_save_user - Save a user space stack trace into a storage array
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   *
   * Return: Number of trace entries stored.
   */
  unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
  {
  	stack_trace_consume_fn consume_entry = stack_trace_consume_entry;
  	struct stacktrace_cookie c = {
  		.store	= store,
  		.size	= size,
  	};
cac9b9a4b   Peter Zijlstra   stacktrace: Force...
227
  	mm_segment_t fs;
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
228
229
  
  	/* Trace user stack if not a kernel thread */
7e8e6816c   Thomas Gleixner   stacktrace: Use P...
230
  	if (current->flags & PF_KTHREAD)
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
231
  		return 0;
cac9b9a4b   Peter Zijlstra   stacktrace: Force...
232
233
  	fs = get_fs();
  	set_fs(USER_DS);
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
234
  	arch_stack_walk_user(consume_entry, &c, task_pt_regs(current));
cac9b9a4b   Peter Zijlstra   stacktrace: Force...
235
  	set_fs(fs);
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
236
237
238
239
240
  	return c.len;
  }
  #endif
  
  #else /* CONFIG_ARCH_STACKWALK */
9212ddb5e   Ingo Molnar   stacktrace: provi...
241
  /*
af085d908   Josh Poimboeuf   stacktrace/x86: a...
242
243
   * Architectures that do not implement save_stack_trace_*()
   * get these weak aliases and once-per-bootup warnings
c624d33f6   Masami Hiramatsu   stack_trace: Add ...
244
   * (whenever this facility is utilized - for example by procfs):
9212ddb5e   Ingo Molnar   stacktrace: provi...
245
246
247
248
249
250
251
   */
  __weak void
  save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  {
  	WARN_ONCE(1, KERN_INFO "save_stack_trace_tsk() not implemented yet.
  ");
  }
c624d33f6   Masami Hiramatsu   stack_trace: Add ...
252
253
254
255
256
257
258
  
  __weak void
  save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
  {
  	WARN_ONCE(1, KERN_INFO "save_stack_trace_regs() not implemented yet.
  ");
  }
af085d908   Josh Poimboeuf   stacktrace/x86: a...
259

e9b98e162   Thomas Gleixner   stacktrace: Provi...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  /**
   * stack_trace_save - Save a stack trace into a storage array
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   * @skipnr:	Number of entries to skip at the start of the stack trace
   *
   * Return: Number of trace entries stored
   */
  unsigned int stack_trace_save(unsigned long *store, unsigned int size,
  			      unsigned int skipnr)
  {
  	struct stack_trace trace = {
  		.entries	= store,
  		.max_entries	= size,
  		.skip		= skipnr + 1,
  	};
  
  	save_stack_trace(&trace);
  	return trace.nr_entries;
  }
  EXPORT_SYMBOL_GPL(stack_trace_save);
  
  /**
   * stack_trace_save_tsk - Save a task stack trace into a storage array
   * @task:	The task to examine
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   * @skipnr:	Number of entries to skip at the start of the stack trace
   *
   * Return: Number of trace entries stored
   */
  unsigned int stack_trace_save_tsk(struct task_struct *task,
  				  unsigned long *store, unsigned int size,
  				  unsigned int skipnr)
  {
  	struct stack_trace trace = {
  		.entries	= store,
  		.max_entries	= size,
b0c51f158   Jiri Slaby   stacktrace: Don't...
298
299
  		/* skip this function if they are tracing us */
  		.skip	= skipnr + !!(current == task),
e9b98e162   Thomas Gleixner   stacktrace: Provi...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  	};
  
  	save_stack_trace_tsk(task, &trace);
  	return trace.nr_entries;
  }
  
  /**
   * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array
   * @regs:	Pointer to pt_regs to examine
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   * @skipnr:	Number of entries to skip at the start of the stack trace
   *
   * Return: Number of trace entries stored
   */
  unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store,
  				   unsigned int size, unsigned int skipnr)
  {
  	struct stack_trace trace = {
  		.entries	= store,
  		.max_entries	= size,
  		.skip		= skipnr,
  	};
  
  	save_stack_trace_regs(regs, &trace);
  	return trace.nr_entries;
  }
  
  #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE
  /**
   * stack_trace_save_tsk_reliable - Save task stack with verification
   * @tsk:	Pointer to the task to examine
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   *
   * Return:	An error if it detects any unreliable features of the
   *		stack. Otherwise it guarantees that the stack trace is
   *		reliable and returns the number of entries stored.
   *
   * If the task is not 'current', the caller *must* ensure the task is inactive.
   */
  int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store,
  				  unsigned int size)
  {
  	struct stack_trace trace = {
  		.entries	= store,
  		.max_entries	= size,
  	};
  	int ret = save_stack_trace_tsk_reliable(tsk, &trace);
  
  	return ret ? ret : trace.nr_entries;
  }
  #endif
  
  #ifdef CONFIG_USER_STACKTRACE_SUPPORT
  /**
   * stack_trace_save_user - Save a user space stack trace into a storage array
   * @store:	Pointer to storage array
   * @size:	Size of the storage array
   *
   * Return: Number of trace entries stored
   */
  unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
  {
  	struct stack_trace trace = {
  		.entries	= store,
  		.max_entries	= size,
  	};
  
  	save_stack_trace_user(&trace);
  	return trace.nr_entries;
  }
  #endif /* CONFIG_USER_STACKTRACE_SUPPORT */
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
373
374
  
  #endif /* !CONFIG_ARCH_STACKWALK */