1/* This changes the definition of ucontext_t */ 2#define _XOPEN_SOURCE 1 3#include <stdio.h> 4#include <unistd.h> 5#include <signal.h> 6#include <string.h> 7#include <stdbool.h> 8#include <valgrind.h> 9 10#define offsetof(type, fld) ((unsigned long)&((type *)0)->fld) 11#define stringify(x) #x 12 13static int verbose = 0; 14 15#define _ASSERT_OP(a, op, b) \ 16 do { \ 17 unsigned long long _a = (unsigned long long)(a); \ 18 unsigned long long _b = (unsigned long long)(b); \ 19 if (verbose) \ 20 fprintf(stderr, "%s:%d: ASSERT(" stringify(a) \ 21 " " stringify(op) " " stringify(b) ")\n", \ 22 __FILE__, __LINE__); \ 23 if (!(_a op _b)) { \ 24 fprintf(stderr, "%s:%d: FAILED ASSERT((" stringify(a) \ 25 "=0x%016llx) " stringify(op) " (" stringify(b) "=0x%016llx))\n", \ 26 __FILE__, __LINE__, _a, _b); \ 27 _exit(1); \ 28 } \ 29 } while(0) 30#define ASSERT_EQ(a, b) _ASSERT_OP(a, ==, b) 31#define ASSERT_NE(a, b) _ASSERT_OP(a, !=, b) 32#define ASSERT_LTE(a, b) _ASSERT_OP(a, <=, b) 33#define ASSERT_GTE(a, b) _ASSERT_OP(a, >=, b) 34#define ASSERT(e) \ 35 do { \ 36 if (verbose) \ 37 fprintf(stderr, "%s:%d: ASSERT(" stringify(e) ")\n", \ 38 __FILE__, __LINE__); \ 39 if (!(e)) { \ 40 fprintf(stderr, "%s:%d: FAILED ASSERT(" stringify(e) ")\n", \ 41 __FILE__, __LINE__); \ 42 _exit(1); \ 43 } \ 44 } while(0) 45 46 47static bool using_int3 = false; 48static volatile int sig_count = 0; 49static volatile int ran_after_fault = 0; 50static void *top_of_stack; 51static void *bottom_of_stack; 52 53void this_function_halts(unsigned long long a0, unsigned long long a1, 54 unsigned long long a2, unsigned long long a3, 55 unsigned long long a4, unsigned long long a5) 56{ 57 int foo; 58 bottom_of_stack = &foo; 59 60 /* Set up registers with known values which will be tested in the signal handler */ 61 __asm__ volatile("movq $0xfeed01010101cafe,%rax"); 62 __asm__ volatile("movq $0xfeed02020202cafe,%rbx"); 63 __asm__ volatile("movq $0xfeed03030303cafe,%r10"); 64 __asm__ volatile("movq $0xfeed04040404cafe,%r11"); 65 __asm__ volatile("movq $0xfeed05050505cafe,%r12"); 66 __asm__ volatile("movq $0xfeed06060606cafe,%r13"); 67 __asm__ volatile("movq $0xfeed07070707cafe,%r14"); 68 __asm__ volatile("movq $0xfeed08080808cafe,%r15"); 69 __asm__ volatile("hlt"); 70 ran_after_fault++; 71} 72 73void this_function_int3s(unsigned long long a0, unsigned long long a1, 74 unsigned long long a2, unsigned long long a3, 75 unsigned long long a4, unsigned long long a5) 76{ 77 int foo; 78 bottom_of_stack = &foo; 79 80 /* Set up registers with known values which will be tested in the signal handler */ 81 __asm__ volatile("movq $0xfeed01010101cafe,%rax"); 82 __asm__ volatile("movq $0xfeed02020202cafe,%rbx"); 83 __asm__ volatile("movq $0xfeed03030303cafe,%r10"); 84 __asm__ volatile("movq $0xfeed04040404cafe,%r11"); 85 __asm__ volatile("movq $0xfeed05050505cafe,%r12"); 86 __asm__ volatile("movq $0xfeed06060606cafe,%r13"); 87 __asm__ volatile("movq $0xfeed07070707cafe,%r14"); 88 __asm__ volatile("movq $0xfeed08080808cafe,%r15"); 89 __asm__ volatile("int $3"); 90 ran_after_fault++; 91} 92 93 94static void 95handle_signal(int sig, siginfo_t *si, void *vuc) 96{ 97 ucontext_t *uc = (ucontext_t *)vuc; 98 99 if (verbose) 100 { 101 fprintf(stderr, "handle_signal\n"); 102 fflush(stderr); 103 } 104 105 sig_count++; 106 ASSERT(sig_count == 1); 107 108 int expected_sig = (using_int3 ? SIGTRAP : SIGSEGV); 109 ASSERT_EQ(sig, expected_sig); 110 ASSERT_NE(si, NULL); 111 ASSERT_NE(uc, NULL); 112 ASSERT_NE(uc->uc_mcontext, NULL); 113 114 /* Test that the siginfo is set up right for this signal */ 115 ASSERT_EQ(si->si_signo, expected_sig); 116 ASSERT_EQ(si->si_errno, 0); 117 int expected_code = (using_int3 ? 1 : 0); 118 ASSERT_EQ(si->si_code, expected_code); 119 ASSERT_EQ(si->si_pid, 0); 120 ASSERT_EQ(si->si_uid, 0); 121 ASSERT_EQ(si->si_status, 0); 122 ASSERT_EQ(si->si_addr, 0); 123 ASSERT_EQ(si->si_band, 0); 124 125 /* Test that RAX is saved to the signal ucontext */ 126 ASSERT_EQ(uc->uc_mcontext->__ss.__rax, 0xfeed01010101cafe); 127 128 /* Test that the registers used to pass the 1st 6 129 * function arguments were saved in the signal ucontext */ 130 ASSERT_EQ(uc->uc_mcontext->__ss.__rdi, 0xbabe01010101cedeULL); 131 ASSERT_EQ(uc->uc_mcontext->__ss.__rsi, 0xbabe02020202cedeULL); 132 ASSERT_EQ(uc->uc_mcontext->__ss.__rdx, 0xbabe03030303cedeULL); 133 ASSERT_EQ(uc->uc_mcontext->__ss.__rcx, 0xbabe04040404cedeULL); 134 ASSERT_EQ(uc->uc_mcontext->__ss.__r8, 0xbabe05050505cedeULL); 135 ASSERT_EQ(uc->uc_mcontext->__ss.__r9, 0xbabe06060606cedeULL); 136 137 /* Test that the saved RBP and RSP point into roughly the right 138 * part of the stack */ 139 ASSERT_GTE(uc->uc_mcontext->__ss.__rbp, bottom_of_stack); 140 ASSERT_LTE(uc->uc_mcontext->__ss.__rbp, top_of_stack); 141 ASSERT_GTE(uc->uc_mcontext->__ss.__rsp, bottom_of_stack); 142 ASSERT_LTE(uc->uc_mcontext->__ss.__rsp, top_of_stack); 143 144 /* Test that the saved RIP points into roughly the 145 * right part of the text segment */ 146 char *calling_fn = (using_int3 ? (char *)&this_function_int3s : (char *)&this_function_halts); 147 ASSERT_GTE(uc->uc_mcontext->__ss.__rip, calling_fn); 148 ASSERT_LTE(uc->uc_mcontext->__ss.__rip, calling_fn+400); 149 150 ASSERT_EQ(uc->uc_mcontext->__ss.__rbx, 0xfeed02020202cafe); 151 ASSERT_EQ(uc->uc_mcontext->__ss.__r10, 0xfeed03030303cafe); 152 ASSERT_EQ(uc->uc_mcontext->__ss.__r11, 0xfeed04040404cafe); 153 ASSERT_EQ(uc->uc_mcontext->__ss.__r12, 0xfeed05050505cafe); 154 ASSERT_EQ(uc->uc_mcontext->__ss.__r13, 0xfeed06060606cafe); 155 ASSERT_EQ(uc->uc_mcontext->__ss.__r14, 0xfeed07070707cafe); 156 ASSERT_EQ(uc->uc_mcontext->__ss.__r15, 0xfeed08080808cafe); 157 /* 158 printf(" RFLAGS 0x%016llx\n", (unsigned long long)uc->uc_mcontext->__ss.__rflags); 159 */ 160 161 /* 162 * Test that the RIP is restored from the signal ucontext; 163 * this should skip past the HLT/INT instruction and 164 * allow execution to continue back out to main() 165 */ 166 if (verbose) 167 { 168 fprintf(stderr, "Setting up to return past the HLT\n"); 169 fflush(stderr); 170 } 171 uc->uc_mcontext->__ss.__rip += (using_int3 ? 0 : 1); 172 173 if (verbose) 174 { 175 fprintf(stderr, "Returning from signal handler\n"); 176 fflush(stderr); 177 } 178} 179 180int main(int argc, char **argv) 181{ 182 int r; 183 struct sigaction act; 184 185 top_of_stack = (void *)&act; 186 187 if (argc > 1 && !strcmp(argv[1], "--verbose")) 188 verbose = 1; 189 190 if (verbose) 191 printf("Setting up signal handler\n"); 192 memset(&act, 0, sizeof(act)); 193 act.sa_sigaction = handle_signal; 194 act.sa_flags |= SA_SIGINFO; 195 if (RUNNING_ON_VALGRIND) 196 using_int3 = true; 197 r = sigaction((using_int3 ? SIGTRAP : SIGSEGV), &act, NULL); 198 ASSERT_EQ(r, 0); 199 200 if (verbose) 201 { 202 fprintf(stderr, "Calling function with a breakpoint insn in it\n"); 203 fflush(stderr); 204 } 205 if (using_int3) 206 this_function_int3s(0xbabe01010101cedeULL, 207 0xbabe02020202cedeULL, 208 0xbabe03030303cedeULL, 209 0xbabe04040404cedeULL, 210 0xbabe05050505cedeULL, 211 0xbabe06060606cedeULL); 212 else 213 this_function_halts(0xbabe01010101cedeULL, 214 0xbabe02020202cedeULL, 215 0xbabe03030303cedeULL, 216 0xbabe04040404cedeULL, 217 0xbabe05050505cedeULL, 218 0xbabe06060606cedeULL); 219 ASSERT_EQ(ran_after_fault, 1); 220 221 fprintf(stderr, "PASS\n"); 222 return 0; 223} 224