This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Revamp legacy GNU/Linux i386 native support


An attempt to remove the usage of deprecated GDB features in
i386-linux-tdep.c led me to rewrite bits of code that are used on
older Linux kernels.

I tested this on a newer Linux kernel by initializing
have_ptrace_getregs to 0 instead of 1, and that seems to work fine.

Committed.

Mark


Index: ChangeLog
from  Mark Kettenis  <kettenis@gnu.org>

	* i386-linux-nat.c (ORIG_EAX): Define to -1 if not already
	defined.
	(regmap): Extend to cover all registers.
	(PT_READ_U, PT_WRITE_U, PTRACE_XFER_TYPE,
	OLD_CANNOT_FETCH_REGISTERS, OLD_CANNOT_STORE_REGISTERS): Remove
	definitions.
	(fetch_register, sore_register): Simplify.
	(old_fetch_inferior_registers, old_store_inferior_registers):
	Remove functions.
	(cannot_fetch_register, cannot_store_register): Change
	implementation to use regmap array to decide which registers
	cannot be fetched/stored.  This removes $orig_eax from the
	registers that cannot be fetched/stored.
	(fetch_inferior_registers): Call fetch_register directly instead
	of calling old_fetch_inferior_registers.
	(store_inferior_registers): Call store_register directly instead
	of calling old_store_inferior_registers.
	(i386_linux_dr_get): Replace PT_READ_U with PTRACE_PEEKUSER.
	(i386_linux_dr_set): Replace PT_WRITE_U with PTRACE_POKEUSER.
	* config/i386/nm-linux.h (U_REGS_OFFSET): Remove definition.

Index: i386-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v
retrieving revision 1.42
diff -u -p -r1.42 i386-linux-nat.c
--- i386-linux-nat.c 1 Sep 2002 22:05:42 -0000 1.42
+++ i386-linux-nat.c 9 Nov 2002 21:29:29 -0000
@@ -34,6 +34,10 @@
 #include <sys/reg.h>
 #endif
 
+#ifndef ORIG_EAX
+#define ORIG_EAX -1
+#endif
+
 #ifdef HAVE_SYS_DEBUGREG_H
 #include <sys/debugreg.h>
 #endif
@@ -90,7 +94,15 @@ static int regmap[] = 
   EAX, ECX, EDX, EBX,
   UESP, EBP, ESI, EDI,
   EIP, EFL, CS, SS,
-  DS, ES, FS, GS
+  DS, ES, FS, GS,
+  -1, -1, -1, -1,		/* st0, st1, st2, st3 */
+  -1, -1, -1, -1,		/* st4, st5, st6, st7 */
+  -1, -1, -1, -1,		/* fctrl, fstat, ftag, fiseg */
+  -1, -1, -1, -1,		/* fioff, foseg, fooff, fop */
+  -1, -1, -1, -1,		/* xmm0, xmm1, xmm2, xmm3 */
+  -1, -1, -1, -1,		/* xmm4, xmm5, xmm6, xmm6 */
+  -1,				/* mxcsr */
+  ORIG_EAX
 };
 
 /* Which ptrace request retrieves which registers?
@@ -148,155 +160,58 @@ kernel_u_size (void)
 }
 
 
-/* Fetching registers directly from the U area, one at a time.  */
-
-/* FIXME: kettenis/2000-03-05: This duplicates code from `inptrace.c'.
-   The problem is that we define FETCH_INFERIOR_REGISTERS since we
-   want to use our own versions of {fetch,store}_inferior_registers
-   that use the GETREGS request.  This means that the code in
-   `infptrace.c' is #ifdef'd out.  But we need to fall back on that
-   code when GDB is running on top of a kernel that doesn't support
-   the GETREGS request.  I want to avoid changing `infptrace.c' right
-   now.  */
-
-#ifndef PT_READ_U
-#define PT_READ_U PTRACE_PEEKUSR
-#endif
-#ifndef PT_WRITE_U
-#define PT_WRITE_U PTRACE_POKEUSR
-#endif
-
-/* Default the type of the ptrace transfer to int.  */
-#ifndef PTRACE_XFER_TYPE
-#define PTRACE_XFER_TYPE int
-#endif
-
-/* Registers we shouldn't try to fetch.  */
-#define OLD_CANNOT_FETCH_REGISTER(regno) ((regno) >= I386_NUM_GREGS)
+/* Accessing registers through the U area, one at a time.  */
 
 /* Fetch one register.  */
 
 static void
 fetch_register (int regno)
 {
-  /* This isn't really an address.  But ptrace thinks of it as one.  */
-  CORE_ADDR regaddr;
-  char mess[128];		/* For messages */
-  register int i;
-  unsigned int offset;		/* Offset of registers within the u area.  */
-  char buf[MAX_REGISTER_RAW_SIZE];
   int tid;
+  int val;
 
-  if (OLD_CANNOT_FETCH_REGISTER (regno))
+  gdb_assert (!have_ptrace_getregs);
+  if (cannot_fetch_register (regno))
     {
-      memset (buf, '\0', REGISTER_RAW_SIZE (regno));	/* Supply zeroes */
-      supply_register (regno, buf);
+      supply_register (regno, NULL);
       return;
     }
 
-  /* Overload thread id onto process id */
+  /* GNU/Linux LWP ID's are process ID's.  */
   if ((tid = TIDGET (inferior_ptid)) == 0)
-    tid = PIDGET (inferior_ptid);	/* no thread id, just use process id */
-
-  offset = U_REGS_OFFSET;
-
-  regaddr = register_addr (regno, offset);
-  for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
-    {
-      errno = 0;
-      *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid,
-					       (PTRACE_ARG3_TYPE) regaddr, 0);
-      regaddr += sizeof (PTRACE_XFER_TYPE);
-      if (errno != 0)
-	{
-	  sprintf (mess, "reading register %s (#%d)", 
-		   REGISTER_NAME (regno), regno);
-	  perror_with_name (mess);
-	}
-    }
-  supply_register (regno, buf);
-}
+    tid = PIDGET (inferior_ptid);	/* Not a threaded program.  */
 
-/* Fetch register values from the inferior.
-   If REGNO is negative, do this for all registers.
-   Otherwise, REGNO specifies which register (so we can save time). */
+  errno = 0;
+  val = ptrace (PTRACE_PEEKUSER, tid, register_addr (regno, 0), 0);
+  if (errno != 0)
+    error ("Couldn't read register %s (#%d): %s.", REGISTER_NAME (regno),
+	   regno, safe_strerror (errno));
 
-void
-old_fetch_inferior_registers (int regno)
-{
-  if (regno >= 0)
-    {
-      fetch_register (regno);
-    }
-  else
-    {
-      for (regno = 0; regno < NUM_REGS; regno++)
-	{
-	  fetch_register (regno);
-	}
-    }
+  supply_register (regno, &val);
 }
 
-/* Registers we shouldn't try to store.  */
-#define OLD_CANNOT_STORE_REGISTER(regno) ((regno) >= I386_NUM_GREGS)
-
 /* Store one register. */
 
 static void
 store_register (int regno)
 {
-  /* This isn't really an address.  But ptrace thinks of it as one.  */
-  CORE_ADDR regaddr;
-  char mess[128];		/* For messages */
-  register int i;
-  unsigned int offset;		/* Offset of registers within the u area.  */
   int tid;
+  int val;
 
-  if (OLD_CANNOT_STORE_REGISTER (regno))
-    {
-      return;
-    }
+  gdb_assert (!have_ptrace_getregs);
+  if (cannot_store_register (regno))
+    return;
 
-  /* Overload thread id onto process id */
+  /* GNU/Linux LWP ID's are process ID's.  */
   if ((tid = TIDGET (inferior_ptid)) == 0)
-    tid = PIDGET (inferior_ptid);	/* no thread id, just use process id */
-
-  offset = U_REGS_OFFSET;
-
-  regaddr = register_addr (regno, offset);
-  for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
-    {
-      errno = 0;
-      ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
-	      *(PTRACE_XFER_TYPE *) & registers[REGISTER_BYTE (regno) + i]);
-      regaddr += sizeof (PTRACE_XFER_TYPE);
-      if (errno != 0)
-	{
-	  sprintf (mess, "writing register %s (#%d)", 
-		   REGISTER_NAME (regno), regno);
-	  perror_with_name (mess);
-	}
-    }
-}
-
-/* Store our register values back into the inferior.
-   If REGNO is negative, do this for all registers.
-   Otherwise, REGNO specifies which register (so we can save time).  */
+    tid = PIDGET (inferior_ptid);	/* Not a threaded program.  */
 
