int my_entrance() { if (fork_syscall() == 0) { // son while(1) { print_char('S'); } } else { // dad while(1) { print_char('D'); } } return 0; }
void stackdump(void) { int pid, core_pid; /* get name now -- will be same for children */ char *exec_name = get_application_name(); char core_name[128]; char tmp_name[128]; snprintf(tmp_name, 128, "%s.%d", TEMPORARY_FILENAME, get_process_id()); #ifdef VMX86_SERVER if (os_in_vmkernel_userworld()) { return; /* no local gdb, no multithreaded fork */ } #endif #if VERBOSE SYSLOG_INTERNAL_ERROR("about to fork parent %d to dump core", get_process_id()); #endif /* Fork a child to dump core */ pid = fork_syscall(); if (pid == 0) { /* child */ #if VERBOSE SYSLOG_INTERNAL_ERROR("about to dump core in process %d parent %d thread " TIDFMT "", get_process_id(), get_parent_id(), get_thread_id()); #endif /* We used to use abort here, but that had lots of complications with * pthreads and libc, so now we just dereference NULL. */ if (!set_default_signal_action(SIGSEGV)) { SYSLOG_INTERNAL_ERROR("ERROR in setting handler"); exit_process_syscall(1); } *(volatile int *)NULL = 0; #if VERBOSE SYSLOG_INTERNAL_ERROR("about to exit process %d", get_process_id()); #endif exit_process_syscall(0); } else if (pid == -1) { SYSLOG_INTERNAL_ERROR("ERROR: could not fork to dump core"); exit_process_syscall(1); } #if VERBOSE SYSLOG_INTERNAL_ERROR("parent %d %d waiting for child %d", get_process_id(), get_thread_id(), pid); #endif /* Parent continues */ core_pid = pid; while (wait_syscall(NULL) != pid) { /* wait for core to be dumped */ } #if VERBOSE SYSLOG_INTERNAL_ERROR("about to fork 2nd child to run gdb"); #endif /* Fork a 2nd child to run gdb */ pid = fork_syscall(); if (pid == 0) { /* child */ file_t fp; int fd; const char *argv[16]; int i; int execve_errno; /* Open a temporary file for the input: the "where" command */ fp = os_open(tmp_name, OS_OPEN_REQUIRE_NEW | OS_OPEN_WRITE); os_write(fp, DEBUGGER_COMMAND, strlen(DEBUGGER_COMMAND)); os_close(fp); fd = open_syscall(tmp_name, O_RDONLY, 0); if (fd < 0) { SYSLOG_INTERNAL_ERROR("ERROR: open failed on temporary file"); exit_process_syscall(1); } #if !BATCH_MODE /* Redirect stdin from the temporary file */ close_syscall(0); /* close stdin */ dup_syscall(fd); /* replace file descriptor 0 with reference to temp file */ #endif close_syscall(fd); /* close the other reference to temporary file */ /* Find the core file */ strncpy(core_name, CORE_NAME, 127); core_name[127] = '\0'; /* if max no null */ fd = open_syscall(core_name, O_RDONLY, 0); if (fd < 0) { snprintf(core_name, 128, "%s.%d", CORE_NAME, core_pid); SYSLOG_INTERNAL_ERROR("core not found, trying %s", core_name); fd = open_syscall(core_name, O_RDONLY, 0); if (fd < 0) { SYSLOG_INTERNAL_ERROR("ERROR: no core file found!"); exit_process_syscall(1); } } close_syscall(fd); /* avoid running the debugger under us! * FIXME: just remove our libraries, instead of entire env var? */ unsetenv("LD_PRELOAD"); SYSLOG_INTERNAL_ERROR("-------------------------------------------"); SYSLOG_INTERNAL_ERROR("stackdump: --- now running the debugger ---"); SYSLOG_INTERNAL_ERROR("%s %s %s %s", DEBUGGER, QUIET_MODE, exec_name, core_name); SYSLOG_INTERNAL_ERROR("-------------------------------------------"); i = 0; /* We rely on /usr/bin/env to do the PATH search for gdb on our behalf. */ argv[i++] = "/usr/bin/env"; argv[i++] = DEBUGGER; argv[i++] = QUIET_MODE; #if BATCH_MODE argv[i++] = "-x"; argv[i++] = tmp_name; argv[i++] = "-batch"; #endif argv[i++] = exec_name; argv[i++] = core_name; argv[i++] = NULL; execve_errno = execve_syscall("/usr/bin/env", argv, our_environ); SYSLOG_INTERNAL_ERROR("ERROR: execve failed for debugger: %d", -execve_errno); exit_process_syscall(1); } else if (pid == -1) { SYSLOG_INTERNAL_ERROR("ERROR: could not fork to run debugger"); exit_process_syscall(1); } /* Parent continues */ /* while(wait(NULL)>0) waits for all children, and could hang, so: */ while (wait_syscall(NULL) != pid) { /* empty loop */ } /* Wait for these children to complete before returning */ while (wait_syscall(NULL) > 0) { /* empty loop */ } os_delete_file(tmp_name); /* clean up the temporary file */ SYSLOG_INTERNAL_ERROR("-------------------------------------------"); }