mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-24 14:00:30 +00:00
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:
parent
b97eb2bdb1
commit
f8aeae3473
47
ChangeLog
47
ChangeLog
@ -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
11
NEWS
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
63
elf/dl-tls.c
63
elf/dl-tls.c
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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. */
|
||||||
|
Loading…
Reference in New Issue
Block a user