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 
this_function_halts(unsigned long long a0,unsigned long long a1,unsigned long long a2,unsigned long long a3,unsigned long long a4,unsigned long long a5)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 
this_function_int3s(unsigned long long a0,unsigned long long a1,unsigned long long a2,unsigned long long a3,unsigned long long a4,unsigned long long a5)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
handle_signal(int sig,siginfo_t * si,void * vuc)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 
main(int argc,char ** argv)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