Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.620 diff -u -p -u -r1.620 gdb.texinfo --- doc/gdb.texinfo 1 Sep 2009 18:48:58 -0000 1.620 +++ doc/gdb.texinfo 2 Sep 2009 16:40:48 -0000 @@ -14767,6 +14767,13 @@ Disable or enable general debugging mess Disable or enable specific debugging messages associated with the remote protocol (@pxref{Remote Protocol}). +@item monitor set libthread-db-search-path [PATH] +@cindex gdbserver, search path for @code{libthread_db} +When this command is issued, @var{path} is a colon-separated list of +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 an empty list. + @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/acinclude.m4 =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/acinclude.m4,v retrieving revision 1.7 diff -u -p -u -r1.7 acinclude.m4 --- gdbserver/acinclude.m4 5 Jun 2008 22:36:57 -0000 1.7 +++ gdbserver/acinclude.m4 2 Sep 2009 16:40:48 -0000 @@ -22,7 +22,7 @@ AC_DEFUN([SRV_CHECK_THREAD_DB], void ps_get_thread_area() {} void ps_getpid() {}], [td_ta_new();], - [srv_cv_thread_db="-lthread_db"], + [srv_cv_thread_db="-ldl"], [srv_cv_thread_db=no if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then Index: gdbserver/server.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/server.c,v retrieving revision 1.102 diff -u -p -u -r1.102 server.c --- gdbserver/server.c 30 Jun 2009 16:35:25 -0000 1.102 +++ gdbserver/server.c 2 Sep 2009 16:40:48 -0000 @@ -32,6 +32,8 @@ #include #endif +#include + ptid_t cont_thread; ptid_t general_thread; ptid_t step_thread; @@ -51,6 +53,10 @@ static char **program_argv, **wrapper_ar was originally used to debug LinuxThreads support. */ int debug_threads; +/* If not NULL, a colon-separated list of paths to use while looking for + libthread_db. */ +char *libthread_db_search_path; + /* Enable debugging of h/w breakpoint/watchpoint support. */ int debug_hw_points; @@ -1245,6 +1251,23 @@ handle_query (char *own_buf, int packet_ monitor_show_help (); else if (strcmp (mon, "exit") == 0) exit_requested = 1; + else if (strncmp (mon, "set libthread-db-search-path", 28) == 0) + { + const char *cp = mon + 28; + + if (libthread_db_search_path != NULL) + free (libthread_db_search_path); + + /* Skip leading space (if any). */ + while (isspace (*cp)) + ++cp; + + libthread_db_search_path = xstrdup (cp); + + monitor_output ("libthread-db-search-path set to `"); + monitor_output (libthread_db_search_path); + monitor_output ("'\n"); + } else { monitor_output ("Unknown monitor command.\n\n"); Index: gdbserver/thread-db.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/thread-db.c,v retrieving revision 1.23 diff -u -p -u -r1.23 thread-db.c --- gdbserver/thread-db.c 3 Apr 2009 20:15:51 -0000 1.23 +++ gdbserver/thread-db.c 2 Sep 2009 16:40:48 -0000 @@ -27,17 +27,42 @@ extern int debug_threads; static int thread_db_use_events; -#ifdef HAVE_THREAD_DB_H -#include -#endif - #include "gdb_proc_service.h" +#include "../gdb_thread_db.h" +#include #include +#include + +extern char *libthread_db_search_path; static int find_one_thread (ptid_t); static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data); +static td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, + td_thragent_t **ta); +static td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta, + td_event_msg_t *msg); +static td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta, + td_thr_events_t *event); +static td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta, + td_event_e event, td_notify_t *ptr); +static td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, + lwpid_t lwpid, td_thrhandle_t *th); +static td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th, + td_thrinfo_t *infop); +static td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, + int event); +static td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta, + td_thr_iter_f *callback, void *cbdata_p, + td_thr_state_e state, int ti_pri, + sigset_t *ti_sigmask_p, + unsigned int ti_user_flags); +static td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th, + void *map_address, + size_t offset, void **address); +static const char ** (*td_symbol_list_p) (void); + static const char * thread_db_err_str (td_err_e err) { @@ -139,7 +164,7 @@ thread_db_create_event (CORE_ADDR where) In the LinuxThreads implementation, this is safe, because all events come from the manager thread (except for its own creation, of course). */ - err = td_ta_event_getmsg (proc->thread_agent, &msg); + err = td_ta_event_getmsg_p (proc->thread_agent, &msg); if (err != TD_OK) fprintf (stderr, "thread getmsg err: %s\n", thread_db_err_str (err)); @@ -187,7 +212,7 @@ thread_db_enable_reporting () td_event_addset (&events, TD_DEATH); #endif - err = td_ta_set_event (proc->thread_agent, &events); + err = td_ta_set_event_p (proc->thread_agent, &events); if (err != TD_OK) { warning ("Unable to set global thread event mask: %s", @@ -196,7 +221,7 @@ thread_db_enable_reporting () } /* Get address for thread creation breakpoint. */ - err = td_ta_event_addr (proc->thread_agent, TD_CREATE, ¬ify); + err = td_ta_event_addr_p (proc->thread_agent, TD_CREATE, ¬ify); if (err != TD_OK) { warning ("Unable to get location for thread creation breakpoint: %s", @@ -211,7 +236,7 @@ thread_db_enable_reporting () with actual thread deaths (via wait). */ /* Get address for thread death breakpoint. */ - err = td_ta_event_addr (proc->thread_agent, TD_DEATH, ¬ify); + err = td_ta_event_addr_p (proc->thread_agent, TD_DEATH, ¬ify); if (err != TD_OK) { warning ("Unable to get location for thread death breakpoint: %s", @@ -233,7 +258,7 @@ find_one_thread (ptid_t ptid) td_err_e err; struct thread_info *inferior; struct lwp_info *lwp; - struct process_info_private *proc; + struct process_info_private *proc = current_process()->private; int lwpid = ptid_get_lwp (ptid); inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid); @@ -242,13 +267,12 @@ find_one_thread (ptid_t ptid) return 1; /* Get information about this thread. */ - proc = get_thread_process (inferior)->private; - err = td_ta_map_lwp2thr (proc->thread_agent, lwpid, &th); + err = td_ta_map_lwp2thr_p (proc->thread_agent, lwpid, &th); if (err != TD_OK) error ("Cannot get thread handle for LWP %d: %s", lwpid, thread_db_err_str (err)); - err = td_thr_get_info (&th, &ti); + err = td_thr_get_info_p (&th, &ti); if (err != TD_OK) error ("Cannot get thread info for LWP %d: %s", lwpid, thread_db_err_str (err)); @@ -266,7 +290,7 @@ find_one_thread (ptid_t ptid) if (thread_db_use_events) { - err = td_thr_event_enable (&th, 1); + err = td_thr_event_enable_p (&th, 1); if (err != TD_OK) error ("Cannot enable thread event reporting for %d: %s", ti.ti_lid, thread_db_err_str (err)); @@ -310,7 +334,7 @@ maybe_attach_thread (const td_thrhandle_ if (thread_db_use_events) { - err = td_thr_event_enable (th_p, 1); + err = td_thr_event_enable_p (th_p, 1); if (err != TD_OK) error ("Cannot enable thread event reporting for %d: %s", ti_p->ti_lid, thread_db_err_str (err)); @@ -323,7 +347,7 @@ find_new_threads_callback (const td_thrh td_thrinfo_t ti; td_err_e err; - err = td_thr_get_info (th_p, &ti); + err = td_thr_get_info_p (th_p, &ti); if (err != TD_OK) error ("Cannot get thread info: %s", thread_db_err_str (err)); @@ -350,10 +374,10 @@ thread_db_find_new_threads (void) return; /* Iterate over all user-space threads to discover new threads. */ - err = td_ta_thr_iter (proc->thread_agent, - find_new_threads_callback, NULL, - TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, - TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); + err = td_ta_thr_iter_p (proc->thread_agent, + find_new_threads_callback, NULL, + TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, + TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); if (err != TD_OK) error ("Cannot find new threads: %s", thread_db_err_str (err)); } @@ -366,10 +390,10 @@ thread_db_find_new_threads (void) static void thread_db_look_up_symbols (void) { - const char **sym_list = td_symbol_list (); + const char **sym_list; CORE_ADDR unused; - for (sym_list = td_symbol_list (); *sym_list; sym_list++) + for (sym_list = td_symbol_list_p (); *sym_list; sym_list++) look_up_one_symbol (*sym_list, &unused); } @@ -383,10 +407,6 @@ thread_db_get_tls_address (struct thread struct lwp_info *lwp; struct thread_info *saved_inferior; - /* If the thread layer is not (yet) initialized, fail. */ - if (!get_thread_process (thread)->all_symbols_looked_up) - return TD_ERR; - lwp = get_thread_lwp (thread); if (!lwp->thread_known) find_one_thread (lwp->head.id); @@ -398,8 +418,8 @@ thread_db_get_tls_address (struct thread /* Note the cast through uintptr_t: this interface only works if a target address fits in a psaddr_t, which is a host pointer. So a 32-bit debugger can not access 64-bit TLS through this. */ - err = td_thr_tls_get_addr (&lwp->th, (psaddr_t) (uintptr_t) load_module, - offset, &addr); + err = td_thr_tls_get_addr_p (&lwp->th, (psaddr_t) (uintptr_t) load_module, + offset, &addr); current_inferior = saved_inferior; if (err == TD_OK) { @@ -413,12 +433,172 @@ thread_db_get_tls_address (struct thread #endif } +static int +try_thread_db_load_1 (void *handle) +{ + td_err_e err; + struct process_info *proc = current_process (); + struct process_info_private *priv = proc->private; + + /* Initialize pointers to the dynamic library functions we will use. + Essential functions first. */ + +#define CHK(a) \ + if ((a) == NULL) { \ + if (debug_threads) { \ + fprintf (stderr, "dlsym: %s\n", dlerror ()); \ + } \ + return 0; \ + } + + CHK (td_ta_new_p = dlsym (handle, "td_ta_new")); + + /* Attempt to open a connection to the thread library. */ + err = td_ta_new_p (&priv->proc_handle, &priv->thread_agent); + if (err != TD_OK) + { + td_ta_new_p = NULL; + if (debug_threads) + fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err)); + return 0; + } + + CHK (td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg")); + CHK (td_ta_set_event_p = dlsym (handle, "td_ta_set_event")); + CHK (td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr")); + CHK (td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr")); + CHK (td_thr_get_info_p = dlsym (handle, "td_thr_get_info")); + CHK (td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable")); + CHK (td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter")); + CHK (td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr")); + CHK (td_symbol_list_p = dlsym (handle, "td_symbol_list")); + +#undef CHK + + return 1; +} + +/* Lookup a library in which given symbol resides. + Note: this is looking in the GDBSERVER 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; +} + +static int +try_thread_db_load (const char *library) +{ + void *handle; + + if (debug_threads) + fprintf (stderr, "Trying host libthread_db library: %s.\n", + library); + handle = dlopen (library, RTLD_NOW); + if (handle == NULL) + { + if (debug_threads) + fprintf (stderr, "dlopen failed: %s.\n", dlerror ()); + return 0; + } + + if (debug_threads && 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) + fprintf (stderr, "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; +} + +static int +thread_db_load_search () +{ + char path[PATH_MAX]; + const char *search_path; + int rc = 0; + + + if (libthread_db_search_path == NULL) + libthread_db_search_path = xstrdup (LIBTHREAD_DB_SEARCH_PATH); + + search_path = libthread_db_search_path; + 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); + free (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 (debug_threads) + fprintf (stderr, "thread_db_load_search trying %s\n", path); + if (try_thread_db_load (path)) + { + 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); + return rc; +} + int thread_db_init (int use_events) { - int err; struct process_info *proc = current_process (); - struct process_info_private *priv = proc->private; /* FIXME drow/2004-10-16: This is the "overall process ID", which GNU/Linux calls tgid, "thread group ID". When we support @@ -433,26 +613,14 @@ thread_db_init (int use_events) thread_db_use_events = use_events; - err = td_ta_new (&priv->proc_handle, &priv->thread_agent); - switch (err) + if (thread_db_load_search ()) { - case TD_NOLIBTHREAD: - /* No thread library was detected. */ - return 0; - - case TD_OK: - /* The thread library was detected. */ - if (use_events && thread_db_enable_reporting () == 0) return 0; thread_db_find_new_threads (); thread_db_look_up_symbols (); proc->all_symbols_looked_up = 1; return 1; - - default: - warning ("error initializing thread_db library: %s", - thread_db_err_str (err)); } return 0; Index: gdbserver/configure.ac =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/configure.ac,v retrieving revision 1.26 diff -u -p -u -r1.26 configure.ac --- gdbserver/configure.ac 6 Jul 2009 18:31:19 -0000 1.26 +++ gdbserver/configure.ac 2 Sep 2009 16:40:48 -0000 @@ -19,16 +19,17 @@ dnl along with this program. If not, se dnl Process this file with autoconf to produce a configure script. -AC_PREREQ(2.59)dnl +AC_PREREQ(2.64)dnl -AC_INIT(server.c) +AC_INIT +AC_CONFIG_SRCDIR([server.c]) AC_CONFIG_HEADER(config.h:config.in) AC_CONFIG_LIBOBJ_DIR(../gnulib) AC_PROG_CC -AC_GNU_SOURCE +AC_USE_SYSTEM_EXTENSIONS -AC_CANONICAL_SYSTEM +AC_CANONICAL_TARGET AC_PROG_INSTALL @@ -47,18 +48,15 @@ AC_REPLACE_FUNCS(memmem) have_errno=no AC_MSG_CHECKING(for errno) -AC_TRY_LINK([ +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #if HAVE_ERRNO_H #include -#endif], [static int x; x = errno;], - [AC_MSG_RESULT(yes - in errno.h); AC_DEFINE(HAVE_ERRNO, 1, [Define if errno is available]) have_errno=yes]) +#endif]], [[static int x; x = errno;]])],[AC_MSG_RESULT(yes - in errno.h); AC_DEFINE(HAVE_ERRNO, 1, [Define if errno is available]) have_errno=yes],[]) if test $have_errno = no; then -AC_TRY_LINK([ +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #if HAVE_ERRNO_H #include -#endif], [extern int errno; static int x; x = errno;], - [AC_MSG_RESULT(yes - must define); AC_DEFINE(HAVE_ERRNO, 1, [Define if errno is available]) AC_DEFINE(MUST_DEFINE_ERRNO, 1, [Checking if errno must be defined])], - [AC_MSG_RESULT(no)]) +#endif]], [[extern int errno; static int x; x = errno;]])],[AC_MSG_RESULT(yes - must define); AC_DEFINE(HAVE_ERRNO, 1, [Define if errno is available]) AC_DEFINE(MUST_DEFINE_ERRNO, 1, [Checking if errno must be defined])],[AC_MSG_RESULT(no)]) fi AC_CHECK_DECLS([strerror, perror, memmem]) @@ -103,10 +101,7 @@ if test "${srv_linux_regsets}" = "yes"; AC_MSG_CHECKING(for PTRACE_GETREGS) AC_CACHE_VAL(gdbsrv_cv_have_ptrace_getregs, - [AC_TRY_COMPILE([#include ], - [PTRACE_GETREGS;], - [gdbsrv_cv_have_ptrace_getregs=yes], - [gdbsrv_cv_have_ptrace_getregs=no])]) + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[PTRACE_GETREGS;]])],[gdbsrv_cv_have_ptrace_getregs=yes],[gdbsrv_cv_have_ptrace_getregs=no])]) AC_MSG_RESULT($gdbsrv_cv_have_ptrace_getregs) if test "${gdbsrv_cv_have_ptrace_getregs}" = "yes"; then AC_DEFINE(HAVE_PTRACE_GETREGS, 1, @@ -116,10 +111,7 @@ if test "${srv_linux_regsets}" = "yes"; AC_MSG_CHECKING(for PTRACE_GETFPXREGS) AC_CACHE_VAL(gdbsrv_cv_have_ptrace_getfpxregs, - [AC_TRY_COMPILE([#include ], - [PTRACE_GETFPXREGS;], - [gdbsrv_cv_have_ptrace_getfpxregs=yes], - [gdbsrv_cv_have_ptrace_getfpxregs=no])]) + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[PTRACE_GETFPXREGS;]])],[gdbsrv_cv_have_ptrace_getfpxregs=yes],[gdbsrv_cv_have_ptrace_getfpxregs=no])]) AC_MSG_RESULT($gdbsrv_cv_have_ptrace_getfpxregs) if test "${gdbsrv_cv_have_ptrace_getfpxregs}" = "yes"; then AC_DEFINE(HAVE_PTRACE_GETFPXREGS, 1, @@ -142,8 +134,8 @@ USE_THREAD_DB= if test "$srv_linux_thread_db" = "yes"; then SRV_CHECK_THREAD_DB if test "$srv_cv_thread_db" = no; then - AC_WARN([Could not find libthread_db.]) - AC_WARN([Disabling thread support in gdbserver.]) + AC_MSG_WARN(Could not find libthread_db.) + AC_MSG_WARN(Disabling thread support in gdbserver.) srv_linux_thread_db=no else srv_libs="$srv_cv_thread_db" @@ -151,7 +143,7 @@ if test "$srv_linux_thread_db" = "yes"; fi old_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -rdynamic" - AC_TRY_LINK([], [], [RDYNAMIC=-rdynamic], [RDYNAMIC=]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[RDYNAMIC=-rdynamic],[RDYNAMIC=]) AC_SUBST(RDYNAMIC) LDFLAGS="$old_LDFLAGS" fi @@ -160,9 +152,7 @@ if test "$srv_linux_thread_db" = "yes"; srv_thread_depfiles="thread-db.o proc-service.o" USE_THREAD_DB="-DUSE_THREAD_DB" AC_CACHE_CHECK([for TD_VERSION], gdbsrv_cv_have_td_version, - [AC_TRY_COMPILE([#include ], [TD_VERSION;], - [gdbsrv_cv_have_td_version=yes], - [gdbsrv_cv_have_td_version=no])]) + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[TD_VERSION;]])],[gdbsrv_cv_have_td_version=yes],[gdbsrv_cv_have_td_version=no])]) if test $gdbsrv_cv_have_td_version = yes; then AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.]) fi @@ -192,9 +182,10 @@ AC_SUBST(USE_THREAD_DB) AC_SUBST(srv_xmlbuiltin) AC_SUBST(srv_xmlfiles) -AC_OUTPUT(Makefile, -[case x$CONFIG_HEADERS in +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_COMMANDS([default],[case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac -]) +],[]) +AC_OUTPUT Index: gdbserver/configure =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/configure,v retrieving revision 1.40 diff -u -p -u -r1.40 configure --- gdbserver/configure 22 Aug 2009 16:56:42 -0000 1.40 +++ gdbserver/configure 2 Sep 2009 16:40:49 -0000 @@ -2182,6 +2182,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + ac_config_headers="$ac_config_headers config.h:config.in" @@ -3412,7 +3413,6 @@ $as_echo "$ac_cv_safe_to_define___extens - ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do for ac_t in install-sh install.sh shtool; do @@ -3547,7 +3547,6 @@ test -n "$target_alias" && NONENONEs,x,x, && program_prefix=${target_alias}- - # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: @@ -4237,7 +4236,7 @@ td_ta_new(); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - srv_cv_thread_db="-lthread_db" + srv_cv_thread_db="-ldl" else srv_cv_thread_db=no