Date: Wed, 14 Apr 2010 14:30:10 GMT From: Attilio Rao <attilio@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 176894 for review Message-ID: <201004141430.o3EEUAbX041368@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@176894?ac=10 Change 176894 by attilio@attilio_pavilion on 2010/04/14 14:30:04 Fix TLS handling within i386 by passing a correct LDT location for any thread rather than using always the same one. Submitted by: stass Affected files ... .. //depot/projects/valgrind/coregrind/m_syswrap/syswrap-x86-freebsd.c#17 edit Differences ... ==== //depot/projects/valgrind/coregrind/m_syswrap/syswrap-x86-freebsd.c#17 (text+ko) ==== @@ -409,10 +409,10 @@ } #endif - -static SysRes sys_set_thread_area ( ThreadId tid, Int idx, void* base ) +static SysRes sys_set_thread_area ( ThreadId tid, Int *idxptr, void *base) { VexGuestX86SegDescr* gdt; + Int idx; vg_assert(8 == sizeof(VexGuestX86SegDescr)); vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*)); @@ -425,12 +425,31 @@ VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt; } + idx = *idxptr; + if (idx == -1) { + /* Find and use the first free entry. Don't allocate entry + zero, because the hardware will never do that, and apparently + doing so confuses some code (perhaps stuff running on + Wine). */ + for (idx = 1; 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 VG_(mk_SysRes_Error)( VKI_ESRCH ); + } else if (idx < 0 || idx == 0 || idx >= VEX_GUEST_X86_GDT_NENT) { + /* Similarly, reject attempts to use GDT[0]. */ + return VG_(mk_SysRes_Error)( VKI_EINVAL ); + } + translate_to_hw_format(base, &gdt[idx]); + *idxptr = idx; return VG_(mk_SysRes_Success)( 0 ); } - static SysRes sys_get_thread_area ( ThreadId tid, Int idx, void ** basep ) { VexGuestX86SegDescr* gdt; @@ -532,6 +551,7 @@ SysRes res; vki_sigset_t blockall, savedmask; struct vki_thr_param tp; + Int idx = -1; Addr stk; PRINT("thr_new ( %#lx, %ld )",ARG1,ARG2); @@ -596,8 +616,8 @@ if (debug) VG_(printf)("clone child has SETTLS: tls at %#lx\n", (Addr)tp.tls_base); - sys_set_thread_area( ctid, 2, tp.tls_base ); - ctst->arch.vex.guest_GS = (2 << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */ + sys_set_thread_area( ctid, &idx, tp.tls_base ); + ctst->arch.vex.guest_GS = (idx << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */ tp.tls_base = 0; /* Don't have the kernel do it too */ /* start the thread with everything blocked */ @@ -908,6 +928,7 @@ PRE(sys_sysarch) { ThreadState *tst; + Int idx; void **p; PRINT("sys_sysarch ( %ld, %#lx )", ARG1, ARG2); @@ -921,9 +942,10 @@ /* On FreeBSD, the syscall loads the %gs selector for us, so do it now. */ tst = VG_(get_ThreadState)(tid); p = (void**)ARG2; - tst->arch.vex.guest_GS = (2 << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */ + tst->arch.vex.guest_GS = (1 << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */ /* "do" the syscall ourselves; the kernel never sees it */ - SET_STATUS_from_SysRes( sys_set_thread_area( tid, 2, *p ) ); + idx = 1; + SET_STATUS_from_SysRes( sys_set_thread_area( tid, &idx, *p ) ); break; case VKI_I386_GET_GSBASE:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004141430.o3EEUAbX041368>