mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-08 21:09:49 +00:00
It compiles, but aborts immediately if you try to run it.
I didn't include ldt.c; I'm not sure how the LDT is used on AMD64. It can be
added later if necessary.
While doing this, did some 64-bit cleanness fixes:
- Added necessary intermediate casts to ULong to avoid warnings when converting
ThreadId to void* and vice versa, in vg_scheduler.c.
- Fixed VALGRIND_NON_SIMD_CALL[0123] to use 'long' as the return type.
- Fixed VALGRIND_PRINTF{,BACKTRACE} to use unsigned longs instead of unsigned
ints, as needed.
- Converted some offsets in vg_symtab2.h from "Int" to "OffT".
- Made strlen, strncat, etc, use SizeT instead of 'unsigned int' for the length
parameter.
- Couple of other minor things.
I had to insert some "#ifdef __amd64__" and "#ifndef __amd64__" guards in
places. In particular, in vg_mylibc.c, some of our syscall wrappers aren't
appropriate for AMD64 because the syscall numbering is a bit different in
places. This difference will have to be abstracted out somehow.
Also rewrote the sys_fcntl and sys_fcntl64 wrappers, as required for AMD64.
Also moved the ipc wrapper into x86, since it's not applicable for
AMD64. However, it is applicable (I think) for ARM, so it would be nice
to work out a way to share syscall wrappers between some, but not all,
archs. Hmm. Also now using the real IPC constants rather than magic
numbers in the wrapper.
Other non-AMD64-related fixes:
- ARM: fixed syscall table by accounting for the fact that syscall
numbers don't start at 0, but rather at 0x900000.
- Converted a few places to use ThreadId instead of 'int' or 'Int' for
thread IDs.
- Added both AMD64 and ARM (which I'd forgotten) entries to valgrind.spec.in.
- Tweaked comments in various places.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3136
231 lines
5.7 KiB
C
231 lines
5.7 KiB
C
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- Arch-specific libpthread code. amd64/libpthread.c ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, an extensible x86 protected-mode
|
|
emulator for monitoring program execution on x86-Unixes.
|
|
|
|
Copyright (C) 2000-2004 Julian Seward
|
|
jseward@acm.org
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
*/
|
|
|
|
/* ALL THIS CODE RUNS ON THE SIMULATED CPU.
|
|
|
|
See the comments at the top of coregrind/vg_libpthread.c for some
|
|
caveats.
|
|
*/
|
|
|
|
#if 0
|
|
#include "core.h" /* For the VG_USERREQ__* constants */
|
|
|
|
#define __USE_UNIX98
|
|
#include <pthread.h>
|
|
#undef __USE_UNIX98
|
|
|
|
#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)(ThreadArchAux *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)(ThreadArchAux *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;
|
|
vki_modify_ldt_t 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 */
|
|
|
|
int pthread_spin_init(pthread_spinlock_t *lock, int pshared)
|
|
{
|
|
/* We can ignore the `pshared' parameter. Since we are busy-waiting
|
|
all processes which can access the memory location `lock' points
|
|
to can use the spinlock. */
|
|
*lock = 1;
|
|
return 0;
|
|
}
|
|
|
|
int pthread_spin_lock(pthread_spinlock_t *lock)
|
|
{
|
|
asm volatile
|
|
("\n"
|
|
"1:\n\t"
|
|
"lock; decl %0\n\t"
|
|
"js 2f\n\t"
|
|
".section .text.spinlock,\"ax\"\n"
|
|
"2:\n\t"
|
|
"cmpl $0,%0\n\t"
|
|
"rep; nop\n\t"
|
|
"jle 2b\n\t"
|
|
"jmp 1b\n\t"
|
|
".previous"
|
|
: "=m" (*lock));
|
|
return 0;
|
|
}
|
|
|
|
int pthread_spin_unlock(pthread_spinlock_t *lock)
|
|
{
|
|
asm volatile
|
|
("movl $1,%0"
|
|
: "=m" (*lock));
|
|
return 0;
|
|
}
|
|
|
|
int pthread_spin_destroy(pthread_spinlock_t *lock)
|
|
{
|
|
/* Nothing to do. */
|
|
return 0;
|
|
}
|
|
|
|
int pthread_spin_trylock(pthread_spinlock_t *lock)
|
|
{
|
|
int oldval;
|
|
|
|
asm volatile
|
|
("xchgl %0,%1"
|
|
: "=r" (oldval), "=m" (*lock)
|
|
: "0" (0));
|
|
return oldval > 0 ? 0 : EBUSY;
|
|
}
|
|
#endif
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end ---*/
|
|
/*--------------------------------------------------------------------*/
|