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(void) 54{ 55 int foo; 56 bottom_of_stack = &foo - 4; 57 /* EAX is used by compiler-generated code to 58 * increment ran_after_fault, so we need to 59 * preserve it in our asm section */ 60 unsigned long saved_eax; 61 62 /* Set up registers with known values which will be tested in the signal handler */ 63 __asm__ volatile("movl %%eax, %0" : "=m"(saved_eax)); 64 __asm__ volatile("movl $0xfeed0101,%eax"); 65 __asm__ volatile("movl $0xfeed0202,%ebx"); 66 __asm__ volatile("movl $0xfeed0303,%ecx"); 67 __asm__ volatile("movl $0xfeed0404,%edx"); 68 __asm__ volatile("movl $0xfeed0505,%edi"); 69 __asm__ volatile("movl $0xfeed0606,%esi"); 70 __asm__ volatile("hlt"); 71 __asm__ volatile("movl %0, %%eax" : : "m"(saved_eax)); 72 ran_after_fault++; 73} 74 75void this_function_int3s(void) 76{ 77 int foo; 78 bottom_of_stack = &foo - 4; 79 unsigned long saved_eax; 80 81 /* Set up registers with known values which will be tested in the signal handler */ 82 __asm__ volatile("movl %%eax, %0" : "=m"(saved_eax)); 83 __asm__ volatile("movl $0xfeed0101,%eax"); 84 __asm__ volatile("movl $0xfeed0202,%ebx"); 85 __asm__ volatile("movl $0xfeed0303,%ecx"); 86 __asm__ volatile("movl $0xfeed0404,%edx"); 87 __asm__ volatile("movl $0xfeed0505,%edi"); 88 __asm__ volatile("movl $0xfeed0606,%esi"); 89 __asm__ volatile("int $3"); 90 __asm__ volatile("movl %0, %%eax" : : "m"(saved_eax)); 91 ran_after_fault++; 92} 93 94 95static void 96handle_signal(int sig, siginfo_t *si, void *vuc) 97{ 98 ucontext_t *uc = (ucontext_t *)vuc; 99 100 if (verbose) 101 { 102 fprintf(stderr, "handle_signal\n"); 103 fflush(stderr); 104 } 105 106 sig_count++; 107 ASSERT(sig_count == 1); 108 109 int expected_sig = (using_int3 ? SIGTRAP : SIGSEGV); 110 ASSERT_EQ(sig, expected_sig); 111 ASSERT_NE(si, NULL); 112 ASSERT_NE(uc, NULL); 113 ASSERT_NE(uc->uc_mcontext, NULL); 114 115 /* Test that the siginfo is set up right for this signal */ 116 ASSERT_EQ(si->si_signo, expected_sig); 117 ASSERT_EQ(si->si_errno, 0); 118 int expected_code = (using_int3 ? 1 : 0); 119 ASSERT_EQ(si->si_code, expected_code); 120 ASSERT_EQ(si->si_pid, 0); 121 ASSERT_EQ(si->si_uid, 0); 122 ASSERT_EQ(si->si_status, 0); 123 ASSERT_EQ(si->si_addr, 0); 124 ASSERT_EQ(si->si_band, 0); 125 126 /* Test that various registers were saved in the signal ucontext */ 127 ASSERT_EQ(uc->uc_mcontext->__ss.__eax, 0xfeed0101); 128 ASSERT_EQ(uc->uc_mcontext->__ss.__ebx, 0xfeed0202); 129 ASSERT_EQ(uc->uc_mcontext->__ss.__ecx, 0xfeed0303); 130 ASSERT_EQ(uc->uc_mcontext->__ss.__edx, 0xfeed0404); 131 ASSERT_EQ(uc->uc_mcontext->__ss.__edi, 0xfeed0505); 132 ASSERT_EQ(uc->uc_mcontext->__ss.__esi, 0xfeed0606); 133 134 /* Test that the saved EBP and ESP point into roughly the right 135 * part of the stack */ 136 ASSERT_GTE(uc->uc_mcontext->__ss.__ebp, bottom_of_stack); 137 ASSERT_LTE(uc->uc_mcontext->__ss.__ebp, top_of_stack); 138 ASSERT_GTE(uc->uc_mcontext->__ss.__esp, bottom_of_stack); 139 ASSERT_LTE(uc->uc_mcontext->__ss.__esp, top_of_stack); 140 141 /* Test that the saved EIP points into roughly the 142 * right part of the text segment */ 143 char *calling_fn = (using_int3 ? (char *)&this_function_int3s : (char *)&this_function_halts); 144 ASSERT_GTE(uc->uc_mcontext->__ss.__eip, calling_fn); 145 ASSERT_LTE(uc->uc_mcontext->__ss.__eip, calling_fn+400); 146 147 /* 148 printf(" RFLAGS 0x%016llx\n", (unsigned long long)uc->uc_mcontext->__ss.__rflags); 149 */ 150 151 /* 152 * Test that the EIP is restored from the signal ucontext; 153 * this should skip past the HLT/INT instruction and 154 * allow execution to continue back out to main() 155 */ 156 if (verbose) 157 { 158 fprintf(stderr, "Setting up to return past the HLT\n"); 159 fflush(stderr); 160 } 161 uc->uc_mcontext->__ss.__eip += (using_int3 ? 0 : 1); 162 163 if (verbose) 164 { 165 fprintf(stderr, "Returning from signal handler\n"); 166 fflush(stderr); 167 } 168} 169 170int main(int argc, char **argv) 171{ 172 int r; 173 struct sigaction act; 174 175 top_of_stack = (void *)&act; 176 177 if (argc > 1 && !strcmp(argv[1], "--verbose")) 178 verbose = 1; 179 180 if (verbose) 181 printf("Setting up signal handler\n"); 182 memset(&act, 0, sizeof(act)); 183 act.sa_sigaction = handle_signal; 184 act.sa_flags |= SA_SIGINFO; 185 if (RUNNING_ON_VALGRIND) 186 using_int3 = true; 187 r = sigaction((using_int3 ? SIGTRAP : SIGSEGV), &act, NULL); 188 ASSERT_EQ(r, 0); 189 190 if (verbose) 191 { 192 fprintf(stderr, "Calling function with a breakpoint insn in it\n"); 193 fflush(stderr); 194 } 195 if (using_int3) 196 this_function_int3s(); 197 else 198 this_function_halts(); 199 ASSERT_EQ(ran_after_fault, 1); 200 201 fprintf(stderr, "PASS\n"); 202 return 0; 203} 204