Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* elf/tst-tls-dlinfo.c: New file.
	* elf/Makefile (tests): Add it.
	($(objpfx)tst-tls-dlinfo): Depend on $(libdl).
	($(objpfx)tst-tls-dlinfo.out): Depend on $(objpfx)tst-tlsmod2.so.

	* dlfcn/dlfcn.h (RTLD_DI_PROFILENAME, RTLD_DI_PROFILEOUT): New enum
	values, reserve unsupported requested names used on Solaris.
	(RTLD_DI_TLS_MODID, RTLD_DI_TLS_DATA): New enum values.
	(RTLD_DI_MAX): Likewise.
	* dlfcn/dlinfo.c (dlinfo_doit): Handle RTLD_DI_TLS_MODID and
	RTLD_DI_TLS_DATA.

	* elf/dl-tls.c (_dl_tls_get_addr_soft): New function.
	* sysdeps/generic/ldsodefs.h: Declare it.
	* elf/Versions (ld: GLIBC_PRIVATE): Add it.
	* elf/link.h (struct dl_phdr_info): New members dlpi_tls_modid,
	dlpi_tls_data.
	* elf/dl-iteratephdr.c (__dl_iterate_phdr): Fill them in.

	* include/link.h: Don't copy contents from elf/link.h.
	Instead, #include it while #define'ing around link_map.
	* elf/dl-debug.c (_dl_debug_initialize): Add a cast.
	Add bogus extern decl to verify link_map members.
	* elf/loadtest.c (MAPS): New macro, cast _r_debug._r_map.
	(OUT, main): Use it in place of _r_debug._r_map.
	* elf/unload.c: Likewise.
	* elf/unload2.c: Likewise.
	* elf/neededtest.c (check_loaded_objects): Likewise.
	* elf/neededtest2.c (check_loaded_objects): Likewise.
	* elf/neededtest3.c (check_loaded_objects): Likewise.
	* elf/neededtest4.c (check_loaded_objects): Likewise.
	* elf/circleload1.c (check_loaded_objects): Likewise.
  • Loading branch information
Roland McGrath committed Mar 1, 2006
1 parent 0b890d5 commit d78efd9
Show file tree
Hide file tree
Showing 20 changed files with 312 additions and 135 deletions.
33 changes: 33 additions & 0 deletions ChangeLog
@@ -1,5 +1,38 @@
2006-02-28 Roland McGrath <roland@redhat.com>

* elf/tst-tls-dlinfo.c: New file.
* elf/Makefile (tests): Add it.
($(objpfx)tst-tls-dlinfo): Depend on $(libdl).
($(objpfx)tst-tls-dlinfo.out): Depend on $(objpfx)tst-tlsmod2.so.

* dlfcn/dlfcn.h (RTLD_DI_PROFILENAME, RTLD_DI_PROFILEOUT): New enum
values, reserve unsupported requested names used on Solaris.
(RTLD_DI_TLS_MODID, RTLD_DI_TLS_DATA): New enum values.
(RTLD_DI_MAX): Likewise.
* dlfcn/dlinfo.c (dlinfo_doit): Handle RTLD_DI_TLS_MODID and
RTLD_DI_TLS_DATA.

* elf/dl-tls.c (_dl_tls_get_addr_soft): New function.
* sysdeps/generic/ldsodefs.h: Declare it.
* elf/Versions (ld: GLIBC_PRIVATE): Add it.
* elf/link.h (struct dl_phdr_info): New members dlpi_tls_modid,
dlpi_tls_data.
* elf/dl-iteratephdr.c (__dl_iterate_phdr): Fill them in.

* include/link.h: Don't copy contents from elf/link.h.
Instead, #include it while #define'ing around link_map.
* elf/dl-debug.c (_dl_debug_initialize): Add a cast.
Add bogus extern decl to verify link_map members.
* elf/loadtest.c (MAPS): New macro, cast _r_debug._r_map.
(OUT, main): Use it in place of _r_debug._r_map.
* elf/unload.c: Likewise.
* elf/unload2.c: Likewise.
* elf/neededtest.c (check_loaded_objects): Likewise.
* elf/neededtest2.c (check_loaded_objects): Likewise.
* elf/neededtest3.c (check_loaded_objects): Likewise.
* elf/neededtest4.c (check_loaded_objects): Likewise.
* elf/circleload1.c (check_loaded_objects): Likewise.

* nscd/nscd_helper.c: Include <time.h> for `time' declaration.

* include/fcntl.h: Declare __openat, __open64. Use libc_hidden_proto.
Expand Down
21 changes: 19 additions & 2 deletions dlfcn/dlfcn.h
@@ -1,5 +1,6 @@
/* User functions for run-time dynamic loading.
Copyright (C) 1995-1999,2000,2001,2003,2004 Free Software Foundation, Inc.
Copyright (C) 1995-1999,2000,2001,2003,2004,2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -135,6 +136,8 @@ enum
store the `struct link_map *' for HANDLE there. */
RTLD_DI_LINKMAP = 2,

RTLD_DI_CONFIGADDR = 3, /* Unsupported, defined by Solaris. */

/* Treat ARG as `Dl_serinfo *' (see below), and fill in to describe the
directories that will be searched for dependencies of this object.
RTLD_DI_SERINFOSIZE fills in just the `dls_cnt' and `dls_size'
Expand All @@ -147,7 +150,21 @@ enum
expand $ORIGIN in this shared object's dependency file names. */
RTLD_DI_ORIGIN = 6,

RTLD_DI_CONFIGADDR = 3 /* Unsupported, defined by Solaris. */
RTLD_DI_PROFILENAME = 7, /* Unsupported, defined by Solaris. */
RTLD_DI_PROFILEOUT = 8, /* Unsupported, defined by Solaris. */

/* Treat ARG as `size_t *', and store there the TLS module ID
of this object's PT_TLS segment, as used in TLS relocations;
store zero if this object does not define a PT_TLS segment. */
RTLD_DI_TLS_MODID = 9,

/* Treat ARG as `void **', and store there a pointer to the calling
thread's TLS block corresponding to this object's PT_TLS segment.
Store a null pointer if this object does not define a PT_TLS
segment, or if the calling thread has not allocated a block for it. */
RTLD_DI_TLS_DATA = 10,

RTLD_DI_MAX = 10,
};


Expand Down
24 changes: 23 additions & 1 deletion dlfcn/dlinfo.c
@@ -1,5 +1,5 @@
/* dlinfo -- Get information from the dynamic linker.
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -32,6 +32,10 @@ dlinfo (void *handle, int request, void *arg)

#else

# ifdef USE_TLS
# include <dl-tls.h>
# endif

struct dlinfo_args
{
ElfW(Addr) caller;
Expand Down Expand Up @@ -90,6 +94,24 @@ RTLD_SELF used in code not dynamically loaded"));
case RTLD_DI_ORIGIN:
strcpy (args->arg, l->l_origin);
break;

case RTLD_DI_TLS_MODID:
*(size_t *) args->arg = 0;
#ifdef USE_TLS
*(size_t *) args->arg = l->l_tls_modid;
#endif
break;

case RTLD_DI_TLS_DATA:
{
void *data = NULL;
#ifdef USE_TLS
if (l->l_tls_modid != 0)
data = _dl_tls_get_addr_soft (l);
#endif
*(void **) args->arg = data;
break;
}
}
}

Expand Down
13 changes: 10 additions & 3 deletions elf/Makefile
Expand Up @@ -163,9 +163,11 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
neededtest3 neededtest4 unload2 lateglobal initfirst global \
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 tst-align \
tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
tst-tls-dlinfo \
tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
tst-dlmodcount tst-dlopenrpath tst-deep1 \
tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
unload3 unload4 unload5 unload6 tst-audit1 tst-global1 order2 \
tst-stackguard1
# reldep9
Expand Down Expand Up @@ -700,6 +702,11 @@ $(objpfx)tst-tls14.out: $(objpfx)tst-tlsmod14b.so
$(objpfx)tst-tls15: $(libdl)
$(objpfx)tst-tls15.out: $(objpfx)tst-tlsmod15a.so $(objpfx)tst-tlsmod15b.so

$(objpfx)tst-tls-dlinfo: $(libdl)
$(objpfx)tst-tls-dlinfo.out: $(objpfx)tst-tlsmod2.so



CFLAGS-tst-align.c = $(stack-align-test-flags)
CFLAGS-tst-align2.c = $(stack-align-test-flags)
CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
Expand Down
1 change: 1 addition & 0 deletions elf/Versions
Expand Up @@ -57,6 +57,7 @@ ld {
_dl_allocate_tls; _dl_deallocate_tls;
_dl_get_tls_static_info; _dl_allocate_tls_init;
_dl_tls_setup; _dl_rtld_di_serinfo;
_dl_tls_get_addr_soft;
_dl_make_stack_executable;
# Only here for gdb while a better method is developed.
_dl_debug_state;
Expand Down
4 changes: 3 additions & 1 deletion elf/circleload1.c
Expand Up @@ -5,6 +5,8 @@
#include <stdlib.h>
#include <string.h>

#define MAPS ((struct link_map *) _r_debug.r_map)

static int
check_loaded_objects (const char **loaded)
{
Expand All @@ -24,7 +26,7 @@ check_loaded_objects (const char **loaded)

printf(" Name\n");
printf(" --------------------------------------------------------\n");
for (lm = _r_debug.r_map; lm; lm = lm->l_next)
for (lm = MAPS; lm; lm = lm->l_next)
{
if (lm->l_name && lm->l_name[0])
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
Expand Down
17 changes: 15 additions & 2 deletions elf/dl-debug.c
@@ -1,5 +1,6 @@
/* Communicate dynamic linker state to the debugger at runtime.
Copyright (C) 1996, 1998,2000,2002,2004,2005 Free Software Foundation, Inc.
Copyright (C) 1996, 1998,2000,2002,2004,2005,2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Expand All @@ -19,6 +20,18 @@

#include <ldsodefs.h>


/* These are the members in the public `struct link_map' type.
Sanity check that the internal type and the public type match. */
#define VERIFY_MEMBER(name) \
(offsetof (struct link_map_public, name) == offsetof (struct link_map, name))
extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
&& VERIFY_MEMBER (l_name)
&& VERIFY_MEMBER (l_ld)
&& VERIFY_MEMBER (l_next)
&& VERIFY_MEMBER (l_prev))
? 1 : -1];

/* This structure communicates dl state to the debugger. The debugger
normally finds it via the DT_DEBUG entry in the dynamic section, but in
a statically-linked program there is no dynamic section for the debugger
Expand Down Expand Up @@ -46,7 +59,7 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
/* Tell the debugger where to find the map of loaded objects. */
r->r_version = 1 /* R_DEBUG_VERSION XXX */;
r->r_ldbase = ldbase ?: _r_debug.r_ldbase;
r->r_map = GL(dl_ns)[ns]._ns_loaded;
r->r_map = (void *) GL(dl_ns)[ns]._ns_loaded;
r->r_brk = (ElfW(Addr)) &_dl_debug_state;
}

Expand Down
9 changes: 8 additions & 1 deletion elf/dl-iteratephdr.c
@@ -1,5 +1,5 @@
/* Get loaded objects program headers.
Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2001,2002,2003,2004,2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
Expand Down Expand Up @@ -68,6 +68,13 @@ __dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
info.dlpi_phnum = l->l_phnum;
info.dlpi_adds = GL(dl_load_adds);
info.dlpi_subs = GL(dl_load_adds) - nloaded;
info.dlpi_tls_modid = 0;
info.dlpi_tls_data = NULL;
#ifdef USE_TLS
info.dlpi_tls_modid = l->l_tls_modid;
if (info.dlpi_tls_modid != 0)
info.dlpi_tls_data = _dl_tls_get_addr_soft (l);
#endif
ret = callback (&info, sizeof (struct dl_phdr_info), data);
if (ret)
break;
Expand Down
48 changes: 46 additions & 2 deletions elf/dl-tls.c
@@ -1,5 +1,5 @@
/* Thread-local storage handling in the ELF dynamic linker. Generic version.
Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2002,2003,2004,2005,2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -735,9 +735,53 @@ __tls_get_addr (GET_ADDR_ARGS)
# endif


/* Look up the module's TLS block as for __tls_get_addr,
but never touch anything. Return null if it's not allocated yet. */
void *
internal_function
_dl_tls_get_addr_soft (struct link_map *l)
{
if (__builtin_expect (l->l_tls_modid == 0, 0))
/* This module has no TLS segment. */
return NULL;

dtv_t *dtv = THREAD_DTV ();
if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
{
/* This thread's DTV is not completely current,
but it might already cover this module. */

if (l->l_tls_modid >= dtv[-1].counter)
/* Nope. */
return NULL;

size_t idx = l->l_tls_modid;
struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
while (idx >= listp->len)
{
idx -= listp->len;
listp = listp->next;
}

/* We've reached the slot for this module.
If its generation counter is higher than the DTV's,
this thread does not know about this module yet. */
if (dtv[0].counter < listp->slotinfo[idx].gen)
return NULL;
}

void *data = dtv[l->l_tls_modid].pointer.val;
if (__builtin_expect (data == TLS_DTV_UNALLOCATED, 0))
/* The DTV is current, but this thread has not yet needed
to allocate this module's segment. */
data = NULL;

return data;
}


void
_dl_add_to_slotinfo (struct link_map *l)
_dl_add_to_slotinfo (struct link_map *l)
{
/* Now that we know the object is loaded successfully add
modules containing TLS data to the dtv info table. We
Expand Down
18 changes: 13 additions & 5 deletions elf/link.h
@@ -1,6 +1,6 @@
/* Data structure for communication from the run-time dynamic linker for
loaded ELF shared objects.
Copyright (C) 1995-2001, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 1995-2001, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -135,23 +135,31 @@ enum
la_symbind call. */
};


struct dl_phdr_info
{
ElfW(Addr) dlpi_addr;
const char *dlpi_name;
const ElfW(Phdr) *dlpi_phdr;
ElfW(Half) dlpi_phnum;

/* Note: the next two members were introduced after the first
/* Note: Following members were introduced after the first
version of this structure was available. Check the SIZE
argument passed to the dl_iterate_phdr() callback to determine
whether or not they are provided. */
argument passed to the dl_iterate_phdr callback to determine
whether or not each later member is available. */

/* Incremented when a new object may have been added. */
unsigned long long int dlpi_adds;
/* Incremented when an object may have been removed. */
unsigned long long int dlpi_subs;

/* If there is a PT_TLS segment, its module ID as used in
TLS relocations, else zero. */
size_t dlpi_tls_modid;

/* The address of the calling thread's instance of this module's
PT_TLS segment, if it has one and it has been allocated
in the calling thread, otherwise a null pointer. */
void *dlpi_tls_data;
};

__BEGIN_DECLS
Expand Down
8 changes: 5 additions & 3 deletions elf/loadtest.c
Expand Up @@ -70,8 +70,10 @@ static const struct

#include <include/link.h>

#define MAPS ((struct link_map *) _r_debug.r_map)

#define OUT \
for (map = _r_debug.r_map; map != NULL; map = map->l_next) \
for (map = MAPS; map != NULL; map = map->l_next) \
if (map->l_type == lt_loaded) \
printf ("name = \"%s\", direct_opencount = %d\n", \
map->l_name, (int) map->l_direct_opencount); \
Expand Down Expand Up @@ -147,7 +149,7 @@ main (int argc, char *argv[])
{
/* In this case none of the objects above should be
present. */
for (map = _r_debug.r_map; map != NULL; map = map->l_next)
for (map = MAPS; map != NULL; map = map->l_next)
if (map->l_type == lt_loaded
&& (strstr (map->l_name, testobjs[0].name) != NULL
|| strstr (map->l_name, testobjs[1].name) != NULL
Expand Down Expand Up @@ -180,7 +182,7 @@ main (int argc, char *argv[])
}

/* Check whether all files are unloaded. */
for (map = _r_debug.r_map; map != NULL; map = map->l_next)
for (map = MAPS; map != NULL; map = map->l_next)
if (map->l_type == lt_loaded)
{
printf ("name = \"%s\", direct_opencount = %d\n",
Expand Down
4 changes: 3 additions & 1 deletion elf/neededtest.c
Expand Up @@ -5,6 +5,8 @@
#include <stdlib.h>
#include <string.h>

#define MAPS ((struct link_map *) _r_debug.r_map)

static int
check_loaded_objects (const char **loaded)
{
Expand All @@ -24,7 +26,7 @@ check_loaded_objects (const char **loaded)

printf(" Name\n");
printf(" --------------------------------------------------------\n");
for (lm = _r_debug.r_map; lm; lm = lm->l_next)
for (lm = MAPS; lm; lm = lm->l_next)
{
if (lm->l_name && lm->l_name[0])
printf(" %s, count = %d\n", lm->l_name, (int) lm->l_direct_opencount);
Expand Down

0 comments on commit d78efd9

Please sign in to comment.