Blame view

kernel/stacktrace.c 9.62 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
  #ifdef CONFIG_ARCH_STACKWALK
  
  struct stacktrace_cookie {
  	unsigned long	*store;
  	unsigned int	size;
  	unsigned int	skip;
  	unsigned int	len;
  };
264c03a24   Mark Brown   stacktrace: Remov...
77
  static bool stack_trace_consume_entry(void *cookie, unsigned long addr)
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
78
79
80
81
82
83
84
85
86
87
88
89
90
  {
  	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;
  }
264c03a24   Mark Brown   stacktrace: Remov...
91
  static bool stack_trace_consume_entry_nosched(void *cookie, unsigned long addr)
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
92
93
94
  {
  	if (in_sched_functions(addr))
  		return true;
264c03a24   Mark Brown   stacktrace: Remov...
95
  	return stack_trace_consume_entry(cookie, addr);
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
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
  }
  
  /**
   * 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...
137
  		/* skip this function if they are tracing us */
4b48512c2   Jiri Slaby   stacktrace: Get r...
138
  		.skip	= skipnr + (current == tsk),
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
139
140
141
142
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
  	};
  
  	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...
204
  	return ret ? ret : c.len;
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  }
  #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...
223
  	mm_segment_t fs;
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
224
225
  
  	/* Trace user stack if not a kernel thread */
7e8e6816c   Thomas Gleixner   stacktrace: Use P...
226
  	if (current->flags & PF_KTHREAD)
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
227
  		return 0;
3d13f313c   Christoph Hellwig   uaccess: add forc...
228
  	fs = force_uaccess_begin();
214d8ca6e   Thomas Gleixner   stacktrace: Provi...
229
  	arch_stack_walk_user(consume_entry, &c, task_pt_regs(current));
3d13f313c   Christoph Hellwig   uaccess: add forc...
230
  	force_uaccess_end(fs);
cac9b9a4b   Peter Zijlstra   stacktrace: Force...
231

214d8ca6e   Thomas Gleixner   stacktrace: Provi...
232
233
234
235
236
  	return c.len;
  }
  #endif
  
  #else /* CONFIG_ARCH_STACKWALK */
9212ddb5e   Ingo Molnar   stacktrace: provi...
237
  /*
af085d908   Josh Poimboeuf   stacktrace/x86: a...
238
239
   * Architectures that do not implement save_stack_trace_*()
   * get these weak aliases and once-per-bootup warnings
c624d33f6   Masami Hiramatsu   stack_trace: Add ...
240
   * (whenever this facility is utilized - for example by procfs):
9212ddb5e   Ingo Molnar   stacktrace: provi...
241
242
243
244
245
246
247
   */
  __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 ...
248
249
250
251
252
253
254
  
  __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...
255

e9b98e162   Thomas Gleixner   stacktrace: Provi...
256
257
258
259
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
  /**
   * 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...
294
  		/* skip this function if they are tracing us */
4b48512c2   Jiri Slaby   stacktrace: Get r...
295
  		.skip	= skipnr + (current == task),
e9b98e162   Thomas Gleixner   stacktrace: Provi...
296
297
298
299
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
  	};
  
  	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...
369
370
  
  #endif /* !CONFIG_ARCH_STACKWALK */