olga / rpms / glibc

Forked from rpms/glibc 5 years ago
Clone

Blame SOURCES/glibc-rh1202952.patch

ce426f
# 
ce426f
# commit f8aeae347377f3dfa8cbadde057adf1827fb1d44
ce426f
# Author: Alexandre Oliva <aoliva@redhat.com>
ce426f
# Date:   Tue Mar 17 01:14:11 2015 -0300
ce426f
# 
ce426f
#     Fix DTV race, assert, DTV_SURPLUS Static TLS limit, and nptl_db garbage
ce426f
#     
ce426f
#     for  ChangeLog
ce426f
#     
ce426f
#         [BZ #17090]
ce426f
#         [BZ #17620]
ce426f
#         [BZ #17621]
ce426f
#         [BZ #17628]
ce426f
#         * NEWS: Update.
ce426f
#         * elf/dl-tls.c (_dl_update_slotinfo): Clean up outdated DTV
ce426f
#         entries with Static TLS too.  Skip entries past the end of the
ce426f
#         allocated DTV, from Alan Modra.
ce426f
#         (tls_get_addr_tail): Update to glibc_likely/unlikely.  Move
ce426f
#         Static TLS DTV entry set up from...
ce426f
#          (_dl_allocate_tls_init): ... here (fix modid assertion), ...
ce426f
#         * elf/dl-reloc.c (_dl_nothread_init_static_tls): ... here...
ce426f
#         * nptl/allocatestack.c (init_one_static_tls): ... and here...
ce426f
#         * elf/dlopen.c (dl_open_worker): Drop l_tls_modid upper bound
ce426f
#         for Static TLS.
ce426f
#         * elf/tlsdeschtab.h (map_generation): Return size_t.  Check
ce426f
#         that the slot we find is associated with the given map before
ce426f
#         using its generation count.
ce426f
#         * nptl_db/db_info.c: Include ldsodefs.h.
ce426f
#         (rtld_global, dtv_slotinfo_list, dtv_slotinfo): New typedefs.
ce426f
#         * nptl_db/structs.def (DB_RTLD_VARIABLE): New macro.
ce426f
#         (DB_MAIN_VARIABLE, DB_RTLD_GLOBAL_FIELD): Likewise.
ce426f
#         (link_map::l_tls_offset): New struct field.
ce426f
#         (dtv_t::counter): Likewise.
ce426f
#         (rtld_global): New struct.
ce426f
#         (_rtld_global): New rtld variable.
ce426f
#         (dl_tls_dtv_slotinfo_list): New rtld global field.
ce426f
#         (dtv_slotinfo_list): New struct.
ce426f
#         (dtv_slotinfo): Likewise.
ce426f
#         * nptl_db/td_symbol_list.c: Drop gnu/lib-names.h include.
ce426f
#         (td_lookup): Rename to...
ce426f
#         (td_mod_lookup): ... this.  Use new mod parameter instead of
ce426f
#         LIBPTHREAD_SO.
ce426f
#         * nptl_db/td_thr_tlsbase.c: Include link.h.
ce426f
#         (dtv_slotinfo_list, dtv_slotinfo): New functions.
ce426f
#         (td_thr_tlsbase): Check DTV generation.  Compute Static TLS
ce426f
#         addresses even if the DTV is out of date or missing them.
ce426f
#         * nptl_db/fetch-value.c (_td_locate_field): Do not refuse to
ce426f
#         index zero-length arrays.
ce426f
#         * nptl_db/thread_dbP.h: Include gnu/lib-names.h.
ce426f
#         (td_lookup): Make it a macro implemented in terms of...
ce426f
#         (td_mod_lookup): ... this declaration.
ce426f
#         * nptl_db/db-symbols.awk (DB_RTLD_VARIABLE): Override.
ce426f
#         (DB_MAIN_VARIABLE): Likewise.
ce426f
# 
ce426f
diff -urN glibc-2.17-c758a686/elf/dl-open.c glibc-2.17-c758a686/elf/dl-open.c
ce426f
--- glibc-2.17-c758a686/elf/dl-open.c	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/elf/dl-open.c	2015-03-17 14:39:47.746505786 -0400
ce426f
@@ -535,17 +535,7 @@
ce426f
 	  && imap->l_tls_blocksize > 0)
