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