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