diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-24 23:26:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-24 23:26:08 +0000 |
commit | 3030734911ede364a11128eb4de1c53710168404 (patch) | |
tree | 215774aa14b3f71266591fe499abf5bdda404ea0 /arch | |
parent | d44ce4991590772faca9bd85805bd58025052f10 (diff) |
Fix get_wchan for real. The 64-bit version also supports 32-bit ps
binaries. For 64-bit kernel and 32-bit the higher 32-bit of addresses
have to be stripped of all addresses.
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/kernel/process.c | 42 | ||||
-rw-r--r-- | arch/mips64/kernel/process.c | 49 |
2 files changed, 71 insertions, 20 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 9d1d0ff62..6071935d5 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -1,10 +1,9 @@ -/* $Id: process.c,v 1.18 2000/01/29 01:41:59 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994 - 1999 by Ralf Baechle and others. + * Copyright (C) 1994 - 2000 by Ralf Baechle and others. * Copyright (C) 1999 Silicon Graphics, Inc. */ #include <linux/errno.h> @@ -194,18 +193,47 @@ extern void scheduling_functions_end_here(void); #define first_sched ((unsigned long) scheduling_functions_start_here) #define last_sched ((unsigned long) scheduling_functions_end_here) +/* get_wchan - a maintenance nightmare ... */ unsigned long get_wchan(struct task_struct *p) { - unsigned long schedule_frame; - unsigned long pc; + unsigned long frame, pc; if (!p || p == current || p->state == TASK_RUNNING) return 0; pc = thread_saved_pc(&p->thread); + if (pc < first_sched || pc >= last_sched) { + return pc; + } + + 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; + goto schedule_timeout_caller; + +schedule_caller: + frame = ((unsigned long *)p->thread.reg30)[9]; + pc = ((unsigned long *)frame)[11]; + return pc; + +schedule_timeout_caller: + /* Must be schedule_timeout ... */ + pc = ((unsigned long *)p->thread.reg30)[10]; + frame = ((unsigned long *)p->thread.reg30)[9]; + + /* The schedule_timeout frame ... */ + pc = ((unsigned long *)frame)[14]; + frame = ((unsigned long *)frame)[13]; + if (pc >= first_sched && pc < last_sched) { - schedule_frame = ((unsigned long *)p->thread.reg30)[9]; - return ((unsigned long *)schedule_frame)[11]; + /* schedule_timeout called by interruptible_sleep_on_timeout */ + pc = ((unsigned long *)frame)[11]; + frame = ((unsigned long *)frame)[10]; } return pc; diff --git a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c index df03ef081..b45f23a36 100644 --- a/arch/mips64/kernel/process.c +++ b/arch/mips64/kernel/process.c @@ -186,28 +186,51 @@ extern void scheduling_functions_end_here(void); #define first_sched ((unsigned long) scheduling_functions_start_here) #define last_sched ((unsigned long) scheduling_functions_end_here) +/* get_wchan - a maintenance nightmare ... */ unsigned long get_wchan(struct task_struct *p) { - unsigned long schedule_frame; - unsigned long pc; + unsigned long frame, pc; if (!p || p == current || p->state == TASK_RUNNING) return 0; pc = thread_saved_pc(&p->thread); - if (pc == (unsigned long) interruptible_sleep_on - || pc == (unsigned long) sleep_on) { - schedule_frame = ((unsigned long *)p->thread.reg30)[9]; - return ((unsigned long *)schedule_frame)[15]; - } - if (pc == (unsigned long) interruptible_sleep_on_timeout - || pc == (unsigned long) sleep_on_timeout) { - schedule_frame = ((unsigned long *)p->thread.reg30)[9]; - return ((unsigned long *)schedule_frame)[16]; - } + if (pc < first_sched || pc >= last_sched) + 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; + goto schedule_timeout_caller; + +schedule_caller: + frame = ((unsigned long *)p->thread.reg30)[10]; + pc = ((unsigned long *)frame)[7]; + goto out; + +schedule_timeout_caller: + /* Must be schedule_timeout ... */ + pc = ((unsigned long *)p->thread.reg30)[11]; + frame = ((unsigned long *)p->thread.reg30)[10]; + + /* The schedule_timeout frame ... */ + pc = ((unsigned long *)frame)[9]; + frame = ((unsigned long *)frame)[8]; + if (pc >= first_sched && pc < last_sched) { - printk(KERN_DEBUG "Bug in %s\n", __FUNCTION__); + /* schedule_timeout called by interruptible_sleep_on_timeout */ + pc = ((unsigned long *)frame)[7]; + frame = ((unsigned long *)frame)[6]; } +out: + if (current->thread.mflags & MF_32BIT) /* Kludge for 32-bit ps */ + pc &= 0xffffffff; + return pc; } |