#include #include #include #if defined(TEST_CLONE) #include #endif #include #include #include #include int g_val = 0; void parent_func() { g_val = 1; printf("function run in parent\n"); } int parent_done[2]; char parent_done_str[16]; void wait_for_parent() { char buf[2]; // wait for the parent to finish its part int ret = read(parent_done[0], buf, sizeof(buf)); assert(ret == 2); ret = close(parent_done[0]); assert(ret == 0); } // This is the function we set breakpoint on. int child_func(const char *argv0) { // we need to avoid memory modifications for vfork(), yet we want // to be able to test watchpoints, so do the next best thing // and restore the original value g_val = 2; g_val = 0; execl(argv0, argv0, parent_done_str, NULL); assert(0 && "this should not be reached"); return 1; } int child_top_func(void *argv0_ptr) { const char *argv0 = static_cast(argv0_ptr); int ret = close(parent_done[1]); assert(ret == 0); // NB: when using vfork(), the parent may be suspended while running // this function, so do not rely on any synchronization until we exec #if defined(TEST_FORK) if (TEST_FORK != vfork) #endif wait_for_parent(); return child_func(argv0); } int main(int argc, char* argv[]) { alignas(uintmax_t) char stack[4096]; int ret; if (argv[1]) { parent_done[0] = atoi(argv[1]); assert(parent_done[0] != 0); #if defined(TEST_FORK) // for vfork(), we need to synchronize after exec if (TEST_FORK == vfork) wait_for_parent(); #endif fprintf(stderr, "function run in exec'd child\n"); return 0; } ret = pipe(parent_done); assert(ret == 0); ret = snprintf(parent_done_str, sizeof(parent_done_str), "%d", parent_done[0]); assert(ret != -1); #if defined(TEST_CLONE) pid_t pid = clone(child_top_func, &stack[sizeof(stack)], 0, argv[0]); #elif defined(TEST_FORK) pid_t pid = TEST_FORK(); // NB: this must be equivalent to the clone() call above if (pid == 0) _exit(child_top_func(argv[0])); #endif assert(pid != -1); ret = close(parent_done[0]); assert(ret == 0); parent_func(); // resume the child ret = write(parent_done[1], "go", 2); assert(ret == 2); ret = close(parent_done[1]); assert(ret == 0); int status, wait_flags = 0; #if defined(TEST_CLONE) wait_flags = __WALL; #endif pid_t waited = waitpid(pid, &status, wait_flags); assert(waited == pid); assert(WIFEXITED(status)); assert(WEXITSTATUS(status) == 0); return 0; }