mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 02:18:37 +00:00
To implement QGetTlsAddr, gdbsrv has to know how to get the glibc dtv address and the module id from the link_map. These 2 things are dependent on the internals of glibc. The dependency is mostly isolated in a few lines of arch dependent code or in an external utility that used a hack + -ldl lib to find the offset of the modid in the link_map structure. Tested on x86/amd64/ppc64/s390x. Somewhat tested on ppc32 and arm64. Untested/a few #ifdef-ed lines not compiled on arm/mips32/mips64 and darwin. For more background info about thread local storage handling, see 'ELF Handling For Thread-Local Storage' http://www.akkadia.org/drepper/tls.pdf Changes: * auxprogs/getoff.c new auxilliary program to get platform specific offsets (currently only the offset for the module id in struct link_map). * configure.ac : check for dlinfo(RTLD_DI_TLS_MODID) needed for getoff.c * new gdbserver_tests/hgtls, testing various types of __thread variables * various m_gdbserver files: - implement decoding of the QGetTlsAddr query - for each platform: platform specific code to get the dtv - call to external program getoff-<platform> the first time an __thread variable is printed. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14283
112 lines
1.8 KiB
C
112 lines
1.8 KiB
C
#include <config.h>
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
|
|
#ifdef HAVE_TLS
|
|
|
|
#define COUNT 10
|
|
|
|
static int race;
|
|
static __thread int local;
|
|
__thread int global;
|
|
extern __thread int static_extern;
|
|
extern __thread int so_extern;
|
|
|
|
/* deliberate failure */
|
|
static int *test_race(void)
|
|
{
|
|
return ∽̱
|
|
}
|
|
|
|
static int *test_local(void)
|
|
{
|
|
return &local;
|
|
}
|
|
|
|
static int *test_global(void)
|
|
{
|
|
return &global;
|
|
}
|
|
|
|
static int *test_static_extern(void)
|
|
{
|
|
return &static_extern;
|
|
}
|
|
|
|
static int *test_so_extern(void)
|
|
{
|
|
return &so_extern;
|
|
}
|
|
|
|
static const struct timespec awhile = { 0, 200000000 };
|
|
|
|
typedef int *(*func_t)(void);
|
|
struct testcase {
|
|
const char *name;
|
|
func_t func;
|
|
char pad[2 * (8 - sizeof(void*))];
|
|
};
|
|
static void *tls_ptr(void *p)
|
|
{
|
|
struct testcase *test = (struct testcase *)p;
|
|
int *ip = (*test->func)();
|
|
int here = 0;
|
|
int i;
|
|
|
|
for(i = 0; i < COUNT; i++) {
|
|
int a = (*ip)++;
|
|
int b = here++;
|
|
if (a != b)
|
|
printf("tls_ptr: case \"%s\" has mismatch: *ip=%d here=%d\n",
|
|
test->name, a, b);
|
|
nanosleep(&awhile, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int *test_so_extern(void);
|
|
int *test_so_local(void);
|
|
int *test_so_global(void);
|
|
|
|
static const struct testcase tests[] = {
|
|
#define T(t) { #t, test_##t }
|
|
T(race),
|
|
T(local),
|
|
T(global),
|
|
T(static_extern),
|
|
T(so_extern),
|
|
T(so_local),
|
|
T(so_global),
|
|
#undef T
|
|
};
|
|
|
|
#define NTESTS (sizeof(tests)/sizeof(*tests))
|
|
|
|
int main()
|
|
{
|
|
pthread_t threads[NTESTS*2];
|
|
int curthread = 0;
|
|
static
|
|
int i;
|
|
|
|
for(i = 0; i < NTESTS; i++) {
|
|
pthread_create(&threads[curthread++], NULL, tls_ptr, (void *)&tests[i]);
|
|
pthread_create(&threads[curthread++], NULL, tls_ptr, (void *)&tests[i]);
|
|
}
|
|
|
|
for(i = 0; i < curthread; i++)
|
|
pthread_join(threads[i], NULL);
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
int main()
|
|
{
|
|
printf("FAILED: no compiler support for __thread\n");
|
|
return 1;
|
|
}
|
|
#endif
|