From patchwork Thu Nov 20 06:48:31 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Oliva X-Patchwork-Id: 3809 Received: (qmail 15761 invoked by alias); 20 Nov 2014 06:48:55 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 15749 invoked by uid 89); 20 Nov 2014 06:48:54 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, SPF_HELO_PASS, SPF_PASS, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx1.redhat.com From: Alexandre Oliva To: Roland McGrath Cc: libc-alpha@sourceware.org Subject: Re: [BZ#17090/17620/17621]: fix DTV race, assert, and DTV_SURPLUS Static TLS limit References: <20141118203338.ECA5F2C3B25@topped-with-meat.com> <20141118224048.600312C3B23@topped-with-meat.com> <20141120021703.86F032C3B18@topped-with-meat.com> Date: Thu, 20 Nov 2014 04:48:31 -0200 In-Reply-To: <20141120021703.86F032C3B18@topped-with-meat.com> (Roland McGrath's message of "Wed, 19 Nov 2014 18:17:03 -0800 (PST)") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 On Nov 20, 2014, Roland McGrath wrote: >> - special-case the _dl_tls_dtv_slotinfo_list lookup so that we can find >> it both as a member of _rtld_global, defined in ld.so, and as a >> stand-alone symbol defined in the main static executable. > I wouldn't really call this a special case. It's easy enough to extend the > DB_SYMBOL macro, db-symbols.h, and td_symbol_list.c to distinguish the > object name for different symbols. Then _rtld_global is a symbol like any > other (but for LD_SO instead of LIBPTHREAD_SO). The td_thr_tlsbase code > can just look for _rtld_global first and if it doesn't find that, look for > _dl_tls_dtv_slotinfo_list instead. > This seems like the right thing to do. Thanks. How about this, WRT the nptl_db new internal interfaces? (now I gotta figure out how to test that the dtv-handling code in nptl_db actually works :-) 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. (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. * 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. * 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. --- NEWS | 8 +- elf/dl-open.c | 12 --- elf/dl-reloc.c | 6 -- elf/dl-tls.c | 57 +++++++--------- nptl/allocatestack.c | 9 +- nptl_db/db-symbols.awk | 2 + nptl_db/db_info.c | 4 + nptl_db/structs.def | 39 +++++++++++ nptl_db/td_symbol_list.c | 10 +-- nptl_db/td_thr_tlsbase.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++ nptl_db/thread_dbP.h | 11 ++- 11 files changed, 256 insertions(+), 69 deletions(-) diff --git a/NEWS b/NEWS index 4b7eeb4..96d2ce1 100644 --- a/NEWS +++ b/NEWS @@ -9,10 +9,10 @@ Version 2.21 * The following bugs are resolved with this release: - 6652, 12926, 14132, 14138, 14171, 15215, 15884, 17266, 17344, 17363, - 17370, 17371, 17411, 17460, 17475, 17485, 17501, 17506, 17508, 17522, - 17555, 17570, 17571, 17572, 17573, 17574, 17582, 17583, 17584, 17585, - 17589, 17594, 17616, 17625. + 6652, 12926, 14132, 14138, 14171, 15215, 15884, 17090, 17266, 17344, + 17363, 17370, 17371, 17411, 17460, 17475, 17485, 17501, 17506, 17508, + 17522, 17555, 17570, 17571, 17572, 17573, 17574, 17582, 17583, 17584, + 17585, 17589, 17594, 17616, 17620, 17621, 17625, 17628. * CVE-2104-7817 The wordexp function could ignore the WRDE_NOCMD flag under certain input conditions resulting in the execution of a shell for diff --git a/elf/dl-open.c b/elf/dl-open.c index 7cc4cc1..9d6006b 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -531,17 +531,7 @@ TLS generation counter wrapped! Please report this.")); && 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 diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 97a7119..1d66f79 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -136,12 +136,6 @@ _dl_nothread_init_static_tls (struct link_map *map) # 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); diff --git a/elf/dl-tls.c b/elf/dl-tls.c index 5204fda..81b86f68 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -437,17 +437,14 @@ _dl_allocate_tls_init (void *result) 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); @@ -459,8 +456,6 @@ _dl_allocate_tls_init (void *result) #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); @@ -632,10 +627,9 @@ _dl_update_slotinfo (unsigned long int req_modid) 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; - } + free (dtv[total + cnt].pointer.val); + dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED; + dtv[total + cnt].pointer.is_static = false; continue; } @@ -698,10 +692,8 @@ _dl_update_slotinfo (unsigned long int req_modid) 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; @@ -739,13 +731,12 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) 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)) @@ -753,22 +744,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; __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; } diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index 8cf0274..8b053c1 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -1190,7 +1190,6 @@ __nptl_setxid (struct xid_command *cmdp) 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 @@ -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" # 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); } diff --git a/nptl_db/db-symbols.awk b/nptl_db/db-symbols.awk index f9a91b9..eb089e1 100644 --- 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" diff --git a/nptl_db/db_info.c b/nptl_db/db_info.c index 69cbcaa..807366b 100644 --- a/nptl_db/db_info.c +++ b/nptl_db/db_info.c @@ -21,6 +21,7 @@ #include #include "thread_dbP.h" #include +#include typedef struct pthread pthread; typedef struct pthread_key_struct pthread_key_struct; @@ -37,6 +38,9 @@ typedef struct } 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; diff --git a/nptl_db/structs.def b/nptl_db/structs.def index ec72ef1..8ad10b7 100644 --- 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 +# ifndef IS_IN_libpthread +# define DB_RTLD_GLOBAL_FIELD(field) \ + DB_STRUCT_FIELD (rtld_global, _##field) \ + DB_MAIN_VARIABLE (_##field) +# elif 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 (pthread_key_data_level2) 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 !defined IS_IN_libpthread || TLS_TCB_AT_TP DB_STRUCT_FIELD (pthread, dtvp) #endif +#if !(defined 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 diff --git a/nptl_db/td_symbol_list.c b/nptl_db/td_symbol_list.c index c637444..0f42976 100644 --- a/nptl_db/td_symbol_list.c +++ b/nptl_db/td_symbol_list.c @@ -18,7 +18,6 @@ . */ #include -#include #include "thread_dbP.h" static const char *symbol_list_arr[] = @@ -41,19 +40,18 @@ td_symbol_list (void) 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. We could be a 64-bit libthread_db debugging a 32-bit libpthread. */ if (result == PS_NOSYM && symbol_list_arr[idx][0] == '.') - result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, &symbol_list_arr[idx][1], - sym_addr); + result = ps_pglobal_lookup (ps, mod, &symbol_list_arr[idx][1], sym_addr); #endif return result; diff --git a/nptl_db/td_thr_tlsbase.c b/nptl_db/td_thr_tlsbase.c index 217df1f..0306630 100644 --- a/nptl_db/td_thr_tlsbase.c +++ b/nptl_db/td_thr_tlsbase.c @@ -17,14 +17,116 @@ . */ #include "thread_dbP.h" +#include +/* Get the slotinfo list from the dynamic loader state. */ +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 slotinfo entry for MODID. */ +static td_err_e +dtv_slotinfo (td_thragent_t *ta, + unsigned long int modid, + psaddr_t *dtvslotinfo) +{ + td_err_e err; + psaddr_t slot; + size_t slbase = 0; + + err = dtv_slotinfo_list (ta, &slot); + if (err != TD_OK) + return err; + + while (slot) + { + psaddr_t temp; + + /* 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 (slot, ta, slot, dtv_slotinfo_list, + next, 0); + if (err != TD_OK) + return err; + } + + /* 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 (slot, ta, slot, dtv_slotinfo_list, + slotinfo, modid - slbase); + if (err != TD_OK) + return err; + + *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 +152,74 @@ td_thr_tlsbase (const td_thrhandle_t *th, return TD_TLSDEFER; } + psaddr_t slot; + err = dtv_slotinfo (th->th_ta_p, modid, &slot); + 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[-1]. */ + err = DB_GET_FIELD_ADDRESS (dtvgenloc, th->th_ta_p, dtv, dtv, dtv, -1); + 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) + { + /* 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; + err = DB_GET_FIELD_ADDRESS (tp, th->th_ta_p, th->th_unique, + pthread, specific, 0); + if (err != TD_OK) + return err; + +#if TLS_TCB_AT_TP + tp += tlsoff; +#elif TLS_DTV_AT_TP + 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) diff --git a/nptl_db/thread_dbP.h b/nptl_db/thread_dbP.h index 66d6d90..e7fe12e 100644 --- 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 +#include /* Indeces for the symbol names. */ enum @@ -139,11 +140,11 @@ ta_ok (const td_thragent_t *ta) } -/* 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. */