This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] Allow gdbserver to dynamically lookup libthread_db.so.1


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]