*listp = new_pid;
}
-static int
-in_pid_list_p (struct simple_pid_list *list, int pid)
-{
- struct simple_pid_list *p;
-
- for (p = list; p != NULL; p = p->next)
- if (p->pid == pid)
- return 1;
- return 0;
-}
-
static int
pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
{
return status;
}
-/* Attach to the LWP specified by PID. Return 0 if successful, -1 if
- the new LWP could not be attached, or 1 if we're already auto
- attached to this thread, but haven't processed the
- PTRACE_EVENT_CLONE event of its parent thread, so we just ignore
- its existance, without considering it an error. */
-
-int
-lin_lwp_attach_lwp (ptid_t ptid)
-{
- struct lwp_info *lp;
- int lwpid;
-
- gdb_assert (ptid_lwp_p (ptid));
-
- lp = find_lwp_pid (ptid);
- lwpid = ptid_get_lwp (ptid);
-
- /* We assume that we're already attached to any LWP that is already
- in our list of LWPs. If we're not seeing exit events from threads
- and we've had PID wraparound since we last tried to stop all threads,
- this assumption might be wrong; fortunately, this is very unlikely
- to happen. */
- if (lp == NULL)
- {
- int status, cloned = 0, signalled = 0;
-
- if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) < 0)
- {
- if (linux_supports_tracefork ())
- {
- /* If we haven't stopped all threads when we get here,
- we may have seen a thread listed in thread_db's list,
- but not processed the PTRACE_EVENT_CLONE yet. If
- that's the case, ignore this new thread, and let
- normal event handling discover it later. */
- if (in_pid_list_p (stopped_pids, lwpid))
- {
- /* We've already seen this thread stop, but we
- haven't seen the PTRACE_EVENT_CLONE extended
- event yet. */
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLAL: attach failed, but already seen "
- "this thread %s stop\n",
- target_pid_to_str (ptid));
- return 1;
- }
- else
- {
- int new_pid;
- int status;
-
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLAL: attach failed, and haven't seen "
- "this thread %s stop yet\n",
- target_pid_to_str (ptid));
-
- /* We may or may not be attached to the LWP already.
- Try waitpid on it. If that errors, we're not
- attached to the LWP yet. Otherwise, we're
- already attached. */
- gdb_assert (lwpid > 0);
- new_pid = my_waitpid (lwpid, &status, WNOHANG);
- if (new_pid == -1 && errno == ECHILD)
- new_pid = my_waitpid (lwpid, &status, __WCLONE | WNOHANG);
- if (new_pid != -1)
- {
- if (new_pid == 0)
- {
- /* The child hasn't stopped for its initial
- SIGSTOP stop yet. */
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLAL: child hasn't "
- "stopped yet\n");
- }
- else if (WIFSTOPPED (status))
- {
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLAL: adding to stopped_pids\n");
- add_to_pid_list (&stopped_pids, lwpid, status);
- }
- return 1;
- }
- }
- }
-
- /* If we fail to attach to the thread, issue a warning,
- but continue. One way this can happen is if thread
- creation is interrupted; as of Linux kernel 2.6.19, a
- bug may place threads in the thread list and then fail
- to create them. */
- warning (_("Can't attach %s: %s"), target_pid_to_str (ptid),
- safe_strerror (errno));
- return -1;
- }
-
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
- target_pid_to_str (ptid));
-
- status = linux_nat_post_attach_wait (ptid, 0, &cloned, &signalled);
- if (!WIFSTOPPED (status))
- return 1;
-
- lp = add_lwp (ptid);
- lp->stopped = 1;
- lp->last_resume_kind = resume_stop;
- lp->cloned = cloned;
- lp->signalled = signalled;
- if (WSTOPSIG (status) != SIGSTOP)
- {
- lp->resumed = 1;
- lp->status = status;
- }
-
- target_post_attach (ptid_get_lwp (lp->ptid));
-
- if (debug_linux_nat)
- {
- fprintf_unfiltered (gdb_stdlog,
- "LLAL: waitpid %s received %s\n",
- target_pid_to_str (ptid),
- status_to_str (status));
- }
- }
-
- return 0;
-}
-
static void
linux_nat_create_inferior (struct target_ops *ops,
char *exec_file, char *allargs, char **env,
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
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;
};
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);
-\f
-
/* Use "struct private_thread_info" to cache thread state. This is
a substantial optimization. */
return buf;
}
}
-\f
-/* 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;
-}
-\f
/* Fetch the user-level thread id of PTID. */
static struct thread_info *
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, ¬ify);
- 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),
- ¤t_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. */
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.
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);
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;
}
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)
{
|| 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. */
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)
{
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);
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,
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);
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);
/* 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;
}
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;
}
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
{
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);