-/* Structure that identifies the child process for the
- <proc_service.h> interface. */
-static struct ps_prochandle proc_handle;
-
-/* Connection to the libthread_db library. */
-static td_thragent_t *thread_agent;
-
-/* Pointers to the libthread_db functions. */
-
-static td_err_e (*td_init_p) (void);
-
-static td_err_e (*td_ta_new_p) (struct ps_prochandle * ps,
- td_thragent_t **ta);
-static td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt,
- td_thrhandle_t *__th);
-static td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta,
- lwpid_t lwpid, td_thrhandle_t *th);
-static 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);
-static td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
- td_event_e event, td_notify_t *ptr);
-static td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
- td_thr_events_t *event);
-static td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
- td_event_msg_t *msg);
-
-static td_err_e (*td_thr_validate_p) (const td_thrhandle_t *th);
-static td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
- td_thrinfo_t *infop);
-static td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th,
- int event);
-
-static td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
- void *map_address,
- size_t offset, void **address);
-
-/* 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. */
-static CORE_ADDR td_create_bp_addr;
-
-/* Location of the thread death event breakpoint. */
-static CORE_ADDR td_death_bp_addr;
-
-/* Prototypes for local functions. */
-static void thread_db_find_new_threads (void);
-static void 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
+struct thread_db_info
+{
+ struct thread_db_info *next;
+
+ /* The target this thread_db_info is bound to. */
+ process_stratum_target *process_target;
+
+ /* Process id this object refers to. */
+ int pid;
+
+ /* Handle from dlopen for libthread_db.so. */
+ void *handle;
+
+ /* Absolute pathname from gdb_realpath to disk file used for dlopen-ing
+ HANDLE. It may be NULL for system library. */
+ char *filename;
+
+ /* Structure that identifies the child process for the
+ <proc_service.h> interface. */
+ struct ps_prochandle proc_handle;
+
+ /* Connection to the libthread_db library. */
+ td_thragent_t *thread_agent;
+
+ /* True if we need to apply the workaround for glibc/BZ5983. When
+ we catch a PTRACE_O_TRACEFORK, and go query the child's thread
+ list, nptl_db returns the parent's threads in addition to the new
+ (single) child thread. If this flag is set, we do extra work to
+ be able to ignore such stale entries. */
+ int need_stale_parent_threads_check;
+
+ /* Pointers to the libthread_db functions. */
+
+ 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;
+ 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
+ bookkeeping. */
+struct thread_db_info *thread_db_list;
+
+static void thread_db_find_new_threads_1 (thread_info *stopped);
+static void thread_db_find_new_threads_2 (thread_info *stopped,
+ bool until_no_new);
+
+static void check_thread_signals (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, 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
+ THREAD_DB_LIST. HANDLE is the handle returned by dlopen'ing
+ LIBTHREAD_DB_SO. */
+
+static struct thread_db_info *
+add_thread_db_info (void *handle)
+{
+ struct thread_db_info *info = XCNEW (struct thread_db_info);
+
+ info->process_target = current_inferior ()->process_target ();
+ info->pid = inferior_ptid.pid ();
+ info->handle = handle;
+
+ /* The workaround works by reading from /proc/pid/status, so it is
+ disabled for core files. */
+ if (target_has_execution)
+ info->need_stale_parent_threads_check = 1;
+
+ info->next = thread_db_list;
+ thread_db_list = info;
+
+ return info;
+}
+
+/* Return the thread_db_info object representing the bookkeeping
+ related to process PID, if any; NULL otherwise. */
+
+static struct thread_db_info *
+get_thread_db_info (process_stratum_target *targ, int pid)
+{
+ struct thread_db_info *info;
+
+ for (info = thread_db_list; info; info = info->next)
+ if (targ == info->process_target && pid == info->pid)
+ return info;
+
+ 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
+ LIBTHREAD_DB_SO's dlopen'ed handle. */
+
+static void
+delete_thread_db_info (process_stratum_target *targ, int pid)
+{
+ struct thread_db_info *info, *info_prev;
+
+ info_prev = NULL;
+
+ for (info = thread_db_list; info; info_prev = info, info = info->next)
+ if (targ == info->process_target && pid == info->pid)
+ break;
+
+ 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);
+
+ xfree (info->filename);
+
+ if (info_prev)
+ info_prev->next = info->next;
+ else
+ thread_db_list = info->next;
+
+ xfree (info);
+}