oops - omitted from previous delta
[deliverable/binutils-gdb.git] / gdb / i386v-nat.c
index f43b87eb52fd75e1f45bf3987edcf25256841bed..678eabc346d9a56601f3ac4f346bd4f88ec16113 100644 (file)
@@ -1,23 +1,35 @@
-/* Intel 386 native support.
-   Copyright (C) 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
+/* Intel 386 native support for System V systems (pre-SVR4).
 
-This file is part of GDB.
+   Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+   1999, 2000, 2002 Free Software Foundation, Inc.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This file is part of GDB.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
+
+#ifdef HAVE_PTRACE_H
+#include <ptrace.h>
+#else
+#ifdef HAVE_SYS_PTRACE_H
+#include <sys/ptrace.h>
+#endif
+#endif
+
 #include "frame.h"
 #include "inferior.h"
 #include "language.h"
@@ -34,19 +46,27 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/ioctl.h>
 #include <fcntl.h>
 
+#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
+#include <sys/debugreg.h>
+#endif
+
 #include <sys/file.h>
-#include <sys/stat.h>
+#include "gdb_stat.h"
 
+#ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
-#include "ieee-float.h"
+#endif
+
+#include "floatformat.h"
 
 #include "target.h"
 
-extern struct ext_format ext_format_i387;
+#include "i386-tdep.h"
 \f
-/* this table must line up with REGISTER_NAMES in tm-i386v.h */
-/* symbols like 'EAX' come from <sys/reg.h> */
-static int regmap[] = 
+
+/* Mapping between the general-purpose registers in `struct user'
+   format and GDB's register array layout.  */
+static int regmap[] =
 {
   EAX, ECX, EDX, EBX,
   UESP, EBP, ESI, EDI,
@@ -54,115 +74,204 @@ static int regmap[] =
   DS, ES, FS, GS,
 };
 
-/* blockend is the value of u.u_ar0, and points to the
- * place where GS is stored
- */
+/* Support for the user struct.  */
 
-int
-i386_register_u_addr (blockend, regnum)
-     int blockend;
-     int regnum;
+/* Return the address of register REGNUM.  BLOCKEND is the value of
+   u.u_ar0, and points to the place where GS is stored.  */
+
+CORE_ADDR
+register_u_addr (CORE_ADDR blockend, int regnum)
 {
-#if 0
-  /* this will be needed if fp registers are reinstated */
-  /* for now, you can look at them with 'info float'
-   * sys5 wont let you change them with ptrace anyway
-   */
-  if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) 
+  struct user u;
+  CORE_ADDR fpstate;
+
+  if (i386_fp_regnum_p (regnum))
     {
-      int ubase, fpstate;
-      struct user u;
-      ubase = blockend + 4 * (SS + 1) - KSTKSZ;
-      fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
+#ifdef KSTKSZ                  /* SCO, and others?  */
+      blockend += 4 * (SS + 1) - KSTKSZ;
+      fpstate = blockend + ((char *) &u.u_fps.u_fpstate - (char *) &u);
       return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
-    } 
-  else
+#else
+      fpstate = blockend + ((char *) &u.i387.st_space - (char *) &u);
+      return (fpstate + 10 * (regnum - FP0_REGNUM));
 #endif
-    return (blockend + 4 * regmap[regnum]);
-  
+    }
+
+  return (blockend + 4 * regmap[regnum]);
+}
+
+/* Return the size of the user struct.  */
+
+int
+kernel_u_size (void)
+{
+  return (sizeof (struct user));
 }
+\f
+#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* Record the value of the debug control register.  */
+static int debug_control_mirror;
+
+/* Record which address associates with which register.  */
+static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1];
 
