diff options
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r-- | gdb/gdbserver/ChangeLog | 21 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 79 | ||||
-rw-r--r-- | gdb/gdbserver/remote-utils.c | 13 | ||||
-rw-r--r-- | gdb/gdbserver/server.c | 55 | ||||
-rw-r--r-- | gdb/gdbserver/server.h | 1 |
5 files changed, 136 insertions, 33 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 3d00ed4..2d04899 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,5 +1,26 @@ 2015-11-30 Pedro Alves <palves@redhat.com> + * linux-low.c (handle_extended_wait): Assert that the LWP's + waitstatus is TARGET_WAITKIND_IGNORE. If GDB wants to hear about + thread create events, leave the new child's status pending. + (linux_low_filter_event): If GDB wants to hear about thread exit + events, leave the LWP marked dead and don't delete it. + (linux_wait_for_event_filtered): Don't check for thread exit. + (filter_exit_event): New function. + (linux_wait_1): Use it, when returning an exit event. + (linux_resume_one_lwp_throw): Assert that the LWP's + waitstatus is TARGET_WAITKIND_IGNORE. + * remote-utils.c (prepare_resume_reply): Handle + TARGET_WAITKIND_THREAD_CREATED and TARGET_WAITKIND_THREAD_EXITED. + * server.c (report_thread_events): New global. + (handle_general_set): Handle QThreadEvents. + (handle_query) <qSupported>: Handle and report QThreadEvents+; + (handle_target_event): Handle TARGET_WAITKIND_THREAD_CREATED and + TARGET_WAITKIND_THREAD_EXITED. + * server.h (report_thread_events): Declare. + +2015-11-30 Pedro Alves <palves@redhat.com> + * linux-low.c (resume_stopped_resumed_lwps): Don't check whether the thread's last_resume_kind was resume_stop. diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 1f7d8d1..cde59a7 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -447,6 +447,8 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) struct thread_info *event_thr = get_lwp_thread (event_lwp); struct lwp_info *new_lwp; + gdb_assert (event_lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); + if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) || (event == PTRACE_EVENT_CLONE)) { @@ -577,6 +579,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) new_lwp->status_pending_p = 1; new_lwp->status_pending = status; } + else if (report_thread_events) + { + new_lwp->waitstatus.kind = TARGET_WAITKIND_THREAD_CREATED; + new_lwp->status_pending_p = 1; + new_lwp->status_pending = status; + } /* Don't report the event. */ return 1; @@ -2256,25 +2264,22 @@ linux_low_filter_event (int lwpid, int wstat) { if (debug_threads) debug_printf ("LLFE: %d exited.\n", lwpid); - if (num_lwps (pid_of (thread)) > 1) + /* If there is at least one more LWP, then the exit signal was + not the end of the debugged application and should be + ignored, unless GDB wants to hear about thread exits. */ + if (report_thread_events + || last_thread_of_process_p (pid_of (thread))) { - - /* If there is at least one more LWP, then the exit signal was - not the end of the debugged application and should be - ignored. */ - delete_lwp (child); - return NULL; + /* Since events are serialized to GDB core, and we can't + report this one right now. Leave the status pending for + the next time we're able to report it. */ + mark_lwp_dead (child, wstat); + return child; } else { - /* This was the last lwp in the process. Since events are - serialized to GDB core, and we can't report this one - right now, but GDB core and the other target layers will - want to be notified about the exit code/signal, leave the - status pending for the next time we're able to report - it. */ - mark_lwp_dead (child, wstat); - return child; + delete_lwp (child); + return NULL; } } @@ -2617,18 +2622,6 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid, current_thread = event_thread; - /* Check for thread exit. */ - if (! WIFSTOPPED (*wstatp)) - { - gdb_assert (last_thread_of_process_p (pid_of (event_thread))); - - if (debug_threads) - debug_printf ("LWP %d is the last lwp of process. " - "Process %ld exiting.\n", - pid_of (event_thread), lwpid_of (event_thread)); - return lwpid_of (event_thread); - } - return lwpid_of (event_thread); } @@ -2913,6 +2906,30 @@ ignore_event (struct target_waitstatus *ourstatus) return null_ptid; } +/* Convenience function that is called when the kernel reports an exit + event. This decides whether to report the event to GDB as a + process exit event, a thread exit event, or to suppress the + event. */ + +static ptid_t +filter_exit_event (struct lwp_info *event_child, + struct target_waitstatus *ourstatus) +{ + struct thread_info *thread = get_lwp_thread (event_child); + ptid_t ptid = ptid_of (thread); + + if (!last_thread_of_process_p (pid_of (thread))) + { + if (report_thread_events) + ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED; + else + ourstatus->kind = TARGET_WAITKIND_IGNORE; + + delete_lwp (event_child); + } + return ptid; +} + /* Wait for process, returns status. */ static ptid_t @@ -3018,6 +3035,9 @@ linux_wait_1 (ptid_t ptid, } } + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + return filter_exit_event (event_child, ourstatus); + return ptid_of (current_thread); } @@ -3507,6 +3527,9 @@ linux_wait_1 (ptid_t ptid, debug_exit (); } + if (ourstatus->kind == TARGET_WAITKIND_EXITED) + return filter_exit_event (event_child, ourstatus); + return ptid_of (current_thread); } @@ -3907,6 +3930,8 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, if (lwp->stopped == 0) return; + gdb_assert (lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); + fast_tp_collecting = lwp->collecting_fast_tracepoint; gdb_assert (!stabilizing_threads || fast_tp_collecting); diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index e366091..0d9cde3 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1119,6 +1119,7 @@ prepare_resume_reply (char *buf, ptid_t ptid, case TARGET_WAITKIND_VFORKED: case TARGET_WAITKIND_VFORK_DONE: case TARGET_WAITKIND_EXECD: + case TARGET_WAITKIND_THREAD_CREATED: { struct thread_info *saved_thread; const char **regp; @@ -1161,6 +1162,13 @@ prepare_resume_reply (char *buf, ptid_t ptid, status->value.execd_pathname = NULL; buf += strlen (buf); } + else if (status->kind == TARGET_WAITKIND_THREAD_CREATED + && report_thread_events) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + + sprintf (buf, "T%02xcreate:;", signal); + } else sprintf (buf, "T%02x", status->value.sig); @@ -1276,6 +1284,11 @@ prepare_resume_reply (char *buf, ptid_t ptid, else sprintf (buf, "X%02x", status->value.sig); break; + case TARGET_WAITKIND_THREAD_EXITED: + sprintf (buf, "w%x;", status->value.integer); + buf += strlen (buf); + buf = write_ptid (buf, ptid); + break; default: error ("unhandled waitkind"); break; diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index f6245d7..0762f6a 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -60,6 +60,7 @@ int multi_process; int report_fork_events; int report_vfork_events; int report_exec_events; +int report_thread_events; int non_stop; int swbreak_feature; int hwbreak_feature; @@ -723,6 +724,39 @@ handle_general_set (char *own_buf) if (handle_btrace_conf_general_set (own_buf)) return; + if (startswith (own_buf, "QThreadEvents:")) + { + char *mode = own_buf + strlen ("QThreadEvents:"); + enum tribool req = TRIBOOL_UNKNOWN; + + if (strcmp (mode, "0") == 0) + req = TRIBOOL_FALSE; + else if (strcmp (mode, "1") == 0) + req = TRIBOOL_TRUE; + else + { + char *mode_copy = xstrdup (mode); + + /* We don't know what this mode is, so complain to GDB. */ + sprintf (own_buf, "E.Unknown thread-events mode requested: %s\n", + mode_copy); + xfree (mode_copy); + return; + } + + report_thread_events = (req == TRIBOOL_TRUE); + + if (remote_debug) + { + const char *req_str = report_thread_events ? "enabled" : "disabled"; + + fprintf (stderr, "[thread events are now %s]\n", req_str); + } + + write_ok (own_buf); + return; + } + /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ own_buf[0] = 0; @@ -2151,6 +2185,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) } else if (strcmp (p, "vContSupported+") == 0) vCont_supported = 1; + else if (strcmp (p, "QThreadEvents+") == 0) + ; else { /* Move the unknown features all together. */ @@ -2271,6 +2307,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) strcat (own_buf, ";vContSupported+"); + strcat (own_buf, ";QThreadEvents+"); + /* Reinitialize components as needed for the new connection. */ hostio_handle_new_gdb_connection (); target_handle_new_gdb_connection (); @@ -4321,6 +4359,8 @@ handle_target_event (int err, gdb_client_data client_data) mark_breakpoints_out (process); mourn_inferior (process); } + else if (last_status.kind == TARGET_WAITKIND_THREAD_EXITED) + ; else { /* We're reporting this thread as stopped. Update its @@ -4338,7 +4378,11 @@ handle_target_event (int err, gdb_client_data client_data) exit (0); } - if (last_status.kind == TARGET_WAITKIND_STOPPED) + if (last_status.kind == TARGET_WAITKIND_EXITED + || last_status.kind == TARGET_WAITKIND_SIGNALLED + || last_status.kind == TARGET_WAITKIND_THREAD_EXITED) + ; + else { /* A thread stopped with a signal, but gdb isn't connected to handle it. Pass it down to the @@ -4353,13 +4397,12 @@ handle_target_event (int err, gdb_client_data client_data) resume_info.thread = last_ptid; resume_info.kind = resume_continue; - resume_info.sig = gdb_signal_to_host (last_status.value.sig); + if (last_status.kind == TARGET_WAITKIND_STOPPED) + resume_info.sig = gdb_signal_to_host (last_status.value.sig); + else + resume_info.sig = 0; (*the_target->resume) (&resume_info, 1); } - else if (debug_threads) - debug_printf ("GDB not connected; ignoring event %d for [%s]\n", - (int) last_status.kind, - target_pid_to_str (last_ptid)); } else { diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 96ad4fa..dc0361f 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -87,6 +87,7 @@ extern int multi_process; extern int report_fork_events; extern int report_vfork_events; extern int report_exec_events; +extern int report_thread_events; extern int non_stop; extern int extended_protocol; |