#include "nat/linux-osdata.h"
#include "auto-load.h"
#include "cli/cli-utils.h"
-
#include <signal.h>
#include <ctype.h>
+#include "nat/linux-namespaces.h"
/* GNU/Linux libthread_db support.
/* Pointers to the libthread_db functions. */
- td_err_e (*td_init_p) (void);
-
- td_err_e (*td_ta_new_p) (struct ps_prochandle * ps,
- td_thragent_t **ta);
- td_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_clear_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);
-
- 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);
-
- td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
- psaddr_t map_address,
- size_t offset, psaddr_t *address);
- td_err_e (*td_thr_tlsbase_p) (const td_thrhandle_t *th,
- unsigned long int modid,
- psaddr_t *base);
+ td_init_ftype *td_init_p;
+ td_ta_new_ftype *td_ta_new_p;
+ td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p;
+ td_ta_thr_iter_ftype *td_ta_thr_iter_p;
+ td_ta_event_addr_ftype *td_ta_event_addr_p;
+ td_ta_set_event_ftype *td_ta_set_event_p;
+ td_ta_clear_event_ftype *td_ta_clear_event_p;
+ td_ta_event_getmsg_ftype * td_ta_event_getmsg_p;
+ td_thr_validate_ftype *td_thr_validate_p;
+ td_thr_get_info_ftype *td_thr_get_info_p;
+ td_thr_event_enable_ftype *td_thr_event_enable_p;
+ td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p;
+ td_thr_tlsbase_ftype *td_thr_tlsbase_p;
};
/* List of known processes using thread_db, and the required
static void check_thread_signals (void);
-static void record_thread (struct thread_db_info *info,
- struct thread_info *tp,
- ptid_t ptid, const td_thrhandle_t *th_p,
- const td_thrinfo_t *ti_p);
+static struct thread_info *record_thread
+ (struct thread_db_info *info, struct thread_info *tp,
+ ptid_t ptid, const td_thrhandle_t *th_p, const td_thrinfo_t *ti_p);
/* Add the current inferior to the list of processes using libpthread.
Return a pointer to the newly allocated object that was added to
static struct thread_db_info *
add_thread_db_info (void *handle)
{
- struct thread_db_info *info;
+ struct thread_db_info *info = XCNEW (struct thread_db_info);
- info = xcalloc (1, sizeof (*info));
info->pid = ptid_get_pid (inferior_ptid);
info->handle = handle;
\f
/* Fetch the user-level thread id of PTID. */
-static void
+static struct thread_info *
thread_from_lwp (ptid_t ptid)
{
td_thrhandle_t th;
/* Fill the cache. */
tp = find_thread_ptid (ptid);
- record_thread (info, tp, ptid, &th, &ti);
+ return record_thread (info, tp, ptid, &th, &ti);
}
\f
}
static td_err_e
-enable_thread_event (int event, CORE_ADDR *bp)
+enable_thread_event (td_event_e event, CORE_ADDR *bp)
{
td_notify_t notify;
td_err_e err;
/* Initialize pointers to the dynamic library functions we will use.
Essential functions first. */
- info->td_init_p = verbose_dlsym (info->handle, "td_init");
- if (info->td_init_p == NULL)
- return 0;
+#define TDB_VERBOSE_DLSYM(info, func) \
+ info->func ## _p = (func ## _ftype *) verbose_dlsym (info->handle, #func)
+
+#define TDB_DLSYM(info, func) \
+ info->func ## _p = (func ## _ftype *) dlsym (info->handle, #func)
+
+#define CHK(a) \
+ do \
+ { \
+ if ((a) == NULL) \
+ return 0; \
+ } while (0)
+
+ CHK (TDB_VERBOSE_DLSYM (info, td_init));
err = info->td_init_p ();
if (err != TD_OK)
return 0;
}
- info->td_ta_new_p = verbose_dlsym (info->handle, "td_ta_new");
- if (info->td_ta_new_p == NULL)
- return 0;
+ CHK (TDB_VERBOSE_DLSYM (info, td_ta_new));
/* Initialize the structure that identifies the child process. */
info->proc_handle.ptid = inferior_ptid;
return 0;
}
- info->td_ta_map_id2thr_p = verbose_dlsym (info->handle, "td_ta_map_id2thr");
- if (info->td_ta_map_id2thr_p == NULL)
- return 0;
-
- info->td_ta_map_lwp2thr_p = verbose_dlsym (info->handle,
- "td_ta_map_lwp2thr");
- if (info->td_ta_map_lwp2thr_p == NULL)
- return 0;
-
- info->td_ta_thr_iter_p = verbose_dlsym (info->handle, "td_ta_thr_iter");
- if (info->td_ta_thr_iter_p == NULL)
- return 0;
-
- info->td_thr_validate_p = verbose_dlsym (info->handle, "td_thr_validate");
- if (info->td_thr_validate_p == NULL)
- return 0;
-
- 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 essential. */
+ CHK (TDB_VERBOSE_DLSYM (info, td_ta_map_lwp2thr));
+ CHK (TDB_VERBOSE_DLSYM (info, td_ta_thr_iter));
+ CHK (TDB_VERBOSE_DLSYM (info, td_thr_validate));
+ CHK (TDB_VERBOSE_DLSYM (info, td_thr_get_info));
/* These are not essential. */
- 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_clear_event_p = dlsym (info->handle, "td_ta_clear_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");
- info->td_thr_tlsbase_p = dlsym (info->handle, "td_thr_tlsbase");
+ TDB_DLSYM (info, td_ta_event_addr);
+ TDB_DLSYM (info, td_ta_set_event);
+ TDB_DLSYM (info, td_ta_clear_event);
+ TDB_DLSYM (info, td_ta_event_getmsg);
+ TDB_DLSYM (info, td_thr_event_enable);
+ TDB_DLSYM (info, td_thr_tls_get_addr);
+ TDB_DLSYM (info, td_thr_tlsbase);
+
+#undef TDB_VERBOSE_DLSYM
+#undef TDB_DLSYM
+#undef CHK
/* It's best to avoid td_ta_thr_iter if possible. That walks data
structures in the inferior's address space that may be corrupted,
child's thread list, we'll mistakenly think it has no threads
since the thread PID fields won't match the PID we give to
libthread_db. */
- char *our_pid_ns = linux_proc_pid_get_ns (getpid (), "pid");
- char *inferior_pid_ns = linux_proc_pid_get_ns (
- ptid_get_pid (inferior_ptid), "pid");
-
- if (our_pid_ns != NULL && inferior_pid_ns != NULL
- && strcmp (our_pid_ns, inferior_pid_ns) != 0)
+ if (!linux_ns_same (ptid_get_pid (inferior_ptid), LINUX_NS_PID))
{
warning (_ ("Target and debugger are in different PID "
"namespaces; thread lists and other data are "
"likely unreliable"));
}
-
- xfree (our_pid_ns);
- xfree (inferior_pid_ns);
}
}
}
/* Record a new thread in GDB's thread list. Creates the thread's
- private info. If TP is NULL, creates a new thread. Otherwise,
- uses TP. */
+ private info. If TP is NULL or TP is marked as having exited,
+ creates a new thread. Otherwise, uses TP. */
-static void
+static struct thread_info *
record_thread (struct thread_db_info *info,
struct thread_info *tp,
ptid_t ptid, const td_thrhandle_t *th_p,
initialized yet. Leave private == NULL until the thread library
has initialized. */
if (ti_p->ti_tid == 0)
- return;
+ return tp;
/* Construct the thread's private data. */
- priv = xmalloc (sizeof (struct private_thread_info));
- memset (priv, 0, sizeof (struct private_thread_info));
+ priv = XCNEW (struct private_thread_info);
priv->th = *th_p;
priv->tid = ti_p->ti_tid;
update_thread_state (priv, ti_p);
- /* Add the thread to GDB's thread list. */
- if (tp == NULL)
+ /* Add the thread to GDB's thread list. If we already know about a
+ thread with this PTID, but it's marked exited, then the kernel
+ reused the tid of an old thread. */
+ if (tp == NULL || tp->state == THREAD_EXITED)
tp = add_thread_with_info (ptid, priv);
else
tp->priv = priv;
if (target_has_execution)
check_thread_signals ();
+
+ return tp;
}
static void
struct thread_info *thread_info;
struct target_ops *beneath;
- /* If we have not discovered any threads yet, check now. */
- if (!have_threads (ptid))
- thread_db_find_new_threads_1 (ptid);
-
/* Find the matching thread. */
thread_info = find_thread_ptid (ptid);
+ /* We may not have discovered the thread yet. */
+ if (thread_info != NULL && thread_info->priv == NULL)
+ thread_info = thread_from_lwp (ptid);
+
if (thread_info != NULL && thread_info->priv != NULL)
{
td_err_e err;
if (info->filename != NULL)
info_count++;
- array = xmalloc (sizeof (*array) * info_count);
+ array = XNEWVEC (struct thread_db_info *, info_count);
back_to = make_cleanup (xfree, array);
info_count = 0;