Index: mm/arch/i386/kernel/traps.c =================================================================== --- mm.orig/arch/i386/kernel/traps.c 2005-09-03 11:22:39.000000000 +0200 +++ mm/arch/i386/kernel/traps.c 2005-09-03 18:17:00.000000000 +0200 @@ -148,6 +148,48 @@ p < (void *)tinfo + THREAD_SIZE - 3; } +unsigned long *next_stack_func(unsigned long *prev_addr, int count) +{ + struct thread_info *tinfo = current_thread_info(); + + if (!prev_addr) + return NULL; + +#ifdef CONFIG_FRAME_POINTER + /* In this case 'prev_addr' is a pointer to the last return + * function found on the stack */ + if (count == 0) { + unsigned long ebp; + unsigned long *func_ptr; + + asm ("movl %%ebp, %0" : "=r" (ebp) : ); + /* We don't want the obvious caller to show up */ + ebp = *(unsigned long *) ebp; + func_ptr = (unsigned long *)(ebp + 4); + if (valid_stack_ptr(tinfo, func_ptr)) + return func_ptr; + } else { + unsigned long *func_ptr; + unsigned long ebp = (unsigned long) prev_addr; + + ebp -= 4; + + ebp = *(unsigned long *) ebp; + func_ptr = (unsigned long *) ((unsigned long)ebp + 4); + if (valid_stack_ptr(tinfo, func_ptr)) + return func_ptr; + } +#else + while (prev_addr++) { + if (!valid_stack_ptr(tinfo, prev_addr)) + break; + if (__kernel_text_address(*prev_addr)) + return prev_addr; + } +#endif + return NULL; +} + static inline unsigned long print_context_stack(struct thread_info *tinfo, unsigned long *stack, unsigned long ebp) { Index: mm/include/linux/sched.h =================================================================== --- mm.orig/include/linux/sched.h 2005-09-03 11:22:51.000000000 +0200 +++ mm/include/linux/sched.h 2005-09-03 15:52:20.000000000 +0200 @@ -171,6 +171,7 @@ * trace (or NULL if the entire call-chain of the task should be shown). */ extern void show_stack(struct task_struct *task, unsigned long *sp); +extern unsigned long *next_stack_func(unsigned long *prev_addr, int count); void io_schedule(void); long io_schedule_timeout(long timeout); Index: mm/arch/x86_64/kernel/traps.c =================================================================== --- mm.orig/arch/x86_64/kernel/traps.c 2005-09-03 17:59:16.000000000 +0200 +++ mm/arch/x86_64/kernel/traps.c 2005-09-03 19:00:48.000000000 +0200 @@ -154,6 +154,54 @@ return NULL; } +static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) +{ + return p > (void *)tinfo && + p < (void *)tinfo + THREAD_SIZE - 3; +} + +unsigned long *next_stack_func(unsigned long *prev_addr, int count) +{ + struct thread_info *tinfo = current_thread_info(); + + if (!prev_addr) + return NULL; + +#ifdef CONFIG_FRAME_POINTER + /* In this case 'prev_addr' is a pointer to the last return + * function found on the stack */ + if (count == 0) { + unsigned long rbp; + unsigned long *func_ptr; + + asm ("movq %%rbp, %0" : "=r" (rbp) : ); + /* We don't want the obvious caller to show up */ + rbp = *(unsigned long *) rbp; + func_ptr = (unsigned long *)(rbp + 8); + if (valid_stack_ptr(tinfo, func_ptr)) + return func_ptr; + } else { + unsigned long *func_ptr; + unsigned long rbp = (unsigned long) prev_addr; + + rbp -= 8; + + rbp = *(unsigned long *) rbp; + func_ptr = (unsigned long *) ((unsigned long)rbp + 8); + if (valid_stack_ptr(tinfo, func_ptr)) + return func_ptr; + } +#else + while (prev_addr++) { + if (!valid_stack_ptr(tinfo, prev_addr)) + break; + if (__kernel_text_address(*prev_addr)) + return prev_addr; + } +#endif + return NULL; +} + /* * x86-64 can have upto three kernel stacks: * process stack