From: Nicholas Nethercote Date: Wed, 9 Nov 2005 04:49:28 +0000 (+0000) Subject: Factor out some common code in m_syswrap. X-Git-Tag: svn/VALGRIND_3_1_0~183 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bf21ecfdb0b839c4fb680f42941822522fd15080;p=thirdparty%2Fvalgrind.git Factor out some common code in m_syswrap. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@5049 --- diff --git a/coregrind/m_syswrap/priv_syswrap-linux.h b/coregrind/m_syswrap/priv_syswrap-linux.h index 22babd859f..5229d149d9 100644 --- a/coregrind/m_syswrap/priv_syswrap-linux.h +++ b/coregrind/m_syswrap/priv_syswrap-linux.h @@ -36,6 +36,12 @@ // Run a thread from beginning to end. extern VgSchedReturnCode ML_(thread_wrapper)(Word /*ThreadId*/ tid); +extern Int ML_(start_thread_NORETURN) ( void* arg ); +extern void ML_(run_a_thread_NORETURN) ( Word tidW ); +extern Addr ML_(allocstack) ( ThreadId tid ); +extern void ML_(call_on_new_stack_0_1) ( Addr stack, Addr retaddr, + void (*f)(Word), Word arg1 ); + DECL_TEMPLATE(linux, sys_mount); DECL_TEMPLATE(linux, sys_oldumount); DECL_TEMPLATE(linux, sys_umount); diff --git a/coregrind/m_syswrap/syswrap-amd64-linux.c b/coregrind/m_syswrap/syswrap-amd64-linux.c index d2d82d6d40..c54340b92d 100644 --- a/coregrind/m_syswrap/syswrap-amd64-linux.c +++ b/coregrind/m_syswrap/syswrap-amd64-linux.c @@ -58,140 +58,21 @@ Note. Why is this stuff here? ------------------------------------------------------------------ */ -/* Allocate a stack for this thread. They're allocated lazily, and - never freed. */ - -/* Allocate a stack for this thread, if it doesn't already have one. - Returns the initial stack pointer value to use, or 0 if allocation - failed. */ - -static Addr allocstack(ThreadId tid) -{ - ThreadState* tst = VG_(get_ThreadState)(tid); - VgStack* stack; - Addr initial_SP; - - /* Either the stack_base and stack_init_SP are both zero (in which - case a stack hasn't been allocated) or they are both non-zero, - in which case it has. */ - - if (tst->os_state.valgrind_stack_base == 0) - vg_assert(tst->os_state.valgrind_stack_init_SP == 0); - - if (tst->os_state.valgrind_stack_base != 0) - vg_assert(tst->os_state.valgrind_stack_init_SP != 0); - - /* If no stack is present, allocate one. */ - - if (tst->os_state.valgrind_stack_base == 0) { - stack = VG_(am_alloc_VgStack)( &initial_SP ); - if (stack) { - tst->os_state.valgrind_stack_base = (Addr)stack; - tst->os_state.valgrind_stack_init_SP = initial_SP; - } - } - - if (0) - VG_(printf)( "stack for tid %d at %p; init_SP=%p\n", - tid, - (void*)tst->os_state.valgrind_stack_base, - (void*)tst->os_state.valgrind_stack_init_SP ); - - return tst->os_state.valgrind_stack_init_SP; -} - - -/* Run a thread all the way to the end, then do appropriate exit actions - (this is the last-one-out-turn-off-the-lights bit). -*/ -static void run_a_thread_NORETURN ( Word tidW ) -{ - ThreadId tid = (ThreadId)tidW; - VgSchedReturnCode src; - Int c; - - VG_(debugLog)(1, "syswrap-amd64-linux", - "run_a_thread_NORETURN(tid=%lld): " - "ML_(thread_wrapper) called\n", - (ULong)tidW); - - /* Run the thread all the way through. */ - src = ML_(thread_wrapper)(tid); - - VG_(debugLog)(1, "syswrap-amd64-linux", - "run_a_thread_NORETURN(tid=%lld): " - "ML_(thread_wrapper) done\n", - (ULong)tidW); - - c = VG_(count_living_threads)(); - vg_assert(c >= 1); /* stay sane */ - - if (c == 1) { - - VG_(debugLog)(1, "syswrap-amd64-linux", - "run_a_thread_NORETURN(tid=%lld): " - "last one standing\n", - (ULong)tidW); - - /* We are the last one standing. Keep hold of the lock and - carry on to show final tool results, then exit the entire system. - Use the continuation pointer set at startup in m_main. */ - ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src); - - } else { - - ThreadState *tst; - - VG_(debugLog)(1, "syswrap-amd64-linux", - "run_a_thread_NORETURN(tid=%lld): " - "not last one standing\n", - (ULong)tidW); - - /* OK, thread is dead, but others still exist. Just exit. */ - tst = VG_(get_ThreadState)(tid); - - /* This releases the run lock */ - VG_(exit_thread)(tid); - vg_assert(tst->status == VgTs_Zombie); - - /* We have to use this sequence to terminate the thread to - prevent a subtle race. If VG_(exit_thread)() had left the - ThreadState as Empty, then it could have been reallocated, - reusing the stack while we're doing these last cleanups. - Instead, VG_(exit_thread) leaves it as Zombie to prevent - reallocation. We need to make sure we don't touch the stack - between marking it Empty and exiting. Hence the - assembler. */ - asm volatile ( - "movl %1, %0\n" /* set tst->status = VgTs_Empty */ - "movq %2, %%rax\n" /* set %rax = __NR_exit */ - "movq %3, %%rdi\n" /* set %rdi = tst->os_state.exitcode */ - "syscall\n" /* exit(tst->os_state.exitcode) */ - : "=m" (tst->status) - : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); - - VG_(core_panic)("Thread exit failed?\n"); - } - - /*NOTREACHED*/ - vg_assert(0); -} - - /* Call f(arg1), but first switch stacks, using 'stack' as the new stack, and use 'retaddr' as f's return-to address. Also, clear all the integer registers before entering f. */ __attribute__((noreturn)) -void call_on_new_stack_0_1 ( Addr stack, - Addr retaddr, - void (*f)(Word), - Word arg1 ); +void ML_(call_on_new_stack_0_1) ( Addr stack, + Addr retaddr, + void (*f)(Word), + Word arg1 ); // %rdi == stack // %rsi == retaddr // %rdx == f // %rcx == arg1 asm( -"call_on_new_stack_0_1:\n" +".globl vgModuleLocal_call_on_new_stack_0_1\n" +vgModuleLocal_call_on_new_stack_0_1:\n" " movq %rdi, %rsp\n" // set stack " pushq %rsi\n" // retaddr to stack " pushq %rdx\n" // f to stack @@ -216,51 +97,6 @@ asm( " ud2\n" // should never get here ); - -/* Allocate a stack for the main thread, and run it all the way to the - end. Although we already have a working VgStack - (VG_(interim_stack)) it's better to allocate a new one, so that - overflow detection works uniformly for all threads. -*/ -void VG_(main_thread_wrapper_NORETURN)(ThreadId tid) -{ - Addr rsp; - - VG_(debugLog)(1, "syswrap-amd64-linux", - "entering VG_(main_thread_wrapper_NORETURN)\n"); - - rsp = allocstack(tid); - - /* If we can't even allocate the first thread's stack, we're hosed. - Give up. */ - vg_assert2(rsp != 0, "Cannot allocate main thread's stack."); - - /* shouldn't be any other threads around yet */ - vg_assert( VG_(count_living_threads)() == 1 ); - - call_on_new_stack_0_1( - (Addr)rsp, /* stack */ - 0, /*bogus return address*/ - run_a_thread_NORETURN, /* fn to call */ - (Word)tid /* arg to give it */ - ); - - /*NOTREACHED*/ - vg_assert(0); -} - - -static Long start_thread_NORETURN ( void* arg ) -{ - ThreadState* tst = (ThreadState*)arg; - ThreadId tid = tst->tid; - - run_a_thread_NORETURN ( (Word)tid ); - /*NOTREACHED*/ - vg_assert(0); -} - - /* --------------------------------------------------------------------- clone() handling ------------------------------------------------------------------ */ @@ -380,7 +216,7 @@ static SysRes do_clone ( ThreadId ptid, vg_assert(VG_(is_running_thread)(ptid)); vg_assert(VG_(is_valid_tid)(ctid)); - stack = (UWord*)allocstack(ctid); + stack = (UWord*)ML_(allocstack)(ctid); if (stack == NULL) { res = VG_(mk_SysRes_Error)( VKI_ENOMEM ); goto out; @@ -445,7 +281,7 @@ static SysRes do_clone ( ThreadId ptid, /* Create the new thread */ rax = do_syscall_clone_amd64_linux( - start_thread_NORETURN, stack, flags, &VG_(threads)[ctid], + ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid], child_tidptr, parent_tidptr, NULL ); res = VG_(mk_SysRes_amd64_linux)( rax ); diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index 9ed5de6f4d..b036b82a2e 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -45,11 +45,14 @@ #include "pub_core_scheduler.h" #include "pub_core_signals.h" #include "pub_core_syscall.h" +#include "pub_core_syswrap.h" #include "priv_types_n_macros.h" #include "priv_syswrap-generic.h" #include "priv_syswrap-linux.h" +#include "vki_unistd.h" /* for the __NR_* constants */ + // Run a thread from beginning to end and return the thread's // scheduler-return-code. VgSchedReturnCode ML_(thread_wrapper)(Word /*ThreadId*/ tidW) @@ -95,6 +98,194 @@ VgSchedReturnCode ML_(thread_wrapper)(Word /*ThreadId*/ tidW) } +/* --------------------------------------------------------------------- + clone-related stuff + ------------------------------------------------------------------ */ + +/* Run a thread all the way to the end, then do appropriate exit actions + (this is the last-one-out-turn-off-the-lights bit). */ +void ML_(run_a_thread_NORETURN) ( Word tidW ) +{ + ThreadId tid = (ThreadId)tidW; + VgSchedReturnCode src; + Int c; + + VG_(debugLog)(1, "syswrap-generic", + "run_a_thread_NORETURN(tid=%lld): " + "ML_(thread_wrapper) called\n", + (ULong)tidW); + + /* Run the thread all the way through. */ + src = ML_(thread_wrapper)(tid); + + VG_(debugLog)(1, "syswrap-ppc32-linux", + "run_a_thread_NORETURN(tid=%lld): " + "ML_(thread_wrapper) done\n", + (ULong)tidW); + + c = VG_(count_living_threads)(); + vg_assert(c >= 1); /* stay sane */ + + if (c == 1) { + + VG_(debugLog)(1, "syswrap-ppc32-linux", + "run_a_thread_NORETURN(tid=%lld): " + "last one standing\n", + (ULong)tidW); + + /* We are the last one standing. Keep hold of the lock and + carry on to show final tool results, then exit the entire system. + Use the continuation pointer set at startup in m_main. */ + ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src); + + } else { + + ThreadState *tst; + + VG_(debugLog)(1, "syswrap-ppc32-linux", + "run_a_thread_NORETURN(tid=%lld): " + "not last one standing\n", + (ULong)tidW); + + /* OK, thread is dead, but others still exist. Just exit. */ + tst = VG_(get_ThreadState)(tid); + + /* This releases the run lock */ + VG_(exit_thread)(tid); + vg_assert(tst->status == VgTs_Zombie); + + /* We have to use this sequence to terminate the thread to + prevent a subtle race. If VG_(exit_thread)() had left the + ThreadState as Empty, then it could have been reallocated, + reusing the stack while we're doing these last cleanups. + Instead, VG_(exit_thread) leaves it as Zombie to prevent + reallocation. We need to make sure we don't touch the stack + between marking it Empty and exiting. Hence the + assembler. */ +#if defined(VGP_x86_linux) + asm volatile ( + "movl %1, %0\n" /* set tst->status = VgTs_Empty */ + "movl %2, %%eax\n" /* set %eax = __NR_exit */ + "movl %3, %%ebx\n" /* set %ebx = tst->os_state.exitcode */ + "int $0x80\n" /* exit(tst->os_state.exitcode) */ + : "=m" (tst->status) + : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); +#elif defined(VGP_amd64_linux) + asm volatile ( + "movl %1, %0\n" /* set tst->status = VgTs_Empty */ + "movq %2, %%rax\n" /* set %rax = __NR_exit */ + "movq %3, %%rdi\n" /* set %rdi = tst->os_state.exitcode */ + "syscall\n" /* exit(tst->os_state.exitcode) */ + : "=m" (tst->status) + : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); +#elif defined(VGP_ppc32_linux) + { UInt vgts_empty = (UInt)VgTs_Empty; + asm volatile ( + "stw %1,%0\n\t" /* set tst->status = VgTs_Empty */ + "li 0,%2\n\t" /* set r0 = __NR_exit */ + "lwz 3,%3\n\t" /* set r3 = tst->os_state.exitcode */ + "sc\n\t" /* exit(tst->os_state.exitcode) */ + : "=m" (tst->status) + : "r" (vgts_empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); + } +#else +# error Unknown platform +#endif + + VG_(core_panic)("Thread exit failed?\n"); + } + + /*NOTREACHED*/ + vg_assert(0); +} + +Int ML_(start_thread_NORETURN) ( void* arg ) +{ + ThreadState* tst = (ThreadState*)arg; + ThreadId tid = tst->tid; + + ML_(run_a_thread_NORETURN) ( (Word)tid ); + /*NOTREACHED*/ + vg_assert(0); +} + +/* Allocate a stack for this thread, if it doesn't already have one. + They're allocated lazily, and never freed. Returns the initial stack + pointer value to use, or 0 if allocation failed. */ +Addr ML_(allocstack)(ThreadId tid) +{ + ThreadState* tst = VG_(get_ThreadState)(tid); + VgStack* stack; + Addr initial_SP; + + /* Either the stack_base and stack_init_SP are both zero (in which + case a stack hasn't been allocated) or they are both non-zero, + in which case it has. */ + + if (tst->os_state.valgrind_stack_base == 0) + vg_assert(tst->os_state.valgrind_stack_init_SP == 0); + + if (tst->os_state.valgrind_stack_base != 0) + vg_assert(tst->os_state.valgrind_stack_init_SP != 0); + + /* If no stack is present, allocate one. */ + + if (tst->os_state.valgrind_stack_base == 0) { + stack = VG_(am_alloc_VgStack)( &initial_SP ); + if (stack) { + tst->os_state.valgrind_stack_base = (Addr)stack; + tst->os_state.valgrind_stack_init_SP = initial_SP; + } + } + + if (0) + VG_(printf)( "stack for tid %d at %p; init_SP=%p\n", + tid, + (void*)tst->os_state.valgrind_stack_base, + (void*)tst->os_state.valgrind_stack_init_SP ); + + return tst->os_state.valgrind_stack_init_SP; +} + +/* Allocate a stack for the main thread, and run it all the way to the + end. Although we already have a working VgStack + (VG_(interim_stack)) it's better to allocate a new one, so that + overflow detection works uniformly for all threads. +*/ +void VG_(main_thread_wrapper_NORETURN)(ThreadId tid) +{ + Addr sp; + VG_(debugLog)(1, "syswrap-linux", + "entering VG_(main_thread_wrapper_NORETURN)\n"); + + sp = ML_(allocstack)(tid); + +#if defined(VGP_ppc32_linux) + /* make a stack frame */ + sp -= 16; + sp &= ~0xF; + *(UWord *)sp = 0; +#endif + + /* If we can't even allocate the first thread's stack, we're hosed. + Give up. */ + vg_assert2(sp != 0, "Cannot allocate main thread's stack."); + + /* shouldn't be any other threads around yet */ + vg_assert( VG_(count_living_threads)() == 1 ); + + ML_(call_on_new_stack_0_1)( + (Addr)sp, /* stack */ + 0, /* bogus return address */ + ML_(run_a_thread_NORETURN), /* fn to call */ + (Word)tid /* arg to give it */ + ); + + /*NOTREACHED*/ + vg_assert(0); +} + + /* --------------------------------------------------------------------- PRE/POST wrappers for arch-generic, Linux-specific syscalls ------------------------------------------------------------------ */ diff --git a/coregrind/m_syswrap/syswrap-ppc32-linux.c b/coregrind/m_syswrap/syswrap-ppc32-linux.c index 6e5b49b4f4..dc3ff04e75 100644 --- a/coregrind/m_syswrap/syswrap-ppc32-linux.c +++ b/coregrind/m_syswrap/syswrap-ppc32-linux.c @@ -58,141 +58,21 @@ Note. Why is this stuff here? ------------------------------------------------------------------ */ -/* Allocate a stack for this thread. They're allocated lazily, and - never freed. */ - -/* Allocate a stack for this thread, if it doesn't already have one. - Returns the initial stack pointer value to use, or 0 if allocation - failed. */ - -static Addr allocstack ( ThreadId tid ) -{ - ThreadState* tst = VG_(get_ThreadState)(tid); - VgStack* stack; - Addr initial_SP; - - /* Either the stack_base and stack_init_SP are both zero (in which - case a stack hasn't been allocated) or they are both non-zero, - in which case it has. */ - - if (tst->os_state.valgrind_stack_base == 0) - vg_assert(tst->os_state.valgrind_stack_init_SP == 0); - - if (tst->os_state.valgrind_stack_base != 0) - vg_assert(tst->os_state.valgrind_stack_init_SP != 0); - - /* If no stack is present, allocate one. */ - - if (tst->os_state.valgrind_stack_base == 0) { - stack = VG_(am_alloc_VgStack)( &initial_SP ); - if (stack) { - tst->os_state.valgrind_stack_base = (Addr)stack; - tst->os_state.valgrind_stack_init_SP = initial_SP; - } - } - - if (0) - VG_(printf)( "stack for tid %d at %p; init_SP=%p\n", - tid, - (void*)tst->os_state.valgrind_stack_base, - (void*)tst->os_state.valgrind_stack_init_SP ); - - return tst->os_state.valgrind_stack_init_SP; -} - - -/* Run a thread all the way to the end, then do appropriate exit actions - (this is the last-one-out-turn-off-the-lights bit). -*/ -static void run_a_thread_NORETURN ( Word tidW ) -{ - Int c; - VgSchedReturnCode src; - ThreadState* tst; - ThreadId tid = (ThreadId)tidW; - - VG_(debugLog)(1, "syswrap-ppc32-linux", - "run_a_thread_NORETURN(tid=%lld): " - "ML_(thread_wrapper) called\n", - (ULong)tidW); - - /* Run the thread all the way through. */ - src = ML_(thread_wrapper)(tid); - - VG_(debugLog)(1, "syswrap-ppc32-linux", - "run_a_thread_NORETURN(tid=%lld): " - "ML_(thread_wrapper) done\n", - (ULong)tidW); - - c = VG_(count_living_threads)(); - vg_assert(c >= 1); /* stay sane */ - - if (c == 1) { - - VG_(debugLog)(1, "syswrap-ppc32-linux", - "run_a_thread_NORETURN(tid=%lld): " - "last one standing\n", - (ULong)tidW); - - /* We are the last one standing. Keep hold of the lock and - carry on to show final tool results, then exit the entire system. - Use the continuation pointer set at startup in m_main. */ - ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src); - - } else { - - VG_(debugLog)(1, "syswrap-ppc32-linux", - "run_a_thread_NORETURN(tid=%lld): " - "not last one standing\n", - (ULong)tidW); - - /* OK, thread is dead, but others still exist. Just exit. */ - tst = VG_(get_ThreadState)(tid); - - /* This releases the run lock */ - VG_(exit_thread)(tid); - vg_assert(tst->status == VgTs_Zombie); - - /* We have to use this sequence to terminate the thread to - prevent a subtle race. If VG_(exit_thread)() had left the - ThreadState as Empty, then it could have been reallocated, - reusing the stack while we're doing these last cleanups. - Instead, VG_(exit_thread) leaves it as Zombie to prevent - reallocation. We need to make sure we don't touch the stack - between marking it Empty and exiting. Hence the - assembler. */ - { UInt vgts_empty = (UInt)VgTs_Empty; - asm volatile ( - "stw %1,%0\n\t" /* set tst->status = VgTs_Empty */ - "li 0,%2\n\t" /* set r0 = __NR_exit */ - "lwz 3,%3\n\t" /* set r3 = tst->os_state.exitcode */ - "sc\n\t" /* exit(tst->os_state.exitcode) */ - : "=m" (tst->status) - : "r" (vgts_empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); - } - - VG_(core_panic)("Thread exit failed?\n"); - } - - /*NOTREACHED*/ - vg_assert(0); -} - - /* Call f(arg1), but first switch stacks, using 'stack' as the new - stack, and use 'retaddr' as f's return-to address. Also, clear all + stack, and use 'retaddr' as f's return-to address. Also, clear all the integer registers before entering f.*/ __attribute__((noreturn)) -void call_on_new_stack_0_1 ( Addr stack, - Addr retaddr, - void (*f)(Word), - Word arg1 ); +void ML_(call_on_new_stack_0_1) ( Addr stack, + Addr retaddr, + void (*f)(Word), + Word arg1 ); // r3 = stack // r4 = retaddr // r5 = f // r6 = arg1 asm( -"call_on_new_stack_0_1:\n" +".globl vgModuleLocal_call_on_new_stack_0_1\n" +"vgModuleLocal_call_on_new_stack_0_1:\n" " mr %r1,%r3\n\t" // stack to %sp " mtlr %r4\n\t" // retaddr to %lr " mtctr %r5\n\t" // f to count reg @@ -233,53 +113,6 @@ asm( ); -/* Allocate a stack for the main thread, and run it all the way to the - end. Although we already have a working VgStack - (VG_(interim_stack)) it's better to allocate a new one, so that - overflow detection works uniformly for all threads. -*/ -void VG_(main_thread_wrapper_NORETURN)(ThreadId tid) -{ - Addr sp; - VG_(debugLog)(1, "syswrap-ppc32-linux", - "entering VG_(main_thread_wrapper_NORETURN)\n"); - - sp = allocstack(tid); - - /* make a stack frame */ - sp -= 16; - sp &= ~0xF; - *(UWord *)sp = 0; - - /* If we can't even allocate the first thread's stack, we're hosed. - Give up. */ - vg_assert2(sp != 0, "Cannot allocate main thread's stack."); - - /* shouldn't be any other threads around yet */ - vg_assert( VG_(count_living_threads)() == 1 ); - - call_on_new_stack_0_1( - (Addr)sp, /* stack */ - 0, /*bogus return address*/ - run_a_thread_NORETURN, /* fn to call */ - (Word)tid /* arg to give it */ - ); - - /*NOTREACHED*/ - vg_assert(0); -} - -static Int start_thread_NORETURN ( void* arg ) -{ - ThreadState* tst = (ThreadState*)arg; - ThreadId tid = tst->tid; - - run_a_thread_NORETURN ( (Word)tid ); - /*NOTREACHED*/ - vg_assert(0); -} - - /* --------------------------------------------------------------------- clone() handling ------------------------------------------------------------------ */ @@ -417,7 +250,7 @@ static SysRes do_clone ( ThreadId ptid, vg_assert(VG_(is_running_thread)(ptid)); vg_assert(VG_(is_valid_tid)(ctid)); - stack = (UWord*)allocstack(ctid); + stack = (UWord*)ML_(allocstack)(ctid); if (stack == NULL) { res = VG_(mk_SysRes_Error)( VKI_ENOMEM ); goto out; @@ -495,7 +328,7 @@ static SysRes do_clone ( ThreadId ptid, /* Create the new thread */ word64 = do_syscall_clone_ppc32_linux( - start_thread_NORETURN, stack, flags, &VG_(threads)[ctid], + ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid], child_tidptr, parent_tidptr, NULL ); /* High half word64 is syscall return value. Low half is diff --git a/coregrind/m_syswrap/syswrap-x86-linux.c b/coregrind/m_syswrap/syswrap-x86-linux.c index 3e804bedbf..6ea89dafda 100644 --- a/coregrind/m_syswrap/syswrap-x86-linux.c +++ b/coregrind/m_syswrap/syswrap-x86-linux.c @@ -66,140 +66,21 @@ Note. Why is this stuff here? ------------------------------------------------------------------ */ -/* Allocate a stack for this thread. They're allocated lazily, and - never freed. */ - -/* Allocate a stack for this thread, if it doesn't already have one. - Returns the initial stack pointer value to use, or 0 if allocation - failed. */ - -static Addr allocstack ( ThreadId tid ) -{ - ThreadState* tst = VG_(get_ThreadState)(tid); - VgStack* stack; - Addr initial_SP; - - /* Either the stack_base and stack_init_SP are both zero (in which - case a stack hasn't been allocated) or they are both non-zero, - in which case it has. */ - - if (tst->os_state.valgrind_stack_base == 0) - vg_assert(tst->os_state.valgrind_stack_init_SP == 0); - - if (tst->os_state.valgrind_stack_base != 0) - vg_assert(tst->os_state.valgrind_stack_init_SP != 0); - - /* If no stack is present, allocate one. */ - - if (tst->os_state.valgrind_stack_base == 0) { - stack = VG_(am_alloc_VgStack)( &initial_SP ); - if (stack) { - tst->os_state.valgrind_stack_base = (Addr)stack; - tst->os_state.valgrind_stack_init_SP = initial_SP; - } - } - - if (0) - VG_(printf)( "stack for tid %d at %p; init_SP=%p\n", - tid, - (void*)tst->os_state.valgrind_stack_base, - (void*)tst->os_state.valgrind_stack_init_SP ); - - return tst->os_state.valgrind_stack_init_SP; -} - - -/* Run a thread all the way to the end, then do appropriate exit actions - (this is the last-one-out-turn-off-the-lights bit). -*/ -static void run_a_thread_NORETURN ( Word tidW ) -{ - ThreadId tid = (ThreadId)tidW; - VgSchedReturnCode src; - Int c; - - VG_(debugLog)(1, "syswrap-x86-linux", - "run_a_thread_NORETURN(tid=%lld): " - "ML_(thread_wrapper) called\n", - (ULong)tidW); - - /* Run the thread all the way through. */ - src = ML_(thread_wrapper)(tid); - - VG_(debugLog)(1, "syswrap-x86-linux", - "run_a_thread_NORETURN(tid=%lld): " - "ML_(thread_wrapper) done\n", - (ULong)tidW); - - c = VG_(count_living_threads)(); - vg_assert(c >= 1); /* stay sane */ - - if (c == 1) { - - VG_(debugLog)(1, "syswrap-x86-linux", - "run_a_thread_NORETURN(tid=%lld): " - "last one standing\n", - (ULong)tidW); - - /* We are the last one standing. Keep hold of the lock and - carry on to show final tool results, then exit the entire system. - Use the continuation pointer set at startup in m_main. */ - ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src); - - } else { - - ThreadState *tst; - - VG_(debugLog)(1, "syswrap-x86-linux", - "run_a_thread_NORETURN(tid=%lld): " - "not last one standing\n", - (ULong)tidW); - - /* OK, thread is dead, but others still exist. Just exit. */ - tst = VG_(get_ThreadState)(tid); - - /* This releases the run lock */ - VG_(exit_thread)(tid); - vg_assert(tst->status == VgTs_Zombie); - - /* We have to use this sequence to terminate the thread to - prevent a subtle race. If VG_(exit_thread)() had left the - ThreadState as Empty, then it could have been reallocated, - reusing the stack while we're doing these last cleanups. - Instead, VG_(exit_thread) leaves it as Zombie to prevent - reallocation. We need to make sure we don't touch the stack - between marking it Empty and exiting. Hence the - assembler. */ - asm volatile ( - "movl %1, %0\n" /* set tst->status = VgTs_Empty */ - "movl %2, %%eax\n" /* set %eax = __NR_exit */ - "movl %3, %%ebx\n" /* set %ebx = tst->os_state.exitcode */ - "int $0x80\n" /* exit(tst->os_state.exitcode) */ - : "=m" (tst->status) - : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)); - - VG_(core_panic)("Thread exit failed?\n"); - } - - /*NOTREACHED*/ - vg_assert(0); -} - - /* Call f(arg1), but first switch stacks, using 'stack' as the new stack, and use 'retaddr' as f's return-to address. Also, clear all the integer registers before entering f.*/ __attribute__((noreturn)) -void call_on_new_stack_0_1 ( Addr stack, - Addr retaddr, - void (*f)(Word), - Word arg1 ); +void ML_(call_on_new_stack_0_1) ( Addr stack, + Addr retaddr, + void (*f)(Word), + Word arg1 ); // 4(%esp) == stack // 8(%esp) == retaddr // 12(%esp) == f // 16(%esp) == arg1 asm( -"call_on_new_stack_0_1:\n" +".globl vgModuleLocal_call_on_new_stack_0_1\n" +"vgModuleLocal_call_on_new_stack_0_1:\n" " movl %esp, %esi\n" // remember old stack pointer " movl 4(%esi), %esp\n" // set stack " pushl 16(%esi)\n" // arg1 to stack @@ -217,50 +98,6 @@ asm( ); -/* Allocate a stack for the main thread, and run it all the way to the - end. Although we already have a working VgStack - (VG_(interim_stack)) it's better to allocate a new one, so that - overflow detection works uniformly for all threads. -*/ -void VG_(main_thread_wrapper_NORETURN)(ThreadId tid) -{ - Addr esp; - - VG_(debugLog)(1, "syswrap-x86-linux", - "entering VG_(main_thread_wrapper_NORETURN)\n"); - - esp = allocstack(tid); - - /* If we can't even allocate the first thread's stack, we're hosed. - Give up. */ - vg_assert2(esp != 0, "Cannot allocate main thread's stack."); - - /* shouldn't be any other threads around yet */ - vg_assert( VG_(count_living_threads)() == 1 ); - - call_on_new_stack_0_1( - esp, /* stack */ - 0, /*bogus return address*/ - run_a_thread_NORETURN, /* fn to call */ - (Word)tid /* arg to give it */ - ); - - /*NOTREACHED*/ - vg_assert(0); -} - - -static Int start_thread_NORETURN ( void* arg ) -{ - ThreadState* tst = (ThreadState*)arg; - ThreadId tid = tst->tid; - - run_a_thread_NORETURN ( (Word)tid ); - /*NOTREACHED*/ - vg_assert(0); -} - - /* --------------------------------------------------------------------- clone() handling ------------------------------------------------------------------ */ @@ -388,7 +225,7 @@ static SysRes do_clone ( ThreadId ptid, vg_assert(VG_(is_running_thread)(ptid)); vg_assert(VG_(is_valid_tid)(ctid)); - stack = (UWord*)allocstack(ctid); + stack = (UWord*)ML_(allocstack)(ctid); if (stack == NULL) { res = VG_(mk_SysRes_Error)( VKI_ENOMEM ); goto out; @@ -464,7 +301,7 @@ static SysRes do_clone ( ThreadId ptid, /* Create the new thread */ eax = do_syscall_clone_x86_linux( - start_thread_NORETURN, stack, flags, &VG_(threads)[ctid], + ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid], child_tidptr, parent_tidptr, NULL ); res = VG_(mk_SysRes_x86_linux)( eax );