[pushed,v2] FreeBSD: Fix 'Couldn't get registers: Device busy' error (PR gdb/23077)

Message ID fd148a80-82bd-b1a2-adf7-0e02a9f105ef@redhat.com
State New, archived
Headers

Commit Message

Pedro Alves April 21, 2018, 6:04 p.m. UTC
  On 04/20/2018 04:19 PM, Rajendra SY wrote:
> I tested your patch it works on FreeBSD.
> No error message after attach.

Great, I've pushed it in now, as below.

Thanks,
Pedro Alves

From 00aecdcf6224e44fedf31a07340e9da11500fcfb Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Sat, 21 Apr 2018 18:19:30 +0100
Subject: [PATCH] FreeBSD: Fix 'Couldn't get registers: Device busy' error (PR
 gdb/23077)

As Rajendra SY reported at
<https://sourceware.org/ml/gdb-patches/2018-04/msg00399.html>, several
attach-related tests are failing on FreeBSD.  The "attach" command
errors with "Couldn't get registers: Device busy".

When the "attach" command is executed, it calls target_attach ->
inf_ptrace_attach, which just does the ptrace(PT_ATTACH), it does not
wait for the child to stop with SIGSTOP.  Afterwards, the command is
complete and we go back to the event loop.  The event loop wakes up
and we end up in target_wait -> fbsd_wait, and handle the SIGSTOP
stop.

At the end of execute_command, though, before going back to the event
loop, we check if the frame language changed via
check_frame_language_change().  That reads the current PC, which is
what leads to the registers read that fails.

The problem is that we fail to mark the attached-to thread as
executing between the initial attach, and the subsequent target_wait.
Until we see the thread stop with SIGSTOP, we shouldn't try to read
registers off of it.  I guess there may a timing issue here - if
you're "lucky", the thread may stop before gdb reads its registers,
masking the problem.

With that fixed, check_frame_language_change() becomes a nop until the
thread is marked not-executing again, after target_wait is called and
we go through handle_inferior_event -> normal_stop.

We haven't seen the problem on Linux because there, the target_attach
implementation waits for the thread to stop before returning.  Still,
that's supposedly hidden from the core, since the Linux target, like
most targets, is a '!to_attach_no_wait' target.

This fixes:
 FAIL: gdb.base/attach.exp: attach1, after setting file
 FAIL: gdb.base/attach.exp: attach2, with no file
 FAIL: gdb.base/attach.exp: load file manually, after attach2 (re-read) (got interactive prompt)
 FAIL: gdb.base/attach.exp: attach when process' a.out not in cwd

 FAIL: gdb.base/dprintf-detach.exp: bai=on ds=gdb dd=on: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=on ds=gdb dd=off: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=on ds=call dd=on: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=on ds=call dd=off: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=on ds=agent dd=on: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=on ds=agent dd=off: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=off ds=gdb dd=on: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=off ds=gdb dd=off: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=off ds=call dd=on: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=off ds=call dd=off: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=off ds=agent dd=on: re-attach to inferior
 FAIL: gdb.base/dprintf-detach.exp: bai=off ds=agent dd=off: re-attach to inferior

gdb/ChangeLog:
2018-04-21  Pedro Alves  <palves@redhat.com>
	    Rajendra SY  <rajendra.sy@gmail.com>

	* inf-ptrace.c (inf_ptrace_attach): Mark the thread as executing.
	* remote.c (extended_remote_attach): In all-stop mode, mark the
	thread as executing.
---
 gdb/ChangeLog    | 7 +++++++
 gdb/inf-ptrace.c | 5 ++++-
 gdb/remote.c     | 5 ++++-
 3 files changed, 15 insertions(+), 2 deletions(-)
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0db5c46f6cd..70c461a4b3a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@ 
+2018-04-21  Pedro Alves  <palves@redhat.com>
+	    Rajendra SY  <rajendra.sy@gmail.com>
+
+	* inf-ptrace.c (inf_ptrace_attach): Mark the thread as executing.
+	* remote.c (extended_remote_attach): In all-stop mode, mark the
+	thread as executing.
+
 2018-04-19  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
 
 	* thread.c (thread_apply_all_command): Fix comment.
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index e20388658fe..942494bbdac 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -235,7 +235,10 @@  inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
 
   /* Always add a main thread.  If some target extends the ptrace
      target, it should decorate the ptid later with more info.  */
-  add_thread_silent (inferior_ptid);
+  thread_info *thr = add_thread_silent (inferior_ptid);
+  /* Don't consider the thread stopped until we've processed its
+     initial SIGSTOP stop.  */
+  set_executing (thr->ptid, true);
 
   unpusher.release ();
 }
diff --git a/gdb/remote.c b/gdb/remote.c
index f54a38833b3..49013848d55 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5316,7 +5316,10 @@  extended_remote_attach (struct target_ops *target, const char *args,
       inferior_ptid = remote_current_thread (inferior_ptid);
 
       /* Add the main thread to the thread list.  */
-      add_thread_silent (inferior_ptid);
+      thread_info *thr = add_thread_silent (inferior_ptid);
+      /* Don't consider the thread stopped until we've processed the
+	 saved stop reply.  */
+      set_executing (thr->ptid, true);
     }
 
   /* Next, if the target can specify a description, read it.  We do