* corelow.c (core_xfer_partial): Pass writebuf to
[deliverable/binutils-gdb.git] / gdb / linux-thread-db.c
index 65d9fd51b89f93c7183fde7623b2cafb655db520..dbb9a3dbde1e41bf0aed4a8bf633d51fdee18eae 100644 (file)
@@ -1,12 +1,13 @@
 /* libthread_db assisted debugging support, generic parts.
 
 /* libthread_db assisted debugging support, generic parts.
 
-   Copyright 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -15,9 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 
 
 #include "defs.h"
 
@@ -27,6 +26,7 @@
 #include "gdb_thread_db.h"
 
 #include "bfd.h"
 #include "gdb_thread_db.h"
 
 #include "bfd.h"
+#include "exceptions.h"
 #include "gdbthread.h"
 #include "inferior.h"
 #include "symfile.h"
 #include "gdbthread.h"
 #include "inferior.h"
 #include "symfile.h"
 #include "target.h"
 #include "regcache.h"
 #include "solib-svr4.h"
 #include "target.h"
 #include "regcache.h"
 #include "solib-svr4.h"
+#include "gdbcore.h"
+#include "observer.h"
+#include "linux-nat.h"
+
+#include <signal.h>
 
 #ifdef HAVE_GNU_LIBC_VERSION_H
 #include <gnu/libc-version.h>
 
 #ifdef HAVE_GNU_LIBC_VERSION_H
 #include <gnu/libc-version.h>
 /* If we're running on GNU/Linux, we must explicitly attach to any new
    threads.  */
 
 /* If we're running on GNU/Linux, we must explicitly attach to any new
    threads.  */
 
-/* FIXME: There is certainly some room for improvements:
-   - Cache LWP ids.
-   - Bypass libthread_db when fetching or storing registers for
-   threads bound to a LWP.  */
-
 /* This module's target vector.  */
 static struct target_ops thread_db_ops;
 
 /* The target vector that we call for things this module can't handle.  */
 static struct target_ops *target_beneath;
 
 /* This module's target vector.  */
 static struct target_ops thread_db_ops;
 
 /* The target vector that we call for things this module can't handle.  */
 static struct target_ops *target_beneath;
 
-/* Pointer to the next function on the objfile event chain.  */
-static void (*target_new_objfile_chain) (struct objfile * objfile);
-
 /* Non-zero if we're using this module's target vector.  */
 static int using_thread_db;
 
 /* Non-zero if we're using this module's target vector.  */
 static int using_thread_db;
 
@@ -101,14 +98,6 @@ static td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
 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_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_event_enable_p) (const td_thrhandle_t *th,
                                          int event);
 
@@ -143,7 +132,6 @@ static void detach_thread (ptid_t ptid, int verbose);
 #define is_thread(ptid)                (GET_THREAD (ptid) != 0)
 
 #define BUILD_LWP(lwp, pid)    ptid_build (pid, lwp, 0)
 #define is_thread(ptid)                (GET_THREAD (ptid) != 0)
 
 #define BUILD_LWP(lwp, pid)    ptid_build (pid, lwp, 0)
-#define BUILD_THREAD(tid, pid) ptid_build (pid, 0, tid)
 \f
 
 /* Use "struct private_thread_info" to cache thread state.  This is
 \f
 
 /* Use "struct private_thread_info" to cache thread state.  This is
@@ -212,37 +200,39 @@ thread_db_err_str (td_err_e err)
       return "only part of register set was written/read";
     case TD_NOXREGS:
       return "X register set not available for this thread";
       return "only part of register set was written/read";
     case TD_NOXREGS:
       return "X register set not available for this thread";
+#ifdef THREAD_DB_HAS_TD_NOTALLOC
+    case TD_NOTALLOC:
+      return "thread has not yet allocated TLS for given module";
+#endif
+#ifdef THREAD_DB_HAS_TD_VERSION
+    case TD_VERSION:
+      return "versions of libpthread and libthread_db do not match";
+#endif
+#ifdef THREAD_DB_HAS_TD_NOTLS
+    case TD_NOTLS:
+      return "there is no TLS segment in the given module";
+#endif
     default:
       snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
       return buf;
     }
 }
     default:
       snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
       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 char *
-thread_db_state_str (td_thr_state_e state)
+static int
+have_threads_callback (struct thread_info *thread, void *dummy)
 {
 {
-  static char buf[64];
+  return 1;
+}
 
 
-  switch (state)
-    {
-    case TD_THR_STOPPED:
-      return "stopped by debugger";
-    case TD_THR_RUN:
-      return "runnable";
-    case TD_THR_ACTIVE:
-      return "active";
-    case TD_THR_ZOMBIE:
-      return "zombie";
-    case TD_THR_SLEEP:
-      return "sleeping";
-    case TD_THR_STOPPED_ASLEEP:
-      return "stopped by debugger AND blocked";
-    default:
-      snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
-      return buf;
-    }
+static int
+have_threads (void)
+{
+  return iterate_over_threads (have_threads_callback, NULL) != NULL;
 }
 }
-\f
+
 /* A callback function for td_ta_thr_iter, which we use to map all
    threads to LWPs.
 
 /* A callback function for td_ta_thr_iter, which we use to map all
    threads to LWPs.
 
@@ -263,11 +253,11 @@ thread_get_info_callback (const td_thrhandle_t *thp, void *infop)
 
   err = td_thr_get_info_p (thp, &ti);
   if (err != TD_OK)
 
   err = td_thr_get_info_p (thp, &ti);
   if (err != TD_OK)
-    error ("thread_get_info_callback: cannot get thread info: %s",
+    error (_("thread_get_info_callback: cannot get thread info: %s"),
           thread_db_err_str (err));
 
   /* Fill the cache.  */
           thread_db_err_str (err));
 
   /* Fill the cache.  */
