* fork-child.c (fork_inferior): Only reset the thread list if this

is the first inferior.
	(startup_inferior): If the target support multi-process, tell it
	to resume only the new process.
	* linux-nat.c (num_lwps): Delete global.
	(purge_lwp_list): New function.
	(num_lwps): New function.
	(add_lwp, delete_lwp): Adjust.
	(ptid_match): New.
	(iterate_over_lwps): Add filter argument.  Handle it.
	(linux_nat_attach): Remove FIXME note.
	(linux_nat_detach): Adjust to iterate over threads of the inferior
	we're detaching from.  Adjust to num_lwps being a function.  Don't
	assume the head of the lwp list is the main thread of the process
	we're detaching from.  Don't destroy the LWP list.
	(resume_callback): Add debug output.
	(linux_nat_resume): Handle resuming a single inferior.  Allow a
	wildcard resume in non-stop mode.
	(linux_handle_extended_wait): Don't assume inferior_ptid is the
	correct inferior of the parent LWP.
	(status_callback): Also check lp->waitstatus.
	(select_event_lwp): Add new filter parameter.  Handle it.
	(linux_nat_filter_event): Adjust to num_lwps being a function.
	(linux_nat_wait_1): When adding the first lwp of the inferior, use
	an is_lwp check instead of checking for the number of lwps.
	(linux_nat_wait_1): Handle waiting for a specific tgid.  Handle
	pending process exit statuses.
	(linux_nat_mourn_inferior): Don't destroy all the LWP info.
	Instead delete LWPs of the inferior that we're mourning.  Don't
	unregister from the event loop here.
	(linux_nat_pid_to_str): Use `num_lwps'.
	(linux_nat_make_corefile_notes): Adjust to walk over lwps of a
	single inferior.
	(linux_nat_is_async_p): Check if async was masked out.
	(linux_multi_process): New global.
	(linux_nat_supports_multi_process): New.
	(linux_nat_stop_lwp): Remove LWP filtering.  It is done by the
	caller.
	(linux_nat_stop): Adjust to make iterate_over_lwps itself do the
	LWP filtering.
	(linux_nat_close): New.
	(linux_nat_add_target): Register linux_nat_close and
	linux_nat_supports_multi_process.
	* linux-nat.h (iterate_over_lwps): Add filter argument.
	* linux-thread-db.c (thread_db_handle): Delete.
	(proc_handle, thread_agent, td_init_p, td_ta_new_p)
	(td_ta_map_id2thr_p, td_ta_map_lwp2thr_p, td_ta_thr_iter_p)
	(td_ta_event_addr_p, td_ta_set_event_p, td_ta_event_getmsg_p)
	(td_thr_validate_p, td_thr_get_info_p, td_thr_event_enable_p)
	(td_thr_tls_get_addr_p, td_create_bp_addr, td_death_bp_addr): No
	longer globals, moved to...
	(struct thread_db_info): ... this new structure.
	(thread_db_list): New.
	(add_thread_db_info, get_thread_db_info, delete_thread_db_info):
	New.
	(have_threads_callback): Filter out threads of all inferiors but
	the one specified by the ARGS argument.
	(have_threads): Add ptid argument specifying the inferior we're
	interested in.  Handle it.
	(struct thread_get_info_inout): New.
	(thread_get_info_callback, thread_from_lwp): Adjust to use it.
	(thread_db_attach_lwp): Check that inferior of the passed in
	thread is using thread-db.  Adjust.
	(enable_thread_event): Remove thread_agent parameter.  Instead,
	get it from the per-inferior thread-db info.
	(dladdr_to_soname): Move higher up.
	(enable_thread_event_reporting): Adjust to use per-inferior
	thread-db info.
	(try_thread_db_load_1): Replace `handle' parameter by a
	thread_db_info parameter.  Adjust to use per-inferior thread-db
	info.
	(try_thread_db_load): Adjust to use per-inferior thread-db info.
	(thread_db_load, disable_thread_event_reporting): Ditto.
	(check_for_thread_db): Remove conditional reporting of which
	libthread_db is in use.
	(thread_db_new_objfile): Add comment about inferior_ptid.
	(attach_thread): Adjust to use per-inferior thread-db info.
	(thread_db_detach): Adjust to use per-inferior thread-db info.
	Remove thread event breakpoints of the current inferior.  Only
	unpush the thread-db target if there are no more processes using
	it.
	(check_event): Adjust to use per-inferior thread-db info.
	(thread_db_wait): Adjust to use per-inferior thread-db info.  Only
	unpush the thread-db target if there are no more processes using
	it.
	(thread_db_mourn_inferior): Adjust to use per-inferior thread-db
	info.  Mark breakpoints of the current inferior out before
	deleting them.  Only unpush the thread-db target if there are no
	more processes using it.
	(find_new_threads_callback): Adjust to use per-inferior thread_db
	info.
	(thread_db_find_new_threads_1): Add new ptid argument.  Adjust to
	use per-inferior thread-db info.
	(thread_db_find_new_threads): Adjust to use per-inferior thread-db
	info.
	(thread_db_get_thread_local_address): Adjust.
	(thread_db_get_ada_task_ptid): Adjust.
	* inf-ptrace.c (inf_ptrace_mourn_inferior): Only unpush the target
	if there no more processes left to debug.
	* thread.c (set_running, set_executing): Handle resuming all
	threads of a single inferior.
	* mi/mi-interp.c (mi_output_running_pid): New.
	(mi_inferior_count): New.
	(mi_on_resume): For backwards compatibility, if resuming all
	threads of an inferior, and there is only one inferior, output
	"all".
This commit is contained in:
Pedro Alves 2009-05-18 14:07:18 +00:00
parent dddfab26ac
commit d90e17a74d
8 changed files with 854 additions and 381 deletions

View file

@ -1,3 +1,112 @@
2009-05-18 Pedro Alves <pedro@codesourcery.com>
* fork-child.c (fork_inferior): Only reset the thread list if this
is the first inferior.
(startup_inferior): If the target support multi-process, tell it
to resume only the new process.
* linux-nat.c (num_lwps): Delete global.
(purge_lwp_list): New function.
(num_lwps): New function.
(add_lwp, delete_lwp): Adjust.
(ptid_match): New.
(iterate_over_lwps): Add filter argument. Handle it.
(linux_nat_attach): Remove FIXME note.
(linux_nat_detach): Adjust to iterate over threads of the inferior
we're detaching from. Adjust to num_lwps being a function. Don't
assume the head of the lwp list is the main thread of the process
we're detaching from. Don't destroy the LWP list.
(resume_callback): Add debug output.
(linux_nat_resume): Handle resuming a single inferior. Allow a
wildcard resume in non-stop mode.
(linux_handle_extended_wait): Don't assume inferior_ptid is the
correct inferior of the parent LWP.
(status_callback): Also check lp->waitstatus.
(select_event_lwp): Add new filter parameter. Handle it.
(linux_nat_filter_event): Adjust to num_lwps being a function.
(linux_nat_wait_1): When adding the first lwp of the inferior, use
an is_lwp check instead of checking for the number of lwps.
(linux_nat_wait_1): Handle waiting for a specific tgid. Handle
pending process exit statuses.
(linux_nat_mourn_inferior): Don't destroy all the LWP info.
Instead delete LWPs of the inferior that we're mourning. Don't
unregister from the event loop here.
(linux_nat_pid_to_str): Use `num_lwps'.
(linux_nat_make_corefile_notes): Adjust to walk over lwps of a
single inferior.
(linux_nat_is_async_p): Check if async was masked out.
(linux_multi_process): New global.
(linux_nat_supports_multi_process): New.
(linux_nat_stop_lwp): Remove LWP filtering. It is done by the
caller.
(linux_nat_stop): Adjust to make iterate_over_lwps itself do the
LWP filtering.
(linux_nat_close): New.
(linux_nat_add_target): Register linux_nat_close and
linux_nat_supports_multi_process.
* linux-nat.h (iterate_over_lwps): Add filter argument.
* linux-thread-db.c (thread_db_handle): Delete.
(proc_handle, thread_agent, td_init_p, td_ta_new_p)
(td_ta_map_id2thr_p, td_ta_map_lwp2thr_p, td_ta_thr_iter_p)
(td_ta_event_addr_p, td_ta_set_event_p, td_ta_event_getmsg_p)
(td_thr_validate_p, td_thr_get_info_p, td_thr_event_enable_p)
(td_thr_tls_get_addr_p, td_create_bp_addr, td_death_bp_addr): No
longer globals, moved to...
(struct thread_db_info): ... this new structure.
(thread_db_list): New.
(add_thread_db_info, get_thread_db_info, delete_thread_db_info):
New.
(have_threads_callback): Filter out threads of all inferiors but
the one specified by the ARGS argument.
(have_threads): Add ptid argument specifying the inferior we're
interested in. Handle it.
(struct thread_get_info_inout): New.
(thread_get_info_callback, thread_from_lwp): Adjust to use it.
(thread_db_attach_lwp): Check that inferior of the passed in
thread is using thread-db. Adjust.
(enable_thread_event): Remove thread_agent parameter. Instead,
get it from the per-inferior thread-db info.
(dladdr_to_soname): Move higher up.
(enable_thread_event_reporting): Adjust to use per-inferior
thread-db info.
(try_thread_db_load_1): Replace `handle' parameter by a
thread_db_info parameter. Adjust to use per-inferior thread-db
info.
(try_thread_db_load): Adjust to use per-inferior thread-db info.
(thread_db_load, disable_thread_event_reporting): Ditto.
(check_for_thread_db): Remove conditional reporting of which
libthread_db is in use.
(thread_db_new_objfile): Add comment about inferior_ptid.
(attach_thread): Adjust to use per-inferior thread-db info.
(thread_db_detach): Adjust to use per-inferior thread-db info.
Remove thread event breakpoints of the current inferior. Only
unpush the thread-db target if there are no more processes using
it.
(check_event): Adjust to use per-inferior thread-db info.
(thread_db_wait): Adjust to use per-inferior thread-db info. Only
unpush the thread-db target if there are no more processes using
it.
(thread_db_mourn_inferior): Adjust to use per-inferior thread-db
info. Mark breakpoints of the current inferior out before
deleting them. Only unpush the thread-db target if there are no
more processes using it.
(find_new_threads_callback): Adjust to use per-inferior thread_db
info.
(thread_db_find_new_threads_1): Add new ptid argument. Adjust to
use per-inferior thread-db info.
(thread_db_find_new_threads): Adjust to use per-inferior thread-db
info.
(thread_db_get_thread_local_address): Adjust.
(thread_db_get_ada_task_ptid): Adjust.
* inf-ptrace.c (inf_ptrace_mourn_inferior): Only unpush the target
if there no more processes left to debug.
* thread.c (set_running, set_executing): Handle resuming all
threads of a single inferior.
* mi/mi-interp.c (mi_output_running_pid): New.
(mi_inferior_count): New.
(mi_on_resume): For backwards compatibility, if resuming all
threads of an inferior, and there is only one inferior, output
"all".
2009-05-18 Ulrich Weigand <uweigand@de.ibm.com> 2009-05-18 Ulrich Weigand <uweigand@de.ibm.com>
* ada-lang.c (ada_find_any_type): Move check for primitive types ... * ada-lang.c (ada_find_any_type): Move check for primitive types ...

View file

@ -392,7 +392,8 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
/* Restore our environment in case a vforked child clob'd it. */ /* Restore our environment in case a vforked child clob'd it. */
environ = save_our_env; environ = save_our_env;
init_thread_list (); if (!have_inferiors ())
init_thread_list ();
add_inferior (pid); add_inferior (pid);
@ -424,6 +425,12 @@ startup_inferior (int ntraps)
{ {
int pending_execs = ntraps; int pending_execs = ntraps;
int terminal_initted = 0; int terminal_initted = 0;
ptid_t resume_ptid;
if (target_supports_multi_process ())
resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
else
resume_ptid = minus_one_ptid;
/* The process was started by the fork that created it, but it will /* The process was started by the fork that created it, but it will
have stopped one instruction after execing the shell. Here we have stopped one instruction after execing the shell. Here we
@ -435,12 +442,11 @@ startup_inferior (int ntraps)
while (1) while (1)
{ {
int resume_signal = TARGET_SIGNAL_0; int resume_signal = TARGET_SIGNAL_0;
ptid_t resume_ptid;
ptid_t event_ptid; ptid_t event_ptid;
struct target_waitstatus ws; struct target_waitstatus ws;
memset (&ws, 0, sizeof (ws)); memset (&ws, 0, sizeof (ws));
event_ptid = target_wait (pid_to_ptid (-1), &ws); event_ptid = target_wait (resume_ptid, &ws);
if (ws.kind == TARGET_WAITKIND_IGNORE) if (ws.kind == TARGET_WAITKIND_IGNORE)
/* The inferior didn't really stop, keep waiting. */ /* The inferior didn't really stop, keep waiting. */
@ -489,12 +495,6 @@ startup_inferior (int ntraps)
break; break;
} }
/* In all-stop mode, resume all threads. */
if (!non_stop)
resume_ptid = pid_to_ptid (-1);
else
resume_ptid = event_ptid;
if (resume_signal != TARGET_SIGNAL_TRAP) if (resume_signal != TARGET_SIGNAL_TRAP)
{ {
/* Let shell child handle its own signals in its own way. */ /* Let shell child handle its own signals in its own way. */
@ -529,7 +529,7 @@ startup_inferior (int ntraps)
} }
/* Mark all threads non-executing. */ /* Mark all threads non-executing. */
set_executing (pid_to_ptid (-1), 0); set_executing (resume_ptid, 0);
} }
/* Implement the "unset exec-wrapper" command. */ /* Implement the "unset exec-wrapper" command. */

View file

