* ppc-linux-nat.c (PTRACE_GET_DEBUGREG, PTRACE_SET_DEBUGREG,
authorWu Zhou <woodzltc@cn.ibm.com>
Wed, 8 Feb 2006 05:41:06 +0000 (05:41 +0000)
committerWu Zhou <woodzltc@cn.ibm.com>
Wed, 8 Feb 2006 05:41:06 +0000 (05:41 +0000)
PTRACE_GETSIGINFO): Define.
(last_stopped_data_address): New.
(ppc_linux_check_watch_resources): New function.
(ppc_linux_region_ok_for_hw_watchpoint): New function.
(ppc_linux_insert_watchpoint): New function.
(ppc_linux_remove_watchpoint): New function.
(ppc_linux_stopped_data_address): New function.
(ppc_linux_stopped_by_watchpoint): New function.
(_initialize_ppc_linux_nat): Set the above hardware watchpoint
related target vectors.
* rs6000-tdep.c (rs6000_gdbarch_init): Set PPC architectures
to have nonsteppable watchpoint.
* target.c (default_region_ok_for_hw_watchpoint,
debug_to_region_ok_for_hw_watchpoint): New prototypes.
(update_current_target): Inherit to_region_ok_for_hw_watchpoint
and set default to_region_ok_for_hw_watchpoint.
(default_region_ok_for_hw_watchpoint): New function.
(debug_to_region_ok_for_hw_watchpoint): New function.
(setup_target_debug): Set to_region_ok_for_hw_watchpoint of
debug_target.
* target.h (struct target_ops): Add a new target vector
to_region_ok_for_hw_watchpoint.
(TARGET_REGION_OK_FOR_HW_WATCHPOINT): Define this if it is not
defined anyplace else.

gdb/ChangeLog
gdb/ppc-linux-nat.c
gdb/rs6000-tdep.c
gdb/target.c
gdb/target.h

index 2a51386ae95839ecf1b1aec5afdfcf86e702ba7a..679131a9dce57ea664bd54945fa57e6787e14670 100644 (file)
@@ -1,5 +1,33 @@
-2005-02-07  Joel Brobecker  <brobecker@adacore.com>
+2006-02-08  Ben Elliston  <bje@au1.ibm.com>
+           Wu Zhou  <woodzltc@cn.ibm.com>
+
+       * ppc-linux-nat.c (PTRACE_GET_DEBUGREG, PTRACE_SET_DEBUGREG,
+       PTRACE_GETSIGINFO): Define.
+       (last_stopped_data_address): New.
+       (ppc_linux_check_watch_resources): New function.
+       (ppc_linux_region_ok_for_hw_watchpoint): New function.
+       (ppc_linux_insert_watchpoint): New function.
+       (ppc_linux_remove_watchpoint): New function.
+       (ppc_linux_stopped_data_address): New function.
+       (ppc_linux_stopped_by_watchpoint): New function.
+       (_initialize_ppc_linux_nat): Set the above hardware watchpoint
+       related target vectors.
+       * rs6000-tdep.c (rs6000_gdbarch_init): Set PPC architectures
+       to have nonsteppable watchpoint.
+       * target.c (default_region_ok_for_hw_watchpoint,
+       debug_to_region_ok_for_hw_watchpoint): New prototypes.
+       (update_current_target): Inherit to_region_ok_for_hw_watchpoint
+       and set default to_region_ok_for_hw_watchpoint.
+       (default_region_ok_for_hw_watchpoint): New function.
+       (debug_to_region_ok_for_hw_watchpoint): New function.
+       (setup_target_debug): Set to_region_ok_for_hw_watchpoint of 
+       debug_target.
+       * target.h (struct target_ops): Add a new target vector 
+       to_region_ok_for_hw_watchpoint.
+       (TARGET_REGION_OK_FOR_HW_WATCHPOINT): Define this if it is not
+       defined anyplace else.
 
+2005-02-07  Joel Brobecker  <brobecker@adacore.com>
        * symfile.c (add_symbol_file_command): Abort if the user forgot
        to provide the address when the file has been loaded.
 
index c8c9376310c1f1d93870dec49418f61618efa592..b52eca2969c156f70f655ab89253892ab9f76cea 100644 (file)
 #define PTRACE_SETEVRREGS 21
 #endif
 
