1 #include <sys/types.h> 2 #include <sys/wait.h> 3 #include <assert.h> 4 #if defined(TEST_CLONE) 5 #include <sched.h> 6 #endif 7 #include <stdint.h> 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <unistd.h> 11 12 int g_val = 0; 13 14 void parent_func() { 15 g_val = 1; 16 printf("function run in parent\n"); 17 } 18 19 int parent_done[2]; 20 char parent_done_str[16]; 21 22 void wait_for_parent() { 23 char buf[2]; 24 // wait for the parent to finish its part 25 int ret = read(parent_done[0], buf, sizeof(buf)); 26 assert(ret == 2); 27 ret = close(parent_done[0]); 28 assert(ret == 0); 29 } 30 31 // This is the function we set breakpoint on. 32 int child_func(const char *argv0) { 33 // we need to avoid memory modifications for vfork(), yet we want 34 // to be able to test watchpoints, so do the next best thing 35 // and restore the original value 36 g_val = 2; 37 g_val = 0; 38 execl(argv0, argv0, parent_done_str, NULL); 39 assert(0 && "this should not be reached"); 40 return 1; 41 } 42 43 int child_top_func(void *argv0_ptr) { 44 const char *argv0 = static_cast<char*>(argv0_ptr); 45 46 int ret = close(parent_done[1]); 47 assert(ret == 0); 48 49 // NB: when using vfork(), the parent may be suspended while running 50 // this function, so do not rely on any synchronization until we exec 51 #if defined(TEST_FORK) 52 if (TEST_FORK != vfork) 53 #endif 54 wait_for_parent(); 55 56 return child_func(argv0); 57 } 58 59 int main(int argc, char* argv[]) { 60 alignas(uintmax_t) char stack[4096]; 61 int ret; 62 63 if (argv[1]) { 64 parent_done[0] = atoi(argv[1]); 65 assert(parent_done[0] != 0); 66 67 #if defined(TEST_FORK) 68 // for vfork(), we need to synchronize after exec 69 if (TEST_FORK == vfork) 70 wait_for_parent(); 71 #endif 72 73 fprintf(stderr, "function run in exec'd child\n"); 74 return 0; 75 } 76 77 ret = pipe(parent_done); 78 assert(ret == 0); 79 80 ret = snprintf(parent_done_str, sizeof(parent_done_str), 81 "%d", parent_done[0]); 82 assert(ret != -1); 83 84 #if defined(TEST_CLONE) 85 pid_t pid = clone(child_top_func, &stack[sizeof(stack)], 0, argv[0]); 86 #elif defined(TEST_FORK) 87 pid_t pid = TEST_FORK(); 88 // NB: this must be equivalent to the clone() call above 89 if (pid == 0) 90 _exit(child_top_func(argv[0])); 91 #endif 92 assert(pid != -1); 93 94 ret = close(parent_done[0]); 95 assert(ret == 0); 96 97 parent_func(); 98 99 // resume the child 100 ret = write(parent_done[1], "go", 2); 101 assert(ret == 2); 102 ret = close(parent_done[1]); 103 assert(ret == 0); 104 105 int status, wait_flags = 0; 106 #if defined(TEST_CLONE) 107 wait_flags = __WALL; 108 #endif 109 pid_t waited = waitpid(pid, &status, wait_flags); 110 assert(waited == pid); 111 assert(WIFEXITED(status)); 112 assert(WEXITSTATUS(status) == 0); 113 114 return 0; 115 } 116