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
_exit_with_stack_teardown(void * stack,size_t sz)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. */
child_fn(void * arg)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. */
main(void)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) && !defined(VGO_dragonfly)
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