diff options
-rw-r--r-- | arch/x86/include/asm/stacktrace.h | 36 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack.c | 86 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack_32.c | 35 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack_64.c | 69 |
4 files changed, 0 insertions, 226 deletions
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index c9ccf0676ca6..37f2e0b377ad 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h | |||
@@ -45,42 +45,6 @@ static inline bool on_stack(struct stack_info *info, void *addr, size_t len) | |||
45 | 45 | ||
46 | extern int kstack_depth_to_print; | 46 | extern int kstack_depth_to_print; |
47 | 47 | ||
48 | struct thread_info; | ||
49 | struct stacktrace_ops; | ||
50 | |||
51 | typedef unsigned long (*walk_stack_t)(struct task_struct *task, | ||
52 | unsigned long *stack, | ||
53 | unsigned long bp, | ||
54 | const struct stacktrace_ops *ops, | ||
55 | void *data, | ||
56 | struct stack_info *info, | ||
57 | int *graph); | ||
58 | |||
59 | extern unsigned long | ||
60 | print_context_stack(struct task_struct *task, | ||
61 | unsigned long *stack, unsigned long bp, | ||
62 | const struct stacktrace_ops *ops, void *data, | ||
63 | struct stack_info *info, int *graph); | ||
64 | |||
65 | extern unsigned long | ||
66 | print_context_stack_bp(struct task_struct *task, | ||
67 | unsigned long *stack, unsigned long bp, | ||
68 | const struct stacktrace_ops *ops, void *data, | ||
69 | struct stack_info *info, int *graph); | ||
70 | |||
71 | /* Generic stack tracer with callbacks */ | ||
72 | |||
73 | struct stacktrace_ops { | ||
74 | int (*address)(void *data, unsigned long address, int reliable); | ||
75 | /* On negative return stop dumping */ | ||
76 | int (*stack)(void *data, const char *name); | ||
77 | walk_stack_t walk_stack; | ||
78 | }; | ||
79 | |||
80 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, | ||
81 | unsigned long *stack, unsigned long bp, | ||
82 | const struct stacktrace_ops *ops, void *data); | ||
83 | |||
84 | #ifdef CONFIG_X86_32 | 48 | #ifdef CONFIG_X86_32 |
85 | #define STACKSLOTS_PER_LINE 8 | 49 | #define STACKSLOTS_PER_LINE 8 |
86 | #else | 50 | #else |
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index c08f32ab8ace..999de3b3f7f4 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -56,92 +56,6 @@ void printk_address(unsigned long address) | |||
56 | pr_cont(" [<%p>] %pS\n", (void *)address, (void *)address); | 56 | pr_cont(" [<%p>] %pS\n", (void *)address, (void *)address); |
57 | } | 57 | } |
58 | 58 | ||
59 | /* | ||
60 | * x86-64 can have up to three kernel stacks: | ||
61 | * process stack | ||
62 | * interrupt stack | ||
63 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | ||
64 | */ | ||
65 | |||
66 | unsigned long | ||
67 | print_context_stack(struct task_struct *task, | ||
68 | unsigned long *stack, unsigned long bp, | ||
69 | const struct stacktrace_ops *ops, void *data, | ||
70 | struct stack_info *info, int *graph) | ||
71 | { | ||
72 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
73 | |||
74 | /* | ||
75 | * If we overflowed the stack into a guard page, jump back to the | ||
76 | * bottom of the usable stack. | ||
77 | */ | ||
78 | if ((unsigned long)task_stack_page(task) - (unsigned long)stack < | ||
79 | PAGE_SIZE) | ||
80 | stack = (unsigned long *)task_stack_page(task); | ||
81 | |||
82 | while (on_stack(info, stack, sizeof(*stack))) { | ||
83 | unsigned long addr = *stack; | ||
84 | |||
85 | if (__kernel_text_address(addr)) { | ||
86 | unsigned long real_addr; | ||
87 | int reliable = 0; | ||
88 | |||
89 | if ((unsigned long) stack == bp + sizeof(long)) { | ||
90 | reliable = 1; | ||
91 | frame = frame->next_frame; | ||
92 | bp = (unsigned long) frame; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * When function graph tracing is enabled for a | ||
97 | * function, its return address on the stack is | ||
98 | * replaced with the address of an ftrace handler | ||
99 | * (return_to_handler). In that case, before printing | ||
100 | * the "real" address, we want to print the handler | ||
101 | * address as an "unreliable" hint that function graph | ||
102 | * tracing was involved. | ||
103 | */ | ||
104 | real_addr = ftrace_graph_ret_addr(task, graph, addr, | ||
105 | stack); | ||
106 | if (real_addr != addr) | ||
107 | ops->address(data, addr, 0); | ||
108 | |||
109 | ops->address(data, real_addr, reliable); | ||
110 | } | ||
111 | stack++; | ||
112 | } | ||
113 | return bp; | ||
114 | } | ||
115 | EXPORT_SYMBOL_GPL(print_context_stack); | ||
116 | |||
117 | unsigned long | ||
118 | print_context_stack_bp(struct task_struct *task, | ||
119 | unsigned long *stack, unsigned long bp, | ||
120 | const struct stacktrace_ops *ops, void *data, | ||
121 | struct stack_info *info, int *graph) | ||
122 | { | ||
123 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
124 | unsigned long *retp = &frame->return_address; | ||
125 | |||
126 | while (on_stack(info, stack, sizeof(*stack) * 2)) { | ||
127 | unsigned long addr = *retp; | ||
128 | unsigned long real_addr; | ||
129 | |||
130 | if (!__kernel_text_address(addr)) | ||
131 | break; | ||
132 | |||
133 | real_addr = ftrace_graph_ret_addr(task, graph, addr, retp); | ||
134 | if (ops->address(data, real_addr, 1)) | ||
135 | break; | ||
136 | |||
137 | frame = frame->next_frame; | ||
138 | retp = &frame->return_address; | ||
139 | } | ||
140 | |||
141 | return (unsigned long)frame; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(print_context_stack_bp); | ||
144 | |||
145 | void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 59 | void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
146 | unsigned long *stack, char *log_lvl) | 60 | unsigned long *stack, char *log_lvl) |
147 | { | 61 | { |
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index e476eb774278..06eb322b5f9f 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c | |||
@@ -121,41 +121,6 @@ unknown: | |||
121 | return -EINVAL; | 121 | return -EINVAL; |
122 | } | 122 | } |
123 | 123 | ||
124 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | ||
125 | unsigned long *stack, unsigned long bp, | ||
126 | const struct stacktrace_ops *ops, void *data) | ||
127 | { | ||
128 | unsigned long visit_mask = 0; | ||
129 | int graph = 0; | ||
130 | |||
131 | task = task ? : current; | ||
132 | stack = stack ? : get_stack_pointer(task, regs); | ||
133 | bp = bp ? : (unsigned long)get_frame_pointer(task, regs); | ||
134 | |||
135 | for (;;) { | ||
136 | const char *begin_str, *end_str; | ||
137 | struct stack_info info; | ||
138 | |||
139 | if (get_stack_info(stack, task, &info, &visit_mask)) | ||
140 | break; | ||
141 | |||
142 | stack_type_str(info.type, &begin_str, &end_str); | ||
143 | |||
144 | if (begin_str && ops->stack(data, begin_str) < 0) | ||
145 | break; | ||
146 | |||
147 | bp = ops->walk_stack(task, stack, bp, ops, data, &info, &graph); | ||
148 | |||
149 | if (end_str && ops->stack(data, end_str) < 0) | ||
150 | break; | ||
151 | |||
152 | stack = info.next_sp; | ||
153 | |||
154 | touch_nmi_watchdog(); | ||
155 | } | ||
156 | } | ||
157 | EXPORT_SYMBOL(dump_trace); | ||
158 | |||
159 | void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 124 | void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
160 | unsigned long *sp, char *log_lvl) | 125 | unsigned long *sp, char *log_lvl) |
161 | { | 126 | { |
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 4e9f2cf64ac8..36cf1a498227 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
@@ -140,75 +140,6 @@ unknown: | |||
140 | return -EINVAL; | 140 | return -EINVAL; |
141 | } | 141 | } |
142 | 142 | ||
143 | /* | ||
144 | * x86-64 can have up to three kernel stacks: | ||
145 | * process stack | ||
146 | * interrupt stack | ||
147 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | ||
148 | */ | ||
149 | |||
150 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | ||
151 | unsigned long *stack, unsigned long bp, | ||
152 | const struct stacktrace_ops *ops, void *data) | ||
153 | { | ||
154 | unsigned long visit_mask = 0; | ||
155 | struct stack_info info; | ||
156 | int graph = 0; | ||
157 | int done = 0; | ||
158 | |||
159 | task = task ? : current; | ||
160 | stack = stack ? : get_stack_pointer(task, regs); | ||
161 | bp = bp ? : (unsigned long)get_frame_pointer(task, regs); | ||
162 | |||
163 | /* | ||
164 | * Print function call entries in all stacks, starting at the | ||
165 | * current stack address. If the stacks consist of nested | ||
166 | * exceptions | ||
167 | */ | ||
168 | while (!done) { | ||
169 | const char *begin_str, *end_str; | ||
170 | |||
171 | get_stack_info(stack, task, &info, &visit_mask); | ||
172 | |||
173 | /* Default finish unless specified to continue */ | ||
174 | done = 1; | ||
175 | |||
176 | switch (info.type) { | ||
177 | |||
178 | /* Break out early if we are on the thread stack */ | ||
179 | case STACK_TYPE_TASK: | ||
180 | break; | ||
181 | |||
182 | case STACK_TYPE_IRQ: | ||
183 | case STACK_TYPE_EXCEPTION ... STACK_TYPE_EXCEPTION_LAST: | ||
184 | |||
185 | stack_type_str(info.type, &begin_str, &end_str); | ||
186 | |||
187 | if (ops->stack(data, begin_str) < 0) | ||
188 | break; | ||
189 | |||
190 | bp = ops->walk_stack(task, stack, bp, ops, | ||
191 | data, &info, &graph); | ||
192 | |||
193 | ops->stack(data, end_str); | ||
194 | |||
195 | stack = info.next_sp; | ||
196 | done = 0; | ||
197 | break; | ||
198 | |||
199 | default: | ||
200 | ops->stack(data, "UNK"); | ||
201 | break; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * This handles the process stack: | ||
207 | */ | ||
208 | bp = ops->walk_stack(task, stack, bp, ops, data, &info, &graph); | ||
209 | } | ||
210 | EXPORT_SYMBOL(dump_trace); | ||
211 | |||
212 | void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 143 | void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
213 | unsigned long *sp, char *log_lvl) | 144 | unsigned long *sp, char *log_lvl) |
214 | { | 145 | { |