-#if 0
-/* using FLOAT_INFO as is would be a problem.  FLOAT_INFO is called
-   via a command xxx and eventually calls ptrace without ever having
-   traversed the target vector.  This would be terribly impolite
-   behaviour for a sun4 hosted remote gdb.
+static int i386_insert_aligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
+                                          int);
 
-   A fix might be to move this code into the "info registers" command.
-   rich@cygnus.com 15 Sept 92. */
-i386_float_info ()
+static int i386_insert_nonaligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
+                                             int);
+
+/* Insert a watchpoint.  */
+
+int
+i386_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
+{
+  return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw);
+}
+
+static int
+i386_insert_aligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
+                               int len, int rw)
 {
-  struct user u; /* just for address computations */
   int i;
-  /* fpstate defined in <sys/user.h> */
-  struct fpstate *fpstatep;
-  char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
-  unsigned int uaddr;
-  char fpvalid = 0;
-  unsigned int rounded_addr;
-  unsigned int rounded_size;
-  extern int corechan;
-  int skip;
-  
-  uaddr = (char *)&u.u_fpvalid - (char *)&u;
-  if (target_has_execution)
+  int read_write_bits, len_bits;
+  int free_debug_register;
+  int register_number;
+
+  /* Look for a free debug register.  */
+  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+    {
+      if (address_lookup[i - DR_FIRSTADDR] == 0)
+       break;
+    }
+
+  /* No more debug registers!  */
+  if (i > DR_LASTADDR)
+    return -1;
+
+  read_write_bits = (rw & 1) ? DR_RW_READ : DR_RW_WRITE;
+
+  if (len == 1)
+    len_bits = DR_LEN_1;
+  else if (len == 2)
     {
-      unsigned int data;
-      unsigned int mask;
-      
-      rounded_addr = uaddr & -sizeof (int);
-      data = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0);
-      mask = 0xff << ((uaddr - rounded_addr) * 8);
-      
-      fpvalid = ((data & mask) != 0);
-    } 
-#if 0
-  else 
+      if (addr % 2)
+       return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
+      len_bits = DR_LEN_2;
+    }
+
+  else if (len == 4)
     {
-      if (lseek (corechan, uaddr, 0) < 0)
-       perror ("seek on core file");
-      if (myread (corechan, &fpvalid, 1) < 0) 
-       perror ("read on core file");
-      
+      if (addr % 4)
+       return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
+      len_bits = DR_LEN_4;
     }
-#endif /* no core support yet */
-  
-  if (fpvalid == 0) 
+  else
+    return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
+
+  free_debug_register = i;
+  register_number = free_debug_register - DR_FIRSTADDR;
+  debug_control_mirror |=
+    ((read_write_bits | len_bits)
+     << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number));
+  debug_control_mirror |=
+    (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
+  debug_control_mirror |= DR_LOCAL_SLOWDOWN;
+  debug_control_mirror &= ~DR_CONTROL_RESERVED;
+
+  ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
+         debug_control_mirror);
+  ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]),
+         addr);
+
+  /* Record where we came from.  */
+  address_lookup[register_number] = addr;
+  return 0;
+}
+
+static int
+i386_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
+                                  int len, int rw)
+{
+  int align;
+  int size;
+  int rv;
+
+  static int size_try_array[4][4] =
+  {
+    { 1, 1, 1, 1 },            /* trying size one */
+    { 2, 1, 2, 1 },            /* trying size two */
+    { 2, 1, 2, 1 },            /* trying size three */
+    { 4, 1, 2, 1 }             /* trying size four */
+  };
+
+  rv = 0;
+  while (len > 0)
     {
-      printf ("no floating point status saved\n");
-      return;
+      align = addr % 4;
+      /* Four is the maximum length for 386.  */
+      size = size_try_array[len > 4 ? 3 : len - 1][align];
+
+      rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
+      if (rv)
+       {
+         i386_remove_watchpoint (pid, waddr, size);
+         return rv;
+       }
+      addr += size;
+      len -= size;
     }
-  
-  uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
-  if (target_has_execution)
+  return rv;
+}
+
+/* Remove a watchpoint.  */
+
+int
+i386_remove_watchpoint (int pid, CORE_ADDR addr, int len)
+{
+  int i;
+  int register_number;
+
+  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
     {
-      int *ip;
-      
-      rounded_addr = uaddr & -sizeof (int);
-      rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
-                     sizeof (int) - 1) / sizeof (int);
-      skip = uaddr - rounded_addr;
-      
-      ip = (int *)buf;
-      for (i = 0; i < rounded_size; i++) 
+      register_number = i - DR_FIRSTADDR;
+      if (address_lookup[register_number] == addr)
        {
-         *ip++ = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0);
-         rounded_addr += sizeof (int);
+         debug_control_mirror &=
+           ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
+         address_lookup[register_number] = 0;
        }
-    } 
-#if 0
-  else 
+    }
+  ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
+         debug_control_mirror);
+  ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
+
+  return 0;
+}
+
+/* Check if stopped by a watchpoint.  */
+
+CORE_ADDR
+i386_stopped_by_watchpoint (int pid)
+{
+  int i;
+  int status;
+
+  status = ptrace (3, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
+  ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
+
+  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
     {
-      if (lseek (corechan, uaddr, 0) < 0)
-       perror_with_name ("seek on core file");
-      if (myread (corechan, buf, sizeof (struct fpstate)) < 0) 
-       perror_with_name ("read from core file");
-      skip = 0;
+      if (status & (1 << (i - DR_FIRSTADDR)))
+       return address_lookup[i - DR_FIRSTADDR];
     }
- #endif        /* 0 */ 
 
-  fpstatep = (struct fpstate *)(buf + skip);
-  print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
+  return 0;
 }
 
-#endif /* never */
+#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */
This page took 0.02909 seconds and 4 git commands to generate.