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;
}
```