aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/ChangeLog21
-rw-r--r--gdb/gdbserver/linux-low.c79
-rw-r--r--gdb/gdbserver/remote-utils.c13
-rw-r--r--gdb/gdbserver/server.c55
-rw-r--r--gdb/gdbserver/server.h1
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;