Support $pdir and $sdir in libthread-db-search-path.
authorDoug Evans <dje@google.com>
Fri, 13 May 2011 22:36:07 +0000 (22:36 +0000)
committerDoug Evans <dje@google.com>
Fri, 13 May 2011 22:36:07 +0000 (22:36 +0000)
* NEWS: Mention $sdir,$pdir.
* gdb_thread_db.h (LIBTHREAD_DB_SEARCH_PATH): Add $sdir:$pdir.
* linux-thread-db.c (try_thread_db_load_from_pdir): New function.
(try_thread_db_load_from_sdir): New function.
(try_thread_db_load_from_dir): New function.
(thread_db_load_search): Handle $pdir, $sdir.  Remove trying of
system directories if search of libthread-db-search-path fails,
that is now done via $sdir.
(has_libpthread): New function.
(thread_db_load): Remove search for libthread_db in directory of
libpthread, that is now done via $pdir.

gdbserver/
* thread-db.c (try_thread_db_load_from_sdir): New function.
(try_thread_db_load_from_dir): New function.
(thread_db_load_search): Handle $sdir, ignore $pdir.
Remove trying of system directories if search of
libthread-db-search-path fails, that is now done via $sdir.

doc/
* gdb.texinfo (Threads): Document $sdir,$pdir.
(Server): Document $pdir exception.

gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdb_thread_db.h
gdb/gdbserver/ChangeLog
gdb/gdbserver/thread-db.c
gdb/linux-thread-db.c

index 302b403..70d4f6c 100644 (file)
@@ -1,5 +1,18 @@
 2011-05-13  Doug Evans  <dje@google.com>
 
+       Support $pdir and $sdir in libthread-db-search-path.
+       * NEWS: Mention $sdir,$pdir.
+       * gdb_thread_db.h (LIBTHREAD_DB_SEARCH_PATH): Add $sdir:$pdir.
+       * linux-thread-db.c (try_thread_db_load_from_pdir): New function.
+       (try_thread_db_load_from_sdir): New function.
+       (try_thread_db_load_from_dir): New function.
+       (thread_db_load_search): Handle $pdir, $sdir.  Remove trying of
+       system directories if search of libthread-db-search-path fails,
+       that is now done via $sdir.
+       (has_libpthread): New function.
+       (thread_db_load): Remove search for libthread_db in directory of
+       libpthread, that is now done via $pdir.
+
        * NEWS: Mention "info auto-load-scripts".
        * python/py-auto-load.c (struct auto_load_pspace_info): New member
        script_not_found_warning_printed.
index f362b08..99615d2 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,20 @@
 
 *** Changes since GDB 7.3
 
+* libthread-db-search-path now supports two special values: $sdir and $pdir.
+  $sdir specifies the default system locations of shared libraries.
+  $pdir specifies the directory where the libpthread used by the application
+  lives.
+
+  GDB no longer looks in $sdir and $pdir after it has searched the directories
+  mentioned in libthread-db-search-path.  If you want to search those
+  directories, they must be specified in libthread-db-search-path.
+  The default value of libthread-db-search-path on GNU/Linux and Solaris
+  systems is now "$sdir:$pdir".
+
+  $pdir is not supported by gdbserver, it is currently ignored.
+  $sdir is supported by gdbserver.
+
 * New configure option --with-iconv-bin.
   When using the internationalization support like the one in the GNU C
   library, GDB will invoke the "iconv" program to get a list of supported
index 15d203e..f145574 100644 (file)
@@ -1,5 +1,8 @@
 2011-05-13  Doug Evans  <dje@google.com>
 
+       * gdb.texinfo (Threads): Document $sdir,$pdir.
+       (Server): Document $pdir exception.
+
        * gdb.texinfo (Auto-loading): Document "info auto-load-scripts".
 
        * gdb.texinfo (Threads): Clarify default value for
