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)
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