/*MOD*/ ThreadArchState* arch );
// Thread stuff
-extern void VGA_(clear_thread) ( ThreadArchState* );
extern void VGA_(cleanup_thread) ( ThreadArchState* );
extern void VGA_(setup_child) ( ThreadArchState*, ThreadArchState* );
void mostly_clear_thread_record ( ThreadId tid )
{
vg_assert(tid >= 0 && tid < VG_N_THREADS);
- VGA_(clear_thread)(&VG_(threads)[tid].arch);
+ VGA_(cleanup_thread)(&VG_(threads)[tid].arch);
VG_(threads)[tid].tid = tid;
VG_(threads)[tid].status = VgTs_Empty;
VG_(threads)[tid].associated_mx = NULL;
am not sure what is and isn't allowed in user-mode.
*/
-#include "core.h"
-
-
-/* Maximum number of LDT entries supported (by the x86). */
-#define VG_M_LDT_ENTRIES 8192
-/* The size of each LDT entry == sizeof(VgLdtEntry) */
-#define VG_LDT_ENTRY_SIZE 8
-
-/* Allocate and deallocate LDTs for threads. */
-
-/* Create an LDT. If the parent_ldt is NULL, zero out the
- new one. If non-NULL, copy the parent. */
-VgLdtEntry* VG_(allocate_LDT_for_thread) ( VgLdtEntry* parent_ldt )
-{
- UInt nbytes, i;
- VgLdtEntry* ldt;
-
- if (0)
- VG_(printf)("allocate_LDT_for_thread: parent = %p\n", parent_ldt );
- vg_assert(VG_LDT_ENTRY_SIZE == sizeof(VgLdtEntry));
- nbytes = VG_M_LDT_ENTRIES * VG_LDT_ENTRY_SIZE;
-
- if (parent_ldt == NULL) {
- /* Allocate a new zeroed-out one. */
- ldt = (VgLdtEntry*)VG_(arena_calloc)(VG_AR_CORE, VG_MIN_MALLOC_SZB,
- nbytes, 1);
- } else {
- ldt = (VgLdtEntry*)VG_(arena_malloc)(VG_AR_CORE, nbytes);
- for (i = 0; i < VG_M_LDT_ENTRIES; i++)
- ldt[i] = parent_ldt[i];
- }
-
- return ldt;
-}
-
-/* Free an LDT created by the above function. */
-void VG_(deallocate_LDT_for_thread) ( VgLdtEntry* ldt )
-{
- if (0)
- VG_(printf)("deallocate_LDT_for_thread: ldt = %p\n", ldt );
- if (ldt != NULL)
- VG_(arena_free)(VG_AR_CORE, ldt);
-}
-
-
-
-/* Clear a TLS array. */
-void VG_(clear_TLS_for_thread) ( VgLdtEntry* tls )
-{
- VgLdtEntry* tlsp;
-
- if (0)
- VG_(printf)("clear_TLS_for_thread\n" );
-
- for (tlsp = tls; tlsp < tls + VKI_GDT_ENTRY_TLS_ENTRIES; tlsp++) {
- tlsp->LdtEnt.Words.word1 = 0;
- tlsp->LdtEnt.Words.word2 = 0;
- }
-
- return;
-}
-
-
-
-/* Fish the base field out of an VgLdtEntry. This is the only part we
- are particularly interested in. */
-
-static
-void *wine_ldt_get_base( const VgLdtEntry *ent )
-{
- return (void *)(ent->LdtEnt.Bits.BaseLow |
- ((unsigned long)ent->LdtEnt.Bits.BaseMid) << 16 |
- ((unsigned long)ent->LdtEnt.Bits.BaseHi) << 24);
-}
-
-static
-unsigned int wine_ldt_get_limit( const VgLdtEntry *ent )
-{
- unsigned int limit = ent->LdtEnt.Bits.LimitLow
- | (ent->LdtEnt.Bits.LimitHi << 16);
- if (ent->LdtEnt.Bits.Granularity) limit = (limit << 12) | 0xfff;
- return limit;
-}
-
-
-#if 0
-/* Actually _DO_ the segment translation. This is the whole entire
- point of this accursed, overcomplicated, baroque, pointless
- segment-override-and-LDT/GDT garbage foisted upon us all by Intel,
- in its infinite wisdom.
-
- THIS IS CALLED FROM GENERATED CODE (AND SO RUNS ON REAL CPU).
-*/
-Addr VG_(do_useseg) ( UInt seg_selector, Addr virtual_addr )
-{
- UInt table;
- Addr base;
- UInt limit;
-
- if (0)
- VG_(printf)("do_useseg: seg_selector = %p, vaddr = %p\n",
- seg_selector, virtual_addr);
-
- seg_selector &= 0x0000FFFF;
-
- /* Sanity check the segment selector. Ensure that RPL=11b (least
- privilege). This forms the bottom 2 bits of the selector. */
- if ((seg_selector & 3) != 3) {
- VG_(synth_fault)(VG_(get_current_tid)());
- return 0;
- }
-
- /* Extract the table number */
- table = (seg_selector & 4) >> 2;
-
- /* Convert the segment selector onto a table index */
- seg_selector >>= 3;
-
- if (table == 0) {
- VgLdtEntry* the_tls;
-
- vg_assert(seg_selector >= VKI_GDT_ENTRY_TLS_MIN && seg_selector <= VKI_GDT_ENTRY_TLS_MAX);
-
- /* Come up with a suitable GDT entry. We look at the thread's TLS
- array, which is pointed to by a VG_(baseBlock) entry. */
- the_tls = (VgLdtEntry*)VG_(baseBlock)[VGOFF_(tls_ptr)];
- base = (Addr)wine_ldt_get_base ( &the_tls[seg_selector-VKI_GDT_ENTRY_TLS_MIN] );
- limit = (UInt)wine_ldt_get_limit ( &the_tls[seg_selector-VKI_GDT_ENTRY_TLS_MIN] );
- } else {
- VgLdtEntry* the_ldt;
-
- vg_assert(seg_selector >= 0 && seg_selector < 8192);
-
- /* Come up with a suitable LDT entry. We look at the thread's LDT,
- which is pointed to by a VG_(baseBlock) entry. If null, we will
- use an implied zero-entry -- although this usually implies the
- program is in deep trouble, since it is using LDT entries which
- it probably hasn't set up. */
- the_ldt = (VgLdtEntry*)VG_(baseBlock)[VGOFF_(ldt)];
- if (the_ldt == NULL) {
- base = 0;
- limit = 0;
- VG_(message)(
- Vg_UserMsg,
- "Warning: segment-override prefix encountered, but thread has no LDT"
- );
- } else {
- base = (Addr)wine_ldt_get_base ( &the_ldt[seg_selector] );
- limit = (UInt)wine_ldt_get_limit ( &the_ldt[seg_selector] );
- }
- }
-
- /* Note, this check is just slightly too slack. Really it should
- be "if (virtual_addr + size - 1 >= limit)," but we don't have the
- size info to hand. Getting it could be significantly complex. */
- if (virtual_addr >= limit) {
- VG_(message)(
- Vg_UserMsg,
- "Warning: segment access: virtual addr %d exceeds segment limit of %d",
- virtual_addr, limit
- );
- }
-
- if (0)
- VG_(printf)("do_useseg: base = %p, addr = %p\n",
- base, base + virtual_addr);
-
- return base + virtual_addr;
-}
-#endif
-
-/* Translate a struct modify_ldt_ldt_s to an VgLdtEntry, using the
- Linux kernel's logic (cut-n-paste of code in linux/kernel/ldt.c). */
-
-static
-void translate_to_hw_format ( /* IN */ vki_modify_ldt_t* inn,
- /* OUT */ VgLdtEntry* out,
- Int oldmode )
-{
- UInt entry_1, entry_2;
-
- if (0)
- VG_(printf)("translate_to_hw_format: base %p, limit %d\n",
- inn->base_addr, inn->limit );
-
- /* Allow LDTs to be cleared by the user. */
- if (inn->base_addr == 0 && inn->limit == 0) {
- if (oldmode ||
- (inn->contents == 0 &&
- inn->read_exec_only == 1 &&
- inn->seg_32bit == 0 &&
- inn->limit_in_pages == 0 &&
- inn->seg_not_present == 1 &&
- inn->useable == 0 )) {
- entry_1 = 0;
- entry_2 = 0;
- goto install;
- }
- }
-
- entry_1 = ((inn->base_addr & 0x0000ffff) << 16) |
- (inn->limit & 0x0ffff);
- entry_2 = (inn->base_addr & 0xff000000) |
- ((inn->base_addr & 0x00ff0000) >> 16) |
- (inn->limit & 0xf0000) |
- ((inn->read_exec_only ^ 1) << 9) |
- (inn->contents << 10) |
- ((inn->seg_not_present ^ 1) << 15) |
- (inn->seg_32bit << 22) |
- (inn->limit_in_pages << 23) |
- 0x7000;
- if (!oldmode)
- entry_2 |= (inn->useable << 20);
-
- /* Install the new entry ... */
- install:
- out->LdtEnt.Words.word1 = entry_1;
- out->LdtEnt.Words.word2 = entry_2;
-}
-
-
-/*
- * linux/kernel/ldt.c
- *
- * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
- * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
- */
-
-/*
- * read_ldt() is not really atomic - this is not a problem since
- * synchronization of reads and writes done to the LDT has to be
- * assured by user-space anyway. Writes are atomic, to protect
- * the security checks done on new descriptors.
- */
-static
-Int read_ldt ( ThreadId tid, UChar* ptr, UInt bytecount )
-{
- Int err;
- UInt i, size;
- Char* ldt;
-
- if (0)
- VG_(printf)("read_ldt: tid = %d, ptr = %p, bytecount = %d\n",
- tid, ptr, bytecount );
-
- ldt = (Char*)(VG_(threads)[tid].arch.ldt);
- err = 0;
- if (ldt == NULL)
- /* LDT not allocated, meaning all entries are null */
- goto out;
-
- size = VG_M_LDT_ENTRIES * VG_LDT_ENTRY_SIZE;
- if (size > bytecount)
- size = bytecount;
-
- err = size;
- for (i = 0; i < size; i++)
- ptr[i] = ldt[i];
-
- out:
- return err;
-}
-
-
-static
-Int write_ldt ( ThreadId tid, void* ptr, UInt bytecount, Int oldmode )
-{
- Int error;
- VgLdtEntry* ldt;
- vki_modify_ldt_t* ldt_info;
-
- if (0)
- VG_(printf)("write_ldt: tid = %d, ptr = %p, "
- "bytecount = %d, oldmode = %d\n",
- tid, ptr, bytecount, oldmode );
-
- ldt = VG_(threads)[tid].arch.ldt;
- ldt_info = (vki_modify_ldt_t*)ptr;
-
- error = -VKI_EINVAL;
- if (bytecount != sizeof(vki_modify_ldt_t))
- goto out;
-
- error = -VKI_EINVAL;
- if (ldt_info->entry_number >= VG_M_LDT_ENTRIES)
- goto out;
- if (ldt_info->contents == 3) {
- if (oldmode)
- goto out;
- if (ldt_info->seg_not_present == 0)
- goto out;
- }
-
- /* If this thread doesn't have an LDT, we'd better allocate it
- now. */
- if (ldt == NULL) {
- ldt = VG_(allocate_LDT_for_thread)( NULL );
- VG_(threads)[tid].arch.ldt = ldt;
- }
-
- /* Install the new entry ... */
- translate_to_hw_format ( ldt_info, &ldt[ldt_info->entry_number], oldmode );
- error = 0;
-
- out:
- return error;
-}
-
-
-Int VG_(sys_modify_ldt) ( ThreadId tid,
- Int func, void* ptr, UInt bytecount )
-{
- Int ret = -VKI_ENOSYS;
-
- switch (func) {
- case 0:
- ret = read_ldt(tid, ptr, bytecount);
- break;
- case 1:
- ret = write_ldt(tid, ptr, bytecount, 1);
- break;
- case 2:
- VG_(unimplemented)("sys_modify_ldt: func == 2");
- /* god knows what this is about */
- /* ret = read_default_ldt(ptr, bytecount); */
- /*UNREACHED*/
- break;
- case 0x11:
- ret = write_ldt(tid, ptr, bytecount, 0);
- break;
- }
- return ret;
-}
-
-
-Int VG_(sys_set_thread_area) ( ThreadId tid,
- vki_modify_ldt_t* info )
-{
- Int idx;
-
- if (info == NULL)
- return -VKI_EFAULT;
-
- idx = info->entry_number;
-
- if (idx == -1) {
- for (idx = 0; idx < VKI_GDT_ENTRY_TLS_ENTRIES; idx++) {
- VgLdtEntry* tls = VG_(threads)[tid].arch.tls + idx;
-
- if (tls->LdtEnt.Words.word1 == 0 && tls->LdtEnt.Words.word2 == 0)
- break;
- }
-
- if (idx == VKI_GDT_ENTRY_TLS_ENTRIES)
- return -VKI_ESRCH;
- } else if (idx < VKI_GDT_ENTRY_TLS_MIN || idx > VKI_GDT_ENTRY_TLS_MAX) {
- return -VKI_EINVAL;
- } else {
- idx = info->entry_number - VKI_GDT_ENTRY_TLS_MIN;
- }
-
- translate_to_hw_format(info, VG_(threads)[tid].arch.tls + idx, 0);
-
- VG_TRACK( pre_mem_write, Vg_CoreSysCall, tid,
- "set_thread_area(info->entry)",
- (Addr) & info->entry_number, sizeof(unsigned int) );
- info->entry_number = idx + VKI_GDT_ENTRY_TLS_MIN;
- VG_TRACK( post_mem_write, Vg_CoreSysCall, tid,
- (Addr) & info->entry_number, sizeof(unsigned int) );
-
- return 0;
-}
-
-
-Int VG_(sys_get_thread_area) ( ThreadId tid,
- vki_modify_ldt_t* info )
-{
- Int idx;
- VgLdtEntry* tls;
-
- if (info == NULL)
- return -VKI_EFAULT;
-
- idx = info->entry_number;
-
- if (idx < VKI_GDT_ENTRY_TLS_MIN || idx > VKI_GDT_ENTRY_TLS_MAX)
- return -VKI_EINVAL;
-
- tls = VG_(threads)[tid].arch.tls + idx - VKI_GDT_ENTRY_TLS_MIN;
-
- info->base_addr = ( tls->LdtEnt.Bits.BaseHi << 24 ) |
- ( tls->LdtEnt.Bits.BaseMid << 16 ) |
- tls->LdtEnt.Bits.BaseLow;
- info->limit = ( tls->LdtEnt.Bits.LimitHi << 16 ) |
- tls->LdtEnt.Bits.LimitLow;
- info->seg_32bit = tls->LdtEnt.Bits.Default_Big;
- info->contents = ( tls->LdtEnt.Bits.Type >> 2 ) & 0x3;
- info->read_exec_only = ( tls->LdtEnt.Bits.Type & 0x1 ) ^ 0x1;
- info->limit_in_pages = tls->LdtEnt.Bits.Granularity;
- info->seg_not_present = tls->LdtEnt.Bits.Pres ^ 0x1;
- info->useable = tls->LdtEnt.Bits.Sys;
- info->reserved = 0;
-
- return 0;
-}
+/* 13 Dec 04: all this stuff has been moved into
+ coregrind/x86/state.c. */
/*--------------------------------------------------------------------*/
/*--- end ---*/
/* This is the hardware-format for a segment descriptor, ie what the
x86 actually deals with. It is 8 bytes long. It's ugly. */
-
+#if 0
typedef struct _LDT_ENTRY {
union {
struct {
}
LdtEnt;
} VgLdtEntry;
-
+#endif
/* ---------------------------------------------------------------------
Architecture-specific part of a ThreadState
// also.
typedef
struct {
- /* Pointer to this thread's Local (Segment) Descriptor Table.
- Starts out as NULL, indicating there is no table, and we hope
- to keep it that way. If the thread does __NR_modify_ldt to
- create entries, we allocate a 8192-entry table at that point.
- This is a straight copy of the Linux kernel's scheme. Don't
- forget to deallocate this at thread exit. */
- VgLdtEntry* ldt;
-
- /* TLS table. This consists of a small number (currently 3) of
- entries from the Global Descriptor Table. */
- VgLdtEntry tls[VKI_GDT_ENTRY_TLS_ENTRIES];
-
/* --- BEGIN vex-mandated guest state --- */
/* Saved machine context. */
SSE/fxsave/fxrestor features. */
Bool VG_(have_ssestate);
+
+/* Global and Local descriptor tables for threads.
+
+ See comments in libvex_guest_x86.h for LibVEX's model of x86
+ segment descriptors.
+
+ Mostly, threads never generate LDT (or GDT?) entries. Therefore,
+ we will initially start off with LDTs and GDTs being (HWord)NULL
+ and allocate them on demand.
+*/
+
+
/*------------------------------------------------------------*/
/*--- Initialising the first thread ---*/
/*------------------------------------------------------------*/
}
+/*------------------------------------------------------------*/
+/*--- LDT/GDT stuff ---*/
+/*------------------------------------------------------------*/
+
+/* Create a zeroed-out GDT. */
+
+static VexGuestX86SegDescr* alloc_zeroed_GDT ( void )
+{
+ Int nbytes
+ = VEX_GUEST_X86_GDT_NENT * sizeof(VexGuestX86SegDescr);
+ return
+ VG_(arena_calloc)(VG_AR_CORE, VG_MIN_MALLOC_SZB, nbytes, 1);
+}
+
+/* Create a zeroed-out LDT. */
+
+static VexGuestX86SegDescr* alloc_zeroed_LDT ( void )
+{
+ Int nbytes
+ = VEX_GUEST_X86_LDT_NENT * sizeof(VexGuestX86SegDescr);
+ return
+ VG_(arena_calloc)(VG_AR_CORE, VG_MIN_MALLOC_SZB, nbytes, 1);
+}
+
+/* Free up an LDT or GDT allocated by the above fns. */
+
+static void free_LDT_or_GDT ( VexGuestX86SegDescr* dt )
+{
+ vg_assert(dt);
+ VG_(arena_free)(VG_AR_CORE, (void*)dt);
+}
+
+/* Copy contents between two existing LDTs. */
+
+static void copy_LDT_from_to ( VexGuestX86SegDescr* src,
+ VexGuestX86SegDescr* dst )
+{
+ Int i;
+ vg_assert(src);
+ vg_assert(dst);
+ for (i = 0; i < VEX_GUEST_X86_LDT_NENT; i++)
+ dst[i] = src[i];
+}
+
+/* Free this thread's DTs, if it has any. */
+
+static void deallocate_LGDTs_for_thread ( VexGuestX86State* vex )
+{
+ vg_assert(sizeof(HWord) == sizeof(void*));
+
+ if (0)
+ VG_(printf)("deallocate_LGDTs_for_thread: "
+ "ldt = 0x%x, gdt = 0x%x\n",
+ vex->guest_LDT, vex->guest_GDT );
+
+ if (vex->guest_LDT != (HWord)NULL) {
+ free_LDT_or_GDT( (VexGuestX86SegDescr*)vex->guest_LDT );
+ vex->guest_LDT = (HWord)NULL;
+ }
+
+ if (vex->guest_GDT != (HWord)NULL) {
+ free_LDT_or_GDT( (VexGuestX86SegDescr*)vex->guest_GDT );
+ vex->guest_GDT = (HWord)NULL;
+ }
+}
+
+
+/* Translate a struct modify_ldt_ldt_s to a VexGuestX86SegDescr, using
+ the Linux kernel's logic (cut-n-paste of code in
+ linux/kernel/ldt.c). */
+
+static
+void translate_to_hw_format ( /* IN */ vki_modify_ldt_t* inn,
+ /* OUT */ VexGuestX86SegDescr* out,
+ Int oldmode )
+{
+ UInt entry_1, entry_2;
+ vg_assert(8 == sizeof(VexGuestX86SegDescr));
+
+ if (0)
+ VG_(printf)("translate_to_hw_format: base %p, limit %d\n",
+ inn->base_addr, inn->limit );
+
+ /* Allow LDTs to be cleared by the user. */
+ if (inn->base_addr == 0 && inn->limit == 0) {
+ if (oldmode ||
+ (inn->contents == 0 &&
+ inn->read_exec_only == 1 &&
+ inn->seg_32bit == 0 &&
+ inn->limit_in_pages == 0 &&
+ inn->seg_not_present == 1 &&
+ inn->useable == 0 )) {
+ entry_1 = 0;
+ entry_2 = 0;
+ goto install;
+ }
+ }
+
+ entry_1 = ((inn->base_addr & 0x0000ffff) << 16) |
+ (inn->limit & 0x0ffff);
+ entry_2 = (inn->base_addr & 0xff000000) |
+ ((inn->base_addr & 0x00ff0000) >> 16) |
+ (inn->limit & 0xf0000) |
+ ((inn->read_exec_only ^ 1) << 9) |
+ (inn->contents << 10) |
+ ((inn->seg_not_present ^ 1) << 15) |
+ (inn->seg_32bit << 22) |
+ (inn->limit_in_pages << 23) |
+ 0x7000;
+ if (!oldmode)
+ entry_2 |= (inn->useable << 20);
+
+ /* Install the new entry ... */
+ install:
+ out->LdtEnt.Words.word1 = entry_1;
+ out->LdtEnt.Words.word2 = entry_2;
+}
+
+
+/*
+ * linux/kernel/ldt.c
+ *
+ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+
+/*
+ * read_ldt() is not really atomic - this is not a problem since
+ * synchronization of reads and writes done to the LDT has to be
+ * assured by user-space anyway. Writes are atomic, to protect
+ * the security checks done on new descriptors.
+ */
+static
+Int read_ldt ( ThreadId tid, UChar* ptr, UInt bytecount )
+{
+ Int err;
+ UInt i, size;
+ UChar* ldt;
+
+ if (0)
+ VG_(printf)("read_ldt: tid = %d, ptr = %p, bytecount = %d\n",
+ tid, ptr, bytecount );
+
+ vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
+ vg_assert(8 == sizeof(VexGuestX86SegDescr));
+
+ ldt = (Char*)(VG_(threads)[tid].arch.vex.guest_LDT);
+ err = 0;
+ if (ldt == NULL)
+ /* LDT not allocated, meaning all entries are null */
+ goto out;
+
+ size = VEX_GUEST_X86_LDT_NENT * sizeof(VexGuestX86SegDescr);
+ if (size > bytecount)
+ size = bytecount;
+
+ err = size;
+ for (i = 0; i < size; i++)
+ ptr[i] = ldt[i];
+
+ out:
+ return err;
+}
+
+
+static
+Int write_ldt ( ThreadId tid, void* ptr, UInt bytecount, Int oldmode )
+{
+ Int error;
+ VexGuestX86SegDescr* ldt;
+ vki_modify_ldt_t* ldt_info;
+
+ if (0)
+ VG_(printf)("write_ldt: tid = %d, ptr = %p, "
+ "bytecount = %d, oldmode = %d\n",
+ tid, ptr, bytecount, oldmode );
+
+ vg_assert(8 == sizeof(VexGuestX86SegDescr));
+ vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
+
+ ldt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_LDT;
+ ldt_info = (vki_modify_ldt_t*)ptr;
+
+ error = -VKI_EINVAL;
+ if (bytecount != sizeof(vki_modify_ldt_t))
+ goto out;
+
+ error = -VKI_EINVAL;
+ if (ldt_info->entry_number >= VEX_GUEST_X86_LDT_NENT)
+ goto out;
+ if (ldt_info->contents == 3) {
+ if (oldmode)
+ goto out;
+ if (ldt_info->seg_not_present == 0)
+ goto out;
+ }
+
+ /* If this thread doesn't have an LDT, we'd better allocate it
+ now. */
+ if (ldt == (HWord)NULL) {
+ ldt = alloc_zeroed_LDT();
+ VG_(threads)[tid].arch.vex.guest_LDT = (HWord)ldt;
+ }
+
+ /* Install the new entry ... */
+ translate_to_hw_format ( ldt_info, &ldt[ldt_info->entry_number], oldmode );
+ error = 0;
+
+ out:
+ return error;
+}
+
+
+Int VG_(sys_modify_ldt) ( ThreadId tid,
+ Int func, void* ptr, UInt bytecount )
+{
+ Int ret = -VKI_ENOSYS;
+
+ switch (func) {
+ case 0:
+ ret = read_ldt(tid, ptr, bytecount);
+ break;
+ case 1:
+ ret = write_ldt(tid, ptr, bytecount, 1);
+ break;
+ case 2:
+ VG_(unimplemented)("sys_modify_ldt: func == 2");
+ /* god knows what this is about */
+ /* ret = read_default_ldt(ptr, bytecount); */
+ /*UNREACHED*/
+ break;
+ case 0x11:
+ ret = write_ldt(tid, ptr, bytecount, 0);
+ break;
+ }
+ return ret;
+}
+
+
+Int VG_(sys_set_thread_area) ( ThreadId tid,
+ vki_modify_ldt_t* info )
+{
+ Int idx;
+ VexGuestX86SegDescr* gdt;
+
+ vg_assert(8 == sizeof(VexGuestX86SegDescr));
+ vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
+
+ if (info == NULL)
+ return -VKI_EFAULT;
+
+ gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT;
+
+ /* If the thread doesn't have a GDT, allocate it now. */
+ if (!gdt) {
+ gdt = alloc_zeroed_GDT();
+ VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt;
+ }
+
+ idx = info->entry_number;
+
+ if (idx == -1) {
+ /* Find and use the first free entry. */
+ for (idx = 0; idx < VEX_GUEST_X86_GDT_NENT; idx++) {
+ if (gdt[idx].LdtEnt.Words.word1 == 0
+ && gdt[idx].LdtEnt.Words.word2 == 0)
+ break;
+ }
+
+ if (idx == VEX_GUEST_X86_GDT_NENT)
+ return -VKI_ESRCH;
+ } else if (idx < 0 || idx >= VEX_GUEST_X86_GDT_NENT) {
+ return -VKI_EINVAL;
+ }
+
+ translate_to_hw_format(info, &gdt[idx], 0);
+
+ VG_TRACK( pre_mem_write, Vg_CoreSysCall, tid,
+ "set_thread_area(info->entry)",
+ (Addr) & info->entry_number, sizeof(unsigned int) );
+ info->entry_number = idx;
+ VG_TRACK( post_mem_write, Vg_CoreSysCall, tid,
+ (Addr) & info->entry_number, sizeof(unsigned int) );
+
+ return 0;
+}
+
+
+Int VG_(sys_get_thread_area) ( ThreadId tid,
+ vki_modify_ldt_t* info )
+{
+ Int idx;
+ VexGuestX86SegDescr* gdt;
+
+ vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
+ vg_assert(8 == sizeof(VexGuestX86SegDescr));
+
+ if (info == NULL)
+ return -VKI_EFAULT;
+
+ idx = info->entry_number;
+
+ if (idx < 0 || idx >= VEX_GUEST_X86_GDT_NENT)
+ return -VKI_EINVAL;
+
+ gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT;
+
+ /* If the thread doesn't have a GDT, allocate it now. */
+ if (!gdt) {
+ gdt = alloc_zeroed_GDT();
+ VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt;
+ }
+
+ info->base_addr = ( gdt[idx].LdtEnt.Bits.BaseHi << 24 ) |
+ ( gdt[idx].LdtEnt.Bits.BaseMid << 16 ) |
+ gdt[idx].LdtEnt.Bits.BaseLow;
+ info->limit = ( gdt[idx].LdtEnt.Bits.LimitHi << 16 ) |
+ gdt[idx].LdtEnt.Bits.LimitLow;
+ info->seg_32bit = gdt[idx].LdtEnt.Bits.Default_Big;
+ info->contents = ( gdt[idx].LdtEnt.Bits.Type >> 2 ) & 0x3;
+ info->read_exec_only = ( gdt[idx].LdtEnt.Bits.Type & 0x1 ) ^ 0x1;
+ info->limit_in_pages = gdt[idx].LdtEnt.Bits.Granularity;
+ info->seg_not_present = gdt[idx].LdtEnt.Bits.Pres ^ 0x1;
+ info->useable = gdt[idx].LdtEnt.Bits.Sys;
+ info->reserved = 0;
+
+ return 0;
+}
+
+
/*------------------------------------------------------------*/
/*--- Thread stuff ---*/
/*------------------------------------------------------------*/
-void VGA_(clear_thread)( ThreadArchState *arch )
+void VGA_(cleanup_thread) ( ThreadArchState* arch )
{
- arch->ldt = NULL;
- VG_(clear_TLS_for_thread)(arch->tls);
+ /* Release arch-specific resources held by this thread. */
+ /* On x86, we have to dump the LDT and GDT. */
+ deallocate_LGDTs_for_thread( &arch->vex );
}
-void VGA_(cleanup_thread) ( ThreadArchState *arch )
-{
- /* Deallocate its LDT, if it ever had one. */
- VG_(deallocate_LDT_for_thread)( arch->ldt );
- arch->ldt = NULL;
-
- /* Clear its TLS array. */
- VG_(clear_TLS_for_thread)( arch->tls );
-}
-void VGA_(setup_child) ( ThreadArchState *arch, ThreadArchState *parent_arch )
-{
+void VGA_(setup_child) ( /*OUT*/ ThreadArchState *child,
+ /*IN*/ ThreadArchState *parent )
+{
/* We inherit our parent's LDT. */
- if (parent_arch->ldt == NULL) {
+ if (parent->vex.guest_LDT == (HWord)NULL) {
/* We hope this is the common case. */
- arch->ldt = NULL;
+ child->vex.guest_LDT = (HWord)NULL;
} else {
/* No luck .. we have to take a copy of the parent's. */
- arch->ldt = VG_(allocate_LDT_for_thread)( parent_arch->ldt );
+ child->vex.guest_LDT = (HWord)alloc_zeroed_LDT();
+ copy_LDT_from_to( (VexGuestX86SegDescr*)parent->vex.guest_LDT,
+ (VexGuestX86SegDescr*)child->vex.guest_LDT );
}
- /* Initialise the thread's TLS array */
- VG_(clear_TLS_for_thread)( arch->tls );
+ /* We need an empty GDT. */
+ child->vex.guest_GDT = (HWord)NULL;
}
+
void VGA_(set_arg_and_bogus_ret)( ThreadId tid, UWord arg, Addr ret )
{
/* Push the arg, and mark it as readable. */
* (UInt*)(VG_(threads)[tid].arch.vex.guest_ESP) = ret;
}
+
void VGA_(thread_initial_stack)(ThreadId tid, UWord arg, Addr ret)
{
Addr esp = (Addr)STACK_PTR(VG_(threads)[tid].arch);
VG_TRACK ( post_mem_write, Vg_CoreSignal, tid, esp, 2 * sizeof(UWord) );
}
-
/*------------------------------------------------------------*/
/*--- Symtab stuff ---*/
/*------------------------------------------------------------*/
#include "x86_private_asm.h" // private arch-specific asm stuff
#include "tool_arch.h" // arch-specific tool stuff
+#include "libvex_guest_x86.h" // for VexGuestX86SegDescr
+
/* ---------------------------------------------------------------------
Exports of state.c that are not core-visible
------------------------------------------------------------------ */
------------------------------------------------------------------ */
/* Alloc & copy, and dealloc. */
-extern VgLdtEntry* VG_(allocate_LDT_for_thread) ( VgLdtEntry* parent_ldt );
-extern void VG_(deallocate_LDT_for_thread) ( VgLdtEntry* ldt );
-extern void VG_(clear_TLS_for_thread) ( VgLdtEntry* tls );
+extern VexGuestX86SegDescr*
+ VG_(allocate_LDT_for_thread) ( VexGuestX86SegDescr* parent_ldt );
+extern void
+ VG_(deallocate_LDT_for_thread) ( VexGuestX86SegDescr* ldt );
+extern void
+ VG_(clear_TLS_for_thread) ( VexGuestX86SegDescr* tls );
#endif // __X86_PRIVATE_H