index ae87528..08ee158 100644 (file)
@@ -2858,16 +2858,22 @@ watchpoints in programs with multiple threads.
 If this variable is set, @var{path} is a colon-separated list of
 directories @value{GDBN} will use to search for @code{libthread_db}.
 If you omit @var{path}, @samp{libthread-db-search-path} will be reset to
-its default value (an empty list on @sc{gnu}/Linux and Solaris systems).
+its default value (@code{$sdir:$pdir} on @sc{gnu}/Linux and Solaris systems).
 Internally, the default value comes from the @code{LIBTHREAD_DB_SEARCH_PATH}
 macro.
 
 On @sc{gnu}/Linux and Solaris systems, @value{GDBN} uses a ``helper''
 @code{libthread_db} library to obtain information about threads in the
 inferior process.  @value{GDBN} will use @samp{libthread-db-search-path}
-to find @code{libthread_db}.  If that fails, @value{GDBN} will continue
-with default system shared library directories, and finally the directory
-from which @code{libpthread} was loaded in the inferior process.
+to find @code{libthread_db}.
+
+A special entry @samp{$sdir} for @samp{libthread-db-search-path}
+refers to the default system directories that are
+normally searched for loading shared libraries.
+
+A special entry @samp{$pdir} for @samp{libthread-db-search-path}
+refers to the directory from which @code{libpthread}
+was loaded in the inferior process.
 
 For any @code{libthread_db} library @value{GDBN} finds in above directories,
 @value{GDBN} attempts to initialize it with the current inferior process.
@@ -16382,6 +16388,9 @@ directories to search for @code{libthread_db} (@pxref{Threads,,set
 libthread-db-search-path}).  If you omit @var{path},
 @samp{libthread-db-search-path} will be reset to its default value.
 
+The special entry @samp{$pdir} for @samp{libthread-db-search-path} is
+not supported in @code{gdbserver}.
+
 @item monitor exit
 Tell gdbserver to exit immediately.  This command should be followed by
 @code{disconnect} to close the debugging session.  @code{gdbserver} will
index 957ed2c..e20b415 100644 (file)
@@ -6,7 +6,10 @@
 #endif
 
 #ifndef LIBTHREAD_DB_SEARCH_PATH
-#define LIBTHREAD_DB_SEARCH_PATH ""
+/* $sdir appears before $pdir for some minimal security protection:
+   we trust the system libthread_db.so a bit more than some random
+   libthread_db associated with whatever libpthread the app is using.  */
+#define LIBTHREAD_DB_SEARCH_PATH "$sdir:$pdir"
 #endif
 
 #else
index c5ae99f..9c19d58 100644 (file)
@@ -1,3 +1,11 @@
+2011-05-13  Doug Evans  <dje@google.com>
+
+       * thread-db.c (try_thread_db_load_from_sdir): New function.
+       (try_thread_db_load_from_dir): New function.
+       (thread_db_load_search): Handle $sdir, ignore $pdir.
+       Remove trying of system directories if search of
+       libthread-db-search-path fails, that is now done via $sdir.
+
 2011-05-12  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        * server.c (handle_query): Add EnableDisableTracepoints to the list
index 872151e..515dff2 100644 (file)
@@ -698,10 +698,50 @@ try_thread_db_load (const char *library)
   return 0;
 }
 
+/* Handle $sdir in libthread-db-search-path.
+   Look for libthread_db in the system dirs, or wherever a plain
+   dlopen(file_without_path) will look.
+   The result is true for success.  */
+
 static int
