A gdb patch for linux 2.0.35

H.J. Lu (hjl@lucon.org)
Thu, 25 Jun 1998 11:14:08 -0700 (PDT)


Hi,

This is a gdb patch for Linux 2.0.33/2.0.34. With this patch and my gdb
4.17.0.x, you can debug floating point numbers on Linux/x86.

BTW, Rudolf, my previous patch missed one line. Hardware watchpoint
doesn't work. This patch fixes it.

-- 
H.J. Lu (hjl@gnu.org)
-- 
--- ../linux-2.0.34/include/asm-i386/ptrace.h	Wed Sep 13 00:08:39 1995
+++ include/asm-i386/ptrace.h	Sat Jun 20 14:48:57 1998
@@ -43,6 +43,12 @@
 	unsigned short ss, __ssu;
 };
 
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+#define PTRACE_GETFPREGS          14
+#define PTRACE_SETFPREGS          15
+
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->cs))
 #define instruction_pointer(regs) ((regs)->eip)
--- ../linux-2.0.34/arch/i386/kernel/ptrace.c	Thu Jun  4 20:14:23 1998
+++ arch/i386/kernel/ptrace.c	Tue Jun 23 17:43:25 1998
@@ -417,6 +417,55 @@
 	return tmp;
 }
 
+static int putreg(struct task_struct *child,
+	unsigned long regno, unsigned long value)
+{
+	switch (regno >> 2) {
+		case ORIG_EAX:
+			return -EIO;
+		case FS:
+		case GS:
+		case DS:
+		case ES:
+			if (value && (value & 3) != 3)
+				return -EIO;
+			value &= 0xffff;
+			break;
+		case SS:
+		case CS:
+			if ((value & 3) != 3)
+				return -EIO;
+			value &= 0xffff;
+			break;
+		case EFL:
+			value &= FLAG_MASK;
+			value |= get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~FLAG_MASK;
+	}
+	put_stack_long(child, regno - sizeof(struct pt_regs), value);
+	return 0;
+}
+
+static unsigned long getreg(struct task_struct *child,
+	unsigned long regno)
+{
+	unsigned long retval = ~0UL;
+
+	switch (regno >> 2) {
+		case FS:
+		case GS:
+		case DS:
+		case ES:
+		case SS:
+		case CS:
+			retval = 0xffff;
+			/* fall through */
+		default:
+			regno = regno - sizeof(struct pt_regs);
+			retval &= get_stack_long(child, regno);
+	}
+	return retval;
+}
+
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
@@ -490,39 +539,23 @@
 			unsigned long tmp;
 			int res;
 			
-  			if ((addr & 3 && 
-  			     (addr < (long) (&dummy->i387) ||
-  			      addr > (long) (&dummy->i387.st_space[20]) )) ||
-  			    addr < 0 || addr > sizeof(struct user) - 3)
+  			if ((addr & 3) || 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. */
-
-			  tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
-			  if (addr == DS || addr == ES ||
-			      addr == FS || addr == GS ||
-			      addr == CS || addr == SS)
-			    tmp &= 0xffff;
-			};
-			if(addr >= (long) &dummy->u_debugreg[0] &&
-			   addr <= (long) &dummy->u_debugreg[7]){
+			if(addr < 17*sizeof(long))
+				tmp = getreg(child, addr);
+			else if(addr >= (long) &dummy->u_debugreg[0]
+				&& addr <= (long) &dummy->u_debugreg[7])
+			{
 				addr -= (long) &dummy->u_debugreg[0];
 				addr = addr >> 2;
 				tmp = child->debugreg[addr];
-			};
+			}
 			put_fs_long(tmp,(unsigned long *) data);
 			return 0;
 		}
