gdbserver/Linux: Introduce NULL_REGSET
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-x86-low.c
index e371873296e8bf9bb5c754e390eddf069c464d93..89ec4e54b3b8f5caee9f93ad436ba4278e595445 100644 (file)
@@ -25,6 +25,7 @@
 #include "i387-fp.h"
 #include "x86-low.h"
 #include "x86-xstate.h"
+#include "nat/gdb_ptrace.h"
 
 #include "gdb_proc_service.h"
 /* Don't include elf/common.h if linux/elf.h got included by
@@ -39,6 +40,7 @@
 #include "ax.h"
 #include "nat/linux-nat.h"
 #include "nat/x86-linux.h"
+#include "nat/x86-linux-dregs.h"
 
 #ifdef __x86_64__
 /* Defined in auto-generated file amd64-linux.c.  */
@@ -116,18 +118,9 @@ static const char *xmltarget_amd64_linux_no_xml = "@<target>\
 
 #include <sys/reg.h>
 #include <sys/procfs.h>
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
 #include <sys/uio.h>
 
-#ifndef PTRACE_GETREGSET
-#define PTRACE_GETREGSET       0x4204
-#endif
-
-#ifndef PTRACE_SETREGSET
-#define PTRACE_SETREGSET       0x4205
-#endif
-
-
 #ifndef PTRACE_GET_THREAD_AREA
 #define PTRACE_GET_THREAD_AREA 25
 #endif
@@ -470,7 +463,7 @@ static struct regset_info x86_regsets[] =
     FP_REGS,
     x86_fill_fpregset, x86_store_fpregset },
 #endif /* HAVE_PTRACE_GETREGS */
-  { 0, 0, 0, -1, -1, NULL, NULL }
+  NULL_REGSET
 };
 
 static CORE_ADDR
@@ -509,7 +502,7 @@ x86_set_pc (struct regcache *regcache, CORE_ADDR pc)
     }
 }
 \f
-static const unsigned char x86_breakpoint[] = { 0xCC };
+static const gdb_byte x86_breakpoint[] = { 0xCC };
 #define x86_breakpoint_len 1
 
 static int
@@ -524,125 +517,6 @@ x86_breakpoint_at (CORE_ADDR pc)
   return 0;
 }
 \f
-
-/* Return the offset of REGNUM in the u_debugreg field of struct
-   user.  */
-
-static int
-u_debugreg_offset (int regnum)
-{
-  return (offsetof (struct user, u_debugreg)
-         + sizeof (((struct user *) 0)->u_debugreg[0]) * regnum);
-}
-
-
-/* Support for debug registers.  */
-
-/* Get debug register REGNUM value from the LWP specified by PTID.  */
-
-static unsigned long
-x86_linux_dr_get (ptid_t ptid, int regnum)
-{
-  int tid;
-  unsigned long value;
-
-  gdb_assert (ptid_lwp_p (ptid));
-  tid = ptid_get_lwp (ptid);
-
-  errno = 0;
-  value = ptrace (PTRACE_PEEKUSER, tid, u_debugreg_offset (regnum), 0);
-  if (errno != 0)
-    perror_with_name (_("Couldn't read debug register"));
-
-  return value;
-}
-
-/* Set debug register REGNUM to VALUE in the LWP specified by PTID.  */
-
-static void
-x86_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
-{
-  int tid;
-
-  gdb_assert (ptid_lwp_p (ptid));
-  tid = ptid_get_lwp (ptid);
-
-  errno = 0;
-  ptrace (PTRACE_POKEUSER, tid, u_debugreg_offset (regnum), value);
-  if (errno != 0)
-    perror_with_name (_("Couldn't write debug register"));
-}
-
-/* Callback for iterate_over_lwps.  Mark that our local mirror of
-   LWP's debug registers has been changed, and cause LWP to stop if
-   it isn't already.  Values are written from our local mirror to
-   the actual debug registers immediately prior to LWP resuming.  */
-
-static int
-update_debug_registers_callback (struct lwp_info *lwp, void *arg)
-{
-  lwp_set_debug_registers_changed (lwp, 1);
-
-  if (!lwp_is_stopped (lwp))
-    linux_stop_lwp (lwp);
-
-  /* Continue the iteration.  */
-  return 0;
-}
-
-/* Store ADDR in debug register REGNUM of all LWPs of the current
-   inferior.  */
-
-static void
-x86_linux_dr_set_addr (int regnum, CORE_ADDR addr)
-{
-  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (current_lwp_ptid ()));
-
-  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
-
-  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
-}
-
-/* Return the address stored in the current inferior's debug register
-   REGNUM.  */
-
-static CORE_ADDR
-x86_linux_dr_get_addr (int regnum)
-{
-  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
-
-  return x86_linux_dr_get (current_lwp_ptid (), regnum);
-}
-
-/* Store CONTROL in the debug control registers of all LWPs of the
-   current inferior.  */
-
-static void
-x86_linux_dr_set_control (unsigned long control)
-{
-  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (current_lwp_ptid ()));
-
-  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
-}
-
-/* Return the value stored in the current inferior's debug control
-   register.  */
-
-static unsigned long
-x86_linux_dr_get_control (void)
-{
-  return x86_linux_dr_get (current_lwp_ptid (), DR_CONTROL);
-}
-
-/* Return the value stored in the current inferior's debug status
-   register.  */
-
-static unsigned long
-x86_linux_dr_get_status (void)
-{
-  return x86_linux_dr_get (current_lwp_ptid (), DR_STATUS);
-}
-
 /* Low-level function vector.  */
 struct x86_dr_low_type x86_dr_low =
   {
@@ -679,9 +553,6 @@ x86_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
 
   switch (type)
     {
-    case raw_bkpt_type_sw:
-      return insert_memory_breakpoint (bp);
-
     case raw_bkpt_type_hw:
     case raw_bkpt_type_write_wp:
     case raw_bkpt_type_access_wp:
@@ -708,9 +579,6 @@ x86_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
 
   switch (type)
     {
-    case raw_bkpt_type_sw:
-      return remove_memory_breakpoint (bp);
-
     case raw_bkpt_type_hw:
     case raw_bkpt_type_write_wp:
     case raw_bkpt_type_access_wp:
@@ -758,12 +626,32 @@ x86_linux_new_process (void)
   return info;
 }
 
-/* Called when a new thread is detected.  */
+/* Target routine for linux_new_fork.  */
 
 static void
-x86_linux_new_thread (struct lwp_info *lwp)
+x86_linux_new_fork (struct process_info *parent, struct process_info *child)
 {
-  lwp_set_debug_registers_changed (lwp, 1);
+  /* 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.  */
+
+  *child->priv->arch_private = *parent->priv->arch_private;
 }
 
 /* See nat/x86-dregs.h.  */
@@ -775,62 +663,6 @@ x86_debug_reg_state (pid_t pid)
 
   return &proc->priv->arch_private->debug_reg_state;
 }
-
-/* Update the thread's debug registers if the values in our local
-   mirror have been changed.  */
-
-static void
-x86_linux_update_debug_registers (struct lwp_info *lwp)
-{
-  ptid_t ptid = ptid_of_lwp (lwp);
-  int clear_status = 0;
-
-  gdb_assert (lwp_is_stopped (lwp));
-
-  if (lwp_debug_registers_changed (lwp))
-    {
-      struct x86_debug_reg_state *state
-       = x86_debug_reg_state (ptid_get_pid (ptid));
-      int i;
-
-      /* Prior to Linux kernel 2.6.33 commit
-        72f674d203cd230426437cdcf7dd6f681dad8b0d, setting DR0-3 to
-        a value that did not match what was enabled in DR_CONTROL
-        resulted in EINVAL.  To avoid this we zero DR_CONTROL before
-        writing address registers, only writing DR_CONTROL's actual
-        value once all the addresses are in place.  */
-      x86_linux_dr_set (ptid, DR_CONTROL, 0);
-
-      ALL_DEBUG_ADDRESS_REGISTERS (i)
-       if (state->dr_ref_count[i] > 0)
-         {
-           x86_linux_dr_set (ptid, i, state->dr_mirror[i]);
-
-           /* If we're setting a watchpoint, any change the inferior
-              has made to its debug registers needs to be discarded
-              to avoid x86_stopped_data_address getting confused.  */
-           clear_status = 1;
-         }
-
-      /* If DR_CONTROL is supposed to be zero then it's already set.  */
-      if (state->dr_control_mirror != 0)
-       x86_linux_dr_set (ptid, DR_CONTROL, state->dr_control_mirror);
-
-      lwp_set_debug_registers_changed (lwp, 0);
-    }
-
-  if (clear_status
-      || lwp_stop_reason (lwp) == TARGET_STOPPED_BY_WATCHPOINT)
-    x86_linux_dr_set (ptid, DR_STATUS, 0);
-}
-
-/* Called prior to resuming a thread.  */
-
-static void
-x86_linux_prepare_to_resume (struct lwp_info *lwp)
-{
-  x86_linux_update_debug_registers (lwp);
-}
 \f
 /* When GDBSERVER is built as a 64-bit application on linux, the
    PTRACE_GETSIGINFO data is always presented in 64-bit layout.  Since
@@ -1310,9 +1142,6 @@ int have_ptrace_getfpxregs =
 #endif
 ;
 
-/* Does the current host support PTRACE_GETREGSET?  */
-static int have_ptrace_getregset = -1;
-
 /* Get Linux/x86 target description from running target.  */
 
 static const struct target_desc *
@@ -3414,6 +3243,15 @@ x86_emit_ops (void)
     return &i386_emit_ops;
 }
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+x86_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = x86_breakpoint_len;
+  return x86_breakpoint;
+}
+
 static int
 x86_supports_range_stepping (void)
 {
@@ -3432,8 +3270,8 @@ struct linux_target_ops the_low_target =
   NULL, /* fetch_register */
   x86_get_pc,
   x86_set_pc,
-  x86_breakpoint,
-  x86_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  x86_sw_breakpoint_from_kind,
   NULL,
   1,
   x86_breakpoint_at,
@@ -3451,6 +3289,7 @@ struct linux_target_ops the_low_target =
   x86_siginfo_fixup,
   x86_linux_new_process,
   x86_linux_new_thread,
+  x86_linux_new_fork,
   x86_linux_prepare_to_resume,
   x86_linux_process_qsupported,
   x86_supports_tracepoints,
@@ -3475,7 +3314,7 @@ initialize_low_arch (void)
   init_registers_x32_avx_linux ();
   init_registers_x32_avx512_linux ();
 
-  tdesc_amd64_linux_no_xml = xmalloc (sizeof (struct target_desc));
+  tdesc_amd64_linux_no_xml = XNEW (struct target_desc);
   copy_target_description (tdesc_amd64_linux_no_xml, tdesc_amd64_linux);
   tdesc_amd64_linux_no_xml->xmltarget = xmltarget_amd64_linux_no_xml;
 #endif
@@ -3485,7 +3324,7 @@ initialize_low_arch (void)
   init_registers_i386_avx512_linux ();
   init_registers_i386_mpx_linux ();
 
-  tdesc_i386_linux_no_xml = xmalloc (sizeof (struct target_desc));
+  tdesc_i386_linux_no_xml = XNEW (struct target_desc);
   copy_target_description (tdesc_i386_linux_no_xml, tdesc_i386_linux);
   tdesc_i386_linux_no_xml->xmltarget = xmltarget_i386_linux_no_xml;
 
This page took 0.043514 seconds and 4 git commands to generate.