2009-05-15 Paul Pluzhnikov <ppluzhnikov@google.com>
* NEWS: Mention set/show libthread-db-search-path. * gdb_thread_db.h (LIBTHREAD_DB_SEARCH_PATH): New define. (LIBTHREAD_DB_SO): Moved from linux-thread-db.c * linux-thread-db.c (libthread_db_search_path): New setting. (thread_db_handle): New variable (replaces using_thread_db). (try_thread_db_load_1): New function. (try_thread_db_load, thread_db_load_search): Likewise. (dladdr_to_soname): Likewise. (thread_db_load): Iterate over possibly multiple libthread_db's. (check_for_thread_db): Attempt to load new libthread_db. (thread_db_detach, thread_db_wait): Unload libthread_db. (thread_db_mourn_inferior): Likewise. (_initialize_thread_db): Add new libthread-db-search-path option. Defer loading of libthread_db to check_for_thread_db. * solib.c (libpthread_name_p): New function. (libpthread_solib_p): Call it. * solib.h (libpthread_name_p): New prototype.
This commit is contained in:
parent
d127ecce68
commit
17a37d488c
|
@ -1,3 +1,23 @@
|
|||
2009-05-15 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
|
||||
* NEWS: Mention set/show libthread-db-search-path.
|
||||
* gdb_thread_db.h (LIBTHREAD_DB_SEARCH_PATH): New define.
|
||||
(LIBTHREAD_DB_SO): Moved from linux-thread-db.c
|
||||
* linux-thread-db.c (libthread_db_search_path): New setting.
|
||||
(thread_db_handle): New variable (replaces using_thread_db).
|
||||
(try_thread_db_load_1): New function.
|
||||
(try_thread_db_load, thread_db_load_search): Likewise.
|
||||
(dladdr_to_soname): Likewise.
|
||||
(thread_db_load): Iterate over possibly multiple libthread_db's.
|
||||
(check_for_thread_db): Attempt to load new libthread_db.
|
||||
(thread_db_detach, thread_db_wait): Unload libthread_db.
|
||||
(thread_db_mourn_inferior): Likewise.
|
||||
(_initialize_thread_db): Add new libthread-db-search-path option.
|
||||
Defer loading of libthread_db to check_for_thread_db.
|
||||
* solib.c (libpthread_name_p): New function.
|
||||
(libpthread_solib_p): Call it.
|
||||
* solib.h (libpthread_name_p): New prototype.
|
||||
|
||||
2009-05-15 Pierre Muller <muller@ics.u-strasbg.fr>
|
||||
|
||||
* MAINTAINERS: Update my email address.
|
||||
|
|
5
gdb/NEWS
5
gdb/NEWS
|
@ -300,6 +300,11 @@ show tcp connect-timeout
|
|||
with a specified timeout period; this is useful if the stub is launched
|
||||
in parallel with GDB but may not be ready to accept connections immediately.
|
||||
|
||||
set libthread-db-search-path
|
||||
show libthread-db-search-path
|
||||
Control list of directories which GDB will search for appropriate
|
||||
libthread_db.
|
||||
|
||||
* New native configurations
|
||||
|
||||
x86/x86_64 Darwin i[34567]86-*-darwin*
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2009-05-15 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
|
||||
* gdb.texinfo (Threads): Document libthread-db-search-path.
|
||||
|
||||
2009-05-15 Nick Roberts <nickrob@snap.net.nz>
|
||||
|
||||
* gdb.texinfo (GDB/MI General Design): Break up into four nodes.
|
||||
|
|
|
@ -2430,6 +2430,9 @@ a command to apply a command to a list of threads
|
|||
@item thread-specific breakpoints
|
||||
@item @samp{set print thread-events}, which controls printing of
|
||||
messages on thread start and exit.
|
||||
@item @samp{set libthread-db-search-path @var{path}}, which lets
|
||||
the user specify which @code{libthread_db} to use if the default choice
|
||||
isn't compatible with the program.
|
||||
@end itemize
|
||||
|
||||
@quotation
|
||||
|
@ -2648,6 +2651,38 @@ programs with multiple threads.
|
|||
@xref{Set Watchpoints,,Setting Watchpoints}, for information about
|
||||
watchpoints in programs with multiple threads.
|
||||
|
||||
@table @code
|
||||
@kindex set libthread-db-search-path
|
||||
@cindex search path for @code{libthread_db}
|
||||
@item set libthread-db-search-path @r{[}@var{path}@r{]}
|
||||
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
|
||||
an empty list.
|
||||
|
||||
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.
|
||||
|
||||
For any @code{libthread_db} library @value{GDBN} finds in above directories,
|
||||
@value{GDBN} attempts to initialize it with the current inferior process.
|
||||
If this initialization fails (which could happen because of a version
|
||||
mismatch between @code{libthread_db} and @code{libpthread}), @value{GDBN}
|
||||
will unload @code{libthread_db}, and continue with the next directory.
|
||||
If none of @code{libthread_db} libraries initialize successfully,
|
||||
@value{GDBN} will issue a warning and thread debugging will be disabled.
|
||||
|
||||
Setting @code{libthread-db-search-path} is currently implemented
|
||||
only on some platforms.
|
||||
|
||||
@kindex show libthread-db-search-path
|
||||
@item show libthread-db-search-path
|
||||
Display current libthread_db search path.
|
||||
@end table
|
||||
|
||||
@node Processes
|
||||
@section Debugging Programs with Multiple Processes
|
||||
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
#ifdef HAVE_THREAD_DB_H
|
||||
#include <thread_db.h>
|
||||
|
||||
#ifndef LIBTHREAD_DB_SO
|
||||
#define LIBTHREAD_DB_SO "libthread_db.so.1"
|
||||
#endif
|
||||
|
||||
#ifndef LIBTHREAD_DB_SEARCH_PATH
|
||||
#define LIBTHREAD_DB_SEARCH_PATH ""
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* Copyright (C) 1999, 2000, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
|
|
@ -26,13 +26,16 @@
|
|||
#include "gdb_thread_db.h"
|
||||
|
||||
#include "bfd.h"
|
||||
#include "command.h"
|
||||
#include "exceptions.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "gdbthread.h"
|
||||
#include "inferior.h"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.h"
|
||||
#include "target.h"
|
||||
#include "regcache.h"
|
||||
#include "solib.h"
|
||||
#include "solib-svr4.h"
|
||||
#include "gdbcore.h"
|
||||
#include "observer.h"
|
||||
|
@ -44,10 +47,6 @@
|
|||
#include <gnu/libc-version.h>
|
||||
#endif
|
||||
|
||||
#ifndef LIBTHREAD_DB_SO
|
||||
#define LIBTHREAD_DB_SO "libthread_db.so.1"
|
||||
#endif
|
||||
|
||||
/* GNU/Linux libthread_db support.
|
||||
|
||||
libthread_db is a library, provided along with libpthread.so, which
|
||||
|
@ -74,14 +73,17 @@
|
|||
of the ptid_t prevents thread IDs changing when libpthread is
|
||||
loaded or unloaded. */
|
||||
|
||||
static char *libthread_db_search_path;
|
||||
|
||||
/* If we're running on GNU/Linux, we must explicitly attach to any new
|
||||
threads. */
|
||||
|
||||
/* This module's target vector. */
|
||||
static struct target_ops thread_db_ops;
|
||||
|
||||
/* Non-zero if we're using this module's target vector. */
|
||||
static int using_thread_db;
|
||||
/* Handle from dlopen for libthread_db.so. Not NULL if we're using this
|
||||
module's target vector. */
|
||||
static void *thread_db_handle;
|
||||
|
||||
/* Non-zero if we have determined the signals used by the threads
|
||||
library. */
|
||||
|
@ -344,7 +346,7 @@ thread_db_attach_lwp (ptid_t ptid)
|
|||
td_thrinfo_t ti;
|
||||
td_err_e err;
|
||||
|
||||
if (!using_thread_db)
|
||||
if (thread_db_handle == NULL)
|
||||
return 0;
|
||||
|
||||
/* This ptid comes from linux-nat.c, which should always fill in the
|
||||
|
@ -385,71 +387,6 @@ verbose_dlsym (void *handle, const char *name)
|
|||
return sym;
|
||||
}
|
||||
|
||||
static int
|
||||
thread_db_load (void)
|
||||
{
|
||||
void *handle;
|
||||
td_err_e err;
|
||||
|
||||
handle = dlopen (LIBTHREAD_DB_SO, RTLD_NOW);
|
||||
if (handle == NULL)
|
||||
{
|
||||
fprintf_filtered (gdb_stderr, "\n\ndlopen failed on '%s' - %s\n",
|
||||
LIBTHREAD_DB_SO, dlerror ());
|
||||
fprintf_filtered (gdb_stderr,
|
||||
"GDB will not be able to debug pthreads.\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize pointers to the dynamic library functions we will use.
|
||||
Essential functions first. */
|
||||
|
||||
td_init_p = verbose_dlsym (handle, "td_init");
|
||||
if (td_init_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_ta_new_p = verbose_dlsym (handle, "td_ta_new");
|
||||
if (td_ta_new_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr");
|
||||
if (td_ta_map_id2thr_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_ta_map_lwp2thr_p = verbose_dlsym (handle, "td_ta_map_lwp2thr");
|
||||
if (td_ta_map_lwp2thr_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_ta_thr_iter_p = verbose_dlsym (handle, "td_ta_thr_iter");
|
||||
if (td_ta_thr_iter_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_thr_validate_p = verbose_dlsym (handle, "td_thr_validate");
|
||||
if (td_thr_validate_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_thr_get_info_p = verbose_dlsym (handle, "td_thr_get_info");
|
||||
if (td_thr_get_info_p == NULL)
|
||||
return 0;
|
||||
|
||||
/* Initialize the library. */
|
||||
err = td_init_p ();
|
||||
if (err != TD_OK)
|
||||
{
|
||||
warning (_("Cannot initialize libthread_db: %s"), thread_db_err_str (err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These are not essential. */
|
||||
td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr");
|
||||
td_ta_set_event_p = dlsym (handle, "td_ta_set_event");
|
||||
td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg");
|
||||
td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable");
|
||||
td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static td_err_e
|
||||
enable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp)
|
||||
{
|
||||
|
@ -541,6 +478,278 @@ enable_thread_event_reporting (void)
|
|||
}
|
||||
}
|
||||
|
||||
/* Attempt to initialize dlopen()ed libthread_db, described by HANDLE.
|
||||
Return 1 on success.
|
||||
Failure could happen if libthread_db does not have symbols we expect,
|
||||
or when it refuses to work with the current inferior (e.g. due to
|
||||
version mismatch between libthread_db and libpthread). */
|
||||
|
||||
static int
|
||||
try_thread_db_load_1 (void *handle)
|
||||
{
|
||||
td_err_e err;
|
||||
|
||||
/* Initialize pointers to the dynamic library functions we will use.
|
||||
Essential functions first. */
|
||||
|
||||
td_init_p = verbose_dlsym (handle, "td_init");
|
||||
if (td_init_p == NULL)
|
||||
return 0;
|
||||
|
||||
err = td_init_p ();
|
||||
if (err != TD_OK)
|
||||
{
|
||||
warning (_("Cannot initialize libthread_db: %s"), thread_db_err_str (err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
td_ta_new_p = verbose_dlsym (handle, "td_ta_new");
|
||||
if (td_ta_new_p == NULL)
|
||||
return 0;
|
||||
|
||||
/* Initialize the structure that identifies the child process. */
|
||||
proc_handle.ptid = inferior_ptid;
|
||||
|
||||
/* Now attempt to open a connection to the thread library. */
|
||||
err = td_ta_new_p (&proc_handle, &thread_agent);
|
||||
if (err != TD_OK)
|
||||
{
|
||||
td_ta_new_p = NULL;
|
||||
if (info_verbose)
|
||||
printf_unfiltered (_("td_ta_new failed: %s\n"),
|
||||
thread_db_err_str (err));
|
||||
else
|
||||
switch (err)
|
||||
{
|
||||
case TD_NOLIBTHREAD:
|
||||
#ifdef THREAD_DB_HAS_TD_VERSION
|
||||
case TD_VERSION:
|
||||
#endif
|
||||
/* The errors above are not unexpected and silently ignored:
|
||||
they just mean we haven't found correct version of
|
||||
libthread_db yet. */
|
||||
break;
|
||||
default:
|
||||
warning (_("td_ta_new failed: %s"), thread_db_err_str (err));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr");
|
||||
if (td_ta_map_id2thr_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_ta_map_lwp2thr_p = verbose_dlsym (handle, "td_ta_map_lwp2thr");
|
||||
if (td_ta_map_lwp2thr_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_ta_thr_iter_p = verbose_dlsym (handle, "td_ta_thr_iter");
|
||||
if (td_ta_thr_iter_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_thr_validate_p = verbose_dlsym (handle, "td_thr_validate");
|
||||
if (td_thr_validate_p == NULL)
|
||||
return 0;
|
||||
|
||||
td_thr_get_info_p = verbose_dlsym (handle, "td_thr_get_info");
|
||||
if (td_thr_get_info_p == NULL)
|
||||
return 0;
|
||||
|
||||
/* These are not essential. */
|
||||
td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr");
|
||||
td_ta_set_event_p = dlsym (handle, "td_ta_set_event");
|
||||
td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg");
|
||||
td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable");
|
||||
td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr");
|
||||
|
||||
printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
|
||||
|
||||
/* The thread library was detected. Activate the thread_db target. */
|
||||
push_target (&thread_db_ops);
|
||||
thread_db_handle = handle;
|
||||
|
||||
enable_thread_event_reporting ();
|
||||
thread_db_find_new_threads_1 ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Lookup a library in which given symbol resides.
|
||||
Note: this is looking in GDB process, not in the inferior.
|
||||
Returns library name, or NULL. */
|
||||
|
||||
static const char *
|
||||
dladdr_to_soname (const void *addr)
|
||||
{
|
||||
Dl_info info;
|
||||
|
||||
if (dladdr (addr, &info) != 0)
|
||||
return info.dli_fname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Attempt to use LIBRARY as libthread_db. LIBRARY could be absolute,
|
||||
relative, or just LIBTHREAD_DB. */
|
||||
|
||||
static int
|
||||
try_thread_db_load (const char *library)
|
||||
{
|
||||
void *handle;
|
||||
|
||||
if (info_verbose)
|
||||
printf_unfiltered (_("Trying host libthread_db library: %s.\n"),
|
||||
library);
|
||||
handle = dlopen (library, RTLD_NOW);
|
||||
if (handle == NULL)
|
||||
{
|
||||
if (info_verbose)
|
||||
printf_unfiltered (_("dlopen failed: %s.\n"), dlerror ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info_verbose && strchr (library, '/') == NULL)
|
||||
{
|
||||
void *td_init;
|
||||
|
||||
td_init = dlsym (handle, "td_init");
|
||||
if (td_init != NULL)
|
||||
{
|
||||
const char *const libpath = dladdr_to_soname (td_init);
|
||||
|
||||
if (libpath != NULL)
|
||||
printf_unfiltered (_("Host %s resolved to: %s.\n"),
|
||||
library, libpath);
|
||||
}
|
||||
}
|
||||
|
||||
if (try_thread_db_load_1 (handle))
|
||||
return 1;
|
||||
|
||||
/* This library "refused" to work on current inferior. */
|
||||
dlclose (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Search libthread_db_search_path for libthread_db which "agrees"
|
||||
to work on current inferior. */
|
||||
|
||||
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, ':');
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t len = strlen (search_path);
|
||||
|
||||
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))
|
||||
{
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rc == 0)
|
||||
rc = try_thread_db_load (LIBTHREAD_DB_SO);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Attempt to load and initialize libthread_db.
|
||||
Return 1 on success.
|
||||
*/
|
||||
|
||||
static int
|
||||
thread_db_load (void)
|
||||
{
|
||||
struct objfile *obj;
|
||||
|
||||
if (thread_db_handle != NULL)
|
||||
return 1;
|
||||
|
||||
/* 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 0;
|
||||
|
||||
/* Don't attempt to use thread_db for remote targets. */
|
||||
if (!target_can_run (¤t_target))
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
disable_thread_event_reporting (void)
|
||||
{
|
||||
|
@ -593,75 +802,34 @@ void
|
|||
check_for_thread_db (void)
|
||||
{
|
||||
td_err_e err;
|
||||
static int already_loaded;
|
||||
static void *last_loaded;
|
||||
|
||||
/* Do nothing if we couldn't load libthread_db.so.1. */
|
||||
if (td_ta_new_p == NULL)
|
||||
if (!thread_db_load ())
|
||||
return;
|
||||
|
||||
/* 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 interpreter and it's console haven't started.
|
||||
We track td_ta_new_p because the user may switch executables,
|
||||
and as a result we may decide to use a different version of
|
||||
libthread_db. */
|
||||
|
||||
if (!already_loaded)
|
||||
if (last_loaded != td_ta_new_p)
|
||||
{
|
||||
Dl_info info;
|
||||
const char *library = NULL;
|
||||
if (dladdr ((*td_ta_new_p), &info) != 0)
|
||||
library = info.dli_fname;
|
||||
last_loaded = td_ta_new_p;
|
||||
|
||||
/* Try dlinfo? */
|
||||
if (info_verbose || *libthread_db_search_path)
|
||||
{
|
||||
const char *library;
|
||||
|
||||
library = dladdr_to_soname (*td_ta_new_p);
|
||||
if (library == NULL)
|
||||
/* Paranoid - don't let a NULL path slip through. */
|
||||
library = LIBTHREAD_DB_SO;
|
||||
|
||||
if (info_verbose)
|
||||
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. */
|
||||
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 (¤t_target))
|
||||
return;
|
||||
|
||||
/* Initialize the structure that identifies the child process. */
|
||||
proc_handle.ptid = inferior_ptid;
|
||||
|
||||
/* Now attempt to open a connection to the thread library. */
|
||||
err = td_ta_new_p (&proc_handle, &thread_agent);
|
||||
switch (err)
|
||||
{
|
||||
case TD_NOLIBTHREAD:
|
||||
/* No thread library was detected. */
|
||||
break;
|
||||
|
||||
case TD_OK:
|
||||
printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
|
||||
|
||||
/* The thread library was detected. Activate the thread_db target. */
|
||||
push_target (&thread_db_ops);
|
||||
using_thread_db = 1;
|
||||
|
||||
enable_thread_event_reporting ();
|
||||
thread_db_find_new_threads_1 ();
|
||||
break;
|
||||
|
||||
default:
|
||||
warning (_("Cannot initialize thread debugging library: %s"),
|
||||
thread_db_err_str (err));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -783,7 +951,9 @@ thread_db_detach (struct target_ops *ops, char *args, int from_tty)
|
|||
|
||||
/* Detach thread_db target ops. */
|
||||
unpush_target (&thread_db_ops);
|
||||
using_thread_db = 0;
|
||||
if (thread_db_handle)
|
||||
dlclose (thread_db_handle);
|
||||
thread_db_handle = NULL;
|
||||
|
||||
target_beneath->to_detach (target_beneath, args, from_tty);
|
||||
}
|
||||
|
@ -896,7 +1066,9 @@ thread_db_wait (struct target_ops *ops,
|
|||
{
|
||||
remove_thread_event_breakpoints ();
|
||||
unpush_target (&thread_db_ops);
|
||||
using_thread_db = 0;
|
||||
if (thread_db_handle)
|
||||
dlclose (thread_db_handle);
|
||||
thread_db_handle = NULL;
|
||||
|
||||
return ptid;
|
||||
}
|
||||
|
@ -944,7 +1116,9 @@ thread_db_mourn_inferior (struct target_ops *ops)
|
|||
|
||||
/* Detach thread_db target ops. */
|
||||
unpush_target (ops);
|
||||
using_thread_db = 0;
|
||||
if (thread_db_handle)
|
||||
dlclose (thread_db_handle);
|
||||
thread_db_handle = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1186,13 +1360,28 @@ extern initialize_file_ftype _initialize_thread_db;
|
|||
void
|
||||
_initialize_thread_db (void)
|
||||
{
|
||||
/* Only initialize the module if we can load libthread_db. */
|
||||
if (thread_db_load ())
|
||||
{
|
||||
init_thread_db_ops ();
|
||||
add_target (&thread_db_ops);
|
||||
|
||||
/* Defer loading of libthread_db.so until inferior is running.
|
||||
This allows gdb to load correct libthread_db for a given
|
||||
executable -- there could be mutiple versions of glibc,
|
||||
compiled with LinuxThreads or NPTL, and until there is
|
||||
a running inferior, we can't tell which libthread_db is
|
||||
the correct one to load. */
|
||||
|
||||
libthread_db_search_path = xstrdup (LIBTHREAD_DB_SEARCH_PATH);
|
||||
|
||||
add_setshow_optional_filename_cmd ("libthread-db-search-path",
|
||||
class_support,
|
||||
&libthread_db_search_path, _("\
|
||||
Set search path for libthread_db."), _("\
|
||||
Show the current search path or libthread_db."), _("\
|
||||
This path is used to search for libthread_db to be loaded into \
|
||||
gdb itself."),
|
||||
NULL,
|
||||
NULL,
|
||||
&setlist, &showlist);
|
||||
/* Add ourselves to objfile event chain. */
|
||||
observer_attach_new_objfile (thread_db_new_objfile);
|
||||
}
|
||||
}
|
||||
|
|
13
gdb/solib.c
13
gdb/solib.c
|
@ -684,16 +684,25 @@ update_solib_list (int from_tty, struct target_ops *target)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return non-zero if SO is the libpthread shared library.
|
||||
|
||||
/* Return non-zero if NAME is the libpthread shared library.
|
||||
|
||||
Uses a fairly simplistic heuristic approach where we check
|
||||
the file name against "/libpthread". This can lead to false
|
||||
positives, but this should be good enough in practice. */
|
||||
|
||||
int
|
||||
libpthread_name_p (const char *name)
|
||||
{
|
||||
return (strstr (name, "/libpthread") != NULL);
|
||||
}
|
||||
|
||||
/* Return non-zero if SO is the libpthread shared library. */
|
||||
|
||||
static int
|
||||
libpthread_solib_p (struct so_list *so)
|
||||
{
|
||||
return (strstr (so->so_name, "/libpthread") != NULL);
|
||||
return libpthread_name_p (so->so_name);
|
||||
}
|
||||
|
||||
/* GLOBAL FUNCTION
|
||||
|
|
|
@ -65,4 +65,8 @@ extern void no_shared_libraries (char *ignored, int from_tty);
|
|||
extern void set_solib_ops (struct gdbarch *gdbarch,
|
||||
struct target_so_ops *new_ops);
|
||||
|
||||
/* Return non-zero if NAME is the libpthread shared library. */
|
||||
|
||||
extern int libpthread_name_p (const char *name);
|
||||
|
||||
#endif /* SOLIB_H */
|
||||
|
|
Loading…
Reference in New Issue