0001 #include <stdlib.h>
0002 #include <string.h>
0003 #include <stdio.h>
0004 #include <signal.h>
0005 #include <unistd.h>
0006 #include <sys/mman.h>
0007
0008 #include "utils.h"
0009
0010 extern char __start___ex_table[];
0011 extern char __stop___ex_table[];
0012
0013 #if defined(__powerpc64__)
0014 #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP]
0015 #elif defined(__powerpc__)
0016 #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP]
0017 #else
0018 #error implement UCONTEXT_NIA
0019 #endif
0020
0021 static void segv_handler(int signr, siginfo_t *info, void *ptr)
0022 {
0023 ucontext_t *uc = (ucontext_t *)ptr;
0024 unsigned long addr = (unsigned long)info->si_addr;
0025 unsigned long *ip = &UCONTEXT_NIA(uc);
0026 unsigned long *ex_p = (unsigned long *)__start___ex_table;
0027
0028 while (ex_p < (unsigned long *)__stop___ex_table) {
0029 unsigned long insn, fixup;
0030
0031 insn = *ex_p++;
0032 fixup = *ex_p++;
0033
0034 if (insn == *ip) {
0035 *ip = fixup;
0036 return;
0037 }
0038 }
0039
0040 printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr);
0041 abort();
0042 }
0043
0044 static void setup_segv_handler(void)
0045 {
0046 struct sigaction action;
0047
0048 memset(&action, 0, sizeof(action));
0049 action.sa_sigaction = segv_handler;
0050 action.sa_flags = SA_SIGINFO;
0051 sigaction(SIGSEGV, &action, NULL);
0052 }
0053
0054 unsigned long COPY_LOOP(void *to, const void *from, unsigned long size);
0055 unsigned long test_copy_tofrom_user_reference(void *to, const void *from, unsigned long size);
0056
0057 static int total_passed;
0058 static int total_failed;
0059
0060 static void do_one_test(char *dstp, char *srcp, unsigned long len)
0061 {
0062 unsigned long got, expected;
0063
0064 got = COPY_LOOP(dstp, srcp, len);
0065 expected = test_copy_tofrom_user_reference(dstp, srcp, len);
0066
0067 if (got != expected) {
0068 total_failed++;
0069 printf("FAIL from=%p to=%p len=%ld returned %ld, expected %ld\n",
0070 srcp, dstp, len, got, expected);
0071
0072 } else
0073 total_passed++;
0074 }
0075
0076
0077 #define MAX_LEN 16
0078
0079 int test_copy_exception(void)
0080 {
0081 int page_size;
0082 static char *p, *q;
0083 unsigned long src, dst, len;
0084
0085 page_size = getpagesize();
0086 p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE,
0087 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
0088
0089 if (p == MAP_FAILED) {
0090 perror("mmap");
0091 exit(1);
0092 }
0093
0094 memset(p, 0, page_size);
0095
0096 setup_segv_handler();
0097
0098 if (mprotect(p + page_size, page_size, PROT_NONE)) {
0099 perror("mprotect");
0100 exit(1);
0101 }
0102
0103 q = p + page_size - MAX_LEN;
0104
0105 for (src = 0; src < MAX_LEN; src++) {
0106 for (dst = 0; dst < MAX_LEN; dst++) {
0107 for (len = 0; len < MAX_LEN+1; len++) {
0108
0109 do_one_test(q+dst, q+src, len);
0110 }
0111 }
0112 }
0113
0114 printf("Totals:\n");
0115 printf(" Pass: %d\n", total_passed);
0116 printf(" Fail: %d\n", total_failed);
0117
0118 return 0;
0119 }
0120
0121 int main(void)
0122 {
0123 return test_harness(test_copy_exception, str(COPY_LOOP));
0124 }