* 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:
parent
dddfab26ac
commit
d90e17a74d
8 changed files with 854 additions and 381 deletions
109
gdb/ChangeLog
109
gdb/ChangeLog
|
@ -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>
|
||||
|
||||
* ada-lang.c (ada_find_any_type): Move check for primitive types ...
|
||||
|
|
|
@ -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. */
|
||||
environ = save_our_env;
|
||||
|
||||
init_thread_list ();
|
||||
if (!have_inferiors ())
|
||||
init_thread_list ();
|
||||
|
||||
add_inferior (pid);
|
||||
|
||||
|
@ -424,6 +425,12 @@ startup_inferior (int ntraps)
|
|||
{
|
||||
int pending_execs = ntraps;
|
||||
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
|
||||
have stopped one instruction after execing the shell. Here we
|
||||
|
@ -435,12 +442,11 @@ startup_inferior (int ntraps)
|
|||
while (1)
|
||||
{
|
||||
int resume_signal = TARGET_SIGNAL_0;
|
||||
ptid_t resume_ptid;
|
||||
ptid_t event_ptid;
|
||||
|
||||
struct target_waitstatus 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)
|
||||
/* The inferior didn't really stop, keep waiting. */
|
||||
|
@ -489,12 +495,6 @@ startup_inferior (int ntraps)
|
|||
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)
|
||||
{
|
||||
/* Let shell child handle its own signals in its own way. */
|
||||
|
@ -529,7 +529,7 @@ startup_inferior (int ntraps)
|
|||
}
|
||||
|
||||
/* Mark all threads non-executing. */
|
||||
set_executing (pid_to_ptid (-1), 0);
|
||||
set_executing (resume_ptid, 0);
|
||||
}
|
||||
|
||||
/* Implement the "unset exec-wrapper" command. */
|
||||
|
|
|
@ -199,8 +199,10 @@ inf_ptrace_mourn_inferior (struct target_ops *ops)
|
|||
only report its exit status to its original parent. */
|
||||
waitpid (ptid_get_pid (inferior_ptid), &status, 0);
|
||||
|
||||
unpush_target (ops);
|
||||
generic_mourn_inferior ();
|
||||
|
||||
if (!have_inferiors ())
|
||||
unpush_target (ops);
|
||||
}
|
||||
|
||||
/* Attach to the process specified by ARGS. If FROM_TTY is non-zero,
|
||||
|
|
463
gdb/linux-nat.c
463
gdb/linux-nat.c
|
@ -841,9 +841,6 @@ linux_child_insert_exec_catchpoint (int pid)
|
|||
|
||||
/* List of known LWPs. */
|
||||
struct lwp_info *lwp_list;
|
||||
|
||||
/* Number of LWPs in the list. */
|
||||
static int num_lwps;
|
||||
|
||||
|
||||
/* Original signal mask. */
|
||||
|
@ -926,7 +923,48 @@ init_lwp_list (void)
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -950,9 +988,8 @@ add_lwp (ptid_t ptid)
|
|||
|
||||
lp->next = lwp_list;
|
||||
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);
|
||||
|
||||
return lp;
|
||||
|
@ -974,8 +1011,6 @@ delete_lwp (ptid_t ptid)
|
|||
if (!lp)
|
||||
return;
|
||||
|
||||
num_lwps--;
|
||||
|
||||
if (lpprev)
|
||||
lpprev->next = lp->next;
|
||||
else
|
||||
|
@ -1005,21 +1040,54 @@ find_lwp_pid (ptid_t ptid)
|
|||
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
|
||||
the list. If CALLBACK returns 1 for a particular LWP, return a
|
||||
pointer to the structure describing that LWP immediately.
|
||||
Otherwise return NULL. */
|
||||
|
||||
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;
|
||||
|
||||
for (lp = lwp_list; lp; lp = lpnext)
|
||||
{
|
||||
lpnext = lp->next;
|
||||
if ((*callback) (lp, data))
|
||||
return lp;
|
||||
|
||||
if (ptid_match (lp->ptid, filter))
|
||||
{
|
||||
if ((*callback) (lp, data))
|
||||
return lp;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -1296,8 +1364,6 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
|
|||
int status;
|
||||
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);
|
||||
|
||||
/* 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 status;
|
||||
enum target_signal sig;
|
||||
struct lwp_info *main_lwp;
|
||||
|
||||
pid = GET_PID (inferior_ptid);
|
||||
|
||||
if (target_can_async_p ())
|
||||
linux_nat_async (NULL, 0);
|
||||
|
||||
/* Stop all threads before detaching. ptrace requires that the
|
||||
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
|
||||
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. */
|
||||
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. */
|
||||
if ((args == NULL || *args == '\0')
|
||||
&& get_pending_status (lwp_list, &status) != -1
|
||||
&& get_pending_status (main_lwp, &status) != -1
|
||||
&& WIFSTOPPED (status))
|
||||
{
|
||||
/* 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,
|
||||
"LND: Sending signal %s to %s\n",
|
||||
args,
|
||||
target_pid_to_str (lwp_list->ptid));
|
||||
target_pid_to_str (main_lwp->ptid));
|
||||
}
|
||||
|
||||
/* Destroy LWP info; it's no longer valid. */
|
||||
init_lwp_list ();
|
||||
|
||||
pid = ptid_get_pid (inferior_ptid);
|
||||
delete_lwp (main_lwp->ptid);
|
||||
|
||||
if (forks_exist_p ())
|
||||
{
|
||||
|
@ -1515,6 +1583,11 @@ resume_callback (struct lwp_info *lp, void *data)
|
|||
{
|
||||
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,
|
||||
pid_to_ptid (GET_LWP (lp->ptid)),
|
||||
0, TARGET_SIGNAL_0);
|
||||
|
@ -1556,7 +1629,7 @@ linux_nat_resume (struct target_ops *ops,
|
|||
{
|
||||
sigset_t prev_mask;
|
||||
struct lwp_info *lp;
|
||||
int resume_all;
|
||||
int resume_many;
|
||||
|
||||
if (debug_linux_nat)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
|
@ -1569,37 +1642,29 @@ linux_nat_resume (struct target_ops *ops,
|
|||
block_child_signals (&prev_mask);
|
||||
|
||||
/* A specific PTID means `step only this process id'. */
|
||||
resume_all = (PIDGET (ptid) == -1);
|
||||
|
||||
if (non_stop && resume_all)
|
||||
internal_error (__FILE__, __LINE__,
|
||||
"can't resume all in non-stop mode");
|
||||
resume_many = (ptid_equal (minus_one_ptid, ptid)
|
||||
|| ptid_is_pid (ptid));
|
||||
|
||||
if (!non_stop)
|
||||
{
|
||||
if (resume_all)
|
||||
iterate_over_lwps (resume_set_callback, NULL);
|
||||
else
|
||||
iterate_over_lwps (resume_clear_callback, NULL);
|
||||
/* Mark the lwps we're resuming as resumed. */
|
||||
iterate_over_lwps (minus_one_ptid, resume_clear_callback, NULL);
|
||||
iterate_over_lwps (ptid, resume_set_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
|
||||
handled specially. */
|
||||
if (PIDGET (ptid) == -1)
|
||||
ptid = inferior_ptid;
|
||||
|
||||
lp = find_lwp_pid (ptid);
|
||||
/* See if it's the current inferior that should be handled
|
||||
specially. */
|
||||
if (resume_many)
|
||||
lp = find_lwp_pid (inferior_ptid);
|
||||
else
|
||||
lp = find_lwp_pid (ptid);
|
||||
gdb_assert (lp != NULL);
|
||||
|
||||
/* Convert to something the lower layer understands. */
|
||||
ptid = pid_to_ptid (GET_LWP (lp->ptid));
|
||||
|
||||
/* Remember if we're stepping. */
|
||||
lp->step = step;
|
||||
|
||||
/* Mark this LWP as resumed. */
|
||||
lp->resumed = 1;
|
||||
|
||||
/* If we have a pending wait status for this thread, there is no
|
||||
point in resuming the process. But first make sure that
|
||||
linux_nat_wait won't preemptively handle the event - we
|
||||
|
@ -1613,7 +1678,7 @@ linux_nat_resume (struct target_ops *ops,
|
|||
int saved_signo;
|
||||
struct inferior *inf;
|
||||
|
||||
inf = find_inferior_pid (ptid_get_pid (ptid));
|
||||
inf = find_inferior_pid (ptid_get_pid (lp->ptid));
|
||||
gdb_assert (inf);
|
||||
saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
|
||||
|
||||
|
@ -1662,8 +1727,11 @@ linux_nat_resume (struct target_ops *ops,
|
|||
resume_callback. */
|
||||
lp->stopped = 0;
|
||||
|
||||
if (resume_all)
|
||||
iterate_over_lwps (resume_callback, NULL);
|
||||
if (resume_many)
|
||||
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);
|
||||
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;
|
||||
|
||||
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->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
|
||||
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. */
|
||||
|
@ -2303,7 +2376,7 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
|
|||
/* Select one LWP out of those that have events pending. */
|
||||
|
||||
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 random_selector;
|
||||
|
@ -2313,7 +2386,8 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
|
|||
(*orig_lp)->status = *status;
|
||||
|
||||
/* 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 (debug_linux_nat)
|
||||
|
@ -2327,7 +2401,7 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
|
|||
which have had SIGTRAP events. */
|
||||
|
||||
/* 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. */
|
||||
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",
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2456,7 +2531,8 @@ linux_nat_filter_event (int lwpid, int status, int options)
|
|||
}
|
||||
|
||||
/* 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 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))
|
||||
{
|
||||
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)
|
||||
|
@ -2479,7 +2556,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
|
|||
"LLW: %s exited.\n",
|
||||
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
|
||||
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
|
||||
signals when they exit so we must check whenever the thread has
|
||||
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)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"LLW: %s exited.\n",
|
||||
|
@ -2503,7 +2582,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
|
|||
exit_lwp (lp);
|
||||
|
||||
/* 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. */
|
||||
return NULL;
|
||||
|
@ -2583,7 +2662,7 @@ linux_nat_wait_1 (struct target_ops *ops,
|
|||
struct lwp_info *lp = NULL;
|
||||
int options = 0;
|
||||
int status = 0;
|
||||
pid_t pid = PIDGET (ptid);
|
||||
pid_t pid;
|
||||
|
||||
if (debug_linux_nat_async)
|
||||
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
|
||||
not have added it to the LWP list yet - this is the earliest
|
||||
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. */
|
||||
thread_change_ptid (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. */
|
||||
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:
|
||||
lp = NULL;
|
||||
status = 0;
|
||||
|
||||
/* 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. */
|
||||
if (pid == -1)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
status = lp->status;
|
||||
|
@ -2658,9 +2748,16 @@ retry:
|
|||
the layer beneath us can understand. */
|
||||
options = lp->cloned ? __WCLONE : 0;
|
||||
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
|
||||
events. In a typical case where interference is a problem,
|
||||
|
@ -2697,7 +2794,7 @@ retry:
|
|||
if (target_can_async_p ())
|
||||
options |= WNOHANG; /* In async mode, don't block. */
|
||||
|
||||
while (status == 0)
|
||||
while (lp == NULL)
|
||||
{
|
||||
pid_t lwpid;
|
||||
|
||||
|
@ -2715,14 +2812,79 @@ retry:
|
|||
}
|
||||
|
||||
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. */
|
||||
status = 0;
|
||||
if (debug_linux_nat)
|
||||
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;
|
||||
}
|
||||
|
||||
break;
|
||||
if (lp)
|
||||
break;
|
||||
else
|
||||
{
|
||||
if (pid == -1)
|
||||
{
|
||||
/* waitpid did return something. Restart over. */
|
||||
options |= __WCLONE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (pid == -1)
|
||||
|
@ -2752,7 +2914,7 @@ retry:
|
|||
}
|
||||
|
||||
/* 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 ())
|
||||
|
@ -2801,7 +2963,6 @@ retry:
|
|||
target_pid_to_str (lp->ptid),
|
||||
signo ? strsignal (signo) : "0");
|
||||
lp->stopped = 0;
|
||||
status = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
@ -2817,7 +2978,8 @@ retry:
|
|||
will receive it - unless they're using CLONE_THREAD to
|
||||
share signals. Since we only want to report it once, we
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
@ -2835,24 +2997,24 @@ retry:
|
|||
if (!non_stop)
|
||||
{
|
||||
/* 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
|
||||
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
|
||||
from among those that have had events. Giving equal priority
|
||||
to all LWPs that have had events helps prevent
|
||||
starvation. */
|
||||
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
|
||||
breakpoints in other LWPs that have hit a GDB breakpoint. See
|
||||
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)
|
||||
{
|
||||
|
@ -3000,18 +3162,19 @@ linux_nat_kill (struct target_ops *ops)
|
|||
linux_fork_killall ();
|
||||
else
|
||||
{
|
||||
ptid_t ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
|
||||
/* Stop all threads before killing them, since ptrace requires
|
||||
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
|
||||
they're no longer running. */
|
||||
iterate_over_lwps (stop_wait_callback, NULL);
|
||||
iterate_over_lwps (ptid, stop_wait_callback, NULL);
|
||||
|
||||
/* 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. */
|
||||
iterate_over_lwps (kill_wait_callback, NULL);
|
||||
iterate_over_lwps (ptid, kill_wait_callback, NULL);
|
||||
}
|
||||
|
||||
target_mourn_inferior ();
|
||||
|
@ -3020,17 +3183,11 @@ linux_nat_kill (struct target_ops *ops)
|
|||
static void
|
||||
linux_nat_mourn_inferior (struct target_ops *ops)
|
||||
{
|
||||
/* Destroy LWP info; it's no longer valid. */
|
||||
init_lwp_list ();
|
||||
purge_lwp_list (ptid_get_pid (inferior_ptid));
|
||||
|
||||
if (! forks_exist_p ())
|
||||
{
|
||||
/* Normal case, no other forks available. */
|
||||
linux_ops->to_mourn_inferior (ops);
|
||||
|
||||
if (target_can_async_p ())
|
||||
linux_nat_async (NULL, 0);
|
||||
}
|
||||
/* Normal case, no other forks available. */
|
||||
linux_ops->to_mourn_inferior (ops);
|
||||
else
|
||||
/* Multi-fork case. The current inferior_ptid has exited, but
|
||||
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];
|
||||
|
||||
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));
|
||||
return buf;
|
||||
|
@ -3450,6 +3607,7 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
|
|||
char psargs[80] = { '\0' };
|
||||
char *note_data = NULL;
|
||||
ptid_t current_ptid = inferior_ptid;
|
||||
ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
|
||||
gdb_byte *auxv;
|
||||
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.num_notes = 0;
|
||||
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);
|
||||
note_data = thread_args.note_data;
|
||||
|
||||
|
@ -4096,7 +4254,8 @@ linux_nat_is_async_p (void)
|
|||
if (!target_async_permitted)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
/* See target.h/target_async_mask. */
|
||||
return linux_nat_async_mask_value;
|
||||
}
|
||||
|
||||
/* target_can_async_p implementation. */
|
||||
|
@ -4120,6 +4279,17 @@ linux_nat_supports_non_stop (void)
|
|||
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. */
|
||||
|
||||
static int
|
||||
|
@ -4317,56 +4487,48 @@ linux_nat_async (void (*callback) (enum inferior_event_type event_type,
|
|||
static int
|
||||
linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
|
||||
{
|
||||
ptid_t ptid = * (ptid_t *) data;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (find_thread_pid (lwp->ptid)->stop_requested)
|
||||
fprintf_unfiltered (gdb_stdlog, "\
|
||||
if (find_thread_pid (lwp->ptid)->stop_requested)
|
||||
fprintf_unfiltered (gdb_stdlog, "\
|
||||
LNSL: already stopped/stop_requested %s\n",
|
||||
target_pid_to_str (lwp->ptid));
|
||||
else
|
||||
fprintf_unfiltered (gdb_stdlog, "\
|
||||
target_pid_to_str (lwp->ptid));
|
||||
else
|
||||
fprintf_unfiltered (gdb_stdlog, "\
|
||||
LNSL: already stopped/no stop_requested yet %s\n",
|
||||
target_pid_to_str (lwp->ptid));
|
||||
}
|
||||
target_pid_to_str (lwp->ptid));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -4376,11 +4538,25 @@ static void
|
|||
linux_nat_stop (ptid_t ptid)
|
||||
{
|
||||
if (non_stop)
|
||||
iterate_over_lwps (linux_nat_stop_lwp, &ptid);
|
||||
iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
|
||||
else
|
||||
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
|
||||
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_terminal_inferior = linux_nat_terminal_inferior;
|
||||
t->to_terminal_ours = linux_nat_terminal_ours;
|
||||
t->to_close = linux_nat_close;
|
||||
|
||||
/* Methods for non-stop support. */
|
||||
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
|
||||
process_stratum and thread_db will set at thread_stratum. This
|
||||
is a little strange, since this is a multi-threaded-capable
|
||||
|
|
|
@ -105,7 +105,8 @@ extern void linux_enable_event_reporting (ptid_t ptid);
|
|||
extern int lin_lwp_attach_lwp (ptid_t ptid);
|
||||
|
||||
/* 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 *data);
|
||||
|
||||
|
|
|
@ -81,67 +81,146 @@ static char *libthread_db_search_path;
|
|||
/* This module's target vector. */
|
||||
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
|
||||
library. */
|
||||
static int thread_signals;
|
||||
static sigset_t thread_stop_set;
|
||||
static sigset_t thread_print_set;
|
||||
|
||||
/* Structure that identifies the child process for the
|
||||
<proc_service.h> interface. */
|
||||
static struct ps_prochandle proc_handle;
|
||||
struct thread_db_info
|
||||
{
|
||||
struct thread_db_info *next;
|
||||
|
||||
/* Connection to the libthread_db library. */
|
||||
static td_thragent_t *thread_agent;
|
||||
/* Process id this object refers to. */
|
||||
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);
|
||||
static td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt,
|
||||
td_thrhandle_t *__th);
|
||||
static td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta,
|
||||
lwpid_t lwpid, td_thrhandle_t *th);
|
||||
static td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta,
|
||||
td_thr_iter_f *callback, void *cbdata_p,
|
||||
td_thr_state_e state, int ti_pri,
|
||||
sigset_t *ti_sigmask_p,
|
||||
unsigned int ti_user_flags);
|
||||
static td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
|
||||
td_event_e event, td_notify_t *ptr);
|
||||
static td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
|
||||
td_thr_events_t *event);
|
||||
static td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
|
||||
td_event_msg_t *msg);
|
||||
td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt,
|
||||
td_thrhandle_t *__th);
|
||||
td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta,
|
||||
lwpid_t lwpid, td_thrhandle_t *th);
|
||||
td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta,
|
||||
td_thr_iter_f *callback, void *cbdata_p,
|
||||
td_thr_state_e state, int ti_pri,
|
||||
sigset_t *ti_sigmask_p,
|
||||
unsigned int ti_user_flags);
|
||||
td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
|
||||
td_event_e event, td_notify_t *ptr);
|
||||
td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
|
||||
td_thr_events_t *event);
|
||||
td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
|
||||
td_event_msg_t *msg);
|
||||
|
||||
static 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_thrinfo_t *infop);
|
||||
static td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th,
|
||||
int event);
|
||||
td_err_e (*td_thr_validate_p) (const td_thrhandle_t *th);
|
||||
td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
|
||||
td_thrinfo_t *infop);
|
||||
td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th,
|
||||
int event);
|
||||
|
||||
static td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
|
||||
void *map_address,
|
||||
size_t offset, void **address);
|
||||
td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
|
||||
void *map_address,
|
||||
size_t offset, void **address);
|
||||
};
|
||||
|
||||
/* 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. */
|
||||
static CORE_ADDR td_create_bp_addr;
|
||||
/* List of known processes using thread_db, and the required
|
||||
bookkeeping. */
|
||||
struct thread_db_info *thread_db_list;
|
||||
|
||||
/* Location of the thread death event breakpoint. */
|
||||
static CORE_ADDR td_death_bp_addr;
|
||||
static void thread_db_find_new_threads_1 (ptid_t ptid);
|
||||
|
||||
/* 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. */
|
||||
static void thread_db_find_new_threads_1 (void);
|
||||
static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||
const td_thrinfo_t *ti_p);
|
||||
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. */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
threads to LWPs.
|
||||
|
||||
|
@ -254,45 +345,42 @@ have_threads (void)
|
|||
zero is returned to indicate success. */
|
||||
|
||||
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_err_e err;
|
||||
struct thread_info *thread_info;
|
||||
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)
|
||||
error (_("thread_get_info_callback: cannot get thread info: %s"),
|
||||
thread_db_err_str (err));
|
||||
|
||||
/* Fill the cache. */
|
||||
thread_ptid = ptid_build (GET_PID (proc_handle.ptid), ti.ti_lid, 0);
|
||||
thread_info = find_thread_pid (thread_ptid);
|
||||
thread_ptid = ptid_build (info->pid, ti.ti_lid, 0);
|
||||
inout->thread_info = find_thread_pid (thread_ptid);
|
||||
|
||||
/* In the case of a zombie thread, don't continue. We don't want to
|
||||
attach to it thinking it is a new thread. */
|
||||
if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
|
||||
{
|
||||
if (infop != NULL)
|
||||
*(struct thread_info **) infop = thread_info;
|
||||
return TD_THR_ZOMBIE;
|
||||
}
|
||||
return TD_THR_ZOMBIE;
|
||||
|
||||
if (thread_info == NULL)
|
||||
if (inout->thread_info == NULL)
|
||||
{
|
||||
/* New thread. Attach to it now (why wait?). */
|
||||
if (!have_threads ())
|
||||
thread_db_find_new_threads_1 ();
|
||||
if (!have_threads (thread_ptid))
|
||||
thread_db_find_new_threads_1 (thread_ptid);
|
||||
else
|
||||
attach_thread (thread_ptid, thp, &ti);
|
||||
thread_info = find_thread_pid (thread_ptid);
|
||||
gdb_assert (thread_info != NULL);
|
||||
inout->thread_info = find_thread_pid (thread_ptid);
|
||||
gdb_assert (inout->thread_info != NULL);
|
||||
}
|
||||
|
||||
if (infop != NULL)
|
||||
*(struct thread_info **) infop = thread_info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -303,22 +391,23 @@ thread_from_lwp (ptid_t ptid)
|
|||
{
|
||||
td_thrhandle_t th;
|
||||
td_err_e err;
|
||||
struct thread_info *thread_info;
|
||||
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
|
||||
LWP. */
|
||||
gdb_assert (GET_LWP (ptid) != 0);
|
||||
|
||||
info = get_thread_db_info (GET_PID (ptid));
|
||||
|
||||
/* Access an lwp we know is stopped. */
|
||||
proc_handle.ptid = ptid;
|
||||
err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
|
||||
info->proc_handle.ptid = ptid;
|
||||
err = info->td_ta_map_lwp2thr_p (info->thread_agent, GET_LWP (ptid), &th);
|
||||
if (err != TD_OK)
|
||||
error (_("Cannot find user-level thread for LWP %ld: %s"),
|
||||
GET_LWP (ptid), thread_db_err_str (err));
|
||||
|
||||
thread_info = NULL;
|
||||
|
||||
/* Fetch the thread info. If we get back TD_THR_ZOMBIE, then the
|
||||
event thread has already died. If another gdb interface has called
|
||||
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,
|
||||
we return a -1 ptid which is also how the thread list marks a
|
||||
dead thread. */
|
||||
if (thread_get_info_callback (&th, &thread_info) == TD_THR_ZOMBIE
|
||||
&& thread_info == NULL)
|
||||
return pid_to_ptid (-1);
|
||||
io.thread_db_info = info;
|
||||
io.thread_info = NULL;
|
||||
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);
|
||||
return ptid;
|
||||
|
@ -345,8 +436,11 @@ thread_db_attach_lwp (ptid_t ptid)
|
|||
td_thrhandle_t th;
|
||||
td_thrinfo_t ti;
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
initialized, we may not know its thread ID yet. Make sure we do
|
||||
before we add another thread to the list. */
|
||||
if (!have_threads ())
|
||||
thread_db_find_new_threads_1 ();
|
||||
if (!have_threads (ptid))
|
||||
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)
|
||||
/* Cannot find user-level thread. */
|
||||
return 0;
|
||||
|
||||
err = td_thr_get_info_p (&th, &ti);
|
||||
err = info->td_thr_get_info_p (&th, &ti);
|
||||
if (err != TD_OK)
|
||||
{
|
||||
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
|
||||
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_err_e err;
|
||||
struct thread_db_info *info;
|
||||
|
||||
info = get_thread_db_info (GET_PID (inferior_ptid));
|
||||
|
||||
/* 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. */
|
||||
err = td_ta_event_addr_p (thread_agent, event, ¬ify);
|
||||
err = info->td_ta_event_addr_p (info->thread_agent, event, ¬ify);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
|
@ -425,11 +522,16 @@ enable_thread_event_reporting (void)
|
|||
const char *libc_version;
|
||||
int libc_major, libc_minor;
|
||||
#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
|
||||
functions aren't available. */
|
||||
if (td_ta_event_addr_p == NULL || td_ta_set_event_p == NULL
|
||||
|| td_ta_event_getmsg_p == NULL || td_thr_event_enable_p == NULL)
|
||||
if (info->td_ta_event_addr_p == NULL
|
||||
|| info->td_ta_set_event_p == NULL
|
||||
|| info->td_ta_event_getmsg_p == NULL
|
||||
|| info->td_thr_event_enable_p == NULL)
|
||||
return;
|
||||
|
||||
/* Set the process wide mask saying which events we're interested in. */
|
||||
|
@ -446,7 +548,7 @@ enable_thread_event_reporting (void)
|
|||
#endif
|
||||
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)
|
||||
{
|
||||
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. */
|
||||
remove_thread_event_breakpoints ();
|
||||
td_create_bp_addr = 0;
|
||||
td_death_bp_addr = 0;
|
||||
info->td_create_bp_addr = 0;
|
||||
info->td_death_bp_addr = 0;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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. */
|
||||
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)
|
||||
{
|
||||
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.
|
||||
Return 1 on success.
|
||||
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). */
|
||||
|
||||
static int
|
||||
try_thread_db_load_1 (void *handle)
|
||||
try_thread_db_load_1 (struct thread_db_info *info)
|
||||
{
|
||||
td_err_e err;
|
||||
|
||||
/* Initialize pointers to the dynamic library functions we will use.
|
||||
Essential functions first. */
|
||||
|
||||
td_init_p = verbose_dlsym (handle, "td_init");
|
||||
if (td_init_p == NULL)
|
||||
info->td_init_p = verbose_dlsym (info->handle, "td_init");
|
||||
if (info->td_init_p == NULL)
|
||||
return 0;
|
||||
|
||||
err = td_init_p ();
|
||||
err = info->td_init_p ();
|
||||
if (err != TD_OK)
|
||||
{
|
||||
warning (_("Cannot initialize libthread_db: %s"), thread_db_err_str (err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
td_ta_new_p = verbose_dlsym (handle, "td_ta_new");
|
||||
if (td_ta_new_p == NULL)
|
||||
info->td_ta_new_p = verbose_dlsym (info->handle, "td_ta_new");
|
||||
if (info->td_ta_new_p == NULL)
|
||||
return 0;
|
||||
|
||||
/* 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. */
|
||||
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)
|
||||
{
|
||||
td_ta_new_p = NULL;
|
||||
if (info_verbose)
|
||||
printf_unfiltered (_("td_ta_new failed: %s\n"),
|
||||
thread_db_err_str (err));
|
||||
|
@ -535,58 +650,57 @@ try_thread_db_load_1 (void *handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr");
|
||||
if (td_ta_map_id2thr_p == NULL)
|
||||
info->td_ta_map_id2thr_p = verbose_dlsym (info->handle, "td_ta_map_id2thr");
|
||||
if (info->td_ta_map_id2thr_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_ta_map_lwp2thr_p = verbose_dlsym (handle, "td_ta_map_lwp2thr");
|
||||
if (td_ta_map_lwp2thr_p == NULL)
|
||||
info->td_ta_map_lwp2thr_p = verbose_dlsym (info->handle, "td_ta_map_lwp2thr");
|
||||
if (info->td_ta_map_lwp2thr_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_ta_thr_iter_p = verbose_dlsym (handle, "td_ta_thr_iter");
|
||||
if (td_ta_thr_iter_p == NULL)
|
||||
info->td_ta_thr_iter_p = verbose_dlsym (info->handle, "td_ta_thr_iter");
|
||||
if (info->td_ta_thr_iter_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_thr_validate_p = verbose_dlsym (handle, "td_thr_validate");
|
||||
if (td_thr_validate_p == NULL)
|
||||
info->td_thr_validate_p = verbose_dlsym (info->handle, "td_thr_validate");
|
||||
if (info->td_thr_validate_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_thr_get_info_p = verbose_dlsym (handle, "td_thr_get_info");
|
||||
if (td_thr_get_info_p == NULL)
|
||||
info->td_thr_get_info_p = verbose_dlsym (info->handle, "td_thr_get_info");
|
||||
if (info->td_thr_get_info_p == NULL)
|
||||
return 0;
|
||||
|
||||
/* These are not essential. */
|
||||
td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr");
|
||||
td_ta_set_event_p = dlsym (handle, "td_ta_set_event");
|
||||
td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg");
|
||||
td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable");
|
||||
td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr");
|
||||
info->td_ta_event_addr_p = dlsym (info->handle, "td_ta_event_addr");
|
||||
info->td_ta_set_event_p = dlsym (info->handle, "td_ta_set_event");
|
||||
info->td_ta_event_getmsg_p = dlsym (info->handle, "td_ta_event_getmsg");
|
||||
info->td_thr_event_enable_p = dlsym (info->handle, "td_thr_event_enable");
|
||||
info->td_thr_tls_get_addr_p = dlsym (info->handle, "td_thr_tls_get_addr");
|
||||
|
||||
printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
|
||||
|
||||
/* The thread library was detected. Activate the thread_db target. */
|
||||
push_target (&thread_db_ops);
|
||||
thread_db_handle = handle;
|
||||
if (info_verbose || *libthread_db_search_path)
|
||||
{
|
||||
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 ();
|
||||
thread_db_find_new_threads_1 ();
|
||||
thread_db_find_new_threads_1 (inferior_ptid);
|
||||
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,
|
||||
relative, or just LIBTHREAD_DB. */
|
||||
|
||||
|
@ -594,6 +708,7 @@ static int
|
|||
try_thread_db_load (const char *library)
|
||||
{
|
||||
void *handle;
|
||||
struct thread_db_info *info;
|
||||
|
||||
if (info_verbose)
|
||||
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;
|
||||
|
||||
/* This library "refused" to work on current inferior. */
|
||||
dlclose (handle);
|
||||
delete_thread_db_info (GET_PID (inferior_ptid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -695,8 +812,11 @@ static int
|
|||
thread_db_load (void)
|
||||
{
|
||||
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;
|
||||
|
||||
/* Don't attempt to use thread_db on targets which can not run
|
||||
|
@ -754,16 +874,19 @@ static void
|
|||
disable_thread_event_reporting (void)
|
||||
{
|
||||
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
|
||||
events anymore. */
|
||||
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. */
|
||||
remove_thread_event_breakpoints ();
|
||||
td_create_bp_addr = 0;
|
||||
td_death_bp_addr = 0;
|
||||
info->td_create_bp_addr = 0;
|
||||
info->td_death_bp_addr = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -807,35 +930,14 @@ check_for_thread_db (void)
|
|||
/* Do nothing if we couldn't load libthread_db.so.1. */
|
||||
if (!thread_db_load ())
|
||||
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
|
||||
thread_db_new_objfile (struct objfile *objfile)
|
||||
{
|
||||
/* This observer must always be called with inferior_ptid set
|
||||
correctly. */
|
||||
|
||||
if (objfile != NULL)
|
||||
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 thread_info *tp = NULL;
|
||||
td_err_e err;
|
||||
struct thread_db_info *info;
|
||||
|
||||
/* 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
|
||||
|
@ -913,8 +1016,10 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
|||
else
|
||||
tp->private = private;
|
||||
|
||||
info = get_thread_db_info (GET_PID (ptid));
|
||||
|
||||
/* 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)
|
||||
error (_("Cannot enable thread event reporting for %s: %s"),
|
||||
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)
|
||||
{
|
||||
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
|
||||
anymore. */
|
||||
proc_handle.ptid = null_ptid;
|
||||
if (info)
|
||||
{
|
||||
disable_thread_event_reporting ();
|
||||
|
||||
/* Detach thread_db target ops. */
|
||||
unpush_target (&thread_db_ops);
|
||||
if (thread_db_handle)
|
||||
dlclose (thread_db_handle);
|
||||
thread_db_handle = NULL;
|
||||
/* Delete the old thread event breakpoints. Note that unlike
|
||||
when mourning, we can remove them here because there's still
|
||||
a live inferior to poke at. In any case, GDB will not try to
|
||||
insert anything in the inferior when removing a
|
||||
breakpoint. */
|
||||
remove_thread_event_breakpoints ();
|
||||
|
||||
delete_thread_db_info (GET_PID (inferior_ptid));
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -972,21 +1089,25 @@ check_event (ptid_t ptid)
|
|||
td_err_e err;
|
||||
CORE_ADDR stop_pc;
|
||||
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. */
|
||||
stop_pc = regcache_read_pc (regcache)
|
||||
- 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;
|
||||
|
||||
/* 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
|
||||
initialized, we may not know its thread ID yet. Make sure we do
|
||||
before we add another thread to the list. */
|
||||
if (!have_threads ())
|
||||
thread_db_find_new_threads_1 ();
|
||||
if (!have_threads (ptid))
|
||||
thread_db_find_new_threads_1 (ptid);
|
||||
|
||||
/* 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.
|
||||
|
@ -1006,7 +1127,7 @@ check_event (ptid_t ptid)
|
|||
|
||||
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_NOMSG)
|
||||
|
@ -1016,7 +1137,7 @@ check_event (ptid_t ptid)
|
|||
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)
|
||||
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,
|
||||
ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||
{
|
||||
struct thread_db_info *info;
|
||||
struct target_ops *beneath = find_target_beneath (ops);
|
||||
|
||||
ptid = beneath->to_wait (beneath, ptid, ourstatus);
|
||||
|
@ -1062,28 +1184,40 @@ thread_db_wait (struct target_ops *ops,
|
|||
|| ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
|
||||
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)
|
||||
{
|
||||
/* 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 ();
|
||||
unpush_target (&thread_db_ops);
|
||||
if (thread_db_handle)
|
||||
dlclose (thread_db_handle);
|
||||
thread_db_handle = NULL;
|
||||
|
||||
/* New image, it may or may not end up using thread_db. Assume
|
||||
not unless we find otherwise. */
|
||||
delete_thread_db_info (GET_PID (ptid));
|
||||
if (!thread_db_list)
|
||||
unpush_target (&thread_db_ops);
|
||||
|
||||
return ptid;
|
||||
}
|
||||
|
||||
/* If we do not know about the main thread yet, this would be a good time to
|
||||
find it. */
|
||||
if (ourstatus->kind == TARGET_WAITKIND_STOPPED && !have_threads ())
|
||||
thread_db_find_new_threads_1 ();
|
||||
if (ourstatus->kind == TARGET_WAITKIND_STOPPED && !have_threads (ptid))
|
||||
thread_db_find_new_threads_1 (ptid);
|
||||
|
||||
if (ourstatus->kind == TARGET_WAITKIND_STOPPED
|
||||
&& ourstatus->value.sig == TARGET_SIGNAL_TRAP)
|
||||
/* Check for a thread event. */
|
||||
check_event (ptid);
|
||||
|
||||
if (have_threads ())
|
||||
if (have_threads (ptid))
|
||||
{
|
||||
/* Change ptids back into the higher level PID + TID format. If
|
||||
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);
|
||||
|
||||
/* Forget about the child's process ID. We shouldn't need it
|
||||
anymore. */
|
||||
proc_handle.ptid = null_ptid;
|
||||
delete_thread_db_info (GET_PID (inferior_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);
|
||||
|
||||
/* 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. */
|
||||
unpush_target (ops);
|
||||
if (thread_db_handle)
|
||||
dlclose (thread_db_handle);
|
||||
thread_db_handle = NULL;
|
||||
if (!thread_db_list)
|
||||
unpush_target (ops);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1128,8 +1259,9 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
|
|||
td_err_e err;
|
||||
ptid_t ptid;
|
||||
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)
|
||||
error (_("find_new_threads_callback: cannot get thread info: %s"),
|
||||
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)
|
||||
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)
|
||||
{
|
||||
|
@ -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
|
||||
it. */
|
||||
|
||||
err = td_thr_event_enable_p (th_p, 1);
|
||||
err = info->td_thr_event_enable_p (th_p, 1);
|
||||
if (err != TD_OK)
|
||||
error (_("Cannot enable thread event reporting for %s: %s"),
|
||||
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. */
|
||||
|
||||
static void
|
||||
thread_db_find_new_threads_1 (void)
|
||||
thread_db_find_new_threads_1 (ptid_t ptid)
|
||||
{
|
||||
td_err_e err;
|
||||
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. */
|
||||
ALL_LWPS (lp, ptid)
|
||||
if (lp->stopped)
|
||||
if (lp->stopped && ptid_get_pid (lp->ptid) == pid)
|
||||
break;
|
||||
|
||||
if (!lp)
|
||||
/* There is no stopped thread. Bail out. */
|
||||
return;
|
||||
|
||||
info = get_thread_db_info (GET_PID (ptid));
|
||||
|
||||
/* 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. */
|
||||
err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, NULL,
|
||||
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
|
||||
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
|
||||
err = info->td_ta_thr_iter_p (info->thread_agent, find_new_threads_callback,
|
||||
info, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
|
||||
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
|
||||
if (err != TD_OK)
|
||||
error (_("Cannot find new threads: %s"), thread_db_err_str (err));
|
||||
}
|
||||
|
@ -1194,7 +1329,14 @@ thread_db_find_new_threads_1 (void)
|
|||
static void
|
||||
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 *
|
||||
|
@ -1250,8 +1392,8 @@ thread_db_get_thread_local_address (struct target_ops *ops,
|
|||
struct target_ops *beneath;
|
||||
|
||||
/* If we have not discovered any threads yet, check now. */
|
||||
if (!have_threads ())
|
||||
thread_db_find_new_threads_1 ();
|
||||
if (!have_threads (ptid))
|
||||
thread_db_find_new_threads_1 (ptid);
|
||||
|
||||
/* Find the matching thread. */
|
||||
thread_info = find_thread_pid (ptid);
|
||||
|
@ -1260,9 +1402,12 @@ thread_db_get_thread_local_address (struct target_ops *ops,
|
|||
{
|
||||
td_err_e err;
|
||||
void *address;
|
||||
struct thread_db_info *info;
|
||||
|
||||
info = get_thread_db_info (GET_PID (ptid));
|
||||
|
||||
/* 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,
|
||||
_("No TLS library support"));
|
||||
|
||||
|
@ -1270,9 +1415,9 @@ thread_db_get_thread_local_address (struct target_ops *ops,
|
|||
gdb_assert (lm != 0);
|
||||
|
||||
/* Finally, get the address of the variable. */
|
||||
err = td_thr_tls_get_addr_p (&thread_info->private->th,
|
||||
(void *)(size_t) lm,
|
||||
offset, &address);
|
||||
err = info->td_thr_tls_get_addr_p (&thread_info->private->th,
|
||||
(void *)(size_t) lm,
|
||||
offset, &address);
|
||||
|
||||
#ifdef THREAD_DB_HAS_TD_NOTALLOC
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
|
||||
gdb_assert (thread_info != NULL);
|
||||
|
|
|
@ -389,6 +389,31 @@ mi_about_to_proceed (void)
|
|||
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
|
||||
mi_on_resume (ptid_t ptid)
|
||||
{
|
||||
|
@ -420,11 +445,19 @@ mi_on_resume (ptid_t ptid)
|
|||
|
||||
if (PIDGET (ptid) == -1)
|
||||
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
|
||||
table has zero threads. Don't print any thread-id field. */
|
||||
fprintf_unfiltered (raw_stdout, "*running\n");
|
||||
int count;
|
||||
|
||||
/* 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
|
||||
{
|
||||
|
|
24
gdb/thread.c
24
gdb/thread.c
|
@ -509,21 +509,23 @@ void
|
|||
set_running (ptid_t ptid, int running)
|
||||
{
|
||||
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
|
||||
the running state -- merely to reduce the number of messages to
|
||||
frontend. Frontend is supposed to handle multiple *running just fine. */
|
||||
if (PIDGET (ptid) == -1)
|
||||
if (all || ptid_is_pid (ptid))
|
||||
{
|
||||
int any_started = 0;
|
||||
for (tp = thread_list; tp; tp = tp->next)
|
||||
{
|
||||
if (tp->state_ == THREAD_EXITED)
|
||||
continue;
|
||||
if (running && tp->state_ == THREAD_STOPPED)
|
||||
any_started = 1;
|
||||
tp->state_ = running ? THREAD_RUNNING : THREAD_STOPPED;
|
||||
}
|
||||
if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
|
||||
{
|
||||
if (tp->state_ == THREAD_EXITED)
|
||||
continue;
|
||||
if (running && tp->state_ == THREAD_STOPPED)
|
||||
any_started = 1;
|
||||
tp->state_ = running ? THREAD_RUNNING : THREAD_STOPPED;
|
||||
}
|
||||
if (any_started)
|
||||
observer_notify_target_resumed (ptid);
|
||||
}
|
||||
|
@ -616,11 +618,13 @@ void
|
|||
set_executing (ptid_t ptid, int executing)
|
||||
{
|
||||
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)
|
||||
tp->executing_ = executing;
|
||||
if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
|
||||
tp->executing_ = executing;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue