Remove support for thread events without PTRACE_EVENT_CLONE in GDB

Before, on systems that did not support PTRACE_EVENT_CLONE, both GDB and
GDBServer coordinated with libthread_db.so to insert breakpoints at magic
locations in libpthread.so, in order to break at thread creation and
thread death.

Support for thread events was removed from GDBServer as patch:
https://sourceware.org/ml/gdb-patches/2015-11/msg00466.html

This patch removes support for thread events in GDB.

No regressions found on Ubuntu 14.04 x86_64.

gdb/ChangeLog:

	* breakpoint.c (remove_thread_event_breakpoints): Remove.
	* breakpoint.h (remove_thread_event_breakpoints): Remove
	declaration.
	* linux-nat.c (in_pid_list_p): Remove.
	(lin_lwp_attach_lwp): Remove.
	* linux-nat.h (lin_lwp_attach_lwp): Remove declaration.
	* linux-thread-db.c (thread_db_use_events): Remove.
	(struct thread_db_info) <td_create_bp_addr>: Remove.
	<td_death_bp_addr>: Likewise.
	<td_ta_event_addr_p>: Likewise.
	<td_ta_set_event_p>: Likewise.
	<td_ta_clear_event_p>: Likewise.
	<td_ta_event_getmsg_p>: Likewise.
	<td_thr_event_enable_p>: Likewise.
	(attach_thread): Likewise.
	(detach_thread): Likewise.
	(have_threads_callback): Likewise.
	(have_threads): Likewise.
	(enable_thread_event): Likewise.
	(enable_thread_event_reporting): Likewise.
	(try_thread_db_load_1): Remove td_ta_event_addr, td_ta_set_event,
	td_ta_clear_event, td_ta_event_getmsg, td_thr_event_enable
	initializations.
	(try_thread_db_load_1): Remove enable_thread_event_reporting call.
	(disable_thread_event_reporting): Remove.
	(record_thread): Adapt to thread_db_use_event removal.
	(detach_thread): Remove.
	(thread_db_detach): Adapt to thread_db_use_event removal.
	(check_event): Remove.
	(thread_db_wait): Adapt to thread events support removal.
	(thread_db_mourn_inferior): Likewise.
	(find_new_threads_callback): Likewise.
	(find_new_threads_once): Likewise.
	(thread_db_update_thread_list): Likewise.
This commit is contained in:
Antoine Tremblay 2015-12-10 10:44:08 -05:00
parent 47f8114261
commit c2c2a31fdb
6 changed files with 46 additions and 587 deletions

View file

@ -78,16 +78,6 @@ static char *libthread_db_search_path;
by the "set auto-load libthread-db" command. */
static int auto_load_thread_db = 1;
/* Returns true if we need to use thread_db thread create/death event
breakpoints to learn about threads. */
static int
thread_db_use_events (void)
{
/* Not necessary if the kernel supports clone events. */
return !linux_supports_traceclone ();
}
/* "show" command for the auto_load_thread_db configuration variable. */
static void
@ -161,30 +151,14 @@ struct thread_db_info
be able to ignore such stale entries. */
int need_stale_parent_threads_check;
/* 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_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;
};
@ -273,12 +247,6 @@ delete_thread_db_info (int pid)
xfree (info);
}
/* Prototypes for local functions. */
static int attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
const td_thrinfo_t *ti_p);
static void detach_thread (ptid_t ptid);
/* Use "struct private_thread_info" to cache thread state. This is
a substantial optimization. */
@ -359,30 +327,7 @@ thread_db_err_str (td_err_e err)
return buf;
}
}
/* Return 1 if any threads have been registered. There may be none if
the threading library is not fully initialized yet. */
static int
have_threads_callback (struct thread_info *thread, void *args)
{
int pid = * (int *) args;
if (ptid_get_pid (thread->ptid) != pid)
return 0;
return thread->priv != NULL;
}
static int
have_threads (ptid_t ptid)
{
int pid = ptid_get_pid (ptid);
return iterate_over_threads (have_threads_callback, &pid) != NULL;
}
/* Fetch the user-level thread id of PTID. */
static struct thread_info *
@ -455,37 +400,6 @@ verbose_dlsym (void *handle, const char *name)
return sym;
}
static td_err_e
enable_thread_event (td_event_e event, CORE_ADDR *bp)
{
td_notify_t notify;
td_err_e err;
struct thread_db_info *info;
info = get_thread_db_info (ptid_get_pid (inferior_ptid));
/* Access an lwp we know is stopped. */
info->proc_handle.ptid = inferior_ptid;
/* Get the breakpoint address for thread EVENT. */
err = info->td_ta_event_addr_p (info->thread_agent, event, &notify);
if (err != TD_OK)
return err;
/* Set up the breakpoint. */
gdb_assert (exec_bfd);
(*bp) = (gdbarch_convert_from_func_ptr_addr
(target_gdbarch (),
/* Do proper sign extension for the target. */
(bfd_get_sign_extend_vma (exec_bfd) > 0
? (CORE_ADDR) (intptr_t) notify.u.bptaddr
: (CORE_ADDR) (uintptr_t) notify.u.bptaddr),
&current_target));
create_thread_event_breakpoint (target_gdbarch (), *bp);
return TD_OK;
}
/* Verify inferior's '\0'-terminated symbol VER_SYMBOL starts with "%d.%d" and
return 1 if this version is lower (and not equal) to
VER_MAJOR_MIN.VER_MINOR_MIN. Return 0 in all other cases. */
@ -517,68 +431,6 @@ inferior_has_bug (const char *ver_symbol, int ver_major_min, int ver_minor_min)
return retval;
}
static void
enable_thread_event_reporting (void)
{
td_thr_events_t events;
td_err_e err;
struct thread_db_info *info;
info = get_thread_db_info (ptid_get_pid (inferior_ptid));
/* We cannot use the thread event reporting facility if these
functions aren't available. */
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. */
td_event_emptyset (&events);
td_event_addset (&events, TD_CREATE);
/* There is a bug fixed between linuxthreads 2.1.3 and 2.2 by
commit 2e4581e4fba917f1779cd0a010a45698586c190a
* manager.c (pthread_exited): Correctly report event as TD_REAP
instead of TD_DEATH. Fix comments.
where event reporting facility is broken for TD_DEATH events,
so don't enable it if we have glibc but a lower version. */
if (!inferior_has_bug ("__linuxthreads_version", 2, 2))
td_event_addset (&events, TD_DEATH);
err = info->td_ta_set_event_p (info->thread_agent, &events);
if (err != TD_OK)
{
warning (_("Unable to set global thread event mask: %s"),
thread_db_err_str (err));
return;
}
/* Delete previous thread event breakpoints, if any. */
remove_thread_event_breakpoints ();
info->td_create_bp_addr = 0;
info->td_death_bp_addr = 0;
/* Set up the thread creation event. */
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"),
thread_db_err_str (err));
return;
}
/* Set up the thread death event. */
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"),
thread_db_err_str (err));
return;
}
}
/* Similar as thread_db_find_new_threads_1, but try to silently ignore errors
if appropriate.
@ -716,11 +568,6 @@ try_thread_db_load_1 (struct thread_db_info *info)
CHK (TDB_VERBOSE_DLSYM (info, td_thr_get_info));
/* These are not essential. */
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);
@ -784,10 +631,6 @@ try_thread_db_load_1 (struct thread_db_info *info)
if (thread_db_list->next == NULL)
push_target (&thread_db_ops);
/* Enable event reporting, but not when debugging a core file. */
if (target_has_execution && thread_db_use_events ())
enable_thread_event_reporting ();
return 1;
}
@ -1095,23 +938,6 @@ thread_db_load (void)
return 0;
}
static void
disable_thread_event_reporting (struct thread_db_info *info)
{
if (info->td_ta_clear_event_p != NULL)
{
td_thr_events_t events;
/* Set the process wide mask saying we aren't interested in any
events anymore. */
td_event_fillset (&events);
info->td_ta_clear_event_p (info->thread_agent, &events);
}
info->td_create_bp_addr = 0;
info->td_death_bp_addr = 0;
}
static void
check_thread_signals (void)
{
@ -1219,75 +1045,6 @@ update_thread_state (struct private_thread_info *priv,
|| ti_p->ti_state == TD_THR_ZOMBIE);
}
/* Attach to a new thread. This function is called when we receive a
TD_CREATE event or when we iterate over all threads and find one
that wasn't already in our list. Returns true on success. */
static int
attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
const td_thrinfo_t *ti_p)
{
struct thread_info *tp;
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
may have iterated over all threads between the thread creation
and the TD_CREATE event, for instance when the user has issued
the `info threads' command before the SIGTRAP for hitting the
thread creation breakpoint was reported. Alternatively, the
thread may have exited and a new one been created with the same
thread ID. In the first case we don't need to do anything; in
the second case we should discard information about the dead
thread and attach to the new one. */
tp = find_thread_ptid (ptid);
if (tp != NULL)
{
/* If tp->priv is NULL, then GDB is already attached to this
thread, but we do not know anything about it. We can learn
about it here. This can only happen if we have some other
way besides libthread_db to notice new threads (i.e.
PTRACE_EVENT_CLONE); assume the same mechanism notices thread
exit, so this can not be a stale thread recreated with the
same ID. */
if (tp->priv != NULL)
{
if (!tp->priv->dying)
return 0;
delete_thread (ptid);
tp = NULL;
}
}
/* Under GNU/Linux, we have to attach to each and every thread. */
if (target_has_execution
&& tp == NULL)
{
int res;
res = lin_lwp_attach_lwp (ptid_build (ptid_get_pid (ptid),
ti_p->ti_lid, 0));
if (res < 0)
{
/* Error, stop iterating. */
return 0;
}
else if (res > 0)
{
/* Pretend this thread doesn't exist yet, and keep
iterating. */
return 1;
}
/* Otherwise, we sucessfully attached to the thread. */
}
info = get_thread_db_info (ptid_get_pid (ptid));
record_thread (info, tp, ptid, th_p, ti_p);
return 1;
}
/* Record a new thread in GDB's thread list. Creates the thread's
private info. If TP is NULL or TP is marked as having exited,
creates a new thread. Otherwise, uses TP. */
@ -1323,40 +1080,12 @@ record_thread (struct thread_db_info *info,
else
tp->priv = priv;
/* Enable thread event reporting for this thread, except when
debugging a core file. */
if (target_has_execution && thread_db_use_events () && new_thread)
{
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));
}
if (target_has_execution)
check_thread_signals ();
return tp;
}
static void
detach_thread (ptid_t ptid)
{
struct thread_info *thread_info;
/* Don't delete the thread now, because it still reports as active
until it has executed a few instructions after the event
breakpoint - if we deleted it now, "info threads" would cause us
to re-attach to it. Just mark it as having had a TD_DEATH
event. This means that we won't delete it from our thread list
until we notice that it's dead (via prune_threads), or until
something re-uses its thread ID. We'll report the thread exit
when the underlying LWP dies. */
thread_info = find_thread_ptid (ptid);
gdb_assert (thread_info != NULL && thread_info->priv != NULL);
thread_info->priv->dying = 1;
}
static void
thread_db_detach (struct target_ops *ops, const char *args, int from_tty)
{
@ -1366,21 +1095,7 @@ thread_db_detach (struct target_ops *ops, const char *args, int from_tty)
info = get_thread_db_info (ptid_get_pid (inferior_ptid));
if (info)
{
if (target_has_execution && thread_db_use_events ())
{
disable_thread_event_reporting (info);
/* 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 (ptid_get_pid (inferior_ptid));
}
delete_thread_db_info (ptid_get_pid (inferior_ptid));
target_beneath->to_detach (target_beneath, args, from_tty);
@ -1392,101 +1107,6 @@ thread_db_detach (struct target_ops *ops, const char *args, int from_tty)
unpush_target (&thread_db_ops);
}
/* Check if PID is currently stopped at the location of a thread event
breakpoint location. If it is, read the event message and act upon
the event. */
static void
check_event (ptid_t ptid)
{
struct regcache *regcache = get_thread_regcache (ptid);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
td_event_msg_t msg;
td_thrinfo_t ti;
td_err_e err;
CORE_ADDR stop_pc;
int loop = 0;
struct thread_db_info *info;
info = get_thread_db_info (ptid_get_pid (ptid));
/* Bail out early if we're not at a thread event breakpoint. */
stop_pc = regcache_read_pc (regcache);
if (!target_supports_stopped_by_sw_breakpoint ())
stop_pc -= gdbarch_decr_pc_after_break (gdbarch);
if (stop_pc != info->td_create_bp_addr
&& stop_pc != info->td_death_bp_addr)
return;
/* Access an lwp we know is stopped. */
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 (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.
We have to call td_ta_event_getmsg() to get
the latest message. Since we have no way of correlating whether
the event message we get back corresponds to our breakpoint, we must
loop and read all event messages, processing them appropriately.
This guarantees we will process the correct message before continuing
from the breakpoint.
Currently, death events are not enabled. If they are enabled,
the death event can use the td_thr_event_getmsg() interface to
get the message specifically for that lwp and avoid looping
below. */
loop = 1;
do
{
err = info->td_ta_event_getmsg_p (info->thread_agent, &msg);
if (err != TD_OK)
{
if (err == TD_NOMSG)
return;
error (_("Cannot get thread event message: %s"),
thread_db_err_str (err));
}
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));
ptid = ptid_build (ptid_get_pid (ptid), ti.ti_lid, 0);
switch (msg.event)
{
case TD_CREATE:
/* Call attach_thread whether or not we already know about a
thread with this thread ID. */
attach_thread (ptid, msg.th_p, &ti);
break;
case TD_DEATH:
if (!in_thread_list (ptid))
error (_("Spurious thread death event."));
detach_thread (ptid);
break;
default:
error (_("Spurious thread event."));
}
}
while (loop);
}
static ptid_t
thread_db_wait (struct target_ops *ops,
ptid_t ptid, struct target_waitstatus *ourstatus,
@ -1518,17 +1138,9 @@ thread_db_wait (struct target_ops *ops,
if (!thread_db_list)
unpush_target (&thread_db_ops);
/* Thread event breakpoints are deleted by
update_breakpoints_after_exec. */
return ptid;
}
if (ourstatus->kind == TARGET_WAITKIND_STOPPED
&& ourstatus->value.sig == GDB_SIGNAL_TRAP)
/* Check for a thread event. */
check_event (ptid);
/* Fill in the thread's user-level thread id and status. */
thread_from_lwp (ptid);
@ -1544,10 +1156,6 @@ thread_db_mourn_inferior (struct target_ops *ops)
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. */
if (!thread_db_list)
unpush_target (ops);
@ -1595,21 +1203,12 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
/* A thread ID of zero means that this is the main thread, but
glibc has not yet initialized thread-local storage and the
pthread library. We do not know what the thread's TID will
be yet. Just enable event reporting and otherwise ignore
it. */
be yet. */
/* In that case, we're not stopped in a fork syscall and don't
need this glibc bug workaround. */
info->need_stale_parent_threads_check = 0;
if (target_has_execution && thread_db_use_events ())
{
err = info->td_thr_event_enable_p (th_p, 1);
if (err != TD_OK)
error (_("Cannot enable thread event reporting for LWP %d: %s"),
(int) ti.ti_lid, thread_db_err_str (err));
}
return 0;
}
@ -1627,24 +1226,7 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
ptid = ptid_build (info->pid, ti.ti_lid, 0);
tp = find_thread_ptid (ptid);
if (tp == NULL || tp->priv == NULL)
{
if (attach_thread (ptid, th_p, &ti))
cb_data->new_threads += 1;
else
/* Problem attaching this thread; perhaps it exited before we
could attach it?
This could mean that the thread list inside glibc itself is in
inconsistent state, and libthread_db could go on looping forever
(observed with glibc-2.3.6). To prevent that, terminate
iteration: thread_db_find_new_threads_2 will retry. */
return 1;
}
else if (target_has_execution && !thread_db_use_events ())
{
/* Need to update this if not using the libthread_db events
(particularly, the TD_DEATH event). */
update_thread_state (tp->priv, &ti);
}
thread_from_lwp (ptid);
return 0;
}
@ -1663,7 +1245,7 @@ find_new_threads_once (struct thread_db_info *info, int iteration,
data.new_threads = 0;
/* See comment in thread_db_update_thread_list. */
gdb_assert (!target_has_execution || thread_db_use_events ());
gdb_assert (!target_has_execution);
TRY
{
@ -1789,12 +1371,11 @@ thread_db_update_thread_list (struct target_ops *ops)
it. In the latter case, it's possible that a thread exits just
at the exact time that causes GDB to get stuck in an infinite
loop. To avoid pausing all threads whenever the core wants to
refresh the thread list, if the kernel supports clone events
(meaning we're always already attached to all LWPs), we use
thread_from_lwp immediately when we see an LWP stop. That uses
thread_db entry points that do not walk libpthread's thread list,
so should be safe, as well as more efficient. */
if (target_has_execution && !thread_db_use_events ())
refresh the thread list, use thread_from_lwp immediately when we
see an LWP stop. That uses thread_db entry points that do not
walk libpthread's thread list, so should be safe, as well as
more efficient. */
if (target_has_execution)
ops->beneath->to_update_thread_list (ops->beneath);
else
thread_db_update_thread_list_td_ta_thr_iter (ops);