From 89be2091496d2a3166460875fea2a2778686f8d3 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Thu, 16 Nov 2006 15:08:25 +0000 Subject: [PATCH] gdb/ * remote.c (PACKET_QPassSignals): New. (last_pass_packet, remote_pass_signals): New. (remote_protocol_features): Add QPassSignals. (remote_query_supported): Correct an infinite loop. (remote_open_1): Reset last_pass_packet. (remote_resume): Call remote_pass_signals. (_initialize_remote): Register "set remote pass-signals". gdb/doc/ * gdb.texinfo (Remote configuration): Mention "pass-signals-packet". (General Query Packets): Document QPassSignals. Fix a typo. gdb/gdbserver/ * linux-low.c (linux_wait_for_event): Reformat. Use the pass_signals array. * remote-utils.c (decode_address_to_semicolon): New. * server.c (pass_signals, handle_general_set): New. (handle_query): Mention QPassSignals for qSupported. (main): Call handle_general_set. * server.h (pass_signals, decode_address_to_semicolon): New. --- gdb/ChangeLog | 10 ++++ gdb/doc/ChangeLog | 7 +++ gdb/doc/gdb.texinfo | 46 ++++++++++++++++-- gdb/gdbserver/ChangeLog | 10 ++++ gdb/gdbserver/linux-low.c | 113 +++++++++++++++++++++++-------------------- gdb/gdbserver/remote-utils.c | 16 ++++++ gdb/gdbserver/server.c | 41 +++++++++++++++- gdb/gdbserver/server.h | 2 + gdb/remote.c | 80 ++++++++++++++++++++++++++++-- 9 files changed, 264 insertions(+), 61 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6ff5bad..cda1e49 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2006-11-16 Daniel Jacobowitz + + * remote.c (PACKET_QPassSignals): New. + (last_pass_packet, remote_pass_signals): New. + (remote_protocol_features): Add QPassSignals. + (remote_query_supported): Correct an infinite loop. + (remote_open_1): Reset last_pass_packet. + (remote_resume): Call remote_pass_signals. + (_initialize_remote): Register "set remote pass-signals". + 2006-11-14 Maxim Grigoriev * NEWS: New port to Xtensa. diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 97f5018..ecf7a8c 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2006-11-16 Daniel Jacobowitz + + * gdb.texinfo (Remote configuration): Mention + "pass-signals-packet". + (General Query Packets): Document QPassSignals. Fix + a typo. + 2006-11-14 Maxim Grigoriev * gdb.texinfo (Contributors): Add contributors of Xtensa port. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0491816..f0b5f87 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -12841,6 +12841,10 @@ The available settings are: @tab @code{qSupported} @tab Remote communications parameters +@item @code{pass-signals-packet} +@tab @code{QPassSignals} +@tab @code{handle @var{signal}} + @end multitable @node remote stub @@ -23347,8 +23351,8 @@ The @samp{C}, @samp{c}, @samp{S}, @samp{s} and @samp{?} packets can receive any of the below as a reply. In the case of the @samp{C}, @samp{c}, @samp{S} and @samp{s} packets, that reply is only returned when the target halts. In the below the exact meaning of @dfn{signal -number} is poorly defined. In general one of the UNIX signal -numbering conventions is used. +number} is defined by the header @file{include/gdb/signals.h} in the +@value{GDBN} source code. As in the description of request packets, we include spaces in the reply templates for clarity; these are not part of the reply packet's @@ -23604,6 +23608,37 @@ Don't use this packet; use the @samp{qThreadExtraInfo} query instead Reply: see @code{remote.c:remote_unpack_thread_info_response()}. +@item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} +@cindex pass signals to inferior, remote request +@cindex @samp{QPassSignals} packet +Each listed @var{signal} should be passed directly to the inferior process. +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. These signals do not need to stop +the inferior, or be reported to @value{GDBN}. All other signals should be +reported to @value{GDBN}. Multiple @samp{QPassSignals} packets do not +combine; any earlier @samp{QPassSignals} list is completely replaced by the +new list. This packet improves performance when using @samp{handle +@var{signal} nostop noprint pass}. + +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{QPassSignals} is not supported by +the stub. +@end table + +Use of this packet is controlled by the @code{set remote pass-signals} +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 qRcmd,@var{command} @cindex execute remote command, remote request @cindex @samp{qRcmd} packet @@ -23747,6 +23782,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{QPassSignals} +@tab No +@tab @samp{-} +@tab Yes + @end multitable These are the currently defined stub features, in more detail: @@ -23862,7 +23902,7 @@ Access the target's @dfn{auxiliary vector}. @xref{OS Information, auxiliary vector}. Note @var{annex} must be empty. This packet is not probed by default; the remote stub must request it, -by suppling an appropriate @samp{qSupported} response (@pxref{qSupported}). +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). @end table @table @samp diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 3a53f86..fa7080f 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,13 @@ +2006-11-16 Daniel Jacobowitz + + * linux-low.c (linux_wait_for_event): Reformat. Use the + pass_signals array. + * remote-utils.c (decode_address_to_semicolon): New. + * server.c (pass_signals, handle_general_set): New. + (handle_query): Mention QPassSignals for qSupported. + (main): Call handle_general_set. + * server.h (pass_signals, decode_address_to_semicolon): New. + 2006-11-06 Daniel Jacobowitz * server.c (handle_query): Correct error handling for read_auxv. diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 2a780ea..83a56aa 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -498,69 +498,76 @@ linux_wait_for_event (struct thread_info *child) current_inferior = (struct thread_info *) find_inferior_id (&all_threads, event_child->tid); - if (using_threads) + /* Check for thread exit. */ + if (using_threads && ! WIFSTOPPED (wstat)) { - /* Check for thread exit. */ - if (! WIFSTOPPED (wstat)) - { - if (debug_threads) - fprintf (stderr, "Thread %ld (LWP %ld) exiting\n", - event_child->tid, event_child->head.id); + if (debug_threads) + fprintf (stderr, "Thread %ld (LWP %ld) exiting\n", + event_child->tid, event_child->head.id); - /* If the last thread is exiting, just return. */ - if (all_threads.head == all_threads.tail) - return wstat; + /* If the last thread is exiting, just return. */ + if (all_threads.head == all_threads.tail) + return wstat; - dead_thread_notify (event_child->tid); + dead_thread_notify (event_child->tid); - remove_inferior (&all_processes, &event_child->head); - free (event_child); - remove_thread (current_inferior); - current_inferior = (struct thread_info *) all_threads.head; + remove_inferior (&all_processes, &event_child->head); + free (event_child); + remove_thread (current_inferior); + current_inferior = (struct thread_info *) all_threads.head; - /* If we were waiting for this particular child to do something... - well, it did something. */ - if (child != NULL) - return wstat; + /* If we were waiting for this particular child to do something... + well, it did something. */ + if (child != NULL) + return wstat; - /* Wait for a more interesting event. */ - continue; - } + /* Wait for a more interesting event. */ + continue; + } - if (WIFSTOPPED (wstat) - && WSTOPSIG (wstat) == SIGSTOP - && event_child->stop_expected) - { - if (debug_threads) - fprintf (stderr, "Expected stop.\n"); - event_child->stop_expected = 0; - linux_resume_one_process (&event_child->head, - event_child->stepping, 0, NULL); - continue; - } + if (using_threads + && WIFSTOPPED (wstat) + && WSTOPSIG (wstat) == SIGSTOP + && event_child->stop_expected) + { + if (debug_threads) + fprintf (stderr, "Expected stop.\n"); + event_child->stop_expected = 0; + linux_resume_one_process (&event_child->head, + event_child->stepping, 0, NULL); + continue; + } - /* FIXME drow/2002-06-09: Get signal numbers from the inferior's - thread library? */ - if (WIFSTOPPED (wstat) - && (WSTOPSIG (wstat) == __SIGRTMIN - || WSTOPSIG (wstat) == __SIGRTMIN + 1)) - { - siginfo_t info, *info_p; + /* If GDB is not interested in this signal, don't stop other + threads, and don't report it to GDB. Just resume the + inferior right away. We do this for threading-related + signals as well as any that GDB specifically requested + we ignore. But never ignore SIGSTOP if we sent it + ourselves. */ + /* FIXME drow/2002-06-09: Get signal numbers from the inferior's + thread library? */ + if (WIFSTOPPED (wstat) + && ((using_threads && (WSTOPSIG (wstat) == __SIGRTMIN + || WSTOPSIG (wstat) == __SIGRTMIN + 1)) + || (pass_signals[target_signal_from_host (WSTOPSIG (wstat))] + && (WSTOPSIG (wstat) != SIGSTOP + || !event_child->sigstop_sent)))) + { + siginfo_t info, *info_p; - if (debug_threads) - fprintf (stderr, "Ignored signal %d for %ld (LWP %ld).\n", - WSTOPSIG (wstat), event_child->tid, - event_child->head.id); + if (debug_threads) + fprintf (stderr, "Ignored signal %d for %ld (LWP %ld).\n", + WSTOPSIG (wstat), event_child->tid, + event_child->head.id); - if (ptrace (PTRACE_GETSIGINFO, event_child->lwpid, 0, &info) == 0) - info_p = &info; - else - info_p = NULL; - linux_resume_one_process (&event_child->head, - event_child->stepping, - WSTOPSIG (wstat), info_p); - continue; - } + if (ptrace (PTRACE_GETSIGINFO, event_child->lwpid, 0, &info) == 0) + info_p = &info; + else + info_p = NULL; + linux_resume_one_process (&event_child->head, + event_child->stepping, + WSTOPSIG (wstat), info_p); + continue; } /* If this event was not handled above, and is not a SIGTRAP, report diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index eb5d05d..fd5c844 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -296,6 +296,22 @@ decode_address (CORE_ADDR *addrp, const char *start, int len) *addrp = addr; } +const char * +decode_address_to_semicolon (CORE_ADDR *addrp, const char *start) +{ + const char *end; + + end = start; + while (*end != '\0' && *end != ';') + end++; + + decode_address (addrp, start, end - start); + + if (*end == ';') + end++; + return end; +} + /* Convert number NIB to a hex digit. */ static int diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 5f78736..10a891e 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -36,6 +36,8 @@ unsigned long old_thread_from_wait; int extended_protocol; int server_waiting; +int pass_signals[TARGET_SIGNAL_LAST]; + jmp_buf toplevel; /* The PID of the originally created or attached inferior. Used to @@ -157,6 +159,40 @@ write_qxfer_response (char *buf, unsigned char *data, int len, int is_more) PBUFSIZ - 2) + 1; } +/* Handle all of the extended 'Q' packets. */ +void +handle_general_set (char *own_buf) +{ + if (strncmp ("QPassSignals:", own_buf, strlen ("QPassSignals:")) == 0) + { + int numsigs = (int) TARGET_SIGNAL_LAST, i; + const char *p = own_buf + strlen ("QPassSignals:"); + CORE_ADDR cursig; + + p = decode_address_to_semicolon (&cursig, p); + for (i = 0; i < numsigs; i++) + { + if (i == cursig) + { + pass_signals[i] = 1; + if (*p == '\0') + /* Keep looping, to clear the remaining signals. */ + cursig = -1; + else + p = decode_address_to_semicolon (&cursig, p); + } + else + pass_signals[i] = 0; + } + strcpy (own_buf, "OK"); + return; + } + + /* Otherwise we didn't know what packet it was. Say we didn't + understand it. */ + own_buf[0] = 0; +} + /* Handle all of the extended 'q' packets. */ void handle_query (char *own_buf, int *new_packet_len_p) @@ -248,7 +284,7 @@ handle_query (char *own_buf, int *new_packet_len_p) if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) { - sprintf (own_buf, "PacketSize=%x", PBUFSIZ - 1); + sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1); if (the_target->read_auxv != NULL) strcat (own_buf, ";qXfer:auxv:read+"); @@ -601,6 +637,9 @@ main (int argc, char *argv[]) case 'q': handle_query (own_buf, &new_packet_len); break; + case 'Q': + handle_general_set (own_buf); + break; case 'd': remote_debug = !remote_debug; break; diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 5e7d394..e1fad45 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -129,6 +129,7 @@ extern unsigned long step_thread; extern unsigned long thread_from_wait; extern unsigned long old_thread_from_wait; extern int server_waiting; +extern int pass_signals[]; extern jmp_buf toplevel; @@ -153,6 +154,7 @@ void new_thread_notify (int id); void dead_thread_notify (int id); void prepare_resume_reply (char *buf, char status, unsigned char sig); +const char *decode_address_to_semicolon (CORE_ADDR *addrp, const char *start); void decode_address (CORE_ADDR *addrp, const char *start, int len); void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr, unsigned int *len_ptr); diff --git a/gdb/remote.c b/gdb/remote.c index afbec0d..513b6c7 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -867,6 +867,7 @@ enum { PACKET_qXfer_memory_map, PACKET_qGetTLSAddr, PACKET_qSupported, + PACKET_QPassSignals, PACKET_MAX }; @@ -1004,6 +1005,65 @@ record_currthread (int currthread) } } +static char *last_pass_packet; + +/* If 'QPassSignals' is supported, tell the remote stub what signals + it can simply pass through to the inferior without reporting. */ + +static void +remote_pass_signals (void) +{ + if (remote_protocol_packets[PACKET_QPassSignals].support != PACKET_DISABLE) + { + char *pass_packet, *p; + int numsigs = (int) TARGET_SIGNAL_LAST; + int count = 0, i; + + gdb_assert (numsigs < 256); + for (i = 0; i < numsigs; i++) + { + if (signal_stop_state (i) == 0 + && signal_print_state (i) == 0 + && signal_pass_state (i) == 1) + count++; + } + pass_packet = xmalloc (count * 3 + strlen ("QPassSignals:") + 1); + strcpy (pass_packet, "QPassSignals:"); + p = pass_packet + strlen (pass_packet); + for (i = 0; i < numsigs; i++) + { + if (signal_stop_state (i) == 0 + && signal_print_state (i) == 0 + && signal_pass_state (i) == 1) + { + if (i >= 16) + *p++ = tohex (i >> 4); + *p++ = tohex (i & 15); + if (count) + *p++ = ';'; + else + break; + count--; + } + } + *p = 0; + if (!last_pass_packet || strcmp (last_pass_packet, pass_packet)) + { + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + + putpkt (pass_packet); + getpkt (&rs->buf, &rs->buf_size, 0); + packet_ok (buf, &remote_protocol_packets[PACKET_QPassSignals]); + if (last_pass_packet) + xfree (last_pass_packet); + last_pass_packet = pass_packet; + } + else + xfree (pass_packet); + } +} + #define MAGIC_NULL_PID 42000 static void @@ -2206,7 +2266,9 @@ static struct protocol_feature remote_protocol_features[] = { { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_auxv }, { "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet, - PACKET_qXfer_memory_map } + PACKET_qXfer_memory_map }, + { "QPassSignals", PACKET_DISABLE, remote_supported_packet, + PACKET_QPassSignals }, }; static void @@ -2260,14 +2322,14 @@ remote_query_supported (void) } else { + *end = '\0'; + next = end + 1; + if (end == p) { warning (_("empty item in \"qSupported\" response")); continue; } - - *end = '\0'; - next = end + 1; } name_end = strchr (p, '='); @@ -2354,6 +2416,10 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target, unpush_target (target); + /* Make sure we send the passed signals list the next time we resume. */ + xfree (last_pass_packet); + last_pass_packet = NULL; + remote_fileio_reset (); reopen_exec_file (); reread_symbols (); @@ -2728,6 +2794,9 @@ remote_resume (ptid_t ptid, int step, enum target_signal siggnal) if (deprecated_target_resume_hook) (*deprecated_target_resume_hook) (); + /* Update the inferior on signals to silently pass, if they've changed. */ + remote_pass_signals (); + /* The vCont packet doesn't need to specify threads via Hc. */ if (remote_vcont_resume (ptid, step, siggnal)) return; @@ -6281,6 +6350,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_vCont], "vCont", "verbose-resume", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], + "QPassSignals", "pass-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qSymbol], "qSymbol", "symbol-lookup", 0); -- 2.7.4