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:
Pedro Alves 2010-04-11 16:33:56 +00:00
parent 5d267c4c70
commit 8336d594d5
15 changed files with 686 additions and 185 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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. */

View File

@ -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;
}

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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,