@ -199,8 +199,10 @@ inf_ptrace_mourn_inferior (struct target_ops *ops)
only report its exit status to its original parent. */ only report its exit status to its original parent. */
waitpid (ptid_get_pid (inferior_ptid), &status, 0); waitpid (ptid_get_pid (inferior_ptid), &status, 0);
unpush_target (ops);
generic_mourn_inferior (); generic_mourn_inferior ();
if (!have_inferiors ())
unpush_target (ops);
} }
/* Attach to the process specified by ARGS. If FROM_TTY is non-zero, /* Attach to the process specified by ARGS. If FROM_TTY is non-zero,

View file

@ -841,9 +841,6 @@ linux_child_insert_exec_catchpoint (int pid)
/* List of known LWPs. */ /* List of known LWPs. */
struct lwp_info *lwp_list; struct lwp_info *lwp_list;
/* Number of LWPs in the list. */
static int num_lwps;
/* Original signal mask. */ /* Original signal mask. */
@ -926,7 +923,48 @@ init_lwp_list (void)
} }
lwp_list = NULL; lwp_list = NULL;
num_lwps = 0; }
/* Remove all LWPs belong to PID from the lwp list. */
static void
purge_lwp_list (int pid)
{
struct lwp_info *lp, *lpprev, *lpnext;
lpprev = NULL;
for (lp = lwp_list; lp; lp = lpnext)
{
lpnext = lp->next;
if (ptid_get_pid (lp->ptid) == pid)
{
if (lp == lwp_list)
lwp_list = lp->next;
else
lpprev->next = lp->next;
xfree (lp);
}
else
lpprev = lp;
}
}
/* Return the number of known LWPs in the tgid given by PID. */
static int
num_lwps (int pid)
{
int count = 0;
struct lwp_info *lp;
for (lp = lwp_list; lp; lp = lp->next)
if (ptid_get_pid (lp->ptid) == pid)
count++;
return count;
} }
/* Add the LWP specified by PID to the list. Return a pointer to the /* Add the LWP specified by PID to the list. Return a pointer to the
@ -950,9 +988,8 @@ add_lwp (ptid_t ptid)
lp->next = lwp_list; lp->next = lwp_list;
lwp_list = lp; lwp_list = lp;
++num_lwps;
if (num_lwps > 1 && linux_nat_new_thread != NULL) if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
linux_nat_new_thread (ptid); linux_nat_new_thread (ptid);
return lp; return lp;
@ -974,8 +1011,6 @@ delete_lwp (ptid_t ptid)
if (!lp) if (!lp)
return; return;
num_lwps--;
if (lpprev) if (lpprev)
lpprev->next = lp->next; lpprev->next = lp->next;
else else
@ -1005,21 +1040,54 @@ find_lwp_pid (ptid_t ptid)
return NULL; return NULL;
} }
/* Returns true if PTID matches filter FILTER. FILTER can be the wild
card MINUS_ONE_PTID (all ptid match it); can be a ptid representing
a process (ptid_is_pid returns true), in which case, all lwps of
that give process match, lwps of other process do not; or, it can
represent a specific thread, in which case, only that thread will
match true. PTID must represent an LWP, it can never be a wild
card. */
static int
ptid_match (ptid_t ptid, ptid_t filter)
{
/* Since both parameters have the same type, prevent easy mistakes
from happening. */
gdb_assert (!ptid_equal (ptid, minus_one_ptid)
&& !ptid_equal (ptid, null_ptid));
if (ptid_equal (filter, minus_one_ptid))
return 1;
if (ptid_is_pid (filter)
&& ptid_get_pid (ptid) == ptid_get_pid (filter))
return 1;
else if (ptid_equal (ptid, filter))
return 1;
return 0;
}
/* Call CALLBACK with its second argument set to DATA for every LWP in /* Call CALLBACK with its second argument set to DATA for every LWP in
the list. If CALLBACK returns 1 for a particular LWP, return a the list. If CALLBACK returns 1 for a particular LWP, return a
pointer to the structure describing that LWP immediately. pointer to the structure describing that LWP immediately.
Otherwise return NULL. */ Otherwise return NULL. */
struct lwp_info * struct lwp_info *
iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data) iterate_over_lwps (ptid_t filter,
int (*callback) (struct lwp_info *, void *),
void *data)
{ {
struct lwp_info *lp, *lpnext; struct lwp_info *lp, *lpnext;
for (lp = lwp_list; lp; lp = lpnext) for (lp = lwp_list; lp; lp = lpnext)
{ {
lpnext = lp->next; lpnext = lp->next;
if ((*callback) (lp, data))
return lp; if (ptid_match (lp->ptid, filter))
{
if ((*callback) (lp, data))
return lp;
}
} }
return NULL; return NULL;
@ -1296,8 +1364,6 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
int status; int status;
ptid_t ptid; ptid_t ptid;
/* FIXME: We should probably accept a list of process id's, and
attach all of them. */
linux_ops->to_attach (ops, args, from_tty); linux_ops->to_attach (ops, args, from_tty);
/* The ptrace base target adds the main thread with (pid,0,0) /* The ptrace base target adds the main thread with (pid,0,0)
@ -1457,25 +1523,30 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
int pid; int pid;
int status; int status;
enum target_signal sig; enum target_signal sig;
struct lwp_info *main_lwp;
pid = GET_PID (inferior_ptid);
if (target_can_async_p ()) if (target_can_async_p ())
linux_nat_async (NULL, 0); linux_nat_async (NULL, 0);
/* Stop all threads before detaching. ptrace requires that the /* Stop all threads before detaching. ptrace requires that the
thread is stopped to sucessfully detach. */ thread is stopped to sucessfully detach. */
iterate_over_lwps (stop_callback, NULL); iterate_over_lwps (pid_to_ptid (pid), stop_callback, NULL);
/* ... and wait until all of them have reported back that /* ... and wait until all of them have reported back that
they're no longer running. */ they're no longer running. */
iterate_over_lwps (stop_wait_callback, NULL); iterate_over_lwps (pid_to_ptid (pid), stop_wait_callback, NULL);
iterate_over_lwps (detach_callback, NULL); iterate_over_lwps (pid_to_ptid (pid), detach_callback, NULL);
/* Only the initial process should be left right now. */ /* Only the initial process should be left right now. */
gdb_assert (num_lwps == 1); gdb_assert (num_lwps (GET_PID (inferior_ptid)) == 1);
main_lwp = find_lwp_pid (pid_to_ptid (pid));
/* Pass on any pending signal for the last LWP. */ /* Pass on any pending signal for the last LWP. */
if ((args == NULL || *args == '\0') if ((args == NULL || *args == '\0')
&& get_pending_status (lwp_list, &status) != -1 && get_pending_status (main_lwp, &status) != -1
&& WIFSTOPPED (status)) && WIFSTOPPED (status))
{ {
/* Put the signal number in ARGS so that inf_ptrace_detach will /* Put the signal number in ARGS so that inf_ptrace_detach will
@ -1485,13 +1556,10 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
fprintf_unfiltered (gdb_stdlog, fprintf_unfiltered (gdb_stdlog,
"LND: Sending signal %s to %s\n", "LND: Sending signal %s to %s\n",
args, args,
target_pid_to_str (lwp_list->ptid)); target_pid_to_str (main_lwp->ptid));
} }
/* Destroy LWP info; it's no longer valid. */ delete_lwp (main_lwp->ptid);
init_lwp_list ();
pid = ptid_get_pid (inferior_ptid);
if (forks_exist_p ()) if (forks_exist_p ())
{ {
@ -1515,6 +1583,11 @@ resume_callback (struct lwp_info *lp, void *data)
{ {
if (lp->stopped && lp->status == 0) if (lp->stopped && lp->status == 0)
{ {
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"RC: PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
target_pid_to_str (lp->ptid));
linux_ops->to_resume (linux_ops, linux_ops->to_resume (linux_ops,
pid_to_ptid (GET_LWP (lp->ptid)), pid_to_ptid (GET_LWP (lp->ptid)),
0, TARGET_SIGNAL_0); 0, TARGET_SIGNAL_0);
@ -1556,7 +1629,7 @@ linux_nat_resume (struct target_ops *ops,
{ {
sigset_t prev_mask; sigset_t prev_mask;
struct lwp_info *lp; struct lwp_info *lp;
int resume_all; int resume_many;
if (debug_linux_nat) if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog, fprintf_unfiltered (gdb_stdlog,
@ -1569,37 +1642,29 @@ linux_nat_resume (struct target_ops *ops,
block_child_signals (&prev_mask); block_child_signals (&prev_mask);
/* A specific PTID means `step only this process id'. */ /* A specific PTID means `step only this process id'. */
resume_all = (PIDGET (ptid) == -1); resume_many = (ptid_equal (minus_one_ptid, ptid)
|| ptid_is_pid (ptid));
if (non_stop && resume_all)
internal_error (__FILE__, __LINE__,
"can't resume all in non-stop mode");
if (!non_stop) if (!non_stop)
{ {
if (resume_all) /* Mark the lwps we're resuming as resumed. */
iterate_over_lwps (resume_set_callback, NULL); iterate_over_lwps (minus_one_ptid, resume_clear_callback, NULL);
else iterate_over_lwps (ptid, resume_set_callback, NULL);
iterate_over_lwps (resume_clear_callback, NULL);
} }
else
iterate_over_lwps (minus_one_ptid, resume_set_callback, NULL);
/* If PID is -1, it's the current inferior that should be /* See if it's the current inferior that should be handled
handled specially. */ specially. */
if (PIDGET (ptid) == -1) if (resume_many)
ptid = inferior_ptid; lp = find_lwp_pid (inferior_ptid);
else
lp = find_lwp_pid (ptid); lp = find_lwp_pid (ptid);
gdb_assert (lp != NULL); gdb_assert (lp != NULL);
/* Convert to something the lower layer understands. */
ptid = pid_to_ptid (GET_LWP (lp->ptid));
/* Remember if we're stepping. */ /* Remember if we're stepping. */
lp->step = step; lp->step = step;
/* Mark this LWP as resumed. */
lp->resumed = 1;
/* If we have a pending wait status for this thread, there is no /* If we have a pending wait status for this thread, there is no
point in resuming the process. But first make sure that point in resuming the process. But first make sure that
linux_nat_wait won't preemptively handle the event - we linux_nat_wait won't preemptively handle the event - we
@ -1613,7 +1678,7 @@ linux_nat_resume (struct target_ops *ops,
int saved_signo; int saved_signo;
struct inferior *inf; struct inferior *inf;
inf = find_inferior_pid (ptid_get_pid (ptid)); inf = find_inferior_pid (ptid_get_pid (lp->ptid));
gdb_assert (inf); gdb_assert (inf);
saved_signo = target_signal_from_host (WSTOPSIG (lp->status)); saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
@ -1662,8 +1727,11 @@ linux_nat_resume (struct target_ops *ops,
resume_callback. */ resume_callback. */
lp->stopped = 0; lp->stopped = 0;
if (resume_all) if (resume_many)
iterate_over_lwps (resume_callback, NULL); iterate_over_lwps (ptid, resume_callback, NULL);
/* Convert to something the lower layer understands. */
ptid = pid_to_ptid (GET_LWP (lp->ptid));
linux_ops->to_resume (linux_ops, ptid, step, signo); linux_ops->to_resume (linux_ops, ptid, step, signo);
memset (&lp->siginfo, 0, sizeof (lp->siginfo)); memset (&lp->siginfo, 0, sizeof (lp->siginfo));
@ -1757,7 +1825,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
struct cleanup *old_chain; struct cleanup *old_chain;
ourstatus->kind = TARGET_WAITKIND_IGNORE; ourstatus->kind = TARGET_WAITKIND_IGNORE;
new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (inferior_ptid))); new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (lp->ptid)));
new_lp->cloned = 1; new_lp->cloned = 1;
new_lp->stopped = 1; new_lp->stopped = 1;
@ -2181,7 +2249,12 @@ status_callback (struct lwp_info *lp, void *data)
{ {
/* Only report a pending wait status if we pretend that this has /* Only report a pending wait status if we pretend that this has
indeed been resumed. */ indeed been resumed. */
return (lp->status != 0 && lp->resumed); /* We check for lp->waitstatus in addition to lp->status, because we
can have pending process exits recorded in lp->waitstatus, and
W_EXITCODE(0,0) == 0. */
return ((lp->status != 0
|| lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
&& lp->resumed);
} }
/* Return non-zero if LP isn't stopped. */ /* Return non-zero if LP isn't stopped. */
@ -2303,7 +2376,7 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
/* Select one LWP out of those that have events pending. */ /* Select one LWP out of those that have events pending. */
static void static void
select_event_lwp (struct lwp_info **orig_lp, int *status) select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
{ {
int num_events = 0; int num_events = 0;
int random_selector; int random_selector;
@ -2313,7 +2386,8 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
(*orig_lp)->status = *status; (*orig_lp)->status = *status;
/* Give preference to any LWP that is being single-stepped. */ /* Give preference to any LWP that is being single-stepped. */
event_lp = iterate_over_lwps (select_singlestep_lwp_callback, NULL); event_lp = iterate_over_lwps (filter,
select_singlestep_lwp_callback, NULL);
if (event_lp != NULL) if (event_lp != NULL)
{ {
if (debug_linux_nat) if (debug_linux_nat)
@ -2327,7 +2401,7 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
which have had SIGTRAP events. */ which have had SIGTRAP events. */
/* First see how many SIGTRAP events we have. */ /* First see how many SIGTRAP events we have. */
iterate_over_lwps (count_events_callback, &num_events); iterate_over_lwps (filter, count_events_callback, &num_events);
/* Now randomly pick a LWP out of those that have had a SIGTRAP. */ /* Now randomly pick a LWP out of those that have had a SIGTRAP. */
random_selector = (int) random_selector = (int)
@ -2338,7 +2412,8 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
"SEL: Found %d SIGTRAP events, selecting #%d\n", "SEL: Found %d SIGTRAP events, selecting #%d\n",
num_events, random_selector); num_events, random_selector);
event_lp = iterate_over_lwps (select_event_lwp_callback, event_lp = iterate_over_lwps (filter,
select_event_lwp_callback,
&random_selector); &random_selector);
} }
@ -2456,7 +2531,8 @@ linux_nat_filter_event (int lwpid, int status, int options)
} }
/* Check if the thread has exited. */ /* Check if the thread has exited. */
if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1) if ((WIFEXITED (status) || WIFSIGNALED (status))
&& num_lwps (GET_PID (lp->ptid)) > 1)
{ {
/* If this is the main thread, we must stop all threads and verify /* If this is the main thread, we must stop all threads and verify
if they are still alive. This is because in the nptl thread model if they are still alive. This is because in the nptl thread model
@ -2471,7 +2547,8 @@ linux_nat_filter_event (int lwpid, int status, int options)
if (GET_PID (lp->ptid) == GET_LWP (lp->ptid)) if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
{ {
lp->stopped = 1; lp->stopped = 1;
iterate_over_lwps (stop_and_resume_callback, NULL); iterate_over_lwps (pid_to_ptid (GET_PID (lp->ptid)),
stop_and_resume_callback, NULL);
} }
if (debug_linux_nat) if (debug_linux_nat)
@ -2479,7 +2556,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
"LLW: %s exited.\n", "LLW: %s exited.\n",
target_pid_to_str (lp->ptid)); target_pid_to_str (lp->ptid));
if (num_lwps > 1) if (num_lwps (GET_PID (lp->ptid)) > 1)
{ {
/* If there is at least one more LWP, then the exit signal /* If there is at least one more LWP, then the exit signal
was not the end of the debugged application and should be was not the end of the debugged application and should be
@ -2493,8 +2570,10 @@ linux_nat_filter_event (int lwpid, int status, int options)
thread model, LWPs other than the main thread do not issue thread model, LWPs other than the main thread do not issue
signals when they exit so we must check whenever the thread has signals when they exit so we must check whenever the thread has
stopped. A similar check is made in stop_wait_callback(). */ stopped. A similar check is made in stop_wait_callback(). */
if (num_lwps > 1 && !linux_thread_alive (lp->ptid)) if (num_lwps (GET_PID (lp->ptid)) > 1 && !linux_thread_alive (lp->ptid))
{ {
ptid_t ptid = pid_to_ptid (GET_PID (lp->ptid));
if (debug_linux_nat) if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog, fprintf_unfiltered (gdb_stdlog,
"LLW: %s exited.\n", "LLW: %s exited.\n",
@ -2503,7 +2582,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
exit_lwp (lp); exit_lwp (lp);
/* Make sure there is at least one thread running. */ /* Make sure there is at least one thread running. */
gdb_assert (iterate_over_lwps (running_callback, NULL)); gdb_assert (iterate_over_lwps (ptid, running_callback, NULL));
/* Discard the event. */ /* Discard the event. */
return NULL; return NULL;
@ -2583,7 +2662,7 @@ linux_nat_wait_1 (struct target_ops *ops,
struct lwp_info *lp = NULL; struct lwp_info *lp = NULL;
int options = 0; int options = 0;
int status = 0; int status = 0;
pid_t pid = PIDGET (ptid); pid_t pid;
if (debug_linux_nat_async) if (debug_linux_nat_async)
fprintf_unfiltered (gdb_stdlog, "LLW: enter\n"); fprintf_unfiltered (gdb_stdlog, "LLW: enter\n");
@ -2591,10 +2670,8 @@ linux_nat_wait_1 (struct target_ops *ops,
/* The first time we get here after starting a new inferior, we may /* The first time we get here after starting a new inferior, we may
not have added it to the LWP list yet - this is the earliest not have added it to the LWP list yet - this is the earliest
moment at which we know its PID. */ moment at which we know its PID. */
if (num_lwps == 0) if (ptid_is_pid (inferior_ptid))
{ {
gdb_assert (!is_lwp (inferior_ptid));
/* Upgrade the main thread's ptid. */ /* Upgrade the main thread's ptid. */
thread_change_ptid (inferior_ptid, thread_change_ptid (inferior_ptid,
BUILD_LWP (GET_PID (inferior_ptid), BUILD_LWP (GET_PID (inferior_ptid),
@ -2607,16 +2684,29 @@ linux_nat_wait_1 (struct target_ops *ops,
/* Make sure SIGCHLD is blocked. */ /* Make sure SIGCHLD is blocked. */
block_child_signals (&prev_mask); block_child_signals (&prev_mask);
if (ptid_equal (ptid, minus_one_ptid))
pid = -1;
else if (ptid_is_pid (ptid))
/* A request to wait for a specific tgid. This is not possible
with waitpid, so instead, we wait for any child, and leave
children we're not interested in right now with a pending
status to report later. */
pid = -1;
else
pid = GET_LWP (ptid);
retry: retry:
lp = NULL;
status = 0;
/* Make sure there is at least one LWP that has been resumed. */ /* Make sure there is at least one LWP that has been resumed. */
gdb_assert (iterate_over_lwps (resumed_callback, NULL)); gdb_assert (iterate_over_lwps (ptid, resumed_callback, NULL));
/* First check if there is a LWP with a wait status pending. */ /* First check if there is a LWP with a wait status pending. */
if (pid == -1) if (pid == -1)
{ {
/* Any LWP that's been resumed will do. */ /* Any LWP that's been resumed will do. */
lp = iterate_over_lwps (status_callback, NULL); lp = iterate_over_lwps (ptid, status_callback, NULL);
if (lp) if (lp)
{ {
status = lp->status; status = lp->status;
@ -2658,9 +2748,16 @@ retry:
the layer beneath us can understand. */ the layer beneath us can understand. */
options = lp->cloned ? __WCLONE : 0; options = lp->cloned ? __WCLONE : 0;
pid = GET_LWP (ptid); pid = GET_LWP (ptid);
/* We check for lp->waitstatus in addition to lp->status,
because we can have pending process exits recorded in
lp->status and W_EXITCODE(0,0) == 0. We should probably have
an additional lp->status_p flag. */
if (status == 0 && lp->waitstatus.kind == TARGET_WAITKIND_IGNORE)
lp = NULL;
} }
if (status && lp->signalled) if (lp && lp->signalled)
{ {
/* A pending SIGSTOP may interfere with the normal stream of /* A pending SIGSTOP may interfere with the normal stream of
events. In a typical case where interference is a problem, events. In a typical case where interference is a problem,
@ -2697,7 +2794,7 @@ retry:
if (target_can_async_p ()) if (target_can_async_p ())
options |= WNOHANG; /* In async mode, don't block. */ options |= WNOHANG; /* In async mode, don't block. */
while (status == 0) while (lp == NULL)
{ {
pid_t lwpid; pid_t lwpid;
@ -2715,14 +2812,79 @@ retry:
} }
lp = linux_nat_filter_event (lwpid, status, options); lp = linux_nat_filter_event (lwpid, status, options);
if (!lp)
if (lp
&& ptid_is_pid (ptid)
&& ptid_get_pid (lp->ptid) != ptid_get_pid (ptid))
{ {
/* A discarded event. */ if (debug_linux_nat)
status = 0; fprintf (stderr, "LWP %ld got an event %06x, leaving pending.\n",
ptid_get_lwp (lp->ptid), status);
if (WIFSTOPPED (status))
{
if (WSTOPSIG (status) != SIGSTOP)
{
lp->status = status;
stop_callback (lp, NULL);
/* Resume in order to collect the sigstop. */
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
stop_wait_callback (lp, NULL);
}
else
{
lp->stopped = 1;
lp->signalled = 0;
}
}
else if (WIFEXITED (status) || WIFSIGNALED (status))
{
if (debug_linux_nat)
fprintf (stderr, "Process %ld exited while stopping LWPs\n",
ptid_get_lwp (lp->ptid));
/* This was the last lwp in the process. Since
events are serialized to GDB core, and we can't
report this one right now, but GDB core and the
other target layers will want to be notified
about the exit code/signal, leave the status
pending for the next time we're able to report
it. */
lp->status = status;
/* Prevent trying to stop this thread again. We'll
never try to resume it because it has a pending
status. */
lp->stopped = 1;
/* Dead LWP's aren't expected to reported a pending
sigstop. */
lp->signalled = 0;
/* Store the pending event in the waitstatus as
well, because W_EXITCODE(0,0) == 0. */
store_waitstatus (&lp->waitstatus, status);
}
/* Keep looking. */
lp = NULL;
continue; continue;
} }
break; if (lp)
break;
else
{
if (pid == -1)
{
/* waitpid did return something. Restart over. */
options |= __WCLONE;
}
continue;
}
} }
if (pid == -1) if (pid == -1)
@ -2752,7 +2914,7 @@ retry:
} }
/* We shouldn't end up here unless we want to try again. */ /* We shouldn't end up here unless we want to try again. */
gdb_assert (status == 0); gdb_assert (lp == NULL);
} }
if (!target_can_async_p ()) if (!target_can_async_p ())
@ -2801,7 +2963,6 @@ retry:
target_pid_to_str (lp->ptid), target_pid_to_str (lp->ptid),
signo ? strsignal (signo) : "0"); signo ? strsignal (signo) : "0");
lp->stopped = 0; lp->stopped = 0;
status = 0;
goto retry; goto retry;
} }
@ -2817,7 +2978,8 @@ retry:
will receive it - unless they're using CLONE_THREAD to will receive it - unless they're using CLONE_THREAD to
share signals. Since we only want to report it once, we share signals. Since we only want to report it once, we
mark it as ignored for all LWPs except this one. */ mark it as ignored for all LWPs except this one. */
iterate_over_lwps (set_ignore_sigint, NULL); iterate_over_lwps (pid_to_ptid (ptid_get_pid (ptid)),
set_ignore_sigint, NULL);
lp->ignore_sigint = 0; lp->ignore_sigint = 0;
} }
else else
@ -2835,24 +2997,24 @@ retry:
if (!non_stop) if (!non_stop)
{ {
/* Now stop all other LWP's ... */ /* Now stop all other LWP's ... */
iterate_over_lwps (stop_callback, NULL); iterate_over_lwps (minus_one_ptid, stop_callback, NULL);
/* ... and wait until all of them have reported back that /* ... and wait until all of them have reported back that
they're no longer running. */ they're no longer running. */
iterate_over_lwps (stop_wait_callback, NULL); iterate_over_lwps (minus_one_ptid, stop_wait_callback, NULL);
/* If we're not waiting for a specific LWP, choose an event LWP /* If we're not waiting for a specific LWP, choose an event LWP
from among those that have had events. Giving equal priority from among those that have had events. Giving equal priority
to all LWPs that have had events helps prevent to all LWPs that have had events helps prevent
starvation. */ starvation. */
if (pid == -1) if (pid == -1)
select_event_lwp (&lp, &status); select_event_lwp (ptid, &lp, &status);
} }
/* Now that we've selected our final event LWP, cancel any /* Now that we've selected our final event LWP, cancel any
breakpoints in other LWPs that have hit a GDB breakpoint. See breakpoints in other LWPs that have hit a GDB breakpoint. See
the comment in cancel_breakpoints_callback to find out why. */ the comment in cancel_breakpoints_callback to find out why. */
iterate_over_lwps (cancel_breakpoints_callback, lp); iterate_over_lwps (minus_one_ptid, cancel_breakpoints_callback, lp);
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP) if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
{ {
@ -3000,18 +3162,19 @@ linux_nat_kill (struct target_ops *ops)
linux_fork_killall (); linux_fork_killall ();
else else
{ {
ptid_t ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
/* Stop all threads before killing them, since ptrace requires /* Stop all threads before killing them, since ptrace requires
that the thread is stopped to sucessfully PTRACE_KILL. */ that the thread is stopped to sucessfully PTRACE_KILL. */
iterate_over_lwps (stop_callback, NULL); iterate_over_lwps (ptid, stop_callback, NULL);
/* ... and wait until all of them have reported back that /* ... and wait until all of them have reported back that
they're no longer running. */ they're no longer running. */
iterate_over_lwps (stop_wait_callback, NULL); iterate_over_lwps (ptid, stop_wait_callback, NULL);
/* Kill all LWP's ... */ /* Kill all LWP's ... */
iterate_over_lwps (kill_callback, NULL); iterate_over_lwps (ptid, kill_callback, NULL);
/* ... and wait until we've flushed all events. */ /* ... and wait until we've flushed all events. */
iterate_over_lwps (kill_wait_callback, NULL); iterate_over_lwps (ptid, kill_wait_callback, NULL);
} }
target_mourn_inferior (); target_mourn_inferior ();
@ -3020,17 +3183,11 @@ linux_nat_kill (struct target_ops *ops)
static void static void
linux_nat_mourn_inferior (struct target_ops *ops) linux_nat_mourn_inferior (struct target_ops *ops)
{ {
/* Destroy LWP info; it's no longer valid. */ purge_lwp_list (ptid_get_pid (inferior_ptid));
init_lwp_list ();
if (! forks_exist_p ()) if (! forks_exist_p ())
{ /* Normal case, no other forks available. */
/* Normal case, no other forks available. */ linux_ops->to_mourn_inferior (ops);
linux_ops->to_mourn_inferior (ops);
if (target_can_async_p ())
linux_nat_async (NULL, 0);
}
else else
/* Multi-fork case. The current inferior_ptid has exited, but /* Multi-fork case. The current inferior_ptid has exited, but
there are other viable forks to debug. Delete the exiting there are other viable forks to debug. Delete the exiting
@ -3174,8 +3331,8 @@ linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
static char buf[64]; static char buf[64];
if (is_lwp (ptid) if (is_lwp (ptid)
&& ((lwp_list && lwp_list->next) && (GET_PID (ptid) != GET_LWP (ptid)
|| GET_PID (ptid) != GET_LWP (ptid))) || num_lwps (GET_PID (ptid)) > 1))
{ {
snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid)); snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
return buf; return buf;
@ -3450,6 +3607,7 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
char psargs[80] = { '\0' }; char psargs[80] = { '\0' };
char *note_data = NULL; char *note_data = NULL;
ptid_t current_ptid = inferior_ptid; ptid_t current_ptid = inferior_ptid;
ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
gdb_byte *auxv; gdb_byte *auxv;
int auxv_len; int auxv_len;
@ -3483,7 +3641,7 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
thread_args.note_size = note_size; thread_args.note_size = note_size;
thread_args.num_notes = 0; thread_args.num_notes = 0;
thread_args.stop_signal = find_stop_signal (); thread_args.stop_signal = find_stop_signal ();
iterate_over_lwps (linux_nat_corefile_thread_callback, &thread_args); iterate_over_lwps (filter, linux_nat_corefile_thread_callback, &thread_args);
gdb_assert (thread_args.num_notes != 0); gdb_assert (thread_args.num_notes != 0);
note_data = thread_args.note_data; note_data = thread_args.note_data;
@ -4096,7 +4254,8 @@ linux_nat_is_async_p (void)
if (!target_async_permitted) if (!target_async_permitted)
return 0; return 0;
return 1; /* See target.h/target_async_mask. */
return linux_nat_async_mask_value;
} }
/* target_can_async_p implementation. */ /* target_can_async_p implementation. */
@ -4120,6 +4279,17 @@ linux_nat_supports_non_stop (void)
return 1; return 1;
} }
/* True if we want to support multi-process. To be removed when GDB
supports multi-exec. */
int linux_multi_process = 0;
static int
linux_nat_supports_multi_process (void)
{
return linux_multi_process;
}
/* target_async_mask implementation. */ /* target_async_mask implementation. */
static int static int
@ -4317,56 +4487,48 @@ linux_nat_async (void (*callback) (enum inferior_event_type event_type,
static int static int
linux_nat_stop_lwp (struct lwp_info *lwp, void *data) linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
{ {
ptid_t ptid = * (ptid_t *) data; if (!lwp->stopped)
if (ptid_equal (lwp->ptid, ptid)
|| ptid_equal (minus_one_ptid, ptid)
|| (ptid_is_pid (ptid)
&& ptid_get_pid (ptid) == ptid_get_pid (lwp->ptid)))
{ {
if (!lwp->stopped) int pid, status;
ptid_t ptid = lwp->ptid;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LNSL: running -> suspending %s\n",
target_pid_to_str (lwp->ptid));
stop_callback (lwp, NULL);
stop_wait_callback (lwp, NULL);
/* If the lwp exits while we try to stop it, there's nothing
else to do. */
lwp = find_lwp_pid (ptid);
if (lwp == NULL)
return 0;
/* If we didn't collect any signal other than SIGSTOP while
stopping the LWP, push a SIGNAL_0 event. In either case, the
event-loop will end up calling target_wait which will collect
these. */
if (lwp->status == 0)
lwp->status = W_STOPCODE (0);
async_file_mark ();
}
else
{
/* Already known to be stopped; do nothing. */
if (debug_linux_nat)
{ {
int pid, status; if (find_thread_pid (lwp->ptid)->stop_requested)
ptid_t ptid = lwp->ptid; fprintf_unfiltered (gdb_stdlog, "\
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LNSL: running -> suspending %s\n",
target_pid_to_str (lwp->ptid));
stop_callback (lwp, NULL);
stop_wait_callback (lwp, NULL);
/* If the lwp exits while we try to stop it, there's nothing
else to do. */
lwp = find_lwp_pid (ptid);
if (lwp == NULL)
return 0;
/* If we didn't collect any signal other than SIGSTOP while
stopping the LWP, push a SIGNAL_0 event. In either case,
the event-loop will end up calling target_wait which will
collect these. */
if (lwp->status == 0)
lwp->status = W_STOPCODE (0);
async_file_mark ();
}
else
{
/* Already known to be stopped; do nothing. */
if (debug_linux_nat)
{
if (find_thread_pid (lwp->ptid)->stop_requested)
fprintf_unfiltered (gdb_stdlog, "\
LNSL: already stopped/stop_requested %s\n", LNSL: already stopped/stop_requested %s\n",
target_pid_to_str (lwp->ptid)); target_pid_to_str (lwp->ptid));
else else
fprintf_unfiltered (gdb_stdlog, "\ fprintf_unfiltered (gdb_stdlog, "\
LNSL: already stopped/no stop_requested yet %s\n", LNSL: already stopped/no stop_requested yet %s\n",
target_pid_to_str (lwp->ptid)); target_pid_to_str (lwp->ptid));
}
} }
} }
return 0; return 0;
@ -4376,11 +4538,25 @@ static void
linux_nat_stop (ptid_t ptid) linux_nat_stop (ptid_t ptid)
{ {
if (non_stop) if (non_stop)
iterate_over_lwps (linux_nat_stop_lwp, &ptid); iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
else else
linux_ops->to_stop (ptid); linux_ops->to_stop (ptid);
} }
static void
linux_nat_close (int quitting)
{
/* Unregister from the event loop. */
if (target_is_async_p ())
target_async (NULL, 0);
/* Reset the async_masking. */
linux_nat_async_mask_value = 1;
if (linux_ops->to_close)
linux_ops->to_close (quitting);
}
void void
linux_nat_add_target (struct target_ops *t) linux_nat_add_target (struct target_ops *t)
{ {
@ -4411,10 +4587,13 @@ linux_nat_add_target (struct target_ops *t)
t->to_async_mask = linux_nat_async_mask; t->to_async_mask = linux_nat_async_mask;
t->to_terminal_inferior = linux_nat_terminal_inferior; t->to_terminal_inferior = linux_nat_terminal_inferior;
t->to_terminal_ours = linux_nat_terminal_ours; t->to_terminal_ours = linux_nat_terminal_ours;
t->to_close = linux_nat_close;
/* Methods for non-stop support. */ /* Methods for non-stop support. */
t->to_stop = linux_nat_stop; t->to_stop = linux_nat_stop;
t->to_supports_multi_process = linux_nat_supports_multi_process;
/* We don't change the stratum; this target will sit at /* We don't change the stratum; this target will sit at
process_stratum and thread_db will set at thread_stratum. This process_stratum and thread_db will set at thread_stratum. This
is a little strange, since this is a multi-threaded-capable is a little strange, since this is a multi-threaded-capable

View file

@ -105,7 +105,8 @@ extern void linux_enable_event_reporting (ptid_t ptid);
extern int lin_lwp_attach_lwp (ptid_t ptid); extern int lin_lwp_attach_lwp (ptid_t ptid);
/* Iterator function for lin-lwp's lwp list. */ /* Iterator function for lin-lwp's lwp list. */
struct lwp_info *iterate_over_lwps (int (*callback) (struct lwp_info *, struct lwp_info *iterate_over_lwps (ptid_t filter,
int (*callback) (struct lwp_info *,
void *), void *),
void *data); void *data);

View file

@ -81,67 +81,146 @@ static char *libthread_db_search_path;
/* This module's target vector. */ /* This module's target vector. */
static struct target_ops thread_db_ops; static struct target_ops thread_db_ops;
/* Handle from dlopen for libthread_db.so. Not NULL if we're using this
module's target vector. */
static void *thread_db_handle;
/* Non-zero if we have determined the signals used by the threads /* Non-zero if we have determined the signals used by the threads
library. */ library. */
static int thread_signals; static int thread_signals;
static sigset_t thread_stop_set; static sigset_t thread_stop_set;
static sigset_t thread_print_set; static sigset_t thread_print_set;
/* Structure that identifies the child process for the struct thread_db_info
<proc_service.h> interface. */ {
static struct ps_prochandle proc_handle; struct thread_db_info *next;
/* Connection to the libthread_db library. */ /* Process id this object refers to. */
static td_thragent_t *thread_agent; int pid;
/* Pointers to the libthread_db functions. */ /* Handle from dlopen for libthread_db.so. */
void *handle;
static td_err_e (*td_init_p) (void); /* Structure that identifies the child process for the
<proc_service.h> interface. */
struct ps_prochandle proc_handle;
static td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, /* Connection to the libthread_db library. */
td_thragent_t *thread_agent;
/* Location of the thread creation event breakpoint. The code at
this location in the child process will be called by the pthread
library whenever a new thread is created. By setting a special
breakpoint at this location, GDB can detect when a new thread is
created. We obtain this location via the td_ta_event_addr
call. */
CORE_ADDR td_create_bp_addr;
/* Location of the thread death event breakpoint. */
CORE_ADDR td_death_bp_addr;
/* Pointers to the libthread_db functions. */
td_err_e (*td_init_p) (void);
td_err_e (*td_ta_new_p) (struct ps_prochandle * ps,
td_thragent_t **ta); td_thragent_t **ta);
static td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt, td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt,
td_thrhandle_t *__th); td_thrhandle_t *__th);
static td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta,
lwpid_t lwpid, td_thrhandle_t *th); lwpid_t lwpid, td_thrhandle_t *th);
static td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta, td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta,
td_thr_iter_f *callback, void *cbdata_p, td_thr_iter_f *callback, void *cbdata_p,
td_thr_state_e state, int ti_pri, td_thr_state_e state, int ti_pri,
sigset_t *ti_sigmask_p, sigset_t *ti_sigmask_p,
unsigned int ti_user_flags); unsigned int ti_user_flags);
static td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta, td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
td_event_e event, td_notify_t *ptr); td_event_e event, td_notify_t *ptr);
static td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta, td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
td_thr_events_t *event); td_thr_events_t *event);
static td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta, td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
td_event_msg_t *msg); td_event_msg_t *msg);
static td_err_e (*td_thr_validate_p) (const td_thrhandle_t *th); td_err_e (*td_thr_validate_p) (const td_thrhandle_t *th);
static td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th, td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
td_thrinfo_t *infop); td_thrinfo_t *infop);
static td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th,
int event); int event);
static td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th, td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
void *map_address, void *map_address,
size_t offset, void **address); size_t offset, void **address);
};
/* Location of the thread creation event breakpoint. The code at this /* List of known processes using thread_db, and the required
location in the child process will be called by the pthread library bookkeeping. */
whenever a new thread is created. By setting a special breakpoint struct thread_db_info *thread_db_list;
at this location, GDB can detect when a new thread is created. We
obtain this location via the td_ta_event_addr call. */
static CORE_ADDR td_create_bp_addr;
/* Location of the thread death event breakpoint. */ static void thread_db_find_new_threads_1 (ptid_t ptid);
static CORE_ADDR td_death_bp_addr;
/* Add the current inferior to the list of processes using libpthread.
Return a pointer to the newly allocated object that was added to
THREAD_DB_LIST. HANDLE is the handle returned by dlopen'ing
LIBTHREAD_DB_SO. */
static struct thread_db_info *
add_thread_db_info (void *handle)
{
int pid;
struct thread_db_info *info;
info = xcalloc (1, sizeof (*info));
info->pid = ptid_get_pid (inferior_ptid);
info->handle = handle;
info->next = thread_db_list;
thread_db_list = info;
return info;
}
/* Return the thread_db_info object representing the bookkeeping
related to process PID, if any; NULL otherwise. */
static struct thread_db_info *
get_thread_db_info (int pid)
{
struct thread_db_info *info;
for (info = thread_db_list; info; info = info->next)
if (pid == info->pid)
return info;
return NULL;
}
/* When PID has exited or has been detached, we no longer want to keep
track of it as using libpthread. Call this function to discard
thread_db related info related to PID. Note that this closes
LIBTHREAD_DB_SO's dlopen'ed handle. */
static void
delete_thread_db_info (int pid)
{
struct thread_db_info *info, *info_prev;
info_prev = NULL;
for (info = thread_db_list; info; info_prev = info, info = info->next)
if (pid == info->pid)
break;
if (info == NULL)
return;
if (info->handle != NULL)
dlclose (info->handle);
if (info_prev)
info_prev->next = info->next;
else
thread_db_list = info->next;
xfree (info);
}
/* Prototypes for local functions. */ /* Prototypes for local functions. */
static void thread_db_find_new_threads_1 (void);
static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
const td_thrinfo_t *ti_p); const td_thrinfo_t *ti_p);
static void detach_thread (ptid_t ptid); static void detach_thread (ptid_t ptid);
@ -232,17 +311,29 @@ thread_db_err_str (td_err_e err)
the threading library is not fully initialized yet. */ the threading library is not fully initialized yet. */
static int static int
have_threads_callback (struct thread_info *thread, void *dummy) have_threads_callback (struct thread_info *thread, void *args)
{ {
int pid = * (int *) args;
if (ptid_get_pid (thread->ptid) != pid)
return 0;
return thread->private != NULL; return thread->private != NULL;
} }
static int static int
have_threads (void) have_threads (ptid_t ptid)
{ {
return iterate_over_threads (have_threads_callback, NULL) != NULL; int pid = ptid_get_pid (ptid);
return iterate_over_threads (have_threads_callback, &pid) != NULL;
} }
struct thread_get_info_inout
{
struct thread_info *thread_info;
struct thread_db_info *thread_db_info;
};
/* A callback function for td_ta_thr_iter, which we use to map all /* A callback function for td_ta_thr_iter, which we use to map all
threads to LWPs. threads to LWPs.
@ -254,45 +345,42 @@ have_threads (void)
zero is returned to indicate success. */ zero is returned to indicate success. */
static int static int
thread_get_info_callback (const td_thrhandle_t *thp, void *infop) thread_get_info_callback (const td_thrhandle_t *thp, void *argp)
{ {
td_thrinfo_t ti; td_thrinfo_t ti;
td_err_e err; td_err_e err;
struct thread_info *thread_info;
ptid_t thread_ptid; ptid_t thread_ptid;
struct thread_get_info_inout *inout;
struct thread_db_info *info;
err = td_thr_get_info_p (thp, &ti); inout = argp;
info = inout->thread_db_info;
err = info->td_thr_get_info_p (thp, &ti);
if (err != TD_OK) if (err != TD_OK)
error (_("thread_get_info_callback: cannot get thread info: %s"), error (_("thread_get_info_callback: cannot get thread info: %s"),
thread_db_err_str (err)); thread_db_err_str (err));
/* Fill the cache. */ /* Fill the cache. */
thread_ptid = ptid_build (GET_PID (proc_handle.ptid), ti.ti_lid, 0); thread_ptid = ptid_build (info->pid, ti.ti_lid, 0);
thread_info = find_thread_pid (thread_ptid); inout->thread_info = find_thread_pid (thread_ptid);
/* In the case of a zombie thread, don't continue. We don't want to /* In the case of a zombie thread, don't continue. We don't want to
attach to it thinking it is a new thread. */ attach to it thinking it is a new thread. */
if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
{ return TD_THR_ZOMBIE;
if (infop != NULL)
*(struct thread_info **) infop = thread_info;
return TD_THR_ZOMBIE;
}
if (thread_info == NULL) if (inout->thread_info == NULL)
{ {
/* New thread. Attach to it now (why wait?). */ /* New thread. Attach to it now (why wait?). */
if (!have_threads ()) if (!have_threads (thread_ptid))
thread_db_find_new_threads_1 (); thread_db_find_new_threads_1 (thread_ptid);
else else
attach_thread (thread_ptid, thp, &ti); attach_thread (thread_ptid, thp, &ti);
thread_info = find_thread_pid (thread_ptid); inout->thread_info = find_thread_pid (thread_ptid);
gdb_assert (thread_info != NULL); gdb_assert (inout->thread_info != NULL);
} }
if (infop != NULL)
*(struct thread_info **) infop = thread_info;
return 0; return 0;
} }
@ -303,22 +391,23 @@ thread_from_lwp (ptid_t ptid)
{ {
td_thrhandle_t th; td_thrhandle_t th;
td_err_e err; td_err_e err;
struct thread_info *thread_info;
ptid_t thread_ptid; ptid_t thread_ptid;
struct thread_db_info *info;
struct thread_get_info_inout io = {0};
/* This ptid comes from linux-nat.c, which should always fill in the /* This ptid comes from linux-nat.c, which should always fill in the
LWP. */ LWP. */
gdb_assert (GET_LWP (ptid) != 0); gdb_assert (GET_LWP (ptid) != 0);
info = get_thread_db_info (GET_PID (ptid));
/* Access an lwp we know is stopped. */ /* Access an lwp we know is stopped. */
proc_handle.ptid = ptid; info->proc_handle.ptid = ptid;
err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th); err = info->td_ta_map_lwp2thr_p (info->thread_agent, GET_LWP (ptid), &th);
if (err != TD_OK) if (err != TD_OK)
error (_("Cannot find user-level thread for LWP %ld: %s"), error (_("Cannot find user-level thread for LWP %ld: %s"),
GET_LWP (ptid), thread_db_err_str (err)); GET_LWP (ptid), thread_db_err_str (err));
thread_info = NULL;
/* Fetch the thread info. If we get back TD_THR_ZOMBIE, then the /* Fetch the thread info. If we get back TD_THR_ZOMBIE, then the
event thread has already died. If another gdb interface has called event thread has already died. If another gdb interface has called
thread_alive() previously, the thread won't be found on the thread list thread_alive() previously, the thread won't be found on the thread list
@ -327,9 +416,11 @@ thread_from_lwp (ptid_t ptid)
discovered thread id that we should add to the list. Thus, discovered thread id that we should add to the list. Thus,
we return a -1 ptid which is also how the thread list marks a we return a -1 ptid which is also how the thread list marks a
dead thread. */ dead thread. */
if (thread_get_info_callback (&th, &thread_info) == TD_THR_ZOMBIE io.thread_db_info = info;
&& thread_info == NULL) io.thread_info = NULL;
return pid_to_ptid (-1); if (thread_get_info_callback (&th, &io) == TD_THR_ZOMBIE
&& io.thread_info == NULL)
return minus_one_ptid;
gdb_assert (ptid_get_tid (ptid) == 0); gdb_assert (ptid_get_tid (ptid) == 0);
return ptid; return ptid;
@ -345,8 +436,11 @@ thread_db_attach_lwp (ptid_t ptid)
td_thrhandle_t th; td_thrhandle_t th;
td_thrinfo_t ti; td_thrinfo_t ti;
td_err_e err; td_err_e err;
struct thread_db_info *info;
if (thread_db_handle == NULL) info = get_thread_db_info (GET_PID (ptid));
if (info == NULL)
return 0; return 0;
/* This ptid comes from linux-nat.c, which should always fill in the /* This ptid comes from linux-nat.c, which should always fill in the
@ -354,20 +448,20 @@ thread_db_attach_lwp (ptid_t ptid)
gdb_assert (GET_LWP (ptid) != 0); gdb_assert (GET_LWP (ptid) != 0);
/* Access an lwp we know is stopped. */ /* Access an lwp we know is stopped. */
proc_handle.ptid = ptid; info->proc_handle.ptid = ptid;
/* If we have only looked at the first thread before libpthread was /* If we have only looked at the first thread before libpthread was
initialized, we may not know its thread ID yet. Make sure we do initialized, we may not know its thread ID yet. Make sure we do
before we add another thread to the list. */ before we add another thread to the list. */
if (!have_threads ()) if (!have_threads (ptid))
thread_db_find_new_threads_1 (); thread_db_find_new_threads_1 (ptid);
err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th); err = info->td_ta_map_lwp2thr_p (info->thread_agent, GET_LWP (ptid), &th);
if (err != TD_OK) if (err != TD_OK)
/* Cannot find user-level thread. */ /* Cannot find user-level thread. */
return 0; return 0;
err = td_thr_get_info_p (&th, &ti); err = info->td_thr_get_info_p (&th, &ti);
if (err != TD_OK) if (err != TD_OK)
{ {
warning (_("Cannot get thread info: %s"), thread_db_err_str (err)); warning (_("Cannot get thread info: %s"), thread_db_err_str (err));
@ -388,16 +482,19 @@ verbose_dlsym (void *handle, const char *name)
} }
static td_err_e static td_err_e
enable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp) enable_thread_event (int event, CORE_ADDR *bp)
{ {
td_notify_t notify; td_notify_t notify;
td_err_e err; td_err_e err;
struct thread_db_info *info;
info = get_thread_db_info (GET_PID (inferior_ptid));
/* Access an lwp we know is stopped. */ /* Access an lwp we know is stopped. */
proc_handle.ptid = inferior_ptid; info->proc_handle.ptid = inferior_ptid;
/* Get the breakpoint address for thread EVENT. */ /* Get the breakpoint address for thread EVENT. */
err = td_ta_event_addr_p (thread_agent, event, &notify); err = info->td_ta_event_addr_p (info->thread_agent, event, &notify);
if (err != TD_OK) if (err != TD_OK)
return err; return err;
@ -425,11 +522,16 @@ enable_thread_event_reporting (void)
const char *libc_version; const char *libc_version;
int libc_major, libc_minor; int libc_major, libc_minor;
#endif #endif
struct thread_db_info *info;
info = get_thread_db_info (GET_PID (inferior_ptid));
/* We cannot use the thread event reporting facility if these /* We cannot use the thread event reporting facility if these
functions aren't available. */ functions aren't available. */
if (td_ta_event_addr_p == NULL || td_ta_set_event_p == NULL if (info->td_ta_event_addr_p == NULL
|| td_ta_event_getmsg_p == NULL || td_thr_event_enable_p == NULL) || info->td_ta_set_event_p == NULL
|| info->td_ta_event_getmsg_p == NULL
|| info->td_thr_event_enable_p == NULL)
return; return;
/* Set the process wide mask saying which events we're interested in. */ /* Set the process wide mask saying which events we're interested in. */
@ -446,7 +548,7 @@ enable_thread_event_reporting (void)
#endif #endif
td_event_addset (&events, TD_DEATH); td_event_addset (&events, TD_DEATH);
err = td_ta_set_event_p (thread_agent, &events); err = info->td_ta_set_event_p (info->thread_agent, &events);
if (err != TD_OK) if (err != TD_OK)
{ {
warning (_("Unable to set global thread event mask: %s"), warning (_("Unable to set global thread event mask: %s"),
@ -456,11 +558,11 @@ enable_thread_event_reporting (void)
/* Delete previous thread event breakpoints, if any. */ /* Delete previous thread event breakpoints, if any. */
remove_thread_event_breakpoints (); remove_thread_event_breakpoints ();
td_create_bp_addr = 0; info->td_create_bp_addr = 0;
td_death_bp_addr = 0; info->td_death_bp_addr = 0;
/* Set up the thread creation event. */ /* Set up the thread creation event. */
err = enable_thread_event (thread_agent, TD_CREATE, &td_create_bp_addr); err = enable_thread_event (TD_CREATE, &info->td_create_bp_addr);
if (err != TD_OK) if (err != TD_OK)
{ {
warning (_("Unable to get location for thread creation breakpoint: %s"), warning (_("Unable to get location for thread creation breakpoint: %s"),
@ -469,7 +571,7 @@ enable_thread_event_reporting (void)
} }
/* Set up the thread death event. */ /* Set up the thread death event. */
err = enable_thread_event (thread_agent, TD_DEATH, &td_death_bp_addr); err = enable_thread_event (TD_DEATH, &info->td_death_bp_addr);
if (err != TD_OK) if (err != TD_OK)
{ {
warning (_("Unable to get location for thread death breakpoint: %s"), warning (_("Unable to get location for thread death breakpoint: %s"),
@ -478,6 +580,20 @@ enable_thread_event_reporting (void)
} }
} }
/* Lookup a library in which given symbol resides.
Note: this is looking in GDB process, not in the inferior.
Returns library name, or NULL. */
static const char *
dladdr_to_soname (const void *addr)
{
Dl_info info;
if (dladdr (addr, &info) != 0)
return info.dli_fname;
return NULL;
}
/* Attempt to initialize dlopen()ed libthread_db, described by HANDLE. /* Attempt to initialize dlopen()ed libthread_db, described by HANDLE.
Return 1 on success. Return 1 on success.
Failure could happen if libthread_db does not have symbols we expect, Failure could happen if libthread_db does not have symbols we expect,
@ -485,36 +601,35 @@ enable_thread_event_reporting (void)
version mismatch between libthread_db and libpthread). */ version mismatch between libthread_db and libpthread). */
static int static int
try_thread_db_load_1 (void *handle) try_thread_db_load_1 (struct thread_db_info *info)
{ {
td_err_e err; td_err_e err;
/* Initialize pointers to the dynamic library functions we will use. /* Initialize pointers to the dynamic library functions we will use.
Essential functions first. */ Essential functions first. */
td_init_p = verbose_dlsym (handle, "td_init"); info->td_init_p = verbose_dlsym (info->handle, "td_init");
if (td_init_p == NULL) if (info->td_init_p == NULL)
return 0; return 0;
err = td_init_p (); err = info->td_init_p ();
if (err != TD_OK) if (err != TD_OK)
{ {
warning (_("Cannot initialize libthread_db: %s"), thread_db_err_str (err)); warning (_("Cannot initialize libthread_db: %s"), thread_db_err_str (err));
return 0; return 0;
} }
td_ta_new_p = verbose_dlsym (handle, "td_ta_new"); info->td_ta_new_p = verbose_dlsym (info->handle, "td_ta_new");
if (td_ta_new_p == NULL) if (info->td_ta_new_p == NULL)
return 0; return 0;
/* Initialize the structure that identifies the child process. */ /* Initialize the structure that identifies the child process. */
proc_handle.ptid = inferior_ptid; info->proc_handle.ptid = inferior_ptid;
/* Now attempt to open a connection to the thread library. */ /* Now attempt to open a connection to the thread library. */
err = td_ta_new_p (&proc_handle, &thread_agent); err = info->td_ta_new_p (&info->proc_handle, &info->thread_agent);
if (err != TD_OK) if (err != TD_OK)
{ {
td_ta_new_p = NULL;
if (info_verbose) if (info_verbose)
printf_unfiltered (_("td_ta_new failed: %s\n"), printf_unfiltered (_("td_ta_new failed: %s\n"),
thread_db_err_str (err)); thread_db_err_str (err));
@ -535,58 +650,57 @@ try_thread_db_load_1 (void *handle)
return 0; return 0;
} }
td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr"); info->td_ta_map_id2thr_p = verbose_dlsym (info->handle, "td_ta_map_id2thr");
if (td_ta_map_id2thr_p == NULL) if (info->td_ta_map_id2thr_p == NULL)
return 0; return 0;
td_ta_map_lwp2thr_p = verbose_dlsym (handle, "td_ta_map_lwp2thr"); info->td_ta_map_lwp2thr_p = verbose_dlsym (info->handle, "td_ta_map_lwp2thr");
if (td_ta_map_lwp2thr_p == NULL) if (info->td_ta_map_lwp2thr_p == NULL)
return 0; return 0;
td_ta_thr_iter_p = verbose_dlsym (handle, "td_ta_thr_iter"); info->td_ta_thr_iter_p = verbose_dlsym (info->handle, "td_ta_thr_iter");
if (td_ta_thr_iter_p == NULL) if (info->td_ta_thr_iter_p == NULL)
return 0; return 0;
td_thr_validate_p = verbose_dlsym (handle, "td_thr_validate"); info->td_thr_validate_p = verbose_dlsym (info->handle, "td_thr_validate");
if (td_thr_validate_p == NULL) if (info->td_thr_validate_p == NULL)
return 0; return 0;
td_thr_get_info_p = verbose_dlsym (handle, "td_thr_get_info"); info->td_thr_get_info_p = verbose_dlsym (info->handle, "td_thr_get_info");
if (td_thr_get_info_p == NULL) if (info->td_thr_get_info_p == NULL)
return 0; return 0;
/* These are not essential. */ /* These are not essential. */
td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"); info->td_ta_event_addr_p = dlsym (info->handle, "td_ta_event_addr");
td_ta_set_event_p = dlsym (handle, "td_ta_set_event"); info->td_ta_set_event_p = dlsym (info->handle, "td_ta_set_event");
td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"); info->td_ta_event_getmsg_p = dlsym (info->handle, "td_ta_event_getmsg");
td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"); info->td_thr_event_enable_p = dlsym (info->handle, "td_thr_event_enable");
td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"); info->td_thr_tls_get_addr_p = dlsym (info->handle, "td_thr_tls_get_addr");
printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n")); printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
/* The thread library was detected. Activate the thread_db target. */ if (info_verbose || *libthread_db_search_path)
push_target (&thread_db_ops); {
thread_db_handle = handle; const char *library;
library = dladdr_to_soname (*info->td_ta_new_p);
if (library == NULL)
library = LIBTHREAD_DB_SO;
printf_unfiltered (_("Using host libthread_db library \"%s\".\n"),
library);
}
/* The thread library was detected. Activate the thread_db target
if this is the first process using it. */
if (thread_db_list->next == NULL)
push_target (&thread_db_ops);
enable_thread_event_reporting (); enable_thread_event_reporting ();
thread_db_find_new_threads_1 (); thread_db_find_new_threads_1 (inferior_ptid);
return 1; return 1;
} }
/* Lookup a library in which given symbol resides.
Note: this is looking in GDB process, not in the inferior.
Returns library name, or NULL. */
static const char *
dladdr_to_soname (const void *addr)
{
Dl_info info;
if (dladdr (addr, &info) != 0)
return info.dli_fname;
return NULL;
}
/* Attempt to use LIBRARY as libthread_db. LIBRARY could be absolute, /* Attempt to use LIBRARY as libthread_db. LIBRARY could be absolute,
relative, or just LIBTHREAD_DB. */ relative, or just LIBTHREAD_DB. */
@ -594,6 +708,7 @@ static int
try_thread_db_load (const char *library) try_thread_db_load (const char *library)
{ {
void *handle; void *handle;
struct thread_db_info *info;
if (info_verbose) if (info_verbose)
printf_unfiltered (_("Trying host libthread_db library: %s.\n"), printf_unfiltered (_("Trying host libthread_db library: %s.\n"),
@ -621,11 +736,13 @@ try_thread_db_load (const char *library)
} }
} }
if (try_thread_db_load_1 (handle)) info = add_thread_db_info (handle);
if (try_thread_db_load_1 (info))
return 1; return 1;
/* This library "refused" to work on current inferior. */ /* This library "refused" to work on current inferior. */
dlclose (handle); delete_thread_db_info (GET_PID (inferior_ptid));
return 0; return 0;
} }
@ -695,8 +812,11 @@ static int
thread_db_load (void) thread_db_load (void)
{ {
struct objfile *obj; struct objfile *obj;
struct thread_db_info *info;
if (thread_db_handle != NULL) info = get_thread_db_info (GET_PID (inferior_ptid));
if (info != NULL)
return 1; return 1;
/* Don't attempt to use thread_db on targets which can not run /* Don't attempt to use thread_db on targets which can not run
@ -754,16 +874,19 @@ static void
disable_thread_event_reporting (void) disable_thread_event_reporting (void)
{ {
td_thr_events_t events; td_thr_events_t events;
struct thread_db_info *info;
info = get_thread_db_info (GET_PID (inferior_ptid));
/* Set the process wide mask saying we aren't interested in any /* Set the process wide mask saying we aren't interested in any
events anymore. */ events anymore. */
td_event_emptyset (&events); td_event_emptyset (&events);
td_ta_set_event_p (thread_agent, &events); info->td_ta_set_event_p (info->thread_agent, &events);
/* Delete thread event breakpoints, if any. */ /* Delete thread event breakpoints, if any. */
remove_thread_event_breakpoints (); remove_thread_event_breakpoints ();
td_create_bp_addr = 0; info->td_create_bp_addr = 0;
td_death_bp_addr = 0; info->td_death_bp_addr = 0;
} }
static void static void
@ -807,35 +930,14 @@ check_for_thread_db (void)
/* Do nothing if we couldn't load libthread_db.so.1. */ /* Do nothing if we couldn't load libthread_db.so.1. */
if (!thread_db_load ()) if (!thread_db_load ())
return; return;
/* First time through, report that libthread_db was successfuly
loaded. Can't print this in in thread_db_load as, at that stage,
the interpreter and it's console haven't started.
We track td_ta_new_p because the user may switch executables,
and as a result we may decide to use a different version of
libthread_db. */
if (last_loaded != td_ta_new_p)
{
last_loaded = td_ta_new_p;
if (info_verbose || *libthread_db_search_path)
{
const char *library;
library = dladdr_to_soname (*td_ta_new_p);
if (library == NULL)
library = LIBTHREAD_DB_SO;
printf_unfiltered (_("Using host libthread_db library \"%s\".\n"),
library);
}
}
} }
static void static void
thread_db_new_objfile (struct objfile *objfile) thread_db_new_objfile (struct objfile *objfile)
{ {
/* This observer must always be called with inferior_ptid set
correctly. */
if (objfile != NULL) if (objfile != NULL)
check_for_thread_db (); check_for_thread_db ();
} }
@ -851,6 +953,7 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
struct private_thread_info *private; struct private_thread_info *private;
struct thread_info *tp = NULL; struct thread_info *tp = NULL;
td_err_e err; td_err_e err;
struct thread_db_info *info;
/* If we're being called after a TD_CREATE event, we may already /* If we're being called after a TD_CREATE event, we may already
know about this thread. There are two ways this can happen. We know about this thread. There are two ways this can happen. We
@ -913,8 +1016,10 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
else else
tp->private = private; tp->private = private;
info = get_thread_db_info (GET_PID (ptid));
/* Enable thread event reporting for this thread. */ /* Enable thread event reporting for this thread. */
err = td_thr_event_enable_p (th_p, 1); err = info->td_thr_event_enable_p (th_p, 1);
if (err != TD_OK) if (err != TD_OK)
error (_("Cannot enable thread event reporting for %s: %s"), error (_("Cannot enable thread event reporting for %s: %s"),
target_pid_to_str (ptid), thread_db_err_str (err)); target_pid_to_str (ptid), thread_db_err_str (err));
@ -942,20 +1047,32 @@ static void
thread_db_detach (struct target_ops *ops, char *args, int from_tty) thread_db_detach (struct target_ops *ops, char *args, int from_tty)
{ {
struct target_ops *target_beneath = find_target_beneath (ops); struct target_ops *target_beneath = find_target_beneath (ops);
struct thread_db_info *info;
disable_thread_event_reporting (); info = get_thread_db_info (GET_PID (inferior_ptid));
/* Forget about the child's process ID. We shouldn't need it if (info)
anymore. */ {
proc_handle.ptid = null_ptid; disable_thread_event_reporting ();
/* Detach thread_db target ops. */ /* Delete the old thread event breakpoints. Note that unlike
unpush_target (&thread_db_ops); when mourning, we can remove them here because there's still
if (thread_db_handle) a live inferior to poke at. In any case, GDB will not try to
dlclose (thread_db_handle); insert anything in the inferior when removing a
thread_db_handle = NULL; breakpoint. */
remove_thread_event_breakpoints ();
delete_thread_db_info (GET_PID (inferior_ptid));
}
target_beneath->to_detach (target_beneath, args, from_tty); target_beneath->to_detach (target_beneath, args, from_tty);
/* NOTE: From this point on, inferior_ptid is null_ptid. */
/* If there are no more processes using libpthread, detach the
thread_db target ops. */
if (!thread_db_list)
unpush_target (&thread_db_ops);
} }
/* Check if PID is currently stopped at the location of a thread event /* Check if PID is currently stopped at the location of a thread event
@ -972,21 +1089,25 @@ check_event (ptid_t ptid)
td_err_e err; td_err_e err;
CORE_ADDR stop_pc; CORE_ADDR stop_pc;
int loop = 0; int loop = 0;
struct thread_db_info *info;
info = get_thread_db_info (GET_PID (ptid));
/* Bail out early if we're not at a thread event breakpoint. */ /* Bail out early if we're not at a thread event breakpoint. */
stop_pc = regcache_read_pc (regcache) stop_pc = regcache_read_pc (regcache)
- gdbarch_decr_pc_after_break (gdbarch); - gdbarch_decr_pc_after_break (gdbarch);
if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr) if (stop_pc != info->td_create_bp_addr
&& stop_pc != info->td_death_bp_addr)
return; return;
/* Access an lwp we know is stopped. */ /* Access an lwp we know is stopped. */
proc_handle.ptid = ptid; info->proc_handle.ptid = ptid;
/* If we have only looked at the first thread before libpthread was /* If we have only looked at the first thread before libpthread was
initialized, we may not know its thread ID yet. Make sure we do initialized, we may not know its thread ID yet. Make sure we do
before we add another thread to the list. */ before we add another thread to the list. */
if (!have_threads ()) if (!have_threads (ptid))
thread_db_find_new_threads_1 (); thread_db_find_new_threads_1 (ptid);
/* If we are at a create breakpoint, we do not know what new lwp /* If we are at a create breakpoint, we do not know what new lwp
was created and cannot specifically locate the event message for it. was created and cannot specifically locate the event message for it.
@ -1006,7 +1127,7 @@ check_event (ptid_t ptid)
do do
{ {
err = td_ta_event_getmsg_p (thread_agent, &msg); err = info->td_ta_event_getmsg_p (info->thread_agent, &msg);
if (err != TD_OK) if (err != TD_OK)
{ {
if (err == TD_NOMSG) if (err == TD_NOMSG)
@ -1016,7 +1137,7 @@ check_event (ptid_t ptid)
thread_db_err_str (err)); thread_db_err_str (err));
} }
err = td_thr_get_info_p (msg.th_p, &ti); err = info->td_thr_get_info_p (msg.th_p, &ti);
if (err != TD_OK) if (err != TD_OK)
error (_("Cannot get thread info: %s"), thread_db_err_str (err)); error (_("Cannot get thread info: %s"), thread_db_err_str (err));
@ -1051,6 +1172,7 @@ static ptid_t
thread_db_wait (struct target_ops *ops, thread_db_wait (struct target_ops *ops,
ptid_t ptid, struct target_waitstatus *ourstatus) ptid_t ptid, struct target_waitstatus *ourstatus)
{ {
struct thread_db_info *info;
struct target_ops *beneath = find_target_beneath (ops); struct target_ops *beneath = find_target_beneath (ops);
ptid = beneath->to_wait (beneath, ptid, ourstatus); ptid = beneath->to_wait (beneath, ptid, ourstatus);
@ -1062,28 +1184,40 @@ thread_db_wait (struct target_ops *ops,
|| ourstatus->kind == TARGET_WAITKIND_SIGNALLED) || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
return ptid; return ptid;
info = get_thread_db_info (GET_PID (ptid));
/* If this process isn't using thread_db, we're done. */
if (info == NULL)
return ptid;
if (ourstatus->kind == TARGET_WAITKIND_EXECD) if (ourstatus->kind == TARGET_WAITKIND_EXECD)
{ {
/* Breakpoints have already been marked non-inserted by the
layer below. We're safe in knowing that removing them will
not write the shadows of the old image into the new
image. */
remove_thread_event_breakpoints (); remove_thread_event_breakpoints ();
unpush_target (&thread_db_ops);
if (thread_db_handle) /* New image, it may or may not end up using thread_db. Assume
dlclose (thread_db_handle); not unless we find otherwise. */
thread_db_handle = NULL; delete_thread_db_info (GET_PID (ptid));
if (!thread_db_list)
unpush_target (&thread_db_ops);
return ptid; return ptid;
} }
/* If we do not know about the main thread yet, this would be a good time to /* If we do not know about the main thread yet, this would be a good time to
find it. */ find it. */
if (ourstatus->kind == TARGET_WAITKIND_STOPPED && !have_threads ()) if (ourstatus->kind == TARGET_WAITKIND_STOPPED && !have_threads (ptid))
thread_db_find_new_threads_1 (); thread_db_find_new_threads_1 (ptid);
if (ourstatus->kind == TARGET_WAITKIND_STOPPED if (ourstatus->kind == TARGET_WAITKIND_STOPPED
&& ourstatus->value.sig == TARGET_SIGNAL_TRAP) && ourstatus->value.sig == TARGET_SIGNAL_TRAP)
/* Check for a thread event. */ /* Check for a thread event. */
check_event (ptid); check_event (ptid);
if (have_threads ()) if (have_threads (ptid))
{ {
/* Change ptids back into the higher level PID + TID format. If /* Change ptids back into the higher level PID + TID format. If
the thread is dead and no longer on the thread list, we will the thread is dead and no longer on the thread list, we will
@ -1104,21 +1238,18 @@ thread_db_mourn_inferior (struct target_ops *ops)
{ {
struct target_ops *target_beneath = find_target_beneath (ops); struct target_ops *target_beneath = find_target_beneath (ops);
/* Forget about the child's process ID. We shouldn't need it delete_thread_db_info (GET_PID (inferior_ptid));
anymore. */
proc_handle.ptid = null_ptid; /* Delete the old thread event breakpoints. Mark breakpoints out,
so that we don't try to un-insert them. */
mark_breakpoints_out ();
remove_thread_event_breakpoints ();
target_beneath->to_mourn_inferior (target_beneath); target_beneath->to_mourn_inferior (target_beneath);
/* Delete the old thread event breakpoints. Do this after mourning
the inferior, so that we don't try to uninsert them. */
remove_thread_event_breakpoints ();
/* Detach thread_db target ops. */ /* Detach thread_db target ops. */
unpush_target (ops); if (!thread_db_list)
if (thread_db_handle) unpush_target (ops);
dlclose (thread_db_handle);
thread_db_handle = NULL;
} }
static int static int
@ -1128,8 +1259,9 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
td_err_e err; td_err_e err;
ptid_t ptid; ptid_t ptid;
struct thread_info *tp; struct thread_info *tp;
struct thread_db_info *info = data;
err = td_thr_get_info_p (th_p, &ti); err = info->td_thr_get_info_p (th_p, &ti);
if (err != TD_OK) if (err != TD_OK)
error (_("find_new_threads_callback: cannot get thread info: %s"), error (_("find_new_threads_callback: cannot get thread info: %s"),
thread_db_err_str (err)); thread_db_err_str (err));
@ -1137,7 +1269,7 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
return 0; /* A zombie -- ignore. */ return 0; /* A zombie -- ignore. */
ptid = ptid_build (GET_PID (proc_handle.ptid), ti.ti_lid, 0); ptid = ptid_build (info->pid, ti.ti_lid, 0);
if (ti.ti_tid == 0) if (ti.ti_tid == 0)
{ {
@ -1147,7 +1279,7 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
be yet. Just enable event reporting and otherwise ignore be yet. Just enable event reporting and otherwise ignore
it. */ it. */
err = td_thr_event_enable_p (th_p, 1); err = info->td_thr_event_enable_p (th_p, 1);
if (err != TD_OK) if (err != TD_OK)
error (_("Cannot enable thread event reporting for %s: %s"), error (_("Cannot enable thread event reporting for %s: %s"),
target_pid_to_str (ptid), thread_db_err_str (err)); target_pid_to_str (ptid), thread_db_err_str (err));
@ -1166,27 +1298,30 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
PTID. */ PTID. */
static void static void
thread_db_find_new_threads_1 (void) thread_db_find_new_threads_1 (ptid_t ptid)
{ {
td_err_e err; td_err_e err;
struct lwp_info *lp; struct lwp_info *lp;
ptid_t ptid; struct thread_db_info *info;
int pid = ptid_get_pid (ptid);
/* In linux, we can only read memory through a stopped lwp. */ /* In linux, we can only read memory through a stopped lwp. */
ALL_LWPS (lp, ptid) ALL_LWPS (lp, ptid)
if (lp->stopped) if (lp->stopped && ptid_get_pid (lp->ptid) == pid)
break; break;
if (!lp) if (!lp)
/* There is no stopped thread. Bail out. */ /* There is no stopped thread. Bail out. */
return; return;
info = get_thread_db_info (GET_PID (ptid));
/* Access an lwp we know is stopped. */ /* Access an lwp we know is stopped. */
proc_handle.ptid = ptid; info->proc_handle.ptid = ptid;
/* Iterate over all user-space threads to discover new threads. */ /* Iterate over all user-space threads to discover new threads. */
err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, NULL, err = info->td_ta_thr_iter_p (info->thread_agent, find_new_threads_callback,
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, info, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
if (err != TD_OK) if (err != TD_OK)
error (_("Cannot find new threads: %s"), thread_db_err_str (err)); error (_("Cannot find new threads: %s"), thread_db_err_str (err));
} }
@ -1194,7 +1329,14 @@ thread_db_find_new_threads_1 (void)
static void static void
thread_db_find_new_threads (struct target_ops *ops) thread_db_find_new_threads (struct target_ops *ops)
{ {
thread_db_find_new_threads_1 (); struct thread_db_info *info;
info = get_thread_db_info (GET_PID (inferior_ptid));
if (info == NULL)
return;
thread_db_find_new_threads_1 (inferior_ptid);
} }
static char * static char *
@ -1250,8 +1392,8 @@ thread_db_get_thread_local_address (struct target_ops *ops,
struct target_ops *beneath; struct target_ops *beneath;
/* If we have not discovered any threads yet, check now. */ /* If we have not discovered any threads yet, check now. */
if (!have_threads ()) if (!have_threads (ptid))
thread_db_find_new_threads_1 (); thread_db_find_new_threads_1 (ptid);
/* Find the matching thread. */ /* Find the matching thread. */
thread_info = find_thread_pid (ptid); thread_info = find_thread_pid (ptid);
@ -1260,9 +1402,12 @@ thread_db_get_thread_local_address (struct target_ops *ops,
{ {
td_err_e err; td_err_e err;
void *address; void *address;
struct thread_db_info *info;
info = get_thread_db_info (GET_PID (ptid));
/* glibc doesn't provide the needed interface. */ /* glibc doesn't provide the needed interface. */
if (!td_thr_tls_get_addr_p) if (!info->td_thr_tls_get_addr_p)
throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR, throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
_("No TLS library support")); _("No TLS library support"));
@ -1270,9 +1415,9 @@ thread_db_get_thread_local_address (struct target_ops *ops,
gdb_assert (lm != 0); gdb_assert (lm != 0);
/* Finally, get the address of the variable. */ /* Finally, get the address of the variable. */
err = td_thr_tls_get_addr_p (&thread_info->private->th, err = info->td_thr_tls_get_addr_p (&thread_info->private->th,
(void *)(size_t) lm, (void *)(size_t) lm,
offset, &address); offset, &address);
#ifdef THREAD_DB_HAS_TD_NOTALLOC #ifdef THREAD_DB_HAS_TD_NOTALLOC
/* The memory hasn't been allocated, yet. */ /* The memory hasn't been allocated, yet. */
@ -1326,7 +1471,7 @@ thread_db_get_ada_task_ptid (long lwp, long thread)
{ {
struct thread_info *thread_info; struct thread_info *thread_info;
thread_db_find_new_threads_1 (); thread_db_find_new_threads_1 (inferior_ptid);
thread_info = iterate_over_threads (thread_db_find_thread_from_tid, &thread); thread_info = iterate_over_threads (thread_db_find_thread_from_tid, &thread);
gdb_assert (thread_info != NULL); gdb_assert (thread_info != NULL);

View file

@ -389,6 +389,31 @@ mi_about_to_proceed (void)
mi_proceeded = 1; mi_proceeded = 1;
} }
static int
mi_output_running_pid (struct thread_info *info, void *arg)
{
ptid_t *ptid = arg;
if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid))
fprintf_unfiltered (raw_stdout,
"*running,thread-id=\"%d\"\n",
info->num);
return 0;
}
static int
mi_inferior_count (struct inferior *inf, void *arg)
{
if (inf->pid != 0)
{
int *count_p = arg;
(*count_p)++;
}
return 0;
}
static void static void
mi_on_resume (ptid_t ptid) mi_on_resume (ptid_t ptid)
{ {
@ -420,11 +445,19 @@ mi_on_resume (ptid_t ptid)
if (PIDGET (ptid) == -1) if (PIDGET (ptid) == -1)
fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n"); fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n");
else if (thread_count () == 0) else if (ptid_is_pid (ptid))
{ {
/* This is a target where for single-threaded programs the thread int count;
table has zero threads. Don't print any thread-id field. */
fprintf_unfiltered (raw_stdout, "*running\n"); /* Backwards compatibility. If there's only one inferior,
output "all", otherwise, output each resumed thread
individually. */
iterate_over_inferiors (mi_inferior_count, &count);
if (count == 1)
fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n");
else
iterate_over_threads (mi_output_running_pid, &ptid);
} }
else else
{ {

View file

@ -509,21 +509,23 @@ void
set_running (ptid_t ptid, int running) set_running (ptid_t ptid, int running)
{ {
struct thread_info *tp; struct thread_info *tp;
int all = ptid_equal (ptid, minus_one_ptid);
/* We try not to notify the observer if no thread has actually changed /* We try not to notify the observer if no thread has actually changed
the running state -- merely to reduce the number of messages to the running state -- merely to reduce the number of messages to
frontend. Frontend is supposed to handle multiple *running just fine. */ frontend. Frontend is supposed to handle multiple *running just fine. */
if (PIDGET (ptid) == -1) if (all || ptid_is_pid (ptid))
{ {
int any_started = 0; int any_started = 0;
for (tp = thread_list; tp; tp = tp->next) for (tp = thread_list; tp; tp = tp->next)
{ if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
if (tp->state_ == THREAD_EXITED) {
continue; if (tp->state_ == THREAD_EXITED)
if (running && tp->state_ == THREAD_STOPPED) continue;
any_started = 1; if (running && tp->state_ == THREAD_STOPPED)
tp->state_ = running ? THREAD_RUNNING : THREAD_STOPPED; any_started = 1;
} tp->state_ = running ? THREAD_RUNNING : THREAD_STOPPED;
}
if (any_started) if (any_started)
observer_notify_target_resumed (ptid); observer_notify_target_resumed (ptid);
} }
@ -616,11 +618,13 @@ void
set_executing (ptid_t ptid, int executing) set_executing (ptid_t ptid, int executing)
{ {
struct thread_info *tp; struct thread_info *tp;
int all = ptid_equal (ptid, minus_one_ptid);
if (PIDGET (ptid) == -1) if (all || ptid_is_pid (ptid))
{ {
for (tp = thread_list; tp; tp = tp->next) for (tp = thread_list; tp; tp = tp->next)
tp->executing_ = executing; if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
tp->executing_ = executing;
} }
else else
{ {