patch-2.0.32 linux/arch/i386/kernel/ptrace.c
Next file: linux/arch/i386/kernel/setup.c
Previous file: linux/arch/i386/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 185
- Date:
Fri Nov 7 09:11:42 1997
- Orig file:
v2.0.31/linux/arch/i386/kernel/ptrace.c
- Orig date:
Mon Aug 4 12:12:22 1997
diff -u --recursive --new-file v2.0.31/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
@@ -294,6 +294,127 @@
put_long(tsk, vma, addr, data);
return 0;
}
+#ifdef CONFIG_MATH_EMULATION
+static void write_emulator_word(struct task_struct *child,
+ unsigned long register_offset,
+ long data)
+{
+ int i, j;
+ struct i387_soft_struct *soft_fpu;
+ struct fpu_reg *this_fpreg, *next_fpreg;
+ char hard_reg[2][10];
+ int control_word;
+ unsigned long top;
+ i = register_offset / 10;
+ j = register_offset % 10;
+ soft_fpu = &child->tss.i387.soft;
+ top = i + (unsigned long) soft_fpu->top;
+ control_word = soft_fpu->cwd;
+ this_fpreg = &soft_fpu->regs[(top + i) % 8];
+ next_fpreg = &soft_fpu->regs[(top + i + 1) % 8];
+ softreg_to_hardreg(this_fpreg, hard_reg[0], control_word);
+ if (j > 6)
+ softreg_to_hardreg(next_fpreg, hard_reg[1], control_word);
+ *(long *) &hard_reg[0][j] = data;
+ hardreg_to_softreg(hard_reg[0], this_fpreg);
+ if (j > 6)
+ hardreg_to_softreg(hard_reg[1], next_fpreg);
+}
+#endif /* defined(CONFIG_MATH_EMULATION) */
+
+/* Put a word to the part of the user structure containing
+ * floating point registers
+ * Floating point support added to ptrace by Ramon Garcia,
+ * ramon@juguete.quim.ucm.es
+ */
+
+static int put_fpreg_word (struct task_struct *child,
+ unsigned long addr, long data)
+{
+ struct user *dummy = NULL;
+ if (addr < (long) (&dummy->i387.st_space))
+ return -EIO;
+ addr -= (long) (&dummy->i387.st_space);
+
+ if (!hard_math) {
+#ifdef CONFIG_MATH_EMULATION
+ write_emulator_word(child, addr, data);
+#else
+ return 0;
+#endif
+ }
+ else
+#ifndef __SMP__
+ if (last_task_used_math == child) {
+ clts();
+ __asm__("fsave %0; fwait":"=m" (child->tss.i387));
+ last_task_used_math = current;
+ stts();
+ }
+#endif
+ *(long *)
+ ((char *) (child->tss.i387.hard.st_space) + addr) = data;
+ return 0;
+}
+
+#ifdef CONFIG_MATH_EMULATION
+
+static unsigned long get_emulator_word(struct task_struct *child,
+ unsigned long register_offset)
+{
+ char hard_reg[2][10];
+ int i, j;
+ struct fpu_reg *this_fpreg, *next_fpreg;
+ struct i387_soft_struct *soft_fpu;
+ long int control_word;
+ unsigned long top;
+ unsigned long tmp;
+ i = register_offset / 10;
+ j = register_offset % 10;
+ soft_fpu = &child->tss.i387.soft;
+ top = (unsigned long) soft_fpu->top;
+ this_fpreg = &soft_fpu->regs[(top + i) % 8];
+ next_fpreg = &soft_fpu->regs[(top + i + 1) % 8];
+ control_word = soft_fpu->cwd;
+ softreg_to_hardreg(this_fpreg, hard_reg[0], control_word);
+ if (j > 6)
+ softreg_to_hardreg(next_fpreg, hard_reg[1], control_word);
+ tmp = *(long *)
+ &hard_reg[0][j];
+ return tmp;
+}
+
+#endif /* defined(CONFIG_MATH_EMULATION) */
+/* Get a word from the part of the user structure containing
+ * floating point registers
+ */
+static unsigned long get_fpreg_word(struct task_struct *child,
+ unsigned long addr)
+{
+ struct user *dummy = NULL;
+ unsigned long tmp;
+ addr -= (long) (&dummy->i387.st_space);
+ if (!hard_math) {
+#ifdef CONFIG_MATH_EMULATION
+ tmp = get_emulator_word(child, addr);
+#else
+ tmp = 0;
+#endif /* !defined(CONFIG_MATH_EMULATION) */
+ } else {
+#ifndef __SMP__
+ if (last_task_used_math == child) {
+ clts();
+ __asm__("fsave %0; fwait":"=m" (child->tss.i387));
+ last_task_used_math = current;
+ stts();
+ }
+#endif
+ tmp = *(long *)
+ ((char *) (child->tss.i387.hard.st_space) +
+ addr);
+ }
+ return tmp;
+}
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
@@ -367,15 +488,25 @@
case PTRACE_PEEKUSR: {
unsigned long tmp;
int res;
-
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
+
+ if ((addr & 3 &&
+ (addr < (long) (&dummy->i387) ||
+ addr > (long) (&dummy->i387.st_space[20]) )) ||
+ addr < 0 || addr > sizeof(struct user) - 3)
return -EIO;
-
+
res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
if (res)
return res;
tmp = 0; /* Default return condition */
+ if (addr >= (long) (&dummy->i387) &&
+ addr < (long) (&dummy->i387.st_space[20]) ) {
+#ifndef CONFIG_MATH_EMULATION
+ if (!hard_math)
+ return -EIO;
+#endif /* defined(CONFIG_MATH_EMULATION) */
+ tmp = get_fpreg_word(child, addr);
+ }
if(addr < 17*sizeof(long)) {
addr = addr >> 2; /* temporary hack. */
@@ -401,12 +532,23 @@
return write_long(child,addr,data);
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
- if ((addr & 3) || addr < 0 ||
+ if ((addr & 3 &&
+ (addr < (long) (&dummy->i387.st_space[0]) ||
+ addr > (long) (&dummy->i387.st_space[20]) )) ||
+ addr < 0 ||
addr > sizeof(struct user) - 3)
return -EIO;
-
+
+ if (addr >= (long) (&dummy->i387.st_space[0]) &&
+ addr < (long) (&dummy->i387.st_space[20]) ) {
+#ifndef CONFIG_MATH_EMULATION
+ if (!hard_math)
+ return -EIO;
+#endif /* defined(CONFIG_MATH_EMULATION) */
+ return put_fpreg_word(child, addr, data);
+ }
addr = addr >> 2; /* temporary hack. */
-
+
if (addr == ORIG_EAX)
return -EIO;
if (addr == DS || addr == ES ||
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov