Fix DTV race, assert, DTV_SURPLUS Static TLS limit, and nptl_db garbage

for  ChangeLog

	[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.
This commit is contained in:
Alexandre Oliva 2015-03-17 01:14:11 -03:00
parent b97eb2bdb1
commit f8aeae3473
14 changed files with 317 additions and 73 deletions

View File

@ -1,3 +1,50 @@
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.
2015-03-16 H.J. Lu <hongjiu.lu@intel.com> 2015-03-16 H.J. Lu <hongjiu.lu@intel.com>
[BZ #18134] [BZ #18134]

11
NEWS
View File

@ -10,11 +10,12 @@ Version 2.22
* The following bugs are resolved with this release: * The following bugs are resolved with this release:
4719, 13064, 14094, 14841, 14906, 15319, 15467, 15790, 15969, 16351, 4719, 13064, 14094, 14841, 14906, 15319, 15467, 15790, 15969, 16351,
16512, 16560, 16783, 17269, 17523, 17569, 17588, 17631, 17711, 17776, 16512, 16560, 16783, 17090, 17269, 17523, 17569, 17588, 17620, 17621,
17779, 17792, 17836, 17912, 17916, 17932, 17944, 17949, 17964, 17965, 17628, 17631, 17711, 17776, 17779, 17792, 17836, 17912, 17916, 17932,
17967, 17969, 17978, 17987, 17991, 17996, 17998, 17999, 18019, 18020, 17944, 17949, 17964, 17965, 17967, 17969, 17978, 17987, 17991, 17996,
18029, 18030, 18032, 18036, 18038, 18039, 18042, 18043, 18046, 18047, 17998, 17999, 18019, 18020, 18029, 18030, 18032, 18036, 18038, 18039,
18068, 18080, 18093, 18104, 18110, 18111, 18128. 18042, 18043, 18046, 18047, 18068, 18080, 18093, 18104, 18110, 18111,
18128.
* Character encoding and ctype tables were updated to Unicode 7.0.0, using * Character encoding and ctype tables were updated to Unicode 7.0.0, using
new generator scripts contributed by Pravin Satpute and Mike FABIAN (Red new generator scripts contributed by Pravin Satpute and Mike FABIAN (Red

View File

@ -533,17 +533,7 @@ TLS generation counter wrapped! Please report this."));
&& imap->l_tls_blocksize > 0) && imap->l_tls_blocksize > 0)
{ {
/* For static TLS we have to allocate the memory here and /* For static TLS we have to allocate the memory here and
now. This includes allocating memory in the DTV. But we now, but we can delay updating the DTV. */
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"));
imap->l_need_tls_init = 0; imap->l_need_tls_init = 0;
#ifdef SHARED #ifdef SHARED
/* Update the slot information data for at least the /* Update the slot information data for at least the

View File

@ -137,12 +137,6 @@ _dl_nothread_init_static_tls (struct link_map *map)
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif #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. */ /* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size), memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size); '\0', map->l_tls_blocksize - map->l_tls_initimage_size);

View File

@ -493,17 +493,14 @@ _dl_allocate_tls_init (void *result)
assert (listp->slotinfo[cnt].gen <= GL(dl_tls_generation)); assert (listp->slotinfo[cnt].gen <= GL(dl_tls_generation));
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen); 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 if (map->l_tls_offset == NO_TLS_OFFSET
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET) || map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
{ continue;
/* 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;
}
assert (map->l_tls_modid == cnt); assert (map->l_tls_modid == total + cnt);
assert (map->l_tls_blocksize >= map->l_tls_initimage_size); assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
#if TLS_TCB_AT_TP #if TLS_TCB_AT_TP
assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize); assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
@ -515,8 +512,6 @@ _dl_allocate_tls_init (void *result)
#endif #endif
/* Copy the initialization image and clear the BSS part. */ /* 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, memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0', map->l_tls_initimage_size), '\0',
map->l_tls_blocksize - map->l_tls_initimage_size); map->l_tls_blocksize - map->l_tls_initimage_size);
@ -679,13 +674,16 @@ _dl_update_slotinfo (unsigned long int req_modid)
struct link_map *map = listp->slotinfo[cnt].map; struct link_map *map = listp->slotinfo[cnt].map;
if (map == NULL) if (map == NULL)
{ {
/* If this modid was used at some point the memory if (dtv[-1].counter >= total + cnt)
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); /* 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.val = TLS_DTV_UNALLOCATED;
dtv[total + cnt].pointer.is_static = false;
} }
continue; continue;
@ -718,10 +716,8 @@ _dl_update_slotinfo (unsigned long int req_modid)
memalign and not malloc. */ memalign and not malloc. */
free (dtv[modid].pointer.val); 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.val = TLS_DTV_UNALLOCATED;
dtv[modid].pointer.is_static = false;
if (modid == req_modid) if (modid == req_modid)
the_map = map; the_map = map;
@ -759,13 +755,12 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
the_map = listp->slotinfo[idx].map; the_map = listp->slotinfo[idx].map;
} }
again:
/* Make sure that, if a dlopen running in parallel forces the /* Make sure that, if a dlopen running in parallel forces the
variable into static storage, we'll wait until the address in 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 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. */ yet, make sure we make the decision holding the lock as well. */
if (__builtin_expect (the_map->l_tls_offset if (__glibc_unlikely (the_map->l_tls_offset
!= FORCED_DYNAMIC_TLS_OFFSET, 0)) != FORCED_DYNAMIC_TLS_OFFSET))
{ {
__rtld_lock_lock_recursive (GL(dl_load_lock)); __rtld_lock_lock_recursive (GL(dl_load_lock));
if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET)) if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
@ -773,22 +768,28 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET; the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
__rtld_lock_unlock_recursive (GL(dl_load_lock)); __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)); __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); 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; return (char *) p + GET_ADDR_OFFSET;
} }

