Home | History | Annotate | Download | only in amd64-darwin
      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 
     13 static 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 
     47 static bool using_int3 = false;
     48 static volatile int sig_count = 0;
     49 static volatile int ran_after_fault = 0;
     50 static void *top_of_stack;
     51 static void *bottom_of_stack;
     52 
     53 void 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 
     73 void 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 
     94 static void
     95 handle_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 
    180 int 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