-thread_db_load_search (void)
+try_thread_db_load_from_sdir (void)
+{
+  return try_thread_db_load (LIBTHREAD_DB_SO);
+}
+
+/* Try to load libthread_db from directory DIR of length DIR_LEN.
+   The result is true for success.  */
+
+static int
+try_thread_db_load_from_dir (const char *dir, size_t dir_len)
 {
   char path[PATH_MAX];
+
+  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);
+      free (cp);
+      return 0;
+    }
+
+  memcpy (path, dir, dir_len);
+  path[dir_len] = '/';
+  strcpy (path + dir_len + 1, LIBTHREAD_DB_SO);
+  return try_thread_db_load (path);
+}
+
+/* Search libthread_db_search_path for libthread_db which "agrees"
+   to work on current inferior.
+   The result is true for success.  */
+
+static int
+thread_db_load_search (void)
+{
   const char *search_path;
   int rc = 0;
 
@@ -712,49 +752,45 @@ thread_db_load_search (void)
   while (*search_path)
     {
       const char *end = strchr (search_path, ':');
+      const char *this_dir = search_path;
+      size_t this_dir_len;
+
       if (end)
        {
-         size_t len = end - search_path;
-         if (len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
-           {
-             char *cp = xmalloc (len + 1);
-             memcpy (cp, search_path, len);
-             cp[len] = '\0';
-             warning ("libthread_db_search_path component too long, "
-                      "ignored: %s.", cp);
-             free (cp);
-             search_path += len + 1;
-             continue;
-           }
-         memcpy (path, search_path, len);
-         path[len] = '\0';
-         search_path += len + 1;
+         this_dir_len = end - search_path;
+         search_path += this_dir_len + 1;
        }
       else
        {
-         size_t len = strlen (search_path);
+         this_dir_len = strlen (this_dir);
+         search_path += this_dir_len;
+       }
 
-         if (len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
+      if (this_dir_len == sizeof ("$pdir") - 1
+         && strncmp (this_dir, "$pdir", this_dir_len) == 0)
+       {
+         /* We don't maintain a list of loaded libraries so we don't know
+            where libpthread lives.  We *could* fetch the info, but we don't
+            do that yet.  Ignore it.  */
+       }
+      else if (this_dir_len == sizeof ("$sdir") - 1
+              && strncmp (this_dir, "$sdir", this_dir_len) == 0)
+       {
+         if (try_thread_db_load_from_sdir ())
            {
-             warning ("libthread_db_search_path component too long,"
-                      " ignored: %s.", search_path);
+             rc = 1;
              break;
            }
-         memcpy (path, search_path, len + 1);
-         search_path += len;
        }
-      strcat (path, "/");
-      strcat (path, LIBTHREAD_DB_SO);
-      if (debug_threads)
-       fprintf (stderr, "thread_db_load_search trying %s\n", path);
-      if (try_thread_db_load (path))
+      else
        {
-         rc = 1;
-         break;
+         if (try_thread_db_load_from_dir (this_dir, this_dir_len))
+           {
+             rc = 1;
+             break;
+           }
        }
     }
-  if (rc == 0)
-    rc = try_thread_db_load (LIBTHREAD_DB_SO);
 
   if (debug_threads)
     fprintf (stderr, "thread_db_load_search returning %d\n", rc);
index 43dda48..aa8e2c7 100644 (file)
@@ -812,73 +812,163 @@ try_thread_db_load (const char *library)
   return 0;
 }
 
+/* Handle $pdir in libthread-db-search-path.
+   Look for libthread_db in the directory of libpthread.
+   The result is true for success.  */
+
+static int
+try_thread_db_load_from_pdir (void)
+{
+  struct objfile *obj;
+
+  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;
+         }
+       return 0;
+      }
+
+  return 0;
+}
+
+/* Handle $sdir in libthread-db-search-path.
+   Look for libthread_db in the system dirs, or wherever a plain
+   dlopen(file_without_path) will look.
+   The result is true for success.  */
+
+static int
+try_thread_db_load_from_sdir (void)
+{
+  return try_thread_db_load (LIBTHREAD_DB_SO);
+}
+
+/* Try to load libthread_db from directory DIR of length DIR_LEN.
+   The result is true for success.  */
+
+static int
+try_thread_db_load_from_dir (const char *dir, size_t dir_len)
+{
+  char path[PATH_MAX];
+
+  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;
+    }
+
+  memcpy (path, dir, dir_len);
+  path[dir_len] = '/';
+  strcpy (path + dir_len + 1, LIBTHREAD_DB_SO);
+  return try_thread_db_load (path);
+}
+
 /* Search libthread_db_search_path for libthread_db which "agrees"
-   to work on current inferior.  */
+   to work on current inferior.
+   The result is true for success.  */
 
 static int
 thread_db_load_search (void)
 {
-  char path[PATH_MAX];
   const char *search_path = libthread_db_search_path;
   int rc = 0;
 
   while (*search_path)
     {
       const char *end = strchr (search_path, ':');
+      const char *this_dir = search_path;
+      size_t this_dir_len;
 
       if (end)
        {
-         size_t len = end - search_path;
-
-          if (len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
-            {
-              char *cp = xmalloc (len + 1);
-
-              memcpy (cp, search_path, len);
-              cp[len] = '\0';
-              warning (_("libthread_db_search_path component too long,"
-                         " ignored: %s."), cp);
-              xfree (cp);
-              search_path += len + 1;
-              continue;
-            }
-         memcpy (path, search_path, len);
-         path[len] = '\0';
-         search_path += len + 1;
+         this_dir_len = end - search_path;
+         search_path += this_dir_len + 1;
        }
       else
        {
-          size_t len = strlen (search_path);
+         this_dir_len = strlen (this_dir);
+         search_path += this_dir_len;
+       }
 
-          if (len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
-            {
-              warning (_("libthread_db_search_path component too long,"
-                         " ignored: %s."), search_path);
-              break;
-            }
-         memcpy (path, search_path, len + 1);
-         search_path += len;
+      if (this_dir_len == sizeof ("$pdir") - 1
+         && strncmp (this_dir, "$pdir", this_dir_len) == 0)
+       {
+         if (try_thread_db_load_from_pdir ())
+           {
+             rc = 1;
+             break;
+           }
        }
-      strcat (path, "/");
-      strcat (path, LIBTHREAD_DB_SO);
-      if (try_thread_db_load (path))
+      else if (this_dir_len == sizeof ("$sdir") - 1
+              && strncmp (this_dir, "$sdir", this_dir_len) == 0)
        {
-         rc = 1;
-         break;
+         if (try_thread_db_load_from_sdir ())
+           {
+             rc = 1;
+             break;
+           }
+       }
+      else
+       {
+         if (try_thread_db_load_from_dir (this_dir, this_dir_len))
+           {
+             rc = 1;
+             break;
+           }
        }
     }
-  if (rc == 0)
-    rc = try_thread_db_load (LIBTHREAD_DB_SO);
+
+  if (libthread_db_debug)
+    printf_unfiltered (_("thread_db_load_search returning %d\n"), rc);
   return rc;
 }
 
+/* Return non-zero if the inferior has a libpthread.  */
+
+static int
+has_libpthread (void)
+{
+  struct objfile *obj;
+
+  ALL_OBJFILES (obj)
+    if (libpthread_name_p (obj->name))
+      return 1;
+
+  return 0;
+}
+
 /* Attempt to load and initialize libthread_db.
    Return 1 on success.  */
 
 static int
 thread_db_load (void)
 {
-  struct objfile *obj;
   struct thread_db_info *info;
 
   info = get_thread_db_info (GET_PID (inferior_ptid));
@@ -898,39 +988,15 @@ thread_db_load (void)
   if (thread_db_load_search ())
     return 1;
 
-  /* None of the libthread_db's on our search path, not the system default
-     ones worked.  If the executable is dynamically linked against
-     libpthread, try loading libthread_db from the same directory.  */
-
-  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;
-         }
-       warning (_("Unable to find libthread_db matching inferior's thread"
-                  " library, thread debugging will not be available."));
-       return 0;
+  /* We couldn't find a libthread_db.
+     If the inferior has a libpthread warn the user.  */
+  if (has_libpthread ())
+    {
+      warning (_("Unable to find libthread_db matching inferior's thread"
+                " library, thread debugging will not be available."));
+      return 0;
     }
+
   /* Either this executable isn't using libpthread at all, or it is
      statically linked.  Since we can't easily distinguish these two cases,
      no warning is issued.  */