Revert 'Remove unused struct serial::name field'
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-mips-low.c
index 0fc8cb4c844edf801c0f9140a889d46c8ffa34a8..f94e141be79ffcd472a65f752adef14bb30ba1df 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU/Linux/MIPS specific low level interface, for the remote server for GDB.
-   Copyright (C) 1995-2014 Free Software Foundation, Inc.
+   Copyright (C) 1995-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -19,7 +19,7 @@
 #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"
@@ -198,8 +198,8 @@ struct arch_lwp_info
 
 /* Pseudo registers can not be read.  ptrace does not provide a way to
    read (or set) PS_REGNUM, and there's no point in reading or setting
-   ZERO_REGNUM.  We also can not set BADVADDR, CAUSE, or FCRIR via
-   ptrace().  */
+   ZERO_REGNUM, it's always 0.  We also can not set BADVADDR, CAUSE,
+   or FCRIR via ptrace().  */
 
 static int
 mips_cannot_fetch_register (int regno)
@@ -211,6 +211,10 @@ mips_cannot_fetch_register (int regno)
 
   tdesc = current_process ()->tdesc;
 
+  /* On n32 we can't access 64-bit registers via PTRACE_PEEKUSR.  */
+  if (register_size (tdesc, regno) > sizeof (PTRACE_XFER_TYPE))
+    return 1;
+
   if (find_regno (tdesc, "r0") == regno)
     return 1;
 
@@ -227,6 +231,10 @@ mips_cannot_store_register (int regno)
 
   tdesc = current_process ()->tdesc;
 
+  /* On n32 we can't access 64-bit registers via PTRACE_POKEUSR.  */
+  if (register_size (tdesc, regno) > sizeof (PTRACE_XFER_TYPE))
+    return 1;
+
   if (find_regno (tdesc, "r0") == regno)
     return 1;
 
@@ -242,6 +250,20 @@ mips_cannot_store_register (int regno)
   return 0;
 }
 
+static int
+mips_fetch_register (struct regcache *regcache, int regno)
+{
+  const struct target_desc *tdesc = current_process ()->tdesc;
+
+  if (find_regno (tdesc, "r0") == regno)
+    {
+      supply_register_zeroed (regcache, regno);
+      return 1;
+    }
+
+  return 0;
+}
+
 static CORE_ADDR
 mips_get_pc (struct regcache *regcache)
 {
@@ -266,16 +288,13 @@ mips_set_pc (struct regcache *regcache, CORE_ADDR pc)
 static const unsigned int mips_breakpoint = 0x0005000d;
 #define mips_breakpoint_len 4
 
-/* We only place breakpoints in empty marker functions, and thread locking
-   is outside of the function.  So rather than importing software single-step,
-   we can just run until exit.  */
-static CORE_ADDR
-mips_reinsert_addr (void)
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+mips_sw_breakpoint_from_kind (int kind, int *size)
 {
-  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;
+  *size = mips_breakpoint_len;
+  return (const gdb_byte *) &mips_breakpoint;
 }
 
 static int
@@ -292,31 +311,21 @@ 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.  */
+/* Mark the watch registers of lwp, represented by ENTRY, as changed.  */
 
-static int
-update_watch_registers_callback (struct inferior_list_entry *entry,
-                                void *pid_p)
+static void
+update_watch_registers_callback (thread_info *thread)
 {
-  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);
-    }
+  /* 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;
 
-  return 0;
+  /* 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);
 }
 
 /* This is the implementation of linux_target_ops method
@@ -325,25 +334,104 @@ update_watch_registers_callback (struct inferior_list_entry *entry,
 static struct arch_process_info *
 mips_linux_new_process (void)
 {
-  struct arch_process_info *info = xcalloc (1, sizeof (*info));
+  struct arch_process_info *info = XCNEW (struct arch_process_info);
 
   return info;
 }
 
+/* This is the implementation of linux_target_ops method
+   delete_process.  */
+
+static void
+mips_linux_delete_process (struct arch_process_info *info)
+{
+  xfree (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 struct arch_lwp_info *
-mips_linux_new_thread (void)
+static void
+mips_linux_new_thread (struct lwp_info *lwp)
 {
-  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
   info->watch_registers_changed = 1;
 
-  return info;
+  lwp->arch_private = info;
+}
+
+/* Function to call when a thread is being deleted.  */
+
+static void
+mips_linux_delete_thread (struct arch_lwp_info *arch_lwp)
+{
+  xfree (arch_lwp);
 }
 
+/* Create a new mips_watchpoint and add it to the list.  */
+
+static void
+mips_add_watchpoint (struct arch_process_info *priv, CORE_ADDR addr, int len,
+                    enum target_hw_bp_type watch_type)
+{
+  struct mips_watchpoint *new_watch;
+  struct mips_watchpoint **pw;
+
+  new_watch = XNEW (struct mips_watchpoint);
+  new_watch->addr = addr;
+  new_watch->len = len;
+  new_watch->type = watch_type;
+  new_watch->next = NULL;
+
+  pw = &priv->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.  */
@@ -352,20 +440,20 @@ 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 *private = proc->private->arch_private;
+  struct process_info *proc = find_process_pid (ptid.pid ());
+  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 (&private->watch_mirror) > 0)
+      if (mips_linux_watch_get_num_valid (&priv->watch_mirror) > 0)
        {
          /* Write the mirrored watch register values.  */
-         int tid = ptid_get_lwp (ptid);
+         int tid = ptid.lwp ();
 
          if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid,
-                           &private->watch_mirror))
+                           &priv->watch_mirror, NULL))
            perror_with_name ("Couldn't write watch register");
        }
 
