X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fthread-db.c;h=1ffb79d5c108ac0aa539e31937602f06c6ffc601;hb=61baf725eca99af2569262d10aca03dcde2698f6;hp=d69c9e43f81f89f8f338a047e4480834e1625fd9;hpb=125f8a3ddedd413a2290dae011f0bed9ffc78278;p=external%2Fbinutils.git diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index d69c9e4..1ffb79d 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -1,5 +1,5 @@ /* Thread management interface, for the remote server for GDB. - Copyright (C) 2002-2014 Free Software Foundation, Inc. + Copyright (C) 2002-2017 Free Software Foundation, Inc. Contributed by MontaVista Software. @@ -24,17 +24,14 @@ extern int debug_threads; -static int thread_db_use_events; - #include "gdb_proc_service.h" #include "nat/gdb_thread_db.h" #include "gdb_vecs.h" +#include "nat/linux-procfs.h" #ifndef USE_LIBTHREAD_DB_DIRECTLY #include #endif - -#include #include #include @@ -57,41 +54,14 @@ struct thread_db void *handle; #endif - /* 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. Note that if the - running kernel supports tracing clones, then we don't need to use - (and in fact don't use) this magic thread event breakpoint to - learn about threads. */ - struct breakpoint *td_create_bp; - /* Addresses of libthread_db functions. */ - td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta); - td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta, - td_event_msg_t *msg); - td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta, - td_thr_events_t *event); - 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_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid, - 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_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_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); - const char ** (*td_symbol_list_p) (void); + td_ta_new_ftype *td_ta_new_p; + td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p; + td_thr_get_info_ftype *td_thr_get_info_p; + td_ta_thr_iter_ftype *td_ta_thr_iter_p; + td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p; + td_thr_tlsbase_ftype *td_thr_tlsbase_p; + td_symbol_list_ftype *td_symbol_list_p; }; static char *libthread_db_search_path; @@ -186,85 +156,6 @@ thread_db_state_str (td_thr_state_e state) #endif static int -thread_db_create_event (CORE_ADDR where) -{ - td_event_msg_t msg; - td_err_e err; - struct lwp_info *lwp; - struct thread_db *thread_db = current_process ()->private->thread_db; - - if (thread_db->td_ta_event_getmsg_p == NULL) - fatal ("unexpected thread_db->td_ta_event_getmsg_p == NULL"); - - if (debug_threads) - debug_printf ("Thread creation event.\n"); - - /* FIXME: This assumes we don't get another event. - In the LinuxThreads implementation, this is safe, - because all events come from the manager thread - (except for its own creation, of course). */ - err = thread_db->td_ta_event_getmsg_p (thread_db->thread_agent, &msg); - if (err != TD_OK) - fprintf (stderr, "thread getmsg err: %s\n", - thread_db_err_str (err)); - - /* If we do not know about the main thread yet, this would be a good time to - find it. We need to do this to pick up the main thread before any newly - created threads. */ - lwp = get_thread_lwp (current_inferior); - if (lwp->thread_known == 0) - find_one_thread (current_inferior->entry.id); - - /* msg.event == TD_EVENT_CREATE */ - - find_new_threads_callback (msg.th_p, NULL); - - return 0; -} - -static int -thread_db_enable_reporting (void) -{ - td_thr_events_t events; - td_notify_t notify; - td_err_e err; - struct thread_db *thread_db = current_process ()->private->thread_db; - - if (thread_db->td_ta_set_event_p == NULL - || thread_db->td_ta_event_addr_p == NULL - || thread_db->td_ta_event_getmsg_p == NULL) - /* This libthread_db is missing required support. */ - return 0; - - /* Set the process wide mask saying which events we're interested in. */ - td_event_emptyset (&events); - td_event_addset (&events, TD_CREATE); - - err = thread_db->td_ta_set_event_p (thread_db->thread_agent, &events); - if (err != TD_OK) - { - warning ("Unable to set global thread event mask: %s", - thread_db_err_str (err)); - return 0; - } - - /* Get address for thread creation breakpoint. */ - err = thread_db->td_ta_event_addr_p (thread_db->thread_agent, TD_CREATE, - ¬ify); - if (err != TD_OK) - { - warning ("Unable to get location for thread creation breakpoint: %s", - thread_db_err_str (err)); - return 0; - } - thread_db->td_create_bp - = set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr, - thread_db_create_event); - - return 1; -} - -static int find_one_thread (ptid_t ptid) { td_thrhandle_t th; @@ -272,7 +163,7 @@ find_one_thread (ptid_t ptid) td_err_e err; struct thread_info *inferior; struct lwp_info *lwp; - struct thread_db *thread_db = current_process ()->private->thread_db; + struct thread_db *thread_db = current_process ()->priv->thread_db; int lwpid = ptid_get_lwp (ptid); inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid); @@ -293,7 +184,7 @@ find_one_thread (ptid_t ptid) if (debug_threads) debug_printf ("Found thread %ld (LWP %d)\n", - ti.ti_tid, ti.ti_lid); + (unsigned long) ti.ti_tid, ti.ti_lid); if (lwpid != ti.ti_lid) { @@ -302,14 +193,6 @@ find_one_thread (ptid_t ptid) return 0; } - if (thread_db_use_events) - { - err = thread_db->td_thr_event_enable_p (&th, 1); - if (err != TD_OK) - error ("Cannot enable thread event reporting for %d: %s", - ti.ti_lid, thread_db_err_str (err)); - } - /* If the new thread ID is zero, a final thread ID will be available later. Do not enable thread debugging yet. */ if (ti.ti_tid == 0) @@ -334,13 +217,13 @@ attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) if (debug_threads) debug_printf ("Attaching to thread %ld (LWP %d)\n", - ti_p->ti_tid, ti_p->ti_lid); + (unsigned long) ti_p->ti_tid, ti_p->ti_lid); err = linux_attach_lwp (ptid); if (err != 0) { warning ("Could not attach to thread %ld (LWP %d): %s\n", - ti_p->ti_tid, ti_p->ti_lid, - linux_attach_fail_reason_string (ptid, err)); + (unsigned long) ti_p->ti_tid, ti_p->ti_lid, + linux_ptrace_attach_fail_reason_string (ptid, err)); return 0; } @@ -349,17 +232,6 @@ attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) lwp->thread_known = 1; lwp->th = *th_p; - if (thread_db_use_events) - { - td_err_e err; - struct thread_db *thread_db = proc->private->thread_db; - - err = thread_db->td_thr_event_enable_p (th_p, 1); - if (err != TD_OK) - error ("Cannot enable thread event reporting for %d: %s", - ti_p->ti_lid, thread_db_err_str (err)); - } - return 1; } @@ -391,12 +263,27 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data) { td_thrinfo_t ti; td_err_e err; - struct thread_db *thread_db = current_process ()->private->thread_db; + struct thread_db *thread_db = current_process ()->priv->thread_db; err = thread_db->td_thr_get_info_p (th_p, &ti); if (err != TD_OK) error ("Cannot get thread info: %s", thread_db_err_str (err)); + if (ti.ti_lid == -1) + { + /* A thread with kernel thread ID -1 is either a thread that + exited and was joined, or a thread that is being created but + hasn't started yet, and that is reusing the tcb/stack of a + thread that previously exited and was joined. (glibc marks + terminated and joined threads with kernel thread ID -1. See + glibc PR17707. */ + if (debug_threads) + debug_printf ("thread_db: skipping exited and " + "joined thread (0x%lx)\n", + (unsigned long) ti.ti_tid); + return 0; + } + /* Check for zombies. */ if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) return 0; @@ -416,7 +303,7 @@ thread_db_find_new_threads (void) { td_err_e err; ptid_t ptid = current_ptid; - struct thread_db *thread_db = current_process ()->private->thread_db; + struct thread_db *thread_db = current_process ()->priv->thread_db; int loop, iteration; /* This function is only called when we first initialize thread_db. @@ -462,7 +349,7 @@ thread_db_find_new_threads (void) static void thread_db_look_up_symbols (void) { - struct thread_db *thread_db = current_process ()->private->thread_db; + struct thread_db *thread_db = current_process ()->priv->thread_db; const char **sym_list; CORE_ADDR unused; @@ -477,7 +364,7 @@ thread_db_look_up_symbols (void) int thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp) { - struct thread_db *thread_db = current_process ()->private->thread_db; + struct thread_db *thread_db = current_process ()->priv->thread_db; int may_ask_gdb = !thread_db->all_symbols_looked_up; /* If we've passed the call to thread_db_look_up_symbols, then @@ -495,12 +382,12 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, psaddr_t addr; td_err_e err; struct lwp_info *lwp; - struct thread_info *saved_inferior; + struct thread_info *saved_thread; struct process_info *proc; struct thread_db *thread_db; proc = get_thread_process (thread); - thread_db = proc->private->thread_db; + thread_db = proc->priv->thread_db; /* If the thread layer is not (yet) initialized, fail. */ if (thread_db == NULL || !thread_db->all_symbols_looked_up) @@ -518,8 +405,8 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, if (!lwp->thread_known) return TD_NOTHR; - saved_inferior = current_inferior; - current_inferior = thread; + saved_thread = current_thread; + current_thread = thread; if (load_module != 0) { @@ -542,7 +429,7 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, addr = (char *) addr + offset; } - current_inferior = saved_inferior; + current_thread = saved_thread; if (err == TD_OK) { *address = (CORE_ADDR) (uintptr_t) addr; @@ -561,11 +448,10 @@ thread_db_load_search (void) struct thread_db *tdb; struct process_info *proc = current_process (); - if (proc->private->thread_db != NULL) - fatal ("unexpected: proc->private->thread_db != NULL"); + gdb_assert (proc->priv->thread_db == NULL); - tdb = xcalloc (1, sizeof (*tdb)); - proc->private->thread_db = tdb; + tdb = XCNEW (struct thread_db); + proc->priv->thread_db = tdb; tdb->td_ta_new_p = &td_ta_new; @@ -576,7 +462,7 @@ thread_db_load_search (void) if (debug_threads) debug_printf ("td_ta_new(): %s\n", thread_db_err_str (err)); free (tdb); - proc->private->thread_db = NULL; + proc->priv->thread_db = NULL; return 0; } @@ -585,13 +471,7 @@ thread_db_load_search (void) tdb->td_ta_thr_iter_p = &td_ta_thr_iter; tdb->td_symbol_list_p = &td_symbol_list; - /* This is required only when thread_db_use_events is on. */ - tdb->td_thr_event_enable_p = &td_thr_event_enable; - /* These are not essential. */ - tdb->td_ta_event_addr_p = &td_ta_event_addr; - tdb->td_ta_set_event_p = &td_ta_set_event; - tdb->td_ta_event_getmsg_p = &td_ta_event_getmsg; tdb->td_thr_tls_get_addr_p = &td_thr_tls_get_addr; tdb->td_thr_tlsbase_p = &td_thr_tlsbase; @@ -607,11 +487,10 @@ try_thread_db_load_1 (void *handle) struct thread_db *tdb; struct process_info *proc = current_process (); - if (proc->private->thread_db != NULL) - fatal ("unexpected: proc->private->thread_db != NULL"); + gdb_assert (proc->priv->thread_db == NULL); - tdb = xcalloc (1, sizeof (*tdb)); - proc->private->thread_db = tdb; + tdb = XCNEW (struct thread_db); + proc->priv->thread_db = tdb; tdb->handle = handle; @@ -628,14 +507,17 @@ try_thread_db_load_1 (void *handle) if (required) \ { \ free (tdb); \ - proc->private->thread_db = NULL; \ + proc->priv->thread_db = NULL; \ return 0; \ } \ } \ } \ while (0) - CHK (1, tdb->td_ta_new_p = dlsym (handle, "td_ta_new")); +#define TDB_DLSYM(tdb, func) \ + tdb->func ## _p = (func ## _ftype *) dlsym (tdb->handle, #func) + + CHK (1, TDB_DLSYM (tdb, td_ta_new)); /* Attempt to open a connection to the thread library. */ err = tdb->td_ta_new_p (&tdb->proc_handle, &tdb->thread_agent); @@ -644,27 +526,21 @@ try_thread_db_load_1 (void *handle) if (debug_threads) debug_printf ("td_ta_new(): %s\n", thread_db_err_str (err)); free (tdb); - proc->private->thread_db = NULL; + proc->priv->thread_db = NULL; return 0; } - CHK (1, tdb->td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr")); - CHK (1, tdb->td_thr_get_info_p = dlsym (handle, "td_thr_get_info")); - CHK (1, tdb->td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter")); - CHK (1, tdb->td_symbol_list_p = dlsym (handle, "td_symbol_list")); - - /* This is required only when thread_db_use_events is on. */ - CHK (thread_db_use_events, - tdb->td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable")); + CHK (1, TDB_DLSYM (tdb, td_ta_map_lwp2thr)); + CHK (1, TDB_DLSYM (tdb, td_thr_get_info)); + CHK (1, TDB_DLSYM (tdb, td_ta_thr_iter)); + CHK (1, TDB_DLSYM (tdb, td_symbol_list)); /* These are not essential. */ - CHK (0, tdb->td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr")); - CHK (0, tdb->td_ta_set_event_p = dlsym (handle, "td_ta_set_event")); - CHK (0, tdb->td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg")); - CHK (0, tdb->td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr")); - CHK (0, tdb->td_thr_tlsbase_p = dlsym (handle, "td_thr_tlsbase")); + CHK (0, TDB_DLSYM (tdb, td_thr_tls_get_addr)); + CHK (0, TDB_DLSYM (tdb, td_thr_tlsbase)); #undef CHK +#undef TDB_DLSYM return 1; } @@ -714,8 +590,7 @@ try_thread_db_load (const char *library) const char *const libpath = dladdr_to_soname (td_init); if (libpath != NULL) - fprintf (stderr, "Host %s resolved to: %s.\n", - library, libpath); + debug_printf ("Host %s resolved to: %s.\n", library, libpath); } } #endif @@ -749,7 +624,7 @@ try_thread_db_load_from_dir (const char *dir, size_t dir_len) if (dir_len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path)) { - char *cp = xmalloc (dir_len + 1); + char *cp = (char *) xmalloc (dir_len + 1); memcpy (cp, dir, dir_len); cp[dir_len] = '\0'; @@ -823,7 +698,7 @@ thread_db_load_search (void) #endif /* USE_LIBTHREAD_DB_DIRECTLY */ int -thread_db_init (int use_events) +thread_db_init (void) { struct process_info *proc = current_process (); @@ -831,24 +706,26 @@ thread_db_init (int use_events) GNU/Linux calls tgid, "thread group ID". When we support attaching to threads, the original thread may not be the correct thread. We would have to get the process ID from /proc for NPTL. - For LinuxThreads we could do something similar: follow the chain - of parent processes until we find the highest one we're attached - to, and use its tgid. This isn't the only place in gdbserver that assumes that the first process in the list is the thread group leader. */ - thread_db_use_events = use_events; - if (thread_db_load_search ()) { - if (use_events && thread_db_enable_reporting () == 0) - { - /* Keep trying; maybe event reporting will work later. */ - thread_db_mourn (proc); - return 0; - } - thread_db_find_new_threads (); + /* 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, or, if the target is running, the list may change + while we walk it. In the latter case, it's possible that a + thread exits just at the exact time that causes GDBserver to + get stuck in an infinite loop. As the kernel supports clone + events and /proc/PID/task/ exists, then we already know about + all threads in the process. When we need info out of + thread_db on a given thread (e.g., for TLS), we'll use + find_one_thread then. That uses thread_db entry points that + do not walk libpthread's thread list, so should be safe, as + well as more efficient. */ + if (!linux_proc_task_list_dir_exists (pid_of (proc))) + thread_db_find_new_threads (); thread_db_look_up_symbols (); return 1; } @@ -859,7 +736,7 @@ thread_db_init (int use_events) static int any_thread_of (struct inferior_list_entry *entry, void *args) { - int *pid_p = args; + int *pid_p = (int *) args; if (ptid_get_pid (entry->id) == *pid_p) return 1; @@ -872,7 +749,7 @@ switch_to_process (struct process_info *proc) { int pid = pid_of (proc); - current_inferior = + current_thread = (struct thread_info *) find_inferior (&all_threads, any_thread_of, &pid); } @@ -882,21 +759,23 @@ switch_to_process (struct process_info *proc) static void disable_thread_event_reporting (struct process_info *proc) { - struct thread_db *thread_db = proc->private->thread_db; + struct thread_db *thread_db = proc->priv->thread_db; if (thread_db) { td_err_e (*td_ta_clear_event_p) (const td_thragent_t *ta, td_thr_events_t *event); #ifndef USE_LIBTHREAD_DB_DIRECTLY - td_ta_clear_event_p = dlsym (thread_db->handle, "td_ta_clear_event"); + td_ta_clear_event_p + = (td_ta_clear_event_ftype *) dlsym (thread_db->handle, + "td_ta_clear_event"); #else td_ta_clear_event_p = &td_ta_clear_event; #endif if (td_ta_clear_event_p != NULL) { - struct thread_info *saved_inferior = current_inferior; + struct thread_info *saved_thread = current_thread; td_thr_events_t events; switch_to_process (proc); @@ -906,38 +785,19 @@ disable_thread_event_reporting (struct process_info *proc) td_event_fillset (&events); (*td_ta_clear_event_p) (thread_db->thread_agent, &events); - current_inferior = saved_inferior; + current_thread = saved_thread; } } } -static void -remove_thread_event_breakpoints (struct process_info *proc) -{ - struct thread_db *thread_db = proc->private->thread_db; - - if (thread_db->td_create_bp != NULL) - { - struct thread_info *saved_inferior = current_inferior; - - switch_to_process (proc); - - delete_breakpoint (thread_db->td_create_bp); - thread_db->td_create_bp = NULL; - - current_inferior = saved_inferior; - } -} - void thread_db_detach (struct process_info *proc) { - struct thread_db *thread_db = proc->private->thread_db; + struct thread_db *thread_db = proc->priv->thread_db; if (thread_db) { disable_thread_event_reporting (proc); - remove_thread_event_breakpoints (proc); } } @@ -946,13 +806,13 @@ thread_db_detach (struct process_info *proc) void thread_db_mourn (struct process_info *proc) { - struct thread_db *thread_db = proc->private->thread_db; + struct thread_db *thread_db = proc->priv->thread_db; if (thread_db) { - td_err_e (*td_ta_delete_p) (td_thragent_t *); + td_ta_delete_ftype *td_ta_delete_p; #ifndef USE_LIBTHREAD_DB_DIRECTLY - td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete"); + td_ta_delete_p = (td_ta_delete_ftype *) dlsym (thread_db->handle, "td_ta_delete"); #else td_ta_delete_p = &td_ta_delete; #endif @@ -965,7 +825,7 @@ thread_db_mourn (struct process_info *proc) #endif /* USE_LIBTHREAD_DB_DIRECTLY */ free (thread_db); - proc->private->thread_db = NULL; + proc->priv->thread_db = NULL; } }