diff options
author | Pedro Alves <palves@redhat.com> | 2012-03-07 19:25:39 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2012-03-07 19:25:39 +0000 |
commit | 9b224c5e1a3d2a2d753affc760de2984b382617a (patch) | |
tree | b9c52226128c098ead038f4690ba10ef24922ef9 /gdb/gdbserver | |
parent | 74c48cbbffd1812b819a0d1ddf1ff6eff282549c (diff) | |
download | gdb-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/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 107 | ||||
-rw-r--r-- | gdb/gdbserver/server.c | 33 | ||||
-rw-r--r-- | gdb/gdbserver/server.h | 2 |
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; |