Created
November 9, 2020 11:43
-
-
Save kostikbel/d2894a187ab1e16f6fb1cddf39f7b969 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* $Id: thread-dbreg-test-pt2.c,v 1.7 2020/11/09 11:42:26 kostik Exp kostik $ */ | |
#include <sys/types.h> | |
#include <sys/ptrace.h> | |
#include <sys/wait.h> | |
#include <machine/reg.h> | |
#include <assert.h> | |
#include <err.h> | |
#include <pthread.h> | |
#include <signal.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
volatile int g_val; | |
volatile int g_val2; | |
static void * | |
thread_func(void* foo __unused) { | |
return (NULL); | |
} | |
static void | |
waitdbg(pid_t pid, int sig) | |
{ | |
pid_t waited; | |
int nthr, ret; | |
waited = waitpid(pid, &ret, 0); | |
printf("wait: pid=%d, waited=%d, ret=%x\n", pid, waited, ret); | |
assert(waited == pid); | |
if (sig < 0) { | |
assert(WIFEXITED(ret)); | |
return; | |
} | |
assert(WSTOPSIG(ret) == sig); | |
nthr = ptrace(PT_GETNUMLWPS, pid, NULL, 0); | |
if (nthr == -1) | |
err(1, "PT_GETNUMLWPS"); | |
lwpid_t ids[nthr]; | |
ret = ptrace(PT_GETLWPLIST, pid, (caddr_t)&ids, nthr); | |
if (ret == -1) | |
err(1, "PT_GETLWPLIST"); | |
printf("threads:"); | |
for (int i = 0; i < nthr; i++) | |
printf(" %d", ids[i]); | |
printf("\n"); | |
} | |
int | |
main(void) | |
{ | |
int ret; | |
int pid = fork(); | |
assert(pid != -1); | |
if (pid == 0) { | |
pthread_t t2; | |
ret = ptrace(PT_TRACE_ME, 0, NULL, 0); | |
assert(ret != -1); | |
// 2. wait for parent to set dbregs | |
raise(SIGSTOP); | |
// 4. start new thread and stop immediately afterwards | |
ret = pthread_create(&t2, NULL, thread_func, NULL); | |
assert(ret == 0); | |
raise(SIGSTOP); | |
printf("thread started\n"); | |
ret = pthread_join(t2, NULL); | |
assert(ret == 0); | |
printf("thread joined\n"); | |
_exit(0); | |
} | |
// 1. wait for the child to start | |
waitdbg(pid, SIGSTOP); | |
struct ptrace_lwpinfo info; | |
ret = ptrace(PT_LWPINFO, pid, (caddr_t)&info, sizeof(info)); | |
assert(ret != -1); | |
assert(info.pl_flags == PL_FLAG_SI); | |
printf("tid = %d, SIGSTOP\n", info.pl_lwpid); | |
// 3. set event mask & dbregs | |
int ev = PTRACE_LWP; | |
ret = ptrace(PT_SET_EVENT_MASK, pid, (caddr_t)&ev, sizeof(ev)); | |
assert(ret != -1); | |
struct dbreg db; | |
ret = ptrace(PT_GETDBREGS, info.pl_lwpid, (caddr_t)&db, 0); | |
assert(ret != -1); | |
db.dr[0] = (uintptr_t)&g_val; | |
db.dr[7] = 0x303; | |
ret = ptrace(PT_SETDBREGS, info.pl_lwpid, (caddr_t)&db, 0); | |
assert(ret != -1); | |
printf("set DR0=%p (&g_val) on tid=%d\n", (void*)db.dr[0], info.pl_lwpid); | |
ret = ptrace(PT_CONTINUE, pid, (caddr_t)1, 0); | |
assert(ret != -1); | |
// 5. we should get SIGSTOP first, change dbregs | |
waitdbg(pid, SIGSTOP); | |
ret = ptrace(PT_LWPINFO, pid, (caddr_t)&info, sizeof(info)); | |
assert(ret != -1); | |
assert(info.pl_flags == PL_FLAG_SI); | |
printf("tid = %d, SIGSTOP\n", info.pl_lwpid); | |
ret = ptrace(PT_GETDBREGS, info.pl_lwpid, (caddr_t)&db, 0); | |
assert(ret != -1); | |
db.dr[0] = (uintptr_t)&g_val2; | |
db.dr[7] = 0x303; | |
ret = ptrace(PT_SETDBREGS, info.pl_lwpid, (caddr_t)&db, 0); | |
assert(ret != -1); | |
printf("set DR0=%p (&g_val2) on tid=%d\n", (void*)db.dr[0], info.pl_lwpid); | |
ret = ptrace(PT_CONTINUE, pid, (caddr_t)1, 0); | |
assert(ret != -1); | |
// 6. now we should get the new thread event | |
waitdbg(pid, SIGTRAP); | |
ret = ptrace(PT_LWPINFO, pid, (caddr_t)&info, sizeof(info)); | |
assert(ret != -1); | |
assert(info.pl_flags & PL_FLAG_BORN); | |
printf("tid = %d, SIGTRAP w/ PL_FLAG_BORN\n", info.pl_lwpid); | |
ret = ptrace(PT_GETDBREGS, info.pl_lwpid, (caddr_t)&db, 0); | |
assert(ret != -1); | |
printf("dr0=%p, g_val=%p, g_val2=%p\n", (void*)db.dr[0], &g_val, &g_val2); | |
ret = ptrace(PT_CONTINUE, pid, (caddr_t)1, 0); | |
assert(ret != -1); | |
// thread exited | |
waitdbg(pid, SIGTRAP); | |
ret = ptrace(PT_LWPINFO, pid, (caddr_t)&info, sizeof(info)); | |
assert(ret != -1); | |
assert(info.pl_flags & PL_FLAG_EXITED); | |
printf("tid = %d, SIGTRAP w/ PL_FLAG_EXITED\n", info.pl_lwpid); | |
ret = ptrace(PT_CONTINUE, pid, (caddr_t)1, 0); | |
assert(ret != -1); | |
waitdbg(pid, -1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment