mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-10-18 13:23:10 +08:00
* 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:
@ -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);
|
||||
|
Reference in New Issue
Block a user