-  thread_ptid = BUILD_THREAD (ti.ti_tid, GET_PID (inferior_ptid));
+  thread_ptid = ptid_build (GET_PID (inferior_ptid), ti.ti_lid, ti.ti_tid);
   thread_info = find_thread_pid (thread_ptid);
 
   /* In the case of a zombie thread, don't continue.  We don't want to
   thread_info = find_thread_pid (thread_ptid);
 
   /* In the case of a zombie thread, don't continue.  We don't want to
@@ -320,34 +310,13 @@ thread_db_map_id2thr (struct thread_info *thread_info, int fatal)
   if (err != TD_OK)
     {
       if (fatal)
   if (err != TD_OK)
     {
       if (fatal)
-       error ("Cannot find thread %ld: %s",
+       error (_("Cannot find thread %ld: %s"),
               (long) GET_THREAD (thread_info->ptid),
               thread_db_err_str (err));
     }
   else
     thread_info->private->th_valid = 1;
 }
               (long) GET_THREAD (thread_info->ptid),
               thread_db_err_str (err));
     }
   else
     thread_info->private->th_valid = 1;
 }
-
-static td_thrinfo_t *
-thread_db_get_info (struct thread_info *thread_info)
-{
-  td_err_e err;
-
-  if (thread_info->private->ti_valid)
-    return &thread_info->private->ti;
-
-  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);
-  if (err != TD_OK)
-    error ("thread_db_get_info: cannot get thread info: %s",
-          thread_db_err_str (err));
-
-  thread_info->private->ti_valid = 1;
-  return &thread_info->private->ti;
-}
 \f
 /* Convert between user-level thread ids and LWP ids.  */
 
 \f
 /* Convert between user-level thread ids and LWP ids.  */
 
@@ -366,7 +335,7 @@ thread_from_lwp (ptid_t ptid)
 
   err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
   if (err != TD_OK)
 
   err = 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",
+    error (_("Cannot find user-level thread for LWP %ld: %s"),
           GET_LWP (ptid), thread_db_err_str (err));
 
   thread_info = NULL;
           GET_LWP (ptid), thread_db_err_str (err));
 
   thread_info = NULL;
@@ -385,22 +354,14 @@ thread_from_lwp (ptid_t ptid)
 
   gdb_assert (thread_info && thread_info->private->ti_valid);
 
 
   gdb_assert (thread_info && thread_info->private->ti_valid);
 
-  return BUILD_THREAD (thread_info->private->ti.ti_tid, GET_PID (ptid));
+  return ptid_build (GET_PID (ptid), GET_LWP (ptid),
+                    thread_info->private->ti.ti_tid);
 }
 
 static ptid_t
 lwp_from_thread (ptid_t ptid)
 {
 }
 
 static ptid_t
 lwp_from_thread (ptid_t ptid)
 {
-  struct thread_info *thread_info;
-  ptid_t thread_ptid;
-
-  if (!is_thread (ptid))
-    return ptid;
-
-  thread_info = find_thread_pid (ptid);
-  thread_db_get_info (thread_info);
-
-  return BUILD_LWP (thread_info->private->ti.ti_lid, GET_PID (ptid));
+  return BUILD_LWP (GET_LWP (ptid), GET_PID (ptid));
 }
 \f
 
 }
 \f
 
@@ -415,7 +376,7 @@ verbose_dlsym (void *handle, const char *name)
 {
   void *sym = dlsym (handle, name);
   if (sym == NULL)
 {
   void *sym = dlsym (handle, name);
   if (sym == NULL)
-    warning ("Symbol \"%s\" not found in libthread_db: %s", name, dlerror ());
+    warning (_("Symbol \"%s\" not found in libthread_db: %s"), name, dlerror ());
   return sym;
 }
 
   return sym;
 }
 
@@ -466,27 +427,11 @@ thread_db_load (void)
   if (td_thr_get_info_p == NULL)
     return 0;
 
   if (td_thr_get_info_p == NULL)
     return 0;
 
-  td_thr_getfpregs_p = verbose_dlsym (handle, "td_thr_getfpregs");
-  if (td_thr_getfpregs_p == NULL)
-    return 0;
-
-  td_thr_getgregs_p = verbose_dlsym (handle, "td_thr_getgregs");
-  if (td_thr_getgregs_p == NULL)
-    return 0;
-
-  td_thr_setfpregs_p = verbose_dlsym (handle, "td_thr_setfpregs");
-  if (td_thr_setfpregs_p == NULL)
-    return 0;
-
-  td_thr_setgregs_p = verbose_dlsym (handle, "td_thr_setgregs");
-  if (td_thr_setgregs_p == NULL)
-    return 0;
-
   /* Initialize the library.  */
   err = td_init_p ();
   if (err != TD_OK)
     {
   /* Initialize the library.  */
   err = td_init_p ();
   if (err != TD_OK)
     {
-      warning ("Cannot initialize libthread_db: %s", thread_db_err_str (err));
+      warning (_("Cannot initialize libthread_db: %s"), thread_db_err_str (err));
       return 0;
     }
 
       return 0;
     }
 
@@ -512,9 +457,14 @@ enable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp)
     return err;
 
   /* Set up the breakpoint.  */
     return err;
 
   /* Set up the breakpoint.  */
-  (*bp) = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
-                                             (CORE_ADDR) notify.u.bptaddr,
-                                             &current_target);
+  gdb_assert (exec_bfd);
+  (*bp) = (gdbarch_convert_from_func_ptr_addr
+          (current_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),
+           &current_target));
   create_thread_event_breakpoint ((*bp));
 
   return TD_OK;
   create_thread_event_breakpoint ((*bp));
 
   return TD_OK;
@@ -542,9 +492,9 @@ enable_thread_event_reporting (void)
   td_event_addset (&events, TD_CREATE);
 
 #ifdef HAVE_GNU_LIBC_VERSION_H
   td_event_addset (&events, TD_CREATE);
 
 #ifdef HAVE_GNU_LIBC_VERSION_H
-  /* FIXME: kettenis/2000-04-23: The event reporting facility is
-     broken for TD_DEATH events in glibc 2.1.3, so don't enable it for
-     now.  */
+  /* The event reporting facility is broken for TD_DEATH events in
+     glibc 2.1.3, so don't enable it if we have glibc but a lower
+     version.  */
   libc_version = gnu_get_libc_version ();
   if (sscanf (libc_version, "%d.%d", &libc_major, &libc_minor) == 2
       && (libc_major > 2 || (libc_major == 2 && libc_minor > 1)))
   libc_version = gnu_get_libc_version ();
   if (sscanf (libc_version, "%d.%d", &libc_major, &libc_minor) == 2
       && (libc_major > 2 || (libc_major == 2 && libc_minor > 1)))
@@ -554,7 +504,7 @@ enable_thread_event_reporting (void)
   err = td_ta_set_event_p (thread_agent, &events);
   if (err != TD_OK)
     {
   err = td_ta_set_event_p (thread_agent, &events);
   if (err != TD_OK)
     {
-      warning ("Unable to set global thread event mask: %s",
+      warning (_("Unable to set global thread event mask: %s"),
               thread_db_err_str (err));
       return;
     }
               thread_db_err_str (err));
       return;
     }
@@ -568,7 +518,7 @@ enable_thread_event_reporting (void)
   err = enable_thread_event (thread_agent, TD_CREATE, &td_create_bp_addr);
   if (err != TD_OK)
     {
   err = enable_thread_event (thread_agent, TD_CREATE, &td_create_bp_addr);
   if (err != TD_OK)
     {
-      warning ("Unable to get location for thread creation breakpoint: %s",
+      warning (_("Unable to get location for thread creation breakpoint: %s"),
               thread_db_err_str (err));
       return;
     }
               thread_db_err_str (err));
       return;
     }
@@ -577,7 +527,7 @@ enable_thread_event_reporting (void)
   err = enable_thread_event (thread_agent, TD_DEATH, &td_death_bp_addr);
   if (err != TD_OK)
     {
   err = enable_thread_event (thread_agent, TD_DEATH, &td_death_bp_addr);
   if (err != TD_OK)
     {
-      warning ("Unable to get location for thread death breakpoint: %s",
+      warning (_("Unable to get location for thread death breakpoint: %s"),
               thread_db_err_str (err));
       return;
     }
               thread_db_err_str (err));
       return;
     }
@@ -627,59 +577,57 @@ check_thread_signals (void)
 #endif
 }
 
 #endif
 }
 
-static void
-thread_db_new_objfile (struct objfile *objfile)
+/* Check whether thread_db is usable.  This function is called when
+   an inferior is created (or otherwise acquired, e.g. attached to)
+   and when new shared libraries are loaded into a running process.  */
+
+void
+check_for_thread_db (void)
 {
   td_err_e err;
 {
   td_err_e err;
+  static int already_loaded;
+
+  /* Do nothing if we couldn't load libthread_db.so.1.  */
+  if (td_ta_new_p == NULL)
+    return;
 
   /* First time through, report that libthread_db was successfuly
      loaded.  Can't print this in in thread_db_load as, at that stage,
 
   /* First time through, report that libthread_db was successfuly
      loaded.  Can't print this in in thread_db_load as, at that stage,
-     the interpreter and it's console haven't started.  The real
-     problem here is that libthread_db is loaded too early - it should
-     only be loaded when there is a program to debug.  */
-  {
-    static int dejavu;
-    if (!dejavu)
-      {
-       Dl_info info;
-       const char *library = NULL;
-       /* Try dladdr.  */
-       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);
-       dejavu = 1;
-      }
-  }
+     the interpreter and it's console haven't started.  */
 
 
-  /* Don't attempt to use thread_db on targets which can not run
-     (core files).  */
-  if (objfile == NULL || !target_has_execution)
+  if (!already_loaded)
     {
     {
-      /* All symbols have been discarded.  If the thread_db target is
-         active, deactivate it now.  */
-      if (using_thread_db)
-       {
-         gdb_assert (proc_handle.pid == 0);
-         unpush_target (&thread_db_ops);
-         using_thread_db = 0;
-       }
+      Dl_info info;
+      const char *library = NULL;
+      if (dladdr ((*td_ta_new_p), &info) != 0)
+       library = info.dli_fname;
+
+      /* Try dlinfo?  */
 
 
-      goto quit;
+      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);
+      already_loaded = 1;
     }
 
   if (using_thread_db)
     /* Nothing to do.  The thread library was already detected and the
        target vector was already activated.  */
     }
 
   if (using_thread_db)
     /* Nothing to do.  The thread library was already detected and the
        target vector was already activated.  */
-    goto quit;
+    return;
+
+  /* Don't attempt to use thread_db on targets which can not run
+     (executables not running yet, core files) for now.  */
+  if (!target_has_execution)
+    return;
+
+  /* Don't attempt to use thread_db for remote targets.  */
+  if (!target_can_run (&current_target))
+    return;
 
 
-  /* Initialize the structure that identifies the child process.  Note
-     that at this point there is no guarantee that we actually have a
-     child process.  */
+  /* Initialize the structure that identifies the child process.  */
   proc_handle.pid = GET_PID (inferior_ptid);
 
   /* Now attempt to open a connection to the thread library.  */
   proc_handle.pid = GET_PID (inferior_ptid);
 
   /* Now attempt to open a connection to the thread library.  */
@@ -691,7 +639,7 @@ thread_db_new_objfile (struct objfile *objfile)
       break;
 
     case TD_OK:
       break;
 
     case TD_OK:
-      printf_unfiltered ("[Thread debugging using libthread_db enabled]\n");
+      printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
 
       /* The thread library was detected.  Activate the thread_db target.  */
       push_target (&thread_db_ops);
 
       /* The thread library was detected.  Activate the thread_db target.  */
       push_target (&thread_db_ops);
@@ -702,14 +650,17 @@ thread_db_new_objfile (struct objfile *objfile)
       break;
 
     default:
       break;
 
     default:
-      warning ("Cannot initialize thread debugging library: %s",
+      warning (_("Cannot initialize thread debugging library: %s"),
               thread_db_err_str (err));
       break;
     }
               thread_db_err_str (err));
       break;
     }
+}
 
 
-quit:
-  if (target_new_objfile_chain)
-    target_new_objfile_chain (objfile);
+static void
+thread_db_new_objfile (struct objfile *objfile)
+{
+  if (objfile != NULL)
+    check_for_thread_db ();
 }
 
 /* Attach to a new thread.  This function is called when we receive a
 }
 
 /* Attach to a new thread.  This function is called when we receive a
@@ -746,53 +697,35 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
 
   check_thread_signals ();
 
 
   check_thread_signals ();
 
+  if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
+    return;                    /* A zombie thread -- do not attach.  */
+
+  /* Under GNU/Linux, we have to attach to each and every thread.  */
+  if (lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0) < 0)
+    return;
+
   /* Add the thread to GDB's thread list.  */
   tp = add_thread (ptid);
   tp->private = xmalloc (sizeof (struct private_thread_info));
   memset (tp->private, 0, sizeof (struct private_thread_info));
 
   if (verbose)
   /* Add the thread to GDB's thread list.  */
   tp = add_thread (ptid);
   tp->private = xmalloc (sizeof (struct private_thread_info));
   memset (tp->private, 0, sizeof (struct private_thread_info));
 
   if (verbose)
-    printf_unfiltered ("[New %s]\n", target_pid_to_str (ptid));
-
-  if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
-    return;                    /* A zombie thread -- do not attach.  */
-
-  /* Under GNU/Linux, we have to attach to each and every thread.  */
-#ifdef ATTACH_LWP
-  ATTACH_LWP (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0);
-#endif
+    printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
 
   /* Enable thread event reporting for this thread.  */
   err = td_thr_event_enable_p (th_p, 1);
   if (err != TD_OK)
 
   /* Enable thread event reporting for this thread.  */
   err = td_thr_event_enable_p (th_p, 1);
   if (err != TD_OK)
-    error ("Cannot enable thread event reporting for %s: %s",
+    error (_("Cannot enable thread event reporting for %s: %s"),
           target_pid_to_str (ptid), thread_db_err_str (err));
 }
 
           target_pid_to_str (ptid), thread_db_err_str (err));
 }
 
-static void
-thread_db_attach (char *args, int from_tty)
-{
-  target_beneath->to_attach (args, from_tty);
-
-  /* Destroy thread info; it's no longer valid.  */
-  init_thread_list ();
-
-  /* The child process is now the actual multi-threaded
-     program.  Snatch its process ID...  */
-  proc_handle.pid = GET_PID (inferior_ptid);
-
-  /* ...and perform the remaining initialization steps.  */
-  enable_thread_event_reporting ();
-  thread_db_find_new_threads ();
-}
-
 static void
 detach_thread (ptid_t ptid, int verbose)
 {
   struct thread_info *thread_info;
 
   if (verbose)
 static void
 detach_thread (ptid_t ptid, int verbose)
 {
   struct thread_info *thread_info;
 
   if (verbose)
-    printf_unfiltered ("[%s exited]\n", target_pid_to_str (ptid));
+    printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (ptid));
 
   /* Don't delete the thread now, because it still reports as active
      until it has executed a few instructions after the event
 
   /* Don't delete the thread now, because it still reports as active
      until it has executed a few instructions after the event
@@ -812,14 +745,13 @@ thread_db_detach (char *args, int from_tty)
   disable_thread_event_reporting ();
 
   /* There's no need to save & restore inferior_ptid here, since the
   disable_thread_event_reporting ();
 
   /* There's no need to save & restore inferior_ptid here, since the
-     inferior is supposed to be survive this function call.  */
+     inferior is not supposed to survive this function call.  */
   inferior_ptid = lwp_from_thread (inferior_ptid);
 
   inferior_ptid = lwp_from_thread (inferior_ptid);
 
-  /* Forget about the child's process ID.  We shouldn't need it
-     anymore.  */
-  proc_handle.pid = 0;
-
   target_beneath->to_detach (args, from_tty);
   target_beneath->to_detach (args, from_tty);
+
+  /* Should this be done by detach_command?  */
+  target_mourn_inferior ();
 }
 
 static int
 }
 
 static int
