14 struct timespec value;
15 return clock_gettime(CLOCK_MONOTONIC, &value)
17 : (int64_t)value.tv_sec * INT64_C(1000000000) + value.tv_nsec;
20static int transfer(
int fd,
void* data,
size_t size,
int writing) {
21 unsigned char* bytes = data;
22 int64_t now = tc_now();
25 const int64_t end = now + INT64_C(10000000000);
34 struct pollfd ready = {.fd = fd, .events = writing ? POLLOUT : POLLIN};
35 int result = poll(&ready, 1, (
int)((end - now) / 1000000 + 1));
36 if (result < 0 && errno == EINTR)
43 ssize_t count = writing ? write(fd, bytes, size) : read(fd, bytes, size);
44 if (count < 0 && (errno == EINTR || errno == EAGAIN))
52 size -= (size_t)count;
57int tc_read(
int fd,
void* data,
size_t size) {
58 return transfer(fd, data, size, 0);
61int tc_write(
int fd,
const void* data,
size_t size) {
62 return transfer(fd, (
void*)data, size, 1);
65int tc_wait(pid_t pid,
int* status,
int milliseconds) {
66 int64_t now = tc_now();
69 const int64_t end = now + (int64_t)milliseconds * 1000000;
71 pid_t result = wait4(pid, status, WNOHANG, NULL);
74 if (result < 0 && errno != EINTR)
76 struct timespec delay = {0, 2000000};
77 nanosleep(&delay, NULL);
86void tc_cleanup(pid_t* pid) {
90 int64_t now = tc_now();
91 const int64_t end = now + INT64_C(2000000000);
92 while (now >= 0 && now < end) {
94 int result = tc_wait(*pid, &status, (
int)((end - now) / 1000000 + 1));
95 if ((!result && (WIFEXITED(status) || WIFSIGNALED(status))) || (result && errno == ECHILD)) {
103 fprintf(stderr,
"child cleanup incomplete pid=%d errno=%d\n", *pid, errno);
106int tc_atomic_wait(atomic_uint* value,
unsigned expected) {
107 int64_t now = tc_now(), end = now + INT64_C(10000000000);
108 while (now >= 0 && now < end) {
109 if (atomic_load(value) == expected)
119int tc_send(
const struct tc_child* child,
int operation,
int signal) {
120 struct tc_command command = {operation, signal};
121 return tc_write(child->command, &command,
sizeof(command));
132 fprintf(stderr,
"report actual=%c expected=%c signal=%d code=%d result=%lld error=%d\n",
139int tc_spawn(
struct tc_child* child,
int traced) {
140 int command[2], report[2];
141 if (pipe2(command, O_CLOEXEC | O_NONBLOCK))
143 if (pipe2(report, O_CLOEXEC | O_NONBLOCK)) {
152 tc_tracee(command[0], report[1], traced);
162 *child = (
struct tc_child){pid, command[1], report[0]};
164 if (tc_receive(child->report,
'R', &ready) || ready.result) {
166 fprintf(stderr,
"TRACEME startup result=%lld errno=%d\n", (
long long)ready.result,
174void tc_close(
struct tc_child* child) {
175 tc_cleanup(&child->pid);
176 if (child->command >= 0)
177 close(child->command);
178 if (child->report >= 0)
179 close(child->report);
180 *child = (
struct tc_child)TC_CHILD_INIT;
183int tc_stop(
struct tc_child* child,
int signal) {
184 if (tc_send(child,
'S', signal))
186 return tc_wait_stop(child, signal);
189int tc_wait_stop(
struct tc_child* child,
int signal) {
191 if (tc_wait(child->pid, &status, 10000))
193 if (WIFEXITED(status) || WIFSIGNALED(status))
195 if (WIFSTOPPED(status) && WSTOPSIG(status) == signal)
197 fprintf(stderr,
"stop signal=%d actual status=%#x\n", signal, status);
201int tc_finish(
struct tc_child* child) {
202 if (tc_send(child,
'E', 0) || tc_receive(child->report,
'E', NULL))
205 if (tc_wait(child->pid, &status, 10000))
207 if (WIFEXITED(status) || WIFSIGNALED(status))
209 if (WIFEXITED(status) && WEXITSTATUS(status) == TC_EXIT_CODE)
211 fprintf(stderr,
"exit status=%#x\n", status);
215int tc_resume(pid_t child,
int request,
int signal) {
216 return (
int)ptrace(request, child, (
void*)0, (
void*)(uintptr_t)(
unsigned)signal);
219int tc_signal_info(
const siginfo_t* info,
int signal,
int code, pid_t pid, uid_t uid) {
220 if (info->si_signo == signal && !info->si_errno && info->si_code == code && info->si_pid == pid &&
223 fprintf(stderr,
"siginfo actual=%d/%d/%d/%d/%u expected=%d/0/%d/%d/%u\n", info->si_signo,
224 info->si_errno, info->si_code, info->si_pid, info->si_uid, signal, code, pid, uid);