8static _Thread_local
volatile uint64_t tls_value;
10static void tracee(
int report) {
12 struct sigaction action = {.sa_handler = SIG_DFL};
13 sigemptyset(&action.sa_mask);
15 sigemptyset(&unblocked);
16 sigaddset(&unblocked, TC_STOP_SIGNAL);
17 sigaddset(&unblocked, SIGALRM);
18 if (sigaction(TC_STOP_SIGNAL, &action, NULL) || sigaction(SIGALRM, &action, NULL) ||
19 sigprocmask(SIG_UNBLOCK, &unblocked, NULL))
24 capture.resumed.orig_rax = UINT64_MAX;
25 capture.resumed.gs_base = UINT64_MAX;
26 capture.setup.pid = (uint64_t)getpid();
27 capture.setup.tid = (uint64_t)syscall(SYS_gettid);
28 tls_value = UINT64_C(0x1726354453627180);
29 if (syscall(SYS_arch_prctl, TC_ARCH_GET_FS, &capture.setup.fs_base))
32 if (ptrace(PTRACE_TRACEME, (pid_t)0, (
void*)0, (
void*)0))
34 if (tc_probe(report, &capture))
36 if (syscall(SYS_arch_prctl, TC_ARCH_GET_FS, &capture.resumed.fs_base) ||
37 capture.resumed.fs_base != capture.setup.fs_base || tls_value != UINT64_C(0x1726354453627180))
39 if (tc_write(report, &capture,
sizeof(capture)))
45static int matches(
const struct user_regs_struct* regs,
const struct tc_setup* setup,
46 uint64_t entry_flags,
int traced) {
47#define FIELD(name, expected) \
49 if (regs->name != (unsigned long)(expected)) { \
50 fprintf(stderr, "%s %s actual=%#lx expected=%#lx\n", traced ? "snapshot" : "resumed", #name, \
51 regs->name, (unsigned long)(expected)); \
55 FIELD(r15, TC_SENT_R15);
56 FIELD(r14, TC_SENT_R14);
57 FIELD(r13, TC_SENT_R13);
58 FIELD(r12, TC_SENT_R12);
59 FIELD(rbp, TC_SENT_RBP);
60 FIELD(rbx, TC_SENT_RBX);
61 FIELD(r10, TC_SENT_R10);
62 FIELD(r9, TC_SENT_R9);
63 FIELD(r8, TC_SENT_R8);
65 FIELD(rcx, setup->label);
66 FIELD(r11, entry_flags);
67 FIELD(rdi, setup->pid);
68 FIELD(rsi, setup->tid);
69 FIELD(rdx, TC_STOP_SIGNAL);
70 FIELD(rip, setup->label);
71 FIELD(rsp, setup->stack);
72 FIELD(eflags, entry_flags);
79 FIELD(fs_base, setup->fs_base);
81 FIELD(orig_rax, SYS_tgkill);
86int tc_registers(
void) {
87 int failed = 0, status = 0;
88 int report[2] = {-1, -1};
92 struct user_regs_struct saved;
94 struct user_regs_struct regs;
97 CHECK(pipe2(report, O_CLOEXEC | O_NONBLOCK) == 0);
107 CHECK(tc_read(report[0], &setup,
sizeof(setup)) == 0);
108 CHECK(setup.pid == (uint64_t)child && setup.tid == (uint64_t)child);
109 CHECK(setup.stack && setup.label && setup.fs_base);
110 CHECK(tc_wait(child, &status, 10000) == 0);
111 if (WIFEXITED(status) || WIFSIGNALED(status))
113 CHECK(WIFSTOPPED(status) && WSTOPSIG(status) == TC_STOP_SIGNAL);
116 memset(&first, 0xa5,
sizeof(first));
117 memset(&second, 0x5a,
sizeof(second));
118 CHECK(ptrace(PTRACE_GETREGS, child, (
void*)0, (
void*)&first.regs) == 0);
119 CHECK(ptrace(PTRACE_GETREGS, child, (
void*)0, (
void*)&second.regs) == 0);
120 CHECK(memcmp(&first.regs, &second.regs, TC_REG_SIZE) == 0);
121 CHECK(first.tail[0] == UINT64_C(0xa5a5a5a5a5a5a5a5) &&
122 first.tail[1] == UINT64_C(0xa5a5a5a5a5a5a5a5));
123 CHECK(second.tail[0] == UINT64_C(0x5a5a5a5a5a5a5a5a) &&
124 second.tail[1] == UINT64_C(0x5a5a5a5a5a5a5a5a));
126 CHECK(ptrace(PTRACE_CONT, child, (
void*)0, (
void*)0) == 0);
127 CHECK(tc_read(report[0], &capture,
sizeof(capture)) == 0);
128 CHECK(memcmp(&capture.setup, &setup,
sizeof(setup)) == 0);
129 CHECK(matches(&first.regs, &setup, capture.entry_flags, 1) == 0);
130 CHECK(matches(&capture.resumed, &setup, capture.entry_flags, 0) == 0);
131 CHECK(memcmp(&first.regs, &saved, TC_REG_SIZE) == 0);
132 CHECK(memcmp(&second.regs, &saved, TC_REG_SIZE) == 0);
133 CHECK(tc_wait(child, &status, 10000) == 0);
134 if (WIFEXITED(status) || WIFSIGNALED(status))
136 CHECK(WIFEXITED(status) && WEXITSTATUS(status) == 0);
139 fprintf(stderr,
"register family status=%#x child=%d\n", status, child);