There are some magic constant numbers about stack layout in thread_saved_pc() and get_wchan() function. I made a patch to eliminate these magic numbers. This patch analyzes some functions prologue codes in heuristic way at run-time. "ps -l" (and "MAGIC SYSRQ" feature) works fine with this patch. --- Atsushi Nemoto
diff -ur linux.sgi/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- linux.sgi/arch/mips/kernel/process.c Sun Aug 5 23:39:09 2001 +++ linux/arch/mips/kernel/process.c Wed Aug 22 14:14:29 2001 @@ -19,6 +19,7 @@ #include <linux/sys.h> #include <linux/user.h> #include <linux/a.out.h> +#include <linux/init.h> #include <asm/bootinfo.h> #include <asm/cpu.h> @@ -31,6 +32,7 @@ #include <asm/io.h> #include <asm/elf.h> #include <asm/isadep.h> +#include <asm/inst.h> void cpu_idle(void) { @@ -196,6 +198,59 @@ #define first_sched ((unsigned long) scheduling_functions_start_here) #define last_sched ((unsigned long) scheduling_functions_end_here) +struct mips_frame_info schedule_frame; +static struct mips_frame_info schedule_timeout_frame; +static struct mips_frame_info sleep_on_frame; +static struct mips_frame_info sleep_on_timeout_frame; +static int mips_frame_info_initialized; +static int __init get_frame_info(struct mips_frame_info *info, void *func) +{ + int i; + union mips_instruction *ip = (union mips_instruction *)func; + info->pc_offset = -1; + info->frame_offset = -1; + for (i = 0; i < 128; i++, ip++) { + /* if jal, jalr, jr, stop. */ + if (ip->j_format.opcode == jal_op || + (ip->r_format.opcode == spec_op && + (ip->r_format.func == jalr_op || + ip->r_format.func == jr_op))) + break; + if (ip->i_format.opcode == sw_op && + ip->i_format.rs == 29) { + /* sw $ra, offset($sp) */ + if (ip->i_format.rt == 31) { + if (info->pc_offset != -1) + break; + info->pc_offset = + ip->i_format.simmediate / sizeof(long); + } + /* sw $s8, offset($sp) */ + if (ip->i_format.rt == 30) { + if (info->frame_offset != -1) + break; + info->frame_offset = + ip->i_format.simmediate / sizeof(long); + } + } + } + if (info->pc_offset == -1 || info->frame_offset == -1) { + printk("Can't analize prologue code at %p\n", func); + info->pc_offset = -1; + info->frame_offset = -1; + return -1; + } + return 0; +} +void __init frame_info_init(void) +{ + mips_frame_info_initialized = + !get_frame_info(&schedule_frame, schedule) && + !get_frame_info(&schedule_timeout_frame, schedule_timeout) && + !get_frame_info(&sleep_on_frame, sleep_on) && + !get_frame_info(&sleep_on_timeout_frame, sleep_on_timeout); +} + /* get_wchan - a maintenance nightmare ... */ unsigned long get_wchan(struct task_struct *p) { @@ -204,6 +259,8 @@ if (!p || p == current || p->state == TASK_RUNNING) return 0; + if (!mips_frame_info_initialized) + return 0; pc = thread_saved_pc(&p->thread); if (pc < first_sched || pc >= last_sched) { return pc; @@ -220,23 +277,24 @@ goto schedule_timeout_caller; schedule_caller: - frame = ((unsigned long *)p->thread.reg30)[9]; - pc = ((unsigned long *)frame)[11]; + /* schedule_timeout called by interruptible_sleep_on or sleep_on */ + frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset]; + pc = ((unsigned long *)frame)[sleep_on_frame.pc_offset]; return pc; schedule_timeout_caller: /* Must be schedule_timeout ... */ - pc = ((unsigned long *)p->thread.reg30)[10]; - frame = ((unsigned long *)p->thread.reg30)[9]; + pc = ((unsigned long *)p->thread.reg30)[schedule_frame.pc_offset]; + frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset]; /* The schedule_timeout frame ... */ - pc = ((unsigned long *)frame)[14]; - frame = ((unsigned long *)frame)[13]; + pc = ((unsigned long *)frame)[schedule_timeout_frame.pc_offset]; + frame = ((unsigned long *)frame)[schedule_timeout_frame.frame_offset]; if (pc >= first_sched && pc < last_sched) { /* schedule_timeout called by interruptible_sleep_on_timeout */ - pc = ((unsigned long *)frame)[11]; - frame = ((unsigned long *)frame)[10]; + pc = ((unsigned long *)frame)[sleep_on_timeout_frame.pc_offset]; + frame = ((unsigned long *)frame)[sleep_on_timeout_frame.frame_offset]; } return pc; diff -ur linux.sgi/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c --- linux.sgi/arch/mips/kernel/setup.c Sun Aug 5 23:39:15 2001 +++ linux/arch/mips/kernel/setup.c Wed Aug 22 14:26:19 2001 @@ -518,12 +518,14 @@ void malta_setup(void); void momenco_ocelot_setup(void); void nino_setup(void); + void frame_info_init(void); unsigned long bootmap_size; unsigned long start_pfn, max_pfn, first_usable_pfn; int i; + frame_info_init(); #ifdef CONFIG_BLK_DEV_FD fd_ops = &no_fd_ops; #endif diff -ur linux.sgi/include/asm-mips/processor.h linux/include/asm-mips/processor.h --- linux.sgi/include/asm-mips/processor.h Sun Aug 5 23:41:29 2001 +++ linux/include/asm-mips/processor.h Wed Aug 22 14:14:59 2001 @@ -217,6 +217,11 @@ #define copy_segments(p, mm) do { } while(0) #define release_segments(mm) do { } while(0) +struct mips_frame_info { + int frame_offset; + int pc_offset; +}; +extern struct mips_frame_info schedule_frame; /* * Return saved PC of a blocked thread. */ @@ -228,7 +233,9 @@ if (t->reg31 == (unsigned long) ret_from_fork) return t->reg31; - return ((unsigned long *)t->reg29)[10]; + if (schedule_frame.pc_offset < 0) + return 0; + return ((unsigned long *)t->reg29)[schedule_frame.pc_offset]; } /*