gdbserver/lynx178: spurious SIG61 signal when resuming inferior.
authorJoel Brobecker <brobecker@gnat.com>
Fri, 17 May 2013 06:47:44 +0000 (06:47 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Fri, 17 May 2013 06:47:44 +0000 (06:47 +0000)
On ppc-lynx178, resuming the execution of a program after hitting
a breakpoint sometimes triggers a spurious SIG61 event:

    (gdb) cont
    Continuing.

    Program received signal SIG61, Real-time event 61.
    [Switching to Thread 39]
    0x10002324 in a_test.task1 (<_task>=0x3ffff774) at a_test.adb:30
    30          select  -- Task 1

From this point on, continuing again lets the signal kill the program.
Using "signal 0" or configuring GDB to discard the signal does not
help either, as the program immediately reports the same signal again.

What happens is the following:

  - GDB sends a single-step order to gdbserver: $vCont;s:31
    This tells GDBserver to do a step using thread 0x31=49.
    GDBserver does the step, and thread 49 receives the SIGTRAP
    indicating that the step has finished.

  - GDB then sends a "continue", but this time does not specify
    which thread to continue: $vCont;c
    GDBserver uses an arbitrary thread's ptid to resume the program's
    execution (the current_inferior's ptid was chosen for that).
    See lynx-low.c:lynx_resume:

        if (ptid_equal (ptid, minus_one_ptid))
          ptid = thread_to_gdb_id (current_inferior);

So far on all LynxOS platforms, this has been good enough. But
not so on LynxOS 178. If the ptid used to resume the execution
is not the same as the thread that did the step, we get the weird
signal.

This patch fixes the problem by saving the ptid of the thread
that last caused an event, received during a call to waitpid.
The ptid is saved in per-process private data.

gdb/gdbserver/ChangeLog:

        * lynx-low.c (struct process_info_private): New type.
        (lynx_add_process): New function.
        (lynx_create_inferior, lynx_attach): Replace calls to
        add_process by calls to lynx_add_process.
        (lynx_resume): If PTID is null, then try using
        current_process()->private->last_wait_event_ptid.
        Add comments.
        (lynx_clear_inferiors): Delete.  The contents of that function
        has been inlined in lynx_mourn;
        (lynx_wait_1): Save the ptid in the process's private data.
        (lynx_mourn): Free the process' private data.  Replace call
        to lynx_clear_inferiors by call to clear_inferiors.

gdb/gdbserver/ChangeLog
gdb/gdbserver/lynx-low.c

index b7fab1cde86b342a7f7de83d3d44a260b1307203..5cc2c252897ef837e07374159fcdc25f0c439c09 100644 (file)
@@ -1,3 +1,18 @@
+2013-05-17  Joel Brobecker  <brobecker@adacore.com>
+
+       * lynx-low.c (struct process_info_private): New type.
+       (lynx_add_process): New function.
+       (lynx_create_inferior, lynx_attach): Replace calls to
+       add_process by calls to lynx_add_process.
+       (lynx_resume): If PTID is null, then try using
+       current_process()->private->last_wait_event_ptid.
+       Add comments.
+       (lynx_clear_inferiors): Delete.  The contents of that function
+       has been inlined in lynx_mourn;
+       (lynx_wait_1): Save the ptid in the process's private data.
+       (lynx_mourn): Free the process' private data.  Replace call
+       to lynx_clear_inferiors by call to clear_inferiors.
+
 2013-05-17  Yao Qi  <yao@codesourcery.com>
 
        * i386-low.c (i386_length_and_rw_bits): Move the comment to
index a5f3b6dc0c0feb47c306bde56ef12a2673a3cc0d..b4cb5d203e0db1c118a8f8fbc55b2d600a8dfcd9 100644 (file)
 
 int using_threads = 1;
 
+/* Per-process private data.  */
+
+struct process_info_private
+{
+  /* The PTID obtained from the last wait performed on this process.
+     Initialized to null_ptid until the first wait is performed.  */
+  ptid_t last_wait_event_ptid;
+};
+
 /* Print a debug trace on standard output if debug_threads is set.  */
 
 static void
@@ -196,6 +205,21 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2)
   return result;
 }
 
+/* Call add_process with the given parameters, and initializes
+   the process' private data.  */
+
+static struct process_info *
+lynx_add_process (int pid, int attached)
+{
+  struct process_info *proc;
+
+  proc = add_process (pid, attached);
+  proc->private = xcalloc (1, sizeof (*proc->private));
+  proc->private->last_wait_event_ptid = null_ptid;
+
+  return proc;
+}
+
 /* Implement the create_inferior method of the target_ops vector.  */
 
 static int
@@ -225,7 +249,7 @@ lynx_create_inferior (char *program, char **allargs)
       _exit (0177);
     }
 
-  add_process (pid, 0);
+  lynx_add_process (pid, 0);
   /* Do not add the process thread just yet, as we do not know its tid.
      We will add it later, during the wait for the STOP event corresponding
      to the lynx_ptrace (PTRACE_TRACEME) call above.  */
@@ -243,7 +267,7 @@ lynx_attach (unsigned long pid)
     error ("Cannot attach to process %lu: %s (%d)\n", pid,
           strerror (errno), errno);
 
-  add_process (pid, 1);
+  lynx_add_process (pid, 1);
   add_thread (ptid, NULL);
 
   return 0;
@@ -260,6 +284,19 @@ lynx_resume (struct thread_resume *resume_info, size_t n)
                        ? PTRACE_SINGLESTEP : PTRACE_CONT);
   const int signal = resume_info[0].sig;
 
+  /* If given a null_ptid, then try using the current_process'
+     private->last_wait_event_ptid.  On most LynxOS versions,
+     using any of the process' thread works well enough, but
+     LynxOS 178 is a little more sensitive, and triggers some
+     unexpected signals (Eg SIG61) when we resume the inferior
+     using a different thread.  */
+  if (ptid_equal (ptid, minus_one_ptid))
+    ptid = current_process()->private->last_wait_event_ptid;
+
+  /* The ptid might still be NULL; this can happen between the moment
+     we create the inferior or attach to a process, and the moment
+     we resume its execution for the first time.  It is fine to
+     use the current_inferior's ptid in those cases.  */
   if (ptid_equal (ptid, minus_one_ptid))
     ptid = thread_to_gdb_id (current_inferior);
 
@@ -285,16 +322,6 @@ lynx_continue (ptid_t ptid)
   lynx_resume (&resume_info, 1);
 }
 
-/* Remove all inferiors and associated threads.  */
-
-static void
-lynx_clear_inferiors (void)
-{
-  /* We do not use private data, so nothing much to do except calling
-     clear_inferiors.  */
-  clear_inferiors ();
-}
-
 /* A wrapper around waitpid that handles the various idiosyncrasies
    of LynxOS' waitpid.  */
 
@@ -352,6 +379,7 @@ retry:
 
   ret = lynx_waitpid (pid, &wstat);
   new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid);
+  find_process_pid (ret)->private->last_wait_event_ptid = new_ptid;
 
   /* If this is a new thread, then add it now.  The reason why we do
      this here instead of when handling new-thread events is because
@@ -480,7 +508,11 @@ lynx_detach (int pid)
 static void
 lynx_mourn (struct process_info *proc)
 {
-  lynx_clear_inferiors ();
+  /* Free our private data.  */
+  free (proc->private);
+  proc->private = NULL;
+
+  clear_inferiors ();
 }
 
 /* Implement the join target_ops method.  */