summaryrefslogtreecommitdiffstats
path: root/kernel/stacktrace.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-05-06 16:11:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-06 16:11:48 -0400
commit2c6a392cddacde153865b15e8295ad0a35ed3c02 (patch)
tree558c34595f8987c87d26fc0fa0dc644fca9ef2cd /kernel/stacktrace.c
parent0a499fc5c37e6db096969a83534fd98a2bf2b36c (diff)
parent3599fe12a125fa7118da2bcc5033d7741fb5f3a1 (diff)
Merge branch 'core-stacktrace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull stack trace updates from Ingo Molnar: "So Thomas looked at the stacktrace code recently and noticed a few weirdnesses, and we all know how such stories of crummy kernel code meeting German engineering perfection end: a 45-patch series to clean it all up! :-) Here's the changes in Thomas's words: 'Struct stack_trace is a sinkhole for input and output parameters which is largely pointless for most usage sites. In fact if embedded into other data structures it creates indirections and extra storage overhead for no benefit. Looking at all usage sites makes it clear that they just require an interface which is based on a storage array. That array is either on stack, global or embedded into some other data structure. Some of the stack depot usage sites are outright wrong, but fortunately the wrongness just causes more stack being used for nothing and does not have functional impact. Another oddity is the inconsistent termination of the stack trace with ULONG_MAX. It's pointless as the number of entries is what determines the length of the stored trace. In fact quite some call sites remove the ULONG_MAX marker afterwards with or without nasty comments about it. Not all architectures do that and those which do, do it inconsistenly either conditional on nr_entries == 0 or unconditionally. The following series cleans that up by: 1) Removing the ULONG_MAX termination in the architecture code 2) Removing the ULONG_MAX fixups at the call sites 3) Providing plain storage array based interfaces for stacktrace and stackdepot. 4) Cleaning up the mess at the callsites including some related cleanups. 5) Removing the struct stack_trace based interfaces This is not changing the struct stack_trace interfaces at the architecture level, but it removes the exposure to the generic code'" * 'core-stacktrace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (45 commits) x86/stacktrace: Use common infrastructure stacktrace: Provide common infrastructure lib/stackdepot: Remove obsolete functions stacktrace: Remove obsolete functions livepatch: Simplify stack trace retrieval tracing: Remove the last struct stack_trace usage tracing: Simplify stack trace retrieval tracing: Make ftrace_trace_userstack() static and conditional tracing: Use percpu stack trace buffer more intelligently tracing: Simplify stacktrace retrieval in histograms lockdep: Simplify stack trace handling lockdep: Remove save argument from check_prev_add() lockdep: Remove unused trace argument from print_circular_bug() drm: Simplify stacktrace handling dm persistent data: Simplify stack trace handling dm bufio: Simplify stack trace retrieval btrfs: ref-verify: Simplify stack trace retrieval dma/debug: Simplify stracktrace retrieval fault-inject: Simplify stacktrace retrieval mm/page_owner: Simplify stack trace handling ...
Diffstat (limited to 'kernel/stacktrace.c')
-rw-r--r--kernel/stacktrace.c333
1 files changed, 316 insertions, 17 deletions
diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
index f8edee9c792d..27bafc1e271e 100644
--- a/kernel/stacktrace.c
+++ b/kernel/stacktrace.c
@@ -5,41 +5,56 @@
5 * 5 *
6 * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> 6 * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
7 */ 7 */
8#include <linux/sched/task_stack.h>
9#include <linux/sched/debug.h>
8#include <linux/sched.h> 10#include <linux/sched.h>
9#include <linux/kernel.h> 11#include <linux/kernel.h>
10#include <linux/export.h> 12#include <linux/export.h>
11#include <linux/kallsyms.h> 13#include <linux/kallsyms.h>
12#include <linux/stacktrace.h> 14#include <linux/stacktrace.h>
13 15
14void print_stack_trace(struct stack_trace *trace, int spaces) 16/**
17 * stack_trace_print - Print the entries in the stack trace
18 * @entries: Pointer to storage array
19 * @nr_entries: Number of entries in the storage array
20 * @spaces: Number of leading spaces to print
21 */
22void stack_trace_print(unsigned long *entries, unsigned int nr_entries,
23 int spaces)
15{ 24{
16 int i; 25 unsigned int i;
17 26
18 if (WARN_ON(!trace->entries)) 27 if (WARN_ON(!entries))
19 return; 28 return;
20 29
21 for (i = 0; i < trace->nr_entries; i++) 30 for (i = 0; i < nr_entries; i++)
22 printk("%*c%pS\n", 1 + spaces, ' ', (void *)trace->entries[i]); 31 printk("%*c%pS\n", 1 + spaces, ' ', (void *)entries[i]);
23} 32}
24EXPORT_SYMBOL_GPL(print_stack_trace); 33EXPORT_SYMBOL_GPL(stack_trace_print);
25 34
26int snprint_stack_trace(char *buf, size_t size, 35/**
27 struct stack_trace *trace, int spaces) 36 * stack_trace_snprint - Print the entries in the stack trace into a buffer
37 * @buf: Pointer to the print buffer
38 * @size: Size of the print buffer
39 * @entries: Pointer to storage array
40 * @nr_entries: Number of entries in the storage array
41 * @spaces: Number of leading spaces to print
42 *
43 * Return: Number of bytes printed.
44 */
45int stack_trace_snprint(char *buf, size_t size, unsigned long *entries,
46 unsigned int nr_entries, int spaces)
28{ 47{
29 int i; 48 unsigned int generated, i, total = 0;
30 int generated;
31 int total = 0;
32 49
33 if (WARN_ON(!trace->entries)) 50 if (WARN_ON(!entries))
34 return 0; 51 return 0;
35 52
36 for (i = 0; i < trace->nr_entries; i++) { 53 for (i = 0; i < nr_entries && size; i++) {
37 generated = snprintf(buf, size, "%*c%pS\n", 1 + spaces, ' ', 54 generated = snprintf(buf, size, "%*c%pS\n", 1 + spaces, ' ',
38 (void *)trace->entries[i]); 55 (void *)entries[i]);
39 56
40 total += generated; 57 total += generated;
41
42 /* Assume that generated isn't a negative number */
43 if (generated >= size) { 58 if (generated >= size) {
44 buf += size; 59 buf += size;
45 size = 0; 60 size = 0;
@@ -51,7 +66,176 @@ int snprint_stack_trace(char *buf, size_t size,
51 66
52 return total; 67 return total;
53} 68}
54EXPORT_SYMBOL_GPL(snprint_stack_trace); 69EXPORT_SYMBOL_GPL(stack_trace_snprint);
70
71#ifdef CONFIG_ARCH_STACKWALK
72
73struct stacktrace_cookie {
74 unsigned long *store;
75 unsigned int size;
76 unsigned int skip;
77 unsigned int len;
78};
79
80static bool stack_trace_consume_entry(void *cookie, unsigned long addr,
81 bool reliable)
82{
83 struct stacktrace_cookie *c = cookie;
84
85 if (c->len >= c->size)
86 return false;
87
88 if (c->skip > 0) {
89 c->skip--;
90 return true;
91 }
92 c->store[c->len++] = addr;
93 return c->len < c->size;
94}
95
96static bool stack_trace_consume_entry_nosched(void *cookie, unsigned long addr,
97 bool reliable)
98{
99 if (in_sched_functions(addr))
100 return true;
101 return stack_trace_consume_entry(cookie, addr, reliable);
102}
103
104/**
105 * stack_trace_save - Save a stack trace into a storage array
106 * @store: Pointer to storage array
107 * @size: Size of the storage array
108 * @skipnr: Number of entries to skip at the start of the stack trace
109 *
110 * Return: Number of trace entries stored.
111 */
112unsigned int stack_trace_save(unsigned long *store, unsigned int size,
113 unsigned int skipnr)
114{
115 stack_trace_consume_fn consume_entry = stack_trace_consume_entry;
116 struct stacktrace_cookie c = {
117 .store = store,
118 .size = size,
119 .skip = skipnr + 1,
120 };
121
122 arch_stack_walk(consume_entry, &c, current, NULL);
123 return c.len;
124}
125EXPORT_SYMBOL_GPL(stack_trace_save);
126
127/**
128 * stack_trace_save_tsk - Save a task stack trace into a storage array
129 * @task: The task to examine
130 * @store: Pointer to storage array
131 * @size: Size of the storage array
132 * @skipnr: Number of entries to skip at the start of the stack trace
133 *
134 * Return: Number of trace entries stored.
135 */
136unsigned int stack_trace_save_tsk(struct task_struct *tsk, unsigned long *store,
137 unsigned int size, unsigned int skipnr)
138{
139 stack_trace_consume_fn consume_entry = stack_trace_consume_entry_nosched;
140 struct stacktrace_cookie c = {
141 .store = store,
142 .size = size,
143 .skip = skipnr + 1,
144 };
145
146 if (!try_get_task_stack(tsk))
147 return 0;
148
149 arch_stack_walk(consume_entry, &c, tsk, NULL);
150 put_task_stack(tsk);
151 return c.len;
152}
153
154/**
155 * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array
156 * @regs: Pointer to pt_regs to examine
157 * @store: Pointer to storage array
158 * @size: Size of the storage array
159 * @skipnr: Number of entries to skip at the start of the stack trace
160 *
161 * Return: Number of trace entries stored.
162 */
163unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store,
164 unsigned int size, unsigned int skipnr)
165{
166 stack_trace_consume_fn consume_entry = stack_trace_consume_entry;
167 struct stacktrace_cookie c = {
168 .store = store,
169 .size = size,
170 .skip = skipnr,
171 };
172
173 arch_stack_walk(consume_entry, &c, current, regs);
174 return c.len;
175}
176
177#ifdef CONFIG_HAVE_RELIABLE_STACKTRACE
178/**
179 * stack_trace_save_tsk_reliable - Save task stack with verification
180 * @tsk: Pointer to the task to examine
181 * @store: Pointer to storage array
182 * @size: Size of the storage array
183 *
184 * Return: An error if it detects any unreliable features of the
185 * stack. Otherwise it guarantees that the stack trace is
186 * reliable and returns the number of entries stored.
187 *
188 * If the task is not 'current', the caller *must* ensure the task is inactive.
189 */
190int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store,
191 unsigned int size)
192{
193 stack_trace_consume_fn consume_entry = stack_trace_consume_entry;
194 struct stacktrace_cookie c = {
195 .store = store,
196 .size = size,
197 };
198 int ret;
199
200 /*
201 * If the task doesn't have a stack (e.g., a zombie), the stack is
202 * "reliably" empty.
203 */
204 if (!try_get_task_stack(tsk))
205 return 0;
206
207 ret = arch_stack_walk_reliable(consume_entry, &c, tsk);
208 put_task_stack(tsk);
209 return ret;
210}
211#endif
212
213#ifdef CONFIG_USER_STACKTRACE_SUPPORT
214/**
215 * stack_trace_save_user - Save a user space stack trace into a storage array
216 * @store: Pointer to storage array
217 * @size: Size of the storage array
218 *
219 * Return: Number of trace entries stored.
220 */
221unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
222{
223 stack_trace_consume_fn consume_entry = stack_trace_consume_entry;
224 struct stacktrace_cookie c = {
225 .store = store,
226 .size = size,
227 };
228
229 /* Trace user stack if not a kernel thread */
230 if (!current->mm)
231 return 0;
232
233 arch_stack_walk_user(consume_entry, &c, task_pt_regs(current));
234 return c.len;
235}
236#endif
237
238#else /* CONFIG_ARCH_STACKWALK */
55 239
56/* 240/*
57 * Architectures that do not implement save_stack_trace_*() 241 * Architectures that do not implement save_stack_trace_*()
@@ -77,3 +261,118 @@ save_stack_trace_tsk_reliable(struct task_struct *tsk,
77 WARN_ONCE(1, KERN_INFO "save_stack_tsk_reliable() not implemented yet.\n"); 261 WARN_ONCE(1, KERN_INFO "save_stack_tsk_reliable() not implemented yet.\n");
78 return -ENOSYS; 262 return -ENOSYS;
79} 263}
264
265/**
266 * stack_trace_save - Save a stack trace into a storage array
267 * @store: Pointer to storage array
268 * @size: Size of the storage array
269 * @skipnr: Number of entries to skip at the start of the stack trace
270 *
271 * Return: Number of trace entries stored
272 */
273unsigned int stack_trace_save(unsigned long *store, unsigned int size,
274 unsigned int skipnr)
275{
276 struct stack_trace trace = {
277 .entries = store,
278 .max_entries = size,
279 .skip = skipnr + 1,
280 };
281
282 save_stack_trace(&trace);
283 return trace.nr_entries;
284}
285EXPORT_SYMBOL_GPL(stack_trace_save);
286
287/**
288 * stack_trace_save_tsk - Save a task stack trace into a storage array
289 * @task: The task to examine
290 * @store: Pointer to storage array
291 * @size: Size of the storage array
292 * @skipnr: Number of entries to skip at the start of the stack trace
293 *
294 * Return: Number of trace entries stored
295 */
296unsigned int stack_trace_save_tsk(struct task_struct *task,
297 unsigned long *store, unsigned int size,
298 unsigned int skipnr)
299{
300 struct stack_trace trace = {
301 .entries = store,
302 .max_entries = size,
303 .skip = skipnr + 1,
304 };
305
306 save_stack_trace_tsk(task, &trace);
307 return trace.nr_entries;
308}
309
310/**
311 * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array
312 * @regs: Pointer to pt_regs to examine
313 * @store: Pointer to storage array
314 * @size: Size of the storage array
315 * @skipnr: Number of entries to skip at the start of the stack trace
316 *
317 * Return: Number of trace entries stored
318 */
319unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store,
320 unsigned int size, unsigned int skipnr)
321{
322 struct stack_trace trace = {
323 .entries = store,
324 .max_entries = size,
325 .skip = skipnr,
326 };
327
328 save_stack_trace_regs(regs, &trace);
329 return trace.nr_entries;
330}
331
332#ifdef CONFIG_HAVE_RELIABLE_STACKTRACE
333/**
334 * stack_trace_save_tsk_reliable - Save task stack with verification
335 * @tsk: Pointer to the task to examine
336 * @store: Pointer to storage array
337 * @size: Size of the storage array
338 *
339 * Return: An error if it detects any unreliable features of the
340 * stack. Otherwise it guarantees that the stack trace is
341 * reliable and returns the number of entries stored.
342 *
343 * If the task is not 'current', the caller *must* ensure the task is inactive.
344 */
345int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store,
346 unsigned int size)
347{
348 struct stack_trace trace = {
349 .entries = store,
350 .max_entries = size,
351 };
352 int ret = save_stack_trace_tsk_reliable(tsk, &trace);
353
354 return ret ? ret : trace.nr_entries;
355}
356#endif
357
358#ifdef CONFIG_USER_STACKTRACE_SUPPORT
359/**
360 * stack_trace_save_user - Save a user space stack trace into a storage array
361 * @store: Pointer to storage array
362 * @size: Size of the storage array
363 *
364 * Return: Number of trace entries stored
365 */
366unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
367{
368 struct stack_trace trace = {
369 .entries = store,
370 .max_entries = size,
371 };
372
373 save_stack_trace_user(&trace);
374 return trace.nr_entries;
375}
376#endif /* CONFIG_USER_STACKTRACE_SUPPORT */
377
378#endif /* !CONFIG_ARCH_STACKWALK */