Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] uml: stack dump fix

Copy (and adapt) to UML the stack code dumper used in i386 when
CONFIG_FRAME_POINTER is enabled.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Paolo 'Blaisorblade' Giarrusso and committed by
Linus Torvalds
b3461034 37fce857

+100 -36
+2 -1
arch/um/include/sysrq.h
··· 1 1 #ifndef __UM_SYSRQ_H 2 2 #define __UM_SYSRQ_H 3 3 4 - extern void show_trace(unsigned long *stack); 4 + struct task_struct; 5 + extern void show_trace(struct task_struct* task, unsigned long *stack); 5 6 6 7 #endif
+14 -7
arch/um/kernel/sysrq.c
··· 3 3 * Licensed under the GPL 4 4 */ 5 5 6 + #include "linux/config.h" 6 7 #include "linux/sched.h" 7 8 #include "linux/kernel.h" 8 9 #include "linux/module.h" ··· 13 12 #include "sysrq.h" 14 13 #include "user_util.h" 15 14 16 - void show_trace(unsigned long * stack) 15 + /* Catch non-i386 SUBARCH's. */ 16 + #if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT) 17 + void show_trace(struct task_struct *task, unsigned long * stack) 17 18 { 18 - /* XXX: Copy the CONFIG_FRAME_POINTER stack-walking backtrace from 19 - * arch/i386/kernel/traps.c, and then move this to sys-i386/sysrq.c.*/ 20 19 unsigned long addr; 21 20 22 21 if (!stack) { 23 - stack = (unsigned long*) &stack; 22 + stack = (unsigned long*) &stack; 24 23 WARN_ON(1); 25 24 } 26 25 ··· 36 35 } 37 36 printk("\n"); 38 37 } 38 + #endif 39 39 40 40 /* 41 41 * stack dumps generator - this is used by arch-independent code. ··· 46 44 { 47 45 unsigned long stack; 48 46 49 - show_trace(&stack); 47 + show_trace(current, &stack); 50 48 } 51 49 EXPORT_SYMBOL(dump_stack); 52 50 ··· 61 59 int i; 62 60 63 61 if (esp == NULL) { 64 - if (task != current) { 62 + if (task != current && task != NULL) { 63 + /* XXX: Isn't this bogus? I.e. isn't this the 64 + * *userspace* stack of this task? If not so, use this 65 + * even when task == current (as in i386). 66 + */ 65 67 esp = (unsigned long *) KSTK_ESP(task); 66 68 /* Which one? No actual difference - just coding style.*/ 67 69 //esp = (unsigned long *) PT_REGS_IP(&task->thread.regs); ··· 83 77 printk("%08lx ", *stack++); 84 78 } 85 79 86 - show_trace(esp); 80 + printk("Call Trace: \n"); 81 + show_trace(current, esp); 87 82 }
+79 -1
arch/um/sys-i386/sysrq.c
··· 3 3 * Licensed under the GPL 4 4 */ 5 5 6 + #include "linux/config.h" 6 7 #include "linux/kernel.h" 7 8 #include "linux/smp.h" 8 9 #include "linux/sched.h" 10 + #include "linux/kallsyms.h" 9 11 #include "asm/ptrace.h" 10 12 #include "sysrq.h" 11 13 14 + /* This is declared by <linux/sched.h> */ 12 15 void show_regs(struct pt_regs *regs) 13 16 { 14 17 printk("\n"); ··· 34 31 0xffff & PT_REGS_DS(regs), 35 32 0xffff & PT_REGS_ES(regs)); 36 33 37 - show_trace((unsigned long *) &regs); 34 + show_trace(NULL, (unsigned long *) &regs); 38 35 } 36 + 37 + /* Copied from i386. */ 38 + static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) 39 + { 40 + return p > (void *)tinfo && 41 + p < (void *)tinfo + THREAD_SIZE - 3; 42 + } 43 + 44 + /* Adapted from i386 (we also print the address we read from). */ 45 + static inline unsigned long print_context_stack(struct thread_info *tinfo, 46 + unsigned long *stack, unsigned long ebp) 47 + { 48 + unsigned long addr; 49 + 50 + #ifdef CONFIG_FRAME_POINTER 51 + while (valid_stack_ptr(tinfo, (void *)ebp)) { 52 + addr = *(unsigned long *)(ebp + 4); 53 + printk("%08lx: [<%08lx>]", ebp + 4, addr); 54 + print_symbol(" %s", addr); 55 + printk("\n"); 56 + ebp = *(unsigned long *)ebp; 57 + } 58 + #else 59 + while (valid_stack_ptr(tinfo, stack)) { 60 + addr = *stack; 61 + if (__kernel_text_address(addr)) { 62 + printk("%08lx: [<%08lx>]", (unsigned long) stack, addr); 63 + print_symbol(" %s", addr); 64 + printk("\n"); 65 + } 66 + stack++; 67 + } 68 + #endif 69 + return ebp; 70 + } 71 + 72 + void show_trace(struct task_struct* task, unsigned long * stack) 73 + { 74 + unsigned long ebp; 75 + struct thread_info *context; 76 + 77 + /* Turn this into BUG_ON if possible. */ 78 + if (!stack) { 79 + stack = (unsigned long*) &stack; 80 + printk("show_trace: got NULL stack, implicit assumption task == current"); 81 + WARN_ON(1); 82 + } 83 + 84 + if (!task) 85 + task = current; 86 + 87 + if (task != current) { 88 + //ebp = (unsigned long) KSTK_EBP(task); 89 + /* Which one? No actual difference - just coding style.*/ 90 + ebp = (unsigned long) PT_REGS_EBP(&task->thread.regs); 91 + } else { 92 + asm ("movl %%ebp, %0" : "=r" (ebp) : ); 93 + } 94 + 95 + context = (struct thread_info *) 96 + ((unsigned long)stack & (~(THREAD_SIZE - 1))); 97 + print_context_stack(context, stack, ebp); 98 + 99 + /*while (((long) stack & (THREAD_SIZE-1)) != 0) { 100 + addr = *stack; 101 + if (__kernel_text_address(addr)) { 102 + printk("%08lx: [<%08lx>]", (unsigned long) stack, addr); 103 + print_symbol(" %s", addr); 104 + printk("\n"); 105 + } 106 + stack++; 107 + }*/ 108 + printk("\n"); 109 + } 110 +
+1 -13
arch/um/sys-ppc/sysrq.c
··· 27 27 0xffff & regs->xds, 0xffff & regs->xes); 28 28 #endif 29 29 30 - show_trace(&regs->gpr[1]); 30 + show_trace(current, &regs->gpr[1]); 31 31 } 32 - 33 - 34 - /* 35 - * Overrides for Emacs so that we follow Linus's tabbing style. 36 - * Emacs will notice this stuff at the end of the file and automatically 37 - * adjust the settings for this buffer only. This must remain at the end 38 - * of the file. 39 - * --------------------------------------------------------------------------- 40 - * Local variables: 41 - * c-file-style: "linux" 42 - * End: 43 - */
+1 -10
arch/um/sys-x86_64/sysrq.c
··· 36 36 void show_regs(struct pt_regs *regs) 37 37 { 38 38 __show_regs(regs); 39 - show_trace((unsigned long *) &regs); 39 + show_trace(current, (unsigned long *) &regs); 40 40 } 41 - 42 - /* Emacs will notice this stuff at the end of the file and automatically 43 - * adjust the settings for this buffer only. This must remain at the end 44 - * of the file. 45 - * --------------------------------------------------------------------------- 46 - * Local variables: 47 - * c-file-style: "linux" 48 - * End: 49 - */
+3 -4
include/asm-um/thread_info.h
··· 41 41 #define init_thread_info (init_thread_union.thread_info) 42 42 #define init_stack (init_thread_union.stack) 43 43 44 + #define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) 44 45 /* how to get the thread information struct from C */ 45 46 static inline struct thread_info *current_thread_info(void) 46 47 { 47 48 struct thread_info *ti; 48 - unsigned long mask = PAGE_SIZE * 49 - (1 << CONFIG_KERNEL_STACK_ORDER) - 1; 50 - ti = (struct thread_info *) (((unsigned long) &ti) & ~mask); 49 + unsigned long mask = THREAD_SIZE - 1; 50 + ti = (struct thread_info *) (((unsigned long) &ti) & ~mask); 51 51 return ti; 52 52 } 53 53 54 54 /* thread information allocation */ 55 - #define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) 56 55 #define alloc_thread_info(tsk) \ 57 56 ((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL)) 58 57 #define free_thread_info(ti) kfree(ti)