+/* Similarly for the hardware watchpoint support.  */
+#ifndef PTRACE_GET_DEBUGREG
+#define PTRACE_GET_DEBUGREG    25
+#endif
+#ifndef PTRACE_SET_DEBUGREG
+#define PTRACE_SET_DEBUGREG    26
+#endif
+#ifndef PTRACE_GETSIGINFO
+#define PTRACE_GETSIGINFO    0x4202
+#endif
 
 /* This oddity is because the Linux kernel defines elf_vrregset_t as
    an array of 33 16 bytes long elements.  I.e. it leaves out vrsave.
@@ -146,6 +156,7 @@ struct gdb_evrregset_t
    error.  */
 int have_ptrace_getvrregs = 1;
 
+static CORE_ADDR last_stopped_data_address = 0;
 
 /* Non-zero if our kernel may support the PTRACE_GETEVRREGS and
    PTRACE_SETEVRREGS requests, for reading and writing the SPE
@@ -153,7 +164,6 @@ int have_ptrace_getvrregs = 1;
    error.  */
 int have_ptrace_getsetevrregs = 1;
 
-
 int
 kernel_u_size (void)
 {
@@ -777,6 +787,124 @@ store_ppc_registers (int tid)
     store_spe_register (tid, -1);
 }
 
+static int
+ppc_linux_check_watch_resources (int type, int cnt, int ot)
+{
+  int tid;
+  ptid_t ptid = inferior_ptid;
+
+  /* DABR (data address breakpoint register) is optional for PPC variants.
+     Some variants have one DABR, others have none.  So CNT can't be larger
+     than 1.  */
+  if (cnt > 1)
+    return 0;
+
+  /* We need to know whether ptrace supports PTRACE_SET_DEBUGREG and whether
+     the target has DABR.  If either answer is no, the ptrace call will
+     return -1.  Fail in that case.  */
+  tid = TIDGET (ptid);
+  if (tid == 0)
+    tid = PIDGET (ptid);
+
+  if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0) == -1)
+    return 0;
+  return 1;
+}
+
+static int
+ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+  /* Handle sub-8-byte quantities.  */
+  if (len <= 0)
+    return 0;
+
+  /* addr+len must fall in the 8 byte watchable region.  */
+  if ((addr + len) > (addr & ~7) + 8)
+    return 0;
+
+  return 1;
+}
+
+/* Set a watchpoint of type TYPE at address ADDR.  */
+static long
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+  int tid;
+  long dabr_value;
+  ptid_t ptid = inferior_ptid;
+
+  dabr_value = addr & ~7;
+  switch (rw)
+    {
+    case hw_read:
+      /* Set read and translate bits.  */
+      dabr_value |= 5;
+      break;
+    case hw_write:
+      /* Set write and translate bits.  */
+      dabr_value |= 6;
+      break;
+    case hw_access:
+      /* Set read, write and translate bits.  */
+      dabr_value |= 7;
+      break;
+    }
+
+  tid = TIDGET (ptid);
+  if (tid == 0)
+    tid = PIDGET (ptid);
+
+  return ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value);
+}
+
+static long
+ppc_linux_remove_watchpoint (CORE_ADDR addr, int len)
+{
+  int tid;
+  ptid_t ptid = inferior_ptid;
+
+  tid = TIDGET (ptid);
+  if (tid == 0)
+    tid = PIDGET (ptid);
+
+  return ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0);
+}
+
+static int
+ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
+{
+  if (last_stopped_data_address)
+    {
+      *addr_p = last_stopped_data_address;
+      last_stopped_data_address = 0;
+      return 1;
+    }
+  return 0;
+}
+
+static int
+ppc_linux_stopped_by_watchpoint (void)
+{
+  int tid;
+  struct siginfo siginfo;
+  ptid_t ptid = inferior_ptid;
+  CORE_ADDR *addr_p;
+
+  tid = TIDGET(ptid);
+  if (tid == 0)
+    tid = PIDGET (ptid);
+
+  errno = 0;
+  ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+
+  if (errno != 0 || siginfo.si_signo != SIGTRAP ||
+      (siginfo.si_code & 0xffff) != 0x0004)
+    return 0;
+
+  last_stopped_data_address = (CORE_ADDR) siginfo.si_addr;
+  return 1;
+}
+
 static void
 ppc_linux_store_inferior_registers (int regno)
 {
@@ -900,6 +1028,14 @@ _initialize_ppc_linux_nat (void)
   t->to_fetch_registers = ppc_linux_fetch_inferior_registers;
   t->to_store_registers = ppc_linux_store_inferior_registers;
 
+  /* Add our watchpoint methods.  */
+  t->to_can_use_hw_breakpoint = ppc_linux_check_watch_resources;
+  t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+  t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
+  t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+  t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
+  t->to_stopped_data_address = ppc_linux_stopped_data_address;
+
   /* Register the target.  */
   add_target (t);
 }
