The test program I'm using right now:
#include <sys/types.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <assert.h> #include <signal.h> #include <spawn.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <pthread.h> #include <unistd.h> volatile int g_val = 0; void* thread1(void* data) { while (1) sleep(1); return NULL; } void* thread2(void* data) { sleep(1); int ret = raise(SIGSTOP); assert(ret != -1); return NULL; } int main() { int ret; pid_t pid = fork(); assert(pid != -1); if (pid == 0) { /* child -- debugged program */ printf("child pid: %ld\n", getpid()); /* request tracing */ ret = ptrace(PT_TRACE_ME, 0, NULL, 0); assert(ret != -1); /* start threads */ pthread_t t1, t2; ret = pthread_create(&t1, NULL, thread1, NULL); assert(ret == 0); ret = pthread_create(&t2, NULL, thread2, NULL); assert(ret == 0); /* join threads */ ret = pthread_join(t1, NULL); assert(ret == 0); ret = pthread_join(t2, NULL); assert(ret == 0); _exit(0); } /* parent -- the debugger */ printf("parent pid: %ld\n", getpid()); pid_t waited; /* SIGSTOP for the process */ waited = waitpid(pid, &ret, 0); assert(waited == pid); assert(WIFSTOPPED(ret)); assert(WSTOPSIG(ret) == SIGSTOP); /* get thread list */ lwpid_t lwps[4]; ret = ptrace(PT_GETLWPLIST, pid, lwps, 4); for (int i = 0; i < ret; ++i) printf("lwp[%d] = %d\n", i, lwps[i]); /* request coredump */ struct ptrace_coredump cd = {}; cd.pc_fd = open("/tmp/mycore", O_WRONLY|O_CREAT, 0666); cd.pc_limit = 0; ret = ptrace(PT_COREDUMP, lwps[0], (void*)&cd, sizeof(cd)); assert(ret == 0); close(cd.pc_fd); /* resume the process */ #if 0 /* TODO: make it stop after coredump */ ret = ptrace(PT_CONTINUE, waited, (void*)1, 0); assert(ret == 0); #endif /* wait for exit */ waited = waitpid(pid, &ret, 0); assert(waited == pid); assert(WIFEXITED(ret)); assert(WEXITSTATUS(ret) == 0); return 0; }