diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 21:49:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 21:49:02 -0400 |
commit | 31003e3a9df675f1ac85d7bcf8e5a5d622576375 (patch) | |
tree | 6b08171deca1bf3cdcd6968ce0859e505048c73a /arch/um/kernel/stacktrace.c | |
parent | 1ee07ef6b5db7235b133ee257a3adf507697e6b3 (diff) | |
parent | 5f786595a291092d20fafe10c5a30378971a8cc3 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML update from Richard Weinberger:
"Besides of fixes this contains also support for CONFIG_STACKTRACE by
Daniel Walter"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
um: net: Eliminate NULL test after alloc_bootmem
um: Add support for CONFIG_STACKTRACE
um: ubd: Fix for processes stuck in D state forever
um: delete unnecessary bootmem struct page array
um: remove csum_partial_copy_generic_i386 to clean up exception table
Diffstat (limited to 'arch/um/kernel/stacktrace.c')
-rw-r--r-- | arch/um/kernel/stacktrace.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/arch/um/kernel/stacktrace.c b/arch/um/kernel/stacktrace.c new file mode 100644 index 000000000000..ebe7bcf62684 --- /dev/null +++ b/arch/um/kernel/stacktrace.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
3 | * Copyright (C) 2013 Richard Weinberger <richard@nod.at> | ||
4 | * Copyright (C) 2014 Google Inc., Author: Daniel Walter <dwalter@google.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kallsyms.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/stacktrace.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/uaccess.h> | ||
17 | #include <asm/stacktrace.h> | ||
18 | |||
19 | void dump_trace(struct task_struct *tsk, | ||
20 | const struct stacktrace_ops *ops, | ||
21 | void *data) | ||
22 | { | ||
23 | int reliable = 0; | ||
24 | unsigned long *sp, bp, addr; | ||
25 | struct pt_regs *segv_regs = tsk->thread.segv_regs; | ||
26 | struct stack_frame *frame; | ||
27 | |||
28 | bp = get_frame_pointer(tsk, segv_regs); | ||
29 | sp = get_stack_pointer(tsk, segv_regs); | ||
30 | |||
31 | frame = (struct stack_frame *)bp; | ||
32 | while (((long) sp & (THREAD_SIZE-1)) != 0) { | ||
33 | addr = *sp; | ||
34 | if (__kernel_text_address(addr)) { | ||
35 | reliable = 0; | ||
36 | if ((unsigned long) sp == bp + sizeof(long)) { | ||
37 | frame = frame ? frame->next_frame : NULL; | ||
38 | bp = (unsigned long)frame; | ||
39 | reliable = 1; | ||
40 | } | ||
41 | ops->address(data, addr, reliable); | ||
42 | } | ||
43 | sp++; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | static void save_addr(void *data, unsigned long address, int reliable) | ||
48 | { | ||
49 | struct stack_trace *trace = data; | ||
50 | |||
51 | if (!reliable) | ||
52 | return; | ||
53 | if (trace->nr_entries >= trace->max_entries) | ||
54 | return; | ||
55 | |||
56 | trace->entries[trace->nr_entries++] = address; | ||
57 | } | ||
58 | |||
59 | static const struct stacktrace_ops dump_ops = { | ||
60 | .address = save_addr | ||
61 | }; | ||
62 | |||
63 | static void __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace) | ||
64 | { | ||
65 | dump_trace(tsk, &dump_ops, trace); | ||
66 | if (trace->nr_entries < trace->max_entries) | ||
67 | trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
68 | } | ||
69 | |||
70 | void save_stack_trace(struct stack_trace *trace) | ||
71 | { | ||
72 | __save_stack_trace(current, trace); | ||
73 | } | ||
74 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
75 | |||
76 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | ||
77 | { | ||
78 | __save_stack_trace(tsk, trace); | ||
79 | } | ||
80 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | ||