* [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
@ 2009-09-02 16:34 Paul Pluzhnikov
2009-09-02 16:43 ` Paul Pluzhnikov
2009-09-02 16:47 ` Pedro Alves
0 siblings, 2 replies; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-09-02 16:34 UTC (permalink / raw)
To: gdb-patches; +Cc: ppluzhnikov, dje
Greetings,
Attached is a patch which allows gdbserver to do the same dynamic lookup
of libthread_db.so.1 as GDB already does.
Previous thread on this subject:
http://sourceware.org/ml/gdb-patches/2009-05/msg00329.html
Thanks,
--
Paul Pluzhnikov
doc/
2009-09-02 Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.texinfo (Server): Document libthread-db-search-path.
gdbserver/
2009-09-02 Paul Pluzhnikov <ppluzhnikov@google.com>
* acinclude.m4: Link with libdl.
* server.c (libthread_db_search_path): New variable.
(handle_query): Set it.
* thread-db.c (td_ta_new_p, td_ta_event_getmsg_p)
(td_ta_set_event_p, td_ta_event_addr_p, td_ta_map_lwp2thr_p)
(td_thr_get_info_p, td_thr_event_enable_p, td_ta_thr_iter_p)
(td_thr_tls_get_addr_p, td_symbol_list_p)
(td_symbol_list_p): New variables.
(thread_db_create_event, thread_db_enable_reporting)
(find_one_thread, maybe_attach_thread, thread_db_find_new_threads)
(thread_db_get_tls_address): Ajust.
(try_thread_db_load_1, dladdr_to_soname): New functions.
(try_thread_db_load, thread_db_load_search): New functions.
(thread_db_init): Search for libthread_db.
* configure.ac: Regenerate.
* configure: Likewise.
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:22:28 -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:22:28 -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:22:28 -0000
@@ -32,6 +32,8 @@
#include <malloc.h>
#endif
+#include <ctype.h>
+
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:22:28 -0000
@@ -27,17 +27,42 @@ extern int debug_threads;
static int thread_db_use_events;
-#ifdef HAVE_THREAD_DB_H
-#include <thread_db.h>
-#endif
-
#include "gdb_proc_service.h"
+#include "../gdb_thread_db.h"
+#include <dlfcn.h>
#include <stdint.h>
+#include <limits.h>
+
+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:22:28 -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 <errno.h>
-#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 <errno.h>
-#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 <sys/ptrace.h>],
- [PTRACE_GETREGS;],
- [gdbsrv_cv_have_ptrace_getregs=yes],
- [gdbsrv_cv_have_ptrace_getregs=no])])
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/ptrace.h>]], [[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 <sys/ptrace.h>],
- [PTRACE_GETFPXREGS;],
- [gdbsrv_cv_have_ptrace_getfpxregs=yes],
- [gdbsrv_cv_have_ptrace_getfpxregs=no])])
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/ptrace.h>]], [[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 <thread_db.h>], [TD_VERSION;],
- [gdbsrv_cv_have_td_version=yes],
- [gdbsrv_cv_have_td_version=no])])
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <thread_db.h>]], [[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:22:28 -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
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-09-02 16:34 [patch] Allow gdbserver to dynamically lookup libthread_db.so.1 Paul Pluzhnikov
@ 2009-09-02 16:43 ` Paul Pluzhnikov
2009-09-02 16:47 ` Pedro Alves
1 sibling, 0 replies; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-09-02 16:43 UTC (permalink / raw)
To: gdb-patches; +Cc: ppluzhnikov, dje
[-- Attachment #1: Type: text/plain, Size: 1300 bytes --]
On Wed, Sep 2, 2009 at 9:33 AM, Paul Pluzhnikov<ppluzhnikov@google.com> wrote:
> + CHK(td_ta_new_p = dlsym (handle, "td_ta_new"));
Just noticed 'space before paren' violation :(
Sorry about that. Fix attached.
--
Paul Pluzhnikov
doc/
2009-09-02 Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.texinfo (Server): Document libthread-db-search-path.
gdbserver/
2009-09-02 Paul Pluzhnikov <ppluzhnikov@google.com>
* acinclude.m4: Link with libdl.
* server.c (libthread_db_search_path): New variable.
(handle_query): Set it.
* thread-db.c (td_ta_new_p, td_ta_event_getmsg_p)
(td_ta_set_event_p, td_ta_event_addr_p, td_ta_map_lwp2thr_p)
(td_thr_get_info_p, td_thr_event_enable_p, td_ta_thr_iter_p)
(td_thr_tls_get_addr_p, td_symbol_list_p)
(td_symbol_list_p): New variables.
(thread_db_create_event, thread_db_enable_reporting)
(find_one_thread, maybe_attach_thread, thread_db_find_new_threads)
(thread_db_get_tls_address): Ajust.
(try_thread_db_load_1, dladdr_to_soname): New functions.
(try_thread_db_load, thread_db_load_search): New functions.
(thread_db_init): Search for libthread_db.
* configure.ac: Regenerate.
* configure: Likewise.
[-- Attachment #2: gdb-gdbserver-threaddb-search-20090902-2.txt --]
[-- Type: text/plain, Size: 21583 bytes --]
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 <malloc.h>
#endif
+#include <ctype.h>
+
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 <thread_db.h>
-#endif
-
#include "gdb_proc_service.h"
+#include "../gdb_thread_db.h"
+#include <dlfcn.h>
#include <stdint.h>
+#include <limits.h>
+
+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 <errno.h>
-#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 <errno.h>
-#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 <sys/ptrace.h>],
- [PTRACE_GETREGS;],
- [gdbsrv_cv_have_ptrace_getregs=yes],
- [gdbsrv_cv_have_ptrace_getregs=no])])
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/ptrace.h>]], [[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 <sys/ptrace.h>],
- [PTRACE_GETFPXREGS;],
- [gdbsrv_cv_have_ptrace_getfpxregs=yes],
- [gdbsrv_cv_have_ptrace_getfpxregs=no])])
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/ptrace.h>]], [[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 <thread_db.h>], [TD_VERSION;],
- [gdbsrv_cv_have_td_version=yes],
- [gdbsrv_cv_have_td_version=no])])
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <thread_db.h>]], [[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
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-09-02 16:34 [patch] Allow gdbserver to dynamically lookup libthread_db.so.1 Paul Pluzhnikov
2009-09-02 16:43 ` Paul Pluzhnikov
@ 2009-09-02 16:47 ` Pedro Alves
2009-09-02 17:16 ` Paul Pluzhnikov
1 sibling, 1 reply; 25+ messages in thread
From: Pedro Alves @ 2009-09-02 16:47 UTC (permalink / raw)
To: gdb-patches; +Cc: Paul Pluzhnikov, dje
Since you're touching this, how about loading a thread_db per-process
like gdb/linux-thread-db.c already does?
Did you intend to remove this?
> - /* If the thread layer is not (yet) initialized, fail. */
> - if (!get_thread_process (thread)->all_symbols_looked_up)
> - return TD_ERR;
> -
> -AC_PREREQ(2.59)dnl
> +AC_PREREQ(2.64)dnl
This should be a separate change.
--
Pedro Alves
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-09-02 16:47 ` Pedro Alves
@ 2009-09-02 17:16 ` Paul Pluzhnikov
2009-09-02 17:19 ` Doug Evans
2009-10-02 23:51 ` Paul Pluzhnikov
0 siblings, 2 replies; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-09-02 17:16 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, dje
On Wed, Sep 2, 2009 at 9:47 AM, Pedro Alves<pedro@codesourcery.com> wrote:
> Since you're touching this, how about loading a thread_db per-process
> like gdb/linux-thread-db.c already does?
Oh, I've had this patch locally for so long, I didn't realize gdbserver
is now multi-process as well. Will fix.
> Did you intend to remove this?
>
>> - /* If the thread layer is not (yet) initialized, fail. */
>> - if (!get_thread_process (thread)->all_symbols_looked_up)
>> - return TD_ERR;
No, I must have accidentally killed it.
>> -AC_PREREQ(2.59)dnl
>> +AC_PREREQ(2.64)dnl
>
> This should be a separate change.
I still can't get a good mental model of autotools :-(
Given gdbserver/acinclude.m4 change, I should include gdbserver/configure
change here, but not gdbserver/configure.ac, right?
Thanks,
--
Paul Pluzhnikov
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-09-02 17:16 ` Paul Pluzhnikov
@ 2009-09-02 17:19 ` Doug Evans
2009-10-02 23:51 ` Paul Pluzhnikov
1 sibling, 0 replies; 25+ messages in thread
From: Doug Evans @ 2009-09-02 17:19 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: Pedro Alves, gdb-patches
On Wed, Sep 2, 2009 at 10:15 AM, Paul Pluzhnikov<ppluzhnikov@google.com> wrote:
> Given gdbserver/acinclude.m4 change, I should include gdbserver/configure
> change here, but not gdbserver/configure.ac, right?
Data point: It is not necessary to include changes to generated files
in patches.
Some even prefer to not include them, less noise in the patch.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-09-02 17:16 ` Paul Pluzhnikov
2009-09-02 17:19 ` Doug Evans
@ 2009-10-02 23:51 ` Paul Pluzhnikov
2009-10-04 20:32 ` Pedro Alves
2009-10-04 20:34 ` Pedro Alves
1 sibling, 2 replies; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-02 23:51 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, dje
[-- Attachment #1: Type: text/plain, Size: 1450 bytes --]
On Wed, Sep 2, 2009 at 10:15 AM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> On Wed, Sep 2, 2009 at 9:47 AM, Pedro Alves<pedro@codesourcery.com> wrote:
>
>> Since you're touching this, how about loading a thread_db per-process
>> like gdb/linux-thread-db.c already does?
>
> Oh, I've had this patch locally for so long, I didn't realize gdbserver
> is now multi-process as well. Will fix.
Here is the fix.
Since we can have several inferiors and several different libthread_db's,
it no longer makes sense to check for td_thr_tls_get_addr at configure time.
Also, previous patch was failing try_thread_db_load_1 on non-essential
functions.
Thanks,
--
Paul Pluzhnikov
doc/
2009-10-02 Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.texinfo (Server): Document libthread-db-search-path.
gdbserver/
2009-10-02 Paul Pluzhnikov <ppluzhnikov@google.com>
* acinclude.m4: Link with libdl.
* server.c (libthread_db_search_path): New variable.
(handle_query): Set it.
* linux-low.h (struct process_info_private): New members.
* linux-low.c (linux_remove_process): Adjust.
* thread-db.c (thread_db_create_event, thread_db_enable_reporting)
(find_one_thread, maybe_attach_thread, find_new_threads_callback)
(thread_db_find_new_threads, (thread_db_get_tls_address): Adjust.
(try_thread_db_load_1, dladdr_to_soname): New functions.
(try_thread_db_load, thread_db_load_search): New functions.
(thread_db_init): Search for libthread_db.
[-- Attachment #2: gdb-gdbserver-threaddb-search-20091002.txt --]
[-- Type: text/plain, Size: 19967 bytes --]
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.629
diff -u -p -u -r1.629 gdb.texinfo
--- doc/gdb.texinfo 26 Sep 2009 16:47:13 -0000 1.629
+++ doc/gdb.texinfo 2 Oct 2009 23:49:31 -0000
@@ -14900,6 +14900,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 Oct 2009 23:49:31 -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
@@ -42,28 +42,9 @@ AC_DEFUN([SRV_CHECK_THREAD_DB],
void ps_get_thread_area() {}
void ps_getpid() {}],
[td_ta_new();],
- [srv_cv_thread_db="$thread_db"],
+ [srv_cv_thread_db="-ldl"],
[srv_cv_thread_db=no])
])
LIBS="$old_LIBS"
])])
-AC_DEFUN([SRV_CHECK_TLS_GET_ADDR],
-[AC_CACHE_CHECK([for thread_db_tls_get_addr],[srv_cv_tls_get_addr],
- [old_LIBS="$LIBS"
- LIBS="$LIBS $srv_cv_thread_db"
- AC_TRY_LINK(
- [void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}],
- [td_thr_tls_get_addr();],
- [srv_cv_tls_get_addr=yes],
- [srv_cv_tls_get_addr=no])
- LIBS="$old_LIBS"
-])])
Index: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.112
diff -u -p -u -r1.112 linux-low.c
--- gdbserver/linux-low.c 31 Jul 2009 15:25:22 -0000 1.112
+++ gdbserver/linux-low.c 2 Oct 2009 23:49:31 -0000
@@ -42,6 +42,7 @@
#include <dirent.h>
#include <sys/stat.h>
#include <sys/vfs.h>
+#include <dlfcn.h>
#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
@@ -261,8 +262,12 @@ linux_add_process (int pid, int attached
static void
linux_remove_process (struct process_info *process)
{
- free (process->private->arch_private);
- free (process->private);
+ struct process_info_private *priv = process->private;
+
+ if (priv->handle != NULL)
+ dlclose (priv->handle);
+ free (priv->arch_private);
+ free (priv);
remove_process (process);
}
Index: gdbserver/linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.32
diff -u -p -u -r1.32 linux-low.h
--- gdbserver/linux-low.h 30 Jun 2009 16:35:25 -0000 1.32
+++ gdbserver/linux-low.h 2 Oct 2009 23:49:31 -0000
@@ -57,6 +57,32 @@ struct process_info_private
/* Connection to the libthread_db library. */
td_thragent_t *thread_agent;
+ /* Handle of the libthread_db from dlopen. */
+ void *handle;
+
+ /* Addresses of libthread_db functions. */
+ td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
+ td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
+ td_event_msg_t *msg);
+ td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
+ td_thr_events_t *event);
+ td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
+ td_event_e event, td_notify_t *ptr);
+ td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid,
+ td_thrhandle_t *th);
+ td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
+ td_thrinfo_t *infop);
+ td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event);
+ 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);
+ td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
+ void *map_address,
+ size_t offset, void **address);
+ const char ** (*td_symbol_list_p) (void);
+
/* Arch-specific additions. */
struct arch_process_info *arch_private;
};
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 Oct 2009 23:49:31 -0000
@@ -32,6 +32,8 @@
#include <malloc.h>
#endif
+#include <ctype.h>
+
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 Oct 2009 23:49:31 -0000
@@ -27,13 +27,14 @@ extern int debug_threads;
static int thread_db_use_events;
-#ifdef HAVE_THREAD_DB_H
-#include <thread_db.h>
-#endif
-
#include "gdb_proc_service.h"
+#include "../gdb_thread_db.h"
+#include <dlfcn.h>
#include <stdint.h>
+#include <limits.h>
+
+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);
@@ -132,6 +133,10 @@ thread_db_create_event (CORE_ADDR where)
struct lwp_info *lwp;
struct process_info_private *proc = current_process()->private;
+ if (proc->td_ta_event_getmsg_p == NULL)
+ /* We shouldn't have ever be here in the first place. */
+ return TD_ERR;
+
if (debug_threads)
fprintf (stderr, "Thread creation event.\n");
@@ -139,7 +144,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 = proc->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));
@@ -177,17 +182,17 @@ thread_db_enable_reporting ()
td_err_e err;
struct process_info_private *proc = current_process()->private;
+ if (proc->td_ta_set_event_p == NULL
+ || proc->td_ta_event_addr_p == NULL
+ || proc->td_ta_event_getmsg_p == NULL)
+ /* This libthread_db is missing required support. */
+ return TD_ERR;
+
/* Set the process wide mask saying which events we're interested in. */
td_event_emptyset (&events);
td_event_addset (&events, TD_CREATE);
-#if 0
- /* This is reported to be broken in glibc 2.1.3. A different approach
- will be necessary to support that. */
- td_event_addset (&events, TD_DEATH);
-#endif
-
- err = td_ta_set_event (proc->thread_agent, &events);
+ err = proc->td_ta_set_event_p (proc->thread_agent, &events);
if (err != TD_OK)
{
warning ("Unable to set global thread event mask: %s",
@@ -196,7 +201,7 @@ thread_db_enable_reporting ()
}
/* Get address for thread creation breakpoint. */
- err = td_ta_event_addr (proc->thread_agent, TD_CREATE, ¬ify);
+ err = proc->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",
@@ -206,22 +211,6 @@ thread_db_enable_reporting ()
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
thread_db_create_event);
-#if 0
- /* Don't concern ourselves with reported thread deaths, only
- with actual thread deaths (via wait). */
-
- /* Get address for thread death breakpoint. */
- err = td_ta_event_addr (proc->thread_agent, TD_DEATH, ¬ify);
- if (err != TD_OK)
- {
- warning ("Unable to get location for thread death breakpoint: %s",
- thread_db_err_str (err));
- return;
- }
- set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
- thread_db_death_event);
-#endif
-
return 1;
}
@@ -233,7 +222,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 +231,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 = proc->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 = proc->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 +254,7 @@ find_one_thread (ptid_t ptid)
if (thread_db_use_events)
{
- err = td_thr_event_enable (&th, 1);
+ err = proc->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 +298,8 @@ maybe_attach_thread (const td_thrhandle_
if (thread_db_use_events)
{
- err = td_thr_event_enable (th_p, 1);
+ struct process_info_private *proc = current_process()->private;
+ err = proc->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));
@@ -322,8 +311,9 @@ find_new_threads_callback (const td_thrh
{
td_thrinfo_t ti;
td_err_e err;
+ struct process_info_private *proc = current_process()->private;
- err = td_thr_get_info (th_p, &ti);
+ err = proc->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 +340,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 = proc->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 +356,11 @@ thread_db_find_new_threads (void)
static void
thread_db_look_up_symbols (void)
{
- const char **sym_list = td_symbol_list ();
+ struct process_info_private *proc = current_process()->private;
+ const char **sym_list;
CORE_ADDR unused;
- for (sym_list = td_symbol_list (); *sym_list; sym_list++)
+ for (sym_list = proc->td_symbol_list_p (); *sym_list; sym_list++)
look_up_one_symbol (*sym_list, &unused);
}
@@ -377,14 +368,21 @@ int
thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
CORE_ADDR load_module, CORE_ADDR *address)
{
-#if HAVE_TD_THR_TLS_GET_ADDR
psaddr_t addr;
td_err_e err;
struct lwp_info *lwp;
struct thread_info *saved_inferior;
+ struct process_info *proc;
+ struct process_info_private *priv;
+
+ proc = get_thread_process (thread);
+ priv = proc->private;
/* If the thread layer is not (yet) initialized, fail. */
- if (!get_thread_process (thread)->all_symbols_looked_up)
+ if (proc->all_symbols_looked_up == 0)
+ return TD_ERR;
+
+ if (priv->td_thr_tls_get_addr_p == NULL)
return TD_ERR;
lwp = get_thread_lwp (thread);
@@ -398,8 +396,9 @@ 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 = priv->td_thr_tls_get_addr_p (&lwp->th,
+ (psaddr_t) (uintptr_t) load_module,
+ offset, &addr);
current_inferior = saved_inferior;
if (err == TD_OK)
{
@@ -408,17 +407,180 @@ thread_db_get_tls_address (struct thread
}
else
return err;
-#else
- return -1;
-#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(required, a) \
+ if ((a) == NULL) { \
+ if (debug_threads) { \
+ fprintf (stderr, "dlsym: %s\n", dlerror ()); \
+ } \
+ if (required) \
+ return 0; \
+ }
+
+ CHK (1, priv->td_ta_new_p = dlsym (handle, "td_ta_new"));
+
+ /* Attempt to open a connection to the thread library. */
+ err = priv->td_ta_new_p (&priv->proc_handle, &priv->thread_agent);
+ if (err != TD_OK)
+ {
+ priv->td_ta_new_p = NULL;
+ if (debug_threads)
+ fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
+ return 0;
+ }
+
+ CHK (1, priv->td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr"));
+ CHK (1, priv->td_thr_get_info_p = dlsym (handle, "td_thr_get_info"));
+ CHK (1, priv->td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter"));
+ CHK (1, priv->td_symbol_list_p = dlsym (handle, "td_symbol_list"));
+
+ /* This is required only when thread_db_use_events is on. */
+ CHK (thread_db_use_events,
+ priv->td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"));
+
+ /* These are not essential. */
+ CHK (0, priv->td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"));
+ CHK (0, priv->td_ta_set_event_p = dlsym (handle, "td_ta_set_event"));
+ CHK (0, priv->td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"));
+ CHK (0, priv->td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"));
+
+#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 +595,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;
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-02 23:51 ` Paul Pluzhnikov
@ 2009-10-04 20:32 ` Pedro Alves
2009-10-05 1:49 ` Paul Pluzhnikov
2009-10-06 23:08 ` Paul Pluzhnikov
2009-10-04 20:34 ` Pedro Alves
1 sibling, 2 replies; 25+ messages in thread
From: Pedro Alves @ 2009-10-04 20:32 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: gdb-patches, dje
On Saturday 03 October 2009 00:51:22, Paul Pluzhnikov wrote:
> On Wed, Sep 2, 2009 at 10:15 AM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> > On Wed, Sep 2, 2009 at 9:47 AM, Pedro Alves<pedro@codesourcery.com> wrote:
> >
> >> Since you're touching this, how about loading a thread_db per-process
> >> like gdb/linux-thread-db.c already does?
> >
> > Oh, I've had this patch locally for so long, I didn't realize gdbserver
> > is now multi-process as well. Will fix.
>
> Here is the fix.
Thanks much. This is close.
I take it you only care for extended-remote? How is the user
supposed to tweak the new setting with plain remote?
"tar remote; monitor foo; c" ? I don't think that would work
with "gdbserver --attach".
> 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 Oct 2009 23:49:31 -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
> @@ -42,28 +42,9 @@ AC_DEFUN([SRV_CHECK_THREAD_DB],
> void ps_get_thread_area() {}
> void ps_getpid() {}],
> [td_ta_new();],
> - [srv_cv_thread_db="$thread_db"],
> + [srv_cv_thread_db="-ldl"],
> [srv_cv_thread_db=no])
> ])
> LIBS="$old_LIBS"
This doesn't make sense.
> Index: gdbserver/linux-low.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
> retrieving revision 1.32
> diff -u -p -u -r1.32 linux-low.h
> --- gdbserver/linux-low.h 30 Jun 2009 16:35:25 -0000 1.32
> +++ gdbserver/linux-low.h 2 Oct 2009 23:49:31 -0000
> @@ -57,6 +57,32 @@ struct process_info_private
> /* Connection to the libthread_db library. */
> td_thragent_t *thread_agent;
>
> + /* Handle of the libthread_db from dlopen. */
> + void *handle;
> +
> + /* Addresses of libthread_db functions. */
> + td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
> + td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
> + td_event_msg_t *msg);
> + td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
> + td_thr_events_t *event);
> + td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
> + td_event_e event, td_notify_t *ptr);
> + td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid,
> + td_thrhandle_t *th);
> + td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
> + td_thrinfo_t *infop);
> + td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event);
> + 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);
> + td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
> + void *map_address,
> + size_t offset, void **address);
> + const char ** (*td_symbol_list_p) (void);
> +
Although gdbserver doesn't have a target stack concept, let's try to keep the
layers a bit separate. Could you please make this a new (private) structure
in thread-db.c, and then have a new pointer here, say
process_info_private->thread_db into such an object?
> /* Arch-specific additions. */
> struct arch_process_info *arch_private;
> };
> 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 Oct 2009 23:49:31 -0000
> @@ -32,6 +32,8 @@
> #include <malloc.h>
> #endif
>
> +#include <ctype.h>
> +
> 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;
We're now leaking target specific code into gdbserver's
common bits. This will definitely not make sense to have on a
Windows build of gdbserver. Can I convince you to add a target hook
to handle monitor commands, and move this handling to thread-db.c?
That's the simplest. Even better would be to have some way
to register monitor commands with a callback, similar to gdb
commands, but much simpler. But I'd be happy with the target
method for now.
> 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 Oct 2009 23:49:31 -0000
<snip>
> @@ -233,7 +222,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;
Missing space before '()'. There are other instances of this.
> /* If the thread layer is not (yet) initialized, fail. */
> - if (!get_thread_process (thread)->all_symbols_looked_up)
> + if (proc->all_symbols_looked_up == 0)
> + return TD_ERR;
Please keep using ! for boolean's.
> +
> + if (priv->td_thr_tls_get_addr_p == NULL)
> return TD_ERR;
Shouldn't this be -1 ? As in ...
> -#else
> - return -1;
> -#endif
... this? < 0 here means unsupported, see server.c.
> +}
> +
> +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(required, a) \
> + if ((a) == NULL) { \
> + if (debug_threads) { \
> + fprintf (stderr, "dlsym: %s\n", dlerror ()); \
> + } \
> + if (required) \
> + return 0; \
> + }
Even though people shouldn't stare at this for too
long (it may cause rare forms of brain rash), please make this
follow the code standards. '{' on new line. I'd prefer to see
this wrapped on do {} while (0). Dangling if's raise eyebrows.
> +
> + CHK (1, priv->td_ta_new_p = dlsym (handle, "td_ta_new"));
> +
> + /* Attempt to open a connection to the thread library. */
> + err = priv->td_ta_new_p (&priv->proc_handle, &priv->thread_agent);
> + if (err != TD_OK)
> + {
> + priv->td_ta_new_p = NULL;
> + if (debug_threads)
> + fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
> + return 0;
> + }
> +
> + CHK (1, priv->td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr"));
> + CHK (1, priv->td_thr_get_info_p = dlsym (handle, "td_thr_get_info"));
> + CHK (1, priv->td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter"));
> + CHK (1, priv->td_symbol_list_p = dlsym (handle, "td_symbol_list"));
> +
> + /* This is required only when thread_db_use_events is on. */
> + CHK (thread_db_use_events,
> + priv->td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"));
> +
> + /* These are not essential. */
> + CHK (0, priv->td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"));
> + CHK (0, priv->td_ta_set_event_p = dlsym (handle, "td_ta_set_event"));
> + CHK (0, priv->td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"));
> + CHK (0, priv->td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"));
> +
> +#undef CHK
Looking at the equivalent code in gdb/linux-thread-db.c, I don't
know that it's less readable there anyway, and I don't think the case
of finding just a couple of the required symbols (and dumping that to
debug output) is something we expect to find. Just MHO.
> +
> + return 1;
> +}
> +
<snip>
> +
> +static int
> +thread_db_load_search ()
^ (void) please.
> +{
> + 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;
Something fishy with the alignment here? Mind tab vs spaces.
> + }
> + 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;
> }
>
<snip>
--
Pedro Alves
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-02 23:51 ` Paul Pluzhnikov
2009-10-04 20:32 ` Pedro Alves
@ 2009-10-04 20:34 ` Pedro Alves
1 sibling, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2009-10-04 20:34 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: gdb-patches, dje
On Saturday 03 October 2009 00:51:22, Paul Pluzhnikov wrote:
> On Wed, Sep 2, 2009 at 10:15 AM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> > On Wed, Sep 2, 2009 at 9:47 AM, Pedro Alves<pedro@codesourcery.com> wrote:
> >
> >> Since you're touching this, how about loading a thread_db per-process
> >> like gdb/linux-thread-db.c already does?
> >
> > Oh, I've had this patch locally for so long, I didn't realize gdbserver
> > is now multi-process as well. Will fix.
>
> Here is the fix.
Thanks much. This is close.
I take it you only care for extended-remote? How is the user
supposed to tweak the new setting with plain remote?
"tar remote; monitor foo; c" ? I don't think that would work
with "gdbserver --attach".
> 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 Oct 2009 23:49:31 -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
> @@ -42,28 +42,9 @@ AC_DEFUN([SRV_CHECK_THREAD_DB],
> void ps_get_thread_area() {}
> void ps_getpid() {}],
> [td_ta_new();],
> - [srv_cv_thread_db="$thread_db"],
> + [srv_cv_thread_db="-ldl"],
> [srv_cv_thread_db=no])
> ])
> LIBS="$old_LIBS"
This doesn't make sense.
> Index: gdbserver/linux-low.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
> retrieving revision 1.32
> diff -u -p -u -r1.32 linux-low.h
> --- gdbserver/linux-low.h 30 Jun 2009 16:35:25 -0000 1.32
> +++ gdbserver/linux-low.h 2 Oct 2009 23:49:31 -0000
> @@ -57,6 +57,32 @@ struct process_info_private
> /* Connection to the libthread_db library. */
> td_thragent_t *thread_agent;
>
> + /* Handle of the libthread_db from dlopen. */
> + void *handle;
> +
> + /* Addresses of libthread_db functions. */
> + td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
> + td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
> + td_event_msg_t *msg);
> + td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
> + td_thr_events_t *event);
> + td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
> + td_event_e event, td_notify_t *ptr);
> + td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid,
> + td_thrhandle_t *th);
> + td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
> + td_thrinfo_t *infop);
> + td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event);
> + 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);
> + td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
> + void *map_address,
> + size_t offset, void **address);
> + const char ** (*td_symbol_list_p) (void);
> +
Although gdbserver doesn't have a target stack concept, let's try to keep the
layers a bit separate. Could you please make this a new (private) structure
in thread-db.c, and then have a new pointer here, say
process_info_private->thread_db into such an object?
> /* Arch-specific additions. */
> struct arch_process_info *arch_private;
> };
> 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 Oct 2009 23:49:31 -0000
> @@ -32,6 +32,8 @@
> #include <malloc.h>
> #endif
>
> +#include <ctype.h>
> +
> 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;
We're now leaking target specific code into gdbserver's
common bits. This will definitely not make sense to have on a
Windows build of gdbserver. Can I convince you to add a target hook
to handle monitor commands, and move this handling to thread-db.c?
That's the simplest. Even better would be to have some way
to register monitor commands with a callback, similar to gdb
commands, but much simpler. But I'd be happy with the target
method for now.
> 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 Oct 2009 23:49:31 -0000
<snip>
> @@ -233,7 +222,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;
Missing space before '()'. There are other instances of this.
> /* If the thread layer is not (yet) initialized, fail. */
> - if (!get_thread_process (thread)->all_symbols_looked_up)
> + if (proc->all_symbols_looked_up == 0)
> + return TD_ERR;
Please keep using ! for boolean's.
> +
> + if (priv->td_thr_tls_get_addr_p == NULL)
> return TD_ERR;
Shouldn't this be -1 ? As in ...
> -#else
> - return -1;
> -#endif
... this? < 0 here means unsupported, see server.c.
> +}
> +
> +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(required, a) \
> + if ((a) == NULL) { \
> + if (debug_threads) { \
> + fprintf (stderr, "dlsym: %s\n", dlerror ()); \
> + } \
> + if (required) \
> + return 0; \
> + }
Even though people shouldn't stare at this for too
long (it may cause rare forms of brain rash), please make this
follow the code standards. '{' on new line. I'd prefer to see
this wrapped on do {} while (0). Dangling if's raise eyebrows.
> +
> + CHK (1, priv->td_ta_new_p = dlsym (handle, "td_ta_new"));
> +
> + /* Attempt to open a connection to the thread library. */
> + err = priv->td_ta_new_p (&priv->proc_handle, &priv->thread_agent);
> + if (err != TD_OK)
> + {
> + priv->td_ta_new_p = NULL;
> + if (debug_threads)
> + fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
> + return 0;
> + }
> +
> + CHK (1, priv->td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr"));
> + CHK (1, priv->td_thr_get_info_p = dlsym (handle, "td_thr_get_info"));
> + CHK (1, priv->td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter"));
> + CHK (1, priv->td_symbol_list_p = dlsym (handle, "td_symbol_list"));
> +
> + /* This is required only when thread_db_use_events is on. */
> + CHK (thread_db_use_events,
> + priv->td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"));
> +
> + /* These are not essential. */
> + CHK (0, priv->td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"));
> + CHK (0, priv->td_ta_set_event_p = dlsym (handle, "td_ta_set_event"));
> + CHK (0, priv->td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"));
> + CHK (0, priv->td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"));
> +
> +#undef CHK
Looking at the equivalent code in gdb/linux-thread-db.c, I don't
know that it's less readable there anyway, and I don't think the case
of finding just a couple of the required symbols (and dumping that to
debug output) is something we expect to find. Just MHO.
> +
> + return 1;
> +}
> +
<snip>
> +
> +static int
> +thread_db_load_search ()
^ (void) please.
> +{
> + 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;
Something fishy with the alignment here? Mind tab vs spaces.
> + }
> + 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;
> }
>
<snip>
--
Pedro Alves
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-04 20:32 ` Pedro Alves
@ 2009-10-05 1:49 ` Paul Pluzhnikov
2009-10-05 3:03 ` Pedro Alves
2009-10-06 23:08 ` Paul Pluzhnikov
1 sibling, 1 reply; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-05 1:49 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, dje
On Sun, Oct 4, 2009 at 1:32 PM, Pedro Alves <pedro@codesourcery.com> wrote:
> Thanks much. This is close.
Thanks for your comments, I'll address most of them soon.
Quick question:
>> + struct process_info_private *proc = current_process()->private;
>
> Missing space before '()'. There are other instances of this.
So this is supposed to be:
struct process_info_private *proc = current_process ()->private;
That A) looks weird and B) contradicts current usage (before the patch):
grep current_process thread-db.c
struct process_info_private *proc = current_process()->private;
struct process_info_private *proc = current_process()->private;
struct process_info_private *proc = current_process()->private;
struct process_info *proc = current_process ();
Thanks,
--
Paul Pluzhnikov
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-05 1:49 ` Paul Pluzhnikov
@ 2009-10-05 3:03 ` Pedro Alves
2009-10-13 13:53 ` Pedro Alves
0 siblings, 1 reply; 25+ messages in thread
From: Pedro Alves @ 2009-10-05 3:03 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: gdb-patches, dje
On Monday 05 October 2009 02:49:19, Paul Pluzhnikov wrote:
> >> + struct process_info_private *proc = current_process()->private;
> >
> > Missing space before '()'. There are other instances of this.
>
> So this is supposed to be:
>
> struct process_info_private *proc = current_process ()->private;
>
> That A) looks weird
Subjective matter of taste. That's why we have code formatting
standards ;-). It's a function call. The standard
says put space there. Try grepping for "()->" in gdb's codebase.
It perhaps looks weird because it's not pretty to dereference
a pointer returned by a function. To me, it has that
but-it-could-be-NULL! feeling.
> and B) contradicts current usage (before the patch):
>
> grep current_process thread-db.c
> struct process_info_private *proc = current_process()->private;
> struct process_info_private *proc = current_process()->private;
> struct process_info_private *proc = current_process()->private;
> struct process_info *proc = current_process ();
Probably a typo followed by copy-paste, and I'm probably to blame
for those. It there are any after your patch goes in, I'll take
care of fixing them.
--
Pedro Alves
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-04 20:32 ` Pedro Alves
2009-10-05 1:49 ` Paul Pluzhnikov
@ 2009-10-06 23:08 ` Paul Pluzhnikov
2009-10-06 23:44 ` Pedro Alves
1 sibling, 1 reply; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-06 23:08 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, dje
[-- Attachment #1: Type: text/plain, Size: 3642 bytes --]
On Sun, Oct 4, 2009 at 1:32 PM, Pedro Alves <pedro@codesourcery.com> wrote:
> I take it you only care for extended-remote? How is the user
> supposed to tweak the new setting with plain remote?
Note that default search path is initialized from LIBTHREAD_DB_SEARCH_PATH.
The user is expected to set this to appropriate system-specific default if
the standard loader search path is inappropriate.
>> 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 Oct 2009 23:49:31 -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
>> @@ -42,28 +42,9 @@ AC_DEFUN([SRV_CHECK_THREAD_DB],
>> void ps_get_thread_area() {}
>> void ps_getpid() {}],
>> [td_ta_new();],
>> - [srv_cv_thread_db="$thread_db"],
>> + [srv_cv_thread_db="-ldl"],
>> [srv_cv_thread_db=no])
>> ])
>> LIBS="$old_LIBS"
>
> This doesn't make sense.
Why not?
If we can find '-lthread_db', '/lib/libthread_db.so.1' or
'$prefix/lib/libthread_db.so.1', then we switch on using libthread_db and
use '-ldl' to dynamically load it.
Perhaps a better fix is to skip this check altogether, and always use
dlopen on Linux?
>> + /* Handle of the libthread_db from dlopen. */
>> + void *handle;
...
>
> Although gdbserver doesn't have a target stack concept, let's try to keep the
> layers a bit separate. Could you please make this a new (private) structure
> in thread-db.c, and then have a new pointer here, say
> process_info_private->thread_db into such an object?
Done. Several existing members of struct process_info_private,
e.g. thread_agent also are thread_db-private, so I moved them as well.
I believe I've addressed all your other comments.
Tested on Linux/x86_64 (with "--target_board native-gdbserver"), no
regressions.
Thanks,
--
Paul Pluzhnikov
doc/
2009-10-06 Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.texinfo (Server): Document libthread-db-search-path.
gdbserver/
2009-10-06 Paul Pluzhnikov <ppluzhnikov@google.com>
* acinclude.m4: Link with libdl.
* configure.ac: Don't check for tls_get_address.
* linux-low.h (struct process_info_private): Move members to struct
thread_db.
(thread_db_free): New prototype.
* linux-low.c (linux_remove_process): Adjust.
(linux_wait_for_event_1, linux_look_up_symbols): Likewise.
* server.c (handle_query): Move code ...
(handle_monitor_command): ... here.
* server.h (handle_monitor_command): New prototype.
* target.h (struct target_ops): New member.
* thread-db.c (struct thread_db): New.
(libthread_db_search_path): New variable.
(thread_db_create_event, thread_db_enable_reporting)
(find_one_thread, maybe_attach_thread, find_new_threads_callback)
(thread_db_find_new_threads, (thread_db_get_tls_address): Adjust.
(try_thread_db_load_1, dladdr_to_soname): New functions.
(try_thread_db_load, thread_db_load_search): New functions.
(thread_db_init): Search for libthread_db.
(thread_db_free): New function.
(thread_db_handle_monitor_command): Likewise.
[-- Attachment #2: gdb-gdbserver-threaddb-search-20091006.txt --]
[-- Type: text/plain, Size: 28781 bytes --]
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.631
diff -u -p -u -r1.631 gdb.texinfo
--- doc/gdb.texinfo 6 Oct 2009 18:02:36 -0000 1.631
+++ doc/gdb.texinfo 6 Oct 2009 22:34:54 -0000
@@ -14903,6 +14903,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 6 Oct 2009 22:34:54 -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
@@ -42,28 +42,9 @@ AC_DEFUN([SRV_CHECK_THREAD_DB],
void ps_get_thread_area() {}
void ps_getpid() {}],
[td_ta_new();],
- [srv_cv_thread_db="$thread_db"],
+ [srv_cv_thread_db="-ldl"],
[srv_cv_thread_db=no])
])
LIBS="$old_LIBS"
])])
-AC_DEFUN([SRV_CHECK_TLS_GET_ADDR],
-[AC_CACHE_CHECK([for thread_db_tls_get_addr],[srv_cv_tls_get_addr],
- [old_LIBS="$LIBS"
- LIBS="$LIBS $srv_cv_thread_db"
- AC_TRY_LINK(
- [void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}],
- [td_thr_tls_get_addr();],
- [srv_cv_tls_get_addr=yes],
- [srv_cv_tls_get_addr=no])
- LIBS="$old_LIBS"
-])])
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 6 Oct 2009 22:34:54 -0000
@@ -147,7 +147,6 @@ if test "$srv_linux_thread_db" = "yes";
srv_linux_thread_db=no
else
srv_libs="$srv_cv_thread_db"
- SRV_CHECK_TLS_GET_ADDR
fi
old_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -rdynamic"
@@ -166,10 +165,6 @@ if test "$srv_linux_thread_db" = "yes";
if test $gdbsrv_cv_have_td_version = yes; then
AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.])
fi
-
- if test "$srv_cv_tls_get_addr" = yes; then
- AC_DEFINE(HAVE_TD_THR_TLS_GET_ADDR, 1, [Define if td_thr_tls_get_addr is available.])
- fi
fi
if test "$srv_xmlfiles" != ""; then
Index: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.112
diff -u -p -u -r1.112 linux-low.c
--- gdbserver/linux-low.c 31 Jul 2009 15:25:22 -0000 1.112
+++ gdbserver/linux-low.c 6 Oct 2009 22:34:54 -0000
@@ -42,6 +42,7 @@
#include <dirent.h>
#include <sys/stat.h>
#include <sys/vfs.h>
+#include <dlfcn.h>
#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
@@ -118,6 +119,11 @@ int stopping_threads;
/* FIXME make into a target method? */
int using_threads = 1;
+#ifdef USE_THREAD_DB
+/* From thread-db.c */
+extern void thread_db_handle_monitor_command (char *);
+#endif
+
/* This flag is true iff we've just created or attached to our first
inferior but it has not stopped yet. As soon as it does, we need
to call the low target's arch_setup callback. Doing this only on
@@ -261,8 +267,11 @@ linux_add_process (int pid, int attached
static void
linux_remove_process (struct process_info *process)
{
- free (process->private->arch_private);
- free (process->private);
+ struct process_info_private *priv = process->private;
+
+ thread_db_free (process);
+ free (priv->arch_private);
+ free (priv);
remove_process (process);
}
@@ -1122,7 +1131,7 @@ linux_wait_for_event_1 (ptid_t ptid, int
&& !event_child->stepping
&& (
#ifdef USE_THREAD_DB
- (current_process ()->private->thread_db_active
+ (current_process ()->private->thread_db != NULL
&& (WSTOPSIG (*wstat) == __SIGRTMIN
|| WSTOPSIG (*wstat) == __SIGRTMIN + 1))
||
@@ -2642,11 +2651,10 @@ linux_look_up_symbols (void)
#ifdef USE_THREAD_DB
struct process_info *proc = current_process ();
- if (proc->private->thread_db_active)
+ if (proc->private->thread_db != NULL)
return;
- proc->private->thread_db_active
- = thread_db_init (!linux_supports_tracefork_flag);
+ thread_db_init (!linux_supports_tracefork_flag);
#endif
}
@@ -3171,7 +3179,12 @@ static struct target_ops linux_target_op
linux_supports_non_stop,
linux_async,
linux_start_non_stop,
- linux_supports_multi_process
+ linux_supports_multi_process,
+#ifdef USE_THREAD_DB
+ thread_db_handle_monitor_command
+#else
+ NULL
+#endif
};
static void
Index: gdbserver/linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.32
diff -u -p -u -r1.32 linux-low.h
--- gdbserver/linux-low.h 30 Jun 2009 16:35:25 -0000 1.32
+++ gdbserver/linux-low.h 6 Oct 2009 22:34:54 -0000
@@ -47,18 +47,12 @@ struct siginfo;
struct process_info_private
{
- /* True if this process has loaded thread_db, and it is active. */
- int thread_db_active;
-
- /* Structure that identifies the child process for the
- <proc_service.h> interface. */
- struct ps_prochandle proc_handle;
-
- /* Connection to the libthread_db library. */
- td_thragent_t *thread_agent;
-
/* Arch-specific additions. */
struct arch_process_info *arch_private;
+
+ /* libthread_db-specific additions. Not NULL if this process has loaded
+ thread_db, and it is active. */
+ struct thread_db *thread_db;
};
struct lwp_info;
@@ -205,6 +199,7 @@ int elf_64_file_p (const char *file);
void linux_attach_lwp (unsigned long pid);
int thread_db_init (int use_events);
+void thread_db_free (struct process_info *);
int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
CORE_ADDR load_module, CORE_ADDR *address);
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 6 Oct 2009 22:34:54 -0000
@@ -1211,46 +1211,11 @@ handle_query (char *own_buf, int packet_
write_ok (own_buf);
- if (strcmp (mon, "set debug 1") == 0)
- {
- debug_threads = 1;
- monitor_output ("Debug output enabled.\n");
- }
- else if (strcmp (mon, "set debug 0") == 0)
- {
- debug_threads = 0;
- monitor_output ("Debug output disabled.\n");
- }
- else if (strcmp (mon, "set debug-hw-points 1") == 0)
- {
- debug_hw_points = 1;
- monitor_output ("H/W point debugging output enabled.\n");
- }
- else if (strcmp (mon, "set debug-hw-points 0") == 0)
- {
- debug_hw_points = 0;
- monitor_output ("H/W point debugging output disabled.\n");
- }
- else if (strcmp (mon, "set remote-debug 1") == 0)
- {
- remote_debug = 1;
- monitor_output ("Protocol debug output enabled.\n");
- }
- else if (strcmp (mon, "set remote-debug 0") == 0)
- {
- remote_debug = 0;
- monitor_output ("Protocol debug output disabled.\n");
- }
- else if (strcmp (mon, "help") == 0)
- monitor_show_help ();
- else if (strcmp (mon, "exit") == 0)
- exit_requested = 1;
+ if (the_target->handle_monitor_command != NULL)
+ (*the_target->handle_monitor_command) (mon);
else
- {
- monitor_output ("Unknown monitor command.\n\n");
- monitor_show_help ();
- write_enn (own_buf);
- }
+ /* Default processing. */
+ handle_monitor_command (mon);
free (mon);
return;
@@ -1295,6 +1260,51 @@ handle_query (char *own_buf, int packet_
own_buf[0] = 0;
}
+void
+handle_monitor_command (char *mon)
+{
+ if (strcmp (mon, "set debug 1") == 0)
+ {
+ debug_threads = 1;
+ monitor_output ("Debug output enabled.\n");
+ }
+ else if (strcmp (mon, "set debug 0") == 0)
+ {
+ debug_threads = 0;
+ monitor_output ("Debug output disabled.\n");
+ }
+ else if (strcmp (mon, "set debug-hw-points 1") == 0)
+ {
+ debug_hw_points = 1;
+ monitor_output ("H/W point debugging output enabled.\n");
+ }
+ else if (strcmp (mon, "set debug-hw-points 0") == 0)
+ {
+ debug_hw_points = 0;
+ monitor_output ("H/W point debugging output disabled.\n");
+ }
+ else if (strcmp (mon, "set remote-debug 1") == 0)
+ {
+ remote_debug = 1;
+ monitor_output ("Protocol debug output enabled.\n");
+ }
+ else if (strcmp (mon, "set remote-debug 0") == 0)
+ {
+ remote_debug = 0;
+ monitor_output ("Protocol debug output disabled.\n");
+ }
+ else if (strcmp (mon, "help") == 0)
+ monitor_show_help ();
+ else if (strcmp (mon, "exit") == 0)
+ exit_requested = 1;
+ else
+ {
+ monitor_output ("Unknown monitor command.\n\n");
+ monitor_show_help ();
+ write_enn (own_buf);
+ }
+}
+
/* Parse vCont packets. */
void
handle_v_cont (char *own_buf)
Index: gdbserver/server.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.h,v
retrieving revision 1.59
diff -u -p -u -r1.59 server.h
--- gdbserver/server.h 30 Jun 2009 16:35:25 -0000 1.59
+++ gdbserver/server.h 6 Oct 2009 22:34:54 -0000
@@ -297,6 +297,7 @@ extern void start_event_loop (void);
/* Functions from server.c. */
extern void handle_serial_event (int err, gdb_client_data client_data);
extern void handle_target_event (int err, gdb_client_data client_data);
+extern void handle_monitor_command (char *);
extern void push_event (ptid_t ptid, struct target_waitstatus *status);
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.39
diff -u -p -u -r1.39 target.h
--- gdbserver/target.h 25 Jun 2009 22:13:53 -0000 1.39
+++ gdbserver/target.h 6 Oct 2009 22:34:54 -0000
@@ -279,6 +279,9 @@ struct target_ops
/* Returns true if the target supports multi-process debugging. */
int (*supports_multi_process) (void);
+
+ /* Process monitor command. */
+ void (*handle_monitor_command) (char *);
};
extern struct target_ops *the_target;
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 6 Oct 2009 22:34:54 -0000
@@ -27,13 +27,51 @@ extern int debug_threads;
static int thread_db_use_events;
-#ifdef HAVE_THREAD_DB_H
-#include <thread_db.h>
-#endif
-
#include "gdb_proc_service.h"
+#include "../gdb_thread_db.h"
+#include <dlfcn.h>
#include <stdint.h>
+#include <limits.h>
+#include <ctype.h>
+
+struct thread_db
+{
+ /* Structure that identifies the child process for the
+ <proc_service.h> interface. */
+ struct ps_prochandle proc_handle;
+
+ /* Connection to the libthread_db library. */
+ td_thragent_t *thread_agent;
+
+ /* Handle of the libthread_db from dlopen. */
+ void *handle;
+
+ /* Addresses of libthread_db functions. */
+ td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
+ td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
+ td_event_msg_t *msg);
+ td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
+ td_thr_events_t *event);
+ td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
+ td_event_e event, td_notify_t *ptr);
+ td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid,
+ td_thrhandle_t *th);
+ td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
+ td_thrinfo_t *infop);
+ td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event);
+ 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);
+ td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
+ void *map_address,
+ size_t offset, void **address);
+ const char ** (*td_symbol_list_p) (void);
+};
+
+static 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);
@@ -130,7 +168,11 @@ thread_db_create_event (CORE_ADDR where)
td_event_msg_t msg;
td_err_e err;
struct lwp_info *lwp;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+
+ if (thread_db->td_ta_event_getmsg_p == NULL)
+ /* We shouldn't have ever be here in the first place. */
+ return TD_ERR;
if (debug_threads)
fprintf (stderr, "Thread creation event.\n");
@@ -139,7 +181,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 = thread_db->td_ta_event_getmsg_p (thread_db->thread_agent, &msg);
if (err != TD_OK)
fprintf (stderr, "thread getmsg err: %s\n",
thread_db_err_str (err));
@@ -158,36 +200,25 @@ thread_db_create_event (CORE_ADDR where)
return 0;
}
-#if 0
-static int
-thread_db_death_event (CORE_ADDR where)
-{
- if (debug_threads)
- fprintf (stderr, "Thread death event.\n");
-
- return 0;
-}
-#endif
-
static int
thread_db_enable_reporting ()
{
td_thr_events_t events;
td_notify_t notify;
td_err_e err;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+
+ if (thread_db->td_ta_set_event_p == NULL
+ || thread_db->td_ta_event_addr_p == NULL
+ || thread_db->td_ta_event_getmsg_p == NULL)
+ /* This libthread_db is missing required support. */
+ return TD_ERR;
/* Set the process wide mask saying which events we're interested in. */
td_event_emptyset (&events);
td_event_addset (&events, TD_CREATE);
-#if 0
- /* This is reported to be broken in glibc 2.1.3. A different approach
- will be necessary to support that. */
- td_event_addset (&events, TD_DEATH);
-#endif
-
- err = td_ta_set_event (proc->thread_agent, &events);
+ err = thread_db->td_ta_set_event_p (thread_db->thread_agent, &events);
if (err != TD_OK)
{
warning ("Unable to set global thread event mask: %s",
@@ -196,7 +227,8 @@ thread_db_enable_reporting ()
}
/* Get address for thread creation breakpoint. */
- err = td_ta_event_addr (proc->thread_agent, TD_CREATE, ¬ify);
+ err = thread_db->td_ta_event_addr_p (thread_db->thread_agent, TD_CREATE,
+ ¬ify);
if (err != TD_OK)
{
warning ("Unable to get location for thread creation breakpoint: %s",
@@ -206,22 +238,6 @@ thread_db_enable_reporting ()
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
thread_db_create_event);
-#if 0
- /* Don't concern ourselves with reported thread deaths, only
- with actual thread deaths (via wait). */
-
- /* Get address for thread death breakpoint. */
- err = td_ta_event_addr (proc->thread_agent, TD_DEATH, ¬ify);
- if (err != TD_OK)
- {
- warning ("Unable to get location for thread death breakpoint: %s",
- thread_db_err_str (err));
- return;
- }
- set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
- thread_db_death_event);
-#endif
-
return 1;
}
@@ -233,7 +249,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 thread_db *thread_db = current_process ()->private->thread_db;
int lwpid = ptid_get_lwp (ptid);
inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
@@ -242,13 +258,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 = thread_db->td_ta_map_lwp2thr_p (thread_db->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 = thread_db->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 +281,7 @@ find_one_thread (ptid_t ptid)
if (thread_db_use_events)
{
- err = td_thr_event_enable (&th, 1);
+ err = thread_db->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 +325,8 @@ maybe_attach_thread (const td_thrhandle_
if (thread_db_use_events)
{
- err = td_thr_event_enable (th_p, 1);
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+ err = thread_db->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));
@@ -322,8 +338,9 @@ find_new_threads_callback (const td_thrh
{
td_thrinfo_t ti;
td_err_e err;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
- err = td_thr_get_info (th_p, &ti);
+ err = thread_db->td_thr_get_info_p (th_p, &ti);
if (err != TD_OK)
error ("Cannot get thread info: %s", thread_db_err_str (err));
@@ -341,7 +358,7 @@ thread_db_find_new_threads (void)
{
td_err_e err;
ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
/* This function is only called when we first initialize thread_db.
First locate the initial thread. If it is not ready for
@@ -350,10 +367,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 = thread_db->td_ta_thr_iter_p (thread_db->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 +383,11 @@ thread_db_find_new_threads (void)
static void
thread_db_look_up_symbols (void)
{
- const char **sym_list = td_symbol_list ();
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+ const char **sym_list;
CORE_ADDR unused;
- for (sym_list = td_symbol_list (); *sym_list; sym_list++)
+ for (sym_list = thread_db->td_symbol_list_p (); *sym_list; sym_list++)
look_up_one_symbol (*sym_list, &unused);
}
@@ -377,16 +395,23 @@ int
thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
CORE_ADDR load_module, CORE_ADDR *address)
{
-#if HAVE_TD_THR_TLS_GET_ADDR
psaddr_t addr;
td_err_e err;
struct lwp_info *lwp;
struct thread_info *saved_inferior;
+ struct process_info *proc;
+ struct thread_db *thread_db;
+
+ proc = get_thread_process (thread);
+ thread_db = proc->private->thread_db;
/* If the thread layer is not (yet) initialized, fail. */
- if (!get_thread_process (thread)->all_symbols_looked_up)
+ if (!proc->all_symbols_looked_up)
return TD_ERR;
+ if (thread_db->td_thr_tls_get_addr_p == NULL)
+ return -1;
+
lwp = get_thread_lwp (thread);
if (!lwp->thread_known)
find_one_thread (lwp->head.id);
@@ -398,8 +423,9 @@ 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 = thread_db->td_thr_tls_get_addr_p (&lwp->th,
+ (psaddr_t) (uintptr_t) load_module,
+ offset, &addr);
current_inferior = saved_inferior;
if (err == TD_OK)
{
@@ -408,17 +434,195 @@ thread_db_get_tls_address (struct thread
}
else
return err;
-#else
- return -1;
-#endif
+}
+
+static int
+try_thread_db_load_1 (void *handle)
+{
+ td_err_e err;
+ struct thread_db tdb;
+ struct process_info *proc = current_process ();
+
+ if (proc->private->thread_db != NULL)
+ {
+ fprintf (stderr, "Internal error: thread_db != NULL in %s:%d\n",
+ __FILE__, __LINE__);
+ return 0;
+ }
+
+ tdb.handle = handle;
+
+ /* Initialize pointers to the dynamic library functions we will use.
+ Essential functions first. */
+
+#define CHK(required, a) \
+ do \
+ { \
+ if ((a) == NULL) \
+ { \
+ if (debug_threads) \
+ fprintf (stderr, "dlsym: %s\n", dlerror ()); \
+ if (required) \
+ return 0; \
+ } \
+ } \
+ while (0)
+
+ CHK (1, tdb.td_ta_new_p = dlsym (handle, "td_ta_new"));
+
+ /* Attempt to open a connection to the thread library. */
+ err = tdb.td_ta_new_p (&tdb.proc_handle, &tdb.thread_agent);
+ if (err != TD_OK)
+ {
+ if (debug_threads)
+ fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
+ return 0;
+ }
+
+ CHK (1, tdb.td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr"));
+ CHK (1, tdb.td_thr_get_info_p = dlsym (handle, "td_thr_get_info"));
+ CHK (1, tdb.td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter"));
+ CHK (1, tdb.td_symbol_list_p = dlsym (handle, "td_symbol_list"));
+
+ /* This is required only when thread_db_use_events is on. */
+ CHK (thread_db_use_events,
+ tdb.td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"));
+
+ /* These are not essential. */
+ CHK (0, tdb.td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"));
+ CHK (0, tdb.td_ta_set_event_p = dlsym (handle, "td_ta_set_event"));
+ CHK (0, tdb.td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"));
+ CHK (0, tdb.td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"));
+
+#undef CHK
+
+ proc->private->thread_db = malloc (sizeof (tdb));
+ memcpy (proc->private->thread_db, &tdb, sizeof (tdb));
+
+ 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 (void)
+{
+ 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,27 +637,62 @@ 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;
}
+
+/* Disconnect from libthread_db and free resources. */
+
+void
+thread_db_free (struct process_info *proc)
+{
+ struct thread_db *thread_db = proc->private->thread_db;
+ if (thread_db)
+ {
+ td_err_e (*td_ta_delete_p) (td_thragent_t *);
+
+ td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete");
+ if (td_ta_delete_p != NULL)
+ (*td_ta_delete_p) (thread_db->thread_agent);
+
+ dlclose (thread_db->handle);
+ free (thread_db);
+ proc->private->thread_db = NULL;
+ }
+}
+
+/* Handle "set libthread-db-search-path" monitor command.
+ Pass any other monitor command back to default handler. */
+
+void
+thread_db_handle_monitor_command (char *mon)
+{
+ 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
+ handle_monitor_command (mon);
+}
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-06 23:08 ` Paul Pluzhnikov
@ 2009-10-06 23:44 ` Pedro Alves
2009-10-07 0:27 ` Paul Pluzhnikov
0 siblings, 1 reply; 25+ messages in thread
From: Pedro Alves @ 2009-10-06 23:44 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: gdb-patches, dje
On Wednesday 07 October 2009 00:08:36, Paul Pluzhnikov wrote:
> > I take it you only care for extended-remote? How is the user
> > supposed to tweak the new setting with plain remote?
>
> Note that default search path is initialized from LIBTHREAD_DB_SEARCH_PATH.
>
> The user is expected to set this to appropriate system-specific default if
> the standard loader search path is inappropriate.
Okay. Something like a command line option would be more user
friendly, but if you don't need it, it's fine to leave that out
until someone does.
On Wednesday 07 October 2009 00:08:36, Paul Pluzhnikov wrote:
> If we can find '-lthread_db', '/lib/libthread_db.so.1' or
> '$prefix/lib/libthread_db.so.1', then we switch on using libthread_db and
> use '-ldl' to dynamically load it.
>
> Perhaps a better fix is to skip this check altogether, and always use
> dlopen on Linux?
I guess your patch's already doing that. You mean always use -dl. Yes,
let's do that. That's how a linux gdb is built too.
I can't look at the whole patch right now, but a quick skim
looked good. I noticed this:
+void
+thread_db_handle_monitor_command (char *mon)
+{
+ 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
+ handle_monitor_command (mon);
+}
Could you tweak the interface a bit, to return a boolean indicating
if the command was handled or not? E.g.,
+int
+thread_db_handle_monitor_command (char *mon)
+{
+ 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");
+ return 1;
+ }
+
+ return 0;
+}
Then this allows chaining handlers, and, only server.c needs to call
handle_monitor_command if nothing handled the command. Might want to
force a whitespace after "set libthread-db-search-path", so that
"set libthread-db-search-pathfoofoo" isn't accepted while at it.
--
Pedro Alves
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-06 23:44 ` Pedro Alves
@ 2009-10-07 0:27 ` Paul Pluzhnikov
2009-10-08 18:08 ` Pedro Alves
0 siblings, 1 reply; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-07 0:27 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, dje
[-- Attachment #1: Type: text/plain, Size: 2000 bytes --]
On Tue, Oct 6, 2009 at 4:44 PM, Pedro Alves <pedro@codesourcery.com> wrote:
>> Perhaps a better fix is to skip this check altogether, and always use
>> dlopen on Linux?
>
> I guess your patch's already doing that.
It did that IFF it could find some libthread_db.
Now it will just always use libdl. If libthread_db usable by the inferior
is found at runtime, it will be used; if not, tough luck.
> Could you tweak the interface a bit, to return a boolean indicating
> if the command was handled or not?
Good call. Patch attached.
> Might want to
> force a whitespace after "set libthread-db-search-path", so that
> "set libthread-db-search-pathfoofoo" isn't accepted while at it.
Done and re-tested.
Thanks,
--
Paul Pluzhnikov
doc/
2009-10-06 Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.texinfo (Server): Document libthread-db-search-path.
gdbserver/
2009-10-06 Paul Pluzhnikov <ppluzhnikov@google.com>
* acinclude.m4: (SRV_CHECK_THREAD_DB, SRV_CHECK_TLS_GET_ADDR): Remove.
* configure.ac: Adjust.
* linux-low.h (struct process_info_private): Move members to struct
thread_db.
(thread_db_free): New prototype.
* linux-low.c (linux_remove_process): Adjust.
(linux_wait_for_event_1, linux_look_up_symbols): Likewise.
* server.c (handle_query): Move code ...
(handle_monitor_command): ... here. New function.
* target.h (struct target_ops): New member.
* thread-db.c (struct thread_db): New.
(libthread_db_search_path): New variable.
(thread_db_create_event, thread_db_enable_reporting)
(find_one_thread, maybe_attach_thread, find_new_threads_callback)
(thread_db_find_new_threads, (thread_db_get_tls_address): Adjust.
(try_thread_db_load_1, dladdr_to_soname): New functions.
(try_thread_db_load, thread_db_load_search): New functions.
(thread_db_init): Search for libthread_db.
(thread_db_free): New function.
(thread_db_handle_monitor_command): Likewise.
[-- Attachment #2: gdb-gdbserver-threaddb-search-20091006-2.txt --]
[-- Type: text/plain, Size: 29584 bytes --]
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.631
diff -u -p -u -r1.631 gdb.texinfo
--- doc/gdb.texinfo 6 Oct 2009 18:02:36 -0000 1.631
+++ doc/gdb.texinfo 7 Oct 2009 00:09:37 -0000
@@ -14903,6 +14903,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 7 Oct 2009 00:09:37 -0000
@@ -7,63 +7,3 @@ sinclude(../../config/override.m4)
dnl For ACX_PKGVERSION and ACX_BUGURL.
sinclude(../../config/acx.m4)
-AC_DEFUN([SRV_CHECK_THREAD_DB],
-[AC_CACHE_CHECK([for libthread_db],[srv_cv_thread_db],
- [old_LIBS="$LIBS"
- LIBS="$LIBS -lthread_db"
- AC_TRY_LINK(
- [void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}],
- [td_ta_new();],
- [srv_cv_thread_db="-lthread_db"],
- [srv_cv_thread_db=no
-
- if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
- thread_db="/lib/libthread_db.so.1"
- else
- thread_db='$prefix/lib/libthread_db.so.1'
- fi
- LIBS="$old_LIBS `eval echo "$thread_db"`"
- AC_TRY_LINK(
- [void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}],
- [td_ta_new();],
- [srv_cv_thread_db="$thread_db"],
- [srv_cv_thread_db=no])
- ])
- LIBS="$old_LIBS"
-])])
-
-AC_DEFUN([SRV_CHECK_TLS_GET_ADDR],
-[AC_CACHE_CHECK([for thread_db_tls_get_addr],[srv_cv_tls_get_addr],
- [old_LIBS="$LIBS"
- LIBS="$LIBS $srv_cv_thread_db"
- AC_TRY_LINK(
- [void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}],
- [td_thr_tls_get_addr();],
- [srv_cv_tls_get_addr=yes],
- [srv_cv_tls_get_addr=no])
- LIBS="$old_LIBS"
-])])
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 7 Oct 2009 00:09:37 -0000
@@ -140,23 +140,13 @@ srv_libs=
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.])
- srv_linux_thread_db=no
- else
- srv_libs="$srv_cv_thread_db"
- SRV_CHECK_TLS_GET_ADDR
- fi
+ srv_libs="-ldl"
old_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -rdynamic"
AC_TRY_LINK([], [], [RDYNAMIC=-rdynamic], [RDYNAMIC=])
AC_SUBST(RDYNAMIC)
LDFLAGS="$old_LDFLAGS"
-fi
-if test "$srv_linux_thread_db" = "yes"; then
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,
@@ -166,10 +156,6 @@ if test "$srv_linux_thread_db" = "yes";
if test $gdbsrv_cv_have_td_version = yes; then
AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.])
fi
-
- if test "$srv_cv_tls_get_addr" = yes; then
- AC_DEFINE(HAVE_TD_THR_TLS_GET_ADDR, 1, [Define if td_thr_tls_get_addr is available.])
- fi
fi
if test "$srv_xmlfiles" != ""; then
Index: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.112
diff -u -p -u -r1.112 linux-low.c
--- gdbserver/linux-low.c 31 Jul 2009 15:25:22 -0000 1.112
+++ gdbserver/linux-low.c 7 Oct 2009 00:09:37 -0000
@@ -42,6 +42,7 @@
#include <dirent.h>
#include <sys/stat.h>
#include <sys/vfs.h>
+#include <dlfcn.h>
#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
@@ -118,6 +119,11 @@ int stopping_threads;
/* FIXME make into a target method? */
int using_threads = 1;
+#ifdef USE_THREAD_DB
+/* From thread-db.c */
+extern int thread_db_handle_monitor_command (char *);
+#endif
+
/* This flag is true iff we've just created or attached to our first
inferior but it has not stopped yet. As soon as it does, we need
to call the low target's arch_setup callback. Doing this only on
@@ -261,8 +267,11 @@ linux_add_process (int pid, int attached
static void
linux_remove_process (struct process_info *process)
{
- free (process->private->arch_private);
- free (process->private);
+ struct process_info_private *priv = process->private;
+
+ thread_db_free (process);
+ free (priv->arch_private);
+ free (priv);
remove_process (process);
}
@@ -1122,7 +1131,7 @@ linux_wait_for_event_1 (ptid_t ptid, int
&& !event_child->stepping
&& (
#ifdef USE_THREAD_DB
- (current_process ()->private->thread_db_active
+ (current_process ()->private->thread_db != NULL
&& (WSTOPSIG (*wstat) == __SIGRTMIN
|| WSTOPSIG (*wstat) == __SIGRTMIN + 1))
||
@@ -2642,11 +2651,10 @@ linux_look_up_symbols (void)
#ifdef USE_THREAD_DB
struct process_info *proc = current_process ();
- if (proc->private->thread_db_active)
+ if (proc->private->thread_db != NULL)
return;
- proc->private->thread_db_active
- = thread_db_init (!linux_supports_tracefork_flag);
+ thread_db_init (!linux_supports_tracefork_flag);
#endif
}
@@ -3171,7 +3179,12 @@ static struct target_ops linux_target_op
linux_supports_non_stop,
linux_async,
linux_start_non_stop,
- linux_supports_multi_process
+ linux_supports_multi_process,
+#ifdef USE_THREAD_DB
+ thread_db_handle_monitor_command
+#else
+ NULL
+#endif
};
static void
Index: gdbserver/linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.32
diff -u -p -u -r1.32 linux-low.h
--- gdbserver/linux-low.h 30 Jun 2009 16:35:25 -0000 1.32
+++ gdbserver/linux-low.h 7 Oct 2009 00:09:37 -0000
@@ -47,18 +47,12 @@ struct siginfo;
struct process_info_private
{
- /* True if this process has loaded thread_db, and it is active. */
- int thread_db_active;
-
- /* Structure that identifies the child process for the
- <proc_service.h> interface. */
- struct ps_prochandle proc_handle;
-
- /* Connection to the libthread_db library. */
- td_thragent_t *thread_agent;
-
/* Arch-specific additions. */
struct arch_process_info *arch_private;
+
+ /* libthread_db-specific additions. Not NULL if this process has loaded
+ thread_db, and it is active. */
+ struct thread_db *thread_db;
};
struct lwp_info;
@@ -205,6 +199,7 @@ int elf_64_file_p (const char *file);
void linux_attach_lwp (unsigned long pid);
int thread_db_init (int use_events);
+void thread_db_free (struct process_info *);
int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
CORE_ADDR load_module, CORE_ADDR *address);
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 7 Oct 2009 00:09:37 -0000
@@ -660,6 +660,53 @@ handle_search_memory (char *own_buf, int
return; \
}
+/* Handle monitor commands not handled by target-specific handlers. */
+
+static void
+handle_monitor_command (char *mon)
+{
+ if (strcmp (mon, "set debug 1") == 0)
+ {
+ debug_threads = 1;
+ monitor_output ("Debug output enabled.\n");
+ }
+ else if (strcmp (mon, "set debug 0") == 0)
+ {
+ debug_threads = 0;
+ monitor_output ("Debug output disabled.\n");
+ }
+ else if (strcmp (mon, "set debug-hw-points 1") == 0)
+ {
+ debug_hw_points = 1;
+ monitor_output ("H/W point debugging output enabled.\n");
+ }
+ else if (strcmp (mon, "set debug-hw-points 0") == 0)
+ {
+ debug_hw_points = 0;
+ monitor_output ("H/W point debugging output disabled.\n");
+ }
+ else if (strcmp (mon, "set remote-debug 1") == 0)
+ {
+ remote_debug = 1;
+ monitor_output ("Protocol debug output enabled.\n");
+ }
+ else if (strcmp (mon, "set remote-debug 0") == 0)
+ {
+ remote_debug = 0;
+ monitor_output ("Protocol debug output disabled.\n");
+ }
+ else if (strcmp (mon, "help") == 0)
+ monitor_show_help ();
+ else if (strcmp (mon, "exit") == 0)
+ exit_requested = 1;
+ else
+ {
+ monitor_output ("Unknown monitor command.\n\n");
+ monitor_show_help ();
+ write_enn (own_buf);
+ }
+}
+
/* Handle all of the extended 'q' packets. */
void
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
@@ -1211,46 +1258,10 @@ handle_query (char *own_buf, int packet_
write_ok (own_buf);
- if (strcmp (mon, "set debug 1") == 0)
- {
- debug_threads = 1;
- monitor_output ("Debug output enabled.\n");
- }
- else if (strcmp (mon, "set debug 0") == 0)
- {
- debug_threads = 0;
- monitor_output ("Debug output disabled.\n");
- }
- else if (strcmp (mon, "set debug-hw-points 1") == 0)
- {
- debug_hw_points = 1;
- monitor_output ("H/W point debugging output enabled.\n");
- }
- else if (strcmp (mon, "set debug-hw-points 0") == 0)
- {
- debug_hw_points = 0;
- monitor_output ("H/W point debugging output disabled.\n");
- }
- else if (strcmp (mon, "set remote-debug 1") == 0)
- {
- remote_debug = 1;
- monitor_output ("Protocol debug output enabled.\n");
- }
- else if (strcmp (mon, "set remote-debug 0") == 0)
- {
- remote_debug = 0;
- monitor_output ("Protocol debug output disabled.\n");
- }
- else if (strcmp (mon, "help") == 0)
- monitor_show_help ();
- else if (strcmp (mon, "exit") == 0)
- exit_requested = 1;
- else
- {
- monitor_output ("Unknown monitor command.\n\n");
- monitor_show_help ();
- write_enn (own_buf);
- }
+ if (the_target->handle_monitor_command == NULL
+ || (*the_target->handle_monitor_command) (mon) == 0)
+ /* Default processing. */
+ handle_monitor_command (mon);
free (mon);
return;
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.39
diff -u -p -u -r1.39 target.h
--- gdbserver/target.h 25 Jun 2009 22:13:53 -0000 1.39
+++ gdbserver/target.h 7 Oct 2009 00:09:37 -0000
@@ -279,6 +279,10 @@ struct target_ops
/* Returns true if the target supports multi-process debugging. */
int (*supports_multi_process) (void);
+
+ /* If not NULL, target-specific routine to process monitor command.
+ Returns 1 if handled, or 0 to perform default processing. */
+ int (*handle_monitor_command) (char *);
};
extern struct target_ops *the_target;
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 7 Oct 2009 00:09:37 -0000
@@ -27,13 +27,51 @@ extern int debug_threads;
static int thread_db_use_events;
-#ifdef HAVE_THREAD_DB_H
-#include <thread_db.h>
-#endif
-
#include "gdb_proc_service.h"
+#include "../gdb_thread_db.h"
+#include <dlfcn.h>
#include <stdint.h>
+#include <limits.h>
+#include <ctype.h>
+
+struct thread_db
+{
+ /* Structure that identifies the child process for the
+ <proc_service.h> interface. */
+ struct ps_prochandle proc_handle;
+
+ /* Connection to the libthread_db library. */
+ td_thragent_t *thread_agent;
+
+ /* Handle of the libthread_db from dlopen. */
+ void *handle;
+
+ /* Addresses of libthread_db functions. */
+ td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
+ td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
+ td_event_msg_t *msg);
+ td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
+ td_thr_events_t *event);
+ td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
+ td_event_e event, td_notify_t *ptr);
+ td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid,
+ td_thrhandle_t *th);
+ td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
+ td_thrinfo_t *infop);
+ td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event);
+ 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);
+ td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
+ void *map_address,
+ size_t offset, void **address);
+ const char ** (*td_symbol_list_p) (void);
+};
+
+static 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);
@@ -130,7 +168,11 @@ thread_db_create_event (CORE_ADDR where)
td_event_msg_t msg;
td_err_e err;
struct lwp_info *lwp;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+
+ if (thread_db->td_ta_event_getmsg_p == NULL)
+ /* We shouldn't have ever be here in the first place. */
+ return TD_ERR;
if (debug_threads)
fprintf (stderr, "Thread creation event.\n");
@@ -139,7 +181,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 = thread_db->td_ta_event_getmsg_p (thread_db->thread_agent, &msg);
if (err != TD_OK)
fprintf (stderr, "thread getmsg err: %s\n",
thread_db_err_str (err));
@@ -158,36 +200,25 @@ thread_db_create_event (CORE_ADDR where)
return 0;
}
-#if 0
-static int
-thread_db_death_event (CORE_ADDR where)
-{
- if (debug_threads)
- fprintf (stderr, "Thread death event.\n");
-
- return 0;
-}
-#endif
-
static int
thread_db_enable_reporting ()
{
td_thr_events_t events;
td_notify_t notify;
td_err_e err;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+
+ if (thread_db->td_ta_set_event_p == NULL
+ || thread_db->td_ta_event_addr_p == NULL
+ || thread_db->td_ta_event_getmsg_p == NULL)
+ /* This libthread_db is missing required support. */
+ return TD_ERR;
/* Set the process wide mask saying which events we're interested in. */
td_event_emptyset (&events);
td_event_addset (&events, TD_CREATE);
-#if 0
- /* This is reported to be broken in glibc 2.1.3. A different approach
- will be necessary to support that. */
- td_event_addset (&events, TD_DEATH);
-#endif
-
- err = td_ta_set_event (proc->thread_agent, &events);
+ err = thread_db->td_ta_set_event_p (thread_db->thread_agent, &events);
if (err != TD_OK)
{
warning ("Unable to set global thread event mask: %s",
@@ -196,7 +227,8 @@ thread_db_enable_reporting ()
}
/* Get address for thread creation breakpoint. */
- err = td_ta_event_addr (proc->thread_agent, TD_CREATE, ¬ify);
+ err = thread_db->td_ta_event_addr_p (thread_db->thread_agent, TD_CREATE,
+ ¬ify);
if (err != TD_OK)
{
warning ("Unable to get location for thread creation breakpoint: %s",
@@ -206,22 +238,6 @@ thread_db_enable_reporting ()
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
thread_db_create_event);
-#if 0
- /* Don't concern ourselves with reported thread deaths, only
- with actual thread deaths (via wait). */
-
- /* Get address for thread death breakpoint. */
- err = td_ta_event_addr (proc->thread_agent, TD_DEATH, ¬ify);
- if (err != TD_OK)
- {
- warning ("Unable to get location for thread death breakpoint: %s",
- thread_db_err_str (err));
- return;
- }
- set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
- thread_db_death_event);
-#endif
-
return 1;
}
@@ -233,7 +249,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 thread_db *thread_db = current_process ()->private->thread_db;
int lwpid = ptid_get_lwp (ptid);
inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
@@ -242,13 +258,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 = thread_db->td_ta_map_lwp2thr_p (thread_db->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 = thread_db->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 +281,7 @@ find_one_thread (ptid_t ptid)
if (thread_db_use_events)
{
- err = td_thr_event_enable (&th, 1);
+ err = thread_db->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 +325,8 @@ maybe_attach_thread (const td_thrhandle_
if (thread_db_use_events)
{
- err = td_thr_event_enable (th_p, 1);
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+ err = thread_db->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));
@@ -322,8 +338,9 @@ find_new_threads_callback (const td_thrh
{
td_thrinfo_t ti;
td_err_e err;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
- err = td_thr_get_info (th_p, &ti);
+ err = thread_db->td_thr_get_info_p (th_p, &ti);
if (err != TD_OK)
error ("Cannot get thread info: %s", thread_db_err_str (err));
@@ -341,7 +358,7 @@ thread_db_find_new_threads (void)
{
td_err_e err;
ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
/* This function is only called when we first initialize thread_db.
First locate the initial thread. If it is not ready for
@@ -350,10 +367,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 = thread_db->td_ta_thr_iter_p (thread_db->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 +383,11 @@ thread_db_find_new_threads (void)
static void
thread_db_look_up_symbols (void)
{
- const char **sym_list = td_symbol_list ();
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+ const char **sym_list;
CORE_ADDR unused;
- for (sym_list = td_symbol_list (); *sym_list; sym_list++)
+ for (sym_list = thread_db->td_symbol_list_p (); *sym_list; sym_list++)
look_up_one_symbol (*sym_list, &unused);
}
@@ -377,16 +395,23 @@ int
thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
CORE_ADDR load_module, CORE_ADDR *address)
{
-#if HAVE_TD_THR_TLS_GET_ADDR
psaddr_t addr;
td_err_e err;
struct lwp_info *lwp;
struct thread_info *saved_inferior;
+ struct process_info *proc;
+ struct thread_db *thread_db;
+
+ proc = get_thread_process (thread);
+ thread_db = proc->private->thread_db;
/* If the thread layer is not (yet) initialized, fail. */
- if (!get_thread_process (thread)->all_symbols_looked_up)
+ if (!proc->all_symbols_looked_up)
return TD_ERR;
+ if (thread_db->td_thr_tls_get_addr_p == NULL)
+ return -1;
+
lwp = get_thread_lwp (thread);
if (!lwp->thread_known)
find_one_thread (lwp->head.id);
@@ -398,8 +423,9 @@ 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 = thread_db->td_thr_tls_get_addr_p (&lwp->th,
+ (psaddr_t) (uintptr_t) load_module,
+ offset, &addr);
current_inferior = saved_inferior;
if (err == TD_OK)
{
@@ -408,17 +434,195 @@ thread_db_get_tls_address (struct thread
}
else
return err;
-#else
- return -1;
-#endif
+}
+
+static int
+try_thread_db_load_1 (void *handle)
+{
+ td_err_e err;
+ struct thread_db tdb;
+ struct process_info *proc = current_process ();
+
+ if (proc->private->thread_db != NULL)
+ {
+ fprintf (stderr, "Internal error: thread_db != NULL in %s:%d\n",
+ __FILE__, __LINE__);
+ return 0;
+ }
+
+ tdb.handle = handle;
+
+ /* Initialize pointers to the dynamic library functions we will use.
+ Essential functions first. */
+
+#define CHK(required, a) \
+ do \
+ { \
+ if ((a) == NULL) \
+ { \
+ if (debug_threads) \
+ fprintf (stderr, "dlsym: %s\n", dlerror ()); \
+ if (required) \
+ return 0; \
+ } \
+ } \
+ while (0)
+
+ CHK (1, tdb.td_ta_new_p = dlsym (handle, "td_ta_new"));
+
+ /* Attempt to open a connection to the thread library. */
+ err = tdb.td_ta_new_p (&tdb.proc_handle, &tdb.thread_agent);
+ if (err != TD_OK)
+ {
+ if (debug_threads)
+ fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
+ return 0;
+ }
+
+ CHK (1, tdb.td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr"));
+ CHK (1, tdb.td_thr_get_info_p = dlsym (handle, "td_thr_get_info"));
+ CHK (1, tdb.td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter"));
+ CHK (1, tdb.td_symbol_list_p = dlsym (handle, "td_symbol_list"));
+
+ /* This is required only when thread_db_use_events is on. */
+ CHK (thread_db_use_events,
+ tdb.td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"));
+
+ /* These are not essential. */
+ CHK (0, tdb.td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"));
+ CHK (0, tdb.td_ta_set_event_p = dlsym (handle, "td_ta_set_event"));
+ CHK (0, tdb.td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"));
+ CHK (0, tdb.td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"));
+
+#undef CHK
+
+ proc->private->thread_db = malloc (sizeof (tdb));
+ memcpy (proc->private->thread_db, &tdb, sizeof (tdb));
+
+ 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 (void)
+{
+ 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,27 +637,64 @@ 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;
+}
+
+/* Disconnect from libthread_db and free resources. */
+
+void
+thread_db_free (struct process_info *proc)
+{
+ struct thread_db *thread_db = proc->private->thread_db;
+ if (thread_db)
+ {
+ td_err_e (*td_ta_delete_p) (td_thragent_t *);
+
+ td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete");
+ if (td_ta_delete_p != NULL)
+ (*td_ta_delete_p) (thread_db->thread_agent);
+
+ dlclose (thread_db->handle);
+ free (thread_db);
+ proc->private->thread_db = NULL;
+ }
+}
+
+/* Handle "set libthread-db-search-path" monitor command and return 1.
+ For any other command, return 0. */
+
+int
+thread_db_handle_monitor_command (char *mon)
+{
+ if (strncmp (mon, "set libthread-db-search-path ", 29) == 0)
+ {
+ const char *cp = mon + 29;
+
+ 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");
+ return 1;
}
+ /* Tell server.c to perform default processing. */
return 0;
}
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-07 0:27 ` Paul Pluzhnikov
@ 2009-10-08 18:08 ` Pedro Alves
2009-10-08 19:05 ` Daniel Jacobowitz
2009-10-08 19:36 ` Paul Pluzhnikov
0 siblings, 2 replies; 25+ messages in thread
From: Pedro Alves @ 2009-10-08 18:08 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: gdb-patches, dje
On Wednesday 07 October 2009 01:26:58, Paul Pluzhnikov wrote:
> doc/
> 2009-10-06 Paul Pluzhnikov <ppluzhnikov@google.com>
>
> * gdb.texinfo (Server): Document libthread-db-search-path.
>
> gdbserver/
> 2009-10-06 Paul Pluzhnikov <ppluzhnikov@google.com>
>
>
> * acinclude.m4: (SRV_CHECK_THREAD_DB, SRV_CHECK_TLS_GET_ADDR): Remove.
> * configure.ac: Adjust.
> * linux-low.h (struct process_info_private): Move members to struct
> thread_db.
> (thread_db_free): New prototype.
> * linux-low.c (linux_remove_process): Adjust.
> (linux_wait_for_event_1, linux_look_up_symbols): Likewise.
> * server.c (handle_query): Move code ...
> (handle_monitor_command): ... here. New function.
> * target.h (struct target_ops): New member.
> * thread-db.c (struct thread_db): New.
> (libthread_db_search_path): New variable.
> (thread_db_create_event, thread_db_enable_reporting)
> (find_one_thread, maybe_attach_thread, find_new_threads_callback)
> (thread_db_find_new_threads, (thread_db_get_tls_address): Adjust.
> (try_thread_db_load_1, dladdr_to_soname): New functions.
> (try_thread_db_load, thread_db_load_search): New functions.
> (thread_db_init): Search for libthread_db.
> (thread_db_free): New function.
> (thread_db_handle_monitor_command): Likewise.
'* configure: Regenerate.' or so is missing. Please always
add that to the changelog even if not posting the regenerated
files.
(Opinions diverge on whether or not to include regenerated files in
patch submissions. Personaly, I prefer them to be included,
as it makes it easier for someone else to try the patch, and
makes it easy to spot if the contributer is using the correct
versions of the autotools. When I include them in my patches, I
tend to put the regenerated files hunk as last hunks in
the patch, so that they don't make review any harder.)
> Index: gdbserver/linux-low.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
> retrieving revision 1.112
> diff -u -p -u -r1.112 linux-low.c
> --- gdbserver/linux-low.c 31 Jul 2009 15:25:22 -0000 1.112
> +++ gdbserver/linux-low.c 7 Oct 2009 00:09:37 -0000
> @@ -42,6 +42,7 @@
> #include <dirent.h>
> #include <sys/stat.h>
> #include <sys/vfs.h>
> +#include <dlfcn.h>
This shouldn't be needed anymore here.
>
> #ifndef SPUFS_MAGIC
> #define SPUFS_MAGIC 0x23c9b64e
> @@ -118,6 +119,11 @@ int stopping_threads;
> /* FIXME make into a target method? */
> int using_threads = 1;
>
> +#ifdef USE_THREAD_DB
> +/* From thread-db.c */
> +extern int thread_db_handle_monitor_command (char *);
> +#endif
This can go to linux-low.h unconditionally, next to...
>
> int thread_db_init (int use_events);
> +void thread_db_free (struct process_info *);
> int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
> CORE_ADDR load_module, CORE_ADDR *address);
... these.
> +
> /* This flag is true iff we've just created or attached to our first
> inferior but it has not stopped yet. As soon as it does, we need
> to call the low target's arch_setup callback. Doing this only on
> @@ -261,8 +267,11 @@ linux_add_process (int pid, int attached
> static void
> linux_remove_process (struct process_info *process)
> {
> - free (process->private->arch_private);
> - free (process->private);
> + struct process_info_private *priv = process->private;
> +
> + thread_db_free (process);
> + free (priv->arch_private);
> + free (priv);
> remove_process (process);
> }
That thread_db_free call should be wrapped in USE_THREAD_DB.
> +static 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);
> @@ -130,7 +168,11 @@ thread_db_create_event (CORE_ADDR where)
> td_event_msg_t msg;
> td_err_e err;
> struct lwp_info *lwp;
> - struct process_info_private *proc = current_process()->private;
> + struct thread_db *thread_db = current_process ()->private->thread_db;
> +
> + if (thread_db->td_ta_event_getmsg_p == NULL)
> + /* We shouldn't have ever be here in the first place. */
> + return TD_ERR;
Is this necessary? Looks like dead code. It would be a bad
programming error to reach here with thread_db->td_ta_event_getmsg_p it
seems. If we had gdb_assert or internal_error it would be more
appropriate here. We have `fatal' though. Until someone adds
an internal_error to gdbserver, I think a `fatal' here would be
better. Or just nothing at all.
> +static int
> +try_thread_db_load_1 (void *handle)
> +{
> + td_err_e err;
> + struct thread_db tdb;
> + struct process_info *proc = current_process ();
> +
> + if (proc->private->thread_db != NULL)
> + {
> + fprintf (stderr, "Internal error: thread_db != NULL in %s:%d\n",
> + __FILE__, __LINE__);
> + return 0;
> + }
> +
Odd. Did you ever actually see this happen? Same comment
about internal errors applies here.
> +
> + proc->private->thread_db = malloc (sizeof (tdb));
xmalloc.
> +static int
> +thread_db_load_search (void)
> +{
> + char path[PATH_MAX];
> + const char *search_path;
> + int rc = 0;
> +
> +
One blank line too much.
> + 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;
> }
Please fix tabs vs spaces issues in this function. I
noticed similar issues in try_thread_db_load as well.
>
> 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,27 +637,64 @@ 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;
I notice that this return 0 here meant that
linux-low.c:linux_look_up_symbols still retry thread_db_init,
and that after your patch it won't. I'm inclined to think this
was a buglet and that following thread_db_init retries
wouldn't work anyway. Do you agree, or is this something
that we still need to keep addressing?
> 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;
> +}
> +
Other than that, this looks OK to me.
--
Pedro Alves
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-08 18:08 ` Pedro Alves
@ 2009-10-08 19:05 ` Daniel Jacobowitz
2009-10-08 19:21 ` Paul Pluzhnikov
2009-10-08 19:36 ` Paul Pluzhnikov
1 sibling, 1 reply; 25+ messages in thread
From: Daniel Jacobowitz @ 2009-10-08 19:05 UTC (permalink / raw)
To: Pedro Alves; +Cc: Paul Pluzhnikov, gdb-patches, dje
On Thu, Oct 08, 2009 at 07:06:37PM +0100, Pedro Alves wrote:
> Other than that, this looks OK to me.
Hi folks,
I realize I've really missed the boat on this, but I'll be sad to see
this go. You used to be able to use gdbserver without a working libdl
- and even a statically linked gdbserver could debug threaded programs
without working dynamic linking at all. I've used this for board
bringup for years.
How horrid would it be to support both modes of operation?
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-08 19:05 ` Daniel Jacobowitz
@ 2009-10-08 19:21 ` Paul Pluzhnikov
2009-10-08 19:42 ` Daniel Jacobowitz
0 siblings, 1 reply; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-08 19:21 UTC (permalink / raw)
To: Pedro Alves, Paul Pluzhnikov, gdb-patches, dje
On Thu, Oct 8, 2009 at 12:05 PM, Daniel Jacobowitz <drow@false.org> wrote:
> How horrid would it be to support both modes of operation?
I think this can be done fairly easily via configure option.
I would prefer to do it as a follow-up patch though.
Would that be ok?
Thanks,
--
Paul Pluzhnikov
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-08 18:08 ` Pedro Alves
2009-10-08 19:05 ` Daniel Jacobowitz
@ 2009-10-08 19:36 ` Paul Pluzhnikov
2009-10-08 22:58 ` Pedro Alves
1 sibling, 1 reply; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-08 19:36 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, dje
[-- Attachment #1: Type: text/plain, Size: 2566 bytes --]
On Thu, Oct 8, 2009 at 11:06 AM, Pedro Alves <pedro@codesourcery.com> wrote:
> '* configure: Regenerate.' or so is missing. Please always
> add that to the changelog even if not posting the regenerated
> files.
Ok.
I believe attached patch fixes all your comments.
> I notice that this return 0 here meant that
> linux-low.c:linux_look_up_symbols still retry thread_db_init,
> and that after your patch it won't. I'm inclined to think this
> was a buglet and that following thread_db_init retries
> wouldn't work anyway. Do you agree, or is this something
> that we still need to keep addressing?
Thanks for noticing this. Looking closer I discovered a buglet in
thread_db_enable_reporting -- it shouldn't return TD_ERR (== 1) here:
if (thread_db->td_ta_set_event_p == NULL
|| thread_db->td_ta_event_addr_p == NULL
|| thread_db->td_ta_event_getmsg_p == NULL)
/* This libthread_db is missing required support. */
return TD_ERR;
Fixed.
I think it's theoretically possible for thread_db_enable_reporting to fail
early in the inferior lifetime, and start working later; so I fixed this
part and linux_look_up_symbols will now keep retrying.
Re-tested on Linux/x86_64.
Thanks,
--
Paul Pluzhnikov
doc/
2009-10-08 Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.texinfo (Server): Document libthread-db-search-path.
gdbserver/
2009-10-08 Paul Pluzhnikov <ppluzhnikov@google.com>
* acinclude.m4: (SRV_CHECK_THREAD_DB, SRV_CHECK_TLS_GET_ADDR): Remove.
* configure.ac: Adjust.
* linux-low.h (struct process_info_private): Move members to struct
thread_db.
(thread_db_free, thread_db_handle_monitor_command): New prototype.
* linux-low.c (linux_remove_process): Adjust.
(linux_wait_for_event_1, linux_look_up_symbols): Likewise.
* server.c (handle_query): Move code ...
(handle_monitor_command): ... here. New function.
* target.h (struct target_ops): New member.
* thread-db.c (struct thread_db): New.
(libthread_db_search_path): New variable.
(thread_db_create_event, thread_db_enable_reporting)
(find_one_thread, maybe_attach_thread, find_new_threads_callback)
(thread_db_find_new_threads, (thread_db_get_tls_address): Adjust.
(try_thread_db_load_1, dladdr_to_soname): New functions.
(try_thread_db_load, thread_db_load_search): New functions.
(thread_db_init): Search for libthread_db.
(thread_db_free): New function.
(thread_db_handle_monitor_command): Likewise.
* config.in: Regenerate.
* configure: Regenerate.
[-- Attachment #2: gdb-gdbserver-threaddb-search-20091008.txt --]
[-- Type: text/plain, Size: 34020 bytes --]
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.631
diff -u -p -u -r1.631 gdb.texinfo
--- doc/gdb.texinfo 6 Oct 2009 18:02:36 -0000 1.631
+++ doc/gdb.texinfo 8 Oct 2009 19:14:25 -0000
@@ -14903,6 +14903,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 8 Oct 2009 19:14:25 -0000
@@ -7,63 +7,3 @@ sinclude(../../config/override.m4)
dnl For ACX_PKGVERSION and ACX_BUGURL.
sinclude(../../config/acx.m4)
-AC_DEFUN([SRV_CHECK_THREAD_DB],
-[AC_CACHE_CHECK([for libthread_db],[srv_cv_thread_db],
- [old_LIBS="$LIBS"
- LIBS="$LIBS -lthread_db"
- AC_TRY_LINK(
- [void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}],
- [td_ta_new();],
- [srv_cv_thread_db="-lthread_db"],
- [srv_cv_thread_db=no
-
- if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
- thread_db="/lib/libthread_db.so.1"
- else
- thread_db='$prefix/lib/libthread_db.so.1'
- fi
- LIBS="$old_LIBS `eval echo "$thread_db"`"
- AC_TRY_LINK(
- [void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}],
- [td_ta_new();],
- [srv_cv_thread_db="$thread_db"],
- [srv_cv_thread_db=no])
- ])
- LIBS="$old_LIBS"
-])])
-
-AC_DEFUN([SRV_CHECK_TLS_GET_ADDR],
-[AC_CACHE_CHECK([for thread_db_tls_get_addr],[srv_cv_tls_get_addr],
- [old_LIBS="$LIBS"
- LIBS="$LIBS $srv_cv_thread_db"
- AC_TRY_LINK(
- [void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}],
- [td_thr_tls_get_addr();],
- [srv_cv_tls_get_addr=yes],
- [srv_cv_tls_get_addr=no])
- LIBS="$old_LIBS"
-])])
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 8 Oct 2009 19:14:25 -0000
@@ -140,23 +140,13 @@ srv_libs=
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.])
- srv_linux_thread_db=no
- else
- srv_libs="$srv_cv_thread_db"
- SRV_CHECK_TLS_GET_ADDR
- fi
+ srv_libs="-ldl"
old_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -rdynamic"
AC_TRY_LINK([], [], [RDYNAMIC=-rdynamic], [RDYNAMIC=])
AC_SUBST(RDYNAMIC)
LDFLAGS="$old_LDFLAGS"
-fi
-if test "$srv_linux_thread_db" = "yes"; then
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,
@@ -166,10 +156,6 @@ if test "$srv_linux_thread_db" = "yes";
if test $gdbsrv_cv_have_td_version = yes; then
AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.])
fi
-
- if test "$srv_cv_tls_get_addr" = yes; then
- AC_DEFINE(HAVE_TD_THR_TLS_GET_ADDR, 1, [Define if td_thr_tls_get_addr is available.])
- fi
fi
if test "$srv_xmlfiles" != ""; then
Index: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.112
diff -u -p -u -r1.112 linux-low.c
--- gdbserver/linux-low.c 31 Jul 2009 15:25:22 -0000 1.112
+++ gdbserver/linux-low.c 8 Oct 2009 19:14:25 -0000
@@ -261,8 +261,14 @@ linux_add_process (int pid, int attached
static void
linux_remove_process (struct process_info *process)
{
- free (process->private->arch_private);
- free (process->private);
+ struct process_info_private *priv = process->private;
+
+#ifdef USE_THREAD_DB
+ thread_db_free (process);
+#endif
+
+ free (priv->arch_private);
+ free (priv);
remove_process (process);
}
@@ -1122,7 +1128,7 @@ linux_wait_for_event_1 (ptid_t ptid, int
&& !event_child->stepping
&& (
#ifdef USE_THREAD_DB
- (current_process ()->private->thread_db_active
+ (current_process ()->private->thread_db != NULL
&& (WSTOPSIG (*wstat) == __SIGRTMIN
|| WSTOPSIG (*wstat) == __SIGRTMIN + 1))
||
@@ -2642,11 +2648,10 @@ linux_look_up_symbols (void)
#ifdef USE_THREAD_DB
struct process_info *proc = current_process ();
- if (proc->private->thread_db_active)
+ if (proc->private->thread_db != NULL)
return;
- proc->private->thread_db_active
- = thread_db_init (!linux_supports_tracefork_flag);
+ thread_db_init (!linux_supports_tracefork_flag);
#endif
}
@@ -3171,7 +3176,12 @@ static struct target_ops linux_target_op
linux_supports_non_stop,
linux_async,
linux_start_non_stop,
- linux_supports_multi_process
+ linux_supports_multi_process,
+#ifdef USE_THREAD_DB
+ thread_db_handle_monitor_command
+#else
+ NULL
+#endif
};
static void
Index: gdbserver/linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.32
diff -u -p -u -r1.32 linux-low.h
--- gdbserver/linux-low.h 30 Jun 2009 16:35:25 -0000 1.32
+++ gdbserver/linux-low.h 8 Oct 2009 19:14:25 -0000
@@ -47,18 +47,12 @@ struct siginfo;
struct process_info_private
{
- /* True if this process has loaded thread_db, and it is active. */
- int thread_db_active;
-
- /* Structure that identifies the child process for the
- <proc_service.h> interface. */
- struct ps_prochandle proc_handle;
-
- /* Connection to the libthread_db library. */
- td_thragent_t *thread_agent;
-
/* Arch-specific additions. */
struct arch_process_info *arch_private;
+
+ /* libthread_db-specific additions. Not NULL if this process has loaded
+ thread_db, and it is active. */
+ struct thread_db *thread_db;
};
struct lwp_info;
@@ -203,9 +197,11 @@ char *linux_child_pid_to_exec_file (int
int elf_64_file_p (const char *file);
void linux_attach_lwp (unsigned long pid);
+struct lwp_info *find_lwp_pid (ptid_t ptid);
+/* From thread-db.c */
int thread_db_init (int use_events);
+void thread_db_free (struct process_info *);
+int thread_db_handle_monitor_command (char *);
int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
CORE_ADDR load_module, CORE_ADDR *address);
-
-struct lwp_info *find_lwp_pid (ptid_t ptid);
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 8 Oct 2009 19:14:25 -0000
@@ -660,6 +660,53 @@ handle_search_memory (char *own_buf, int
return; \
}
+/* Handle monitor commands not handled by target-specific handlers. */
+
+static void
+handle_monitor_command (char *mon)
+{
+ if (strcmp (mon, "set debug 1") == 0)
+ {
+ debug_threads = 1;
+ monitor_output ("Debug output enabled.\n");
+ }
+ else if (strcmp (mon, "set debug 0") == 0)
+ {
+ debug_threads = 0;
+ monitor_output ("Debug output disabled.\n");
+ }
+ else if (strcmp (mon, "set debug-hw-points 1") == 0)
+ {
+ debug_hw_points = 1;
+ monitor_output ("H/W point debugging output enabled.\n");
+ }
+ else if (strcmp (mon, "set debug-hw-points 0") == 0)
+ {
+ debug_hw_points = 0;
+ monitor_output ("H/W point debugging output disabled.\n");
+ }
+ else if (strcmp (mon, "set remote-debug 1") == 0)
+ {
+ remote_debug = 1;
+ monitor_output ("Protocol debug output enabled.\n");
+ }
+ else if (strcmp (mon, "set remote-debug 0") == 0)
+ {
+ remote_debug = 0;
+ monitor_output ("Protocol debug output disabled.\n");
+ }
+ else if (strcmp (mon, "help") == 0)
+ monitor_show_help ();
+ else if (strcmp (mon, "exit") == 0)
+ exit_requested = 1;
+ else
+ {
+ monitor_output ("Unknown monitor command.\n\n");
+ monitor_show_help ();
+ write_enn (own_buf);
+ }
+}
+
/* Handle all of the extended 'q' packets. */
void
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
@@ -1211,46 +1258,10 @@ handle_query (char *own_buf, int packet_
write_ok (own_buf);
- if (strcmp (mon, "set debug 1") == 0)
- {
- debug_threads = 1;
- monitor_output ("Debug output enabled.\n");
- }
- else if (strcmp (mon, "set debug 0") == 0)
- {
- debug_threads = 0;
- monitor_output ("Debug output disabled.\n");
- }
- else if (strcmp (mon, "set debug-hw-points 1") == 0)
- {
- debug_hw_points = 1;
- monitor_output ("H/W point debugging output enabled.\n");
- }
- else if (strcmp (mon, "set debug-hw-points 0") == 0)
- {
- debug_hw_points = 0;
- monitor_output ("H/W point debugging output disabled.\n");
- }
- else if (strcmp (mon, "set remote-debug 1") == 0)
- {
- remote_debug = 1;
- monitor_output ("Protocol debug output enabled.\n");
- }
- else if (strcmp (mon, "set remote-debug 0") == 0)
- {
- remote_debug = 0;
- monitor_output ("Protocol debug output disabled.\n");
- }
- else if (strcmp (mon, "help") == 0)
- monitor_show_help ();
- else if (strcmp (mon, "exit") == 0)
- exit_requested = 1;
- else
- {
- monitor_output ("Unknown monitor command.\n\n");
- monitor_show_help ();
- write_enn (own_buf);
- }
+ if (the_target->handle_monitor_command == NULL
+ || (*the_target->handle_monitor_command) (mon) == 0)
+ /* Default processing. */
+ handle_monitor_command (mon);
free (mon);
return;
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.39
diff -u -p -u -r1.39 target.h
--- gdbserver/target.h 25 Jun 2009 22:13:53 -0000 1.39
+++ gdbserver/target.h 8 Oct 2009 19:14:25 -0000
@@ -279,6 +279,10 @@ struct target_ops
/* Returns true if the target supports multi-process debugging. */
int (*supports_multi_process) (void);
+
+ /* If not NULL, target-specific routine to process monitor command.
+ Returns 1 if handled, or 0 to perform default processing. */
+ int (*handle_monitor_command) (char *);
};
extern struct target_ops *the_target;
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 8 Oct 2009 19:14:25 -0000
@@ -27,13 +27,51 @@ extern int debug_threads;
static int thread_db_use_events;
-#ifdef HAVE_THREAD_DB_H
-#include <thread_db.h>
-#endif
-
#include "gdb_proc_service.h"
+#include "../gdb_thread_db.h"
+#include <dlfcn.h>
#include <stdint.h>
+#include <limits.h>
+#include <ctype.h>
+
+struct thread_db
+{
+ /* Structure that identifies the child process for the
+ <proc_service.h> interface. */
+ struct ps_prochandle proc_handle;
+
+ /* Connection to the libthread_db library. */
+ td_thragent_t *thread_agent;
+
+ /* Handle of the libthread_db from dlopen. */
+ void *handle;
+
+ /* Addresses of libthread_db functions. */
+ td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
+ td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
+ td_event_msg_t *msg);
+ td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
+ td_thr_events_t *event);
+ td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
+ td_event_e event, td_notify_t *ptr);
+ td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid,
+ td_thrhandle_t *th);
+ td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
+ td_thrinfo_t *infop);
+ td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event);
+ 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);
+ td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
+ void *map_address,
+ size_t offset, void **address);
+ const char ** (*td_symbol_list_p) (void);
+};
+
+static 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);
@@ -130,7 +168,10 @@ thread_db_create_event (CORE_ADDR where)
td_event_msg_t msg;
td_err_e err;
struct lwp_info *lwp;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+
+ if (thread_db->td_ta_event_getmsg_p == NULL)
+ fatal ("unexpected thread_db->td_ta_event_getmsg_p == NULL");
if (debug_threads)
fprintf (stderr, "Thread creation event.\n");
@@ -139,7 +180,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 = thread_db->td_ta_event_getmsg_p (thread_db->thread_agent, &msg);
if (err != TD_OK)
fprintf (stderr, "thread getmsg err: %s\n",
thread_db_err_str (err));
@@ -158,36 +199,25 @@ thread_db_create_event (CORE_ADDR where)
return 0;
}
-#if 0
-static int
-thread_db_death_event (CORE_ADDR where)
-{
- if (debug_threads)
- fprintf (stderr, "Thread death event.\n");
-
- return 0;
-}
-#endif
-
static int
thread_db_enable_reporting ()
{
td_thr_events_t events;
td_notify_t notify;
td_err_e err;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+
+ if (thread_db->td_ta_set_event_p == NULL
+ || thread_db->td_ta_event_addr_p == NULL
+ || thread_db->td_ta_event_getmsg_p == NULL)
+ /* This libthread_db is missing required support. */
+ return 0;
/* Set the process wide mask saying which events we're interested in. */
td_event_emptyset (&events);
td_event_addset (&events, TD_CREATE);
-#if 0
- /* This is reported to be broken in glibc 2.1.3. A different approach
- will be necessary to support that. */
- td_event_addset (&events, TD_DEATH);
-#endif
-
- err = td_ta_set_event (proc->thread_agent, &events);
+ err = thread_db->td_ta_set_event_p (thread_db->thread_agent, &events);
if (err != TD_OK)
{
warning ("Unable to set global thread event mask: %s",
@@ -196,7 +226,8 @@ thread_db_enable_reporting ()
}
/* Get address for thread creation breakpoint. */
- err = td_ta_event_addr (proc->thread_agent, TD_CREATE, ¬ify);
+ err = thread_db->td_ta_event_addr_p (thread_db->thread_agent, TD_CREATE,
+ ¬ify);
if (err != TD_OK)
{
warning ("Unable to get location for thread creation breakpoint: %s",
@@ -206,22 +237,6 @@ thread_db_enable_reporting ()
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
thread_db_create_event);
-#if 0
- /* Don't concern ourselves with reported thread deaths, only
- with actual thread deaths (via wait). */
-
- /* Get address for thread death breakpoint. */
- err = td_ta_event_addr (proc->thread_agent, TD_DEATH, ¬ify);
- if (err != TD_OK)
- {
- warning ("Unable to get location for thread death breakpoint: %s",
- thread_db_err_str (err));
- return;
- }
- set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
- thread_db_death_event);
-#endif
-
return 1;
}
@@ -233,7 +248,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 thread_db *thread_db = current_process ()->private->thread_db;
int lwpid = ptid_get_lwp (ptid);
inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
@@ -242,13 +257,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 = thread_db->td_ta_map_lwp2thr_p (thread_db->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 = thread_db->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 +280,7 @@ find_one_thread (ptid_t ptid)
if (thread_db_use_events)
{
- err = td_thr_event_enable (&th, 1);
+ err = thread_db->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 +324,8 @@ maybe_attach_thread (const td_thrhandle_
if (thread_db_use_events)
{
- err = td_thr_event_enable (th_p, 1);
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+ err = thread_db->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));
@@ -322,8 +337,9 @@ find_new_threads_callback (const td_thrh
{
td_thrinfo_t ti;
td_err_e err;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
- err = td_thr_get_info (th_p, &ti);
+ err = thread_db->td_thr_get_info_p (th_p, &ti);
if (err != TD_OK)
error ("Cannot get thread info: %s", thread_db_err_str (err));
@@ -341,7 +357,7 @@ thread_db_find_new_threads (void)
{
td_err_e err;
ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id;
- struct process_info_private *proc = current_process()->private;
+ struct thread_db *thread_db = current_process ()->private->thread_db;
/* This function is only called when we first initialize thread_db.
First locate the initial thread. If it is not ready for
@@ -350,10 +366,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 = thread_db->td_ta_thr_iter_p (thread_db->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 +382,11 @@ thread_db_find_new_threads (void)
static void
thread_db_look_up_symbols (void)
{
- const char **sym_list = td_symbol_list ();
+ struct thread_db *thread_db = current_process ()->private->thread_db;
+ const char **sym_list;
CORE_ADDR unused;
- for (sym_list = td_symbol_list (); *sym_list; sym_list++)
+ for (sym_list = thread_db->td_symbol_list_p (); *sym_list; sym_list++)
look_up_one_symbol (*sym_list, &unused);
}
@@ -377,16 +394,23 @@ int
thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
CORE_ADDR load_module, CORE_ADDR *address)
{
-#if HAVE_TD_THR_TLS_GET_ADDR
psaddr_t addr;
td_err_e err;
struct lwp_info *lwp;
struct thread_info *saved_inferior;
+ struct process_info *proc;
+ struct thread_db *thread_db;
+
+ proc = get_thread_process (thread);
+ thread_db = proc->private->thread_db;
/* If the thread layer is not (yet) initialized, fail. */
- if (!get_thread_process (thread)->all_symbols_looked_up)
+ if (!proc->all_symbols_looked_up)
return TD_ERR;
+ if (thread_db->td_thr_tls_get_addr_p == NULL)
+ return -1;
+
lwp = get_thread_lwp (thread);
if (!lwp->thread_known)
find_one_thread (lwp->head.id);
@@ -398,8 +422,9 @@ 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 = thread_db->td_thr_tls_get_addr_p (&lwp->th,
+ (psaddr_t) (uintptr_t) load_module,
+ offset, &addr);
current_inferior = saved_inferior;
if (err == TD_OK)
{
@@ -408,17 +433,190 @@ thread_db_get_tls_address (struct thread
}
else
return err;
-#else
- return -1;
-#endif
+}
+
+static int
+try_thread_db_load_1 (void *handle)
+{
+ td_err_e err;
+ struct thread_db tdb;
+ struct process_info *proc = current_process ();
+
+ if (proc->private->thread_db != NULL)
+ fatal ("unexpected: proc->private->thread_db != NULL");
+
+ tdb.handle = handle;
+
+ /* Initialize pointers to the dynamic library functions we will use.
+ Essential functions first. */
+
+#define CHK(required, a) \
+ do \
+ { \
+ if ((a) == NULL) \
+ { \
+ if (debug_threads) \
+ fprintf (stderr, "dlsym: %s\n", dlerror ()); \
+ if (required) \
+ return 0; \
+ } \
+ } \
+ while (0)
+
+ CHK (1, tdb.td_ta_new_p = dlsym (handle, "td_ta_new"));
+
+ /* Attempt to open a connection to the thread library. */
+ err = tdb.td_ta_new_p (&tdb.proc_handle, &tdb.thread_agent);
+ if (err != TD_OK)
+ {
+ if (debug_threads)
+ fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
+ return 0;
+ }
+
+ CHK (1, tdb.td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr"));
+ CHK (1, tdb.td_thr_get_info_p = dlsym (handle, "td_thr_get_info"));
+ CHK (1, tdb.td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter"));
+ CHK (1, tdb.td_symbol_list_p = dlsym (handle, "td_symbol_list"));
+
+ /* This is required only when thread_db_use_events is on. */
+ CHK (thread_db_use_events,
+ tdb.td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"));
+
+ /* These are not essential. */
+ CHK (0, tdb.td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"));
+ CHK (0, tdb.td_ta_set_event_p = dlsym (handle, "td_ta_set_event"));
+ CHK (0, tdb.td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"));
+ CHK (0, tdb.td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"));
+
+#undef CHK
+
+ proc->private->thread_db = xmalloc (sizeof (tdb));
+ memcpy (proc->private->thread_db, &tdb, sizeof (tdb));
+
+ 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 (void)
+{
+ 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,27 +631,68 @@ 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;
+ {
+ /* Keep trying; maybe event reporting will work later. */
+ thread_db_free (proc);
+ 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;
+}
+
+/* Disconnect from libthread_db and free resources. */
+
+void
+thread_db_free (struct process_info *proc)
+{
+ struct thread_db *thread_db = proc->private->thread_db;
+ if (thread_db)
+ {
+ td_err_e (*td_ta_delete_p) (td_thragent_t *);
+
+ td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete");
+ if (td_ta_delete_p != NULL)
+ (*td_ta_delete_p) (thread_db->thread_agent);
+
+ dlclose (thread_db->handle);
+ free (thread_db);
+ proc->private->thread_db = NULL;
+ }
+}
+
+/* Handle "set libthread-db-search-path" monitor command and return 1.
+ For any other command, return 0. */
+
+int
+thread_db_handle_monitor_command (char *mon)
+{
+ if (strncmp (mon, "set libthread-db-search-path ", 29) == 0)
+ {
+ const char *cp = mon + 29;
+
+ 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");
+ return 1;
}
+ /* Tell server.c to perform default processing. */
return 0;
}
Index: gdbserver/config.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/config.in,v
retrieving revision 1.23
diff -u -p -u -r1.23 config.in
--- gdbserver/config.in 22 Aug 2009 16:56:42 -0000 1.23
+++ gdbserver/config.in 8 Oct 2009 19:14:25 -0000
@@ -130,9 +130,6 @@
/* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H
-/* Define if td_thr_tls_get_addr is available. */
-#undef HAVE_TD_THR_TLS_GET_ADDR
-
/* Define if TD_VERSION is available. */
#undef HAVE_TD_VERSION
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 8 Oct 2009 19:14:25 -0000
@@ -4210,125 +4210,7 @@ srv_libs=
USE_THREAD_DB=
if test "$srv_linux_thread_db" = "yes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libthread_db" >&5
-$as_echo_n "checking for libthread_db... " >&6; }
-if test "${srv_cv_thread_db+set}" = set; then :
- $as_echo_n "(cached) " >&6
-else
- old_LIBS="$LIBS"
- LIBS="$LIBS -lthread_db"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}
-int
-main ()
-{
-td_ta_new();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- srv_cv_thread_db="-lthread_db"
-else
- srv_cv_thread_db=no
-
- if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
- thread_db="/lib/libthread_db.so.1"
- else
- thread_db='$prefix/lib/libthread_db.so.1'
- fi
- LIBS="$old_LIBS `eval echo "$thread_db"`"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}
-int
-main ()
-{
-td_ta_new();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- srv_cv_thread_db="$thread_db"
-else
- srv_cv_thread_db=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
- LIBS="$old_LIBS"
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $srv_cv_thread_db" >&5
-$as_echo "$srv_cv_thread_db" >&6; }
- if test "$srv_cv_thread_db" = no; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find libthread_db." >&5
-$as_echo "$as_me: WARNING: Could not find libthread_db." >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling thread support in gdbserver." >&5
-$as_echo "$as_me: WARNING: Disabling thread support in gdbserver." >&2;}
- srv_linux_thread_db=no
- else
- srv_libs="$srv_cv_thread_db"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread_db_tls_get_addr" >&5
-$as_echo_n "checking for thread_db_tls_get_addr... " >&6; }
-if test "${srv_cv_tls_get_addr+set}" = set; then :
- $as_echo_n "(cached) " >&6
-else
- old_LIBS="$LIBS"
- LIBS="$LIBS $srv_cv_thread_db"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-void ps_pglobal_lookup() {}
- void ps_pdread() {}
- void ps_pdwrite() {}
- void ps_lgetregs() {}
- void ps_lsetregs() {}
- void ps_lgetfpregs() {}
- void ps_lsetfpregs() {}
- void ps_get_thread_area() {}
- void ps_getpid() {}
-int
-main ()
-{
-td_thr_tls_get_addr();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- srv_cv_tls_get_addr=yes
-else
- srv_cv_tls_get_addr=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
- LIBS="$old_LIBS"
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $srv_cv_tls_get_addr" >&5
-$as_echo "$srv_cv_tls_get_addr" >&6; }
- fi
+ srv_libs="-ldl"
old_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -rdynamic"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4351,9 +4233,7 @@ rm -f core conftest.err conftest.$ac_obj
conftest$ac_exeext conftest.$ac_ext
LDFLAGS="$old_LDFLAGS"
-fi
-if test "$srv_linux_thread_db" = "yes"; then
srv_thread_depfiles="thread-db.o proc-service.o"
USE_THREAD_DB="-DUSE_THREAD_DB"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TD_VERSION" >&5
@@ -4386,12 +4266,6 @@ $as_echo "$gdbsrv_cv_have_td_version" >&
$as_echo "#define HAVE_TD_VERSION 1" >>confdefs.h
fi
-
- if test "$srv_cv_tls_get_addr" = yes; then
-
-$as_echo "#define HAVE_TD_THR_TLS_GET_ADDR 1" >>confdefs.h
-
- fi
fi
if test "$srv_xmlfiles" != ""; then
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-08 19:21 ` Paul Pluzhnikov
@ 2009-10-08 19:42 ` Daniel Jacobowitz
2009-10-16 0:41 ` Paul Pluzhnikov
0 siblings, 1 reply; 25+ messages in thread
From: Daniel Jacobowitz @ 2009-10-08 19:42 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: Pedro Alves, gdb-patches, dje
On Thu, Oct 08, 2009 at 12:20:53PM -0700, Paul Pluzhnikov wrote:
> On Thu, Oct 8, 2009 at 12:05 PM, Daniel Jacobowitz <drow@false.org> wrote:
>
> > How horrid would it be to support both modes of operation?
>
> I think this can be done fairly easily via configure option.
>
> I would prefer to do it as a follow-up patch though.
> Would that be ok?
Oh, absolutely. This isn't a common use case, just one I've found
handy. As usual, I appreciate how helpful you are!
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-08 19:36 ` Paul Pluzhnikov
@ 2009-10-08 22:58 ` Pedro Alves
0 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2009-10-08 22:58 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: gdb-patches, dje
On Thursday 08 October 2009 20:35:42, Paul Pluzhnikov wrote:
> I believe attached patch fixes all your comments.
Indeed it does. Go ahead.
--
Pedro Alves
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-05 3:03 ` Pedro Alves
@ 2009-10-13 13:53 ` Pedro Alves
0 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2009-10-13 13:53 UTC (permalink / raw)
To: gdb-patches; +Cc: Paul Pluzhnikov, dje
On Monday 05 October 2009 04:03:27, Pedro Alves wrote:
> > and B) contradicts current usage (before the patch):
> >
> > grep current_process thread-db.c
> > ? struct process_info_private *proc = current_process()->private;
> > ? struct process_info_private *proc = current_process()->private;
> > ? struct process_info_private *proc = current_process()->private;
> > ? struct process_info *proc = current_process ();
>
> Probably a typo followed by copy-paste, and I'm probably to blame
> for those. ?It there are any after your patch goes in, I'll take
> care of fixing them.
'grep -rn "[a-zA-Z0-9_]()->" *' found only these left.
Applied.
--
Pedro Alves
2009-10-13 Pedro Alves <pedro@codesourcery.com>
gdb/
* infcall.c (call_function_by_hand): Formatting.
2009-10-13 Pedro Alves <pedro@codesourcery.com>
gdb/gdbserver/
* proc-service.c (ps_lgetregs): Formatting.
---
gdb/gdbserver/proc-service.c | 2 +-
gdb/infcall.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
Index: src/gdb/gdbserver/proc-service.c
===================================================================
--- src.orig/gdb/gdbserver/proc-service.c 2009-10-12 12:37:03.000000000 +0100
+++ src/gdb/gdbserver/proc-service.c 2009-10-12 12:37:22.000000000 +0100
@@ -111,7 +111,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwp
current_inferior = reg_inferior;
the_target->fetch_registers (-1);
- gregset_info()->fill_function (gregset);
+ gregset_info ()->fill_function (gregset);
current_inferior = save_inferior;
return PS_OK;
Index: src/gdb/infcall.c
===================================================================
--- src.orig/gdb/infcall.c 2009-10-12 12:37:03.000000000 +0100
+++ src/gdb/infcall.c 2009-10-12 12:37:36.000000000 +0100
@@ -940,7 +940,7 @@ When the function is done executing, GDB
user. */
if (terminate_bp != NULL
- && (inferior_thread()->stop_bpstat->breakpoint_at->address
+ && (inferior_thread ()->stop_bpstat->breakpoint_at->address
== terminate_bp->loc->address))
{
/* We must get back to the frame we were before the
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-08 19:42 ` Daniel Jacobowitz
@ 2009-10-16 0:41 ` Paul Pluzhnikov
2009-10-22 21:03 ` Paul Pluzhnikov
0 siblings, 1 reply; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-16 0:41 UTC (permalink / raw)
To: Paul Pluzhnikov, Pedro Alves, gdb-patches, Daniel Jacobowitz
[-- Attachment #1: Type: text/plain, Size: 992 bytes --]
On Thu, Oct 8, 2009 at 12:42 PM, Daniel Jacobowitz <drow@false.org> wrote:
> On Thu, Oct 08, 2009 at 12:20:53PM -0700, Paul Pluzhnikov wrote:
>> I would prefer to do it as a follow-up patch though.
>> Would that be ok?
>
> Oh, absolutely. This isn't a common use case, just one I've found
> handy. As usual, I appreciate how helpful you are!
Here is the promised follow-up patch.
If gdbserver is configured with
--with-libthread-db=/path/to/libthread.db.{a,so}
then we link with the given library instead of libdl, and directly import
all the symbols from it.
Tested by configuring --with-libthread-db=/lib64/libthread_db.so.1 and
running 'make check RUNTESTFLAGS="--target_board native-gdbserver"'.
No regressions.
Thanks,
--
Paul Pluzhnikov
2009-10-15 Paul Pluzhnikov <ppluzhnikov@google.com>
* configure.ac: New --with-libthread-db option.
* thread-db.c: Allow direct dependence on libthread_db.
(thread_db_free): Adjust.
* config.in: Regenerate.
* configure: Likewise.
[-- Attachment #2: gdb-gdbserver-threaddb-search-20091015.txt --]
[-- Type: text/plain, Size: 5680 bytes --]
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.ac,v
retrieving revision 1.27
diff -u -p -u -r1.27 configure.ac
--- configure.ac 9 Oct 2009 00:31:01 -0000 1.27
+++ configure.ac 16 Oct 2009 00:13:49 -0000
@@ -158,6 +158,13 @@ if test "$srv_linux_thread_db" = "yes";
fi
fi
+AC_ARG_WITH(libthread-db,
+AS_HELP_STRING([--with-libthread-db=PATH], [use given libthread_db directly]),
+[srv_libthread_db_path="${withval}"
+ AC_DEFINE(USE_LIBTHREAD_DB_DIRECTLY, 1, [Define if we should use libthread_db directly.])
+ srv_libs="$srv_libthread_db_path"
+])
+
if test "$srv_xmlfiles" != ""; then
srv_xmlbuiltin="xml-builtin.o"
AC_DEFINE(USE_XML, 1, [Define if an XML target description is available.])
Index: thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/thread-db.c,v
retrieving revision 1.24
diff -u -p -u -r1.24 thread-db.c
--- thread-db.c 9 Oct 2009 00:31:01 -0000 1.24
+++ thread-db.c 16 Oct 2009 00:38:43 -0000
@@ -30,7 +30,10 @@ static int thread_db_use_events;
#include "gdb_proc_service.h"
#include "../gdb_thread_db.h"
+#ifndef USE_LIBTHREAD_DB_DIRECTLY
#include <dlfcn.h>
+#endif
+
#include <stdint.h>
#include <limits.h>
#include <ctype.h>
@@ -44,8 +47,10 @@ struct thread_db
/* Connection to the libthread_db library. */
td_thragent_t *thread_agent;
+#ifndef USE_LIBTHREAD_DB_DIRECTLY
/* Handle of the libthread_db from dlopen. */
void *handle;
+#endif
/* Addresses of libthread_db functions. */
td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
@@ -435,6 +440,51 @@ thread_db_get_tls_address (struct thread
return err;
}
+#ifdef USE_LIBTHREAD_DB_DIRECTLY
+
+static int
+thread_db_load_search (void)
+{
+ td_err_e err;
+ struct thread_db tdb;
+ struct process_info *proc = current_process ();
+
+ if (proc->private->thread_db != NULL)
+ fatal ("unexpected: proc->private->thread_db != NULL");
+
+ tdb.td_ta_new_p = &td_ta_new;
+
+ /* Attempt to open a connection to the thread library. */
+ err = tdb.td_ta_new_p (&tdb.proc_handle, &tdb.thread_agent);
+ if (err != TD_OK)
+ {
+ if (debug_threads)
+ fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
+ return 0;
+ }
+
+ tdb.td_ta_map_lwp2thr_p = &td_ta_map_lwp2thr;
+ tdb.td_thr_get_info_p = &td_thr_get_info;
+ tdb.td_ta_thr_iter_p = &td_ta_thr_iter;
+ tdb.td_symbol_list_p = &td_symbol_list;
+
+ /* This is required only when thread_db_use_events is on. */
+ tdb.td_thr_event_enable_p = &td_thr_event_enable;
+
+ /* These are not essential. */
+ tdb.td_ta_event_addr_p = &td_ta_event_addr;
+ tdb.td_ta_set_event_p = &td_ta_set_event;
+ tdb.td_ta_event_getmsg_p = &td_ta_event_getmsg;
+ tdb.td_thr_tls_get_addr_p = &td_thr_tls_get_addr;
+
+ proc->private->thread_db = xmalloc (sizeof (tdb));
+ memcpy (proc->private->thread_db, &tdb, sizeof (tdb));
+
+ return 1;
+}
+
+#else
+
static int
try_thread_db_load_1 (void *handle)
{
@@ -613,6 +663,8 @@ thread_db_load_search (void)
return rc;
}
+#endif /* USE_LIBTHREAD_DB_DIRECTLY */
+
int
thread_db_init (int use_events)
{
@@ -656,6 +708,7 @@ thread_db_free (struct process_info *pro
struct thread_db *thread_db = proc->private->thread_db;
if (thread_db)
{
+#ifndef USE_LIBTHREAD_DB_DIRECTLY
td_err_e (*td_ta_delete_p) (td_thragent_t *);
td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete");
@@ -663,6 +716,10 @@ thread_db_free (struct process_info *pro
(*td_ta_delete_p) (thread_db->thread_agent);
dlclose (thread_db->handle);
+#else
+ td_ta_delete (thread_db->thread_agent);
+#endif /* USE_LIBTHREAD_DB_DIRECTLY */
+
free (thread_db);
proc->private->thread_db = NULL;
}
Index: config.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/config.in,v
retrieving revision 1.24
diff -u -p -u -r1.24 config.in
--- config.in 9 Oct 2009 00:31:01 -0000 1.24
+++ config.in 16 Oct 2009 00:13:49 -0000
@@ -175,6 +175,9 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
+/* Define if we should use libthread_db directly. */
+#undef USE_LIBTHREAD_DB_DIRECTLY
+
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
Index: configure
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure,v
retrieving revision 1.41
diff -u -p -u -r1.41 configure
--- configure 9 Oct 2009 00:31:01 -0000 1.41
+++ configure 16 Oct 2009 00:13:49 -0000
@@ -668,6 +668,7 @@ ac_user_opts='
enable_option_checking
with_pkgversion
with_bugurl
+with_libthread_db
'
ac_precious_vars='build_alias
host_alias
@@ -1297,6 +1298,8 @@ Optional Packages:
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-pkgversion=PKG Use PKG in the version string in place of "GDB"
--with-bugurl=URL Direct users to URL to report a bug
+ --with-libthread-db=PATH
+ use given libthread_db directly
Some influential environment variables:
CC C compiler command
@@ -4268,6 +4271,18 @@ $as_echo "#define HAVE_TD_VERSION 1" >>c
fi
fi
+
+# Check whether --with-libthread-db was given.
+if test "${with_libthread_db+set}" = set; then :
+ withval=$with_libthread_db; srv_libthread_db_path="${withval}"
+
+$as_echo "#define USE_LIBTHREAD_DB_DIRECTLY 1" >>confdefs.h
+
+ srv_libs="$srv_libthread_db_path"
+
+fi
+
+
if test "$srv_xmlfiles" != ""; then
srv_xmlbuiltin="xml-builtin.o"
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-16 0:41 ` Paul Pluzhnikov
@ 2009-10-22 21:03 ` Paul Pluzhnikov
2009-10-29 16:52 ` Paul Pluzhnikov
0 siblings, 1 reply; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-22 21:03 UTC (permalink / raw)
To: Paul Pluzhnikov, Pedro Alves, gdb-patches, Daniel Jacobowitz
On Thu, Oct 15, 2009 at 5:41 PM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> If gdbserver is configured with
> --with-libthread-db=/path/to/libthread.db.{a,so}
> then we link with the given library instead of libdl, and directly import
> all the symbols from it.
http://sourceware.org/ml/gdb-patches/2009-10/msg00356.html
Ping?
--
Paul Pluzhnikov
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-22 21:03 ` Paul Pluzhnikov
@ 2009-10-29 16:52 ` Paul Pluzhnikov
2009-10-29 17:27 ` Daniel Jacobowitz
0 siblings, 1 reply; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-29 16:52 UTC (permalink / raw)
To: Paul Pluzhnikov, Pedro Alves, gdb-patches, Daniel Jacobowitz
On Thu, Oct 22, 2009 at 2:03 PM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> On Thu, Oct 15, 2009 at 5:41 PM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
>
>> If gdbserver is configured with
>> --with-libthread-db=/path/to/libthread.db.{a,so}
>> then we link with the given library instead of libdl, and directly import
>> all the symbols from it.
>
> http://sourceware.org/ml/gdb-patches/2009-10/msg00356.html
>
> Ping?
Ping? Ping?
--
Paul Pluzhnikov
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-29 16:52 ` Paul Pluzhnikov
@ 2009-10-29 17:27 ` Daniel Jacobowitz
2009-10-29 17:45 ` Paul Pluzhnikov
0 siblings, 1 reply; 25+ messages in thread
From: Daniel Jacobowitz @ 2009-10-29 17:27 UTC (permalink / raw)
To: Paul Pluzhnikov; +Cc: Pedro Alves, gdb-patches
On Thu, Oct 29, 2009 at 09:50:29AM -0700, Paul Pluzhnikov wrote:
> On Thu, Oct 22, 2009 at 2:03 PM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> > On Thu, Oct 15, 2009 at 5:41 PM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> >
> >> If gdbserver is configured with
> >> Â --with-libthread-db=/path/to/libthread.db.{a,so}
> >> then we link with the given library instead of libdl, and directly import
> >> all the symbols from it.
> >
> > http://sourceware.org/ml/gdb-patches/2009-10/msg00356.html
> >
> > Ping?
>
> Ping? Ping?
Thanks! This looks fine.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1
2009-10-29 17:27 ` Daniel Jacobowitz
@ 2009-10-29 17:45 ` Paul Pluzhnikov
0 siblings, 0 replies; 25+ messages in thread
From: Paul Pluzhnikov @ 2009-10-29 17:45 UTC (permalink / raw)
To: Paul Pluzhnikov, Pedro Alves, gdb-patches
On Thu, Oct 29, 2009 at 10:26 AM, Daniel Jacobowitz <drow@false.org> wrote:
> This looks fine.
So committed.
Thanks.
--
Paul Pluzhnikov
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2009-10-29 17:45 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-02 16:34 [patch] Allow gdbserver to dynamically lookup libthread_db.so.1 Paul Pluzhnikov
2009-09-02 16:43 ` Paul Pluzhnikov
2009-09-02 16:47 ` Pedro Alves
2009-09-02 17:16 ` Paul Pluzhnikov
2009-09-02 17:19 ` Doug Evans
2009-10-02 23:51 ` Paul Pluzhnikov
2009-10-04 20:32 ` Pedro Alves
2009-10-05 1:49 ` Paul Pluzhnikov
2009-10-05 3:03 ` Pedro Alves
2009-10-13 13:53 ` Pedro Alves
2009-10-06 23:08 ` Paul Pluzhnikov
2009-10-06 23:44 ` Pedro Alves
2009-10-07 0:27 ` Paul Pluzhnikov
2009-10-08 18:08 ` Pedro Alves
2009-10-08 19:05 ` Daniel Jacobowitz
2009-10-08 19:21 ` Paul Pluzhnikov
2009-10-08 19:42 ` Daniel Jacobowitz
2009-10-16 0:41 ` Paul Pluzhnikov
2009-10-22 21:03 ` Paul Pluzhnikov
2009-10-29 16:52 ` Paul Pluzhnikov
2009-10-29 17:27 ` Daniel Jacobowitz
2009-10-29 17:45 ` Paul Pluzhnikov
2009-10-08 19:36 ` Paul Pluzhnikov
2009-10-08 22:58 ` Pedro Alves
2009-10-04 20:34 ` Pedro Alves
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox