]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb/tdep] Fix gdb.base/watchpoint-running.exp on {arm,ppc64le}-linux
authorPedro Alves <pedro@palves.net>
Fri, 21 Jun 2024 13:14:08 +0000 (15:14 +0200)
committerTom de Vries <tdevries@suse.de>
Fri, 21 Jun 2024 13:14:08 +0000 (15:14 +0200)
When running test-case gdb.base/watchpoint-running on ppc64le-linux (and
similar on arm-linux), we get:
...
(gdb) watch global_var^M
warning: Error when detecting the debug register interface. \
  Debug registers will be unavailable.^M
Watchpoint 2: global_var^M
(gdb) FAIL: $exp: all-stop: hardware: watch global_var
FAIL: $exp: all-stop: hardware: watchpoint hit (timeout)
...

The problem is that ppc_linux_dreg_interface::detect fails to detect the
hardware watchpoint interface, because the calls to ptrace return with errno
set to ESRCH.

This is a feature of ptrace: if a call is done while the tracee is not
ptrace-stopped, it returns ESRCH.

Indeed, in the test-case "watch global_var" is executed while the inferior is
running, and that triggers the first call to ppc_linux_dreg_interface::detect.

And because the detection failure is cached, subsequent attempts at setting
hardware watchpoints will also fail, even if the tracee is ptrace-stopped.

The way to fix this is to make sure that ppc_linux_dreg_interface::detect is
called when we know that the thread is ptrace-stopped, which in the current
setup is best addressed by using target-specific post_attach and
post_startup_inferior overrides.  However, as we can see in
aarch64_linux_nat_target, that causes code duplication.

Fix this by:
- defining a new target hook low_init_process, called from
  linux_init_ptrace_procfs, which is called from both
  linux_nat_target::post_attach and linux_nat_target::post_startup_inferior,
- adding implementations for ppc_linux_nat_target and arm_linux_nat_target
  that detect the hardware watchpoint interface,
- replacing the aarch64_linux_nat_target implementations of post_attach and
  post_startup_inferior with a low_init_process implementation.

Tested on ppc64le-linux, arm-linux, aarch64-linux and x86_64-linux.

Co-Authored-By: Tom de Vries <tdevries@suse.de>
Approved-By: Luis Machado <luis.machado@arm.com>
PR tdep/31834
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31834
PR tdep/31705
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31705

gdb/aarch64-linux-nat.c
gdb/arm-linux-nat.c
gdb/linux-nat.c
gdb/linux-nat.h
gdb/ppc-linux-nat.c

index 4b2a0ba9f7bedfe3501b940d3113bc60e9166b87..2e6541f53c3c7d0563d0361be1cfc6147127c49c 100644 (file)
@@ -78,12 +78,6 @@ public:
 
   int can_do_single_step () override;
 
-  /* Override the GNU/Linux inferior startup hook.  */
-  void post_startup_inferior (ptid_t) override;
-
-  /* Override the GNU/Linux post attach hook.  */
-  void post_attach (int pid) override;
-
   /* These three defer to common nat/ code.  */
   void low_new_thread (struct lwp_info *lp) override
   { aarch64_linux_new_thread (lp); }
@@ -93,6 +87,7 @@ public:
   { aarch64_linux_prepare_to_resume (lp); }
 
   void low_new_fork (struct lwp_info *parent, pid_t child_pid) override;
+  void low_init_process (pid_t pid) override;
   void low_forget_process (pid_t pid) override;
 
   /* Add our siginfo layout converter.  */
@@ -844,29 +839,18 @@ ps_get_thread_area (struct ps_prochandle *ph,
 }
 \f
 
-/* Implement the virtual inf_ptrace_target::post_startup_inferior method.  */
-
-void
-aarch64_linux_nat_target::post_startup_inferior (ptid_t ptid)
-{
-  low_forget_process (ptid.pid ());
-  aarch64_linux_get_debug_reg_capacity (ptid.pid ());
-  linux_nat_target::post_startup_inferior (ptid);
-}
-
-/* Implement the "post_attach" target_ops method.  */
+/* Implement the "low_init_process" target_ops method.  */
 
 void
-aarch64_linux_nat_target::post_attach (int pid)
+aarch64_linux_nat_target::low_init_process (pid_t pid)
 {
   low_forget_process (pid);
-  /* Set the hardware debug register capacity.  If
-     aarch64_linux_get_debug_reg_capacity is not called
-     (as it is in aarch64_linux_child_post_startup_inferior) then
-     software watchpoints will be used instead of hardware
-     watchpoints when attaching to a target.  */
+  /* Set the hardware debug register capacity.  This requires the process to be
+     ptrace-stopped, otherwise detection will fail and software watchpoints will
+     be used instead of hardware.  If we allow this to be done lazily, we
+     cannot guarantee that it's called when the process is ptrace-stopped, so
+     do it now.  */
   aarch64_linux_get_debug_reg_capacity (pid);
-  linux_nat_target::post_attach (pid);
 }
 
 /* Implement the "read_description" target_ops method.  */
index 50c24ecfcd2e73497a8915d16958e31d6acab72d..ac53bed72d753aaa8a7a3e0fb694d3e158b0f52e 100644 (file)
@@ -103,6 +103,7 @@ public:
 
   /* Handle process creation and exit.  */
   void low_new_fork (struct lwp_info *parent, pid_t child_pid) override;
+  void low_init_process (pid_t pid) override;
   void low_forget_process (pid_t pid) override;
 };
 
@@ -805,6 +806,19 @@ arm_linux_process_info_get (pid_t pid)
   return proc;
 }
 
+/* Implement the "low_init_process" target_ops method.  */
+
+void
+arm_linux_nat_target::low_init_process (pid_t pid)
+{
+  /* Set the hardware debug register capacity.  This requires the process to be
+     ptrace-stopped, otherwise detection will fail and software watchpoints will
+     be used instead of hardware.  If we allow this to be done lazily, we
+     cannot guarantee that it's called when the process is ptrace-stopped, so
+     do it now.  */
+  arm_linux_get_hwbp_cap ();
+}
+
 /* Called whenever GDB is no longer debugging process PID.  It deletes
    data structures that keep track of debug register state.  */
 
index c0fe08a2a8b5944560fbe706f38ad3058e354a72..3f252370c7b275b80e01848b190d7c48246fd25a 100644 (file)
@@ -454,6 +454,12 @@ linux_init_ptrace_procfs (pid_t pid, int attached)
   linux_ptrace_init_warnings ();
   linux_proc_init_warnings ();
   proc_mem_file_is_writable ();
+
+  /* Let the arch-specific native code do any needed initialization.
+     Some architectures need to call ptrace to check for hardware
+     watchpoints support, etc.  Call it now, when we know the tracee
+     is ptrace-stopped.  */
+  linux_target->low_init_process (pid);
 }
 
 linux_nat_target::~linux_nat_target ()
index f30a5f90e2a86d3d4b8366ef16dbda1398924bde..ee8603743f664cf8ab138e6b9eb6e3a5a2d6aaf5 100644 (file)
@@ -164,6 +164,12 @@ public:
   virtual void low_new_clone (struct lwp_info *parent, pid_t child_lwp)
   {}
 
+  /* The method to call, if any, when we have a new (from run/attach,
+     not fork) process to debug.  The process is ptrace-stopped when
+     this is called.  */
+  virtual void low_init_process (pid_t pid)
+  {}
+
   /* The method to call, if any, when a process is no longer
      attached.  */
   virtual void low_forget_process (pid_t pid)
index c73c7c90b4cde1233e3288f6f545b7cb73565d1e..40a5665a18fad8593dd5a36fbac65f07392cf2f3 100644 (file)
@@ -545,6 +545,8 @@ struct ppc_linux_nat_target final : public linux_nat_target
 
   void low_new_clone (struct lwp_info *, pid_t) override;
 
+  void low_init_process (pid_t pid) override;
+
   void low_forget_process (pid_t pid) override;
 
   void low_prepare_to_resume (struct lwp_info *) override;
@@ -2705,6 +2707,19 @@ ppc_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len,
   return 0;
 }
 
+/* Implement the "low_init_process" target_ops method.  */
+
+void
+ppc_linux_nat_target::low_init_process (pid_t pid)
+{
+  /* Set the hardware debug register capacity.  This requires the process to be
+     ptrace-stopped, otherwise detection will fail and software watchpoints will
+     be used instead of hardware.  If we allow this to be done lazily, we
+     cannot guarantee that it's called when the process is ptrace-stopped, so
+     do it now.  */
+  m_dreg_interface.detect (ptid_t (pid, pid));
+}
+
 /* Clean up the per-process info associated with PID.  When using the
    HWDEBUG interface, we also erase the per-thread state of installed
    debug registers for all the threads that belong to the group of PID.