@@ -867,7 +799,7 @@ check_event (ptid_t ptid)
   int loop = 0;
 
   /* Bail out early if we're not at a thread event breakpoint.  */
   int loop = 0;
 
   /* Bail out early if we're not at a thread event breakpoint.  */
-  stop_pc = read_pc_pid (ptid) - DECR_PC_AFTER_BREAK;
+  stop_pc = read_pc_pid (ptid) - gdbarch_decr_pc_after_break (current_gdbarch);
   if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr)
     return;
 
   if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr)
     return;
 
@@ -895,15 +827,15 @@ check_event (ptid_t ptid)
          if (err == TD_NOMSG)
            return;
 
          if (err == TD_NOMSG)
            return;
 
-         error ("Cannot get thread event message: %s",
+         error (_("Cannot get thread event message: %s"),
                 thread_db_err_str (err));
        }
 
       err = td_thr_get_info_p (msg.th_p, &ti);
       if (err != TD_OK)
                 thread_db_err_str (err));
        }
 
       err = td_thr_get_info_p (msg.th_p, &ti);
       if (err != TD_OK)
-       error ("Cannot get thread info: %s", thread_db_err_str (err));
+       error (_("Cannot get thread info: %s"), thread_db_err_str (err));
 
 
-      ptid = BUILD_THREAD (ti.ti_tid, GET_PID (ptid));
+      ptid = ptid_build (GET_PID (ptid), ti.ti_lid, ti.ti_tid);
 
       switch (msg.event)
        {
 
       switch (msg.event)
        {
@@ -917,14 +849,14 @@ check_event (ptid_t ptid)
        case TD_DEATH:
 
          if (!in_thread_list (ptid))
        case TD_DEATH:
 
          if (!in_thread_list (ptid))
-           error ("Spurious thread death event.");
+           error (_("Spurious thread death event."));
 
          detach_thread (ptid, 1);
 
          break;
 
        default:
 
          detach_thread (ptid, 1);
 
          break;
 
        default:
-         error ("Spurious thread event.");
+         error (_("Spurious thread event."));
        }
     }
   while (loop);
        }
     }
   while (loop);
@@ -940,133 +872,46 @@ thread_db_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 
   ptid = target_beneath->to_wait (ptid, ourstatus);
 
 
   ptid = target_beneath->to_wait (ptid, ourstatus);
 
-  if (proc_handle.pid == 0)
-    /* The current child process isn't the actual multi-threaded
-       program yet, so don't try to do any special thread-specific
-       post-processing and bail out early.  */
-    return ptid;
-
-  if (ourstatus->kind == TARGET_WAITKIND_EXITED)
+  if (ourstatus->kind == TARGET_WAITKIND_EXITED
+    || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
     return pid_to_ptid (-1);
 
     return pid_to_ptid (-1);
 
-  if (ourstatus->kind == TARGET_WAITKIND_STOPPED
-      && ourstatus->value.sig == TARGET_SIGNAL_TRAP)
-    /* Check for a thread event.  */
-    check_event (ptid);
-
-  if (!ptid_equal (trap_ptid, null_ptid))
-    trap_ptid = thread_from_lwp (trap_ptid);
-
-  /* Change the ptid back into the higher level PID + TID format.
-     If the thread is dead and no longer on the thread list, we will 
-     get back a dead ptid.  This can occur if the thread death event
-     gets postponed by other simultaneous events.  In such a case, 
-     we want to just ignore the event and continue on.  */
-  ptid = thread_from_lwp (ptid);
-  if (GET_PID (ptid) == -1)
-    ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-  
-  return ptid;
-}
-
-static int
-thread_db_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
-                      struct mem_attrib *attrib, struct target_ops *target)
-{
-  struct cleanup *old_chain = save_inferior_ptid ();
-  int xfer;
-
-  if (is_thread (inferior_ptid))
+  if (ourstatus->kind == TARGET_WAITKIND_EXECD)
     {
     {
-      /* FIXME: This seems to be necessary to make sure breakpoints
-         are removed.  */
-      if (!target_thread_alive (inferior_ptid))
-       inferior_ptid = pid_to_ptid (GET_PID (inferior_ptid));
-      else
-       inferior_ptid = lwp_from_thread (inferior_ptid);
-    }
+      remove_thread_event_breakpoints ();
+      unpush_target (&thread_db_ops);
+      using_thread_db = 0;
 
 
-  xfer =
-    target_beneath->deprecated_xfer_memory (memaddr, myaddr, len, write,
-                                           attrib, target);
-
-  do_cleanups (old_chain);
-  return xfer;
-}
-
-static void
-thread_db_fetch_registers (int regno)
-{
-  struct thread_info *thread_info;
-  prgregset_t gregset;
-  gdb_prfpregset_t fpregset;
-  td_err_e err;
-
-  if (!is_thread (inferior_ptid))
-    {
-      /* Pass the request to the target beneath us.  */
-      target_beneath->to_fetch_registers (regno);
-      return;
+      return pid_to_ptid (GET_PID (ptid));
     }
 
     }
 
-  thread_info = find_thread_pid (inferior_ptid);
-  thread_db_map_id2thr (thread_info, 1);
-
-  err = 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));
+  /* If we do not know about the main thread yet, this would be a good time to
+     find it.  */
+  if (ourstatus->kind == TARGET_WAITKIND_STOPPED && !have_threads ())
+    thread_db_find_new_threads ();
 
 
-  err = 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));
-
-  /* Note that we must call supply_gregset after calling the thread_db
-     routines because the thread_db routines call ps_lgetgregs and
-     friends which clobber GDB's register cache.  */
-  supply_gregset ((gdb_gregset_t *) gregset);
-  supply_fpregset (&fpregset);
-}
-
-static void
-thread_db_store_registers (int regno)
-{
-  prgregset_t gregset;
-  gdb_prfpregset_t fpregset;
-  td_err_e err;
-  struct thread_info *thread_info;
-
-  if (!is_thread (inferior_ptid))
-    {
-      /* Pass the request to the target beneath us.  */
-      target_beneath->to_store_registers (regno);
-      return;
-    }
-
-  thread_info = find_thread_pid (inferior_ptid);
-  thread_db_map_id2thr (thread_info, 1);
+  if (ourstatus->kind == TARGET_WAITKIND_STOPPED
+      && ourstatus->value.sig == TARGET_SIGNAL_TRAP)
+    /* Check for a thread event.  */
+    check_event (ptid);
 
 
-  if (regno != -1)
+  if (have_threads ())
     {
     {
-      char raw[MAX_REGISTER_SIZE];
-
-      deprecated_read_register_gen (regno, raw);
-      thread_db_fetch_registers (-1);
-      regcache_raw_supply (current_regcache, regno, raw);
+      /* Change ptids back into the higher level PID + TID format.  If
+        the thread is dead and no longer on the thread list, we will
+        get back a dead ptid.  This can occur if the thread death
+        event gets postponed by other simultaneous events.  In such a
+        case, we want to just ignore the event and continue on.  */
+
+      if (!ptid_equal (trap_ptid, null_ptid))
+       trap_ptid = thread_from_lwp (trap_ptid);
+
+      ptid = thread_from_lwp (ptid);
+      if (GET_PID (ptid) == -1)
+       ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
     }
 
     }
 
-  fill_gregset ((gdb_gregset_t *) gregset, -1);
-  fill_fpregset (&fpregset, -1);
-
-  err = 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);
-  if (err != TD_OK)
-    error ("Cannot store floating-point registers  for thread %ld: %s",
-          (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+  return ptid;
 }
 
 static void
 }
 
 static void
