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