View File

@ -42,7 +42,7 @@ eq_tlsdesc (void *p, void *q)
return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset; return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
} }
inline static int inline static size_t
map_generation (struct link_map *map) map_generation (struct link_map *map)
{ {
size_t idx = map->l_tls_modid; size_t idx = map->l_tls_modid;
@ -58,7 +58,7 @@ map_generation (struct link_map *map)
we can assume that, if the generation count is zero, we we can assume that, if the generation count is zero, we
still haven't determined the generation count for this still haven't determined the generation count for this
module. */ module. */
if (listp->slotinfo[idx].gen) if (listp->slotinfo[idx].map == map && listp->slotinfo[idx].gen)
return listp->slotinfo[idx].gen; return listp->slotinfo[idx].gen;
else else
break; break;

View File

@ -1190,7 +1190,6 @@ __nptl_setxid (struct xid_command *cmdp)
static inline void __attribute__((always_inline)) static inline void __attribute__((always_inline))
init_one_static_tls (struct pthread *curp, struct link_map *map) init_one_static_tls (struct pthread *curp, struct link_map *map)
{ {
dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
# if TLS_TCB_AT_TP # if TLS_TCB_AT_TP
void *dest = (char *) curp - map->l_tls_offset; void *dest = (char *) curp - map->l_tls_offset;
# elif TLS_DTV_AT_TP # elif TLS_DTV_AT_TP
@ -1199,11 +1198,9 @@ init_one_static_tls (struct pthread *curp, struct link_map *map)
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif # endif
/* Fill in the DTV slot so that a later LD/GD access will find it. */ /* We cannot delay the initialization of the Static TLS area, since
dtv[map->l_tls_modid].pointer.val = dest; it can be accessed with LE or IE, but since the DTV is only used
dtv[map->l_tls_modid].pointer.is_static = true; by GD and LD, we can delay its update to avoid a race. */
/* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size), memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size); '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
} }

View File

@ -2,6 +2,8 @@
# we've just built. It checks for all the symbols used in td_symbol_list. # we've just built. It checks for all the symbols used in td_symbol_list.
BEGIN { 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(idx, name) required[STRINGIFY (name)] = 1;
%define DB_LOOKUP_NAME_TH_UNIQUE(idx, name) th_unique[STRINGIFY (name)] = 1; %define DB_LOOKUP_NAME_TH_UNIQUE(idx, name) th_unique[STRINGIFY (name)] = 1;
%include "db-symbols.h" %include "db-symbols.h"

View File

@ -21,6 +21,7 @@
#include <stdint.h> #include <stdint.h>
#include "thread_dbP.h" #include "thread_dbP.h"
#include <tls.h> #include <tls.h>
#include <ldsodefs.h>
typedef struct pthread pthread; typedef struct pthread pthread;
typedef struct pthread_key_struct pthread_key_struct; typedef struct pthread_key_struct pthread_key_struct;
@ -37,6 +38,9 @@ typedef struct
} dtv; } dtv;
typedef struct link_map link_map; 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. */ /* Actually static in nptl/init.c, but we only need it for typeof. */
extern bool __nptl_initial_report_events; extern bool __nptl_initial_report_events;

View File

@ -69,7 +69,8 @@ _td_locate_field (td_thragent_t *ta,
} }
} }
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 /* This is an internal indicator to callers with nonzero IDX
that the IDX value is too big. */ that the IDX value is too big. */
return TD_NOAPLIC; return TD_NOAPLIC;

View File

@ -22,6 +22,28 @@
# define STRUCTS_DEF_DEFAULTS 1 # define STRUCTS_DEF_DEFAULTS 1
#endif #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 (pthread)
DB_STRUCT_FIELD (pthread, list) DB_STRUCT_FIELD (pthread, list)
DB_STRUCT_FIELD (pthread, report_events) DB_STRUCT_FIELD (pthread, report_events)
@ -70,14 +92,31 @@ DB_STRUCT (pthread_key_data_level2)
DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data) DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data)
DB_STRUCT_FIELD (link_map, l_tls_modid) DB_STRUCT_FIELD (link_map, l_tls_modid)
DB_STRUCT_FIELD (link_map, l_tls_offset)
DB_STRUCT_ARRAY_FIELD (dtv, dtv) DB_STRUCT_ARRAY_FIELD (dtv, dtv)
#define pointer_val pointer.val /* Field of anonymous struct in dtv_t. */ #define pointer_val pointer.val /* Field of anonymous struct in dtv_t. */
DB_STRUCT_FIELD (dtv_t, pointer_val) DB_STRUCT_FIELD (dtv_t, pointer_val)
DB_STRUCT_FIELD (dtv_t, counter)
#if !IS_IN (libpthread) || TLS_TCB_AT_TP #if !IS_IN (libpthread) || TLS_TCB_AT_TP
DB_STRUCT_FIELD (pthread, dtvp) DB_STRUCT_FIELD (pthread, dtvp)
#endif #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 #ifdef STRUCTS_DEF_DEFAULTS
# undef DB_STRUCT_ARRAY_FIELD # undef DB_STRUCT_ARRAY_FIELD
# undef DB_ARRAY_VARIABLE # undef DB_ARRAY_VARIABLE