@@ -395,28 +483,25 @@ 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 *private = proc->private->arch_private;
+  struct arch_process_info *priv = proc->priv->arch_private;
   struct pt_watch_regs regs;
-  struct mips_watchpoint *new_watch;
-  struct mips_watchpoint **pw;
-  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,
-                                       &private->watch_readback,
-                                       &private->watch_readback_valid,
+                                       &priv->watch_readback,
+                                       &priv->watch_readback_valid,
                                        0))
     return -1;
 
   if (len <= 0)
     return -1;
 
-  regs = private->watch_readback;
+  regs = priv->watch_readback;
   /* Add the current watches.  */
-  mips_linux_watch_populate_regs (private->current_watches, &regs);
+  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);
@@ -425,22 +510,12 @@ mips_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
     return -1;
 
   /* It fit.  Stick it on the end of the list.  */
-  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;
+  mips_add_watchpoint (priv, addr, len, watch_type);
 
-  private->watch_mirror = regs;
+  priv->watch_mirror = regs;
 
   /* Only update the threads of this process.  */
-  pid = pid_of (proc);
-  find_inferior (&all_threads, update_watch_registers_callback, &pid);
+  for_each_thread (proc->pid, update_watch_registers_callback);
 
   return 0;
 }
@@ -453,10 +528,9 @@ 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 *private = proc->private->arch_private;
+  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;
@@ -465,7 +539,7 @@ mips_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
   /* 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 = &private->current_watches;
+  pw = &priv->current_watches;
   while ((w = *pw))
     {
       if (w->addr == addr && w->len == len && w->type == watch_type)
@@ -483,15 +557,15 @@ mips_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
 
   /* At this point watch_readback is known to be valid because we
      could not have added the watch without reading it.  */
-  gdb_assert (private->watch_readback_valid == 1);
+  gdb_assert (priv->watch_readback_valid == 1);
 
-  private->watch_mirror = private->watch_readback;
-  mips_linux_watch_populate_regs (private->current_watches,
-                                 &private->watch_mirror);
+  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);
+  for_each_thread (proc->pid, update_watch_registers_callback);
+
   return 0;
 }
 
