From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2138 invoked by alias); 10 May 2011 19:09:53 -0000 Received: (qmail 2111 invoked by uid 22791); 10 May 2011 19:09:51 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_HELO_PASS,TW_BJ,TW_CP,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.67) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 10 May 2011 19:09:34 +0000 Received: from wpaz5.hot.corp.google.com (wpaz5.hot.corp.google.com [172.24.198.69]) by smtp-out.google.com with ESMTP id p4AJ9Sg0013593; Tue, 10 May 2011 12:09:28 -0700 Received: from ruffy.mtv.corp.google.com (ruffy.mtv.corp.google.com [172.18.118.116]) by wpaz5.hot.corp.google.com with ESMTP id p4AJ9QlT027962; Tue, 10 May 2011 12:09:27 -0700 Received: by ruffy.mtv.corp.google.com (Postfix, from userid 67641) id A294F246199; Tue, 10 May 2011 12:09:26 -0700 (PDT) To: gdb-patches@sourceware.org, tromey@redhat.com.jankratochvil@redhat.com Subject: [RFA] Add support for $sdir and $pdir to libthread-db-search-path Message-Id: <20110510190926.A294F246199@ruffy.mtv.corp.google.com> Date: Tue, 10 May 2011 19:09:00 -0000 From: dje@google.com (Doug Evans) X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-05/txt/msg00257.txt.bz2 Hi. This patch adds $sdir to the patch referenced here: http://sourceware.org/ml/gdb-patches/2011-04/msg00553.html and puts $sdir ahead of $pdir. If/when gdb gets a security model I think $pdir should be moved ahead of $sdir. It also simplifies some of the code to parse libthread-db-search-path. Ok to check in? 2011-05-10 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. 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. Index: NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.438 diff -u -p -r1.438 NEWS --- NEWS 9 May 2011 21:49:55 -0000 1.438 +++ NEWS 10 May 2011 18:48:38 -0000 @@ -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: gdb_thread_db.h =================================================================== RCS file: /cvs/src/src/gdb/gdb_thread_db.h,v retrieving revision 1.16 diff -u -p -r1.16 gdb_thread_db.h --- gdb_thread_db.h 7 Jan 2011 19:36:17 -0000 1.16 +++ gdb_thread_db.h 10 May 2011 18:48:38 -0000 @@ -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: linux-thread-db.c =================================================================== RCS file: /cvs/src/src/gdb/linux-thread-db.c,v retrieving revision 1.84 diff -u -p -r1.84 linux-thread-db.c --- linux-thread-db.c 10 May 2011 18:45:22 -0000 1.84 +++ linux-thread-db.c 10 May 2011 18:48:38 -0000 @@ -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; - } - strcat (path, "/"); - strcat (path, LIBTHREAD_DB_SO); - if (try_thread_db_load (path)) + if (this_dir_len == sizeof ("$pdir") - 1 + && strncmp (this_dir, "$pdir", this_dir_len) == 0) { - rc = 1; - break; + if (try_thread_db_load_from_pdir ()) + { + rc = 1; + break; + } + } + else if (this_dir_len == sizeof ("$sdir") - 1 + && strncmp (this_dir, "$sdir", this_dir_len) == 0) + { + 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. */ Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.832 diff -u -p -r1.832 gdb.texinfo --- doc/gdb.texinfo 10 May 2011 16:53:22 -0000 1.832 +++ doc/gdb.texinfo 10 May 2011 18:48:39 -0000 @@ -2855,14 +2855,22 @@ watchpoints in programs with multiple th 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. +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. @@ -16371,6 +16379,9 @@ directories to search for @code{libthrea 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: gdbserver/thread-db.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/thread-db.c,v retrieving revision 1.40 diff -u -p -r1.40 thread-db.c --- gdbserver/thread-db.c 10 May 2011 16:53:23 -0000 1.40 +++ gdbserver/thread-db.c 10 May 2011 18:48:39 -0000 @@ -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);