GDBserver disconnected tracing support.
* linux-low.c (linux_remove_process): Delete. (add_lwp): Don't set last_resume_kind here. (linux_kill): Use `mourn'. (linux_detach): Use `thread_db_detach', and `mourn'. (linux_mourn): New. (linux_attach_lwp_1): Adjust comment. (linux_attach): last_resume_kind moved the thread_info; adjust. (status_pending_p_callback): Adjust. (linux_wait_for_event_1): Adjust. (count_events_callback, select_singlestep_lwp_callback) (select_event_lwp_callback, cancel_breakpoints_callback) (db_wants_lwp_stopped, linux_wait_1, need_step_over_p) (proceed_one_lwp): Adjust. (linux_async): Add debug output. (linux_thread_stopped): New. (linux_pause_all): New. (linux_target_ops): Install linux_mourn, linux_thread_stopped and linux_pause_all. * linux-low.h (struct lwp_info): Delete last_resume_kind field. (thread_db_free): Delete declaration. (thread_db_detach, thread_db_mourn): Declare. * thread-db.c (thread_db_init): Use thread_db_mourn. (thread_db_free): Delete, split in two. (disable_thread_event_reporting): New. (thread_db_detach): New. (thread_db_mourn): New. * server.h (struct thread_info) <last_resume_kind>: New field. <attached>: Add comment. <gdb_detached>: New field. (handler_func): Change return type to int. (handle_serial_event, handle_target_event): Ditto. (gdb_connected): Declare. (tracing): Delete. (disconnected_tracing): Declare. (stop_tracing): Declare. * server.c (handle_query) <qSupported>: Report support for disconnected tracing. (queue_stop_reply_callback): Account for running threads. (gdb_wants_thread_stopped): New. (gdb_wants_all_threads_stopped): New. (gdb_reattached_process): New. (handle_status): Clear the `gdb_detached' flag of all processes. In all-stop, stop all threads. (main): Be sure to leave tfind mode. Handle disconnected tracing. (process_serial_event): If the remote connection breaks, or if an exit was forced with "monitor exit", force an event loop exit. Handle disconnected tracing on detach. (handle_serial_event): Adjust. (handle_target_event): If GDB isn't connected, forward events back to the inferior, unless the last process exited, in which case, exit gdbserver. Adjust interface. * remote-utils.c (remote_open): Don't block in accept. Instead register an event loop source on the listen socket file descriptor. Refactor bits into ... (listen_desc): ... this new global. (gdb_connected): ... this new function. (enable_async_notification): ... this new function. (handle_accept_event): ... this new function. (remote_close): Clear remote_desc. * inferiors.c (add_thread): Set the new thread's last_resume_kind. * target.h (struct target_ops) <mourn, thread_stopped, pause_all>: New fields. (mourn_inferior): Define. (target_process_qsupported): Avoid the dangling else problem. (thread_stopped): Define. (pause_all): Define. (target_waitstatus_to_string): Declare. * target.c (target_waitstatus_to_string): New. * tracepoint.c (tracing): Make extern. (disconnected_tracing): New. (stop_tracing): Make extern. Handle tracing stops due to GDB disconnecting. (cmd_qtdisconnected): New. (cmd_qtstatus): Report disconnected tracing status in trace reply. (handle_tracepoint_general_set): Handle QTDisconnected. * event-loop.c (event_handler_func): Change return type to int. (process_event): Bail out if the event handler wants the event loop to stop. (handle_file_event): Ditto. (start_event_loop): Bail out if the event handler wants the event loop to stop. * nto-low.c (nto_target_ops): Adjust. * spu-low.c (spu_wait): Don't remove the process here. (spu_target_ops): Adjust. * win32-low.c (win32_wait): Don't remove the process here. (win32_target_ops): Adjust.
This commit is contained in:
parent
5d267c4c70
commit
8336d594d5
@ -1,3 +1,102 @@
|
||||
2010-04-11 Pedro Alves <pedro@codesourcery.com>
|
||||
|
||||
GDBserver disconnected tracing support.
|
||||
|
||||
* linux-low.c (linux_remove_process): Delete.
|
||||
(add_lwp): Don't set last_resume_kind here.
|
||||
(linux_kill): Use `mourn'.
|
||||
(linux_detach): Use `thread_db_detach', and `mourn'.
|
||||
(linux_mourn): New.
|
||||
(linux_attach_lwp_1): Adjust comment.
|
||||
(linux_attach): last_resume_kind moved the thread_info; adjust.
|
||||
(status_pending_p_callback): Adjust.
|
||||
(linux_wait_for_event_1): Adjust.
|
||||
(count_events_callback, select_singlestep_lwp_callback)
|
||||
(select_event_lwp_callback, cancel_breakpoints_callback)
|
||||
(db_wants_lwp_stopped, linux_wait_1, need_step_over_p)
|
||||
(proceed_one_lwp): Adjust.
|
||||
(linux_async): Add debug output.
|
||||
(linux_thread_stopped): New.
|
||||
(linux_pause_all): New.
|
||||
(linux_target_ops): Install linux_mourn, linux_thread_stopped and
|
||||
linux_pause_all.
|
||||
* linux-low.h (struct lwp_info): Delete last_resume_kind field.
|
||||
(thread_db_free): Delete declaration.
|
||||
(thread_db_detach, thread_db_mourn): Declare.
|
||||
* thread-db.c (thread_db_init): Use thread_db_mourn.
|
||||
(thread_db_free): Delete, split in two.
|
||||
(disable_thread_event_reporting): New.
|
||||
(thread_db_detach): New.
|
||||
(thread_db_mourn): New.
|
||||
|
||||
* server.h (struct thread_info) <last_resume_kind>: New field.
|
||||
<attached>: Add comment.
|
||||
<gdb_detached>: New field.
|
||||
(handler_func): Change return type to int.
|
||||
(handle_serial_event, handle_target_event): Ditto.
|
||||
(gdb_connected): Declare.
|
||||
(tracing): Delete.
|
||||
(disconnected_tracing): Declare.
|
||||
(stop_tracing): Declare.
|
||||
|
||||
* server.c (handle_query) <qSupported>: Report support for
|
||||
disconnected tracing.
|
||||
(queue_stop_reply_callback): Account for running threads.
|
||||
(gdb_wants_thread_stopped): New.
|
||||
(gdb_wants_all_threads_stopped): New.
|
||||
(gdb_reattached_process): New.
|
||||
(handle_status): Clear the `gdb_detached' flag of all processes.
|
||||
In all-stop, stop all threads.
|
||||
(main): Be sure to leave tfind mode. Handle disconnected tracing.
|
||||
(process_serial_event): If the remote connection breaks, or if an
|
||||
exit was forced with "monitor exit", force an event loop exit.
|
||||
Handle disconnected tracing on detach.
|
||||
(handle_serial_event): Adjust.
|
||||
(handle_target_event): If GDB isn't connected, forward events back
|
||||
to the inferior, unless the last process exited, in which case,
|
||||
exit gdbserver. Adjust interface.
|
||||
|
||||
* remote-utils.c (remote_open): Don't block in accept. Instead
|
||||
register an event loop source on the listen socket file
|
||||
descriptor. Refactor bits into ...
|
||||
(listen_desc): ... this new global.
|
||||
(gdb_connected): ... this new function.
|
||||
(enable_async_notification): ... this new function.
|
||||
(handle_accept_event): ... this new function.
|
||||
(remote_close): Clear remote_desc.
|
||||
|
||||
* inferiors.c (add_thread): Set the new thread's last_resume_kind.
|
||||
|
||||
* target.h (struct target_ops) <mourn, thread_stopped, pause_all>:
|
||||
New fields.
|
||||
(mourn_inferior): Define.
|
||||
(target_process_qsupported): Avoid the dangling else problem.
|
||||
(thread_stopped): Define.
|
||||
(pause_all): Define.
|
||||
(target_waitstatus_to_string): Declare.
|
||||
* target.c (target_waitstatus_to_string): New.
|
||||
|
||||
* tracepoint.c (tracing): Make extern.
|
||||
(disconnected_tracing): New.
|
||||
(stop_tracing): Make extern. Handle tracing stops due to GDB
|
||||
disconnecting.
|
||||
(cmd_qtdisconnected): New.
|
||||
(cmd_qtstatus): Report disconnected tracing status in trace reply.
|
||||
(handle_tracepoint_general_set): Handle QTDisconnected.
|
||||
|
||||
* event-loop.c (event_handler_func): Change return type to int.
|
||||
(process_event): Bail out if the event handler wants the event
|
||||
loop to stop.
|
||||
(handle_file_event): Ditto.
|
||||
(start_event_loop): Bail out if the event handler wants the event
|
||||
loop to stop.
|
||||
|
||||
* nto-low.c (nto_target_ops): Adjust.
|
||||
* spu-low.c (spu_wait): Don't remove the process here.
|
||||
(spu_target_ops): Adjust.
|
||||
* win32-low.c (win32_wait): Don't remove the process here.
|
||||
(win32_target_ops): Adjust.
|
||||
|
||||
2010-04-11 Pedro Alves <pedro@codesourcery.com>
|
||||
|
||||
* regcache.c (realloc_register_cache): Invalidate inferior's
|
||||
|
@ -39,7 +39,7 @@
|
||||
#endif
|
||||
|
||||
typedef struct gdb_event gdb_event;
|
||||
typedef void (event_handler_func) (int);
|
||||
typedef int (event_handler_func) (int);
|
||||
|
||||
/* Tell create_file_handler what events we are interested in. */
|
||||
|
||||
@ -211,7 +211,8 @@ process_event (void)
|
||||
free (event_ptr);
|
||||
|
||||
/* Now call the procedure associated with the event. */
|
||||
(*proc) (fd);
|
||||
if ((*proc) (fd))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -347,7 +348,7 @@ delete_file_handler (int fd)
|
||||
through event_ptr->proc. EVENT_FILE_DESC is file descriptor of the
|
||||
event in the front of the event queue. */
|
||||
|
||||
static void
|
||||
static int
|
||||
handle_file_event (int event_file_desc)
|
||||
{
|
||||
file_handler *file_ptr;
|
||||
@ -378,10 +379,16 @@ handle_file_event (int event_file_desc)
|
||||
|
||||
/* If there was a match, then call the handler. */
|
||||
if (mask != 0)
|
||||
(*file_ptr->proc) (file_ptr->error, file_ptr->client_data);
|
||||
{
|
||||
if ((*file_ptr->proc) (file_ptr->error,
|
||||
file_ptr->client_data) < 0)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a file event, to be enqueued in the event queue for
|
||||
@ -491,7 +498,13 @@ start_event_loop (void)
|
||||
while (1)
|
||||
{
|
||||
/* Any events already waiting in the queue? */
|
||||
if (process_event ())
|
||||
int res = process_event ();
|
||||
|
||||
/* Did the event handler want the event loop to stop? */
|
||||
if (res == -1)
|
||||
return;
|
||||
|
||||
if (res)
|
||||
continue;
|
||||
|
||||
/* Wait for a new event. If wait_for_event returns -1, we
|
||||
|
@ -171,6 +171,7 @@ add_thread (ptid_t thread_id, void *target_data)
|
||||
memset (new_thread, 0, sizeof (*new_thread));
|
||||
|
||||
new_thread->entry.id = thread_id;
|
||||
new_thread->last_resume_kind = resume_continue;
|
||||
new_thread->last_status.kind = TARGET_WAITKIND_IGNORE;
|
||||
|
||||
add_inferior_to_list (&all_threads, & new_thread->entry);
|
||||
|
@ -287,19 +287,6 @@ linux_add_process (int pid, int attached)
|
||||
return proc;
|
||||
}
|
||||
|
||||
/* Remove a process from the common process list,
|
||||
also freeing all private data. */
|
||||
|
||||
static void
|
||||
linux_remove_process (struct process_info *process)
|
||||
{
|
||||
struct process_info_private *priv = process->private;
|
||||
|
||||
free (priv->arch_private);
|
||||
free (priv);
|
||||
remove_process (process);
|
||||
}
|
||||
|
||||
/* Wrapper function for waitpid which handles EINTR, and emulates
|
||||
__WALL for systems where that is not available. */
|
||||
|
||||
@ -534,8 +521,6 @@ add_lwp (ptid_t ptid)
|
||||
|
||||
lwp->head.id = ptid;
|
||||
|
||||
lwp->last_resume_kind = resume_continue;
|
||||
|
||||
if (the_low_target.new_thread != NULL)
|
||||
lwp->arch_private = the_low_target.new_thread ();
|
||||
|
||||
@ -644,7 +629,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
|
||||
of a new thread that is being created.
|
||||
In this case we should ignore that SIGSTOP and resume the
|
||||
process. This is handled below by setting stop_expected = 1,
|
||||
and the fact that add_lwp sets last_resume_kind ==
|
||||
and the fact that add_thread sets last_resume_kind ==
|
||||
resume_continue.
|
||||
|
||||
2) This is the first thread (the process thread), and we're attaching
|
||||
@ -680,19 +665,17 @@ linux_attach_lwp (unsigned long lwpid)
|
||||
int
|
||||
linux_attach (unsigned long pid)
|
||||
{
|
||||
struct lwp_info *lwp;
|
||||
|
||||
linux_attach_lwp_1 (pid, 1);
|
||||
|
||||
linux_add_process (pid, 1);
|
||||
|
||||
if (!non_stop)
|
||||
{
|
||||
/* Don't ignore the initial SIGSTOP if we just attached to this
|
||||
process. It will be collected by wait shortly. */
|
||||
lwp = (struct lwp_info *) find_inferior_id (&all_lwps,
|
||||
ptid_build (pid, pid, 0));
|
||||
lwp->last_resume_kind = resume_stop;
|
||||
struct thread_info *thread;
|
||||
|
||||
/* Don't ignore the initial SIGSTOP if we just attached to this
|
||||
process. It will be collected by wait shortly. */
|
||||
thread = find_thread_ptid (ptid_build (pid, pid, 0));
|
||||
thread->last_resume_kind = resume_stop;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -808,11 +791,9 @@ linux_kill (int pid)
|
||||
lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
|
||||
} while (lwpid > 0 && WIFSTOPPED (wstat));
|
||||
|
||||
#ifdef USE_THREAD_DB
|
||||
thread_db_free (process, 0);
|
||||
#endif
|
||||
delete_lwp (lwp);
|
||||
linux_remove_process (process);
|
||||
|
||||
the_target->mourn (process);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -893,7 +874,7 @@ linux_detach (int pid)
|
||||
return -1;
|
||||
|
||||
#ifdef USE_THREAD_DB
|
||||
thread_db_free (process, 1);
|
||||
thread_db_detach (process);
|
||||
#endif
|
||||
|
||||
current_inferior =
|
||||
@ -901,10 +882,27 @@ linux_detach (int pid)
|
||||
|
||||
delete_all_breakpoints ();
|
||||
find_inferior (&all_threads, linux_detach_one_lwp, &pid);
|
||||
linux_remove_process (process);
|
||||
|
||||
the_target->mourn (process);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
linux_mourn (struct process_info *process)
|
||||
{
|
||||
struct process_info_private *priv;
|
||||
|
||||
#ifdef USE_THREAD_DB
|
||||
thread_db_mourn (process);
|
||||
#endif
|
||||
|
||||
/* Freeing all private data. */
|
||||
priv = process->private;
|
||||
free (priv->arch_private);
|
||||
free (priv);
|
||||
process->private = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
linux_join (int pid)
|
||||
{
|
||||
@ -955,7 +953,7 @@ status_pending_p_callback (struct inferior_list_entry *entry, void *arg)
|
||||
|
||||
/* If we got a `vCont;t', but we haven't reported a stop yet, do
|
||||
report any status pending the LWP may have. */
|
||||
if (lwp->last_resume_kind == resume_stop
|
||||
if (thread->last_resume_kind == resume_stop
|
||||
&& thread->last_status.kind == TARGET_WAITKIND_STOPPED)
|
||||
return 0;
|
||||
|
||||
@ -1377,7 +1375,7 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
|
||||
fprintf (stderr, "Expected stop.\n");
|
||||
event_child->stop_expected = 0;
|
||||
|
||||
should_stop = (event_child->last_resume_kind == resume_stop
|
||||
should_stop = (current_inferior->last_resume_kind == resume_stop
|
||||
|| stopping_threads);
|
||||
|
||||
if (!should_stop)
|
||||
@ -1442,14 +1440,15 @@ static int
|
||||
count_events_callback (struct inferior_list_entry *entry, void *data)
|
||||
{
|
||||
struct lwp_info *lp = (struct lwp_info *) entry;
|
||||
struct thread_info *thread = get_lwp_thread (lp);
|
||||
int *count = data;
|
||||
|
||||
gdb_assert (count != NULL);
|
||||
|
||||
/* Count only resumed LWPs that have a SIGTRAP event pending that
|
||||
should be reported to GDB. */
|
||||
if (get_lwp_thread (lp)->last_status.kind == TARGET_WAITKIND_IGNORE
|
||||
&& lp->last_resume_kind != resume_stop
|
||||
if (thread->last_status.kind == TARGET_WAITKIND_IGNORE
|
||||
&& thread->last_resume_kind != resume_stop
|
||||
&& lp->status_pending_p
|
||||
&& WIFSTOPPED (lp->status_pending)
|
||||
&& WSTOPSIG (lp->status_pending) == SIGTRAP
|
||||
@ -1465,9 +1464,10 @@ static int
|
||||
select_singlestep_lwp_callback (struct inferior_list_entry *entry, void *data)
|
||||
{
|
||||
struct lwp_info *lp = (struct lwp_info *) entry;
|
||||
struct thread_info *thread = get_lwp_thread (lp);
|
||||
|
||||
if (get_lwp_thread (lp)->last_status.kind == TARGET_WAITKIND_IGNORE
|
||||
&& lp->last_resume_kind == resume_step
|
||||
if (thread->last_status.kind == TARGET_WAITKIND_IGNORE
|
||||
&& thread->last_resume_kind == resume_step
|
||||
&& lp->status_pending_p)
|
||||
return 1;
|
||||
else
|
||||
@ -1481,13 +1481,14 @@ static int
|
||||
select_event_lwp_callback (struct inferior_list_entry *entry, void *data)
|
||||
{
|
||||
struct lwp_info *lp = (struct lwp_info *) entry;
|
||||
struct thread_info *thread = get_lwp_thread (lp);
|
||||
int *selector = data;
|
||||
|
||||
gdb_assert (selector != NULL);
|
||||
|
||||
/* Select only resumed LWPs that have a SIGTRAP event pending. */
|
||||
if (lp->last_resume_kind != resume_stop
|
||||
&& get_lwp_thread (lp)->last_status.kind == TARGET_WAITKIND_IGNORE
|
||||
if (thread->last_resume_kind != resume_stop
|
||||
&& thread->last_status.kind == TARGET_WAITKIND_IGNORE
|
||||
&& lp->status_pending_p
|
||||
&& WIFSTOPPED (lp->status_pending)
|
||||
&& WSTOPSIG (lp->status_pending) == SIGTRAP
|
||||
@ -1502,6 +1503,7 @@ static int
|
||||
cancel_breakpoints_callback (struct inferior_list_entry *entry, void *data)
|
||||
{
|
||||
struct lwp_info *lp = (struct lwp_info *) entry;
|
||||
struct thread_info *thread = get_lwp_thread (lp);
|
||||
struct lwp_info *event_lp = data;
|
||||
|
||||
/* Leave the LWP that has been elected to receive a SIGTRAP alone. */
|
||||
@ -1519,8 +1521,8 @@ cancel_breakpoints_callback (struct inferior_list_entry *entry, void *data)
|
||||
delete or disable the breakpoint, but the LWP will have already
|
||||
tripped on it. */
|
||||
|
||||
if (lp->last_resume_kind != resume_stop
|
||||
&& get_lwp_thread (lp)->last_status.kind == TARGET_WAITKIND_IGNORE
|
||||
if (thread->last_resume_kind != resume_stop
|
||||
&& thread->last_status.kind == TARGET_WAITKIND_IGNORE
|
||||
&& lp->status_pending_p
|
||||
&& WIFSTOPPED (lp->status_pending)
|
||||
&& WSTOPSIG (lp->status_pending) == SIGTRAP
|
||||
@ -1597,7 +1599,7 @@ gdb_wants_lwp_stopped (struct inferior_list_entry *entry)
|
||||
thread->last_status.kind = TARGET_WAITKIND_STOPPED;
|
||||
thread->last_status.value.sig = TARGET_SIGNAL_0;
|
||||
|
||||
lwp->last_resume_kind = resume_stop;
|
||||
thread->last_resume_kind = resume_stop;
|
||||
}
|
||||
|
||||
/* Set all LWP's states as "want-stopped". */
|
||||
@ -1691,14 +1693,7 @@ retry:
|
||||
{
|
||||
if (WIFEXITED (w) || WIFSIGNALED (w))
|
||||
{
|
||||
int pid = pid_of (event_child);
|
||||
struct process_info *process = find_process_pid (pid);
|
||||
|
||||
#ifdef USE_THREAD_DB
|
||||
thread_db_free (process, 0);
|
||||
#endif
|
||||
delete_lwp (event_child);
|
||||
linux_remove_process (process);
|
||||
|
||||
current_inferior = NULL;
|
||||
|
||||
@ -1800,7 +1795,7 @@ retry:
|
||||
breakpoint and still reporting the event to GDB. If we don't,
|
||||
we're out of luck, GDB won't see the breakpoint hit. */
|
||||
report_to_gdb = (!maybe_internal_trap
|
||||
|| event_child->last_resume_kind == resume_step
|
||||
|| current_inferior->last_resume_kind == resume_step
|
||||
|| event_child->stopped_by_watchpoint
|
||||
|| (!step_over_finished && !bp_explains_trap && !trace_event)
|
||||
|| gdb_breakpoint_here (event_child->stop_pc));
|
||||
@ -1843,7 +1838,7 @@ retry:
|
||||
|
||||
if (debug_threads)
|
||||
{
|
||||
if (event_child->last_resume_kind == resume_step)
|
||||
if (current_inferior->last_resume_kind == resume_step)
|
||||
fprintf (stderr, "GDB wanted to single-step, reporting event.\n");
|
||||
if (event_child->stopped_by_watchpoint)
|
||||
fprintf (stderr, "Stopped by watchpoint.\n");
|
||||
@ -1895,14 +1890,16 @@ retry:
|
||||
|
||||
/* Do this before the gdb_wants_all_stopped calls below, since they
|
||||
always set last_resume_kind to resume_stop. */
|
||||
if (event_child->last_resume_kind == resume_stop && WSTOPSIG (w) == SIGSTOP)
|
||||
if (current_inferior->last_resume_kind == resume_stop
|
||||
&& WSTOPSIG (w) == SIGSTOP)
|
||||
{
|
||||
/* A thread that has been requested to stop by GDB with vCont;t,
|
||||
and it stopped cleanly, so report as SIG0. The use of
|
||||
SIGSTOP is an implementation detail. */
|
||||
ourstatus->value.sig = TARGET_SIGNAL_0;
|
||||
}
|
||||
else if (event_child->last_resume_kind == resume_stop && WSTOPSIG (w) != SIGSTOP)
|
||||
else if (current_inferior->last_resume_kind == resume_stop
|
||||
&& WSTOPSIG (w) != SIGSTOP)
|
||||
{
|
||||
/* A thread that has been requested to stop by GDB with vCont;t,
|
||||
but, it stopped for other reasons. */
|
||||
@ -2361,7 +2358,7 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
|
||||
&& (ptid_get_pid (ptid) == pid_of (lwp))))
|
||||
{
|
||||
if (r->resume[ndx].kind == resume_stop
|
||||
&& lwp->last_resume_kind == resume_stop)
|
||||
&& thread->last_resume_kind == resume_stop)
|
||||
{
|
||||
if (debug_threads)
|
||||
fprintf (stderr, "already %s LWP %ld at GDB's request\n",
|
||||
@ -2374,7 +2371,7 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
|
||||
}
|
||||
|
||||
lwp->resume = &r->resume[ndx];
|
||||
lwp->last_resume_kind = lwp->resume->kind;
|
||||
thread->last_resume_kind = lwp->resume->kind;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -2412,6 +2409,7 @@ static int
|
||||
need_step_over_p (struct inferior_list_entry *entry, void *dummy)
|
||||
{
|
||||
struct lwp_info *lwp = (struct lwp_info *) entry;
|
||||
struct thread_info *thread;
|
||||
struct thread_info *saved_inferior;
|
||||
CORE_ADDR pc;
|
||||
|
||||
@ -2427,7 +2425,9 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lwp->last_resume_kind == resume_stop)
|
||||
thread = get_lwp_thread (lwp);
|
||||
|
||||
if (thread->last_resume_kind == resume_stop)
|
||||
{
|
||||
if (debug_threads)
|
||||
fprintf (stderr,
|
||||
@ -2474,7 +2474,7 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy)
|
||||
}
|
||||
|
||||
saved_inferior = current_inferior;
|
||||
current_inferior = get_lwp_thread (lwp);
|
||||
current_inferior = thread;
|
||||
|
||||
/* We can only step over breakpoints we know about. */
|
||||
if (breakpoint_here (pc))
|
||||
@ -2802,6 +2802,7 @@ static void
|
||||
proceed_one_lwp (struct inferior_list_entry *entry)
|
||||
{
|
||||
struct lwp_info *lwp;
|
||||
struct thread_info *thread;
|
||||
int step;
|
||||
|
||||
lwp = (struct lwp_info *) entry;
|
||||
@ -2817,7 +2818,9 @@ proceed_one_lwp (struct inferior_list_entry *entry)
|
||||
return;
|
||||
}
|
||||
|
||||
if (lwp->last_resume_kind == resume_stop)
|
||||
thread = get_lwp_thread (lwp);
|
||||
|
||||
if (thread->last_resume_kind == resume_stop)
|
||||
{
|
||||
if (debug_threads)
|
||||
fprintf (stderr, " client wants LWP %ld stopped\n", lwpid_of (lwp));
|
||||
@ -2839,7 +2842,7 @@ proceed_one_lwp (struct inferior_list_entry *entry)
|
||||
return;
|
||||
}
|
||||
|
||||
step = lwp->last_resume_kind == resume_step;
|
||||
step = thread->last_resume_kind == resume_step;
|
||||
linux_resume_one_lwp (lwp, step, 0, NULL);
|
||||
}
|
||||
|
||||
@ -4032,6 +4035,10 @@ linux_async (int enable)
|
||||
{
|
||||
int previous = (linux_event_pipe[0] != -1);
|
||||
|
||||
if (debug_threads)
|
||||
fprintf (stderr, "linux_async (%d), previous=%d\n",
|
||||
enable, previous);
|
||||
|
||||
if (previous != enable)
|
||||
{
|
||||
sigset_t mask;
|
||||
@ -4261,11 +4268,26 @@ linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
|
||||
(*the_low_target.set_pc) (regcache, pc);
|
||||
}
|
||||
|
||||
static int
|
||||
linux_thread_stopped (struct thread_info *thread)
|
||||
{
|
||||
return get_thread_lwp (thread)->stopped;
|
||||
}
|
||||
|
||||
/* This exposes stop-all-threads functionality to other modules. */
|
||||
|
||||
static void
|
||||
linux_pause_all (void)
|
||||
{
|
||||
stop_all_lwps ();
|
||||
}
|
||||
|
||||
static struct target_ops linux_target_ops = {
|
||||
linux_create_inferior,
|
||||
linux_attach,
|
||||
linux_kill,
|
||||
linux_detach,
|
||||
linux_mourn,
|
||||
linux_join,
|
||||
linux_thread_alive,
|
||||
linux_resume,
|
||||
@ -4308,7 +4330,9 @@ static struct target_ops linux_target_ops = {
|
||||
linux_process_qsupported,
|
||||
linux_supports_tracepoints,
|
||||
linux_read_pc,
|
||||
linux_write_pc
|
||||
linux_write_pc,
|
||||
linux_thread_stopped,
|
||||
linux_pause_all
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -201,9 +201,6 @@ struct lwp_info
|
||||
and then processed and cleared in linux_resume_one_lwp. */
|
||||
struct thread_resume *resume;
|
||||
|
||||
/* The last resume GDB requested on this thread. */
|
||||
enum resume_kind last_resume_kind;
|
||||
|
||||
/* True if the LWP was seen stop at an internal breakpoint and needs
|
||||
stepping over later when it is resumed. */
|
||||
int need_step_over;
|
||||
@ -229,7 +226,8 @@ struct lwp_info *find_lwp_pid (ptid_t ptid);
|
||||
|
||||
/* From thread-db.c */
|
||||
int thread_db_init (int use_events);
|
||||
void thread_db_free (struct process_info *, int detaching);
|
||||
void thread_db_detach (struct process_info *);
|
||||
void thread_db_mourn (struct process_info *);
|
||||
int thread_db_handle_monitor_command (char *);
|
||||
int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
|
||||
CORE_ADDR load_module, CORE_ADDR *address);
|
||||
|
@ -900,6 +900,7 @@ static struct target_ops nto_target_ops = {
|
||||
nto_attach,
|
||||
nto_kill,
|
||||
nto_detach,
|
||||
NULL, /* nto_mourn */
|
||||
NULL, /* nto_join */
|
||||
nto_thread_alive,
|
||||
nto_resume,
|
||||
|
@ -92,6 +92,7 @@ int remote_debug = 0;
|
||||
struct ui_file *gdb_stdlog;
|
||||
|
||||
static int remote_desc = INVALID_DESCRIPTOR;
|
||||
static int listen_desc = INVALID_DESCRIPTOR;
|
||||
|
||||
/* FIXME headerize? */
|
||||
extern int using_threads;
|
||||
@ -107,15 +108,88 @@ int transport_is_reliable = 0;
|
||||
# define write(fd, buf, len) send (fd, (char *) buf, len, 0)
|
||||
#endif
|
||||
|
||||
int
|
||||
gdb_connected (void)
|
||||
{
|
||||
return remote_desc != INVALID_DESCRIPTOR;
|
||||
}
|
||||
|
||||
static void
|
||||
enable_async_notification (int fd)
|
||||
{
|
||||
#if defined(F_SETFL) && defined (FASYNC)
|
||||
int save_fcntl_flags;
|
||||
|
||||
save_fcntl_flags = fcntl (fd, F_GETFL, 0);
|
||||
fcntl (fd, F_SETFL, save_fcntl_flags | FASYNC);
|
||||
#if defined (F_SETOWN)
|
||||
fcntl (fd, F_SETOWN, getpid ());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
handle_accept_event (int err, gdb_client_data client_data)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t tmp;
|
||||
|
||||
if (debug_threads)
|
||||
fprintf (stderr, "handling possible accept event\n");
|
||||
|
||||
tmp = sizeof (sockaddr);
|
||||
remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &tmp);
|
||||
if (remote_desc == -1)
|
||||
perror_with_name ("Accept failed");
|
||||
|
||||
/* Enable TCP keep alive process. */
|
||||
tmp = 1;
|
||||
setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(char *) &tmp, sizeof (tmp));
|
||||
|
||||
/* Tell TCP not to delay small packets. This greatly speeds up
|
||||
interactive response. */
|
||||
tmp = 1;
|
||||
setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *) &tmp, sizeof (tmp));
|
||||
|
||||
#ifndef USE_WIN32API
|
||||
close (listen_desc); /* No longer need this */
|
||||
|
||||
signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply
|
||||
exits when the remote side dies. */
|
||||
#else
|
||||
closesocket (listen_desc); /* No longer need this */
|
||||
#endif
|
||||
|
||||
delete_file_handler (listen_desc);
|
||||
|
||||
/* Convert IP address to string. */
|
||||
fprintf (stderr, "Remote debugging from host %s\n",
|
||||
inet_ntoa (sockaddr.sin_addr));
|
||||
|
||||
enable_async_notification (remote_desc);
|
||||
|
||||
/* Register the event loop handler. */
|
||||
add_file_handler (remote_desc, handle_serial_event, NULL);
|
||||
|
||||
/* We have a new GDB connection now. If we were disconnected
|
||||
tracing, there's a window where the target could report a stop
|
||||
event to the event loop, and since we have a connection now, we'd
|
||||
try to send vStopped notifications to GDB. But, don't do that
|
||||
until GDB as selected all-stop/non-stop, and has queried the
|
||||
threads' status ('?'). */
|
||||
target_async (0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a connection to a remote debugger.
|
||||
NAME is the filename used for communication. */
|
||||
|
||||
void
|
||||
remote_open (char *name)
|
||||
{
|
||||
#if defined(F_SETFL) && defined (FASYNC)
|
||||
int save_fcntl_flags;
|
||||
#endif
|
||||
char *port_str;
|
||||
|
||||
port_str = strchr (name, ':');
|
||||
@ -183,9 +257,14 @@ remote_open (char *name)
|
||||
#endif
|
||||
|
||||
fprintf (stderr, "Remote debugging using %s\n", name);
|
||||
#endif /* USE_WIN32API */
|
||||
|
||||
transport_is_reliable = 0;
|
||||
|
||||
enable_async_notification (remote_desc);
|
||||
|
||||
/* Register the event loop handler. */
|
||||
add_file_handler (remote_desc, handle_serial_event, NULL);
|
||||
#endif /* USE_WIN32API */
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -195,7 +274,6 @@ remote_open (char *name)
|
||||
int port;
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t tmp;
|
||||
int tmp_desc;
|
||||
char *port_end;
|
||||
|
||||
port = strtoul (port_str + 1, &port_end, 10);
|
||||
@ -212,21 +290,21 @@ remote_open (char *name)
|
||||
}
|
||||
#endif
|
||||
|
||||
tmp_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (tmp_desc < 0)
|
||||
listen_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (listen_desc < 0)
|
||||
perror_with_name ("Can't open socket");
|
||||
|
||||
/* Allow rapid reuse of this port. */
|
||||
tmp = 1;
|
||||
setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
|
||||
setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
|
||||
sizeof (tmp));
|
||||
|
||||
sockaddr.sin_family = PF_INET;
|
||||
sockaddr.sin_port = htons (port);
|
||||
sockaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
|
||||
|| listen (tmp_desc, 1))
|
||||
if (bind (listen_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
|
||||
|| listen (listen_desc, 1))
|
||||
perror_with_name ("Can't bind address");
|
||||
|
||||
/* If port is zero, a random port will be selected, and the
|
||||
@ -234,7 +312,7 @@ remote_open (char *name)
|
||||
if (port == 0)
|
||||
{
|
||||
socklen_t len = sizeof (sockaddr);
|
||||
if (getsockname (tmp_desc, (struct sockaddr *) &sockaddr, &len) < 0
|
||||
if (getsockname (listen_desc, (struct sockaddr *) &sockaddr, &len) < 0
|
||||
|| len < sizeof (sockaddr))
|
||||
perror_with_name ("Can't determine port");
|
||||
port = ntohs (sockaddr.sin_port);
|
||||
@ -243,49 +321,11 @@ remote_open (char *name)
|
||||
fprintf (stderr, "Listening on port %d\n", port);
|
||||
fflush (stderr);
|
||||
|
||||
tmp = sizeof (sockaddr);
|
||||
remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
|
||||
if (remote_desc == -1)
|
||||
perror_with_name ("Accept failed");
|
||||
|
||||
/* Enable TCP keep alive process. */
|
||||
tmp = 1;
|
||||
setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(char *) &tmp, sizeof (tmp));
|
||||
|
||||
/* Tell TCP not to delay small packets. This greatly speeds up
|
||||
interactive response. */
|
||||
tmp = 1;
|
||||
setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *) &tmp, sizeof (tmp));
|
||||
|
||||
|
||||
#ifndef USE_WIN32API
|
||||
close (tmp_desc); /* No longer need this */
|
||||
|
||||
signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply
|
||||
exits when the remote side dies. */
|
||||
#else
|
||||
closesocket (tmp_desc); /* No longer need this */
|
||||
#endif
|
||||
|
||||
/* Convert IP address to string. */
|
||||
fprintf (stderr, "Remote debugging from host %s\n",
|
||||
inet_ntoa (sockaddr.sin_addr));
|
||||
/* Register the event loop handler. */
|
||||
add_file_handler (listen_desc, handle_accept_event, NULL);
|
||||
|
||||
transport_is_reliable = 1;
|
||||
}
|
||||
|
||||
#if defined(F_SETFL) && defined (FASYNC)
|
||||
save_fcntl_flags = fcntl (remote_desc, F_GETFL, 0);
|
||||
fcntl (remote_desc, F_SETFL, save_fcntl_flags | FASYNC);
|
||||
#if defined (F_SETOWN)
|
||||
fcntl (remote_desc, F_SETOWN, getpid ());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Register the event loop handler. */
|
||||
add_file_handler (remote_desc, handle_serial_event, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@ -298,6 +338,7 @@ remote_close (void)
|
||||
#else
|
||||
close (remote_desc);
|
||||
#endif
|
||||
remote_desc = INVALID_DESCRIPTOR;
|
||||
}
|
||||
|
||||
/* Convert hex digit A to a number. */
|
||||
|
@ -1392,6 +1392,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
strcat (own_buf, ";ConditionalTracepoints+");
|
||||
strcat (own_buf, ";TraceStateVariables+");
|
||||
strcat (own_buf, ";TracepointSource+");
|
||||
strcat (own_buf, ";DisconnectedTracing+");
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1976,31 +1977,81 @@ myresume (char *own_buf, int step, int sig)
|
||||
static int
|
||||
queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg)
|
||||
{
|
||||
int pid = * (int *) arg;
|
||||
struct thread_info *thread = (struct thread_info *) entry;
|
||||
|
||||
if (pid == -1
|
||||
|| ptid_get_pid (entry->id) == pid)
|
||||
/* For now, assume targets that don't have this callback also don't
|
||||
manage the thread's last_status field. */
|
||||
if (the_target->thread_stopped == NULL)
|
||||
{
|
||||
struct target_waitstatus status;
|
||||
|
||||
status.kind = TARGET_WAITKIND_STOPPED;
|
||||
status.value.sig = TARGET_SIGNAL_TRAP;
|
||||
|
||||
/* Pass the last stop reply back to GDB, but don't notify. */
|
||||
queue_stop_reply (entry->id, &status);
|
||||
/* Pass the last stop reply back to GDB, but don't notify
|
||||
yet. */
|
||||
queue_stop_reply (entry->id, &thread->last_status);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (thread_stopped (thread))
|
||||
{
|
||||
if (debug_threads)
|
||||
fprintf (stderr, "Reporting thread %s as already stopped with %s\n",
|
||||
target_pid_to_str (entry->id),
|
||||
target_waitstatus_to_string (&thread->last_status));
|
||||
|
||||
/* Pass the last stop reply back to GDB, but don't notify
|
||||
yet. */
|
||||
queue_stop_reply (entry->id, &thread->last_status);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set this inferior LWP's state as "want-stopped". We won't resume
|
||||
this LWP until the client gives us another action for it. */
|
||||
|
||||
static void
|
||||
gdb_wants_thread_stopped (struct inferior_list_entry *entry)
|
||||
{
|
||||
struct thread_info *thread = (struct thread_info *) entry;
|
||||
|
||||
thread->last_resume_kind = resume_stop;
|
||||
|
||||
if (thread->last_status.kind == TARGET_WAITKIND_IGNORE)
|
||||
{
|
||||
thread->last_status.kind = TARGET_WAITKIND_STOPPED;
|
||||
thread->last_status.value.sig = TARGET_SIGNAL_0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set all threads' states as "want-stopped". */
|
||||
|
||||
static void
|
||||
gdb_wants_all_threads_stopped (void)
|
||||
{
|
||||
for_each_inferior (&all_threads, gdb_wants_thread_stopped);
|
||||
}
|
||||
|
||||
/* Clear the gdb_detached flag of every process. */
|
||||
|
||||
static void
|
||||
gdb_reattached_process (struct inferior_list_entry *entry)
|
||||
{
|
||||
struct process_info *process = (struct process_info *) entry;
|
||||
|
||||
process->gdb_detached = 0;
|
||||
}
|
||||
|
||||
/* Status handler for the '?' packet. */
|
||||
|
||||
static void
|
||||
handle_status (char *own_buf)
|
||||
{
|
||||
struct target_waitstatus status;
|
||||
status.kind = TARGET_WAITKIND_STOPPED;
|
||||
status.value.sig = TARGET_SIGNAL_TRAP;
|
||||
/* GDB is connected, don't forward events to the target anymore. */
|
||||
for_each_inferior (&all_processes, gdb_reattached_process);
|
||||
|
||||
/* In non-stop mode, we must send a stop reply for each stopped
|
||||
thread. In all-stop mode, just send one for the first stopped
|
||||
@ -2008,9 +2059,8 @@ handle_status (char *own_buf)
|
||||
|
||||
if (non_stop)
|
||||
{
|
||||
int pid = -1;
|
||||
discard_queued_stop_replies (pid);
|
||||
find_inferior (&all_threads, queue_stop_reply_callback, &pid);
|
||||
discard_queued_stop_replies (-1);
|
||||
find_inferior (&all_threads, queue_stop_reply_callback, NULL);
|
||||
|
||||
/* The first is sent immediatly. OK is sent if there is no
|
||||
stopped thread, which is the same handling of the vStopped
|
||||
@ -2019,9 +2069,18 @@ handle_status (char *own_buf)
|
||||
}
|
||||
else
|
||||
{
|
||||
pause_all ();
|
||||
gdb_wants_all_threads_stopped ();
|
||||
|
||||
if (all_threads.head)
|
||||
prepare_resume_reply (own_buf,
|
||||
all_threads.head->id, &status);
|
||||
{
|
||||
struct target_waitstatus status;
|
||||
|
||||
status.kind = TARGET_WAITKIND_STOPPED;
|
||||
status.value.sig = TARGET_SIGNAL_TRAP;
|
||||
prepare_resume_reply (own_buf,
|
||||
all_threads.head->id, &status);
|
||||
}
|
||||
else
|
||||
strcpy (own_buf, "W00");
|
||||
}
|
||||
@ -2390,7 +2449,8 @@ main (int argc, char *argv[])
|
||||
{
|
||||
noack_mode = 0;
|
||||
multi_process = 0;
|
||||
non_stop = 0;
|
||||
/* Be sure we're out of tfind mode. */
|
||||
current_traceframe = -1;
|
||||
|
||||
remote_open (port);
|
||||
|
||||
@ -2405,7 +2465,7 @@ main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Wait for events. This will return when all event sources are
|
||||
removed from the event loop. */
|
||||
removed from the event loop. */
|
||||
start_event_loop ();
|
||||
|
||||
/* If an exit was requested (using the "monitor exit" command),
|
||||
@ -2418,9 +2478,37 @@ main (int argc, char *argv[])
|
||||
detach_or_kill_for_exit ();
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "Remote side has terminated connection. "
|
||||
"GDBserver will reopen the connection.\n");
|
||||
|
||||
fprintf (stderr,
|
||||
"Remote side has terminated connection. "
|
||||
"GDBserver will reopen the connection.\n");
|
||||
|
||||
if (tracing)
|
||||
{
|
||||
if (disconnected_tracing)
|
||||
{
|
||||
/* Try to enable non-stop/async mode, so we we can both
|
||||
wait for an async socket accept, and handle async
|
||||
target events simultaneously. There's also no point
|
||||
either in having the target always stop all threads,
|
||||
when we're going to pass signals down without
|
||||
informing GDB. */
|
||||
if (!non_stop)
|
||||
{
|
||||
if (start_non_stop (1))
|
||||
non_stop = 1;
|
||||
|
||||
/* Detaching implicitly resumes all threads; simply
|
||||
disconnecting does not. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Disconnected tracing disabled; stopping trace run.\n");
|
||||
stop_tracing ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2429,7 +2517,7 @@ main (int argc, char *argv[])
|
||||
a brisk pace, so we read the rest of the packet with a blocking
|
||||
getpkt call. */
|
||||
|
||||
static void
|
||||
static int
|
||||
process_serial_event (void)
|
||||
{
|
||||
char ch;
|
||||
@ -2455,9 +2543,9 @@ process_serial_event (void)
|
||||
packet_len = getpkt (own_buf);
|
||||
if (packet_len <= 0)
|
||||
{
|
||||
target_async (0);
|
||||
remote_close ();
|
||||
return;
|
||||
/* Force an event loop break. */
|
||||
return -1;
|
||||
}
|
||||
response_needed = 1;
|
||||
|
||||
@ -2483,7 +2571,49 @@ process_serial_event (void)
|
||||
pid =
|
||||
ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id);
|
||||
|
||||
if (tracing && disconnected_tracing)
|
||||
{
|
||||
struct thread_resume resume_info;
|
||||
struct process_info *process = find_process_pid (pid);
|
||||
|
||||
if (process == NULL)
|
||||
{
|
||||
write_enn (own_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf (stderr,
|
||||
"Disconnected tracing in effect, "
|
||||
"leaving gdbserver attached to the process\n");
|
||||
|
||||
/* Make sure we're in non-stop/async mode, so we we can both
|
||||
wait for an async socket accept, and handle async target
|
||||
events simultaneously. There's also no point either in
|
||||
having the target stop all threads, when we're going to
|
||||
pass signals down without informing GDB. */
|
||||
if (!non_stop)
|
||||
{
|
||||
if (debug_threads)
|
||||
fprintf (stderr, "Forcing non-stop mode\n");
|
||||
|
||||
non_stop = 1;
|
||||
start_non_stop (1);
|
||||
}
|
||||
|
||||
process->gdb_detached = 1;
|
||||
|
||||
/* Detaching implicitly resumes all threads. */
|
||||
resume_info.thread = minus_one_ptid;
|
||||
resume_info.kind = resume_continue;
|
||||
resume_info.sig = 0;
|
||||
(*the_target->resume) (&resume_info, 1);
|
||||
|
||||
write_ok (own_buf);
|
||||
break; /* from switch/case */
|
||||
}
|
||||
|
||||
fprintf (stderr, "Detaching from process %d\n", pid);
|
||||
stop_tracing ();
|
||||
if (detach_inferior (pid) != 0)
|
||||
write_enn (own_buf);
|
||||
else
|
||||
@ -2727,7 +2857,7 @@ process_serial_event (void)
|
||||
if (!target_running ())
|
||||
/* The packet we received doesn't make sense - but we can't
|
||||
reply to it, either. */
|
||||
return;
|
||||
return 0;
|
||||
|
||||
fprintf (stderr, "Killing all inferiors\n");
|
||||
for_each_inferior (&all_processes, kill_inferior_callback);
|
||||
@ -2738,13 +2868,11 @@ process_serial_event (void)
|
||||
{
|
||||
last_status.kind = TARGET_WAITKIND_EXITED;
|
||||
last_status.value.sig = TARGET_SIGNAL_KILL;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
exit (0);
|
||||
break;
|
||||
}
|
||||
exit (0);
|
||||
|
||||
case 'T':
|
||||
{
|
||||
ptid_t gdb_id, thread_id;
|
||||
@ -2785,7 +2913,7 @@ process_serial_event (void)
|
||||
last_status.kind = TARGET_WAITKIND_EXITED;
|
||||
last_status.value.sig = TARGET_SIGNAL_KILL;
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2826,27 +2954,35 @@ process_serial_event (void)
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (exit_requested)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Event-loop callback for serial events. */
|
||||
|
||||
void
|
||||
int
|
||||
handle_serial_event (int err, gdb_client_data client_data)
|
||||
{
|
||||
if (debug_threads)
|
||||
fprintf (stderr, "handling possible serial event\n");
|
||||
|
||||
/* Really handle it. */
|
||||
process_serial_event ();
|
||||
if (process_serial_event () < 0)
|
||||
return -1;
|
||||
|
||||
/* Be sure to not change the selected inferior behind GDB's back.
|
||||
Important in the non-stop mode asynchronous protocol. */
|
||||
set_desired_inferior (1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Event-loop callback for target events. */
|
||||
|
||||
void
|
||||
int
|
||||
handle_target_event (int err, gdb_client_data client_data)
|
||||
{
|
||||
if (debug_threads)
|
||||
@ -2857,11 +2993,58 @@ handle_target_event (int err, gdb_client_data client_data)
|
||||
|
||||
if (last_status.kind != TARGET_WAITKIND_IGNORE)
|
||||
{
|
||||
/* Something interesting. Tell GDB about it. */
|
||||
push_event (last_ptid, &last_status);
|
||||
int pid = ptid_get_pid (last_ptid);
|
||||
struct process_info *process = find_process_pid (pid);
|
||||
int forward_event = !gdb_connected () || process->gdb_detached;
|
||||
|
||||
if (last_status.kind == TARGET_WAITKIND_EXITED
|
||||
|| last_status.kind == TARGET_WAITKIND_SIGNALLED)
|
||||
{
|
||||
mourn_inferior (process);
|
||||
remove_process (process);
|
||||
}
|
||||
|
||||
if (forward_event)
|
||||
{
|
||||
if (!target_running ())
|
||||
{
|
||||
/* The last process exited. We're done. */
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (last_status.kind == TARGET_WAITKIND_STOPPED)
|
||||
{
|
||||
/* A thread stopped with a signal, but gdb isn't
|
||||
connected to handle it. Pass it down to the
|
||||
inferior, as if it wasn't being traced. */
|
||||
struct thread_resume resume_info;
|
||||
|
||||
if (debug_threads)
|
||||
fprintf (stderr,
|
||||
"GDB not connected; forwarding event %d for [%s]\n",
|
||||
(int) last_status.kind,
|
||||
target_pid_to_str (last_ptid));
|
||||
|
||||
resume_info.thread = last_ptid;
|
||||
resume_info.kind = resume_continue;
|
||||
resume_info.sig = last_status.value.sig;
|
||||
(*the_target->resume) (&resume_info, 1);
|
||||
}
|
||||
else if (debug_threads)
|
||||
fprintf (stderr, "GDB not connected; ignoring event %d for [%s]\n",
|
||||
(int) last_status.kind,
|
||||
target_pid_to_str (last_ptid));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Something interesting. Tell GDB about it. */
|
||||
push_event (last_ptid, &last_status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Be sure to not change the selected inferior behind GDB's back.
|
||||
Important in the non-stop mode asynchronous protocol. */
|
||||
set_desired_inferior (1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -179,6 +179,9 @@ struct thread_info
|
||||
void *target_data;
|
||||
void *regcache_data;
|
||||
|
||||
/* The last resume GDB requested on this thread. */
|
||||
enum resume_kind last_resume_kind;
|
||||
|
||||
/* The last wait status reported for this thread. */
|
||||
struct target_waitstatus last_status;
|
||||
|
||||
@ -224,8 +227,14 @@ struct process_info
|
||||
{
|
||||
struct inferior_list_entry head;
|
||||
|
||||
/* Nonzero if this child process was attached rather than
|
||||
spawned. */
|
||||
int attached;
|
||||
|
||||
/* True if GDB asked us to detach from this process, but we remained
|
||||
attached anyway. */
|
||||
int gdb_detached;
|
||||
|
||||
/* The symbol cache. */
|
||||
struct sym_cache *symbol_cache;
|
||||
|
||||
@ -327,7 +336,7 @@ extern int non_stop;
|
||||
|
||||
/* Functions from event-loop.c. */
|
||||
typedef void *gdb_client_data;
|
||||
typedef void (handler_func) (int, gdb_client_data);
|
||||
typedef int (handler_func) (int, gdb_client_data);
|
||||
|
||||
extern void delete_file_handler (int fd);
|
||||
extern void add_file_handler (int fd, handler_func *proc,
|
||||
@ -336,8 +345,8 @@ extern void add_file_handler (int fd, handler_func *proc,
|
||||
extern void start_event_loop (void);
|
||||
|
||||
/* Functions from server.c. */
|
||||
extern void handle_serial_event (int err, gdb_client_data client_data);
|
||||
extern void handle_target_event (int err, gdb_client_data client_data);
|
||||
extern int handle_serial_event (int err, gdb_client_data client_data);
|
||||
extern int handle_target_event (int err, gdb_client_data client_data);
|
||||
|
||||
extern void push_event (ptid_t ptid, struct target_waitstatus *status);
|
||||
|
||||
@ -354,6 +363,8 @@ extern int all_symbols_looked_up;
|
||||
extern int noack_mode;
|
||||
extern int transport_is_reliable;
|
||||
|
||||
int gdb_connected (void);
|
||||
|
||||
ptid_t read_ptid (char *buf, char **obuf);
|
||||
char *write_ptid (char *buf, ptid_t ptid);
|
||||
|
||||
@ -499,6 +510,11 @@ char *phex_nz (ULONGEST l, int sizeof_l);
|
||||
|
||||
void initialize_tracepoint (void);
|
||||
|
||||
extern int tracing;
|
||||
extern int disconnected_tracing;
|
||||
|
||||
void stop_tracing (void);
|
||||
|
||||
int handle_tracepoint_general_set (char *own_buf);
|
||||
int handle_tracepoint_query (char *own_buf);
|
||||
|
||||
|
@ -448,7 +448,6 @@ spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
|
||||
ourstatus->kind = TARGET_WAITKIND_EXITED;
|
||||
ourstatus->value.integer = WEXITSTATUS (w);
|
||||
clear_inferiors ();
|
||||
remove_process (find_process_pid (ret));
|
||||
return pid_to_ptid (ret);
|
||||
}
|
||||
else if (!WIFSTOPPED (w))
|
||||
@ -457,7 +456,6 @@ spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
|
||||
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
|
||||
ourstatus->value.sig = target_signal_from_host (WTERMSIG (w));
|
||||
clear_inferiors ();
|
||||
remove_process (find_process_pid (ret));
|
||||
return pid_to_ptid (ret);
|
||||
}
|
||||
|
||||
@ -608,6 +606,7 @@ static struct target_ops spu_target_ops = {
|
||||
spu_attach,
|
||||
spu_kill,
|
||||
spu_detach,
|
||||
NULL, /* mourn */
|
||||
spu_join,
|
||||
spu_thread_alive,
|
||||
spu_resume,
|
||||
|
@ -154,3 +154,45 @@ target_pid_to_str (ptid_t ptid)
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Return a pretty printed form of target_waitstatus. */
|
||||
|
||||
const char *
|
||||
target_waitstatus_to_string (const struct target_waitstatus *ws)
|
||||
{
|
||||
static char buf[200];
|
||||
const char *kind_str = "status->kind = ";
|
||||
|
||||
switch (ws->kind)
|
||||
{
|
||||
case TARGET_WAITKIND_EXITED:
|
||||
sprintf (buf, "%sexited, status = %d",
|
||||
kind_str, ws->value.integer);
|
||||
break;
|
||||
case TARGET_WAITKIND_STOPPED:
|
||||
sprintf (buf, "%sstopped, signal = %s",
|
||||
kind_str, target_signal_to_name (ws->value.sig));
|
||||
break;
|
||||
case TARGET_WAITKIND_SIGNALLED:
|
||||
sprintf (buf, "%ssignalled, signal = %s",
|
||||
kind_str, target_signal_to_name (ws->value.sig));
|
||||
break;
|
||||
case TARGET_WAITKIND_LOADED:
|
||||
sprintf (buf, "%sloaded", kind_str);
|
||||
break;
|
||||
case TARGET_WAITKIND_EXECD:
|
||||
sprintf (buf, "%sexecd", kind_str);
|
||||
break;
|
||||
case TARGET_WAITKIND_SPURIOUS:
|
||||
sprintf (buf, "%sspurious", kind_str);
|
||||
break;
|
||||
case TARGET_WAITKIND_IGNORE:
|
||||
sprintf (buf, "%signore", kind_str);
|
||||
break;
|
||||
default:
|
||||
sprintf (buf, "%sunknown???", kind_str);
|
||||
break;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -138,6 +138,10 @@ struct target_ops
|
||||
|
||||
int (*detach) (int pid);
|
||||
|
||||
/* The inferior process has died. Do what is right. */
|
||||
|
||||
void (*mourn) (struct process_info *proc);
|
||||
|
||||
/* Wait for inferior PID to exit. */
|
||||
void (*join) (int pid);
|
||||
|
||||
@ -299,6 +303,12 @@ struct target_ops
|
||||
|
||||
/* Write PC to REGCACHE. */
|
||||
void (*write_pc) (struct regcache *regcache, CORE_ADDR pc);
|
||||
|
||||
/* Return true if THREAD is known to be stopped now. */
|
||||
int (*thread_stopped) (struct thread_info *thread);
|
||||
|
||||
/* Pause all threads. */
|
||||
void (*pause_all) (void);
|
||||
};
|
||||
|
||||
extern struct target_ops *the_target;
|
||||
@ -317,6 +327,9 @@ void set_target_ops (struct target_ops *);
|
||||
#define detach_inferior(pid) \
|
||||
(*the_target->detach) (pid)
|
||||
|
||||
#define mourn_inferior(PROC) \
|
||||
(*the_target->mourn) (PROC)
|
||||
|
||||
#define mythread_alive(pid) \
|
||||
(*the_target->thread_alive) (pid)
|
||||
|
||||
@ -339,14 +352,27 @@ void set_target_ops (struct target_ops *);
|
||||
(the_target->supports_multi_process ? \
|
||||
(*the_target->supports_multi_process) () : 0)
|
||||
|
||||
#define target_process_qsupported(query) \
|
||||
if (the_target->process_qsupported) \
|
||||
the_target->process_qsupported (query)
|
||||
#define target_process_qsupported(query) \
|
||||
do \
|
||||
{ \
|
||||
if (the_target->process_qsupported) \
|
||||
the_target->process_qsupported (query); \
|
||||
} while (0)
|
||||
|
||||
#define target_supports_tracepoints() \
|
||||
(the_target->supports_tracepoints \
|
||||
? (*the_target->supports_tracepoints) () : 0)
|
||||
|
||||
#define thread_stopped(thread) \
|
||||
(*the_target->thread_stopped) (thread)
|
||||
|
||||
#define pause_all() \
|
||||
do \
|
||||
{ \
|
||||
if (the_target->pause_all) \
|
||||
(*the_target->pause_all) (); \
|
||||
} while (0)
|
||||
|
||||
/* Start non-stop mode, returns 0 on success, -1 on failure. */
|
||||
|
||||
int start_non_stop (int nonstop);
|
||||
@ -363,4 +389,6 @@ void set_desired_inferior (int id);
|
||||
|
||||
const char *target_pid_to_str (ptid_t);
|
||||
|
||||
const char *target_waitstatus_to_string (const struct target_waitstatus *);
|
||||
|
||||
#endif /* TARGET_H */
|
||||
|
@ -743,7 +743,7 @@ thread_db_init (int use_events)
|
||||
if (use_events && thread_db_enable_reporting () == 0)
|
||||
{
|
||||
/* Keep trying; maybe event reporting will work later. */
|
||||
thread_db_free (proc, 0);
|
||||
thread_db_mourn (proc);
|
||||
return 0;
|
||||
}
|
||||
thread_db_find_new_threads ();
|
||||
@ -768,41 +768,64 @@ any_thread_of (struct inferior_list_entry *entry, void *args)
|
||||
|
||||
/* Disconnect from libthread_db and free resources. */
|
||||
|
||||
void
|
||||
thread_db_free (struct process_info *proc, int detaching)
|
||||
static void
|
||||
disable_thread_event_reporting (struct process_info *proc)
|
||||
{
|
||||
struct thread_db *thread_db = proc->private->thread_db;
|
||||
if (thread_db)
|
||||
{
|
||||
struct thread_info *saved_inferior;
|
||||
int pid;
|
||||
td_err_e (*td_ta_delete_p) (td_thragent_t *);
|
||||
td_err_e (*td_ta_clear_event_p) (const td_thragent_t *ta,
|
||||
td_thr_events_t *event);
|
||||
|
||||
#ifndef USE_LIBTHREAD_DB_DIRECTLY
|
||||
td_ta_clear_event_p = dlsym (thread_db->handle, "td_ta_clear_event");
|
||||
td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete");
|
||||
#else
|
||||
td_ta_delete_p = &td_ta_delete;
|
||||
td_ta_clear_event_p = &td_ta_clear_event;
|
||||
#endif
|
||||
|
||||
pid = pid_of (proc);
|
||||
saved_inferior = current_inferior;
|
||||
current_inferior =
|
||||
(struct thread_info *) find_inferior (&all_threads,
|
||||
any_thread_of, &pid);
|
||||
|
||||
if (detaching && td_ta_clear_event_p != NULL)
|
||||
if (td_ta_clear_event_p != NULL)
|
||||
{
|
||||
struct thread_info *saved_inferior;
|
||||
td_thr_events_t events;
|
||||
int pid;
|
||||
|
||||
pid = pid_of (proc);
|
||||
saved_inferior = current_inferior;
|
||||
current_inferior =
|
||||
(struct thread_info *) find_inferior (&all_threads,
|
||||
any_thread_of, &pid);
|
||||
|
||||
/* Set the process wide mask saying we aren't interested
|
||||
in any events anymore. */
|
||||
td_event_fillset (&events);
|
||||
(*td_ta_clear_event_p) (thread_db->thread_agent, &events);
|
||||
|
||||
current_inferior = saved_inferior;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
thread_db_detach (struct process_info *proc)
|
||||
{
|
||||
disable_thread_event_reporting (proc);
|
||||
}
|
||||
|
||||
/* Disconnect from libthread_db and free resources. */
|
||||
|
||||
void
|
||||
thread_db_mourn (struct process_info *proc)
|
||||
{
|
||||
struct thread_db *thread_db = proc->private->thread_db;
|
||||
if (thread_db)
|
||||
{
|
||||
td_err_e (*td_ta_delete_p) (td_thragent_t *);
|
||||
|
||||
#ifndef USE_LIBTHREAD_DB_DIRECTLY
|
||||
td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete");
|
||||
#else
|
||||
td_ta_delete_p = &td_ta_delete;
|
||||
#endif
|
||||
|
||||
if (td_ta_delete_p != NULL)
|
||||
(*td_ta_delete_p) (thread_db->thread_agent);
|
||||
@ -813,7 +836,6 @@ thread_db_free (struct process_info *proc, int detaching)
|
||||
|
||||
free (thread_db);
|
||||
proc->private->thread_db = NULL;
|
||||
current_inferior = saved_inferior;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,7 +558,11 @@ static struct readonly_region *readonly_regions;
|
||||
|
||||
/* The global that controls tracing overall. */
|
||||
|
||||
static int tracing;
|
||||
int tracing;
|
||||
|
||||
/* Controls whether tracing should continue after GDB disconnects. */
|
||||
|
||||
int disconnected_tracing;
|
||||
|
||||
/* The reason for the last tracing run to have stopped. We initialize
|
||||
to a distinct string so that GDB can distinguish between "stopped
|
||||
@ -1699,7 +1703,7 @@ cmd_qtstart (char *packet)
|
||||
/* End a tracing run, filling in a stop reason to report back to GDB,
|
||||
and removing the tracepoints from the code. */
|
||||
|
||||
static void
|
||||
void
|
||||
stop_tracing (void)
|
||||
{
|
||||
if (!tracing)
|
||||
@ -1736,6 +1740,11 @@ stop_tracing (void)
|
||||
tracing_stop_reason = eval_result_names[expr_eval_result];
|
||||
tracing_stop_tpnum = error_tracepoint->number;
|
||||
}
|
||||
else if (!gdb_connected ())
|
||||
{
|
||||
trace_debug ("Stopping the trace because GDB disconnected");
|
||||
tracing_stop_reason = "tdisconnected";
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_debug ("Stopping the trace because of a tstop command");
|
||||
@ -1756,6 +1765,21 @@ cmd_qtstop (char *packet)
|
||||
write_ok (packet);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_qtdisconnected (char *own_buf)
|
||||
{
|
||||
ULONGEST setting;
|
||||
char *packet = own_buf;
|
||||
|
||||
packet += strlen ("QTDisconnected:");
|
||||
|
||||
unpack_varlen_hex (packet, &setting);
|
||||
|
||||
write_ok (own_buf);
|
||||
|
||||
disconnected_tracing = setting;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_qtframe (char *own_buf)
|
||||
{
|
||||
@ -1853,13 +1877,19 @@ cmd_qtstatus (char *packet)
|
||||
convert_int_to_ascii ((gdb_byte *) result_name, p, strlen (result_name));
|
||||
}
|
||||
|
||||
sprintf (packet, "T%d;%s:%x;tframes:%x;tcreated:%x;tfree:%x;tsize:%s;circular:%d",
|
||||
sprintf (packet,
|
||||
"T%d;"
|
||||
"%s:%x;"
|
||||
"tframes:%x;tcreated:%x;"
|
||||
"tfree:%x;tsize:%s;"
|
||||
"circular:%d;"
|
||||
"disconn:%d",
|
||||
tracing ? 1 : 0,
|
||||
stop_reason_rsp, tracing_stop_tpnum,
|
||||
traceframe_count, traceframes_created,
|
||||
free_space (),
|
||||
phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
|
||||
circular_trace_buffer);
|
||||
free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
|
||||
circular_trace_buffer,
|
||||
disconnected_tracing);
|
||||
}
|
||||
|
||||
/* State variables to help return all the tracepoint bits. */
|
||||
@ -2168,6 +2198,12 @@ handle_tracepoint_general_set (char *packet)
|
||||
cmd_qtstop (packet);
|
||||
return 1;
|
||||
}
|
||||
else if (strncmp ("QTDisconnected:", packet,
|
||||
strlen ("QTDisconnected:")) == 0)
|
||||
{
|
||||
cmd_qtdisconnected (packet);
|
||||
return 1;
|
||||
}
|
||||
else if (strncmp ("QTFrame:", packet, strlen ("QTFrame:")) == 0)
|
||||
{
|
||||
cmd_qtframe (packet);
|
||||
|
@ -1581,9 +1581,6 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
|
||||
case TARGET_WAITKIND_EXITED:
|
||||
OUTMSG2 (("Child exited with retcode = %x\n",
|
||||
ourstatus->value.integer));
|
||||
|
||||
process = find_process_pid (current_process_id);
|
||||
remove_process (process);
|
||||
win32_clear_inferiors ();
|
||||
return pid_to_ptid (current_event.dwProcessId);
|
||||
case TARGET_WAITKIND_STOPPED:
|
||||
@ -1755,6 +1752,7 @@ static struct target_ops win32_target_ops = {
|
||||
win32_attach,
|
||||
win32_kill,
|
||||
win32_detach,
|
||||
NULL,
|
||||
win32_join,
|
||||
win32_thread_alive,
|
||||
win32_resume,
|
||||
|
Loading…
x
Reference in New Issue
Block a user