>>>>> On Fri, 24 Sep 2004 10:52:40 +0200, Thomas Petazzoni <thomas.petazzoni@xxxxxxxx> said: thomas> In arch/mips/kernel/process.c, the function frame_info_init() thomas> called at boot time, calls the get_frame_info() to a analyze thomas> the prologue of a few functions (I don't know why, does anyone thomas> know ?). Because thread_saved_pc(), get_wchan() needs those information. The information of 'schedule' function is required, others are optional ("ps -l" shows better output with those informations). thomas> The get_frame_info() seems to search a sw or sd instruction, thomas> but here is the beginning of the schedule_timeout() function : This is because now schedule_timeout is in kernel/timer.c (not kernel/sched.c) which is compiled without -fno-omit-frame-pointer option. I rewrote get_wchan() to handle this problem. Please try this patch. Note that this patch still depends on order of address of sched functions, so not gcc-3.4 proof. Sorting minfo[] array will make it more robust. If anyone interested in, I will implement it. diff -u linux-mips/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- linux-mips/arch/mips/kernel/process.c Wed Sep 22 13:27:59 2004 +++ linux/arch/mips/kernel/process.c Wed Sep 22 17:03:10 2004 @@ -177,21 +177,41 @@ } struct mips_frame_info { + void *func; + int omit_fp; /* compiled without fno-omit-frame-pointer */ int frame_offset; int pc_offset; +} mfinfo [] = { + /* must be in address order */ + { __down_interruptible, 1 }, + { schedule, 0 }, +#define schedule_frame 1 +#ifdef CONFIG_PREEMPT + { preempt_schedule, 0 }, +#endif + { wait_for_completion, 0 }, + { interruptible_sleep_on, 0 }, + { interruptible_sleep_on_timeout, 0 }, + { sleep_on, 0 }, + { sleep_on_timeout, 0 }, + { __cond_resched, 0 }, + { yield, 0 }, + { io_schedule, 0 }, + { io_schedule_timeout, 0 }, + { schedule_timeout, 1 }, +/* { nanosleep_restart, 1 }, */ + { __down_read, 1 }, + { __down_write, 1 }, }; -static 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 struct mips_frame_info wait_for_completion_frame; + static int mips_frame_info_initialized; -static int __init get_frame_info(struct mips_frame_info *info, void *func) +static int __init get_frame_info(struct mips_frame_info *info) { int i; + void *func = info->func; union mips_instruction *ip = (union mips_instruction *)func; info->pc_offset = -1; - info->frame_offset = -1; + info->frame_offset = info->omit_fp ? 0 : -1; for (i = 0; i < 128; i++, ip++) { /* if jal, jalr, jr, stop. */ if (ip->j_format.opcode == jal_op || @@ -237,13 +257,11 @@ static int __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_frame_info(&wait_for_completion_frame, wait_for_completion); - + int i; + for (i = 0; i < ARRAY_SIZE(mfinfo); i++) + if (get_frame_info(&mfinfo[i])) + return -1; + mips_frame_info_initialized = 1; return 0; } @@ -261,9 +279,9 @@ if (t->reg31 == (unsigned long) ret_from_fork) return t->reg31; - if (schedule_frame.pc_offset < 0) + if (mfinfo[schedule_frame].pc_offset < 0) return 0; - return ((unsigned long *)t->reg29)[schedule_frame.pc_offset]; + return ((unsigned long *)t->reg29)[mfinfo[schedule_frame].pc_offset]; } /* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */ @@ -277,48 +295,27 @@ if (!mips_frame_info_initialized) return 0; pc = thread_saved_pc(p); + if (!in_sched_functions(pc)) goto out; - if (pc >= (unsigned long) sleep_on_timeout) - goto schedule_timeout_caller; - if (pc >= (unsigned long) sleep_on) - goto schedule_caller; - if (pc >= (unsigned long) interruptible_sleep_on_timeout) - goto schedule_timeout_caller; - if (pc >= (unsigned long)interruptible_sleep_on) - goto schedule_caller; - if (pc >= (unsigned long)wait_for_completion) - goto schedule_caller; - goto schedule_timeout_caller; - -schedule_caller: - frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset]; - if (pc >= (unsigned long) sleep_on) - pc = ((unsigned long *)frame)[sleep_on_frame.pc_offset]; - else - pc = ((unsigned long *)frame)[wait_for_completion_frame.pc_offset]; - goto out; - -schedule_timeout_caller: - /* - * The schedule_timeout frame - */ - frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset]; - - /* - * frame now points to sleep_on_timeout's frame - */ - pc = ((unsigned long *)frame)[schedule_timeout_frame.pc_offset]; - - if (in_sched_functions(pc)) { - /* schedule_timeout called by [interruptible_]sleep_on_timeout */ - frame = ((unsigned long *)frame)[schedule_timeout_frame.frame_offset]; - pc = ((unsigned long *)frame)[sleep_on_timeout_frame.pc_offset]; - } + frame = ((unsigned long *)p->thread.reg30)[mfinfo[schedule_frame].frame_offset]; + do { + int i; + for (i = ARRAY_SIZE(mfinfo) - 1; i >= 0; i--) { + if (pc >= (unsigned long) mfinfo[i].func) + break; + } + if (i < 0) + break; -out: + if (mfinfo[i].omit_fp) + break; + pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; + frame = ((unsigned long *)frame)[mfinfo[i].frame_offset]; + } while (in_sched_functions(pc)); +out: #ifdef CONFIG_MIPS64 if (current->thread.mflags & MF_32BIT_REGS) /* Kludge for 32-bit ps */ pc &= 0xffffffffUL; --- Atsushi Nemoto