* gdb.threads/linux-dp.exp: Unset 'seen' before 'array set'.
[deliverable/binutils-gdb.git] / gdb / ppc-linux-nat.c
index 6f117152d4563a62e29c5239fdb647a43faa6f14..9bd11fd8bbbe2ce3c4323b014280ca0c060bb78d 100644 (file)
@@ -1,8 +1,7 @@
 /* PPC GNU/Linux native support.
 
-   Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 1988-1989, 1991-1992, 1994, 1996, 2000-2012 Free
+   Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -594,9 +593,10 @@ fetch_register (struct regcache *regcache, int tid, int regno)
        bytes_transferred < register_size (gdbarch, regno);
        bytes_transferred += sizeof (long))
     {
+      long l;
+
       errno = 0;
-      *(long *) &buf[bytes_transferred]
-        = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
+      l = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
       regaddr += sizeof (long);
       if (errno != 0)
        {
@@ -605,6 +605,7 @@ fetch_register (struct regcache *regcache, int tid, int regno)
                   gdbarch_register_name (gdbarch, regno), regno);
          perror_with_name (message);
        }
+      memcpy (&buf[bytes_transferred], &l, sizeof (l));
     }
 
   /* Now supply the register.  Keep in mind that the regcache's idea
@@ -1074,9 +1075,11 @@ store_register (const struct regcache *regcache, int tid, int regno)
 
   for (i = 0; i < bytes_to_transfer; i += sizeof (long))
     {
+      long l;
+
+      memcpy (&l, &buf[i], sizeof (l));
       errno = 0;
-      ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr,
-             *(long *) &buf[i]);
+      ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr, l);
       regaddr += sizeof (long);
 
       if (errno == EIO 
@@ -1348,7 +1351,8 @@ store_ppc_registers (const struct regcache *regcache, int tid)
 }
 
 /* Fetch the AT_HWCAP entry from the aux vector.  */
-unsigned long ppc_linux_get_hwcap (void)
+static unsigned long
+ppc_linux_get_hwcap (void)
 {
   CORE_ADDR field;
 
@@ -1654,7 +1658,6 @@ static int
 ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
                                  struct bp_target_info *bp_tgt)
 {
-  ptid_t ptid;
   struct lwp_info *lp;
   struct ppc_hw_breakpoint p;
 
@@ -1681,8 +1684,8 @@ ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
       p.addr2 = 0;
     }
 
-  ALL_LWPS (lp, ptid)
-    booke_insert_point (&p, TIDGET (ptid));
+  ALL_LWPS (lp)
+    booke_insert_point (&p, TIDGET (lp->ptid));
 
   return 0;
 }
@@ -1691,7 +1694,6 @@ static int
 ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
                                  struct bp_target_info *bp_tgt)
 {
-  ptid_t ptid;
   struct lwp_info *lp;
   struct ppc_hw_breakpoint p;
 
@@ -1718,8 +1720,8 @@ ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
       p.addr2 = 0;
     }
 
-  ALL_LWPS (lp, ptid)
-    booke_remove_point (&p, TIDGET (ptid));
+  ALL_LWPS (lp)
+    booke_remove_point (&p, TIDGET (lp->ptid));
 
   return 0;
 }
@@ -1739,6 +1741,62 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+                                 CORE_ADDR mask, int rw)
+{
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp)
+    booke_insert_point (&p, TIDGET (lp->ptid));
+
+  return 0;
+}
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+                                 CORE_ADDR mask, int rw)
+{
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp)
+    booke_remove_point (&p, TIDGET (lp->ptid));
+
+  return 0;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -1956,7 +2014,8 @@ create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr,
                           int len, int rw, struct expression *cond,
                           int insert)
 {
-  if (len == 1)
+  if (len == 1
+      || !(booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
     {
       int use_condition;
       CORE_ADDR data_value;
@@ -2001,7 +2060,6 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
                             struct expression *cond)
 {
   struct lwp_info *lp;
-  ptid_t ptid;
   int ret = -1;
 
   if (have_ptrace_booke_interface ())
@@ -2010,8 +2068,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
 
       create_watchpoint_request (&p, addr, len, rw, cond, 1);
 
-      ALL_LWPS (lp, ptid)
-       booke_insert_point (&p, TIDGET (ptid));
+      ALL_LWPS (lp)
+       booke_insert_point (&p, TIDGET (lp->ptid));
 
       ret = 0;
     }
@@ -2054,8 +2112,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
 
       saved_dabr_value = dabr_value;
 
-      ALL_LWPS (lp, ptid)
-       if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+      ALL_LWPS (lp)
+       if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (lp->ptid), 0,
                    saved_dabr_value) < 0)
          return -1;
 
@@ -2070,7 +2128,6 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
                             struct expression *cond)
 {
   struct lwp_info *lp;
-  ptid_t ptid;
   int ret = -1;
 
   if (have_ptrace_booke_interface ())
@@ -2079,16 +2136,16 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
 
       create_watchpoint_request (&p, addr, len, rw, cond, 0);
 
-      ALL_LWPS (lp, ptid)
-       booke_remove_point (&p, TIDGET (ptid));
+      ALL_LWPS (lp)
+       booke_remove_point (&p, TIDGET (lp->ptid));
 
       ret = 0;
     }
   else
     {
       saved_dabr_value = 0;
-      ALL_LWPS (lp, ptid)
-       if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
+      ALL_LWPS (lp)
+       if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (lp->ptid), 0,
                    saved_dabr_value) < 0)
          return -1;
 
@@ -2099,9 +2156,9 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
 }
 
 static void
-ppc_linux_new_thread (ptid_t ptid)
+ppc_linux_new_thread (struct lwp_info *lp)
 {
-  int tid = TIDGET (ptid);
+  int tid = TIDGET (lp->ptid);
 
   if (have_ptrace_booke_interface ())
     {
@@ -2161,7 +2218,7 @@ ppc_linux_thread_exit (struct thread_info *tp, int silent)
 static int
 ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
 {
-  struct siginfo *siginfo_p;
+  siginfo_t *siginfo_p;
 
   siginfo_p = linux_nat_get_siginfo (inferior_ptid);
 
@@ -2224,6 +2281,26 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+/* Return the number of registers needed for a masked hardware watchpoint.  */
+
+static int
+ppc_linux_masked_watch_num_registers (struct target_ops *target,
+                                     CORE_ADDR addr, CORE_ADDR mask)
+{
+  if (!have_ptrace_booke_interface ()
+          || (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
+    return -1;
+  else if ((mask & 0xC0000000) != 0xC0000000)
+    {
+      warning (_("The given mask covers kernel address space "
+                "and cannot be used.\n"));
+
+      return -2;
+    }
+  else
+    return 2;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
                                    struct regcache *regcache, int regno)
@@ -2438,11 +2515,14 @@ _initialize_ppc_linux_nat (void)
   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_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+  t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
   t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
   t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
This page took 0.026172 seconds and 4 git commands to generate.