/* libthread_db assisted debugging support, generic parts.
- Copyright (C) 1999-2018 Free Software Foundation, Inc.
+ Copyright (C) 1999-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include <dlfcn.h>
#include "gdb_proc_service.h"
#include "nat/gdb_thread_db.h"
-#include "gdb_vecs.h"
+#include "common/gdb_vecs.h"
#include "bfd.h"
#include "command.h"
#include "gdbcmd.h"
class thread_db_target final : public target_ops
{
public:
- thread_db_target ();
-
const target_info &info () const override
{ return thread_db_target_info; }
+ strata stratum () const override { return thread_stratum; }
+
void detach (inferior *, int) override;
ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
void resume (ptid_t, int, enum gdb_signal) override;
void mourn_inferior () override;
void update_thread_list () override;
- const char *pid_to_str (ptid_t) override;
+ std::string pid_to_str (ptid_t) override;
CORE_ADDR get_thread_local_address (ptid_t ptid,
CORE_ADDR load_module_addr,
CORE_ADDR offset) override;
thread_info *thread_handle_to_thread_info (const gdb_byte *thread_handle,
int handle_len,
inferior *inf) override;
+ gdb::byte_vector thread_info_to_thread_handle (struct thread_info *) override;
};
-thread_db_target::thread_db_target ()
-{
- this->to_stratum = thread_stratum;
-}
-
static char *libthread_db_search_path;
/* Set to non-zero if thread_db auto-loading is enabled
td_init_ftype *td_init_p;
td_ta_new_ftype *td_ta_new_p;
+ td_ta_delete_ftype *td_ta_delete_p;
td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p;
td_ta_thr_iter_ftype *td_ta_thr_iter_p;
td_thr_get_info_ftype *td_thr_get_info_p;
{
struct thread_db_info *info = XCNEW (struct thread_db_info);
- info->pid = ptid_get_pid (inferior_ptid);
+ info->pid = inferior_ptid.pid ();
info->handle = handle;
/* The workaround works by reading from /proc/pid/status, so it is
return NULL;
}
+static const char *thread_db_err_str (td_err_e err);
+
/* 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
if (info == NULL)
return;
+ if (info->thread_agent != NULL && info->td_ta_delete_p != NULL)
+ {
+ td_err_e err = info->td_ta_delete_p (info->thread_agent);
+
+ if (err != TD_OK)
+ warning (_("Cannot deregister process %d from libthread_db: %s"),
+ pid, thread_db_err_str (err));
+ info->thread_agent = NULL;
+ }
+
if (info->handle != NULL)
dlclose (info->handle);
/* This ptid comes from linux-nat.c, which should always fill in the
LWP. */
- gdb_assert (ptid_get_lwp (ptid) != 0);
+ gdb_assert (ptid.lwp () != 0);
- info = get_thread_db_info (ptid_get_pid (ptid));
+ info = get_thread_db_info (ptid.pid ());
/* Access an lwp we know is stopped. */
info->proc_handle.thread = stopped;
- err = info->td_ta_map_lwp2thr_p (info->thread_agent, ptid_get_lwp (ptid),
+ err = info->td_ta_map_lwp2thr_p (info->thread_agent, ptid.lwp (),
&th);
if (err != TD_OK)
error (_("Cannot find user-level thread for LWP %ld: %s"),
- ptid_get_lwp (ptid), thread_db_err_str (err));
+ ptid.lwp (), thread_db_err_str (err));
err = info->td_thr_get_info_p (&th, &ti);
if (err != TD_OK)
{
struct thread_db_info *info;
- info = get_thread_db_info (ptid_get_pid (child));
+ info = get_thread_db_info (child.pid ());
if (info == NULL)
return 0;
thread_db_find_new_threads_silently (thread_info *stopped)
{
- TRY
+ try
{
thread_db_find_new_threads_2 (stopped, true);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
if (libthread_db_debug)
exception_fprintf (gdb_stdlog, except,
return 1;
}
}
- END_CATCH
return 0;
}
fail. */
linux_stop_and_wait_all_lwps ();
- TRY
+ try
{
td_err_e err = td_ta_thr_iter_p (info->thread_agent,
check_thread_db_callback,
if (!tdb_testinfo->threads_seen)
error (_("no threads seen"));
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
if (warning_pre_print)
fputs_unfiltered (warning_pre_print, gdb_stderr);
test_passed = false;
}
- END_CATCH
if (test_passed && log_progress)
debug_printf (_("libthread_db integrity checks passed.\n"));
/* These are not essential. */
TDB_DLSYM (info, td_thr_tls_get_addr);
TDB_DLSYM (info, td_thr_tlsbase);
+ TDB_DLSYM (info, td_ta_delete);
/* 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,
td_ta_map_lwp2thr uses ps_get_thread_area, but we can't use that
currently on core targets, as it uses ptrace directly. */
if (target_has_execution
- && linux_proc_task_list_dir_exists (ptid_get_pid (inferior_ptid)))
+ && linux_proc_task_list_dir_exists (inferior_ptid.pid ()))
info->td_ta_thr_iter_p = NULL;
else
CHK (TDB_VERBOSE_DLSYM (info, td_ta_thr_iter));
if (info->td_ta_thr_iter_p == NULL)
{
struct lwp_info *lp;
- int pid = ptid_get_pid (inferior_ptid);
+ int pid = inferior_ptid.pid ();
thread_info *curr_thread = inferior_thread ();
linux_stop_and_wait_all_lwps ();
ALL_LWPS (lp)
- if (ptid_get_pid (lp->ptid) == pid)
+ if (lp->ptid.pid () == pid)
thread_from_lwp (curr_thread, lp->ptid);
linux_unstop_all_lwps ();
return 1;
/* This library "refused" to work on current inferior. */
- delete_thread_db_info (ptid_get_pid (inferior_ptid));
+ delete_thread_db_info (inferior_ptid.pid ());
return 0;
}
static int
try_thread_db_load_from_pdir (const char *subdir)
{
- struct objfile *obj;
-
if (!auto_load_thread_db)
return 0;
- ALL_OBJFILES (obj)
+ for (objfile *obj : current_program_space->objfiles ())
if (libpthread_name_p (objfile_name (obj)))
{
if (try_thread_db_load_from_pdir_1 (obj, subdir))
static int
has_libpthread (void)
{
- struct objfile *obj;
-
- ALL_OBJFILES (obj)
+ for (objfile *obj : current_program_space->objfiles ())
if (libpthread_name_p (objfile_name (obj)))
return 1;
{
struct thread_db_info *info;
- info = get_thread_db_info (ptid_get_pid (inferior_ptid));
+ info = get_thread_db_info (inferior_ptid.pid ());
if (info != NULL)
return 1;
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. */
- if (!linux_ns_same (ptid_get_pid (inferior_ptid), LINUX_NS_PID))
+ if (!linux_ns_same (inferior_ptid.pid (), LINUX_NS_PID))
{
warning (_ ("Target and debugger are in different PID "
"namespaces; thread lists and other data are "
return ptid;
}
- info = get_thread_db_info (ptid_get_pid (ptid));
+ info = get_thread_db_info (ptid.pid ());
/* If this process isn't using thread_db, we're done. */
if (info == NULL)
{
/* New image, it may or may not end up using thread_db. Assume
not unless we find otherwise. */
- delete_thread_db_info (ptid_get_pid (ptid));
+ delete_thread_db_info (ptid.pid ());
if (!thread_db_list)
unpush_target (&the_thread_db_target);
void
thread_db_target::mourn_inferior ()
{
- delete_thread_db_info (ptid_get_pid (inferior_ptid));
+ delete_thread_db_info (inferior_ptid.pid ());
beneath ()->mourn_inferior ();
/* See comment in thread_db_update_thread_list. */
gdb_assert (info->td_ta_thr_iter_p != NULL);
- TRY
+ try
{
/* Iterate over all user-space threads to discover new threads. */
err = info->td_ta_thr_iter_p (info->thread_agent,
TD_SIGNO_MASK,
TD_THR_ANY_USER_FLAGS);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
if (libthread_db_debug)
{
"Warning: find_new_threads_once: ");
}
}
- END_CATCH
if (libthread_db_debug)
{
thread_db_target::update_thread_list ()
{
struct thread_db_info *info;
- struct inferior *inf;
prune_threads ();
- ALL_INFERIORS (inf)
+ for (inferior *inf : all_inferiors ())
{
struct thread_info *thread;
this->beneath ()->update_thread_list ();
}
-const char *
+std::string
thread_db_target::pid_to_str (ptid_t ptid)
{
struct thread_info *thread_info = find_thread_ptid (ptid);
if (thread_info != NULL && thread_info->priv != NULL)
{
- static char buf[64];
thread_db_thread_info *priv = get_thread_db_thread_info (thread_info);
- snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld)",
- (unsigned long) priv->tid, ptid_get_lwp (ptid));
-
- return buf;
+ return string_printf ("Thread 0x%lx (LWP %ld)",
+ (unsigned long) priv->tid, ptid.lwp ());
}
return beneath ()->pid_to_str (ptid);
int handle_len,
inferior *inf)
{
- struct thread_info *tp;
thread_t handle_tid;
/* Thread handle sizes must match in order to proceed. We don't use an
handle_tid = * (const thread_t *) thread_handle;
- ALL_NON_EXITED_THREADS (tp)
+ for (thread_info *tp : inf->non_exited_threads ())
{
thread_db_thread_info *priv = get_thread_db_thread_info (tp);
- if (tp->inf == inf && priv != NULL && handle_tid == priv->tid)
+ if (priv != NULL && handle_tid == priv->tid)
return tp;
}
return NULL;
}
+/* Return the thread handle associated the thread_info pointer TP. */
+
+gdb::byte_vector
+thread_db_target::thread_info_to_thread_handle (struct thread_info *tp)
+{
+ thread_db_thread_info *priv = get_thread_db_thread_info (tp);
+
+ if (priv == NULL)
+ return gdb::byte_vector ();
+
+ int handle_size = sizeof (priv->tid);
+ gdb::byte_vector rv (handle_size);
+
+ memcpy (rv.data (), &priv->tid, handle_size);
+
+ return rv;
+}
+
/* Get the address of the thread local variable in load module LM which
is stored at OFFSET within the thread local storage for thread PTID. */
{
td_err_e err;
psaddr_t address;
- thread_db_info *info = get_thread_db_info (ptid_get_pid (ptid));
+ thread_db_info *info = get_thread_db_info (ptid.pid ());
thread_db_thread_info *priv = get_thread_db_thread_info (thread_info);
/* Finally, get the address of the variable. */
thread_db_target::get_ada_task_ptid (long lwp, long thread)
{
/* NPTL uses a 1:1 model, so the LWP id suffices. */
- return ptid_t (ptid_get_pid (inferior_ptid), lwp, 0);
+ return ptid_t (inferior_ptid.pid (), lwp, 0);
}
void
{
struct thread_db_info *info;
- if (ptid_equal (ptid, minus_one_ptid))
- info = get_thread_db_info (ptid_get_pid (inferior_ptid));
+ if (ptid == minus_one_ptid)
+ info = get_thread_db_info (inferior_ptid.pid ());
else
- info = get_thread_db_info (ptid_get_pid (ptid));
+ info = get_thread_db_info (ptid.pid ());
/* This workaround is only needed for child fork lwps stopped in a
PTRACE_O_TRACEFORK event. When the inferior is resumed, the
static void
maintenance_check_libthread_db (const char *args, int from_tty)
{
- int inferior_pid = ptid_get_pid (inferior_ptid);
+ int inferior_pid = inferior_ptid.pid ();
struct thread_db_info *info;
if (inferior_pid == 0)
If enabled, libthread_db will be searched in 'set libthread-db-search-path'\n\
locations to load libthread_db compatible with the inferior.\n\
Standard system libthread_db still gets loaded even with this option off.\n\
-This options has security implications for untrusted inferiors."),
+This option has security implications for untrusted inferiors."),
NULL, show_auto_load_thread_db,
auto_load_set_cmdlist_get (),
auto_load_show_cmdlist_get ());