From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3002 invoked by alias); 6 Mar 2012 18:26:59 -0000 Received: (qmail 2985 invoked by uid 22791); 6 Mar 2012 18:26:53 -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; Tue, 06 Mar 2012 18:26:35 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q26IQVLn022459 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 6 Mar 2012 13:26:35 -0500 Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q26IBYuc002822; Tue, 6 Mar 2012 13:11:34 -0500 Message-ID: <4F565356.6040302@redhat.com> Date: Tue, 06 Mar 2012 18:26:00 -0000 From: Pedro Alves User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.1) Gecko/20120216 Thunderbird/10.0.1 MIME-Version: 1.0 To: Pedro Alves CC: gdb-patches@sourceware.org Subject: Re: [PATCH] [RFC, docs RFA] gdbserver and gdb.threads/attach-into-signal.exp. References: <20120222171937.29946.56976.stgit@hit-nxdomain.opendns.com> In-Reply-To: <20120222171937.29946.56976.stgit@hit-nxdomain.opendns.com> 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-03/txt/msg00197.txt.bz2 Hi! Any further comments on this? Eli, this needs a documentation review. Thanks! -- Pedro Alves On 02/22/2012 05:19 PM, Pedro Alves wrote: > 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); >