@@ -503,21 +577,21 @@ static int
 mips_stopped_by_watchpoint (void)
 {
   struct process_info *proc = current_process ();
-  struct arch_process_info *private = proc->private->arch_private;
+  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,
-                                       &private->watch_readback,
-                                       &private->watch_readback_valid,
+                                       &priv->watch_readback,
+                                       &priv->watch_readback_valid,
                                        1))
     return 0;
 
-  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+  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 (&private->watch_readback, n)
+    if (mips_linux_watch_get_watchhi (&priv->watch_readback, n)
        & (R_MASK | W_MASK))
       return 1;
 
@@ -531,7 +605,7 @@ static CORE_ADDR
 mips_stopped_data_address (void)
 {
   struct process_info *proc = current_process ();
-  struct arch_process_info *private = proc->private->arch_private;
+  struct arch_process_info *priv = proc->priv->arch_private;
   int n;
   int num_valid;
   long lwpid = lwpid_of (current_thread);
@@ -543,28 +617,28 @@ mips_stopped_data_address (void)
      triggered.  */
 
   if (!mips_linux_read_watch_registers (lwpid,
-                                       &private->watch_readback,
-                                       &private->watch_readback_valid,
+                                       &priv->watch_readback,
+                                       &priv->watch_readback_valid,
                                        0))
     return 0;
 
-  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+  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 (&private->watch_readback, 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 (&private->watch_readback, n);
+       t_low = mips_linux_watch_get_watchlo (&priv->watch_readback, n);
        t_irw = t_low & IRW_MASK;
-       t_hi = (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+       t_hi = (mips_linux_watch_get_watchhi (&priv->watch_readback, n)
                | IRW_MASK);
        t_low &= ~(CORE_ADDR)t_hi;
 
-       for (watch = private->current_watches;
+       for (watch = priv->current_watches;
             watch != NULL;
             watch = watch->next)
          {
@@ -589,7 +663,7 @@ mips_stopped_data_address (void)
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
-ps_get_thread_area (const struct ps_prochandle *ph,
+ps_get_thread_area (struct ps_prochandle *ph,
                    lwpid_t lwpid, int idx, void **base)
 {
   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
@@ -603,8 +677,6 @@ ps_get_thread_area (const struct ps_prochandle *ph,
   return PS_OK;
 }
 
-#ifdef HAVE_PTRACE_GETREGS
-
 static void
 mips_collect_register (struct regcache *regcache,
                       int use_64bit, int regno, union mips_register *reg)
@@ -637,6 +709,8 @@ mips_supply_register (struct regcache *regcache,
   supply_register (regcache, regno, reg->buf + offset);
 }
 
+#ifdef HAVE_PTRACE_GETREGS
+
 static void
 mips_collect_register_32bit (struct regcache *regcache,
                             int use_64bit, int regno, unsigned char *buf)
@@ -664,7 +738,7 @@ mips_supply_register_32bit (struct regcache *regcache,
 static void
 mips_fill_gregset (struct regcache *regcache, void *buf)
 {
-  union mips_register *regset = buf;
+  union mips_register *regset = (union mips_register *) buf;
   int i, use_64bit;
   const struct target_desc *tdesc = regcache->tdesc;
 
@@ -693,12 +767,14 @@ mips_fill_gregset (struct regcache *regcache, void *buf)
 static void
 mips_store_gregset (struct regcache *regcache, const void *buf)
 {
-  const union mips_register *regset = buf;
+  const union mips_register *regset = (const union mips_register *) buf;
   int i, use_64bit;
 
   use_64bit = (register_size (regcache->tdesc, 0) == 8);
 
-  for (i = 0; i < 32; i++)
+  supply_register_by_name_zeroed (regcache, "r0");
+
+  for (i = 1; i < 32; i++)
     mips_supply_register (regcache, use_64bit, i, regset + i);
 
   mips_supply_register (regcache, use_64bit,
@@ -721,7 +797,7 @@ mips_store_gregset (struct regcache *regcache, const void *buf)
 static void
 mips_fill_fpregset (struct regcache *regcache, void *buf)
 {
-  union mips_register *regset = buf;
+  union mips_register *regset = (union mips_register *) buf;
   int i, use_64bit, first_fp, big_endian;
 
   use_64bit = (register_size (regcache->tdesc, 0) == 8);
@@ -746,7 +822,7 @@ mips_fill_fpregset (struct regcache *regcache, void *buf)
 static void
 mips_store_fpregset (struct regcache *regcache, const void *buf)
 {
-  const union mips_register *regset = buf;
+  const union mips_register *regset = (const union mips_register *) buf;
   int i, use_64bit, first_fp, big_endian;
 
   use_64bit = (register_size (regcache->tdesc, 0) == 8);
@@ -770,6 +846,44 @@ mips_store_fpregset (struct regcache *regcache, const void *buf)
 }
 #endif /* HAVE_PTRACE_GETREGS */
 
+/* Take care of 32-bit registers with 64-bit ptrace, POKEUSER side.  */
+
+static void
+mips_collect_ptrace_register (struct regcache *regcache,
+                             int regno, char *buf)
+{
+  int use_64bit = sizeof (PTRACE_XFER_TYPE) == 8;
+
+  if (use_64bit && register_size (regcache->tdesc, regno) == 4)
+    {
+      union mips_register reg;
+
+      mips_collect_register (regcache, 0, regno, &reg);
+      memcpy (buf, &reg, sizeof (reg));
+    }
+  else
+    collect_register (regcache, regno, buf);
+}
+
+/* Take care of 32-bit registers with 64-bit ptrace, PEEKUSER side.  */
+
+static void
+mips_supply_ptrace_register (struct regcache *regcache,
+                            int regno, const char *buf)
+{
+  int use_64bit = sizeof (PTRACE_XFER_TYPE) == 8;
+
+  if (use_64bit && register_size (regcache->tdesc, regno) == 4)
+    {
+      union mips_register reg;
+
+      memcpy (&reg, buf, sizeof (reg));
+      mips_supply_register (regcache, 0, regno, &reg);
+    }
+  else
+    supply_register (regcache, regno, buf);
+}
+
 static struct regset_info mips_regsets[] = {
 #ifdef HAVE_PTRACE_GETREGS
   { PTRACE_GETREGS, PTRACE_SETREGS, 0, 38 * 8, GENERAL_REGS,
@@ -777,7 +891,7 @@ static struct regset_info mips_regsets[] = {
   { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, 33 * 8, FP_REGS,
     mips_fill_fpregset, mips_store_fpregset },
 #endif /* HAVE_PTRACE_GETREGS */
-  { 0, 0, 0, -1, -1, NULL, NULL }
+  NULL_REGSET
 };
 
 static struct regsets_info mips_regsets_info =
@@ -827,12 +941,12 @@ struct linux_target_ops the_low_target = {
   mips_regs_info,
   mips_cannot_fetch_register,
   mips_cannot_store_register,
-  NULL, /* fetch_register */
+  mips_fetch_register,
   mips_get_pc,
   mips_set_pc,
-  (const unsigned char *) &mips_breakpoint,
-  mips_breakpoint_len,
-  mips_reinsert_addr,
+  NULL, /* breakpoint_kind_from_pc */
+  mips_sw_breakpoint_from_kind,
+  NULL, /* get_next_pcs */
   0,
   mips_breakpoint_at,
   mips_supports_z_point_type,
@@ -840,11 +954,14 @@ struct linux_target_ops the_low_target = {
   mips_remove_point,
   mips_stopped_by_watchpoint,
   mips_stopped_data_address,
-  NULL,
-  NULL,
+  mips_collect_ptrace_register,
+  mips_supply_ptrace_register,
   NULL, /* siginfo_fixup */
   mips_linux_new_process,
+  mips_linux_delete_process,
   mips_linux_new_thread,
+  mips_linux_delete_thread,
+  mips_linux_new_fork,
   mips_linux_prepare_to_resume
 };
 
This page took 0.034026 seconds and 4 git commands to generate.