static void clear_ldt_entry(uint index) { our_modify_ldt_t array; int ret; clear_ldt_struct(&array, index); ret = modify_ldt_syscall(1, (void *)&array, sizeof(array)); ASSERT(ret >= 0); }
void tls_thread_free(tls_type_t tls_type, int index) { if (tls_type == TLS_TYPE_LDT) clear_ldt_entry(index); else if (tls_type == TLS_TYPE_GDT) { our_modify_ldt_t desc; clear_ldt_struct(&desc, index); DEBUG_DECLARE(int res = ) dynamorio_syscall(SYS_set_thread_area, 1, &desc); ASSERT(res >= 0); }
/* i#2089: we skip this for non-detach */ void tls_thread_free(tls_type_t tls_type, int index) { /* XXX i#107 (and i#2088): We need to restore the segment base the * app was using when we detach, instead of just clearing. */ if (tls_type == TLS_TYPE_LDT) clear_ldt_entry(index); else if (tls_type == TLS_TYPE_GDT) { our_modify_ldt_t desc; clear_ldt_struct(&desc, index); DEBUG_DECLARE(int res =) dynamorio_syscall(SYS_set_thread_area, 1, &desc); ASSERT(res >= 0); }
/* Queries the set of available GDT slots, and initializes: * - tls_gdt_index * - gdt_entry_tls_min on ia32 * - lib_tls_gdt_index if using private loader * GDT slots are initialized with a base and limit of zero. The caller is * responsible for setting them to a real base. */ static void choose_gdt_slots(os_local_state_t *os_tls) { our_modify_ldt_t desc; int i; int avail_index[GDT_NUM_TLS_SLOTS]; our_modify_ldt_t clear_desc; int res; /* using local static b/c dynamo_initialized is not set for a client thread * when created in client's dr_init routine */ /* FIXME: Could be racy if we have multiple threads initializing during * startup. */ if (tls_global_init) return; tls_global_init = true; /* We don't want to break the assumptions of pthreads or wine, * so we try to take the last slot. We don't want to hardcode * the index b/c the kernel will let us clobber entries so we want * to only pass in -1. */ ASSERT(!dynamo_initialized); ASSERT(tls_gdt_index == -1); for (i = 0; i < GDT_NUM_TLS_SLOTS; i++) avail_index[i] = -1; for (i = 0; i < GDT_NUM_TLS_SLOTS; i++) { /* We use a base and limit of 0 for testing what's available. */ initialize_ldt_struct(&desc, NULL, 0, -1); res = dynamorio_syscall(SYS_set_thread_area, 1, &desc); LOG(GLOBAL, LOG_THREADS, 4, "%s: set_thread_area -1 => %d res, %d index\n", __FUNCTION__, res, desc.entry_number); if (res >= 0) { /* We assume monotonic increases */ avail_index[i] = desc.entry_number; ASSERT(avail_index[i] > tls_gdt_index); tls_gdt_index = desc.entry_number; } else break; } #ifndef X64 /* In x86-64's ia32 emulation, * set_thread_area(6 <= entry_number && entry_number <= 8) fails * with EINVAL (22) because x86-64 only accepts GDT indices 12 to 14 * for TLS entries. */ if (tls_gdt_index > (gdt_entry_tls_min + GDT_NUM_TLS_SLOTS)) gdt_entry_tls_min = GDT_ENTRY_TLS_MIN_64; /* The kernel is x64. */ #endif /* Now give up the earlier slots */ for (i = 0; i < GDT_NUM_TLS_SLOTS; i++) { if (avail_index[i] > -1 && avail_index[i] != tls_gdt_index) { LOG(GLOBAL, LOG_THREADS, 4, "clearing set_thread_area index %d\n", avail_index[i]); clear_ldt_struct(&clear_desc, avail_index[i]); res = dynamorio_syscall(SYS_set_thread_area, 1, &clear_desc); ASSERT(res >= 0); } } #ifndef VMX86_SERVER ASSERT_CURIOSITY(tls_gdt_index == (kernel_is_64bit() ? GDT_64BIT : GDT_32BIT)); #endif #ifdef CLIENT_INTERFACE if (INTERNAL_OPTION(private_loader) && tls_gdt_index != -1) { /* Use the app's selector with our own TLS base for libraries. app_fs * and app_gs are initialized by the caller in os_tls_app_seg_init(). */ int index = SELECTOR_INDEX(os_tls->app_lib_tls_reg); if (index == 0) { /* An index of zero means the app has no TLS (yet), and happens * during early injection. We use -1 to grab a new entry. When the * app asks for its first table entry with set_thread_area, we give * it this one and emulate its usage of the segment. */ ASSERT_CURIOSITY(DYNAMO_OPTION(early_inject) && "app has " "no TLS, but we used non-early injection"); initialize_ldt_struct(&desc, NULL, 0, -1); res = dynamorio_syscall(SYS_set_thread_area, 1, &desc); LOG(GLOBAL, LOG_THREADS, 4, "%s: set_thread_area -1 => %d res, %d index\n", __FUNCTION__, res, desc.entry_number); ASSERT(res >= 0); if (res >= 0) { return_stolen_lib_tls_gdt = true; index = desc.entry_number; } } lib_tls_gdt_index = index; } #endif }