diff options
author | Josh Poimboeuf <jpoimboe@redhat.com> | 2016-09-14 22:07:42 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-09-15 02:13:15 -0400 |
commit | cb76c93982404273d746f3ccd5085b47689099a8 (patch) | |
tree | 95103a60e29ad190e4ee9ef3818f97825eab936f /arch/x86/kernel/dumpstack.c | |
parent | 9c00390757fd9f5851f7973b2f0e1e41550bb3b8 (diff) |
x86/dumpstack: Add get_stack_info() interface
valid_stack_ptr() is buggy: it assumes that all stacks are of size
THREAD_SIZE, which is not true for exception stacks. So the
walk_stack() callbacks will need to know the location of the beginning
of the stack as well as the end.
Another issue is that in general the various features of a stack (type,
size, next stack pointer, description string) are scattered around in
various places throughout the stack dump code.
Encapsulate all that information in a single place with a new stack_info
struct and a get_stack_info() interface.
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Byungchul Park <byungchul.park@lge.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nilay Vaish <nilayvaish@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/8164dd0db96b7e6a279fa17ae5e6dc375eecb4a9.1473905218.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel/dumpstack.c')
-rw-r--r-- | arch/x86/kernel/dumpstack.c | 40 |
1 files changed, 22 insertions, 18 deletions
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index c6c6c39c367f..aa208e565b03 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -25,6 +25,23 @@ unsigned int code_bytes = 64; | |||
25 | int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; | 25 | int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; |
26 | static int die_counter; | 26 | static int die_counter; |
27 | 27 | ||
28 | bool in_task_stack(unsigned long *stack, struct task_struct *task, | ||
29 | struct stack_info *info) | ||
30 | { | ||
31 | unsigned long *begin = task_stack_page(task); | ||
32 | unsigned long *end = task_stack_page(task) + THREAD_SIZE; | ||
33 | |||
34 | if (stack < begin || stack >= end) | ||
35 | return false; | ||
36 | |||
37 | info->type = STACK_TYPE_TASK; | ||
38 | info->begin = begin; | ||
39 | info->end = end; | ||
40 | info->next_sp = NULL; | ||
41 | |||
42 | return true; | ||
43 | } | ||
44 | |||
28 | static void printk_stack_address(unsigned long address, int reliable, | 45 | static void printk_stack_address(unsigned long address, int reliable, |
29 | char *log_lvl) | 46 | char *log_lvl) |
30 | { | 47 | { |
@@ -46,24 +63,11 @@ void printk_address(unsigned long address) | |||
46 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | 63 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack |
47 | */ | 64 | */ |
48 | 65 | ||
49 | static inline int valid_stack_ptr(struct task_struct *task, | ||
50 | void *p, unsigned int size, void *end) | ||
51 | { | ||
52 | void *t = task_stack_page(task); | ||
53 | if (end) { | ||
54 | if (p < end && p >= (end-THREAD_SIZE)) | ||
55 | return 1; | ||
56 | else | ||
57 | return 0; | ||
58 | } | ||
59 | return p >= t && p < t + THREAD_SIZE - size; | ||
60 | } | ||
61 | |||
62 | unsigned long | 66 | unsigned long |
63 | print_context_stack(struct task_struct *task, | 67 | print_context_stack(struct task_struct *task, |
64 | unsigned long *stack, unsigned long bp, | 68 | unsigned long *stack, unsigned long bp, |
65 | const struct stacktrace_ops *ops, void *data, | 69 | const struct stacktrace_ops *ops, void *data, |
66 | unsigned long *end, int *graph) | 70 | struct stack_info *info, int *graph) |
67 | { | 71 | { |
68 | struct stack_frame *frame = (struct stack_frame *)bp; | 72 | struct stack_frame *frame = (struct stack_frame *)bp; |
69 | 73 | ||
@@ -75,7 +79,7 @@ print_context_stack(struct task_struct *task, | |||
75 | PAGE_SIZE) | 79 | PAGE_SIZE) |
76 | stack = (unsigned long *)task_stack_page(task); | 80 | stack = (unsigned long *)task_stack_page(task); |
77 | 81 | ||
78 | while (valid_stack_ptr(task, stack, sizeof(*stack), end)) { | 82 | while (on_stack(info, stack, sizeof(*stack))) { |
79 | unsigned long addr = *stack; | 83 | unsigned long addr = *stack; |
80 | 84 | ||
81 | if (__kernel_text_address(addr)) { | 85 | if (__kernel_text_address(addr)) { |
@@ -114,12 +118,12 @@ unsigned long | |||
114 | print_context_stack_bp(struct task_struct *task, | 118 | print_context_stack_bp(struct task_struct *task, |
115 | unsigned long *stack, unsigned long bp, | 119 | unsigned long *stack, unsigned long bp, |
116 | const struct stacktrace_ops *ops, void *data, | 120 | const struct stacktrace_ops *ops, void *data, |
117 | unsigned long *end, int *graph) | 121 | struct stack_info *info, int *graph) |
118 | { | 122 | { |
119 | struct stack_frame *frame = (struct stack_frame *)bp; | 123 | struct stack_frame *frame = (struct stack_frame *)bp; |
120 | unsigned long *retp = &frame->return_address; | 124 | unsigned long *retp = &frame->return_address; |
121 | 125 | ||
122 | while (valid_stack_ptr(task, retp, sizeof(*retp), end)) { | 126 | while (on_stack(info, stack, sizeof(*stack) * 2)) { |
123 | unsigned long addr = *retp; | 127 | unsigned long addr = *retp; |
124 | unsigned long real_addr; | 128 | unsigned long real_addr; |
125 | 129 | ||
@@ -138,7 +142,7 @@ print_context_stack_bp(struct task_struct *task, | |||
138 | } | 142 | } |
139 | EXPORT_SYMBOL_GPL(print_context_stack_bp); | 143 | EXPORT_SYMBOL_GPL(print_context_stack_bp); |
140 | 144 | ||
141 | static int print_trace_stack(void *data, char *name) | 145 | static int print_trace_stack(void *data, const char *name) |
142 | { | 146 | { |
143 | printk("%s <%s> ", (char *)data, name); | 147 | printk("%s <%s> ", (char *)data, name); |
144 | return 0; | 148 | return 0; |