aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elf/dl-misc.c31
-rw-r--r--elf/dl-tls.c159
-rw-r--r--elf/rtld.c2
-rw-r--r--sysdeps/generic/ldsodefs.h5
4 files changed, 189 insertions, 8 deletions
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index ec70298..ed90394 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -81,7 +81,10 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
struct iovec iov[NIOVMAX];
int niov = 0;
pid_t pid = 0;
- char pidbuf[12];
+ char pidbuf[23];
+ pid_t tid = 0;
+ /* Start with a known bad value, should never get used. */
+ char *tag_start = NULL;
while (*fmt != '\0')
{
@@ -93,20 +96,32 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
colon followed by a tab. */
if (pid == 0)
{
- char *p;
+ char *p = &pidbuf[21];
+
pid = __getpid ();
assert (pid >= 0 && sizeof (pid_t) <= 4);
- p = _itoa (pid, &pidbuf[10], 10, 0);
- while (p > pidbuf)
+
+ /* If we are doing thread-related output, maybe add a thread id,
+ taking care that pid continues to appear at the same
+ positions. */
+ tid = _dl_tls_tid ();
+ if (tid > 0)
+ {
+ p = _itoa (tid, p, 10, 0);
+ *--p = '/';
+ }
+ tag_start = p - 10;
+ p = _itoa (pid, p, 10, 0);
+ while (p > tag_start)
*--p = ' ';
- pidbuf[10] = ':';
- pidbuf[11] = '\t';
+ pidbuf[21] = ':';
+ pidbuf[22] = '\t';
}
/* Append to the output. */
assert (niov < NIOVMAX);
- iov[niov].iov_len = 12;
- iov[niov++].iov_base = pidbuf;
+ iov[niov].iov_len = &(pidbuf[23]) - tag_start;
+ iov[niov++].iov_base = tag_start;
/* No more tags until we see the next newline. */
tag_p = -1;
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 67198f7..592512f 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -30,6 +30,8 @@
#include <dl-tls.h>
#include <ldsodefs.h>
+static void _dl_print_dtv(const char *msg, dtv_t *dtv, int numentries);
+
/* Amount of excess space to allocate in the static TLS area
to allow dynamic loading of modules defining IE-model TLS data. */
#define TLS_STATIC_SURPLUS 64 + DL_NNS * 100
@@ -428,6 +430,13 @@ _dl_resize_dtv (dtv_t *dtv)
memset (newp + 2 + oldsize, '\0',
(newsize - oldsize) * sizeof (dtv_t));
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("Resized dtv 0x%0*Zx, size %lu, to dtv 0x%0*Zx, size %lu\n",
+ (int) sizeof (void *) * 2, (unsigned long int) dtv,
+ oldsize,
+ (int) sizeof (void *) * 2, (unsigned long int) &newp[1],
+ newsize);
+
/* Return the generation counter. */
return &newp[1];
}
@@ -484,6 +493,12 @@ _dl_allocate_tls_init (void *result)
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[map->l_tls_modid].pointer.to_free = NULL;
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("_dl_allocate_tls_init unallocates %sdtv 0x%0*Zx module %lu\n",
+ (dtv == THREAD_DTV () ? "own " : ""),
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ map->l_tls_modid);
if (map->l_tls_offset == NO_TLS_OFFSET
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
@@ -503,6 +518,14 @@ _dl_allocate_tls_init (void *result)
/* Set up the DTV entry. The simplified __tls_get_addr that
some platforms use in static programs requires it. */
dtv[map->l_tls_modid].pointer.val = dest;
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("_dl_allocate_tls_init sets %sdtv 0x%0*Zx module %lu to 0x%0*Zx\n",
+ (dtv == THREAD_DTV () ? "own " : ""),
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ map->l_tls_modid,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dest);
/* Copy the initialization image and clear the BSS part. */
memset (__mempcpy (dest, map->l_tls_initimage,
@@ -521,6 +544,9 @@ _dl_allocate_tls_init (void *result)
/* The DTV version is up-to-date now. */
dtv[0].counter = maxgen;
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_print_dtv ("_dl_allocate_tls_init return ", dtv, 10);
+
return result;
}
rtld_hidden_def (_dl_allocate_tls_init)
@@ -655,6 +681,12 @@ _dl_update_slotinfo (unsigned long int req_modid)
struct link_map *the_map = NULL;
dtv_t *dtv = THREAD_DTV ();
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ // (should mention module name?)
+ _dl_debug_printf ("Updating slot info for own dtv 0x%0*Zx module %lu\n",
+ (int) sizeof (void *) * 2, (unsigned long int) dtv,
+ req_modid);
+
/* The global dl_tls_dtv_slotinfo array contains for each module
index the generation counter current when the entry was created.
This array never shrinks so that all module indices which were
@@ -698,6 +730,11 @@ _dl_update_slotinfo (unsigned long int req_modid)
if (dtv[0].counter >= listp->slotinfo[idx].gen)
{
_dl_unmask_signals (&old);
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("Slot info update for own dtv 0x%0*Zx module %lu done, exiting early\n",
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ req_modid);
return the_map;
}
}
@@ -728,6 +765,13 @@ _dl_update_slotinfo (unsigned long int req_modid)
{
/* If this modid was used at some point the memory
might still be allocated. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("Slot info update for own dtv 0x%0*Zx module %lu unallocating 0x%0*Zx\n",
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ total + cnt,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[total + cnt].pointer.val);
__signal_safe_free (dtv[total + cnt].pointer.to_free);
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
dtv[total + cnt].pointer.to_free = NULL;
@@ -755,6 +799,13 @@ _dl_update_slotinfo (unsigned long int req_modid)
dtv entry free it. */
/* XXX Ideally we will at some point create a memory
pool. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("Slot info update for own dtv 0x%0*Zx module %lu unallocating 0x%0*Zx\n",
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ modid,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[modid].pointer.val);
__signal_safe_free (dtv[modid].pointer.to_free);
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[modid].pointer.to_free = NULL;
@@ -796,6 +847,15 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
the_map = listp->slotinfo[idx].map;
}
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ {
+ char *map_name = (the_map->l_name ? the_map->l_name : "no name");
+ _dl_debug_printf ("tls_get_addr_tail entry, own dtv 0x%0*Zx module %lu (%s) pointer.val = 0x%0*Zx\n",
+ (int) sizeof (void *) * 2, (unsigned long int) dtv,
+ GET_ADDR_MODULE, map_name,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[GET_ADDR_MODULE].pointer.val);
+ }
if (!GLRO(dl_async_signal_safe)) {
@@ -826,6 +886,13 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
dtv[GET_ADDR_MODULE].pointer.val = p;
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("tls_get_addr_tail sets own dtv 0x%0*Zx module %lu pointer.val to 0x%0*Zx, returns\n",
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ GET_ADDR_MODULE,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) p);
return (char *) p + GET_ADDR_OFFSET;
}
@@ -835,6 +902,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
struct dtv_pointer result = allocate_and_init (the_map);
dtv[GET_ADDR_MODULE].pointer = result;
assert (result.to_free != NULL);
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("tls_get_addr_tail sets own dtv 0x%0*Zx module %lu pointer.val to 0x%0*Zx, returns\n",
+ (int) sizeof (void *) * 2, (unsigned long int) dtv,
+ GET_ADDR_MODULE,
+ (int) sizeof (void *) * 2, (unsigned long int) result.val);
return (char *) result.val + GET_ADDR_OFFSET;
@@ -849,6 +921,9 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
{
_dl_unmask_signals (&old);
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("tls_get_addr_tail keeps own dtv pointer.val, returns\n");
+
return (char *) dtv[GET_ADDR_MODULE].pointer.val + GET_ADDR_OFFSET;
}
@@ -874,10 +949,22 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
if (offset == FORCED_DYNAMIC_TLS_OFFSET)
{
signal_safe_allocate_and_init (&dtv[GET_ADDR_MODULE], the_map);
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("tls_get_addr_tail allocates own dtv 0x%0*Zx module %lu pointer.val = 0x%0*Zx\n",
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ GET_ADDR_MODULE,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[GET_ADDR_MODULE].pointer.val);
}
else
{
void ** volatile pp = &dtv[GET_ADDR_MODULE].pointer.val;
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("tls_get_addr_tail waiting for own dtv 0x%0*Zx module %lu to be allocated\n",
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ GET_ADDR_MODULE);
while (atomic_forced_read (*pp) == TLS_DTV_UNALLOCATED)
{
/* for lack of a better (safe) thing to do, just spin.
@@ -893,6 +980,13 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
init_one_static_tls, guaranteeing that we see their write of
the tls_initimage into the static region. */
atomic_read_barrier ();
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ _dl_debug_printf ("tls_get_addr_tail sees own dtv 0x%0*Zx module %lu has pointer.val = 0x%0*Zx\n",
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv,
+ GET_ADDR_MODULE,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[GET_ADDR_MODULE].pointer.val);
}
assert (dtv[GET_ADDR_MODULE].pointer.val != TLS_DTV_UNALLOCATED);
_dl_unmask_signals (&old);
@@ -1052,3 +1146,68 @@ cannot create TLS data structures"));
listp->slotinfo[idx].map = l;
listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
}
+
+/* Return a thread id of the current thread if we are debugging tls and the
+ value is meaningful. */
+
+pid_t
+_dl_tls_tid (void)
+{
+ if (!__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_TLS))
+ return 0;
+
+#ifdef SHARED
+ if (GL(dl_initial_dtv) == NULL)
+ return 0;
+#endif
+
+ struct pthread *thr = THREAD_SELF;
+
+ return thr->tid;
+}
+
+/* Print all or part of a dtv. Note that the output may be large; for instance
+ nptl/tst-stack4 has dtv's with hundreds of entries. */
+
+static void
+_dl_print_dtv (const char *msg, dtv_t *dtv, int numentries)
+{
+ size_t cnt, last_used, num_to_print, i;
+
+ cnt = dtv[-1].counter;
+ last_used = 0;
+ for (i = 1; i <= cnt; ++i)
+ {
+ if (dtv[i].pointer.val || dtv[i].pointer.to_free)
+ last_used = i;
+ }
+ num_to_print = last_used;
+ if (numentries >= 0 && numentries < num_to_print)
+ num_to_print = numentries;
+ _dl_debug_printf ("%sdtv 0x%0*Zx has %lu used of %lu entries, generation %lu\n",
+ msg,
+ (int) sizeof (void *) * 2, (unsigned long int) dtv,
+ last_used, cnt, dtv[0].counter);
+ for (i = 1; i <= num_to_print; ++i)
+ {
+ if (dtv[i].pointer.to_free == dtv[i].pointer.val)
+ _dl_debug_printf ("%*lu: pointer.val = 0x%0*Zx to_free = same\n",
+ 4, i,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[i].pointer.val);
+ else if (dtv[i].pointer.to_free)
+ _dl_debug_printf ("%*lu: pointer.val = 0x%0*Zx to_free = 0x%0*Zx\n",
+ 4, i,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[i].pointer.val,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[i].pointer.to_free);
+ else
+ _dl_debug_printf ("%*lu: pointer.val = 0x%0*Zx\n",
+ 4, i,
+ (int) sizeof (void *) * 2,
+ (unsigned long int) dtv[i].pointer.val);
+ }
+ if (num_to_print < last_used)
+ _dl_debug_printf (" [...]\n");
+}
diff --git a/elf/rtld.c b/elf/rtld.c
index 8071e2f..498d9f5 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2395,6 +2395,8 @@ process_dl_debug (const char *dl_debug)
DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS },
{ LEN_AND_STR ("scopes"), "display scope information",
DL_DEBUG_SCOPES },
+ { LEN_AND_STR ("tls"), "display thread-local storage processing",
+ DL_DEBUG_TLS },
{ LEN_AND_STR ("fastload"), "display fastload information",
DL_DEBUG_FASTLOAD },
{ LEN_AND_STR ("all"), "all previous options combined",
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 32647f8..0495f85 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -500,6 +500,8 @@ struct rtld_global_ro
/* Google-local. */
#define DL_DEBUG_FASTLOAD (1 << 12)
+#define DL_DEBUG_TLS (1 << 13)
+
/* OS version. */
EXTERN unsigned int _dl_osversion;
/* Platform name. */
@@ -1196,6 +1198,9 @@ extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid)
but never touch anything. Return null if it's not allocated yet. */
extern void *_dl_tls_get_addr_soft (struct link_map *l) attribute_hidden;
+/* Return an id for the current thread if possible, otherwise 0. */
+extern pid_t _dl_tls_tid (void) attribute_hidden;
+
extern int _dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
attribute_hidden;