1 | #include <stdlib.h> |
2 | #include <string.h> |
3 | #include <stdio.h> |
4 | #include <signal.h> |
5 | #include <unistd.h> |
6 | #include <sys/mman.h> |
7 | |
8 | #include "utils.h" |
9 | |
10 | extern char __start___ex_table[]; |
11 | extern char __stop___ex_table[]; |
12 | |
13 | #if defined(__powerpc64__) |
14 | #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP] |
15 | #elif defined(__powerpc__) |
16 | #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP] |
17 | #else |
18 | #error implement UCONTEXT_NIA |
19 | #endif |
20 | |
21 | static void segv_handler(int signr, siginfo_t *info, void *ptr) |
22 | { |
23 | ucontext_t *uc = (ucontext_t *)ptr; |
24 | unsigned long addr = (unsigned long)info->si_addr; |
25 | unsigned long *ip = &UCONTEXT_NIA(uc); |
26 | unsigned long *ex_p = (unsigned long *)__start___ex_table; |
27 | |
28 | while (ex_p < (unsigned long *)__stop___ex_table) { |
29 | unsigned long insn, fixup; |
30 | |
31 | insn = *ex_p++; |
32 | fixup = *ex_p++; |
33 | |
34 | if (insn == *ip) { |
35 | *ip = fixup; |
36 | return; |
37 | } |
38 | } |
39 | |
40 | printf("No exception table match for NIA %lx ADDR %lx\n" , *ip, addr); |
41 | abort(); |
42 | } |
43 | |
44 | static void setup_segv_handler(void) |
45 | { |
46 | struct sigaction action; |
47 | |
48 | memset(&action, 0, sizeof(action)); |
49 | action.sa_sigaction = segv_handler; |
50 | action.sa_flags = SA_SIGINFO; |
51 | sigaction(SIGSEGV, &action, NULL); |
52 | } |
53 | |
54 | unsigned long COPY_LOOP(void *to, const void *from, unsigned long size); |
55 | unsigned long test_copy_tofrom_user_reference(void *to, const void *from, unsigned long size); |
56 | |
57 | static int total_passed; |
58 | static int total_failed; |
59 | |
60 | static void do_one_test(char *dstp, char *srcp, unsigned long len) |
61 | { |
62 | unsigned long got, expected; |
63 | |
64 | got = COPY_LOOP(to: dstp, from: srcp, size: len); |
65 | expected = test_copy_tofrom_user_reference(to: dstp, from: srcp, size: len); |
66 | |
67 | if (got != expected) { |
68 | total_failed++; |
69 | printf("FAIL from=%p to=%p len=%ld returned %ld, expected %ld\n" , |
70 | srcp, dstp, len, got, expected); |
71 | //abort(); |
72 | } else |
73 | total_passed++; |
74 | } |
75 | |
76 | //#define MAX_LEN 512 |
77 | #define MAX_LEN 16 |
78 | |
79 | int test_copy_exception(void) |
80 | { |
81 | int page_size; |
82 | static char *p, *q; |
83 | unsigned long src, dst, len; |
84 | |
85 | page_size = getpagesize(); |
86 | p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE, |
87 | MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
88 | |
89 | if (p == MAP_FAILED) { |
90 | perror("mmap" ); |
91 | exit(1); |
92 | } |
93 | |
94 | memset(p, 0, page_size); |
95 | |
96 | setup_segv_handler(); |
97 | |
98 | if (mprotect(p + page_size, page_size, PROT_NONE)) { |
99 | perror("mprotect" ); |
100 | exit(1); |
101 | } |
102 | |
103 | q = p + page_size - MAX_LEN; |
104 | |
105 | for (src = 0; src < MAX_LEN; src++) { |
106 | for (dst = 0; dst < MAX_LEN; dst++) { |
107 | for (len = 0; len < MAX_LEN+1; len++) { |
108 | // printf("from=%p to=%p len=%ld\n", q+dst, q+src, len); |
109 | do_one_test(dstp: q+dst, srcp: q+src, len); |
110 | } |
111 | } |
112 | } |
113 | |
114 | printf("Totals:\n" ); |
115 | printf(" Pass: %d\n" , total_passed); |
116 | printf(" Fail: %d\n" , total_failed); |
117 | |
118 | return 0; |
119 | } |
120 | |
121 | int main(void) |
122 | { |
123 | return test_harness(test_copy_exception, str(COPY_LOOP)); |
124 | } |
125 | |