unsigned long get_wchan(struct task_struct *p) { unsigned long fp, lr; unsigned long stack_page; int count = 0; if (!p || p == current || p->state == TASK_RUNNING) return 0; stack_page = 4096 + (unsigned long)p; fp = thread_saved_fp(p); do { if (fp < stack_page || fp > 4092+stack_page) return 0; lr = pc_pointer (((unsigned long *)fp)[-1]); if (!in_sched_functions(lr)) return lr; fp = *(unsigned long *) (fp - 12); } while (count ++ < 16); return 0; }
static unsigned long get_wchan(struct task_struct *p) { if (!p || p == current || p->state == TASK_RUNNING) return 0; #if defined(__i386__) { unsigned long ebp, esp, eip; unsigned long stack_page; int count = 0; stack_page = (unsigned long)p; esp = p->tss.esp; if (!stack_page || esp < stack_page || esp >= 8188+stack_page) return 0; /* include/asm-i386/system.h:switch_to() pushes ebp last. */ ebp = *(unsigned long *) esp; do { if (ebp < stack_page || ebp >= 8188+stack_page) return 0; eip = *(unsigned long *) (ebp+4); if (eip < first_sched || eip >= last_sched) return eip; ebp = *(unsigned long *) ebp; } while (count++ < 16); } #elif defined(__alpha__) /* * This one depends on the frame size of schedule(). Do a * "disass schedule" in gdb to find the frame size. Also, the * code assumes that sleep_on() follows immediately after * interruptible_sleep_on() and that add_timer() follows * immediately after interruptible_sleep(). Ugly, isn't it? * Maybe adding a wchan field to task_struct would be better, * after all... */ { unsigned long schedule_frame; unsigned long pc; pc = thread_saved_pc(&p->tss); if (pc >= first_sched && pc < last_sched) { schedule_frame = ((unsigned long *)p->tss.ksp)[6]; return ((unsigned long *)schedule_frame)[12]; } return pc; } #elif defined(__mips__) /* * The same comment as on the Alpha applies here, too ... */ { unsigned long schedule_frame; unsigned long pc; pc = thread_saved_pc(&p->tss); if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) { schedule_frame = ((unsigned long *)(long)p->tss.reg30)[16]; return (unsigned long)((unsigned long *)schedule_frame)[11]; } return pc; } #elif defined(__mc68000__) { unsigned long fp, pc; unsigned long stack_page; int count = 0; stack_page = (unsigned long)p; fp = ((struct switch_stack *)p->tss.ksp)->a6; do { if (fp < stack_page+sizeof(struct task_struct) || fp >= 8184+stack_page) return 0; pc = ((unsigned long *)fp)[1]; /* FIXME: This depends on the order of these functions. */ if (pc < first_sched || pc >= last_sched) return pc; fp = *(unsigned long *) fp; } while (count++ < 16); } #elif defined(__powerpc__) { unsigned long ip, sp; unsigned long stack_page = (unsigned long) p; int count = 0; sp = p->tss.ksp; do { sp = *(unsigned long *)sp; if (sp < stack_page || sp >= stack_page + 8188) return 0; if (count > 0) { ip = *(unsigned long *)(sp + 4); if (ip < first_sched || ip >= last_sched) return ip; } } while (count++ < 16); } #elif defined(__arm__) { unsigned long fp, lr; unsigned long stack_page; int count = 0; stack_page = 4096 + (unsigned long)p; fp = get_css_fp (&p->tss); do { if (fp < stack_page || fp > 4092+stack_page) return 0; lr = pc_pointer (((unsigned long *)fp)[-1]); if (lr < first_sched || lr > last_sched) return lr; fp = *(unsigned long *) (fp - 12); } while (count ++ < 16); } #elif defined (__sparc__) { unsigned long pc, fp, bias = 0; unsigned long task_base = (unsigned long) p; struct reg_window *rw; int count = 0; #ifdef __sparc_v9__ bias = STACK_BIAS; #endif fp = p->tss.ksp + bias; do { /* Bogus frame pointer? */ if (fp < (task_base + sizeof(struct task_struct)) || fp >= (task_base + (2 * PAGE_SIZE))) break; rw = (struct reg_window *) fp; pc = rw->ins[7]; if (pc < first_sched || pc >= last_sched) return pc; fp = rw->ins[6] + bias; } while (++count < 16); } #elif defined (__s390__) { unsigned long ksp, backchain, ip; unsigned long stack_page; int count = 0; stack_page = (unsigned long)p; ksp = p->tss.ksp; if (!stack_page || ksp < stack_page || ksp >= 8188+stack_page) return 0; backchain = (*(unsigned long *) ksp) & 0x7fffffff; do { if (backchain < stack_page || backchain >= 8188+stack_page) return 0; ip = (*(unsigned long *) (backchain+56)) & 0x7fffffff; if (ip < first_sched || ip >= last_sched) return ip; backchain = (*(unsigned long *) backchain) & 0x7fffffff; } while (count++ < 16); } #endif return 0; }