diff options
author | Arjan van de Ven <arjan@linux.intel.com> | 2008-01-30 07:33:07 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:33:07 -0500 |
commit | 5bc27dc2f55fd3043597b5a8de6536183f28a449 (patch) | |
tree | dca83b12fb2f01f85a9e31bf1fb3802bd2cfef2a /arch/x86 | |
parent | e9d4efddbec3d852d435b370b9c40ff7ac24afe6 (diff) |
x86: pull bp calculation earlier into the backtrace path
Right now, we take the stack pointer early during the backtrace path, but
only calculate bp several functions deep later, making it hard to reconcile
the stack and bp backtraces (as well as showing several internal backtrace
functions on the stack with bp based backtracing).
This patch moves the bp taking to the same place we take the stack pointer;
sadly this ripples through several layers of the back tracing stack,
but it's not all that bad in the end I hope.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/process_32.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/stacktrace.c | 7 | ||||
-rw-r--r-- | arch/x86/kernel/traps_32.c | 39 | ||||
-rw-r--r-- | arch/x86/oprofile/backtrace.c | 2 |
4 files changed, 23 insertions, 27 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 35a6f318c541..7a61b54649de 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -379,7 +379,7 @@ void __show_registers(struct pt_regs *regs, int all) | |||
379 | void show_regs(struct pt_regs *regs) | 379 | void show_regs(struct pt_regs *regs) |
380 | { | 380 | { |
381 | __show_registers(regs, 1); | 381 | __show_registers(regs, 1); |
382 | show_trace(NULL, regs, ®s->sp); | 382 | show_trace(NULL, regs, ®s->sp, regs->bp); |
383 | } | 383 | } |
384 | 384 | ||
385 | /* | 385 | /* |
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index 8c4e4f5bf040..4f4021b5bfb5 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c | |||
@@ -33,7 +33,8 @@ static void save_stack_address(void *data, unsigned long addr, int reliable) | |||
33 | trace->entries[trace->nr_entries++] = addr; | 33 | trace->entries[trace->nr_entries++] = addr; |
34 | } | 34 | } |
35 | 35 | ||
36 | static void save_stack_address_nosched(void *data, unsigned long addr) | 36 | static void |
37 | save_stack_address_nosched(void *data, unsigned long addr, int reliable) | ||
37 | { | 38 | { |
38 | struct stack_trace *trace = (struct stack_trace *)data; | 39 | struct stack_trace *trace = (struct stack_trace *)data; |
39 | if (in_sched_functions(addr)) | 40 | if (in_sched_functions(addr)) |
@@ -65,14 +66,14 @@ static const struct stacktrace_ops save_stack_ops_nosched = { | |||
65 | */ | 66 | */ |
66 | void save_stack_trace(struct stack_trace *trace) | 67 | void save_stack_trace(struct stack_trace *trace) |
67 | { | 68 | { |
68 | dump_trace(current, NULL, NULL, &save_stack_ops, trace); | 69 | dump_trace(current, NULL, NULL, 0, &save_stack_ops, trace); |
69 | if (trace->nr_entries < trace->max_entries) | 70 | if (trace->nr_entries < trace->max_entries) |
70 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 71 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
71 | } | 72 | } |
72 | 73 | ||
73 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 74 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
74 | { | 75 | { |
75 | dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace); | 76 | dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace); |
76 | if (trace->nr_entries < trace->max_entries) | 77 | if (trace->nr_entries < trace->max_entries) |
77 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 78 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
78 | } | 79 | } |
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 959d40edecd5..6f3bb287c702 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
@@ -120,15 +120,6 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, | |||
120 | { | 120 | { |
121 | struct stack_frame *frame = (struct stack_frame *)bp; | 121 | struct stack_frame *frame = (struct stack_frame *)bp; |
122 | 122 | ||
123 | /* | ||
124 | * if EBP is "deeper" into the stack than the actual stack pointer, | ||
125 | * we need to rewind the stack pointer a little to start at the | ||
126 | * first stack frame, but only if EBP is in this stack frame. | ||
127 | */ | ||
128 | if (stack > (unsigned long *) bp | ||
129 | && valid_stack_ptr(tinfo, frame, sizeof(*frame))) | ||
130 | stack = (unsigned long *) bp; | ||
131 | |||
132 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) { | 123 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) { |
133 | unsigned long addr; | 124 | unsigned long addr; |
134 | 125 | ||
@@ -139,7 +130,7 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, | |||
139 | frame = frame->next_frame; | 130 | frame = frame->next_frame; |
140 | bp = (unsigned long) frame; | 131 | bp = (unsigned long) frame; |
141 | } else { | 132 | } else { |
142 | ops->address(data, addr, 0); | 133 | ops->address(data, addr, bp == 0); |
143 | } | 134 | } |
144 | } | 135 | } |
145 | stack++; | 136 | stack++; |
@@ -150,11 +141,9 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, | |||
150 | #define MSG(msg) ops->warning(data, msg) | 141 | #define MSG(msg) ops->warning(data, msg) |
151 | 142 | ||
152 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | 143 | void dump_trace(struct task_struct *task, struct pt_regs *regs, |
153 | unsigned long *stack, | 144 | unsigned long *stack, unsigned long bp, |
154 | const struct stacktrace_ops *ops, void *data) | 145 | const struct stacktrace_ops *ops, void *data) |
155 | { | 146 | { |
156 | unsigned long bp = 0; | ||
157 | |||
158 | if (!task) | 147 | if (!task) |
159 | task = current; | 148 | task = current; |
160 | 149 | ||
@@ -234,20 +223,20 @@ static const struct stacktrace_ops print_trace_ops = { | |||
234 | 223 | ||
235 | static void | 224 | static void |
236 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 225 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
237 | unsigned long * stack, char *log_lvl) | 226 | unsigned long *stack, unsigned long bp, char *log_lvl) |
238 | { | 227 | { |
239 | dump_trace(task, regs, stack, &print_trace_ops, log_lvl); | 228 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); |
240 | printk("%s =======================\n", log_lvl); | 229 | printk("%s =======================\n", log_lvl); |
241 | } | 230 | } |
242 | 231 | ||
243 | void show_trace(struct task_struct *task, struct pt_regs *regs, | 232 | void show_trace(struct task_struct *task, struct pt_regs *regs, |
244 | unsigned long * stack) | 233 | unsigned long *stack, unsigned long bp) |
245 | { | 234 | { |
246 | show_trace_log_lvl(task, regs, stack, ""); | 235 | show_trace_log_lvl(task, regs, stack, bp, ""); |
247 | } | 236 | } |
248 | 237 | ||
249 | static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 238 | static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
250 | unsigned long *sp, char *log_lvl) | 239 | unsigned long *sp, unsigned long bp, char *log_lvl) |
251 | { | 240 | { |
252 | unsigned long *stack; | 241 | unsigned long *stack; |
253 | int i; | 242 | int i; |
@@ -268,13 +257,13 @@ static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
268 | printk("%08lx ", *stack++); | 257 | printk("%08lx ", *stack++); |
269 | } | 258 | } |
270 | printk("\n%sCall Trace:\n", log_lvl); | 259 | printk("\n%sCall Trace:\n", log_lvl); |
271 | show_trace_log_lvl(task, regs, sp, log_lvl); | 260 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); |
272 | } | 261 | } |
273 | 262 | ||
274 | void show_stack(struct task_struct *task, unsigned long *sp) | 263 | void show_stack(struct task_struct *task, unsigned long *sp) |
275 | { | 264 | { |
276 | printk(" "); | 265 | printk(" "); |
277 | show_stack_log_lvl(task, NULL, sp, ""); | 266 | show_stack_log_lvl(task, NULL, sp, 0, ""); |
278 | } | 267 | } |
279 | 268 | ||
280 | /* | 269 | /* |
@@ -283,13 +272,19 @@ void show_stack(struct task_struct *task, unsigned long *sp) | |||
283 | void dump_stack(void) | 272 | void dump_stack(void) |
284 | { | 273 | { |
285 | unsigned long stack; | 274 | unsigned long stack; |
275 | unsigned long bp = 0; | ||
276 | |||
277 | #ifdef CONFIG_FRAME_POINTER | ||
278 | if (!bp) | ||
279 | asm("movl %%ebp, %0" : "=r" (bp):); | ||
280 | #endif | ||
286 | 281 | ||
287 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | 282 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", |
288 | current->pid, current->comm, print_tainted(), | 283 | current->pid, current->comm, print_tainted(), |
289 | init_utsname()->release, | 284 | init_utsname()->release, |
290 | (int)strcspn(init_utsname()->version, " "), | 285 | (int)strcspn(init_utsname()->version, " "), |
291 | init_utsname()->version); | 286 | init_utsname()->version); |
292 | show_trace(current, NULL, &stack); | 287 | show_trace(current, NULL, &stack, bp); |
293 | } | 288 | } |
294 | 289 | ||
295 | EXPORT_SYMBOL(dump_stack); | 290 | EXPORT_SYMBOL(dump_stack); |
@@ -314,7 +309,7 @@ void show_registers(struct pt_regs *regs) | |||
314 | unsigned char c; | 309 | unsigned char c; |
315 | 310 | ||
316 | printk("\n" KERN_EMERG "Stack: "); | 311 | printk("\n" KERN_EMERG "Stack: "); |
317 | show_stack_log_lvl(NULL, regs, ®s->sp, KERN_EMERG); | 312 | show_stack_log_lvl(NULL, regs, ®s->sp, 0, KERN_EMERG); |
318 | 313 | ||
319 | printk(KERN_EMERG "Code: "); | 314 | printk(KERN_EMERG "Code: "); |
320 | 315 | ||
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c index 671a7ecf11aa..0ca4815a2938 100644 --- a/arch/x86/oprofile/backtrace.c +++ b/arch/x86/oprofile/backtrace.c | |||
@@ -81,7 +81,7 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth) | |||
81 | 81 | ||
82 | if (!user_mode_vm(regs)) { | 82 | if (!user_mode_vm(regs)) { |
83 | if (depth) | 83 | if (depth) |
84 | dump_trace(NULL, regs, (unsigned long *)stack, | 84 | dump_trace(NULL, regs, (unsigned long *)stack, 0, |
85 | &backtrace_ops, &depth); | 85 | &backtrace_ops, &depth); |
86 | return; | 86 | return; |
87 | } | 87 | } |