Mirror of the gdb mailing list
 help / color / mirror / Atom feed
From: Pedro Alves <palves@redhat.com>
To: Zack Weinberg <zackw@panix.com>
Cc: GNU C Library <libc-alpha@sourceware.org>, gdb@sourceware.org
Subject: Using libthread_db.so with single-threaded programs, for TLS access (was: Re: [RFC PATCH 0/3] Pretty-printing for errno)
Date: Wed, 13 Sep 2017 11:22:00 -0000	[thread overview]
Message-ID: <72a8ac9b-2429-c8bd-83b9-d758224571c5@redhat.com> (raw)
In-Reply-To: <2432779a-f146-1612-236e-84dde15c5d01@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 3819 bytes --]

On 09/07/2017 12:34 PM, Pedro Alves wrote:
> On 09/06/2017 10:03 PM, Zack Weinberg wrote:
> 
>> So, changes to both gdb and libthread_db seem to be required here.  I
>> do think that _in principle_ it ought to be possible to use
>> libthread_db to retrieve the address of thread-local data even if the
>> inferior is not linked with libpthread; glibc has quite a few
>> thread-specific variables (errno most prominent, of course, but also
>> h_errno, _res, etc), and so might any library which can be used from
>> both single- and multithreaded programs.
>>
>> This is really not code I feel comfortable hacking up, though, and
>> it's probably more of a project than I have time for, in any case.
> 
> Sounds like a promising approach though.  I'd like to see this path
> explored a bit more.  I'll keep this in my TODO, even though it's
> not likely to bubble up very soon.  Thanks for the discussion/ideas!

So I played with this a bit more on the plane back from Cauldron,
to try to see if we'd hit some major roadblock.  I also chatted
with Carlos a bit about this back at the Cauldron, and seemingly
there's no major reason this can't be made to work,
TLS-internals-wise.

Seems like that it's mainly a case of moving libthread_db.so-related
symbols from libpthread.so elsewhere.  More below.

I hacked libthread_db.so to disable the nptl_version check, so that
it always successfully loads with non-threaded programs.  And then
I tweaked GDB enough to make it actually reach libthread_db.so's
td_thr_tls_get_addr in that scenario too.  That's when I hit
another snag: the symbols that libthread_db.so needs which describe
the necessary offsets of internal data structures for getting at the
TLS blocks are also in libpthread.so...  In particular, the first
we stumble on is "_thread_db_link_map_l_tls_modid".  I made GDB
print the symbol lookups to make it easier to debug.  Vis:

 (gdb) p errno
 ps_pglobal_lookup: name="__stack_user" => PS_NOSYM
 warning: Cannot find user-level thread for LWP 31772: generic error
 ps_pglobal_lookup: name="_thread_db_link_map_l_tls_modid" => PS_NOSYM
 Cannot find thread-local storage for process 31772, shared library /lib64/libc.so.6:
 operation not applicable to

The lookup is coming from here:

 (top-gdb) bt
 #0  ps_pglobal_lookup (ph=0x1f65fe0, obj=0x7fffe58f93ae "libpthread.so.0", name=0x7fffe58f9e48 "_thread_db_link_map_l_tls_modid", sym_addr=0x7fffffffc428) at src/gdb/proc-service.c:115
 #1  0x00007fffe58f88a8 in td_mod_lookup (ps=<optimized out>, mod=mod@entry=0x7fffe58f93ae "libpthread.so.0", idx=<optimized out>, sym_addr=sym_addr@entry=0x7fffffffc428)
     at td_symbol_list.c:48
 #2  0x00007fffe58f8f45 in _td_locate_field (ta=ta@entry=0x1f84df0, desc=desc@entry=0x1f84fbc, descriptor_name=descriptor_name@entry=43, idx=idx@entry=0x0, 
     address=address@entry=0x7fffffffc458) at fetch-value.c:54
 #3  0x00007fffe58f8ff0 in _td_fetch_value (ta=0x1f84df0, desc=0x1f84fbc, descriptor_name=descriptor_name@entry=43, idx=idx@entry=0x0, address=0x7ffff7ff7658, 
     result=result@entry=0x7fffffffc498) at fetch-value.c:94
 #4  0x00007fffe58f8ddf in td_thr_tls_get_addr (th=0x7fffffffc4e0, map_address=<optimized out>, offset=16, address=0x7fffffffc4f8) at td_thr_tls_get_addr.c:31
 ...

So we'd need to move that symbol (and maybe others) to one of ld.so/libc.so
instead.  AFAICT, those magic symbols are described in nptl_db/structs.def.
I haven't looked enough to figure out what ends up expanding those macros
in libpthread.so.  This is where I stopped.

I'm attaching the gdb and libthread_db.so patches I used, both against current
master in their respective projects.  See comments within the patches.
I've also pushed the gdb patch to a "users/palves/tls-nonthreaded" branch.
(I don't think I have write access to glibc's git.)

Thanks,
Pedro Alves


[-- Attachment #2: gdb.patch --]
[-- Type: text/x-patch, Size: 4919 bytes --]

From 24f816f528fa110b2dc670a5f43899b60983ac2b Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 13 Sep 2017 11:43:15 +0100
Subject: [PATCH] Use libthread_db.so with non-threaded programs, for TLS

---
 gdb/linux-thread-db.c | 39 ++++++++++++++++++++++++++++++---------
 gdb/proc-service.c    | 19 ++++++++++++++++---
 2 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 0e16f6a..c2fea86 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -104,7 +104,7 @@ set_libthread_db_search_path (char *ignored, int from_tty,
 
 /* If non-zero, print details of libthread_db processing.  */
 
-static unsigned int libthread_db_debug;
+unsigned int libthread_db_debug;
 
 static void
 show_libthread_db_debug (struct ui_file *file, int from_tty,
@@ -354,13 +354,19 @@ thread_from_lwp (ptid_t ptid)
   err = info->td_ta_map_lwp2thr_p (info->thread_agent, ptid_get_lwp (ptid),
 				   &th);
   if (err != TD_OK)
-    error (_("Cannot find user-level thread for LWP %ld: %s"),
-	   ptid_get_lwp (ptid), thread_db_err_str (err));
+    {
+      warning (_("Cannot find user-level thread for LWP %ld: %s"),
+	       ptid_get_lwp (ptid), thread_db_err_str (err));
+      return NULL;
+    }
 
   err = info->td_thr_get_info_p (&th, &ti);
   if (err != TD_OK)
-    error (_("thread_get_info_callback: cannot get thread info: %s"),
-	   thread_db_err_str (err));
+    {
+      warning (_("thread_get_info_callback: cannot get thread info: %s"),
+	       thread_db_err_str (err));
+      return NULL;
+    }
 
   /* Fill the cache.  */
   tp = find_thread_ptid (ptid);
@@ -1429,7 +1435,7 @@ thread_db_get_thread_local_address (struct target_ops *ops,
   if (thread_info != NULL && thread_info->priv == NULL)
     thread_info = thread_from_lwp (ptid);
 
-  if (thread_info != NULL && thread_info->priv != NULL)
+  if (true)
     {
       td_err_e err;
       psaddr_t address;
@@ -1437,6 +1443,21 @@ thread_db_get_thread_local_address (struct target_ops *ops,
 
       info = get_thread_db_info (ptid_get_pid (ptid));
 
+      /* Handle executables that don't link with pthread.  We still
+	 use libthread_db.so with those in order to be able to access
+	 TLS variables.  This bakes in awareness that the main
+	 thread's special handle is "0".  Should maybe make
+	 td_ta_map_lwp2thr return that handle instead for non-threaded
+	 programs.  */
+      td_thrhandle_t main_thr_th {};
+      main_thr_th.th_ta_p = info->thread_agent;
+
+      td_thrhandle_t *th;
+      if (thread_info == NULL || thread_info->priv == NULL)
+	th = &main_thr_th;
+      else
+	th = &thread_info->priv->th;
+
       /* Finally, get the address of the variable.  */
       if (lm != 0)
 	{
@@ -1448,7 +1469,8 @@ thread_db_get_thread_local_address (struct target_ops *ops,
 	  /* 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 = info->td_thr_tls_get_addr_p (&thread_info->priv->th,
+
+	  err = info->td_thr_tls_get_addr_p (th,
 					     (psaddr_t)(uintptr_t) lm,
 					     offset, &address);
 	}
@@ -1466,8 +1488,7 @@ thread_db_get_thread_local_address (struct target_ops *ops,
 	     PR libc/16831 due to GDB PR threads/16954 LOAD_MODULE is also NULL.
 	     The constant number 1 depends on GNU __libc_setup_tls
 	     initialization of l_tls_modid to 1.  */
-	  err = info->td_thr_tlsbase_p (&thread_info->priv->th,
-					1, &address);
+	  err = info->td_thr_tlsbase_p (th, 1, &address);
 	  address = (char *) address + offset;
 	}
 
diff --git a/gdb/proc-service.c b/gdb/proc-service.c
index 4620fea..940993c 100644
--- a/gdb/proc-service.c
+++ b/gdb/proc-service.c
@@ -102,6 +102,8 @@ ps_xfer_memory (const struct ps_prochandle *ph, psaddr_t addr,
 }
 \f
 
+extern unsigned int libthread_db_debug;
+
 /* Search for the symbol named NAME within the object named OBJ within
    the target process PH.  If the symbol is found the address of the
    symbol is stored in SYM_ADDR.  */
@@ -119,9 +121,20 @@ ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
   /* FIXME: kettenis/2000-09-03: What should we do with OBJ?  */
   bound_minimal_symbol ms = lookup_minimal_symbol (name, NULL, NULL);
   if (ms.minsym == NULL)
-    return PS_NOSYM;
-
-  *sym_addr = core_addr_to_ps_addr (BMSYMBOL_VALUE_ADDRESS (ms));
+    {
+      if (libthread_db_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "ps_pglobal_lookup: name=\"%s\" => PS_NOSYM\n",
+			    name);
+      return PS_NOSYM;
+    }
+
+  CORE_ADDR ms_addr = BMSYMBOL_VALUE_ADDRESS (ms);
+  if (libthread_db_debug)
+    fprintf_unfiltered (gdb_stdlog,
+			"ps_pglobal_lookup: name=\"%s\" => PS_OK, %s\n", name,
+			paddress (target_gdbarch (), ms_addr));
+  *sym_addr = core_addr_to_ps_addr (ms_addr);
   return PS_OK;
 }
 
-- 
2.5.5


[-- Attachment #3: glibc.patch --]
[-- Type: text/x-patch, Size: 2296 bytes --]

From 386b8dc8ef16197b3efa38f4bbbc98833ce7c2c6 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Mon, 11 Sep 2017 13:48:04 +0100
Subject: [PATCH] remove version checks hack

---
 nptl_db/td_ta_map_lwp2thr.c | 10 ++++++++--
 nptl_db/td_ta_new.c         |  9 ++++++++-
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/nptl_db/td_ta_map_lwp2thr.c b/nptl_db/td_ta_map_lwp2thr.c
index d34711d..85620cb 100644
--- a/nptl_db/td_ta_map_lwp2thr.c
+++ b/nptl_db/td_ta_map_lwp2thr.c
@@ -185,11 +185,17 @@ td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
      sometimes contain garbage that would confuse us, left by the kernel
      at exec.  So if it looks like initialization is incomplete, we only
      fake a special descriptor for the initial thread.  */
-
   psaddr_t list;
   td_err_e err = DB_GET_SYMBOL (list, ta, __stack_user);
   if (err != TD_OK)
-    return err;
+    {
+      /* '__stack_user' is in pthread.so, so this always fails with
+	 non-threaded programs.  GDB hardcodes/assumes th_unique==0
+	 for the main thread - maybe we should instead return the fake
+	 special descriptor for the initial thread here too.  See
+	 below.  */
+      return err;
+    }
 
   err = DB_GET_FIELD (list, ta, list, list_t, next, 0);
   if (err != TD_OK)
diff --git a/nptl_db/td_ta_new.c b/nptl_db/td_ta_new.c
index aec2356..40424ad 100644
--- a/nptl_db/td_ta_new.c
+++ b/nptl_db/td_ta_new.c
@@ -33,12 +33,18 @@ LIST_HEAD (__td_agent_list);
 td_err_e
 td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
 {
+#if 0
   psaddr_t versaddr;
   char versbuf[sizeof (VERSION)];
+#endif
 
   LOG ("td_ta_new");
 
-  /* Check whether the versions match.  */
+  /* Check whether the versions match.
+
+     XXX: Disabled because "nptl_version" currently lives in
+     libpthread.so.  */
+#if 0
   if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK)
     return TD_NOLIBTHREAD;
   if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
@@ -47,6 +53,7 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
   if (memcmp (versbuf, VERSION, sizeof VERSION) != 0)
     /* Not the right version.  */
     return TD_VERSION;
+#endif
 
   /* Fill in the appropriate information.  */
   *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t));
-- 
2.5.5


  parent reply	other threads:[~2017-09-13 11:22 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-22 22:45 [RFC PATCH 0/3] Pretty-printing for errno Zack Weinberg
2017-06-22 22:45 ` [PATCH 1/3] Improve testing of GDB pretty-printers Zack Weinberg
2017-06-22 22:46 ` [PATCH 2/3] Make error_t always int; make __errno_location return an __error_t Zack Weinberg
2017-06-22 22:46 ` [PATCH 3/3] Add pretty-printer for errno Zack Weinberg
2017-06-29 15:48 ` [RFC PATCH 0/3] Pretty-printing " Phil Muldoon
2017-06-29 16:53   ` Pedro Alves
2017-06-29 17:02     ` Pedro Alves
2017-06-29 17:28       ` Pedro Alves
2017-06-30  0:28         ` Zack Weinberg
2017-06-30 16:38           ` Pedro Alves
2017-06-30 16:47             ` Pedro Alves
2017-06-30 17:27             ` Zack Weinberg
2017-06-30 18:11               ` Pedro Alves
2017-07-01 11:56                 ` Pedro Alves
2017-07-13  2:30                 ` Pedro Alves
2017-09-04 21:25                   ` Pedro Alves
2017-09-05 21:15                     ` Zack Weinberg
2017-09-05 22:32                       ` Pedro Alves
2017-09-06 13:05                         ` Zack Weinberg
2017-09-06 13:32                           ` Pedro Alves
2017-09-06 21:03                             ` Zack Weinberg
     [not found]                               ` <2432779a-f146-1612-236e-84dde15c5d01@redhat.com>
2017-09-13 11:22                                 ` Pedro Alves [this message]
2017-09-13 19:27                                   ` Using libthread_db.so with single-threaded programs, for TLS access (was: Re: [RFC PATCH 0/3] Pretty-printing for errno) Philippe Waroquiers
2017-09-14  0:02                                   ` Using libthread_db.so with single-threaded programs, for TLS access Pedro Alves
2017-09-18 13:17                                     ` Carlos O'Donell
2017-09-18 14:28                                       ` Pedro Alves
2017-07-01 14:35               ` [RFC PATCH 0/3] Pretty-printing for errno Siddhesh Poyarekar
2017-07-04 15:54                 ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=72a8ac9b-2429-c8bd-83b9-d758224571c5@redhat.com \
    --to=palves@redhat.com \
    --cc=gdb@sourceware.org \
    --cc=libc-alpha@sourceware.org \
    --cc=zackw@panix.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox