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(void)53 void 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 
this_function_int3s(void)75 void 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 
95 static void
handle_signal(int sig,siginfo_t * si,void * vuc)96 handle_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 
main(int argc,char ** argv)170 int 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