*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / linux-thread-db.c
index aa8e2c7c44d3ae79dc36131ec60be37ccf9580a2..b64ac2ed0c063e2d0423fc0a0e28a38037243cfd 100644 (file)
@@ -1,7 +1,6 @@
 /* libthread_db assisted debugging support, generic parts.
 
-   Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1999-2001, 2003-2012 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -40,6 +39,7 @@
 #include "gdbcore.h"
 #include "observer.h"
 #include "linux-nat.h"
+#include "linux-procfs.h"
 
 #include <signal.h>
 
@@ -431,6 +431,9 @@ thread_from_lwp (ptid_t ptid)
   struct thread_db_info *info;
   struct thread_get_info_inout io = {0};
 
+  /* Just in case td_ta_map_lwp2thr doesn't initialize it completely.  */
+  th.th_unique = 0;
+
   /* This ptid comes from linux-nat.c, which should always fill in the
      LWP.  */
   gdb_assert (GET_LWP (ptid) != 0);
@@ -812,6 +815,38 @@ try_thread_db_load (const char *library)
   return 0;
 }
 
+/* Subroutine of try_thread_db_load_from_pdir to simplify it.
+   Try loading libthread_db from the same directory as OBJ.
+   The result is true for success.  */
+
+static int
+try_thread_db_load_from_pdir_1 (struct objfile *obj)
+{
+  struct cleanup *cleanup;
+  char *path, *cp;
+  int result;
+
+  if (obj->name[0] != '/')
+    {
+      warning (_("Expected absolute pathname for libpthread in the"
+                " inferior, but got %s."), obj->name);
+      return 0;
+    }
+
+  path = xmalloc (strlen (obj->name) + 1 + strlen (LIBTHREAD_DB_SO) + 1);
+  cleanup = make_cleanup (xfree, path);
+
+  strcpy (path, obj->name);
+  cp = strrchr (path, '/');
+  /* This should at minimum hit the first character.  */
+  gdb_assert (cp != NULL);
+  strcpy (cp + 1, LIBTHREAD_DB_SO);
+  result = try_thread_db_load (path);
+
+  do_cleanups (cleanup);
+  return result;
+}
+
 /* Handle $pdir in libthread-db-search-path.
    Look for libthread_db in the directory of libpthread.
    The result is true for success.  */
@@ -824,28 +859,15 @@ try_thread_db_load_from_pdir (void)
   ALL_OBJFILES (obj)
     if (libpthread_name_p (obj->name))
       {
-       char path[PATH_MAX], *cp;
-
-       gdb_assert (strlen (obj->name) < sizeof (path));
-       strcpy (path, obj->name);
-       cp = strrchr (path, '/');
-
-       if (cp == NULL)
-         {
-           warning (_("Expected absolute pathname for libpthread in the"
-                      " inferior, but got %s."), path);
-         }
-       else if (cp + 1 + strlen (LIBTHREAD_DB_SO) + 1 > path + sizeof (path))
-         {
-           warning (_("Unexpected: path to libpthread in the inferior is"
-                      " too long: %s"), path);
-         }
-       else
-         {
-           strcpy (cp + 1, LIBTHREAD_DB_SO);
-           if (try_thread_db_load (path))
-             return 1;
-         }
+       if (try_thread_db_load_from_pdir_1 (obj))
+         return 1;
+
+       /* We may have found the separate-debug-info version of
+          libpthread, and it may live in a directory without a matching
+          libthread_db.  */
+       if (obj->separate_debug_objfile_backlink != NULL)
+         return try_thread_db_load_from_pdir_1 (obj->separate_debug_objfile_backlink);
+
        return 0;
       }
 
