aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2012-03-07 19:25:39 +0000
committerPedro Alves <palves@redhat.com>2012-03-07 19:25:39 +0000
commit9b224c5e1a3d2a2d753affc760de2984b382617a (patch)
treeb9c52226128c098ead038f4690ba10ef24922ef9 /gdb/gdbserver
parent74c48cbbffd1812b819a0d1ddf1ff6eff282549c (diff)
downloadgdb-9b224c5e1a3d2a2d753affc760de2984b382617a.zip
gdb-9b224c5e1a3d2a2d753affc760de2984b382617a.tar.gz
gdb-9b224c5e1a3d2a2d753affc760de2984b382617a.tar.bz2
2012-03-07 Pedro Alves <palves@redhat.com>
gdb/doc/ * gdb.texinfo (General Query Packets): Document new QProgramSignals packet. * gdb.texinfo (Remote configuration): Mention "program-signals-packet". gdb/gdbserver/ * linux-low.c (get_detach_signal): New. (linux_detach_one_lwp): Get rid of a pending SIGSTOP with SIGCONT. Pass on pending signals to PTRACE_DETACH. Check the result of the ptrace call. * server.c (program_signals, program_signals_p): New. (handle_general_set): Handle QProgramSignals. * server.h (program_signals, program_signals_p): Declare. gdb/ * NEWS: Mention QProgramSignals. * inferior.h (update_signals_program_target): Declare. * infrun.c: (update_signals_program_target): New. (handle_command): Update the target of the new program signals array changes. * remote.c (PACKET_QProgramSignals): New enum. (last_program_signals_packet): New global. (remote_program_signals): New. (remote_start_remote): Update the target with the program signals list. (remote_protocol_features): Add entry for QPassSignals. (remote_open_1): Free anc clear last_program_signals_packet. (init_remote_ops): Install remote_program_signals. * target.c (update_current_target): Adjust. (target_program_signals): New. * target.h (struct target_ops) <to_program_signals>: New field. (target_program_signals): Declare.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/ChangeLog10
-rw-r--r--gdb/gdbserver/linux-low.c107
-rw-r--r--gdb/gdbserver/server.c33
-rw-r--r--gdb/gdbserver/server.h2
4 files changed, 143 insertions, 9 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index e1005ee..521866d 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,13 @@
+2012-03-07 Pedro Alves <palves@redhat.com>
+
+ * linux-low.c (get_detach_signal): New.
+ (linux_detach_one_lwp): Get rid of a pending SIGSTOP with SIGCONT.
+ Pass on pending signals to PTRACE_DETACH. Check the result of the
+ ptrace call.
+ * server.c (program_signals, program_signals_p): New.
+ (handle_general_set): Handle QProgramSignals.
+ * server.h (program_signals, program_signals_p): Declare.
+
2012-03-05 Pedro Alves <palves@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 4f8ec6b..997e5a0 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -999,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;
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 0de3f52..586581c 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -59,6 +59,8 @@ int debug_threads;
int debug_hw_points;
int pass_signals[TARGET_SIGNAL_LAST];
+int program_signals[TARGET_SIGNAL_LAST];
+int program_signals_p;
jmp_buf toplevel;
@@ -455,6 +457,33 @@ handle_general_set (char *own_buf)
return;
}
+ if (strncmp ("QProgramSignals:", own_buf, strlen ("QProgramSignals:")) == 0)
+ {
+ int numsigs = (int) TARGET_SIGNAL_LAST, i;
+ const char *p = own_buf + strlen ("QProgramSignals:");
+ CORE_ADDR cursig;
+
+ program_signals_p = 1;
+
+ p = decode_address_to_semicolon (&cursig, p);
+ for (i = 0; i < numsigs; i++)
+ {
+ if (i == cursig)
+ {
+ program_signals[i] = 1;
+ if (*p == '\0')
+ /* Keep looping, to clear the remaining signals. */
+ cursig = -1;
+ else
+ p = decode_address_to_semicolon (&cursig, p);
+ }
+ else
+ program_signals[i] = 0;
+ }
+ strcpy (own_buf, "OK");
+ return;
+ }
+
if (strcmp (own_buf, "QStartNoAckMode") == 0)
{
if (remote_debug)
@@ -1584,7 +1613,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
free (qsupported);
}
- sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);
+ sprintf (own_buf,
+ "PacketSize=%x;QPassSignals+;QProgramSignals+",
+ PBUFSIZ - 1);
if (the_target->qxfer_libraries_svr4 != NULL)
strcat (own_buf, ";qXfer:libraries-svr4:read+");
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index fad58e8..a419c36 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -292,6 +292,8 @@ extern int server_waiting;
extern int debug_threads;
extern int debug_hw_points;
extern int pass_signals[];
+extern int program_signals[];
+extern int program_signals_p;
extern jmp_buf toplevel;