gdb/
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-low.c
index 7638ca334d45ba2fd0c85a5700e242f395cd7671..06ec5763c624d66f1be540f7268688da6b459215 100644 (file)
@@ -19,6 +19,7 @@
 #include "server.h"
 #include "linux-low.h"
 #include "linux-osdata.h"
+#include "agent.h"
 
 #include <sys/wait.h>
 #include <stdio.h>
@@ -659,10 +660,10 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
          fflush (stderr);
          return;
        }
-      else
-       /* If we fail to attach to a process, report an error.  */
-       error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid,
-              strerror (errno), errno);
+
+      /* If we fail to attach to a process, report an error.  */
+      error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid,
+            strerror (errno), errno);
     }
 
   if (initial)
@@ -998,36 +999,127 @@ linux_kill (int pid)
   return 0;
 }
 
+/* Get pending signal of THREAD, for detaching purposes.  This is the
+   signal the thread last stopped for, which we need to deliver to the
+   thread when detaching, otherwise, it'd be suppressed/lost.  */
+
+static int
+get_detach_signal (struct thread_info *thread)
+{
+  enum target_signal signo = TARGET_SIGNAL_0;
+  int status;
+  struct lwp_info *lp = get_thread_lwp (thread);
+
+  if (lp->status_pending_p)
+    status = lp->status_pending;
+  else
+    {
+      /* If the thread had been suspended by gdbserver, and it stopped
+        cleanly, then it'll have stopped with SIGSTOP.  But we don't
+        want to deliver that SIGSTOP.  */
+      if (thread->last_status.kind != TARGET_WAITKIND_STOPPED
+         || thread->last_status.value.sig == TARGET_SIGNAL_0)
+       return 0;
+
+      /* Otherwise, we may need to deliver the signal we
+        intercepted.  */
+      status = lp->last_status;
+    }
+
+  if (!WIFSTOPPED (status))
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "GPS: lwp %s hasn't stopped: no pending signal\n",
+                target_pid_to_str (ptid_of (lp)));
+      return 0;
+    }
+
+  /* Extended wait statuses aren't real SIGTRAPs.  */
+  if (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "GPS: lwp %s had stopped with extended "
+                "status: no pending signal\n",
+                target_pid_to_str (ptid_of (lp)));
+      return 0;
+    }
+
+  signo = target_signal_from_host (WSTOPSIG (status));
+
+  if (program_signals_p && !program_signals[signo])
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "GPS: lwp %s had signal %s, but it is in nopass state\n",
+                target_pid_to_str (ptid_of (lp)),
+                target_signal_to_string (signo));
+      return 0;
+    }
+  else if (!program_signals_p
+          /* If we have no way to know which signals GDB does not
+             want to have passed to the program, assume
+             SIGTRAP/SIGINT, which is GDB's default.  */
+          && (signo == TARGET_SIGNAL_TRAP || signo == TARGET_SIGNAL_INT))
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "GPS: lwp %s had signal %s, "
+                "but we don't know if we should pass it.  Default to not.\n",
+                target_pid_to_str (ptid_of (lp)),
+                target_signal_to_string (signo));
+      return 0;
+    }
+  else
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "GPS: lwp %s has pending signal %s: delivering it.\n",
+                target_pid_to_str (ptid_of (lp)),
+                target_signal_to_string (signo));
+
+      return WSTOPSIG (status);
+    }
+}
+
 static int
 linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
 {
   struct thread_info *thread = (struct thread_info *) entry;
   struct lwp_info *lwp = get_thread_lwp (thread);
   int pid = * (int *) args;
+  int sig;
 
   if (ptid_get_pid (entry->id) != pid)
     return 0;
 
-  /* If this process is stopped but is expecting a SIGSTOP, then make
-     sure we take care of that now.  This isn't absolutely guaranteed
-     to collect the SIGSTOP, but is fairly likely to.  */
+  /* If there is a pending SIGSTOP, get rid of it.  */
   if (lwp->stop_expected)
     {
-      int wstat;
-      /* Clear stop_expected, so that the SIGSTOP will be reported.  */
+      if (debug_threads)
+       fprintf (stderr,
+                "Sending SIGCONT to %s\n",
+                target_pid_to_str (ptid_of (lwp)));
+
+      kill_lwp (lwpid_of (lwp), SIGCONT);
       lwp->stop_expected = 0;
-      linux_resume_one_lwp (lwp, 0, 0, NULL);
-      linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     }
 
   /* Flush any pending changes to the process's registers.  */
   regcache_invalidate_one ((struct inferior_list_entry *)
                           get_lwp_thread (lwp));
 
+  /* Pass on any pending signal for this thread.  */
+  sig = get_detach_signal (thread);
+
   /* Finally, let it resume.  */
   if (the_low_target.prepare_to_resume != NULL)
     the_low_target.prepare_to_resume (lwp);
-  ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0);
+  if (ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, sig) < 0)
+    error (_("Can't detach %s: %s"),
+          target_pid_to_str (ptid_of (lwp)),
+          strerror (errno));
 
   delete_lwp (lwp);
   return 0;
@@ -1390,7 +1482,7 @@ maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat)
   if ((wstat == NULL
        || (WIFSTOPPED (*wstat) && WSTOPSIG (*wstat) != SIGTRAP))
       && supports_fast_tracepoints ()
-      && in_process_agent_loaded ())
+      && agent_loaded_p ())
     {
       struct fast_tpoint_collect_status status;
       int r;
@@ -2321,7 +2413,7 @@ retry:
   if (WIFSTOPPED (w)
       && WSTOPSIG (w) != SIGTRAP
       && supports_fast_tracepoints ()
-      && in_process_agent_loaded ())
+      && agent_loaded_p ())
     {
       if (debug_threads)
        fprintf (stderr,
@@ -2875,7 +2967,7 @@ stuck_in_jump_pad_callback (struct inferior_list_entry *entry, void *data)
 
   /* Allow debugging the jump pad, gdb_collect, etc..  */
   return (supports_fast_tracepoints ()
-         && in_process_agent_loaded ()
+         && agent_loaded_p ()
          && (gdb_breakpoint_here (lwp->stop_pc)
              || lwp->stopped_by_watchpoint
              || thread->last_resume_kind == resume_step)
@@ -4854,6 +4946,12 @@ linux_supports_disable_randomization (void)
 #endif
 }
 
+static int
+linux_supports_agent (void)
+{
+  return 1;
+}
+
 /* Enumerate spufs IDs for process PID.  */
 static int
 spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
@@ -5243,7 +5341,16 @@ get_dynamic (const int pid, const int is_elf64)
 
   if (relocation == -1)
     {
-      warning ("Unexpected missing PT_PHDR");
+      /* PT_PHDR is optional, but necessary for PIE in general.  Fortunately
+        any real world executables, including PIE executables, have always
+        PT_PHDR present.  PT_PHDR is not present in some shared libraries or
+        in fpc (Free Pascal 2.4) binaries but neither of those have a need for
+        or present DT_DEBUG anyway (fpc binaries are statically linked).
+
+        Therefore if there exists DT_DEBUG there is always also PT_PHDR.
+
+        GDB could find RELOCATION also from AT_ENTRY - e_entry.  */
+
       return 0;
     }
 
@@ -5576,6 +5683,7 @@ static struct target_ops linux_target_ops = {
   linux_supports_disable_randomization,
   linux_get_min_fast_tracepoint_insn_len,
   linux_qxfer_libraries_svr4,
+  linux_supports_agent,
 };
 
 static void
This page took 0.038101 seconds and 4 git commands to generate.