@@ -869,24 +891,20 @@ try_thread_db_load_from_sdir (void)
 static int
 try_thread_db_load_from_dir (const char *dir, size_t dir_len)
 {
-  char path[PATH_MAX];
+  struct cleanup *cleanup;
+  char *path;
+  int result;
 
-  if (dir_len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
-    {
-      char *cp = xmalloc (dir_len + 1);
-
-      memcpy (cp, dir, dir_len);
-      cp[dir_len] = '\0';
-      warning (_("libthread-db-search-path component too long,"
-                " ignored: %s."), cp);
-      xfree (cp);
-      return 0;
-    }
+  path = xmalloc (dir_len + 1 + strlen (LIBTHREAD_DB_SO) + 1);
+  cleanup = make_cleanup (xfree, path);
 
   memcpy (path, dir, dir_len);
   path[dir_len] = '/';
   strcpy (path + dir_len + 1, LIBTHREAD_DB_SO);
-  return try_thread_db_load (path);
+  result = try_thread_db_load (path);
+
+  do_cleanups (cleanup);
+  return result;
 }
 
 /* Search libthread_db_search_path for libthread_db which "agrees"
@@ -1058,16 +1076,37 @@ check_for_thread_db (void)
     return;
 }
 
+/* This function is called via the new_objfile observer.  */
+
 static void
 thread_db_new_objfile (struct objfile *objfile)
 {
   /* This observer must always be called with inferior_ptid set
      correctly.  */
 
-  if (objfile != NULL)
+  if (objfile != NULL
+      /* Only check for thread_db if we loaded libpthread,
+        or if this is the main symbol file.
+        We need to check OBJF_MAINLINE to handle the case of debugging
+        a statically linked executable AND the symbol file is specified AFTER
+        the exec file is loaded (e.g., gdb -c core ; file foo).
+        For dynamically linked executables, libpthread can be near the end
+        of the list of shared libraries to load, and in an app of several
+        thousand shared libraries, this can otherwise be painful.  */
+      && ((objfile->flags & OBJF_MAINLINE) != 0
+         || libpthread_name_p (objfile->name)))
     check_for_thread_db ();
 }
 
+/* This function is called via the inferior_created observer.
+   This handles the case of debugging statically linked executables.  */
+
+static void
+thread_db_inferior_created (struct target_ops *target, int from_tty)
+{
+  check_for_thread_db ();
+}
+
 /* Attach to a new thread.  This function is called when we receive a
    TD_CREATE event or when we iterate over all threads and find one
    that wasn't already in our list.  Returns true on success.  */
@@ -1121,9 +1160,25 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
 
   /* Under GNU/Linux, we have to attach to each and every thread.  */
   if (target_has_execution
-      && tp == NULL
-      && lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid))) < 0)
-    return 0;
+      && tp == NULL)
+    {
+      int res;
+
+      res = lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)));
+      if (res < 0)
+       {
+         /* Error, stop iterating.  */
+         return 0;
+       }
+      else if (res > 0)
+       {
+         /* Pretend this thread doesn't exist yet, and keep
+            iterating.  */
+         return 1;
+       }
+
+      /* Otherwise, we sucessfully attached to the thread.  */
+    }
 
   /* Construct the thread's private data.  */
   private = xmalloc (sizeof (struct private_thread_info));
@@ -1517,20 +1572,6 @@ thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
   int pid = ptid_get_pid (ptid);
   int i, loop;
 
-  if (target_has_execution)
-    {
-      struct lwp_info *lp;
-
-      /* In linux, we can only read memory through a stopped lwp.  */
-      ALL_LWPS (lp, ptid)
-       if (lp->stopped && ptid_get_pid (lp->ptid) == pid)
-         break;
-
-      if (!lp)
-       /* There is no stopped thread.  Bail out.  */
-       return;
-    }
-
   info = get_thread_db_info (GET_PID (ptid));
 
   /* Access an lwp we know is stopped.  */
@@ -1572,13 +1613,25 @@ static void
 thread_db_find_new_threads (struct target_ops *ops)
 {
   struct thread_db_info *info;
+  struct inferior *inf;
 
-  info = get_thread_db_info (GET_PID (inferior_ptid));
+  ALL_INFERIORS (inf)
+    {
+      struct thread_info *thread;
 
-  if (info == NULL)
-    return;
+      if (inf->pid == 0)
+       continue;
 
-  thread_db_find_new_threads_1 (inferior_ptid);
+      info = get_thread_db_info (inf->pid);
+      if (info == NULL)
+       continue;
+
+      thread = any_live_thread_of_process (inf->pid);
+      if (thread == NULL || thread->executing)
+       continue;
+
+      thread_db_find_new_threads_1 (thread->ptid);
+    }
 
   if (target_has_execution)
     iterate_over_lwps (minus_one_ptid /* iterate over all */,
@@ -1812,4 +1865,9 @@ When non-zero, libthread-db debugging is enabled."),
 
   /* Add ourselves to objfile event chain.  */
   observer_attach_new_objfile (thread_db_new_objfile);
+
+  /* Add ourselves to inferior_created event chain.
+     This is needed to handle debugging statically linked programs where
+     the new_objfile observer won't get called for libpthread.  */
+  observer_attach_inferior_created (thread_db_inferior_created);
 }
This page took 0.027493 seconds and 4 git commands to generate.