@@ -1078,88 +923,24 @@ thread_db_kill (void)
   target_beneath->to_kill ();
 }
 
   target_beneath->to_kill ();
 }
 
-static void
-thread_db_create_inferior (char *exec_file, char *allargs, char **env,
-                          int from_tty)
-{
-  unpush_target (&thread_db_ops);
-  using_thread_db = 0;
-  target_beneath->to_create_inferior (exec_file, allargs, env, from_tty);
-}
-
-static void
-thread_db_post_startup_inferior (ptid_t ptid)
-{
-  if (proc_handle.pid == 0)
-    {
-      /* The child process is now the actual multi-threaded
-         program.  Snatch its process ID...  */
-      proc_handle.pid = GET_PID (ptid);
-
-      /* ...and perform the remaining initialization steps.  */
-      enable_thread_event_reporting ();
-      thread_db_find_new_threads ();
-    }
-}
-
 static void
 thread_db_mourn_inferior (void)
 {
 static void
 thread_db_mourn_inferior (void)
 {
-  remove_thread_event_breakpoints ();
-
   /* Forget about the child's process ID.  We shouldn't need it
      anymore.  */
   proc_handle.pid = 0;
 
   target_beneath->to_mourn_inferior ();
 
   /* Forget about the child's process ID.  We shouldn't need it
      anymore.  */
   proc_handle.pid = 0;
 
   target_beneath->to_mourn_inferior ();
 
+  /* 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.  */
   unpush_target (&thread_db_ops);
   using_thread_db = 0;
 }
 
   /* Detach thread_db target ops.  */
   unpush_target (&thread_db_ops);
   using_thread_db = 0;
 }
 
-static int
-thread_db_thread_alive (ptid_t ptid)
-{
-  td_thrhandle_t th;
-  td_err_e err;
-
-  if (is_thread (ptid))
-    {
-      struct thread_info *thread_info;
-      thread_info = find_thread_pid (ptid);
-
-      thread_db_map_id2thr (thread_info, 0);
-      if (!thread_info->private->th_valid)
-       return 0;
-
-      err = 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);
-         if (err != TD_OK)
-           return 0;
-         thread_info->private->ti_valid = 1;
-       }
-
-      if (thread_info->private->ti.ti_state == TD_THR_UNKNOWN
-         || thread_info->private->ti.ti_state == TD_THR_ZOMBIE)
-       return 0;               /* A zombie thread.  */
-
-      return 1;
-    }
-
-  if (target_beneath->to_thread_alive)
-    return target_beneath->to_thread_alive (ptid);
-
-  return 0;
-}
-
 static int
 find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
 {
 static int
 find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
 {
@@ -1169,13 +950,29 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
 
   err = td_thr_get_info_p (th_p, &ti);
   if (err != TD_OK)
 
   err = td_thr_get_info_p (th_p, &ti);
   if (err != TD_OK)
-    error ("find_new_threads_callback: cannot get thread info: %s",
+    error (_("find_new_threads_callback: cannot get thread info: %s"),
           thread_db_err_str (err));
 
   if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
     return 0;                  /* A zombie -- ignore.  */
 
           thread_db_err_str (err));
 
   if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
     return 0;                  /* A zombie -- ignore.  */
 
-  ptid = BUILD_THREAD (ti.ti_tid, GET_PID (inferior_ptid));
+  ptid = ptid_build (GET_PID (inferior_ptid), ti.ti_lid, ti.ti_tid);
+
+  if (ti.ti_tid == 0)
+    {
+      /* 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.  */
+
+      err = 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));
+
+      return 0;
+    }
 
   if (!in_thread_list (ptid))
     attach_thread (ptid, th_p, &ti, 1);
 
   if (!in_thread_list (ptid))
     attach_thread (ptid, th_p, &ti, 1);
