From 98a5dd1327030f71f3bd23c7c3c3d87ca1e3fac4 Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Fri, 13 May 2011 22:36:07 +0000 Subject: [PATCH] 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. 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 | 13 +++ gdb/NEWS | 14 ++++ gdb/doc/ChangeLog | 3 + gdb/doc/gdb.texinfo | 17 +++- gdb/gdb_thread_db.h | 5 +- gdb/gdbserver/ChangeLog | 8 ++ gdb/gdbserver/thread-db.c | 98 +++++++++++++++------- gdb/linux-thread-db.c | 202 ++++++++++++++++++++++++++++++---------------- 8 files changed, 256 insertions(+), 104 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 302b403..70d4f6c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,18 @@ 2011-05-13 Doug Evans + 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. diff --git a/gdb/NEWS b/gdb/NEWS index f362b08..99615d2 100644 --- 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 diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 15d203e..f145574 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,5 +1,8 @@ 2011-05-13 Doug Evans + * 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 diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index ae87528..08ee158 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -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 diff --git a/gdb/gdb_thread_db.h b/gdb/gdb_thread_db.h index 957ed2c..e20b415 100644 --- a/gdb/gdb_thread_db.h +++ b/gdb/gdb_thread_db.h @@ -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 diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index c5ae99f..9c19d58 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,11 @@ +2011-05-13 Doug Evans + + * 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 * server.c (handle_query): Add EnableDisableTracepoints to the list diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index 872151e..515dff2 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -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); diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index 43dda48..aa8e2c7 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -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. */ -- 2.7.4