aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2008-01-30 07:33:07 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:33:07 -0500
commitbc850d6b374fffd08336996f4b4d3bbd6bf427f6 (patch)
tree1106f4a1718f5ed09625f75c95a8bc06635231de
parent3d1f7cae883ce4aac99c661562111a25d52effe0 (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.c2
-rw-r--r--arch/x86/kernel/process_64.c4
-rw-r--r--arch/x86/kernel/stacktrace.c2
-rw-r--r--arch/x86/kernel/traps_32.c8
-rw-r--r--arch/x86/kernel/traps_64.c39
-rw-r--r--arch/x86/mm/fault_64.c2
-rw-r--r--arch/x86/oprofile/backtrace.c2
-rw-r--r--include/asm-x86/kdebug.h5
-rw-r--r--include/asm-x86/stacktrace.h5
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
25static void save_stack_address(void *data, unsigned long addr) 25static 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 */
223static void print_trace_address(void *data, unsigned long addr) 223static 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)
99int kstack_depth_to_print = 12; 99int kstack_depth_to_print = 12;
100 100
101#ifdef CONFIG_KALLSYMS 101#ifdef CONFIG_KALLSYMS
102void printk_address(unsigned long address) 102void 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
122void printk_address(unsigned long address) 126void 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
217void dump_trace(struct task_struct *tsk, struct pt_regs *regs, 221void 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
334static void print_trace_address(void *data, unsigned long addr) 338static 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
340static const struct stacktrace_ops print_trace_ops = { 344static const struct stacktrace_ops print_trace_ops = {
@@ -345,15 +349,17 @@ static const struct stacktrace_ops print_trace_ops = {
345}; 349};
346 350
347void 351void
348show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack) 352show_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
355static void 360static 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
393void show_stack(struct task_struct *tsk, unsigned long * sp) 399void 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)
401void dump_stack(void) 407void 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
413EXPORT_SYMBOL(dump_stack); 420EXPORT_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
35static void backtrace_address(void *data, unsigned long addr) 35static 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
25extern void printk_address(unsigned long address); 25extern void printk_address(unsigned long address, int reliable);
26extern void die(const char *,struct pt_regs *,long); 26extern void die(const char *,struct pt_regs *,long);
27extern int __must_check __die(const char *, struct pt_regs *, long); 27extern int __must_check __die(const char *, struct pt_regs *, long);
28extern void show_registers(struct pt_regs *regs); 28extern void show_registers(struct pt_regs *regs);
29extern void __show_registers(struct pt_regs *, int all); 29extern void __show_registers(struct pt_regs *, int all);
30extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long *); 30extern void show_trace(struct task_struct *t, struct pt_regs *regs,
31 unsigned long *sp, unsigned long bp);
31extern void __show_regs(struct pt_regs *regs); 32extern void __show_regs(struct pt_regs *regs);
32extern void show_regs(struct pt_regs *regs); 33extern void show_regs(struct pt_regs *regs);
33extern void dump_pagetable(unsigned long); 34extern 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
17void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack, 17void 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