index 1d4a437ac599e18336984cb79aa43bcb46d34951..19a4bc9d0d03cda2aaae05fc82f43ed847079eae 100644 (file)
@@ -3387,6 +3387,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                     _("rs6000_gdbarch_init: "
                     "received unexpected BFD 'arch' value"));
 
+  set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
   /* Sanity check on registers.  */
   gdb_assert (strcmp (tdep->regs[tdep->ppc_gp0_regnum].name, "r0") == 0);
 
index 81f8716d353c9f69a39e8bcb924c22826e030a6e..d542bbf1c1047a0b4b5aee0ea6a71a8d522d8f39 100644 (file)
@@ -48,6 +48,8 @@ static void kill_or_be_killed (int);
 
 static void default_terminal_info (char *, int);
 
+static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+
 static int default_region_size_ok_for_hw_watchpoint (int);
 
 static int nosymbol (char *, CORE_ADDR *);
@@ -129,6 +131,8 @@ static int debug_to_stopped_by_watchpoint (void);
 
 static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *);
 
+static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+
 static int debug_to_region_size_ok_for_hw_watchpoint (int);
 
 static void debug_to_terminal_init (void);
@@ -406,6 +410,7 @@ update_current_target (void)
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_stopped_by_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
+      INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_region_size_ok_for_hw_watchpoint, t);
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
@@ -532,6 +537,8 @@ update_current_target (void)
   de_fault (to_stopped_data_address,
            (int (*) (struct target_ops *, CORE_ADDR *))
            return_zero);
+  de_fault (to_region_ok_for_hw_watchpoint,
+           default_region_ok_for_hw_watchpoint);
   de_fault (to_region_size_ok_for_hw_watchpoint,
            default_region_size_ok_for_hw_watchpoint);
   de_fault (to_terminal_init, 
@@ -1578,6 +1585,12 @@ find_default_create_inferior (char *exec_file, char *allargs, char **env,
   return;
 }
 
+static int
+default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+  return TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT (len);
+}
+
 static int
 default_region_size_ok_for_hw_watchpoint (int byte_count)
 {
@@ -2118,6 +2131,21 @@ debug_to_can_use_hw_breakpoint (int type, int cnt, int from_tty)
   return retval;
 }
 
+static int
+debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+  CORE_ADDR retval;
+
+  retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len);
+
+  fprintf_unfiltered (gdb_stdlog,
+                     "TARGET_REGION_OK_FOR_HW_WATCHPOINT (%ld, %ld) = 0x%lx\n",
+                     (unsigned long) addr,
+                     (unsigned long) len,
+                     (unsigned long) retval);
+  return retval;
+}
+
 static int
 debug_to_region_size_ok_for_hw_watchpoint (int byte_count)
 {
@@ -2537,6 +2565,7 @@ setup_target_debug (void)
   current_target.to_remove_watchpoint = debug_to_remove_watchpoint;
   current_target.to_stopped_by_watchpoint = debug_to_stopped_by_watchpoint;
   current_target.to_stopped_data_address = debug_to_stopped_data_address;
+  current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint;
   current_target.to_region_size_ok_for_hw_watchpoint = debug_to_region_size_ok_for_hw_watchpoint;
   current_target.to_terminal_init = debug_to_terminal_init;
   current_target.to_terminal_inferior = debug_to_terminal_inferior;
index 9bb31f984ab29b2f0d5646df6f085e28c24fe7fb..7a72c3668091b54526b23b14c2cec6a402e7e5b5 100644 (file)
@@ -346,6 +346,7 @@ struct target_ops
     int (*to_stopped_by_watchpoint) (void);
     int to_have_continuable_watchpoint;
     int (*to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
+    int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
     int (*to_region_size_ok_for_hw_watchpoint) (int);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
@@ -1031,6 +1032,11 @@ extern void (*deprecated_target_new_objfile_hook) (struct objfile *);
  (*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE);
 #endif
 
+#ifndef TARGET_REGION_OK_FOR_HW_WATCHPOINT
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr, len) \
+    (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
+#endif
+
 #if !defined(TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT)
 #define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(byte_count) \
     (*current_target.to_region_size_ok_for_hw_watchpoint) (byte_count)