-void
-old_store_inferior_registers (int regno)
-{
-  if (regno >= 0)
-    {
-      store_register (regno);
-    }
-  else
-    {
-      for (regno = 0; regno < NUM_REGS; regno++)
-	{
-	  store_register (regno);
-	}
-    }
+  errno = 0;
+  regcache_collect (regno, &val);
+  ptrace (PTRACE_POKEUSER, tid, register_addr (regno, 0), val);
+  if (errno != 0)
+    error ("Couldn't read register %s (#%d): %s.", REGISTER_NAME (regno),
+	   regno, safe_strerror (errno));
 }
 
 
@@ -573,16 +488,15 @@ static void dummy_sse_values (void) {}
 int
 cannot_fetch_register (int regno)
 {
-  if (! have_ptrace_getregs)
-    return OLD_CANNOT_FETCH_REGISTER (regno);
-  return 0;
+  gdb_assert (regno >= 0 && regno < NUM_REGS);
+  return (!have_ptrace_getregs && regmap[regno] == -1);
 }
+
 int
 cannot_store_register (int regno)
 {
-  if (! have_ptrace_getregs)
-    return OLD_CANNOT_STORE_REGISTER (regno);
-  return 0;
+  gdb_assert (regno >= 0 && regno < NUM_REGS);
+  return (!have_ptrace_getregs && regmap[regno] == -1);
 }
 
 /* Fetch register REGNO from the child process.  If REGNO is -1, do
@@ -596,9 +510,14 @@ fetch_inferior_registers (int regno)
 
   /* Use the old method of peeking around in `struct user' if the
      GETREGS request isn't available.  */
-  if (! have_ptrace_getregs)
+  if (!have_ptrace_getregs)
     {
-      old_fetch_inferior_registers (regno);
+      int i;
+
+      for (i = 0; i < NUM_REGS; i++)
+	if (regno == -1 || regno == i)
+	  fetch_register (i);
+
       return;
     }
 
@@ -615,9 +534,9 @@ fetch_inferior_registers (int regno)
       fetch_regs (tid);
 
       /* The call above might reset `have_ptrace_getregs'.  */
-      if (! have_ptrace_getregs)
+      if (!have_ptrace_getregs)
 	{
-	  old_fetch_inferior_registers (-1);
+	  fetch_inferior_registers (regno);
 	  return;
 	}
 
@@ -662,9 +581,14 @@ store_inferior_registers (int regno)
 
   /* Use the old method of poking around in `struct user' if the
      SETREGS request isn't available.  */
-  if (! have_ptrace_getregs)
+  if (!have_ptrace_getregs)
     {
-      old_store_inferior_registers (regno);
+      int i;
+
+      for (i = 0; i < NUM_REGS; i++)
+	if (regno == -1 || regno == i)
+	  store_register (i);
+
       return;
     }
 
@@ -724,7 +648,7 @@ i386_linux_dr_get (int regnum)
      stuff to the target vectore.  For now, just return zero if the
      ptrace call fails.  */
   errno = 0;
-  value = ptrace (PT_READ_U, tid,
+  value = ptrace (PTRACE_PEEKUSER, tid,
 		  offsetof (struct user, u_debugreg[regnum]), 0);
   if (errno != 0)
 #if 0
@@ -747,7 +671,7 @@ i386_linux_dr_set (int regnum, unsigned 
   tid = PIDGET (inferior_ptid);
 
   errno = 0;
-  ptrace (PT_WRITE_U, tid,
+  ptrace (PTRACE_POKEUSER, tid,
 	  offsetof (struct user, u_debugreg[regnum]), value);
   if (errno != 0)
     perror_with_name ("Couldn't write debug register");
Index: config/i386/nm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/nm-linux.h,v
retrieving revision 1.18
diff -u -p -r1.18 nm-linux.h
--- config/i386/nm-linux.h 30 Jun 2002 18:43:06 -0000 1.18
+++ config/i386/nm-linux.h 9 Nov 2002 21:29:29 -0000
@@ -39,9 +39,6 @@ extern int kernel_u_size (void);
    the core file of the register values.  */
 #define KERNEL_U_ADDR 0
 
-/* Offset of the registers within the user area.  */
-#define U_REGS_OFFSET 0
-
 extern CORE_ADDR register_u_addr (CORE_ADDR blockend, int regnum);
 #define REGISTER_U_ADDR(addr, blockend, regnum) \
   (addr) = register_u_addr (blockend, regnum)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]