ce426f
 	{
ce426f
 	  /* For static TLS we have to allocate the memory here and
ce426f
-	     now.  This includes allocating memory in the DTV.  But we
ce426f
-	     cannot change any DTV other than our own.  So, if we
ce426f
-	     cannot guarantee that there is room in the DTV we don't
ce426f
-	     even try it and fail the load.
ce426f
-
ce426f
-	     XXX We could track the minimum DTV slots allocated in
ce426f
-	     all threads.  */
ce426f
-	  if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
ce426f
-	    _dl_signal_error (0, "dlopen", NULL, N_("\
ce426f
-cannot load any more object with static TLS"));
ce426f
-
ce426f
+	     now, but we can delay updating the DTV.  */
ce426f
 	  imap->l_need_tls_init = 0;
ce426f
 #ifdef SHARED
ce426f
 	  /* Update the slot information data for at least the
ce426f
diff -urN glibc-2.17-c758a686/elf/dl-reloc.c glibc-2.17-c758a686/elf/dl-reloc.c
ce426f
--- glibc-2.17-c758a686/elf/dl-reloc.c	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/elf/dl-reloc.c	2015-03-17 14:39:47.747505754 -0400
ce426f
@@ -136,12 +136,6 @@
ce426f
 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
ce426f
 #endif
ce426f
 
ce426f
-  /* Fill in the DTV slot so that a later LD/GD access will find it.  */
ce426f
-  dtv_t *dtv = THREAD_DTV ();
ce426f
-  assert (map->l_tls_modid <= dtv[-1].counter);
ce426f
-  dtv[map->l_tls_modid].pointer.val = dest;
ce426f
-  dtv[map->l_tls_modid].pointer.is_static = true;
ce426f
-
ce426f
   /* Initialize the memory.  */
ce426f
   memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
ce426f
 	  '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
ce426f
diff -urN glibc-2.17-c758a686/elf/dl-tls.c glibc-2.17-c758a686/elf/dl-tls.c
ce426f
--- glibc-2.17-c758a686/elf/dl-tls.c	2015-03-17 14:39:31.335019227 -0400
ce426f
+++ glibc-2.17-c758a686/elf/dl-tls.c	2015-03-17 14:42:48.443852579 -0400
ce426f
@@ -432,17 +432,14 @@
ce426f
 	  assert (listp->slotinfo[cnt].gen <= GL(dl_tls_generation));
ce426f
 	  maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
ce426f
 
ce426f
+	  dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
ce426f
+	  dtv[map->l_tls_modid].pointer.is_static = false;
ce426f
+
ce426f
 	  if (map->l_tls_offset == NO_TLS_OFFSET
ce426f
 	      || map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
ce426f
-	    {
ce426f
-	      /* For dynamically loaded modules we simply store
ce426f
-		 the value indicating deferred allocation.  */
ce426f
-	      dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
ce426f
-	      dtv[map->l_tls_modid].pointer.is_static = false;
ce426f
-	      continue;
ce426f
-	    }
ce426f
+	    continue;
ce426f
 
ce426f
-	  assert (map->l_tls_modid == cnt);
ce426f
+	  assert (map->l_tls_modid == total + cnt);
ce426f
 	  assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
ce426f
 #if TLS_TCB_AT_TP
ce426f
 	  assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
ce426f
@@ -454,8 +451,6 @@
ce426f
 #endif
ce426f
 
ce426f
 	  /* Copy the initialization image and clear the BSS part.  */
ce426f
-	  dtv[map->l_tls_modid].pointer.val = dest;
ce426f
-	  dtv[map->l_tls_modid].pointer.is_static = true;
ce426f
 	  memset (__mempcpy (dest, map->l_tls_initimage,
ce426f
 			     map->l_tls_initimage_size), '\0',
ce426f
 		  map->l_tls_blocksize - map->l_tls_initimage_size);
ce426f
@@ -623,13 +618,16 @@
ce426f
 	      struct link_map *map = listp->slotinfo[cnt].map;
ce426f
 	      if (map == NULL)
ce426f
 		{
ce426f
-		  /* If this modid was used at some point the memory
ce426f
-		     might still be allocated.  */
ce426f
-		  if (! dtv[total + cnt].pointer.is_static
ce426f
-		      && dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
ce426f
+		  if (dtv[-1].counter >= total + cnt)
ce426f
 		    {
ce426f
-		      free (dtv[total + cnt].pointer.val);
ce426f
+		      /* If this modid was used at some point the memory
ce426f
+			 might still be allocated.  */
ce426f
+		      if (! dtv[total + cnt].pointer.is_static
ce426f
+			  && (dtv[total + cnt].pointer.val
ce426f
+			      != TLS_DTV_UNALLOCATED))
ce426f
+			free (dtv[total + cnt].pointer.val);
ce426f
 		      dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
ce426f
+		      dtv[total + cnt].pointer.is_static = false;
ce426f
 		    }
ce426f
 
ce426f
 		  continue;
ce426f
@@ -693,10 +691,8 @@
ce426f
 		   memalign and not malloc.  */
ce426f
 		free (dtv[modid].pointer.val);
ce426f
 
ce426f
-	      /* This module is loaded dynamically- We defer memory
ce426f
-		 allocation.  */
ce426f
-	      dtv[modid].pointer.is_static = false;
ce426f
 	      dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
ce426f
+	      dtv[modid].pointer.is_static = false;
ce426f
 
ce426f
 	      if (modid == req_modid)
ce426f
 		the_map = map;
ce426f
@@ -734,13 +730,12 @@
ce426f
       the_map = listp->slotinfo[idx].map;
ce426f
     }
ce426f
 
ce426f
- again:
ce426f
   /* Make sure that, if a dlopen running in parallel forces the
ce426f
      variable into static storage, we'll wait until the address in the
ce426f
      static TLS block is set up, and use that.  If we're undecided
ce426f
      yet, make sure we make the decision holding the lock as well.  */
ce426f
-  if (__builtin_expect (the_map->l_tls_offset
ce426f
-			!= FORCED_DYNAMIC_TLS_OFFSET, 0))
ce426f
+  if (__glibc_unlikely (the_map->l_tls_offset
ce426f
+			!= FORCED_DYNAMIC_TLS_OFFSET))
ce426f
     {
ce426f
       __rtld_lock_lock_recursive (GL(dl_load_lock));
ce426f
       if (__builtin_expect (the_map->l_tls_offset == NO_TLS_OFFSET, 1))
ce426f
@@ -748,22 +743,28 @@
ce426f
 	  the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
ce426f
 	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
ce426f
 	}
ce426f
-      else
ce426f
+      else if (__glibc_likely (the_map->l_tls_offset
ce426f
+			       != FORCED_DYNAMIC_TLS_OFFSET))
ce426f
 	{
ce426f
+#if TLS_TCB_AT_TP
ce426f
+	  void *p = (char *) THREAD_SELF - the_map->l_tls_offset;
ce426f
+#elif TLS_DTV_AT_TP
ce426f
+	  void *p = (char *) THREAD_SELF + the_map->l_tls_offset + TLS_PRE_TCB_SIZE;
ce426f
+#else
ce426f
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
ce426f
+#endif
ce426f
 	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
ce426f
-	  if (__builtin_expect (the_map->l_tls_offset
ce426f
-				!= FORCED_DYNAMIC_TLS_OFFSET, 1))
ce426f
-	    {
ce426f
-	      void *p = dtv[GET_ADDR_MODULE].pointer.val;
ce426f
-	      if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
ce426f
-		goto again;
ce426f
+	  dtv[GET_ADDR_MODULE].pointer.is_static = true;
ce426f
+	  dtv[GET_ADDR_MODULE].pointer.val = p;
ce426f
 
ce426f
-	      return (char *) p + GET_ADDR_OFFSET;
ce426f
-	    }
ce426f
+	  return (char *) p + GET_ADDR_OFFSET;
ce426f
 	}
ce426f
+      else
ce426f
+	__rtld_lock_unlock_recursive (GL(dl_load_lock));
ce426f
+
ce426f
     }
ce426f
   void *p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
ce426f
-  dtv[GET_ADDR_MODULE].pointer.is_static = false;
ce426f
+  assert (!dtv[GET_ADDR_MODULE].pointer.is_static);
ce426f
 
ce426f
   return (char *) p + GET_ADDR_OFFSET;
ce426f
 }
ce426f
diff -urN glibc-2.17-c758a686/elf/tlsdeschtab.h glibc-2.17-c758a686/elf/tlsdeschtab.h
ce426f
--- glibc-2.17-c758a686/elf/tlsdeschtab.h	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/elf/tlsdeschtab.h	2015-03-17 14:39:47.747505754 -0400
ce426f
@@ -42,7 +42,7 @@
ce426f
   return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
ce426f
 }
ce426f
 
ce426f
-inline static int
ce426f
+inline static size_t
ce426f
 map_generation (struct link_map *map)
ce426f
 {
ce426f
   size_t idx = map->l_tls_modid;
ce426f
@@ -58,7 +58,7 @@
ce426f
 	     we can assume that, if the generation count is zero, we
ce426f
 	     still haven't determined the generation count for this
ce426f
 	     module.  */
ce426f
-	  if (listp->slotinfo[idx].gen)
ce426f
+	  if (listp->slotinfo[idx].map == map && listp->slotinfo[idx].gen)
ce426f
 	    return listp->slotinfo[idx].gen;
ce426f
 	  else
ce426f
 	    break;
ce426f
diff -urN glibc-2.17-c758a686/nptl/allocatestack.c glibc-2.17-c758a686/nptl/allocatestack.c
ce426f
--- glibc-2.17-c758a686/nptl/allocatestack.c	2015-03-17 14:39:31.342019008 -0400
ce426f
+++ glibc-2.17-c758a686/nptl/allocatestack.c	2015-03-17 14:39:47.747505754 -0400
ce426f
@@ -1157,7 +1157,6 @@
ce426f
 static inline void __attribute__((always_inline))
ce426f
 init_one_static_tls (struct pthread *curp, struct link_map *map)
ce426f
 {
ce426f
-  dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
ce426f
 # if TLS_TCB_AT_TP
ce426f
   void *dest = (char *) curp - map->l_tls_offset;
ce426f
 # elif TLS_DTV_AT_TP
ce426f
@@ -1166,11 +1165,9 @@
ce426f
 #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
ce426f
 # endif
ce426f
 
ce426f
-  /* Fill in the DTV slot so that a later LD/GD access will find it.  */
ce426f
-  dtv[map->l_tls_modid].pointer.val = dest;
ce426f
-  dtv[map->l_tls_modid].pointer.is_static = true;
ce426f
-
ce426f
-  /* Initialize the memory.  */
ce426f
+  /* We cannot delay the initialization of the Static TLS area, since
ce426f
+     it can be accessed with LE or IE, but since the DTV is only used
ce426f
+     by GD and LD, we can delay its update to avoid a race.  */
ce426f
   memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
ce426f
 	  '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
ce426f
 }
ce426f
diff -urN glibc-2.17-c758a686/nptl_db/db_info.c glibc-2.17-c758a686/nptl_db/db_info.c
ce426f
--- glibc-2.17-c758a686/nptl_db/db_info.c	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/nptl_db/db_info.c	2015-03-17 14:39:47.747505754 -0400
ce426f
@@ -20,6 +20,7 @@
ce426f
 
ce426f
 #include "thread_dbP.h"
ce426f
 #include <tls.h>
ce426f
+#include <ldsodefs.h>
ce426f
 
ce426f
 typedef struct pthread pthread;
ce426f
 typedef struct pthread_key_struct pthread_key_struct;
ce426f
@@ -36,6 +37,9 @@
ce426f
 } dtv;
ce426f
 
ce426f
 typedef struct link_map link_map;
ce426f
+typedef struct rtld_global rtld_global;
ce426f
+typedef struct dtv_slotinfo_list dtv_slotinfo_list;
ce426f
+typedef struct dtv_slotinfo dtv_slotinfo;
ce426f
 
ce426f
 /* Actually static in nptl/init.c, but we only need it for typeof.  */
ce426f
 extern bool __nptl_initial_report_events;
ce426f
diff -urN glibc-2.17-c758a686/nptl_db/db-symbols.awk glibc-2.17-c758a686/nptl_db/db-symbols.awk
ce426f
--- glibc-2.17-c758a686/nptl_db/db-symbols.awk	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/nptl_db/db-symbols.awk	2015-03-17 14:39:47.747505754 -0400
ce426f
@@ -2,6 +2,8 @@
ce426f
 # we've just built.  It checks for all the symbols used in td_symbol_list.
ce426f
 
ce426f
 BEGIN {
ce426f
+%define DB_RTLD_VARIABLE(name) /* Nothing. */
ce426f
+%define DB_MAIN_VARIABLE(name) /* Nothing. */
ce426f
 %define DB_LOOKUP_NAME(idx, name)		required[STRINGIFY (name)] = 1;
ce426f
 %define DB_LOOKUP_NAME_TH_UNIQUE(idx, name)	th_unique[STRINGIFY (name)] = 1;
ce426f
 %include "db-symbols.h"
ce426f
diff -urN glibc-2.17-c758a686/nptl_db/fetch-value.c glibc-2.17-c758a686/nptl_db/fetch-value.c
ce426f
--- glibc-2.17-c758a686/nptl_db/fetch-value.c	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/nptl_db/fetch-value.c	2015-03-17 14:39:47.747505754 -0400
ce426f
@@ -68,7 +68,8 @@
ce426f
 	}
ce426f
     }
ce426f
 
ce426f
-  if (idx != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
ce426f
+  if (idx != 0 && DB_DESC_NELEM (desc) != 0
ce426f
+      && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
ce426f
     /* This is an internal indicator to callers with nonzero IDX
ce426f
        that the IDX value is too big.  */
ce426f
     return TD_NOAPLIC;
ce426f
diff -urN glibc-2.17-c758a686/nptl_db/structs.def glibc-2.17-c758a686/nptl_db/structs.def
ce426f
--- glibc-2.17-c758a686/nptl_db/structs.def	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/nptl_db/structs.def	2015-03-17 14:44:29.779682236 -0400
ce426f
@@ -22,6 +22,28 @@
ce426f
 # define STRUCTS_DEF_DEFAULTS 1
ce426f
 #endif
ce426f
 
ce426f
+#ifndef DB_RTLD_VARIABLE
ce426f
+# define DB_RTLD_VARIABLE(name) DB_VARIABLE (name)
ce426f
+#endif
ce426f
+
ce426f
+#ifndef DB_MAIN_VARIABLE
ce426f
+# define DB_MAIN_VARIABLE(name) DB_VARIABLE (name)
ce426f
+#endif
ce426f
+
ce426f
+#ifndef DB_RTLD_GLOBAL_FIELD
ce426f
+# if !defined IS_IN_libpthread
ce426f
+#  define DB_RTLD_GLOBAL_FIELD(field)		\
ce426f
+  DB_STRUCT_FIELD (rtld_global, _##field)	\
ce426f
+  DB_MAIN_VARIABLE (_##field)
ce426f
+# elif defined SHARED
ce426f
+#  define DB_RTLD_GLOBAL_FIELD(field)		\
ce426f
+  DB_STRUCT_FIELD (rtld_global, _##field)
ce426f
+# else
ce426f
+#  define DB_RTLD_GLOBAL_FIELD(field)		\
ce426f
+  DB_MAIN_VARIABLE (_##field)
ce426f
+# endif
ce426f
+#endif /* DB_RTLD_GLOBAL_FIELD */
ce426f
+
ce426f
 DB_STRUCT (pthread)
ce426f
 DB_STRUCT_FIELD (pthread, list)
ce426f
 DB_STRUCT_FIELD (pthread, report_events)
ce426f
@@ -70,14 +92,31 @@
ce426f
 DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data)
ce426f
 
ce426f
 DB_STRUCT_FIELD (link_map, l_tls_modid)
ce426f
+DB_STRUCT_FIELD (link_map, l_tls_offset)
ce426f
 
ce426f
 DB_STRUCT_ARRAY_FIELD (dtv, dtv)
ce426f
 #define pointer_val pointer.val /* Field of anonymous struct in dtv_t.  */
ce426f
 DB_STRUCT_FIELD (dtv_t, pointer_val)
ce426f
+DB_STRUCT_FIELD (dtv_t, counter)
ce426f
 #if !defined IS_IN_libpthread || TLS_TCB_AT_TP
ce426f
 DB_STRUCT_FIELD (pthread, dtvp)
ce426f
 #endif
ce426f
 
ce426f
+#if !(defined IS_IN_libpthread && !defined SHARED)
ce426f
+DB_STRUCT (rtld_global)
ce426f
+DB_RTLD_VARIABLE (_rtld_global)
ce426f
+#endif
ce426f
+DB_RTLD_GLOBAL_FIELD (dl_tls_dtv_slotinfo_list)
ce426f
+
ce426f
+DB_STRUCT (dtv_slotinfo_list)
ce426f
+DB_STRUCT_FIELD (dtv_slotinfo_list, len)
ce426f
+DB_STRUCT_FIELD (dtv_slotinfo_list, next)
ce426f
+DB_STRUCT_ARRAY_FIELD (dtv_slotinfo_list, slotinfo)
ce426f
+
ce426f
+DB_STRUCT (dtv_slotinfo)
ce426f
+DB_STRUCT_FIELD (dtv_slotinfo, gen)
ce426f
+DB_STRUCT_FIELD (dtv_slotinfo, map)
ce426f
+
ce426f
 #ifdef STRUCTS_DEF_DEFAULTS
ce426f
 # undef DB_STRUCT_ARRAY_FIELD
ce426f
 # undef DB_ARRAY_VARIABLE
ce426f
diff -urN glibc-2.17-c758a686/nptl_db/td_symbol_list.c glibc-2.17-c758a686/nptl_db/td_symbol_list.c
ce426f
--- glibc-2.17-c758a686/nptl_db/td_symbol_list.c	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/nptl_db/td_symbol_list.c	2015-03-17 14:39:47.747505754 -0400
ce426f
@@ -18,7 +18,6 @@
ce426f
    <http://www.gnu.org/licenses/>.  */
ce426f
 
ce426f
 #include <assert.h>
ce426f
-#include <gnu/lib-names.h>
ce426f
 #include "thread_dbP.h"
ce426f
 
ce426f
 static const char *symbol_list_arr[] =
ce426f
@@ -41,12 +40,12 @@
ce426f
 
ce426f
 
ce426f
 ps_err_e
ce426f
-td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
ce426f
+td_mod_lookup (struct ps_prochandle *ps, const char *mod,
ce426f
+	       int idx, psaddr_t *sym_addr)
ce426f
 {
ce426f
   ps_err_e result;
ce426f
   assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
ce426f
-  result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx],
ce426f
-			      sym_addr);
ce426f
+  result = ps_pglobal_lookup (ps, mod, symbol_list_arr[idx], sym_addr);
ce426f
 
ce426f
 #ifdef HAVE_ASM_GLOBAL_DOT_NAME
ce426f
   /* For PowerPC, 64-bit uses dot symbols but 32-bit does not.
ce426f
diff -urN glibc-2.17-c758a686/nptl_db/td_thr_tlsbase.c glibc-2.17-c758a686/nptl_db/td_thr_tlsbase.c
ce426f
--- glibc-2.17-c758a686/nptl_db/td_thr_tlsbase.c	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/nptl_db/td_thr_tlsbase.c	2015-03-17 14:39:47.748505723 -0400
ce426f
@@ -17,14 +17,118 @@
ce426f
    <http://www.gnu.org/licenses/>.  */
ce426f
 
ce426f
 #include "thread_dbP.h"
ce426f
+#include <link.h>
ce426f
 
ce426f
+/* Get the DTV slotinfo list head entry from the dynamic loader state
ce426f
+   into *LISTHEAD.  */
ce426f
+static td_err_e
ce426f
+dtv_slotinfo_list (td_thragent_t *ta,
ce426f
+		   psaddr_t *listhead)
ce426f
+{
ce426f
+  td_err_e err;
ce426f
+  psaddr_t head;
ce426f
+
ce426f
+  if (ta->ta_addr__rtld_global == 0
ce426f
+      && td_mod_lookup (ta->ph, LD_SO, SYM__rtld_global,
ce426f
+			&ta->ta_addr__rtld_global) != PS_OK)
ce426f
+    ta->ta_addr__rtld_global = (void*)-1;
ce426f
+
ce426f
+  if (ta->ta_addr__rtld_global != (void*)-1)
ce426f
+    {
ce426f
+      err = DB_GET_FIELD (head, ta, ta->ta_addr__rtld_global,
ce426f
+			  rtld_global, _dl_tls_dtv_slotinfo_list, 0);
ce426f
+      if (err != TD_OK)
ce426f
+	return err;
ce426f
+    }
ce426f
+  else
ce426f
+    {
ce426f
+      if (ta->ta_addr__dl_tls_dtv_slotinfo_list == 0
ce426f
+	  && td_mod_lookup (ta->ph, NULL, SYM__dl_tls_dtv_slotinfo_list,
ce426f
+			    &ta->ta_addr__dl_tls_dtv_slotinfo_list) != PS_OK)
ce426f
+	return TD_ERR;
ce426f
+
ce426f
+      err = _td_fetch_value (ta, ta->ta_var__dl_tls_dtv_slotinfo_list,
ce426f
+			     SYM_DESC__dl_tls_dtv_slotinfo_list,
ce426f
+			     0, ta->ta_addr__dl_tls_dtv_slotinfo_list, &head;;
ce426f
+      if (err != TD_OK)
ce426f
+	return err;
ce426f
+    }
ce426f
+
ce426f
+  *listhead = head;
ce426f
+  return TD_OK;
ce426f
+}
ce426f
+
ce426f
+/* Get the address of the DTV slotinfo entry for MODID into
ce426f
+   *DTVSLOTINFO.  */
ce426f
+static td_err_e
ce426f
+dtv_slotinfo (td_thragent_t *ta,
ce426f
+	      unsigned long int modid,
ce426f
+	      psaddr_t *dtvslotinfo)
ce426f
+{
ce426f
+  td_err_e err;
ce426f
+  psaddr_t slot, temp;
ce426f
+  size_t slbase = 0;
ce426f
+
ce426f
+  err = dtv_slotinfo_list (ta, &slot);
ce426f
+  if (err != TD_OK)
ce426f
+    return err;
ce426f
+
ce426f
+  while (slot)
ce426f
+    {
ce426f
+      /* Get the number of entries in this list entry's array.  */
ce426f
+      err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list, len, 0);
ce426f
+      if (err != TD_OK)
ce426f
+	return err;
ce426f
+      size_t len = (uintptr_t)temp;
ce426f
+
ce426f
+      /* Did we find the list entry for modid?  */
ce426f
+      if (modid < slbase + len)
ce426f
+	break;
ce426f
+
ce426f
+      /* We didn't, so get the next list entry.  */
ce426f
+      slbase += len;
ce426f
+      err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list,
ce426f
+			  next, 0);
ce426f
+      if (err != TD_OK)
ce426f
+	return err;
ce426f
+      slot = temp;
ce426f
+    }
ce426f
+
ce426f
+  /* We reached the end of the list and found nothing.  */
ce426f
+  if (!slot)
ce426f
+    return TD_ERR;
ce426f
+
ce426f
+  /* Take the slotinfo for modid from the list entry.  */
ce426f
+  err = DB_GET_FIELD_ADDRESS (temp, ta, slot, dtv_slotinfo_list,
ce426f
+			      slotinfo, modid - slbase);
ce426f
+  if (err != TD_OK)
ce426f
+    return err;
ce426f
+  slot = temp;
ce426f
+
ce426f
+  *dtvslotinfo = slot;
ce426f
+  return TD_OK;
ce426f
+}
ce426f
+
ce426f
+/* Return in *BASE the base address of the TLS block for MODID within
ce426f
+   TH.
ce426f
+
ce426f
+   It should return success and yield the correct pointer in any
ce426f
+   circumstance where the TLS block for the module and thread
ce426f
+   requested has already been initialized.
ce426f
+
ce426f
+   It should fail with TD_TLSDEFER only when the thread could not
ce426f
+   possibly have observed any values in that TLS block.  That way, the
ce426f
+   debugger can fall back to showing initial values from the PT_TLS
ce426f
+   segment (and refusing attempts to mutate) for the TD_TLSDEFER case,
ce426f
+   and never fail to make the values the program will actually see
ce426f
+   available to the user of the debugger.  */
ce426f
 td_err_e
ce426f
 td_thr_tlsbase (const td_thrhandle_t *th,
ce426f
 		unsigned long int modid,
ce426f
 		psaddr_t *base)
ce426f
 {
ce426f
   td_err_e err;
ce426f
-  psaddr_t dtv, dtvslot, dtvptr;
ce426f
+  psaddr_t dtv, dtvslot, dtvptr, temp;
ce426f
 
ce426f
   if (modid < 1)
ce426f
     return TD_NOTLS;
ce426f
@@ -50,11 +154,75 @@
ce426f
 	return TD_TLSDEFER;
ce426f
     }
ce426f
 
ce426f
+  err = dtv_slotinfo (th->th_ta_p, modid, &temp);
ce426f
+  if (err != TD_OK)
ce426f
+    return err;
ce426f
+
ce426f
+  psaddr_t slot;
ce426f
+  err = DB_GET_STRUCT (slot, th->th_ta_p, temp, dtv_slotinfo);
ce426f
+  if (err != TD_OK)
ce426f
+    return err;
ce426f
+
ce426f
+  /* Take the link_map from the slotinfo.  */
ce426f
+  psaddr_t map;
ce426f
+  err = DB_GET_FIELD_LOCAL (map, th->th_ta_p, slot, dtv_slotinfo, map, 0);
ce426f
+  if (err != TD_OK)
ce426f
+    return err;
ce426f
+  if (!map)
ce426f
+    return TD_ERR;
ce426f
+
ce426f
+  /* Ok, the modid is good, now find out what DTV generation it
ce426f
+     requires.  */
ce426f
+  err = DB_GET_FIELD_LOCAL (temp, th->th_ta_p, slot, dtv_slotinfo, gen, 0);
ce426f
+  if (err != TD_OK)
ce426f
+    return err;
ce426f
+  size_t modgen = (uintptr_t)temp;
ce426f
+
ce426f
   /* Get the DTV pointer from the thread descriptor.  */
ce426f
   err = DB_GET_FIELD (dtv, th->th_ta_p, pd, pthread, dtvp, 0);
ce426f
   if (err != TD_OK)
ce426f
     return err;
ce426f
 
ce426f
+  psaddr_t dtvgenloc;
ce426f
+  /* Get the DTV generation count at dtv[0].counter.  */
ce426f
+  err = DB_GET_FIELD_ADDRESS (dtvgenloc, th->th_ta_p, dtv, dtv, dtv, 0);
ce426f
+  if (err != TD_OK)
ce426f
+    return err;
ce426f
+  err = DB_GET_FIELD (temp, th->th_ta_p, dtvgenloc, dtv_t, counter, 0);
ce426f
+  if (err != TD_OK)
ce426f
+    return err;
ce426f
+  size_t dtvgen = (uintptr_t)temp;
ce426f
+
ce426f
+  /* Is the DTV current enough?  */
ce426f
+  if (dtvgen < modgen)
ce426f
+    {
ce426f
+    try_static_tls:
ce426f
+      /* If the module uses Static TLS, we're still good.  */
ce426f
+      err = DB_GET_FIELD (temp, th->th_ta_p, map, link_map, l_tls_offset, 0);
ce426f
+      if (err != TD_OK)
ce426f
+	return err;
ce426f
+      ptrdiff_t tlsoff = (uintptr_t)temp;
ce426f
+
ce426f
+      if (tlsoff != FORCED_DYNAMIC_TLS_OFFSET
ce426f
+	  && tlsoff != NO_TLS_OFFSET)
ce426f
+	{
ce426f
+	  psaddr_t tp = pd;
ce426f
+
ce426f
+#if TLS_TCB_AT_TP
ce426f
+	  dtvptr = tp - tlsoff;
ce426f
+#elif TLS_DTV_AT_TP
ce426f
+	  dtvptr = tp + tlsoff + TLS_PRE_TCB_SIZE;
ce426f
+#else
ce426f
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
ce426f
+#endif
ce426f
+
ce426f
+	  *base = dtvptr;
ce426f
+	  return TD_OK;
ce426f
+	}
ce426f
+
ce426f
+      return TD_TLSDEFER;
ce426f
+    }
ce426f
+
ce426f
   /* Find the corresponding entry in the DTV.  */
ce426f
   err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid);
ce426f
   if (err != TD_OK)
ce426f
@@ -68,7 +236,7 @@
ce426f
   /* It could be that the memory for this module is not allocated for
ce426f
      the given thread.  */
ce426f
   if ((uintptr_t) dtvptr & 1)
ce426f
-    return TD_TLSDEFER;
ce426f
+    goto try_static_tls;
ce426f
 
ce426f
   *base = dtvptr;
ce426f
   return TD_OK;
ce426f
diff -urN glibc-2.17-c758a686/nptl_db/thread_dbP.h glibc-2.17-c758a686/nptl_db/thread_dbP.h
ce426f
--- glibc-2.17-c758a686/nptl_db/thread_dbP.h	2012-12-24 22:02:13.000000000 -0500
ce426f
+++ glibc-2.17-c758a686/nptl_db/thread_dbP.h	2015-03-17 14:39:47.748505723 -0400
ce426f
@@ -29,6 +29,7 @@
ce426f
 #include "thread_db.h"
ce426f
 #include "../nptl/pthreadP.h"  	/* This is for *_BITMASK only.  */
ce426f
 #include <list.h>
ce426f
+#include <gnu/lib-names.h>
ce426f
 
ce426f
 /* Indeces for the symbol names.  */
ce426f
 enum
ce426f
@@ -139,11 +140,11 @@
ce426f
 }
ce426f
 
ce426f
 
ce426f
-/* Internal wrapper around ps_pglobal_lookup.  */
ce426f
-extern ps_err_e td_lookup (struct ps_prochandle *ps,
ce426f
-			   int idx, psaddr_t *sym_addr) attribute_hidden;
ce426f
-
ce426f
-
ce426f
+/* Internal wrappers around ps_pglobal_lookup.  */
ce426f
+extern ps_err_e td_mod_lookup (struct ps_prochandle *ps, const char *modname,
ce426f
+			       int idx, psaddr_t *sym_addr) attribute_hidden;
ce426f
+#define td_lookup(ps, idx, sym_addr) \
ce426f
+  td_mod_lookup ((ps), LIBPTHREAD_SO, (idx), (sym_addr))
ce426f
 
ce426f
 
ce426f
 /* Store in psaddr_t VAR the address of inferior's symbol NAME.  */