summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-10-24 23:26:08 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-10-24 23:26:08 +0000
commit3030734911ede364a11128eb4de1c53710168404 (patch)
tree215774aa14b3f71266591fe499abf5bdda404ea0 /arch
parentd44ce4991590772faca9bd85805bd58025052f10 (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.c42
-rw-r--r--arch/mips64/kernel/process.c49
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;
}