From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 23933 invoked by alias); 22 Feb 2012 17:20:13 -0000 Received: (qmail 23797 invoked by uid 22791); 22 Feb 2012 17:20:01 -0000 X-SWARE-Spam-Status: No, hits=-6.7 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_CP,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 22 Feb 2012 17:19:40 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q1MHJdre026872 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 22 Feb 2012 12:19:39 -0500 Received: from hit-nxdomain.opendns.com (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q1MHJbln007891 for ; Wed, 22 Feb 2012 12:19:38 -0500 Subject: [PATCH] [RFC, docs RFA] gdbserver and gdb.threads/attach-into-signal.exp. To: gdb-patches@sourceware.org From: Pedro Alves Date: Wed, 22 Feb 2012 19:29:00 -0000 Message-ID: <20120222171937.29946.56976.stgit@hit-nxdomain.opendns.com> User-Agent: StGit/0.15 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-02/txt/msg00482.txt.bz2 This patch fixes gdbserver so that it passes attach-into-signal.exp. Currently, we get (with the extended-remote board): Running ../../../src/gdb/testsuite/gdb.threads/attach-into-signal.exp ... FAIL: gdb.threads/attach-into-signal.exp: nonthreaded: detach (the program is no longer running) FAIL: gdb.threads/attach-into-signal.exp: nonthreaded: detach (the program is no longer running) FAIL: gdb.threads/attach-into-signal.exp: nonthreaded: detach (the program is no longer running) FAIL: gdb.threads/attach-into-signal.exp: nonthreaded: detach (the program is no longer running) FAIL: gdb.threads/attach-into-signal.exp: nonthreaded: detach (the program is no longer running) FAIL: gdb.threads/attach-into-signal.exp: nonthreaded: detach (the program is no longer running) FAIL: gdb.threads/attach-into-signal.exp: nonthreaded: detach (the program is no longer running) (...) The test exercises attaching and findind the program stops with a signal not SIGSTOP, and then detaching, then attaching, etc, in a loop. In gdb.log, we see: (gdb) attach 28431 Attaching to program: /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.threads/attach-into-signal-nothr, process 28431 Attached; pid = 28431 Program received signal SIGALRM, Alarm clock. Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libm.so.6 Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libc.so.6 Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 0x000000339e636285 in raise () from /lib64/libc.so.6 (gdb) PASS: gdb.threads/attach-into-signal.exp: nonthreaded: attach (pass 1), pending signal catch attach (pass 1), pending signal catch succeeded on the attempt # 2 of 100 detach Detaching from program: /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.threads/attach-into-signal-nothr, process 28431 Detaching from process 28431 (gdb) attach 28431 Attaching to program: /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.threads/attach-into-signal-nothr, process 28431 Attached; pid = 28431 Child terminated with signal = 0x6 (SIGABRT) warning: Selected architecture i386:x86-64 is not compatible with reported target architecture i386 warning: Architecture rejected target-supplied description Program terminated with signal SIGABRT, Aborted. The test code reads: raise (SIGALRM); /* We must not get past this point, either in a free standing or debugged state. */ abort (); The issue is that when GDBserver detaches the inferior, it forgets the SIGALRM signal it had found when it attached, so the inferior doesn't get the signal (it is suppressed) and reaches the abort. The fix is to make sure we forward the pending signals to the inferior on detach, like gdb/linux-nat.c does. gdb/linux-nat.c does not pass down to the inferior signals that are in the "handle SIG nopass" state, however. GDBserver has no idea currently about the pass/nopass state of signals, so in order for GDBserver to do the same GDB, we need to make GDB tell GDBserver about the pass/nopass state of all signals. This is recorded in GDB in the infrun.c:signal_program array. The patch adds a new RSP packet QProgramSignals (similar to QPassSignals, though with different semantics) to do exactly that. Comments on the approach? I first thought of augmenting the detach packet, but I quickly gave up, due to pending signals and multi-threading (any, or multiple threads can have pending signals that need to be delivered). I went back and forth between caring about "handle SIG nopass" at all. It is always possible a signal gets queued right after we check for "handle SIG nopass", so we could just punt it, but I think this handles 99.99% of the cases and its what a users expect in the common case (especially for the case of the signal that _has_ been reported to GDB, if one gets program stopped by SIGFOO, and SIGFOO is nopass, I think it's reasonable to expect that detach suppresses it). Tested on x86_64 Fedora 16, extended-remote gdbserver. No regressions. The test gdb.threads/attach-into-signal.exp test passes cleanly with the patch applied. 2012-02-22 Pedro Alves gdb/doc/ * gdb.texinfo (): Document new QProgramSignals packet. * gdb.texinfo (Remote configuration): Mention "program-signals-packet". (General Query Packets): Document QProgramSignals. gdb/gdbserver/ * linux-low.c (get_pending_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/ * 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) : New field. (target_program_signals): Declare. --- gdb/doc/gdb.texinfo | 46 ++++++++++++++++++++ gdb/gdbserver/linux-low.c | 105 ++++++++++++++++++++++++++++++++++++++++++--- gdb/gdbserver/server.c | 33 ++++++++++++++ gdb/gdbserver/server.h | 2 + gdb/inferior.h | 2 + gdb/infrun.c | 10 ++++ gdb/remote.c | 75 ++++++++++++++++++++++++++++++++ gdb/target.c | 31 +++++++++++++ gdb/target.h | 20 +++++++++ 9 files changed, 315 insertions(+), 9 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 73779a7..8223931 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -17453,6 +17453,10 @@ are: @tab @code{QPassSignals} @tab @code{handle @var{signal}} +@item @code{program-signals} +@tab @code{QProgramSignals} +@tab @code{handle @var{signal}} + @item @code{hostio-close-packet} @tab @code{vFile:close} @tab @code{remote get}, @code{remote put} @@ -34817,6 +34821,48 @@ command (@pxref{Remote Configuration, set remote pass-signals}). This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). +@item QProgramSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} +@cindex signals the inferior may see, remote request +@cindex @samp{QProgramSignals} packet +@anchor{QProgramSignals} +Each listed @var{signal} may be delivered to the inferior process. +Others should be silently discarded. + +In some cases, the remote stub may need to decide whether to deliver a +signal to the program or not without @value{GDBN} involvement. One +example of that is while detaching --- the program's threads may have +stopped for signals that haven't yet had a chance of being reported to +@value{GDBN}, and so the remote stub can use the signal list specified +by this packet to know whether to deliver or ignore those pending +signals. + +This does not influence whether to deliver a signal as requested by a +resumption packet (@pxref{vCont packet}). + +Signals are numbered identically to continue packets and stop replies +(@pxref{Stop Reply Packets}). Each @var{signal} list item should be +strictly greater than the previous item. Multiple +@samp{QProgramSignals} packets do not combine; any earlier +@samp{QProgramSignals} list is completely replaced by the new list. + +Reply: +@table @samp +@item OK +The request succeeded. + +@item E @var{nn} +An error occurred. @var{nn} are hex digits. + +@item +An empty reply indicates that @samp{QProgramSignals} is not supported +by the stub. +@end table + +Use of this packet is controlled by the @code{set remote program-signals} +command (@pxref{Remote Configuration, set remote program-signals}). +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item qRcmd,@var{command} @cindex execute remote command, remote request @cindex @samp{qRcmd} packet diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index ab34d84..5353cff 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -928,36 +928,125 @@ linux_kill (int pid) return 0; } +/* Get pending signal of LP, for detaching purposes. */ + +static int +get_pending_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_pending_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 37dc8d1..96429cb 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -58,6 +58,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; @@ -454,6 +456,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) @@ -1559,7 +1588,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 d3b4463..0a19664 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -288,6 +288,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; diff --git a/gdb/inferior.h b/gdb/inferior.h index 65abf26..2cd8be4 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -645,4 +645,6 @@ extern struct inferior *add_inferior_with_spaces (void); extern void update_observer_mode (void); +extern void update_signals_program_target (void); + #endif /* !defined (INFERIOR_H) */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 1b2da67..ee4b9a7 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -335,6 +335,15 @@ static unsigned char *signal_pass; (flags)[signum] = 0; \ } while (0) +/* Update the target's copy of SIGNAL_PROGRAM. The sole purpose of + this function is to avoid exporting `signal_program'. */ + +void +update_signals_program_target (void) +{ + target_program_signals ((int) TARGET_SIGNAL_LAST, signal_program); +} + /* Value to pass to target_resume() to cause all threads to resume. */ #define RESUME_ALL minus_one_ptid @@ -6358,6 +6367,7 @@ Are you sure you want to change it? "), { signal_cache_update (-1); target_pass_signals ((int) TARGET_SIGNAL_LAST, signal_pass); + target_program_signals ((int) TARGET_SIGNAL_LAST, signal_program); if (from_tty) { diff --git a/gdb/remote.c b/gdb/remote.c index 14c343b..4e6ff1c 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1254,6 +1254,7 @@ enum { PACKET_qGetTLSAddr, PACKET_qSupported, PACKET_QPassSignals, + PACKET_QProgramSignals, PACKET_qSearch_memory, PACKET_vAttach, PACKET_vRun, @@ -1662,6 +1663,65 @@ remote_pass_signals (int numsigs, unsigned char *pass_signals) } } +/* The last QProgramSignals packet sent to the target. We bypass + sending a new program signals list down to the target if the new + packet is exactly the same as the last we sent. IOW, we only let + the target know about program signals list changes. */ + +static char *last_program_signals_packet; + +/* If 'QProgramSignals' is supported, tell the remote stub what + signals it should pass through to the inferior when detaching. */ + +static void +remote_program_signals (int numsigs, unsigned char *signals) +{ + if (remote_protocol_packets[PACKET_QProgramSignals].support != PACKET_DISABLE) + { + char *packet, *p; + int count = 0, i; + + gdb_assert (numsigs < 256); + for (i = 0; i < numsigs; i++) + { + if (signals[i]) + count++; + } + packet = xmalloc (count * 3 + strlen ("QProgramSignals:") + 1); + strcpy (packet, "QProgramSignals:"); + p = packet + strlen (packet); + for (i = 0; i < numsigs; i++) + { + if (signal_pass_state (i)) + { + if (i >= 16) + *p++ = tohex (i >> 4); + *p++ = tohex (i & 15); + if (count) + *p++ = ';'; + else + break; + count--; + } + } + *p = 0; + if (!last_program_signals_packet + || strcmp (last_program_signals_packet, packet) != 0) + { + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + + putpkt (packet); + getpkt (&rs->buf, &rs->buf_size, 0); + packet_ok (buf, &remote_protocol_packets[PACKET_QProgramSignals]); + xfree (last_program_signals_packet); + last_program_signals_packet = packet; + } + else + xfree (packet); + } +} + /* If PTID is MAGIC_NULL_PTID, don't set any thread. If PTID is MINUS_ONE_PTID, set the thread to -1, so the stub returns the thread. If GEN is set, set the general thread, if not, then set @@ -3253,6 +3313,10 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) getpkt (&rs->buf, &rs->buf_size, 0); } + /* Let the target know which signals it is allowed to pass down to + the program. */ + update_signals_program_target (); + /* Next, if the target can specify a description, read it. We do this before anything involving memory or registers. */ target_find_description (); @@ -3800,6 +3864,8 @@ static struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_traceframe_info }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QPassSignals }, + { "QProgramSignals", PACKET_DISABLE, remote_supported_packet, + PACKET_QProgramSignals }, { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, PACKET_QStartNoAckMode }, { "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 }, @@ -4065,6 +4131,11 @@ remote_open_1 (char *name, int from_tty, xfree (last_pass_packet); last_pass_packet = NULL; + /* Make sure we send the program signals list the next time we + resume. */ + xfree (last_program_signals_packet); + last_program_signals_packet = NULL; + remote_fileio_reset (); reopen_exec_file (); reread_symbols (); @@ -10715,6 +10786,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_load = generic_load; remote_ops.to_mourn_inferior = remote_mourn; remote_ops.to_pass_signals = remote_pass_signals; + remote_ops.to_program_signals = remote_program_signals; remote_ops.to_thread_alive = remote_thread_alive; remote_ops.to_find_new_threads = remote_threads_info; remote_ops.to_pid_to_str = remote_pid_to_str; @@ -11156,6 +11228,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], "QPassSignals", "pass-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals], + "QProgramSignals", "program-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qSymbol], "qSymbol", "symbol-lookup", 0); diff --git a/gdb/target.c b/gdb/target.c index ad304bc..6098bd9 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -638,6 +638,7 @@ update_current_target (void) /* Do not inherit to_mourn_inferior. */ INHERIT (to_can_run, t); /* Do not inherit to_pass_signals. */ + /* Do not inherit to_program_signals. */ /* Do not inherit to_thread_alive. */ /* Do not inherit to_find_new_threads. */ /* Do not inherit to_pid_to_str. */ @@ -2713,6 +2714,36 @@ target_pass_signals (int numsigs, unsigned char *pass_signals) } } +void +target_program_signals (int numsigs, unsigned char *program_signals) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + { + if (t->to_program_signals != NULL) + { + if (targetdebug) + { + int i; + + fprintf_unfiltered (gdb_stdlog, "target_program_signals (%d, {", + numsigs); + + for (i = 0; i < numsigs; i++) + if (program_signals[i]) + fprintf_unfiltered (gdb_stdlog, " %s", + target_signal_to_name (i)); + + fprintf_unfiltered (gdb_stdlog, " })\n"); + } + + (*t->to_program_signals) (numsigs, program_signals); + return; + } + } +} + /* Look through the list of possible targets for a target that can follow forks. */ diff --git a/gdb/target.h b/gdb/target.h index d4605ae..f824ed4 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -509,6 +509,10 @@ struct target_ops target_* macro. */ void (*to_pass_signals) (int, unsigned char *); + /* Documentation of this routine is provided with the + corresponding target_* function. */ + void (*to_program_signals) (int, unsigned char *); + int (*to_thread_alive) (struct target_ops *, ptid_t ptid); void (*to_find_new_threads) (struct target_ops *); char *(*to_pid_to_str) (struct target_ops *, ptid_t); @@ -1242,6 +1246,22 @@ void target_mourn_inferior (void); extern void target_pass_signals (int nsig, unsigned char *pass_signals); +/* Set list of signals the target may pass to the inferior. This + directly maps to the "handle SIGNAL pass/nopass" setting. + + PROGRAM_SIGNALS is an array of size NSIG, indexed by target signal + number (enum target_signal). For every signal whose entry in this + array is non-zero, the target is allowed to pass the signal to the + inferior. Signals not present in the array shall be silently + discarded. This does not influence whether to pass signals to the + inferior as a result of a target_resume call. This is useful in + scenarios where the target needs to decide whether to pass or not a + signal to the inferior without GDB core involvement, such as for + example, when detaching (as threads may have been suspended with + pending signals not reported to GDB). */ + +extern void target_program_signals (int nsig, unsigned char *program_signals); + /* Check to see if a thread is still alive. */ extern int target_thread_alive (ptid_t ptid);