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 | bc850d6b374fffd08336996f4b4d3bbd6bf427f6 (patch) | |
tree | 1106f4a1718f5ed09625f75c95a8bc06635231de | |
parent | 3d1f7cae883ce4aac99c661562111a25d52effe0 (diff) |
x86: add the capability to print fuzzy backtraces
For enhancing the 32 bit EBP based backtracer, I need the capability
for the backtracer to tell it's customer that an entry is either
reliable or unreliable, and the backtrace printing code then needs to
print the unreliable ones slightly different.
This patch adds the basic capability, the next patch will add a user
of this capability.
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>
-rw-r--r-- | arch/x86/kernel/pci-gart_64.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/stacktrace.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/traps_32.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/traps_64.c | 39 | ||||
-rw-r--r-- | arch/x86/mm/fault_64.c | 2 | ||||
-rw-r--r-- | arch/x86/oprofile/backtrace.c | 2 | ||||
-rw-r--r-- | include/asm-x86/kdebug.h | 5 | ||||
-rw-r--r-- | include/asm-x86/stacktrace.h | 5 |
9 files changed, 40 insertions, 29 deletions
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index d2b46b489412..04ca5c5221d7 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c | |||
@@ -167,7 +167,7 @@ static void dump_leak(void) | |||
167 | iommu_leak_pages); | 167 | iommu_leak_pages); |
168 | for (i = 0; i < iommu_leak_pages; i += 2) { | 168 | for (i = 0; i < iommu_leak_pages; i += 2) { |
169 | printk(KERN_DEBUG "%lu: ", iommu_pages-i); | 169 | printk(KERN_DEBUG "%lu: ", iommu_pages-i); |
170 | printk_address((unsigned long) iommu_leak_tab[iommu_pages-i]); | 170 | printk_address((unsigned long) iommu_leak_tab[iommu_pages-i], 0); |
171 | printk(KERN_CONT "%c", (i+1)%2 == 0 ? '\n' : ' '); | 171 | printk(KERN_CONT "%c", (i+1)%2 == 0 ? '\n' : ' '); |
172 | } | 172 | } |
173 | printk(KERN_DEBUG "\n"); | 173 | printk(KERN_DEBUG "\n"); |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index a0130eb2fa50..383760bfd283 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -329,7 +329,7 @@ void __show_regs(struct pt_regs * regs) | |||
329 | (int)strcspn(init_utsname()->version, " "), | 329 | (int)strcspn(init_utsname()->version, " "), |
330 | init_utsname()->version); | 330 | init_utsname()->version); |
331 | printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->ip); | 331 | printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->ip); |
332 | printk_address(regs->ip); | 332 | printk_address(regs->ip, regs->bp); |
333 | printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->sp, | 333 | printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->sp, |
334 | regs->flags); | 334 | regs->flags); |
335 | printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", | 335 | printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", |
@@ -377,7 +377,7 @@ void show_regs(struct pt_regs *regs) | |||
377 | { | 377 | { |
378 | printk("CPU %d:", smp_processor_id()); | 378 | printk("CPU %d:", smp_processor_id()); |
379 | __show_regs(regs); | 379 | __show_regs(regs); |
380 | show_trace(NULL, regs, (void *)(regs + 1)); | 380 | show_trace(NULL, regs, (void *)(regs + 1), regs->bp); |
381 | } | 381 | } |
382 | 382 | ||
383 | /* | 383 | /* |
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index c571edd11878..8c4e4f5bf040 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c | |||
@@ -22,7 +22,7 @@ static int save_stack_stack(void *data, char *name) | |||
22 | return -1; | 22 | return -1; |
23 | } | 23 | } |
24 | 24 | ||
25 | static void save_stack_address(void *data, unsigned long addr) | 25 | static void save_stack_address(void *data, unsigned long addr, int reliable) |
26 | { | 26 | { |
27 | struct stack_trace *trace = (struct stack_trace *)data; | 27 | struct stack_trace *trace = (struct stack_trace *)data; |
28 | if (trace->skip > 0) { | 28 | if (trace->skip > 0) { |
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index acc9af260fac..8ef8a9ddfec6 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
@@ -126,7 +126,7 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, | |||
126 | 126 | ||
127 | addr = frame->return_address; | 127 | addr = frame->return_address; |
128 | if (__kernel_text_address(addr)) | 128 | if (__kernel_text_address(addr)) |
129 | ops->address(data, addr); | 129 | ops->address(data, addr, 1); |
130 | /* | 130 | /* |
131 | * break out of recursive entries (such as | 131 | * break out of recursive entries (such as |
132 | * end_of_stack_stop_unwind_function). Also, | 132 | * end_of_stack_stop_unwind_function). Also, |
@@ -145,7 +145,7 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, | |||
145 | 145 | ||
146 | addr = *stack++; | 146 | addr = *stack++; |
147 | if (__kernel_text_address(addr)) | 147 | if (__kernel_text_address(addr)) |
148 | ops->address(data, addr); | 148 | ops->address(data, addr, 1); |
149 | } | 149 | } |
150 | #endif | 150 | #endif |
151 | return bp; | 151 | return bp; |
@@ -220,9 +220,11 @@ static int print_trace_stack(void *data, char *name) | |||
220 | /* | 220 | /* |
221 | * Print one address/symbol entries per line. | 221 | * Print one address/symbol entries per line. |
222 | */ | 222 | */ |
223 | static void print_trace_address(void *data, unsigned long addr) | 223 | static void print_trace_address(void *data, unsigned long addr, int reliable) |
224 | { | 224 | { |
225 | printk("%s [<%08lx>] ", (char *)data, addr); | 225 | printk("%s [<%08lx>] ", (char *)data, addr); |
226 | if (!reliable) | ||
227 | printk("? "); | ||
226 | print_symbol("%s\n", addr); | 228 | print_symbol("%s\n", addr); |
227 | touch_nmi_watchdog(); | 229 | touch_nmi_watchdog(); |
228 | } | 230 | } |
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 37b07d08704b..62c4d8f46ee9 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c | |||
@@ -99,13 +99,14 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) | |||
99 | int kstack_depth_to_print = 12; | 99 | int kstack_depth_to_print = 12; |
100 | 100 | ||
101 | #ifdef CONFIG_KALLSYMS | 101 | #ifdef CONFIG_KALLSYMS |
102 | void printk_address(unsigned long address) | 102 | void printk_address(unsigned long address, int reliable) |
103 | { | 103 | { |
104 | unsigned long offset = 0, symsize; | 104 | unsigned long offset = 0, symsize; |
105 | const char *symname; | 105 | const char *symname; |
106 | char *modname; | 106 | char *modname; |
107 | char *delim = ":"; | 107 | char *delim = ":"; |
108 | char namebuf[128]; | 108 | char namebuf[128]; |
109 | char reliab[4] = "";; | ||
109 | 110 | ||
110 | symname = kallsyms_lookup(address, &symsize, &offset, | 111 | symname = kallsyms_lookup(address, &symsize, &offset, |
111 | &modname, namebuf); | 112 | &modname, namebuf); |
@@ -113,13 +114,16 @@ void printk_address(unsigned long address) | |||
113 | printk(" [<%016lx>]\n", address); | 114 | printk(" [<%016lx>]\n", address); |
114 | return; | 115 | return; |
115 | } | 116 | } |
117 | if (!reliable) | ||
118 | strcpy(reliab, "? "); | ||
119 | |||
116 | if (!modname) | 120 | if (!modname) |
117 | modname = delim = ""; | 121 | modname = delim = ""; |
118 | printk(" [<%016lx>] %s%s%s%s+0x%lx/0x%lx\n", | 122 | printk(" [<%016lx>] %s%s%s%s%s+0x%lx/0x%lx\n", |
119 | address, delim, modname, delim, symname, offset, symsize); | 123 | address, reliab, delim, modname, delim, symname, offset, symsize); |
120 | } | 124 | } |
121 | #else | 125 | #else |
122 | void printk_address(unsigned long address) | 126 | void printk_address(unsigned long address, int reliable) |
123 | { | 127 | { |
124 | printk(" [<%016lx>]\n", address); | 128 | printk(" [<%016lx>]\n", address); |
125 | } | 129 | } |
@@ -215,7 +219,7 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) | |||
215 | } | 219 | } |
216 | 220 | ||
217 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, | 221 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, |
218 | unsigned long *stack, | 222 | unsigned long *stack, unsigned long bp, |
219 | const struct stacktrace_ops *ops, void *data) | 223 | const struct stacktrace_ops *ops, void *data) |
220 | { | 224 | { |
221 | const unsigned cpu = get_cpu(); | 225 | const unsigned cpu = get_cpu(); |
@@ -252,7 +256,7 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, | |||
252 | * down the cause of the crash will be able to figure \ | 256 | * down the cause of the crash will be able to figure \ |
253 | * out the call path that was taken. \ | 257 | * out the call path that was taken. \ |
254 | */ \ | 258 | */ \ |
255 | ops->address(data, addr); \ | 259 | ops->address(data, addr, 1); \ |
256 | } \ | 260 | } \ |
257 | } while (0) | 261 | } while (0) |
258 | 262 | ||
@@ -331,10 +335,10 @@ static int print_trace_stack(void *data, char *name) | |||
331 | return 0; | 335 | return 0; |
332 | } | 336 | } |
333 | 337 | ||
334 | static void print_trace_address(void *data, unsigned long addr) | 338 | static void print_trace_address(void *data, unsigned long addr, int reliable) |
335 | { | 339 | { |
336 | touch_nmi_watchdog(); | 340 | touch_nmi_watchdog(); |
337 | printk_address(addr); | 341 | printk_address(addr, reliable); |
338 | } | 342 | } |
339 | 343 | ||
340 | static const struct stacktrace_ops print_trace_ops = { | 344 | static const struct stacktrace_ops print_trace_ops = { |
@@ -345,15 +349,17 @@ static const struct stacktrace_ops print_trace_ops = { | |||
345 | }; | 349 | }; |
346 | 350 | ||
347 | void | 351 | void |
348 | show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack) | 352 | show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack, |
353 | unsigned long bp) | ||
349 | { | 354 | { |
350 | printk("\nCall Trace:\n"); | 355 | printk("\nCall Trace:\n"); |
351 | dump_trace(tsk, regs, stack, &print_trace_ops, NULL); | 356 | dump_trace(tsk, regs, stack, bp, &print_trace_ops, NULL); |
352 | printk("\n"); | 357 | printk("\n"); |
353 | } | 358 | } |
354 | 359 | ||
355 | static void | 360 | static void |
356 | _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp) | 361 | _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp, |
362 | unsigned long bp) | ||
357 | { | 363 | { |
358 | unsigned long *stack; | 364 | unsigned long *stack; |
359 | int i; | 365 | int i; |
@@ -387,12 +393,12 @@ _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp) | |||
387 | printk(" %016lx", *stack++); | 393 | printk(" %016lx", *stack++); |
388 | touch_nmi_watchdog(); | 394 | touch_nmi_watchdog(); |
389 | } | 395 | } |
390 | show_trace(tsk, regs, sp); | 396 | show_trace(tsk, regs, sp, bp); |
391 | } | 397 | } |
392 | 398 | ||
393 | void show_stack(struct task_struct *tsk, unsigned long * sp) | 399 | void show_stack(struct task_struct *tsk, unsigned long * sp) |
394 | { | 400 | { |
395 | _show_stack(tsk, NULL, sp); | 401 | _show_stack(tsk, NULL, sp, 0); |
396 | } | 402 | } |
397 | 403 | ||
398 | /* | 404 | /* |
@@ -401,13 +407,14 @@ void show_stack(struct task_struct *tsk, unsigned long * sp) | |||
401 | void dump_stack(void) | 407 | void dump_stack(void) |
402 | { | 408 | { |
403 | unsigned long dummy; | 409 | unsigned long dummy; |
410 | unsigned long bp = 0; | ||
404 | 411 | ||
405 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | 412 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", |
406 | current->pid, current->comm, print_tainted(), | 413 | current->pid, current->comm, print_tainted(), |
407 | init_utsname()->release, | 414 | init_utsname()->release, |
408 | (int)strcspn(init_utsname()->version, " "), | 415 | (int)strcspn(init_utsname()->version, " "), |
409 | init_utsname()->version); | 416 | init_utsname()->version); |
410 | show_trace(NULL, NULL, &dummy); | 417 | show_trace(NULL, NULL, &dummy, bp); |
411 | } | 418 | } |
412 | 419 | ||
413 | EXPORT_SYMBOL(dump_stack); | 420 | EXPORT_SYMBOL(dump_stack); |
@@ -432,7 +439,7 @@ void show_registers(struct pt_regs *regs) | |||
432 | */ | 439 | */ |
433 | if (in_kernel) { | 440 | if (in_kernel) { |
434 | printk("Stack: "); | 441 | printk("Stack: "); |
435 | _show_stack(NULL, regs, (unsigned long*)sp); | 442 | _show_stack(NULL, regs, (unsigned long *)sp, regs->bp); |
436 | 443 | ||
437 | printk("\nCode: "); | 444 | printk("\nCode: "); |
438 | if (regs->ip < PAGE_OFFSET) | 445 | if (regs->ip < PAGE_OFFSET) |
@@ -527,7 +534,7 @@ int __kprobes __die(const char * str, struct pt_regs * regs, long err) | |||
527 | add_taint(TAINT_DIE); | 534 | add_taint(TAINT_DIE); |
528 | /* Executive summary in case the oops scrolled away */ | 535 | /* Executive summary in case the oops scrolled away */ |
529 | printk(KERN_ALERT "RIP "); | 536 | printk(KERN_ALERT "RIP "); |
530 | printk_address(regs->ip); | 537 | printk_address(regs->ip, regs->bp); |
531 | printk(" RSP <%016lx>\n", regs->sp); | 538 | printk(" RSP <%016lx>\n", regs->sp); |
532 | if (kexec_should_crash(current)) | 539 | if (kexec_should_crash(current)) |
533 | crash_kexec(regs); | 540 | crash_kexec(regs); |
diff --git a/arch/x86/mm/fault_64.c b/arch/x86/mm/fault_64.c index e82832961d72..cf7e99895b91 100644 --- a/arch/x86/mm/fault_64.c +++ b/arch/x86/mm/fault_64.c | |||
@@ -578,7 +578,7 @@ no_context: | |||
578 | else | 578 | else |
579 | printk(KERN_ALERT "Unable to handle kernel paging request"); | 579 | printk(KERN_ALERT "Unable to handle kernel paging request"); |
580 | printk(" at %016lx RIP: \n" KERN_ALERT, address); | 580 | printk(" at %016lx RIP: \n" KERN_ALERT, address); |
581 | printk_address(regs->ip); | 581 | printk_address(regs->ip, regs->bp); |
582 | dump_pagetable(address); | 582 | dump_pagetable(address); |
583 | tsk->thread.cr2 = address; | 583 | tsk->thread.cr2 = address; |
584 | tsk->thread.trap_no = 14; | 584 | tsk->thread.trap_no = 14; |
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c index cc353a0b183e..671a7ecf11aa 100644 --- a/arch/x86/oprofile/backtrace.c +++ b/arch/x86/oprofile/backtrace.c | |||
@@ -32,7 +32,7 @@ static int backtrace_stack(void *data, char *name) | |||
32 | return 0; | 32 | return 0; |
33 | } | 33 | } |
34 | 34 | ||
35 | static void backtrace_address(void *data, unsigned long addr) | 35 | static void backtrace_address(void *data, unsigned long addr, int reliable) |
36 | { | 36 | { |
37 | unsigned int *depth = data; | 37 | unsigned int *depth = data; |
38 | 38 | ||
diff --git a/include/asm-x86/kdebug.h b/include/asm-x86/kdebug.h index e9f42d1ac38f..dd442a1632c0 100644 --- a/include/asm-x86/kdebug.h +++ b/include/asm-x86/kdebug.h | |||
@@ -22,12 +22,13 @@ enum die_val { | |||
22 | DIE_PAGE_FAULT, | 22 | DIE_PAGE_FAULT, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | extern void printk_address(unsigned long address); | 25 | extern void printk_address(unsigned long address, int reliable); |
26 | extern void die(const char *,struct pt_regs *,long); | 26 | extern void die(const char *,struct pt_regs *,long); |
27 | extern int __must_check __die(const char *, struct pt_regs *, long); | 27 | extern int __must_check __die(const char *, struct pt_regs *, long); |
28 | extern void show_registers(struct pt_regs *regs); | 28 | extern void show_registers(struct pt_regs *regs); |
29 | extern void __show_registers(struct pt_regs *, int all); | 29 | extern void __show_registers(struct pt_regs *, int all); |
30 | extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long *); | 30 | extern void show_trace(struct task_struct *t, struct pt_regs *regs, |
31 | unsigned long *sp, unsigned long bp); | ||
31 | extern void __show_regs(struct pt_regs *regs); | 32 | extern void __show_regs(struct pt_regs *regs); |
32 | extern void show_regs(struct pt_regs *regs); | 33 | extern void show_regs(struct pt_regs *regs); |
33 | extern void dump_pagetable(unsigned long); | 34 | extern void dump_pagetable(unsigned long); |
diff --git a/include/asm-x86/stacktrace.h b/include/asm-x86/stacktrace.h index 70dd5bae3235..30f82526a8e2 100644 --- a/include/asm-x86/stacktrace.h +++ b/include/asm-x86/stacktrace.h | |||
@@ -9,12 +9,13 @@ struct stacktrace_ops { | |||
9 | void (*warning)(void *data, char *msg); | 9 | void (*warning)(void *data, char *msg); |
10 | /* msg must contain %s for the symbol */ | 10 | /* msg must contain %s for the symbol */ |
11 | void (*warning_symbol)(void *data, char *msg, unsigned long symbol); | 11 | void (*warning_symbol)(void *data, char *msg, unsigned long symbol); |
12 | void (*address)(void *data, unsigned long address); | 12 | void (*address)(void *data, unsigned long address, int reliable); |
13 | /* On negative return stop dumping */ | 13 | /* On negative return stop dumping */ |
14 | int (*stack)(void *data, char *name); | 14 | int (*stack)(void *data, char *name); |
15 | }; | 15 | }; |
16 | 16 | ||
17 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack, | 17 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, |
18 | unsigned long *stack, unsigned long bp, | ||
18 | const struct stacktrace_ops *ops, void *data); | 19 | const struct stacktrace_ops *ops, void *data); |
19 | 20 | ||
20 | #endif | 21 | #endif |