Index: kernel/arch/i386/kernel/traps.c =================================================================== --- kernel.orig/arch/i386/kernel/traps.c 2006-05-26 16:12:28.000000000 -0700 +++ kernel/arch/i386/kernel/traps.c 2006-05-26 16:15:54.000000000 -0700 @@ -133,6 +133,30 @@ #endif +void scan_stack (unsigned long *stack) +{ + int i; + unsigned long addr; + /* static to not take up stackspace */ + static char buffer[NR_CPUS][512], *bufp; + + bufp = buffer[smp_processor_id()]; + + /* + * If we have frame pointers then use them to get + * a 100% exact backtrace, up until the entry frame: + */ + i = 1; + while (((long) stack & (THREAD_SIZE-1)) != 0) { + addr = *stack++; + if (kernel_text_address(addr)) { + lookup_symbol(addr, bufp, 512); + printk("[<%08lx>] %s (0x%p)\n", addr,bufp,stack-1); + i++; + } + } +} + #if CONFIG_FRAME_POINTER void show_stack_frame_params (int param_count, unsigned long params[]) { @@ -160,27 +184,23 @@ printk("0x%x)\n", *p); } -void frame_pointer_walk(unsigned long *stack) +/* Display a stack trace for the currently executing task. The 'dummy' + * parameter serves a purpose although its value is unused. We use the + * address of 'dummy' as a reference point for finding the saved %ebp register + * value on the stack. + */ +void frame_pointer_walk (void *dummy) { int i; unsigned long addr, task_addr, *frame_ptr, *next_frame_ptr, *eip_ptr, eip, stack_base; - /* static to not take up stackspace; if we race here too bad */ - static char buffer[512]; + /* static to not take up stackspace */ + static char buffer[NR_CPUS][512], *bufp; - addr = (unsigned long) stack; + bufp = buffer[smp_processor_id()]; task_addr = (unsigned long) current; stack_base = task_addr + THREAD_SIZE - 1; - - /* Simply return if we are doing a stack trace for any task other - * than the currently executing task. To trace another task, we - * would need an %ebp register value for that task. - */ - if (((addr < task_addr) || (addr > stack_base))) { - return; - } - - frame_ptr = (unsigned long *) (&stack - 2); + frame_ptr = (unsigned long *) (&dummy - 2); for (; ; ) { next_frame_ptr = (unsigned long *) (*frame_ptr); @@ -196,9 +216,9 @@ eip = *eip_ptr; if (kernel_text_address(eip)) { - lookup_symbol(eip, buffer, 512); + lookup_symbol(eip, bufp, 512); show_stack_frame_params(4, frame_ptr + 2); - printk("[<%08lx>] %s (0x%x)\n", eip, buffer, + printk("[<%08lx>] %s (0x%x)\n", eip, bufp, eip_ptr); } @@ -207,40 +227,49 @@ } #endif +typedef void (*stack_trace_fn_t) (unsigned long *stack); + +#if CONFIG_FRAME_POINTER void show_trace(unsigned long * stack) { -#if !CONFIG_FRAME_POINTER - int i; -#endif - unsigned long addr, limit; - /* static to not take up stackspace; if we race here too bad */ - static char buffer[512]; + static const stack_trace_fn_t trace_fn_vector[] = + { scan_stack, frame_pointer_walk }; + unsigned long addr, task_addr, stack_base; + int task_is_current; if (!stack) stack = (unsigned long*)&stack; printk("Call Trace: "); - /* - * If we have frame pointers then use them to get - * a 100% exact backtrace, up until the entry frame: - */ -#if CONFIG_FRAME_POINTER - frame_pointer_walk(stack); -#else - i = 1; - limit = ((unsigned long)stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE - 3; - while ((unsigned long)stack < limit) { - addr = *stack++; - if (kernel_text_address(addr)) { - lookup_symbol(addr, buffer, 512); - printk("[<%08lx>] %s (0x%x)\n", addr,buffer,stack-1); - i++; - } - } -#endif + addr = (unsigned long) stack; + task_addr = (unsigned long) current; + stack_base = task_addr + THREAD_SIZE - 1; + task_is_current = (addr >= task_addr) && (addr <= stack_base); + + /* We may use frame pointers to do a stack trace only if the current + * task is being traced. Tracing some other task in this manner + * would require a saved %ebp register value. Perhaps in the future + * I'll consider providing a means of obtaining this. + */ + trace_fn_vector[task_is_current](stack); + + printk("\n"); +} + +#else /* CONFIG_FRAME_POINTER */ + +void show_trace(unsigned long * stack) +{ + if (!stack) + stack = (unsigned long*)&stack; + + printk("Call Trace:\n"); + scan_stack(stack); printk("\n"); } +#endif /* CONFIG_FRAME_POINTER */ + void show_trace_task(struct task_struct *tsk) { unsigned long esp = tsk->thread.esp; Index: kernel/include/asm-i386/hw_irq.h =================================================================== --- kernel.orig/include/asm-i386/hw_irq.h 2006-05-26 16:11:33.000000000 -0700 +++ kernel/include/asm-i386/hw_irq.h 2006-05-26 16:13:51.000000000 -0700 @@ -153,6 +153,9 @@ /* there is a second layer of macro just to get the symbolic name for the vector evaluated. This change is for RTLinux */ #define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v) + +#if CONFIG_X86_HIGH_ENTRY + #define XBUILD_SMP_INTERRUPT(x,v)\ asmlinkage void x(void); \ asmlinkage void call_##x(void); \ @@ -165,7 +168,26 @@ "movl $"SYMBOL_NAME_STR(smp_##x)", %ebp; call *%ebp\n\t" \ "jmp ret_from_intr; .previous\n"); +#else + +#define XBUILD_SMP_INTERRUPT(x,v)\ +asmlinkage void x(void); \ +asmlinkage void call_##x(void); \ +__asm__( \ +".section .entry.text,\"ax\"\n"__ALIGN_STR"\n" \ +SYMBOL_NAME_STR(x) ":\n\t" \ + "pushl $"#v"-256\n\t" \ + SAVE_ALL_SWITCH \ + SYMBOL_NAME_STR(call_##x)":\n\t" \ + "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ + "jmp ret_from_intr; .previous\n"); + +#endif + #define BUILD_SMP_TIMER_INTERRUPT(x,v) XBUILD_SMP_TIMER_INTERRUPT(x,v) + +#if CONFIG_X86_HIGH_ENTRY + #define XBUILD_SMP_TIMER_INTERRUPT(x,v) \ asmlinkage void x(struct pt_regs * regs); \ asmlinkage void call_##x(void); \ @@ -181,6 +203,27 @@ "addl $4,%esp\n\t" \ "jmp ret_from_intr; .previous\n"); +#else + +#define XBUILD_SMP_TIMER_INTERRUPT(x,v) \ +asmlinkage void x(struct pt_regs * regs); \ +asmlinkage void call_##x(void); \ +__asm__( \ +".section .entry.text,\"ax\"\n"__ALIGN_STR"\n" \ +SYMBOL_NAME_STR(x) ":\n\t" \ + "pushl $"#v"-256\n\t" \ + SAVE_ALL_SWITCH \ + "movl %esp,%eax\n\t" \ + "pushl %eax\n\t" \ + SYMBOL_NAME_STR(call_##x)":\n\t" \ + "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ + "addl $4,%esp\n\t" \ + "jmp ret_from_intr; .previous\n"); + +#endif + +#if CONFIG_X86_HIGH_ENTRY + #define BUILD_COMMON_IRQ() \ asmlinkage void call_do_IRQ(void); \ __asm__( \ @@ -191,6 +234,20 @@ "movl $"SYMBOL_NAME_STR(do_IRQ)", %ebp; call *%ebp\n\t" \ "jmp ret_from_intr; .previous\n"); +#else + +#define BUILD_COMMON_IRQ() \ +asmlinkage void call_do_IRQ(void); \ +__asm__( \ + ".section .entry.text,\"ax\"\n" __ALIGN_STR"\n" \ + "common_interrupt:\n\t" \ + SAVE_ALL_SWITCH \ + SYMBOL_NAME_STR(call_do_IRQ)":\n\t" \ + "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ + "jmp ret_from_intr; .previous\n"); + +#endif + /* * subtle. orig_eax is used by the signal code to distinct between * system calls and interrupted 'random user-space'. Thus we have