| 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, ¬ify); |
| + err = current_pointers->td_ta_event_addr_p (thread_agent, event, ¬ify); |
| 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); |
| } |