summaryrefslogtreecommitdiff
path: root/toolchain/gdb/patches/710-debian_thread-db-multiple-libraries.patch
diff options
context:
space:
mode:
Diffstat (limited to 'toolchain/gdb/patches/710-debian_thread-db-multiple-libraries.patch')
-rw-r--r--toolchain/gdb/patches/710-debian_thread-db-multiple-libraries.patch593
1 files changed, 593 insertions, 0 deletions
diff --git a/toolchain/gdb/patches/710-debian_thread-db-multiple-libraries.patch b/toolchain/gdb/patches/710-debian_thread-db-multiple-libraries.patch
new file mode 100644
index 0000000000..c164bd11a2
--- /dev/null
+++ b/toolchain/gdb/patches/710-debian_thread-db-multiple-libraries.patch
@@ -0,0 +1,593 @@
+Support loading two libthread_db DSOs. In this case, the LinuxThreads
+and NPTL ones.
+
+Index: gdb-6.3/gdb/thread-db.c
+===================================================================
+--- gdb-6.3.orig/gdb/thread-db.c 2004-11-10 10:46:24.000000000 -0500
++++ gdb-6.3/gdb/thread-db.c 2004-11-10 11:22:34.858812426 -0500
+@@ -79,53 +79,63 @@ static td_thragent_t *thread_agent;
+
+ /* Pointers to the libthread_db functions. */
+
+-static td_err_e (*td_init_p) (void);
++struct thread_db_pointers
++{
++ const char *filename;
++
++ 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_getfpregs_p) (const td_thrhandle_t *th,
+- gdb_prfpregset_t *regset);
+-static td_err_e (*td_thr_getgregs_p) (const td_thrhandle_t *th,
+- prgregset_t gregs);
+-static td_err_e (*td_thr_setfpregs_p) (const td_thrhandle_t *th,
+- const gdb_prfpregset_t *fpregs);
+-static td_err_e (*td_thr_setgregs_p) (const td_thrhandle_t *th,
+- prgregset_t gregs);
+-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);
++ td_err_e (*td_ta_new_p) (struct ps_prochandle * ps,
++ td_thragent_t **ta);
++ td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt,
++ td_thrhandle_t *__th);
++ td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta,
++ lwpid_t lwpid, td_thrhandle_t *th);
++
++ 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_ta_event_addr_p) (const td_thragent_t *ta,
++ td_event_e event, td_notify_t *ptr);
++ td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
++ td_thr_events_t *event);
++ td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
++ td_event_msg_t *msg);
++
++ td_err_e (*td_thr_validate_p) (const 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_getfpregs_p) (const td_thrhandle_t *th,
++ gdb_prfpregset_t *regset);
++ td_err_e (*td_thr_getgregs_p) (const td_thrhandle_t *th,
++ prgregset_t gregs);
++ td_err_e (*td_thr_setfpregs_p) (const td_thrhandle_t *th,
++ const gdb_prfpregset_t *fpregs);
++ td_err_e (*td_thr_setgregs_p) (const td_thrhandle_t *th,
++ prgregset_t gregs);
++ td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th,
++ int event);
++
++ td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
++ void *map_address,
++ size_t offset, void **address);
++
++ struct thread_db_pointers *next;
++};
+
+ /* 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;
++CORE_ADDR td_create_bp_addr;
+
+ /* Location of the thread death event breakpoint. */
+-static CORE_ADDR td_death_bp_addr;
++CORE_ADDR td_death_bp_addr;
++
++static struct thread_db_pointers *current_pointers, *all_pointers;
+
+ /* Prototypes for local functions. */
+ static void thread_db_find_new_threads (void);
+@@ -262,7 +272,7 @@ thread_get_info_callback (const td_thrha
+ struct thread_info *thread_info;
+ ptid_t thread_ptid;
+
+- err = td_thr_get_info_p (thp, &ti);
++ err = current_pointers->td_thr_get_info_p (thp, &ti);
+ if (err != TD_OK)
+ error ("thread_get_info_callback: cannot get thread info: %s",
+ thread_db_err_str (err));
+@@ -316,8 +326,9 @@ thread_db_map_id2thr (struct thread_info
+ if (thread_info->private->th_valid)
+ return;
+
+- err = td_ta_map_id2thr_p (thread_agent, GET_THREAD (thread_info->ptid),
+- &thread_info->private->th);
++ err = current_pointers->td_ta_map_id2thr_p (thread_agent,
++ GET_THREAD (thread_info->ptid),
++ &thread_info->private->th);
+ if (err != TD_OK)
+ {
+ if (fatal)
+@@ -340,8 +351,8 @@ thread_db_get_info (struct thread_info *
+ if (!thread_info->private->th_valid)
+ thread_db_map_id2thr (thread_info, 1);
+
+- err =
+- td_thr_get_info_p (&thread_info->private->th, &thread_info->private->ti);
++ err = current_pointers->td_thr_get_info_p (&thread_info->private->th,
++ &thread_info->private->ti);
+ if (err != TD_OK)
+ error ("thread_db_get_info: cannot get thread info: %s",
+ thread_db_err_str (err));
+@@ -365,7 +376,8 @@ thread_from_lwp (ptid_t ptid)
+
+ gdb_assert (is_lwp (ptid));
+
+- err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
++ err = current_pointers->td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid),
++ &th);
+ if (err != TD_OK)
+ error ("Cannot find user-level thread for LWP %ld: %s",
+ GET_LWP (ptid), thread_db_err_str (err));
+@@ -420,85 +432,102 @@ verbose_dlsym (void *handle, const char
+ return sym;
+ }
+
+-static int
+-thread_db_load (void)
++static struct thread_db_pointers *
++thread_db_load (const char *name)
+ {
++ struct thread_db_pointers *ptrs;
++ Dl_info info;
+ void *handle;
+ td_err_e err;
+
+- handle = dlopen (LIBTHREAD_DB_SO, RTLD_NOW);
++ ptrs = xcalloc (1, sizeof (struct thread_db_pointers));
++
++ handle = dlopen (name, RTLD_NOW);
+ if (handle == NULL)
+ {
+- fprintf_filtered (gdb_stderr, "\n\ndlopen failed on '%s' - %s\n",
+- LIBTHREAD_DB_SO, dlerror ());
+- fprintf_filtered (gdb_stderr,
+- "GDB will not be able to debug pthreads.\n\n");
++ if (all_pointers == NULL)
++ {
++ fprintf_filtered (gdb_stderr, "\n\ndlopen failed on '%s' - %s\n",
++ name, dlerror ());
++ fprintf_filtered (gdb_stderr,
++ "GDB will not be able to debug pthreads.\n\n");
++ }
+ return 0;
+ }
+
+ /* Initialize pointers to the dynamic library functions we will use.
+ Essential functions first. */
+
+- td_init_p = verbose_dlsym (handle, "td_init");
+- if (td_init_p == NULL)
++ ptrs->td_init_p = verbose_dlsym (handle, "td_init");
++ if (ptrs->td_init_p == NULL)
+ return 0;
+
+- td_ta_new_p = verbose_dlsym (handle, "td_ta_new");
+- if (td_ta_new_p == NULL)
++ ptrs->td_ta_new_p = verbose_dlsym (handle, "td_ta_new");
++ if (ptrs->td_ta_new_p == NULL)
+ return 0;
+
+- td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr");
+- if (td_ta_map_id2thr_p == NULL)
++ ptrs->td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr");
++ if (ptrs->td_ta_map_id2thr_p == NULL)
+ return 0;
+
+- td_ta_map_lwp2thr_p = verbose_dlsym (handle, "td_ta_map_lwp2thr");
+- if (td_ta_map_lwp2thr_p == NULL)
++ ptrs->td_ta_map_lwp2thr_p = verbose_dlsym (handle, "td_ta_map_lwp2thr");
++ if (ptrs->td_ta_map_lwp2thr_p == NULL)
+ return 0;
+
+- td_ta_thr_iter_p = verbose_dlsym (handle, "td_ta_thr_iter");
+- if (td_ta_thr_iter_p == NULL)
++ ptrs->td_ta_thr_iter_p = verbose_dlsym (handle, "td_ta_thr_iter");
++ if (ptrs->td_ta_thr_iter_p == NULL)
+ return 0;
+
+- td_thr_validate_p = verbose_dlsym (handle, "td_thr_validate");
+- if (td_thr_validate_p == NULL)
++ ptrs->td_thr_validate_p = verbose_dlsym (handle, "td_thr_validate");
++ if (ptrs->td_thr_validate_p == NULL)
+ return 0;
+
+- td_thr_get_info_p = verbose_dlsym (handle, "td_thr_get_info");
+- if (td_thr_get_info_p == NULL)
++ ptrs->td_thr_get_info_p = verbose_dlsym (handle, "td_thr_get_info");
++ if (ptrs->td_thr_get_info_p == NULL)
+ return 0;
+
+- td_thr_getfpregs_p = verbose_dlsym (handle, "td_thr_getfpregs");
+- if (td_thr_getfpregs_p == NULL)
++ ptrs->td_thr_getfpregs_p = verbose_dlsym (handle, "td_thr_getfpregs");
++ if (ptrs->td_thr_getfpregs_p == NULL)
+ return 0;
+
+- td_thr_getgregs_p = verbose_dlsym (handle, "td_thr_getgregs");
+- if (td_thr_getgregs_p == NULL)
++ ptrs->td_thr_getgregs_p = verbose_dlsym (handle, "td_thr_getgregs");
++ if (ptrs->td_thr_getgregs_p == NULL)
+ return 0;
+
+- td_thr_setfpregs_p = verbose_dlsym (handle, "td_thr_setfpregs");
+- if (td_thr_setfpregs_p == NULL)
++ ptrs->td_thr_setfpregs_p = verbose_dlsym (handle, "td_thr_setfpregs");
++ if (ptrs->td_thr_setfpregs_p == NULL)
+ return 0;
+
+- td_thr_setgregs_p = verbose_dlsym (handle, "td_thr_setgregs");
+- if (td_thr_setgregs_p == NULL)
++ ptrs->td_thr_setgregs_p = verbose_dlsym (handle, "td_thr_setgregs");
++ if (ptrs->td_thr_setgregs_p == NULL)
+ return 0;
+
+ /* Initialize the library. */
+- err = td_init_p ();
++ err = ptrs->td_init_p ();
+ if (err != TD_OK)
+ {
+ warning ("Cannot initialize libthread_db: %s", thread_db_err_str (err));
++ xfree (ptrs);
+ return 0;
+ }
+
+ /* These are not essential. */
+- td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr");
+- td_ta_set_event_p = dlsym (handle, "td_ta_set_event");
+- td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg");
+- td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable");
+- td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr");
++ ptrs->td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr");
++ ptrs->td_ta_set_event_p = dlsym (handle, "td_ta_set_event");
++ ptrs->td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg");
++ ptrs->td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable");
++ ptrs->td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr");
++
++ if (dladdr (ptrs->td_ta_new_p, &info) != 0)
++ ptrs->filename = info.dli_fname;
++
++ /* Try dlinfo? */
++
++ if (ptrs->filename == NULL)
++ /* Paranoid - don't let a NULL path slip through. */
++ ptrs->filename = name;
+
+- return 1;
++ return ptrs;
+ }
+
+ static td_err_e
+@@ -508,7 +537,7 @@ enable_thread_event (td_thragent_t *thre
+ td_err_e err;
+
+ /* Get the breakpoint address for thread EVENT. */
+- err = td_ta_event_addr_p (thread_agent, event, &notify);
++ err = current_pointers->td_ta_event_addr_p (thread_agent, event, &notify);
+ if (err != TD_OK)
+ return err;
+
+@@ -534,8 +563,10 @@ enable_thread_event_reporting (void)
+
+ /* We cannot use the thread event reporting facility if these
+ functions aren't available. */
+- if (td_ta_event_addr_p == NULL || td_ta_set_event_p == NULL
+- || td_ta_event_getmsg_p == NULL || td_thr_event_enable_p == NULL)
++ if (current_pointers->td_ta_event_addr_p == NULL
++ || current_pointers->td_ta_set_event_p == NULL
++ || current_pointers->td_ta_event_getmsg_p == NULL
++ || current_pointers->td_thr_event_enable_p == NULL)
+ return;
+
+ /* Set the process wide mask saying which events we're interested in. */
+@@ -552,7 +583,7 @@ enable_thread_event_reporting (void)
+ #endif
+ td_event_addset (&events, TD_DEATH);
+
+- err = td_ta_set_event_p (thread_agent, &events);
++ err = current_pointers->td_ta_set_event_p (thread_agent, &events);
+ if (err != TD_OK)
+ {
+ warning ("Unable to set global thread event mask: %s",
+@@ -592,7 +623,7 @@ disable_thread_event_reporting (void)
+ /* Set the process wide mask saying we aren't interested in any
+ events anymore. */
+ td_event_emptyset (&events);
+- td_ta_set_event_p (thread_agent, &events);
++ current_pointers->td_ta_set_event_p (thread_agent, &events);
+
+ /* Delete thread event breakpoints, if any. */
+ remove_thread_event_breakpoints ();
+@@ -635,7 +666,6 @@ check_thread_signals (void)
+ static void
+ check_for_thread_db (void)
+ {
+- td_err_e err;
+ static int already_loaded;
+
+ /* First time through, report that libthread_db was successfuly
+@@ -644,19 +674,8 @@ check_for_thread_db (void)
+
+ if (!already_loaded)
+ {
+- Dl_info info;
+- const char *library = NULL;
+- if (dladdr ((*td_ta_new_p), &info) != 0)
+- library = info.dli_fname;
+-
+- /* Try dlinfo? */
+-
+- if (library == NULL)
+- /* Paranoid - don't let a NULL path slip through. */
+- library = LIBTHREAD_DB_SO;
+-
+ printf_unfiltered ("Using host libthread_db library \"%s\".\n",
+- library);
++ all_pointers->filename);
+ already_loaded = 1;
+ }
+
+@@ -674,28 +693,34 @@ check_for_thread_db (void)
+ proc_handle.pid = GET_PID (inferior_ptid);
+
+ /* Now attempt to open a connection to the thread library. */
+- err = td_ta_new_p (&proc_handle, &thread_agent);
+- switch (err)
++ for (current_pointers = all_pointers;
++ current_pointers != NULL;
++ current_pointers = current_pointers->next)
+ {
+- case TD_NOLIBTHREAD:
+- /* No thread library was detected. */
+- break;
+-
+- case TD_OK:
+- printf_unfiltered ("[Thread debugging using libthread_db enabled]\n");
++ td_err_e err;
++ err = current_pointers->td_ta_new_p (&proc_handle, &thread_agent);
++ switch (err)
++ {
++ case TD_NOLIBTHREAD:
++ /* No thread library was detected. */
++ break;
+
+- /* The thread library was detected. Activate the thread_db target. */
+- push_target (&thread_db_ops);
+- using_thread_db = 1;
++ case TD_OK:
++ printf_unfiltered ("[Thread debugging using libthread_db enabled]\n");
+
+- enable_thread_event_reporting ();
+- thread_db_find_new_threads ();
+- break;
++ /* The thread library was detected. Activate the thread_db target. */
++ push_target (&thread_db_ops);
++ using_thread_db = 1;
++
++ enable_thread_event_reporting ();
++ thread_db_find_new_threads ();
++ return;
+
+- default:
+- warning ("Cannot initialize thread debugging library: %s",
+- thread_db_err_str (err));
+- break;
++ default:
++ warning ("Cannot initialize thread debugging library: %s",
++ thread_db_err_str (err));
++ break;
++ }
+ }
+ }
+
+@@ -766,7 +791,7 @@ attach_thread (ptid_t ptid, const td_thr
+ #endif
+
+ /* Enable thread event reporting for this thread. */
+- err = td_thr_event_enable_p (th_p, 1);
++ err = current_pointers->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));
+@@ -892,7 +917,7 @@ check_event (ptid_t ptid)
+
+ do
+ {
+- err = td_ta_event_getmsg_p (thread_agent, &msg);
++ err = current_pointers->td_ta_event_getmsg_p (thread_agent, &msg);
+ if (err != TD_OK)
+ {
+ if (err == TD_NOMSG)
+@@ -902,7 +927,7 @@ check_event (ptid_t ptid)
+ thread_db_err_str (err));
+ }
+
+- err = td_thr_get_info_p (msg.th_p, &ti);
++ err = current_pointers->td_thr_get_info_p (msg.th_p, &ti);
+ if (err != TD_OK)
+ error ("Cannot get thread info: %s", thread_db_err_str (err));
+
+@@ -1015,12 +1040,14 @@ thread_db_fetch_registers (int regno)
+ thread_info = find_thread_pid (inferior_ptid);
+ thread_db_map_id2thr (thread_info, 1);
+
+- err = td_thr_getgregs_p (&thread_info->private->th, gregset);
++ err = current_pointers->td_thr_getgregs_p (&thread_info->private->th,
++ gregset);
+ if (err != TD_OK)
+ error ("Cannot fetch general-purpose registers for thread %ld: %s",
+ (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+
+- err = td_thr_getfpregs_p (&thread_info->private->th, &fpregset);
++ err = current_pointers->td_thr_getfpregs_p (&thread_info->private->th,
++ &fpregset);
+ if (err != TD_OK)
+ error ("Cannot get floating-point registers for thread %ld: %s",
+ (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+@@ -1062,11 +1089,13 @@ thread_db_store_registers (int regno)
+ fill_gregset ((gdb_gregset_t *) gregset, -1);
+ fill_fpregset (&fpregset, -1);
+
+- err = td_thr_setgregs_p (&thread_info->private->th, gregset);
++ err = current_pointers->td_thr_setgregs_p (&thread_info->private->th,
++ gregset);
+ if (err != TD_OK)
+ error ("Cannot store general-purpose registers for thread %ld: %s",
+ (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+- err = td_thr_setfpregs_p (&thread_info->private->th, &fpregset);
++ err = current_pointers->td_thr_setfpregs_p (&thread_info->private->th,
++ &fpregset);
+ if (err != TD_OK)
+ error ("Cannot store floating-point registers for thread %ld: %s",
+ (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+@@ -1136,15 +1165,14 @@ thread_db_thread_alive (ptid_t ptid)
+ if (!thread_info->private->th_valid)
+ return 0;
+
+- err = td_thr_validate_p (&thread_info->private->th);
++ err = current_pointers->td_thr_validate_p (&thread_info->private->th);
+ if (err != TD_OK)
+ return 0;
+
+ if (!thread_info->private->ti_valid)
+ {
+- err =
+- td_thr_get_info_p (&thread_info->private->th,
+- &thread_info->private->ti);
++ err = current_pointers->td_thr_get_info_p
++ (&thread_info->private->th, &thread_info->private->ti);
+ if (err != TD_OK)
+ return 0;
+ thread_info->private->ti_valid = 1;
+@@ -1170,7 +1198,7 @@ find_new_threads_callback (const td_thrh
+ td_err_e err;
+ ptid_t ptid;
+
+- err = td_thr_get_info_p (th_p, &ti);
++ err = current_pointers->td_thr_get_info_p (th_p, &ti);
+ if (err != TD_OK)
+ error ("find_new_threads_callback: cannot get thread info: %s",
+ thread_db_err_str (err));
+@@ -1192,9 +1220,10 @@ thread_db_find_new_threads (void)
+ td_err_e err;
+
+ /* Iterate over all user-space threads to discover new threads. */
+- err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, NULL,
+- TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+- TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
++ err = current_pointers->td_ta_thr_iter_p
++ (thread_agent, find_new_threads_callback, NULL,
++ TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
++ TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+ if (err != TD_OK)
+ error ("Cannot find new threads: %s", thread_db_err_str (err));
+ }
+@@ -1257,7 +1286,7 @@ thread_db_get_thread_local_address (ptid
+ struct thread_info *thread_info;
+
+ /* glibc doesn't provide the needed interface. */
+- if (!td_thr_tls_get_addr_p)
++ if (!current_pointers->td_thr_tls_get_addr_p)
+ error ("Cannot find thread-local variables in this thread library.");
+
+ /* Get the address of the link map for this objfile. */
+@@ -1279,8 +1308,8 @@ thread_db_get_thread_local_address (ptid
+ thread_db_map_id2thr (thread_info, 1);
+
+ /* Finally, get the address of the variable. */
+- err = td_thr_tls_get_addr_p (&thread_info->private->th, (void *) lm,
+- offset, &address);
++ err = current_pointers->td_thr_tls_get_addr_p
++ (&thread_info->private->th, (void *) lm, offset, &address);
+
+ #ifdef THREAD_DB_HAS_TD_NOTALLOC
+ /* The memory hasn't been allocated, yet. */
+@@ -1360,17 +1389,49 @@ init_thread_db_ops (void)
+ void
+ _initialize_thread_db (void)
+ {
++ struct thread_db_pointers *ptrs;
++ const char *p;
++
+ /* Only initialize the module if we can load libthread_db. */
+- if (thread_db_load ())
+- {
+- init_thread_db_ops ();
+- add_target (&thread_db_ops);
++ ptrs = thread_db_load (LIBTHREAD_DB_SO);
++ if (ptrs == NULL)
++ return;
++
++ all_pointers = ptrs;
+
+- /* Add ourselves to objfile event chain. */
+- target_new_objfile_chain = deprecated_target_new_objfile_hook;
+- deprecated_target_new_objfile_hook = thread_db_new_objfile;
++ /* Some GNU/Linux systems have more than one binary-compatible copy
++ of libthread_db. If we can find a second one, load that too.
++ The inferior may force the use of a different threading package
++ than we expect. Our guess for the location is somewhat hokey:
++ strip out anything between /lib (or /lib64) and LIBTHREAD_DB_SO.
++ If we loaded the NPTL libthread_db by default, this may find us
++ the LinuxThreads copy. */
++ p = strrchr (ptrs->filename, '/');
++ while (p != NULL && p > ptrs->filename)
++ {
++ const char *component;
+
+- /* Register ourselves for the new inferior observer. */
+- observer_attach_inferior_created (check_for_thread_db_observer);
++ component = memrchr (ptrs->filename, '/', p - ptrs->filename);
++ if (component != NULL && strncmp (component, "/lib", 4) == 0)
++ {
++ char *new_name = xmalloc (p - ptrs->filename + 2
++ + strlen (LIBTHREAD_DB_SO));
++ memcpy (new_name, ptrs->filename, p - ptrs->filename + 1);
++ strcpy (new_name + (p - ptrs->filename) + 1, LIBTHREAD_DB_SO);
++ ptrs->next = thread_db_load (new_name);
++ xfree (new_name);
++ break;
++ }
++ p = component;
+ }
++
++ init_thread_db_ops ();
++ add_target (&thread_db_ops);
++
++ /* Add ourselves to objfile event chain. */
++ target_new_objfile_chain = deprecated_target_new_objfile_hook;
++ deprecated_target_new_objfile_hook = thread_db_new_objfile;
++
++ /* Register ourselves for the new inferior observer. */
++ observer_attach_inferior_created (check_for_thread_db_observer);
+ }