1 #include <sys/mman.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 #include <assert.h> 5 #include <unistd.h> 6 #include <sys/syscall.h> 7 #include "../../config.h" 8 9 #define VG_STRINGIFZ(__str) #__str 10 #define VG_STRINGIFY(__str) VG_STRINGIFZ(__str) 11 12 extern void _exit_with_stack_teardown(void*, size_t); 13 14 /* Below code is modified version of android bionic 15 pthread_exit: when a detached thread exits: it munmaps 16 its stack and then exits. We cannot do that in C, 17 as we cannot touch the stack after the munmap 18 and before the exit. */ 19 20 #if defined(VGP_x86_linux) 21 asm("\n" 22 ".text\n" 23 "\t.globl _exit_with_stack_teardown\n" 24 "\t.type _exit_with_stack_teardown,@function\n" 25 "_exit_with_stack_teardown:\n" 26 // We can trash registers because this function never returns. 27 "\tmov 4(%esp), %ebx\n" // stackBase 28 "\tmov 8(%esp), %ecx\n" // stackSize 29 "\tmov $"VG_STRINGIFY(__NR_munmap)", %eax\n" 30 "\tint $0x80\n" 31 // If munmap failed, we ignore the failure and exit anyway. 32 33 "\tmov $0, %ebx\n" // status 34 "\tmovl $"VG_STRINGIFY(__NR_exit)", %eax\n" 35 "\tint $0x80\n"); 36 // The exit syscall does not return. 37 38 #elif defined(VGP_amd64_linux) 39 asm("\n" 40 ".text\n" 41 "\t.globl _exit_with_stack_teardown\n" 42 "\t.type _exit_with_stack_teardown,@function\n" 43 "_exit_with_stack_teardown:\n" 44 "\tmov $"VG_STRINGIFY(__NR_munmap)", %eax\n" 45 "\tsyscall\n" 46 // If munmap failed, we ignore the failure and exit anyway. 47 "\tmov $0, %rdi\n" 48 "\tmov $"VG_STRINGIFY(__NR_exit)", %eax\n" 49 "\tsyscall\n"); 50 // The exit syscall does not return. 51 52 #elif defined(VGP_arm_linux) 53 asm("\n" 54 ".text\n" 55 "\t.globl _exit_with_stack_teardown\n" 56 "\t.type _exit_with_stack_teardown,%function\n" 57 "_exit_with_stack_teardown:\n" 58 "\tldr r7, ="VG_STRINGIFY(__NR_munmap)"\n" 59 "\tswi #0\n" 60 // If munmap failed, we ignore the failure and exit anyway. 61 62 "\tmov r0, #0\n" 63 "\tldr r7, ="VG_STRINGIFY(__NR_exit)"\n" 64 "\tswi #0\n"); 65 // The exit syscall does not return. 66 67 #else 68 void _exit_with_stack_teardown(void*stack, size_t sz) 69 { 70 // asm code not done for this platform. 71 // Do nothing, just return. The thread will exit spontaneously 72 } 73 74 #endif 75 static void *stack; 76 static size_t sz = 64 * 1024; 77 78 /* This one detaches, does its own thing. */ 79 void* child_fn ( void* arg ) 80 { 81 int r; 82 r= pthread_detach( pthread_self() ); assert(!r); 83 _exit_with_stack_teardown(stack, sz); 84 return NULL; 85 } 86 87 /* Parent creates 1 child, that will detach, and exit after destroying 88 its own stack. */ 89 int main ( void ) 90 { 91 int r; 92 pthread_attr_t attr; 93 pthread_t child; 94 95 r = pthread_attr_init(&attr); assert(!r); 96 # if !defined(VGO_darwin) 97 stack = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 98 -1, 0); 99 # else 100 stack = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANON, 101 -1, 0); 102 # endif 103 assert(stack != (void *)-1); 104 r = pthread_attr_setstack(&attr, stack, sz); 105 r = pthread_create(&child, &attr, child_fn, NULL); assert(!r); 106 sleep(1); 107 108 return 0; 109 } 110