@@ -533,50 +566,18 @@
 			return write_long(child,addr,data);
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-			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 ||
-			    addr == FS || addr == GS ||
-			    addr == CS || addr == SS) {
-			    	data &= 0xffff;
-			    	if (data && (data & 3) != 3)
-					return -EIO;
-			}
-			if (addr == EFL) {   /* flags. */
-				data &= FLAG_MASK;
-				data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER)  & ~FLAG_MASK;
-			}
-		  /* Do not allow the user to set the debug register for kernel
-		     address space */
-		  if(addr < 17){
-			  if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
+  			if ((addr & 3) || addr < 0
+			    || addr > sizeof(struct user) - 3)
 				return -EIO;
-			return 0;
-			};
+
+			if(addr < 17*sizeof(long))
+				return putreg(child, addr, data);
 
 		  /* We need to be very careful here.  We implicitly
 		     want to modify a portion of the task_struct, and we
 		     have to be selective about what portions we allow someone
 		     to modify. */
 
-		  addr = addr << 2;  /* Convert back again */
 		  if(addr >= (long) &dummy->u_debugreg[0] &&
 		     addr <= (long) &dummy->u_debugreg[7]){
 
@@ -665,6 +666,108 @@
 			put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
 			return 0;
 		}
+
+		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+#ifdef CONFIG_MATH_EMULATION
+			if (!hard_math)
+				/* Not supported. */
+				return -EIO;
+#endif
+
+			if (verify_area(VERIFY_WRITE, (void *) data,
+					17*sizeof(long)))
+			  return -EIO;
+			for (i = 0; i < 17*sizeof(long);
+			     i += sizeof(long), data += sizeof(long))
+			  put_fs_long (getreg(child, i), (unsigned long *) data);
+			return 0;
+		  };
+
+		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+			unsigned long tmp;
+
+#ifdef CONFIG_MATH_EMULATION
+			if (!hard_math)
+				/* Not supported. */
+				return -EIO;
+#endif
+
+			if (verify_area(VERIFY_READ, (void *) data,
+					17*sizeof(long)))
+			  return -EIO;
+			for (i = 0; i < 17*sizeof(long);
+			     i += sizeof(long), data += sizeof(long))
+			  {
+			    tmp = get_fs_long ((unsigned long *) data);
+			    putreg(child, i, tmp);
+			  }
+			return 0;
+		  };
+
+		case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+			unsigned long *tmp;
+
+#ifdef CONFIG_MATH_EMULATION
+			if (!hard_math)
+				/* Not supported. */
+				return -EIO;
+#endif
+
+			if (verify_area(VERIFY_WRITE, (void *) data,
+					sizeof(struct user_i387_struct)))
+			  return -EIO;
+			if ( !child->used_math ) {
+			  /* Simulate an empty FPU. */
+			  child->tss.i387.hard.cwd = 0xffff037f;
+			  child->tss.i387.hard.swd = 0xffff0000;
+			  child->tss.i387.hard.twd = 0xffffffff;
+			}
+			if (last_task_used_math == child)
+			  {
+			    clts();
+			    __asm__("fnsave %0; fwait":"=m" (child->tss.i387.hard));
+			    last_task_used_math = NULL;
+			    stts();
+			  }
+			tmp = (unsigned long *) &child->tss.i387.hard;
+			for ( i = 0; i < sizeof(struct user_i387_struct); i += sizeof(long) )
+			  {
+			    put_fs_long (*tmp, (unsigned long *) data);
+			    data += sizeof(long);
+			    tmp++;
+			  }
+
+			return 0;
+		  };
+
+		case PTRACE_SETFPREGS: { /* Set the child FPU state. */
+			unsigned long *tmp;
+
+#ifdef CONFIG_MATH_EMULATION
+			if (!hard_math)
+				/* Not supported. */
+				return -EIO;
+#endif
+
+			if (verify_area(VERIFY_READ, (void *) data,
+					sizeof(struct user_i387_struct)))
+			  return -EIO;
+			child->used_math = 1;
+			if (last_task_used_math == child)
+			  {
+			    /* Discard the state of the FPU */
+			    last_task_used_math = NULL;
+			  }
+			tmp = (unsigned long *) &child->tss.i387.hard;
+			for ( i = 0; i < sizeof(struct user_i387_struct); i += sizeof(long) )
+			  {
+			    *tmp = get_fs_long ((unsigned long *) data);
+			    data += sizeof(long);
+			    tmp++;
+			  }
+			child->flags &= ~PF_USEDFPU;
+			return 0;
+		  };
 
 		default:
 			return -EIO;

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu