const vki_ksigset_t *mask);
extern Int VGA_(pop_signal_frame) ( ThreadId tid );
+// libpthread stuff
+typedef struct arch_thread_aux arch_thread_aux_t;
+
+void VGA_(thread_create) ( arch_thread_aux_t *aux );
+void VGA_(thread_wrapper)( arch_thread_aux_t *aux );
+void VGA_(thread_exit) ( void );
+
+Bool VGA_(has_tls) ( void );
+
+#define MY__STRING(__str) #__str
+
+// Assertion to use in code running on the simulated CPU.
+#define my_assert(expr) \
+ ((void) ((expr) ? 0 : \
+ (VG_(user_assert_fail) (MY__STRING(expr), \
+ __FILE__, __LINE__, \
+ __PRETTY_FUNCTION__), 0)))
+
+extern void VG_(user_assert_fail) ( const Char* expr, const Char* file,
+ Int line, const Char* fn );
+
+
// ---------------------------------------------------------------------
// Platform-specific things defined in eg. x86/*.c
// ---------------------------------------------------------------------
}
-static
-void my_assert_fail ( const Char* expr, const Char* file, Int line, const Char* fn )
+void VG_(user_assert_fail) ( const Char* expr, const Char* file, Int line, const Char* fn )
{
char buf[1000];
static Bool entered = False;
_exit(1);
}
-#define MY__STRING(__str) #__str
-
-#define my_assert(expr) \
- ((void) ((expr) ? 0 : \
- (my_assert_fail (MY__STRING(expr), \
- __FILE__, __LINE__, \
- __PRETTY_FUNCTION__), 0)))
-
static
void my_free ( void* ptr )
{
}
-
-/* ---------------------------------------------------
- Helper functions for running a thread
- and for clearing up afterwards.
- ------------------------------------------------ */
-
-typedef void *(*__attribute__ ((stdcall)) REGPARM(3) allocate_tls_t) (void *result);
-typedef void (*__attribute__ ((stdcall)) REGPARM(3) deallocate_tls_t) (void *tcb, int dealloc_tcb);
-
-static allocate_tls_t allocate_tls = NULL;
-static deallocate_tls_t deallocate_tls = NULL;
-
-static
-int get_gs()
-{
- int gs;
-
- asm volatile ("movw %%gs, %w0" : "=q" (gs));
-
- return gs & 0xffff;
-}
-
-static
-void set_gs( int gs )
-{
- asm volatile ("movw %w0, %%gs" :: "q" (gs));
-}
-
-static
-void *get_tcb()
-{
- void *tcb;
-
- asm volatile ("movl %%gs:0, %0" : "=r" (tcb));
-
- return tcb;
-}
-
/* All exiting threads eventually pass through here, bearing the
return value, or PTHREAD_CANCELED, in ret_val. */
static
if (specifics_ptr != NULL)
my_free(specifics_ptr);
- /* Free up any TLS data */
- if ((get_gs() & 7) == 3 && pthread_self() > 1) {
- my_assert(deallocate_tls != NULL);
- deallocate_tls(get_tcb(), 1);
- }
+ VGA_(thread_exit)();
/* Decide on my final disposition. */
VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
typedef
struct {
int attr__detachstate;
- void* tls_data;
- int tls_segment;
- unsigned long sysinfo;
void* (*root_fn) ( void* );
void* arg;
sigset_t sigmask;
+ arch_thread_aux_t aux;
}
NewThreadInfo;
void thread_wrapper ( NewThreadInfo* info )
{
int attr__detachstate;
- void* tls_data;
- int tls_segment;
- unsigned long sysinfo;
void* (*root_fn) ( void* );
void* arg;
void* ret_val;
__pthread_unwind_buf_t ub;
attr__detachstate = info->attr__detachstate;
- tls_data = info->tls_data;
- tls_segment = info->tls_segment;
- sysinfo = info->sysinfo;
root_fn = info->root_fn;
arg = info->arg;
- if (tls_data) {
- tcbhead_t *tcb = tls_data;
- struct vki_modify_ldt_ldt_s ldt_info;
-
- /* Fill in the TCB header */
- tcb->tcb = tcb;
- tcb->self = tcb;
- tcb->multiple_threads = 1;
- tcb->sysinfo = sysinfo;
-
- /* Fill in an LDT descriptor */
- ldt_info.entry_number = tls_segment;
- ldt_info.base_addr = (unsigned long)tls_data;
- ldt_info.limit = 0xfffff;
- ldt_info.seg_32bit = 1;
- ldt_info.contents = 0;
- ldt_info.read_exec_only = 0;
- ldt_info.limit_in_pages = 1;
- ldt_info.seg_not_present = 0;
- ldt_info.useable = 1;
- ldt_info.reserved = 0;
-
- /* Install the thread area */
- VG_(do_syscall)(__NR_set_thread_area, &ldt_info);
-
- /* Setup the GS segment register */
- set_gs(ldt_info.entry_number * 8 + 3);
- }
+ VGA_(thread_wrapper)(&info->aux);
/* Minimally observe the attributes supplied. */
if (attr__detachstate != PTHREAD_CREATE_DETACHED
{
int tid_child;
NewThreadInfo* info;
- int gs;
StackInfo si;
vg_pthread_attr_t* __vg_attr;
CONVERT(attr, __attr, __vg_attr);
else
info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
- gs = get_gs();
-
- if ((gs & 7) == 3) {
- tcbhead_t *tcb = get_tcb();
-
- if (allocate_tls == NULL || deallocate_tls == NULL) {
- allocate_tls = (allocate_tls_t)dlsym(RTLD_DEFAULT, "_dl_allocate_tls");
- deallocate_tls = (deallocate_tls_t)dlsym(RTLD_DEFAULT, "_dl_deallocate_tls");
- }
-
- my_assert(allocate_tls != NULL);
-
- info->tls_data = allocate_tls(NULL);
- info->tls_segment = gs >> 3;
- info->sysinfo = tcb->sysinfo;
-
- tcb->multiple_threads = 1;
- } else {
- info->tls_data = NULL;
- info->tls_segment = -1;
- info->sysinfo = 0;
- }
+ VGA_(thread_create)(&info->aux);
info->root_fn = __start_routine;
info->arg = __arg;
if (tid < 1 || tid >= VG_N_THREADS)
barf("__errno_location: invalid ThreadId");
if (thread_specific_state[tid].errno_ptr == NULL) {
- if ((get_gs() & 7) == 3)
+ if (VGA_(has_tls)())
thread_specific_state[tid].errno_ptr = dlsym(RTLD_DEFAULT, "errno");
else if (tid == 1)
thread_specific_state[tid].errno_ptr = dlvsym(RTLD_DEFAULT, "errno", "GLIBC_2.0");
if (tid < 1 || tid >= VG_N_THREADS)
barf("__h_errno_location: invalid ThreadId");
if (thread_specific_state[tid].h_errno_ptr == NULL) {
- if ((get_gs() & 7) == 3)
+ if (VGA_(has_tls)())
thread_specific_state[tid].h_errno_ptr = dlsym(RTLD_DEFAULT, "h_errno");
else if (tid == 1)
thread_specific_state[tid].h_errno_ptr = dlvsym(RTLD_DEFAULT, "h_errno", "GLIBC_2.0");
if (tid < 1 || tid >= VG_N_THREADS)
barf("__res_state: invalid ThreadId");
if (thread_specific_state[tid].res_state_ptr == NULL) {
- if ((get_gs() & 7) == 3) {
+ if (VGA_(has_tls)()) {
struct __res_state **resp = dlsym(RTLD_DEFAULT, "__resp");
thread_specific_state[tid].res_state_ptr = *resp;
caveats.
*/
-//#include "valgrind.h" /* For the request-passing mechanism */
-//#include "core.h" /* For the VG_USERREQ__* constants */
+#include "core.h" /* For the VG_USERREQ__* constants */
-//#define __USE_UNIX98
-//#include <sys/types.h>
-//#include <pthread.h>
-//#undef __USE_UNIX98
+#define __USE_UNIX98
+#include <pthread.h>
+#undef __USE_UNIX98
-//#define __USE_GNU
-//#include <dlfcn.h>
-//#undef __USE_GNU
+#define __USE_GNU
+#include <dlfcn.h>
+#undef __USE_GNU
#include <errno.h>
+// Struct used to describe a TDB header, copied from glibc.
+typedef
+ struct {
+ void *tcb;
+ void *dtv;
+ void *self;
+ int multiple_threads;
+ unsigned long sysinfo;
+ }
+ tcbhead_t;
+
+/* ---------------------------------------------------
+ Helper functions for running a thread
+ and for clearing up afterwards.
+ ------------------------------------------------ */
+
+typedef void *(*__attribute__ ((stdcall)) REGPARM(3) allocate_tls_t) (void *result);
+typedef void (*__attribute__ ((stdcall)) REGPARM(3) deallocate_tls_t) (void *tcb, int dealloc_tcb);
+
+static allocate_tls_t allocate_tls = NULL;
+static deallocate_tls_t deallocate_tls = NULL;
+
+static int get_gs()
+{
+ int gs;
+ asm volatile ("movw %%gs, %w0" : "=q" (gs));
+ return gs & 0xffff;
+}
+
+static void set_gs( int gs )
+{
+ asm volatile ("movw %w0, %%gs" :: "q" (gs));
+}
+
+static void *get_tcb()
+{
+ void *tcb;
+ asm volatile ("movl %%gs:0, %0" : "=r" (tcb));
+ return tcb;
+}
+
+
+Bool VGA_(has_tls)(void)
+{
+ return (get_gs() & 7) == 3;
+}
+
+
+void VGA_(thread_create)(arch_thread_aux_t *aux)
+{
+ if (VGA_(has_tls)) {
+ tcbhead_t *tcb = get_tcb();
+
+ if (allocate_tls == NULL || deallocate_tls == NULL) {
+ allocate_tls = (allocate_tls_t)dlsym(RTLD_DEFAULT, "_dl_allocate_tls");
+ deallocate_tls = (deallocate_tls_t)dlsym(RTLD_DEFAULT, "_dl_deallocate_tls");
+ }
+
+ my_assert(allocate_tls != NULL);
+
+ aux->tls_data = allocate_tls(NULL);
+ aux->tls_segment = get_gs() >> 3;
+ aux->sysinfo = tcb->sysinfo;
+
+ tcb->multiple_threads = 1;
+ } else {
+ aux->tls_data = NULL;
+ aux->tls_segment = -1;
+ aux->sysinfo = 0;
+ }
+}
+
+void VGA_(thread_wrapper)(arch_thread_aux_t *aux)
+{
+ void* tls_data;
+ int tls_segment;
+ unsigned long sysinfo;
+
+ tls_data = aux->tls_data;
+ tls_segment = aux->tls_segment;
+ sysinfo = aux->sysinfo;
+
+ if (tls_data) {
+ tcbhead_t *tcb = tls_data;
+ struct vki_modify_ldt_ldt_s ldt_info;
+
+ /* Fill in the TCB header */
+ tcb->tcb = tcb;
+ tcb->self = tcb;
+ tcb->multiple_threads = 1;
+ tcb->sysinfo = sysinfo;
+
+ /* Fill in an LDT descriptor */
+ ldt_info.entry_number = tls_segment;
+ ldt_info.base_addr = (unsigned long)tls_data;
+ ldt_info.limit = 0xfffff;
+ ldt_info.seg_32bit = 1;
+ ldt_info.contents = 0;
+ ldt_info.read_exec_only = 0;
+ ldt_info.limit_in_pages = 1;
+ ldt_info.seg_not_present = 0;
+ ldt_info.useable = 1;
+ ldt_info.reserved = 0;
+
+ /* Install the thread area */
+ VG_(do_syscall)(__NR_set_thread_area, &ldt_info);
+
+ /* Setup the GS segment register */
+ set_gs(ldt_info.entry_number * 8 + 3);
+ }
+}
+
+void VGA_(thread_exit)(void)
+{
+ /* Free up any TLS data */
+ if ((get_gs() & 7) == 3 && pthread_self() > 1) {
+ my_assert(deallocate_tls != NULL);
+ deallocate_tls(get_tcb(), 1);
+ }
+}
+
/* POSIX spinlocks, taken from glibc linuxthreads/sysdeps/i386 */
typedef volatile int pthread_spinlock_t; /* Huh? Guarded by __USE_XOPEN2K */