Linux: sys/ptrace.h -> nat/gdb_ptrace.h everywhere
[binutils-gdb.git] / gdb / gdbserver / linux-mips-low.c
index 1010528524b715bf2f6ee1ca384d7ca9b5f63e62..d3b01d61f957025c78a185c4f5a7568eff71a9e2 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU/Linux/MIPS specific low level interface, for the remote server for GDB.
-   Copyright (C) 1995-2013 Free Software Foundation, Inc.
+   Copyright (C) 1995-2015 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "server.h"
 #include "linux-low.h"
 
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
 #include <endian.h>
 
+#include "nat/mips-linux-watch.h"
 #include "gdb_proc_service.h"
 
 /* Defined in auto-generated file mips-linux.c.  */
@@ -125,8 +126,9 @@ mips_read_description (void)
 {
   if (have_dsp < 0)
     {
-      int pid = lwpid_of (get_thread_lwp (current_inferior));
+      int pid = lwpid_of (current_thread);
 
+      errno = 0;
       ptrace (PTRACE_PEEKUSER, pid, DSP_CONTROL, 0);
       switch (errno)
        {
@@ -159,6 +161,39 @@ get_usrregs_info (void)
   return regs_info->usrregs;
 }
 
+/* Per-process arch-specific data we want to keep.  */
+
+struct arch_process_info
+{
+  /* -1 if the kernel and/or CPU do not support watch registers.
+      1 if watch_readback is valid and we can read style, num_valid
+       and the masks.
+      0 if we need to read the watch_readback.  */
+
+  int watch_readback_valid;
+
+  /* Cached watch register read values.  */
+
+  struct pt_watch_regs watch_readback;
+
+  /* Current watchpoint requests for this process.  */
+
+  struct mips_watchpoint *current_watches;
+
+  /* The current set of watch register values for writing the
+     registers.  */
+
+  struct pt_watch_regs watch_mirror;
+};
+
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int watch_registers_changed;
+};
+
 /* From mips-linux-nat.c.  */
 
 /* Pseudo registers can not be read.  ptrace does not provide a way to
@@ -237,7 +272,7 @@ static const unsigned int mips_breakpoint = 0x0005000d;
 static CORE_ADDR
 mips_reinsert_addr (void)
 {
-  struct regcache *regcache = get_thread_regcache (current_inferior, 1);
+  struct regcache *regcache = get_thread_regcache (current_thread, 1);
   union mips_register ra;
   collect_register_by_name (regcache, "r31", ra.buf);
   return register_size (regcache->tdesc, 0) == 4 ? ra.reg32 : ra.reg64;
@@ -257,6 +292,351 @@ mips_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Mark the watch registers of lwp, represented by ENTRY, as changed,
+   if the lwp's process id is *PID_P.  */
+
+static int
+update_watch_registers_callback (struct inferior_list_entry *entry,
+                                void *pid_p)
+{
+  struct thread_info *thread = (struct thread_info *) entry;
+  struct lwp_info *lwp = get_thread_lwp (thread);
+  int pid = *(int *) pid_p;
+
+  /* Only update the threads of this process.  */
+  if (pid_of (thread) == pid)
+    {
+      /* The actual update is done later just before resuming the lwp,
+        we just mark that the registers need updating.  */
+      lwp->arch_private->watch_registers_changed = 1;
+
+      /* If the lwp isn't stopped, force it to momentarily pause, so
+        we can update its watch registers.  */
+      if (!lwp->stopped)
+       linux_stop_lwp (lwp);
+    }
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   new_process.  */
+
+static struct arch_process_info *
+mips_linux_new_process (void)
+{
+  struct arch_process_info *info = xcalloc (1, sizeof (*info));
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method new_thread.
+   Mark the watch registers as changed, so the threads' copies will
+   be updated.  */
+
+static void
+mips_linux_new_thread (struct lwp_info *lwp)
+{
+  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+
+  info->watch_registers_changed = 1;
+
+  lwp->arch_private = info;
+}
+
+/* Create a new mips_watchpoint and add it to the list.  */
+
+static void
+mips_add_watchpoint (struct arch_process_info *private, CORE_ADDR addr,
+                    int len, int watch_type)
+{
+  struct mips_watchpoint *new_watch;
+  struct mips_watchpoint **pw;
+
+  new_watch = xmalloc (sizeof (struct mips_watchpoint));
+  new_watch->addr = addr;
+  new_watch->len = len;
+  new_watch->type = watch_type;
+  new_watch->next = NULL;
+
+  pw = &private->current_watches;
+  while (*pw != NULL)
+    pw = &(*pw)->next;
+  *pw = new_watch;
+}
+
+/* Hook to call when a new fork is attached.  */
+
+static void
+mips_linux_new_fork (struct process_info *parent,
+                       struct process_info *child)
+{
+  struct arch_process_info *parent_private;
+  struct arch_process_info *child_private;
+  struct mips_watchpoint *wp;
+
+  /* These are allocated by linux_add_process.  */
+  gdb_assert (parent->priv != NULL
+             && parent->priv->arch_private != NULL);
+  gdb_assert (child->priv != NULL
+             && child->priv->arch_private != NULL);
+
+  /* Linux kernel before 2.6.33 commit
+     72f674d203cd230426437cdcf7dd6f681dad8b0d
+     will inherit hardware debug registers from parent
+     on fork/vfork/clone.  Newer Linux kernels create such tasks with
+     zeroed debug registers.
+
+     GDB core assumes the child inherits the watchpoints/hw
+     breakpoints of the parent, and will remove them all from the
+     forked off process.  Copy the debug registers mirrors into the
+     new process so that all breakpoints and watchpoints can be
+     removed together.  The debug registers mirror will become zeroed
+     in the end before detaching the forked off process, thus making
+     this compatible with older Linux kernels too.  */
+
+  parent_private = parent->priv->arch_private;
+  child_private = child->priv->arch_private;
+
+  child_private->watch_readback_valid = parent_private->watch_readback_valid;
+  child_private->watch_readback = parent_private->watch_readback;
+
+  for (wp = parent_private->current_watches; wp != NULL; wp = wp->next)
+    mips_add_watchpoint (child_private, wp->addr, wp->len, wp->type);
+
+  child_private->watch_mirror = parent_private->watch_mirror;
+}
+/* This is the implementation of linux_target_ops method
+   prepare_to_resume.  If the watch regs have changed, update the
+   thread's copies.  */
+
+static void
+mips_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  ptid_t ptid = ptid_of (get_lwp_thread (lwp));
+  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
+  struct arch_process_info *priv = proc->priv->arch_private;
+
+  if (lwp->arch_private->watch_registers_changed)
+    {
+      /* Only update the watch registers if we have set or unset a
+        watchpoint already.  */
+      if (mips_linux_watch_get_num_valid (&priv->watch_mirror) > 0)
+       {
+         /* Write the mirrored watch register values.  */
+         int tid = ptid_get_lwp (ptid);
+
+         if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid,
+                           &priv->watch_mirror))
+           perror_with_name ("Couldn't write watch register");
+       }
+
+      lwp->arch_private->watch_registers_changed = 0;
+    }
+}
+
+static int
+mips_supports_z_point_type (char z_type)
+{
+  switch (z_type)
+    {
+    case Z_PACKET_WRITE_WP:
+    case Z_PACKET_READ_WP:
+    case Z_PACKET_ACCESS_WP:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+/* This is the implementation of linux_target_ops method
+   insert_point.  */
+
+static int
+mips_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
+                  int len, struct raw_breakpoint *bp)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *priv = proc->priv->arch_private;
+  struct pt_watch_regs regs;
+  int pid;
+  long lwpid;
+  enum target_hw_bp_type watch_type;
+  uint32_t irw;
+
+  lwpid = lwpid_of (current_thread);
+  if (!mips_linux_read_watch_registers (lwpid,
+                                       &priv->watch_readback,
+                                       &priv->watch_readback_valid,
+                                       0))
+    return -1;
+
+  if (len <= 0)
+    return -1;
+
+  regs = priv->watch_readback;
+  /* Add the current watches.  */
+  mips_linux_watch_populate_regs (priv->current_watches, &regs);
+
+  /* Now try to add the new watch.  */
+  watch_type = raw_bkpt_type_to_target_hw_bp_type (type);
+  irw = mips_linux_watch_type_to_irw (watch_type);
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len, irw))
+    return -1;
+
+  /* It fit.  Stick it on the end of the list.  */
+  mips_add_watchpoint (priv, addr, len, watch_type);
+
+  priv->watch_mirror = regs;
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_threads, update_watch_registers_callback, &pid);
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   remove_point.  */
+
+static int
+mips_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
+                  int len, struct raw_breakpoint *bp)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *priv = proc->priv->arch_private;
+
+  int deleted_one;
+  int pid;
+  enum target_hw_bp_type watch_type;
+
+  struct mips_watchpoint **pw;
+  struct mips_watchpoint *w;
+
+  /* Search for a known watch that matches.  Then unlink and free it.  */
+  watch_type = raw_bkpt_type_to_target_hw_bp_type (type);
+  deleted_one = 0;
+  pw = &priv->current_watches;
+  while ((w = *pw))
+    {
+      if (w->addr == addr && w->len == len && w->type == watch_type)
+       {
+         *pw = w->next;
+         free (w);
+         deleted_one = 1;
+         break;
+       }
+      pw = &(w->next);
+    }
+
+  if (!deleted_one)
+    return -1;  /* We don't know about it, fail doing nothing.  */
+
+  /* At this point watch_readback is known to be valid because we
+     could not have added the watch without reading it.  */
+  gdb_assert (priv->watch_readback_valid == 1);
+
+  priv->watch_mirror = priv->watch_readback;
+  mips_linux_watch_populate_regs (priv->current_watches,
+                                 &priv->watch_mirror);
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_threads, update_watch_registers_callback, &pid);
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_by_watchpoint.  The watchhi R and W bits indicate
+   the watch register triggered. */
+
+static int
+mips_stopped_by_watchpoint (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *priv = proc->priv->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (current_thread);
+
+  if (!mips_linux_read_watch_registers (lwpid,
+                                       &priv->watch_readback,
+                                       &priv->watch_readback_valid,
+                                       1))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&priv->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&priv->watch_readback, n)
+       & (R_MASK | W_MASK))
+      return 1;
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_data_address.  */
+
+static CORE_ADDR
+mips_stopped_data_address (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *priv = proc->priv->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (current_thread);
+
+  /* On MIPS we don't know the low order 3 bits of the data address.
+     GDB does not support remote targets that can't report the
+     watchpoint address.  So, make our best guess; return the starting
+     address of a watchpoint request which overlaps the one that
+     triggered.  */
+
+  if (!mips_linux_read_watch_registers (lwpid,
+                                       &priv->watch_readback,
+                                       &priv->watch_readback_valid,
+                                       0))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&priv->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&priv->watch_readback, n)
+       & (R_MASK | W_MASK))
+      {
+       CORE_ADDR t_low, t_hi;
+       int t_irw;
+       struct mips_watchpoint *watch;
+
+       t_low = mips_linux_watch_get_watchlo (&priv->watch_readback, n);
+       t_irw = t_low & IRW_MASK;
+       t_hi = (mips_linux_watch_get_watchhi (&priv->watch_readback, n)
+               | IRW_MASK);
+       t_low &= ~(CORE_ADDR)t_hi;
+
+       for (watch = priv->current_watches;
+            watch != NULL;
+            watch = watch->next)
+         {
+           CORE_ADDR addr = watch->addr;
+           CORE_ADDR last_byte = addr + watch->len - 1;
+
+           if ((t_irw & mips_linux_watch_type_to_irw (watch->type)) == 0)
+             {
+               /* Different type.  */
+               continue;
+             }
+           /* Check for overlap of even a single byte.  */
+           if (last_byte >= t_low && addr <= t_low + t_hi)
+             return addr;
+         }
+      }
+
+  /* Shouldn't happen.  */
+  return 0;
+}
+
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -506,6 +886,18 @@ struct linux_target_ops the_low_target = {
   mips_reinsert_addr,
   0,
   mips_breakpoint_at,
+  mips_supports_z_point_type,
+  mips_insert_point,
+  mips_remove_point,
+  mips_stopped_by_watchpoint,
+  mips_stopped_data_address,
+  NULL,
+  NULL,
+  NULL, /* siginfo_fixup */
+  mips_linux_new_process,
+  mips_linux_new_thread,
+  mips_linux_new_fork,
+  mips_linux_prepare_to_resume
 };
 
 void