View File

@ -18,7 +18,6 @@
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#include <assert.h> #include <assert.h>
#include <gnu/lib-names.h>
#include "thread_dbP.h" #include "thread_dbP.h"
static const char *symbol_list_arr[] = static const char *symbol_list_arr[] =
@ -41,12 +40,12 @@ td_symbol_list (void)
ps_err_e 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; ps_err_e result;
assert (idx >= 0 && idx < SYM_NUM_MESSAGES); assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], result = ps_pglobal_lookup (ps, mod, symbol_list_arr[idx], sym_addr);
sym_addr);
return result; return result;
} }

View File

@ -17,14 +17,118 @@
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#include "thread_dbP.h" #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_err_e
td_thr_tlsbase (const td_thrhandle_t *th, td_thr_tlsbase (const td_thrhandle_t *th,
unsigned long int modid, unsigned long int modid,
psaddr_t *base) psaddr_t *base)
{ {
td_err_e err; td_err_e err;
psaddr_t dtv, dtvslot, dtvptr; psaddr_t dtv, dtvslot, dtvptr, temp;
if (modid < 1) if (modid < 1)
return TD_NOTLS; return TD_NOTLS;
@ -50,11 +154,75 @@ td_thr_tlsbase (const td_thrhandle_t *th,
return TD_TLSDEFER; 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. */ /* Get the DTV pointer from the thread descriptor. */
err = DB_GET_FIELD (dtv, th->th_ta_p, pd, pthread, dtvp, 0); err = DB_GET_FIELD (dtv, th->th_ta_p, pd, pthread, dtvp, 0);
if (err != TD_OK) if (err != TD_OK)
return err; 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. */ /* Find the corresponding entry in the DTV. */
err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid); err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid);
if (err != TD_OK) if (err != TD_OK)
@ -68,7 +236,7 @@ td_thr_tlsbase (const td_thrhandle_t *th,
/* It could be that the memory for this module is not allocated for /* It could be that the memory for this module is not allocated for
the given thread. */ the given thread. */
if ((uintptr_t) dtvptr & 1) if ((uintptr_t) dtvptr & 1)
return TD_TLSDEFER; goto try_static_tls;
*base = dtvptr; *base = dtvptr;
return TD_OK; return TD_OK;

View File

@ -29,6 +29,7 @@
#include "thread_db.h" #include "thread_db.h"
#include "../nptl/pthreadP.h" /* This is for *_BITMASK only. */ #include "../nptl/pthreadP.h" /* This is for *_BITMASK only. */
#include <list.h> #include <list.h>
#include <gnu/lib-names.h>
/* Indeces for the symbol names. */ /* Indeces for the symbol names. */
enum enum
@ -139,11 +140,11 @@ ta_ok (const td_thragent_t *ta)
} }
/* Internal wrapper around ps_pglobal_lookup. */ /* Internal wrappers around ps_pglobal_lookup. */
extern ps_err_e td_lookup (struct ps_prochandle *ps, extern ps_err_e td_mod_lookup (struct ps_prochandle *ps, const char *modname,
int idx, psaddr_t *sym_addr) attribute_hidden; 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. */ /* Store in psaddr_t VAR the address of inferior's symbol NAME. */