@@ -1193,7 +990,7 @@ thread_db_find_new_threads (void)
                          TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
                          TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
   if (err != TD_OK)
                          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));
+    error (_("Cannot find new threads: %s"), thread_db_err_str (err));
 }
 
 static char *
 }
 
 static char *
@@ -1202,32 +999,15 @@ thread_db_pid_to_str (ptid_t ptid)
   if (is_thread (ptid))
     {
       static char buf[64];
   if (is_thread (ptid))
     {
       static char buf[64];
-      td_thrinfo_t *ti_p;
-      td_err_e err;
       struct thread_info *thread_info;
 
       thread_info = find_thread_pid (ptid);
       struct thread_info *thread_info;
 
       thread_info = find_thread_pid (ptid);
-      thread_db_map_id2thr (thread_info, 0);
-      if (!thread_info->private->th_valid)
-       {
-         snprintf (buf, sizeof (buf), "Thread %ld (Missing)",
-                   GET_THREAD (ptid));
-         return buf;
-       }
-
-      ti_p = thread_db_get_info (thread_info);
-
-      if (ti_p->ti_state == TD_THR_ACTIVE && ti_p->ti_lid != 0)
-       {
-         snprintf (buf, sizeof (buf), "Thread %ld (LWP %d)",
-                   (long) ti_p->ti_tid, ti_p->ti_lid);
-       }
+      if (thread_info == NULL)
+       snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld) (Missing)",
+                 GET_THREAD (ptid), GET_LWP (ptid));
       else
       else
-       {
-         snprintf (buf, sizeof (buf), "Thread %ld (%s)",
-                   (long) ti_p->ti_tid,
-                   thread_db_state_str (ti_p->ti_state));
-       }
+       snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld)",
+                 GET_THREAD (ptid), GET_LWP (ptid));
 
       return buf;
     }
 
       return buf;
     }
@@ -1238,93 +1018,103 @@ thread_db_pid_to_str (ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
   return normal_pid_to_str (ptid);
 }
 
-/* Get the address of the thread local variable in OBJFILE which is
-   stored at OFFSET within the thread local storage for thread PTID.  */
+/* Return a string describing the state of the thread specified by
+   INFO.  */
+
+static char *
+thread_db_extra_thread_info (struct thread_info *info)
+{
+  if (info->private->dying)
+    return "Exiting";
+
+  return NULL;
+}
+
+/* Return 1 if this thread has the same LWP as the passed PTID.  */
+
+static int
+same_ptid_callback (struct thread_info *thread, void *arg)
+{
+  ptid_t *ptid_p = arg;
+
+  return GET_LWP (thread->ptid) == GET_LWP (*ptid_p);
+}
+
+/* Get the address of the thread local variable in load module LM which
+   is stored at OFFSET within the thread local storage for thread PTID.  */
 
 static CORE_ADDR
 
 static CORE_ADDR
-thread_db_get_thread_local_address (ptid_t ptid, struct objfile *objfile,
+thread_db_get_thread_local_address (ptid_t ptid,
+                                   CORE_ADDR lm,
                                    CORE_ADDR offset)
 {
                                    CORE_ADDR offset)
 {
+  /* If we have not discovered any threads yet, check now.  */
+  if (!is_thread (ptid) && !have_threads ())
+    thread_db_find_new_threads ();
+
+  /* Try to find a matching thread if we still have the LWP ID instead
+     of the thread ID.  */
+  if (!is_thread (ptid))
+    {
+      struct thread_info *thread;
+
+      thread = iterate_over_threads (same_ptid_callback, &ptid);
+      if (thread != NULL)
+       ptid = thread->ptid;
+    }
+
   if (is_thread (ptid))
     {
   if (is_thread (ptid))
     {
-      int objfile_is_library = (objfile->flags & OBJF_SHARED);
       td_err_e err;
       void *address;
       td_err_e err;
       void *address;
-      CORE_ADDR lm;
       struct thread_info *thread_info;
 
       /* glibc doesn't provide the needed interface.  */
       if (!td_thr_tls_get_addr_p)
       struct thread_info *thread_info;
 
       /* glibc doesn't provide the needed interface.  */
       if (!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.  */
-      lm = svr4_fetch_objfile_link_map (objfile);
+       throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
+                    _("No TLS library support"));
 
 
-      /* Whoops, we couldn't find one. Bail out.  */
-      if (!lm)
-       {
-         if (objfile_is_library)
-           error ("Cannot find shared library `%s' link_map in dynamic"
-                  " linker's module list", objfile->name);
-         else
-           error ("Cannot find executable file `%s' link_map in dynamic"
-                  " linker's module list", objfile->name);
-       }
+      /* Caller should have verified that lm != 0.  */
+      gdb_assert (lm != 0);
 
       /* Get info about the thread.  */
       thread_info = find_thread_pid (ptid);
 
       /* Get info about the thread.  */
       thread_info = find_thread_pid (ptid);
+      gdb_assert (thread_info);
       thread_db_map_id2thr (thread_info, 1);
 
       /* Finally, get the address of the variable.  */
       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,
+      err = td_thr_tls_get_addr_p (&thread_info->private->th,
+                                  (void *)(size_t) lm,
                                   offset, &address);
 
 #ifdef THREAD_DB_HAS_TD_NOTALLOC
       /* The memory hasn't been allocated, yet.  */
       if (err == TD_NOTALLOC)
                                   offset, &address);
 
 #ifdef THREAD_DB_HAS_TD_NOTALLOC
       /* The memory hasn't been allocated, yet.  */
       if (err == TD_NOTALLOC)
-       {
          /* Now, if libthread_db provided the initialization image's
             address, we *could* try to build a non-lvalue value from
             the initialization image.  */
          /* Now, if libthread_db provided the initialization image's
             address, we *could* try to build a non-lvalue value from
             the initialization image.  */
-         if (objfile_is_library)
-           error ("The inferior has not yet allocated storage for"
-                  " thread-local variables in\n"
-                  "the shared library `%s'\n"
-                  "for the thread %ld",
-                  objfile->name, (long) GET_THREAD (ptid));
-         else
-           error ("The inferior has not yet allocated storage for"
-                  " thread-local variables in\n"
-                  "the executable `%s'\n"
-                  "for the thread %ld",
-                  objfile->name, (long) GET_THREAD (ptid));
-       }
+        throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
+                     _("TLS not allocated yet"));
 #endif
 
       /* Something else went wrong.  */
       if (err != TD_OK)
 #endif
 
       /* Something else went wrong.  */
       if (err != TD_OK)
-       {
-         if (objfile_is_library)
-           error ("Cannot find thread-local storage for thread %ld, "
-                  "shared library %s:\n%s",
-                  (long) GET_THREAD (ptid),
-                  objfile->name, thread_db_err_str (err));
-         else
-           error ("Cannot find thread-local storage for thread %ld, "
-                  "executable file %s:\n%s",
-                  (long) GET_THREAD (ptid),
-                  objfile->name, thread_db_err_str (err));
-       }
+        throw_error (TLS_GENERIC_ERROR,
+                     (("%s")), thread_db_err_str (err));
 
       /* Cast assuming host == target.  Joy.  */
 
       /* Cast assuming host == target.  Joy.  */
-      return (CORE_ADDR) address;
+      /* Do proper sign extension for the target.  */
+      gdb_assert (exec_bfd);
+      return (bfd_get_sign_extend_vma (exec_bfd) > 0
+             ? (CORE_ADDR) (intptr_t) address
+             : (CORE_ADDR) (uintptr_t) address);
     }
 
   if (target_beneath->to_get_thread_local_address)
     }
 
   if (target_beneath->to_get_thread_local_address)
