13a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#include <sys/mman.h> 23a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#include <pthread.h> 33a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#include <unistd.h> 43a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#include <assert.h> 53a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#include <unistd.h> 63a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#include <sys/syscall.h> 73a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#include "../../config.h" 83a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 93a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#define VG_STRINGIFZ(__str) #__str 103a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#define VG_STRINGIFY(__str) VG_STRINGIFZ(__str) 113a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 123a75d2e7a6b8e8d28024b7444228097ae1504ca2philippeextern void _exit_with_stack_teardown(void*, size_t); 133a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 143a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe/* Below code is modified version of android bionic 153a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe pthread_exit: when a detached thread exits: it munmaps 163a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe its stack and then exits. We cannot do that in C, 173a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe as we cannot touch the stack after the munmap 183a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe and before the exit. */ 193a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 203a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#if defined(VGP_x86_linux) 213a75d2e7a6b8e8d28024b7444228097ae1504ca2philippeasm("\n" 223a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe ".text\n" 233a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\t.globl _exit_with_stack_teardown\n" 243a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\t.type _exit_with_stack_teardown,@function\n" 253a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "_exit_with_stack_teardown:\n" 263a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // We can trash registers because this function never returns. 273a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmov 4(%esp), %ebx\n" // stackBase 283a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmov 8(%esp), %ecx\n" // stackSize 293a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmov $"VG_STRINGIFY(__NR_munmap)", %eax\n" 303a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tint $0x80\n" 313a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // If munmap failed, we ignore the failure and exit anyway. 323a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 333a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmov $0, %ebx\n" // status 343a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmovl $"VG_STRINGIFY(__NR_exit)", %eax\n" 353a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tint $0x80\n"); 363a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // The exit syscall does not return. 373a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 383a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#elif defined(VGP_amd64_linux) 393a75d2e7a6b8e8d28024b7444228097ae1504ca2philippeasm("\n" 403a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe ".text\n" 413a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\t.globl _exit_with_stack_teardown\n" 423a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\t.type _exit_with_stack_teardown,@function\n" 433a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "_exit_with_stack_teardown:\n" 443a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmov $"VG_STRINGIFY(__NR_munmap)", %eax\n" 453a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tsyscall\n" 463a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // If munmap failed, we ignore the failure and exit anyway. 473a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmov $0, %rdi\n" 483a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmov $"VG_STRINGIFY(__NR_exit)", %eax\n" 493a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tsyscall\n"); 503a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // The exit syscall does not return. 513a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 523a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#elif defined(VGP_arm_linux) 533a75d2e7a6b8e8d28024b7444228097ae1504ca2philippeasm("\n" 543a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe ".text\n" 553a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\t.globl _exit_with_stack_teardown\n" 563a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\t.type _exit_with_stack_teardown,%function\n" 573a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "_exit_with_stack_teardown:\n" 583a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tldr r7, ="VG_STRINGIFY(__NR_munmap)"\n" 593a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tswi #0\n" 603a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // If munmap failed, we ignore the failure and exit anyway. 613a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 623a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tmov r0, #0\n" 633a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tldr r7, ="VG_STRINGIFY(__NR_exit)"\n" 643a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe "\tswi #0\n"); 653a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // The exit syscall does not return. 663a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 673a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#else 683a75d2e7a6b8e8d28024b7444228097ae1504ca2philippevoid _exit_with_stack_teardown(void*stack, size_t sz) 693a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe{ 703a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // asm code not done for this platform. 713a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe // Do nothing, just return. The thread will exit spontaneously 723a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe} 733a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 743a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe#endif 753a75d2e7a6b8e8d28024b7444228097ae1504ca2philippestatic void *stack; 763a75d2e7a6b8e8d28024b7444228097ae1504ca2philippestatic size_t sz = 64 * 1024; 773a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 783a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe/* This one detaches, does its own thing. */ 793a75d2e7a6b8e8d28024b7444228097ae1504ca2philippevoid* child_fn ( void* arg ) 803a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe{ 813a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe int r; 823a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe r= pthread_detach( pthread_self() ); assert(!r); 833a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe _exit_with_stack_teardown(stack, sz); 843a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe return NULL; 853a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe} 863a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 873a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe/* Parent creates 1 child, that will detach, and exit after destroying 883a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe its own stack. */ 893a75d2e7a6b8e8d28024b7444228097ae1504ca2philippeint main ( void ) 903a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe{ 913a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe int r; 923a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe pthread_attr_t attr; 933a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe pthread_t child; 943a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 953a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe r = pthread_attr_init(&attr); assert(!r); 963858abd33e8ffd77d6781014a03516e71a79db92rhyskidd# if !defined(VGO_darwin) 973a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe stack = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 983a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe -1, 0); 993858abd33e8ffd77d6781014a03516e71a79db92rhyskidd# else 1003858abd33e8ffd77d6781014a03516e71a79db92rhyskidd stack = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANON, 1013858abd33e8ffd77d6781014a03516e71a79db92rhyskidd -1, 0); 1023858abd33e8ffd77d6781014a03516e71a79db92rhyskidd# endif 1033a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe assert(stack != (void *)-1); 1043a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe r = pthread_attr_setstack(&attr, stack, sz); 1053a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe r = pthread_create(&child, &attr, child_fn, NULL); assert(!r); 1063a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe sleep(1); 1073a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe 1083a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe return 0; 1093a75d2e7a6b8e8d28024b7444228097ae1504ca2philippe} 110