-    return target_beneath->to_get_thread_local_address (ptid, objfile,
-                                                       offset);
-
-  error ("Cannot find thread-local values on this target.");
+    return target_beneath->to_get_thread_local_address (ptid, lm, offset);
+  else
+    throw_error (TLS_GENERIC_ERROR,
+                _("TLS not supported on this target"));
 }
 
 static void
 }
 
 static void
@@ -1333,24 +1123,18 @@ init_thread_db_ops (void)
   thread_db_ops.to_shortname = "multi-thread";
   thread_db_ops.to_longname = "multi-threaded child process.";
   thread_db_ops.to_doc = "Threads and pthreads support.";
   thread_db_ops.to_shortname = "multi-thread";
   thread_db_ops.to_longname = "multi-threaded child process.";
   thread_db_ops.to_doc = "Threads and pthreads support.";
-  thread_db_ops.to_attach = thread_db_attach;
   thread_db_ops.to_detach = thread_db_detach;
   thread_db_ops.to_resume = thread_db_resume;
   thread_db_ops.to_wait = thread_db_wait;
   thread_db_ops.to_detach = thread_db_detach;
   thread_db_ops.to_resume = thread_db_resume;
   thread_db_ops.to_wait = thread_db_wait;
-  thread_db_ops.to_fetch_registers = thread_db_fetch_registers;
-  thread_db_ops.to_store_registers = thread_db_store_registers;
-  thread_db_ops.deprecated_xfer_memory = thread_db_xfer_memory;
   thread_db_ops.to_kill = thread_db_kill;
   thread_db_ops.to_kill = thread_db_kill;
-  thread_db_ops.to_create_inferior = thread_db_create_inferior;
-  thread_db_ops.to_post_startup_inferior = thread_db_post_startup_inferior;
   thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
   thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
-  thread_db_ops.to_thread_alive = thread_db_thread_alive;
   thread_db_ops.to_find_new_threads = thread_db_find_new_threads;
   thread_db_ops.to_pid_to_str = thread_db_pid_to_str;
   thread_db_ops.to_stratum = thread_stratum;
   thread_db_ops.to_has_thread_control = tc_schedlock;
   thread_db_ops.to_get_thread_local_address
     = thread_db_get_thread_local_address;
   thread_db_ops.to_find_new_threads = thread_db_find_new_threads;
   thread_db_ops.to_pid_to_str = thread_db_pid_to_str;
   thread_db_ops.to_stratum = thread_stratum;
   thread_db_ops.to_has_thread_control = tc_schedlock;
   thread_db_ops.to_get_thread_local_address
     = thread_db_get_thread_local_address;
+  thread_db_ops.to_extra_thread_info = thread_db_extra_thread_info;
   thread_db_ops.to_magic = OPS_MAGIC;
 }
 
   thread_db_ops.to_magic = OPS_MAGIC;
 }
 
@@ -1364,7 +1148,6 @@ _initialize_thread_db (void)
       add_target (&thread_db_ops);
 
       /* Add ourselves to objfile event chain.  */
       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;
+      observer_attach_new_objfile (thread_db_new_objfile);
     }
 }
     }
 }
This page took 0.03548 seconds and 4 git commands to generate.