1 static char sccsid[] = "@(#)runcompat.c 4.2 83/07/31"; 2 3 /* 4 * Compatability mode support 5 * written by Art Wetzel during August 1979 6 * at the Interdisciplinary Dept of Information Science 7 * Room 711, LIS Bldg 8 * University of Pittsburgh 9 * Pittsburgh, Pa 15260 10 * 11 * No claims are made on the completeness of the support of any 12 * of the systems simulated under this package 13 */ 14 15 #include <stdio.h> 16 #include <signal.h> 17 #include <sys/types.h> 18 #include <sys/stat.h> 19 #include <errno.h> 20 #include "defs.h" 21 #ifdef UNIX 22 #include "unixhdr.h" 23 #endif 24 #ifdef RT11 25 #include "rt11.h" 26 #endif 27 28 struct stat stat32v; 29 u_short regs[8]; 30 u_long psl; 31 u_short *pc; 32 int incompat; 33 char *progname; 34 char *nameend; 35 36 main(argc, argv, envp) 37 int argc; 38 char **argv, **envp; 39 { 40 41 if (argc < 2) { 42 fprintf(stderr,"Usage: %s [-rootdir] file args...\n",argv[0]); 43 exit(1); 44 } 45 /* remember where the program name etc should go for using ps */ 46 progname = argv[0]; 47 nameend = envp[0]-1; 48 argv++; 49 /* set up alternate root directory if flagged for */ 50 if (*argv[0] == '-') { 51 if (chroot(argv[0]+1)) { 52 fprintf(stderr,"Can't change root to %s\n",argv[0]+1); 53 exit(-1); 54 } 55 argv++; 56 } 57 /* check out file stats of file to run */ 58 if (stat(argv[0], &stat32v)) { 59 fprintf(stderr,"%s does not exist\n",argv[0]); 60 exit(1); 61 } 62 /* a version of SETUID and SETGID file executions */ 63 /* the binary of this program should be SETUID root for this to work */ 64 /* requires nonstandard seteuid and setegid sys calls */ 65 if (!(stat32v.st_mode & S_ISGID) || setegid(stat32v.st_gid)) 66 /* if not SETGID file or error, drop back to real group */ 67 setgid(getgid()); 68 if (!(stat32v.st_mode & S_ISUID) || seteuid(stat32v.st_uid)) 69 /* if not SETUID file or error, drop back to real uid */ 70 setuid(getuid()); 71 #ifdef V6UNIX 72 /* no umasks in version 6 */ 73 umask(0); 74 #endif 75 /* go try to execute , passing along args and environment */ 76 execute(argv[0], argv, envp); 77 /* only get here if execute fails */ 78 fprintf(stderr,"Execution failure on %s\n",argv[0]); 79 exit(1); 80 } 81 82 execute(file, argv, envp) 83 char *file, **argv, **envp; 84 { 85 int fd, n, tloadpt, dloadpt, tloadsize, dloadsize, stacksize; 86 register short *p; 87 extern illtrap(); 88 extern char **environ; 89 90 /* file to run should be readable */ 91 if ((fd = open(file, 0)) == -1) { 92 fprintf(stderr,"Can't open %s for read access\n",file); 93 return(-1); 94 } 95 #ifdef UNIX 96 if ((n = read(fd, &header, sizeof header)) != sizeof header) 97 return(ENOEXEC); 98 /* check to see if really unix file */ 99 if (header.magic != MAGIC1 && header.magic != MAGIC2 && 100 header.magic != MAGIC3 && header.magic != MAGIC4) { 101 return(ENOEXEC); 102 } 103 /* if a UNIX file run it */ 104 if (header.textsize == 0) { 105 close(fd); 106 /* if no explicit env, pass along environ */ 107 if (!envp || *envp == 0) 108 return(execve(file, argv, environ)); 109 return(execve(file, argv, envp)); 110 } 111 /* checks out OK as PDP-11 UNIX file */ 112 if (header.magic == MAGIC3) { 113 fprintf(stderr,"%s compiled for separate I/D space\n",argv[0]); 114 return(-1); 115 } 116 /* unix text loads at 0 */ 117 tloadpt = 0; 118 /* set starting pc value */ 119 pc = (unsigned short *)header.entry; 120 /* figure out where to load initialized data */ 121 dloadpt = tloadsize = header.textsize; 122 /* check if alignment of data segment to 8k byte boundary */ 123 if (header.magic == MAGIC2) 124 dloadpt = (dloadpt+8191) & (~8191); 125 /* how much data */ 126 dloadsize = header.datasize; 127 stacksize = header.bsssize; 128 #endif 129 #ifdef RT11 130 if ((n = read(fd, shortspace, RTHDRSIZ)) != RTHDRSIZ) { 131 fprintf(stderr,"Error reading 1st block\n"); 132 return(-1); 133 } 134 /* rt11 files are 0 aligned including the header */ 135 tloadpt = RTHDRSIZ; 136 /* set starting pc value */ 137 pc = (unsigned short *)shortspace[RTPC]; 138 /* initialize stack location */ 139 regs[6] = shortspace[RTSP]; 140 /* figure how much to load */ 141 dloadpt = tloadsize = shortspace[RTHGH]-RTHDRSIZ; 142 /* no separate data as in unix */ 143 dloadsize = 0; 144 stacksize = 0; 145 #endif 146 /* see if it all fits into available memory space */ 147 if ((dloadpt+dloadsize+stacksize) > (int)memsiz) { 148 fprintf(stderr,"File too big to run\n"); 149 return(-1); 150 } 151 /* read text segment */ 152 if ((n = read(fd, tloadpt, tloadsize)) < tloadsize) { 153 fprintf(stderr,"Text read failure\n"); 154 return(-1); 155 } 156 /* read data segment */ 157 if ((n = read(fd, dloadpt, dloadsize)) < dloadsize) { 158 fprintf(stderr,"Data read failure\n"); 159 return(-1); 160 } 161 /* clear out the rest of memory */ 162 p = (short *)(dloadpt + dloadsize); 163 while (p < (short *)memsiz) 164 *p++ = 0; 165 /* close file before starting it */ 166 close(fd); 167 /* set up illegal instruction trapping */ 168 signal(SIGILL, illtrap); 169 /* lets give it a try */ 170 start(argv, envp); 171 } 172 173 illtrap(signum, faultcode, scp) 174 int signum, faultcode; 175 struct sigcontext *scp; 176 { 177 unsigned short *pcptr; 178 int instr; 179 register int i; 180 extern getregs(); 181 182 /* record the fact that we are not in compatability mode now */ 183 incompat = 0; 184 /* get the register values before they get clobbered */ 185 getregs(); 186 /* figure out what the pc was */ 187 pcptr = (unsigned short *) &scp->sc_pc; 188 pc = (unsigned short *) *pcptr; 189 /* get the instruction */ 190 instr = *pc; 191 /* incriment the pc over this instruction */ 192 pc++; 193 /* set register 7 as pc synonym */ 194 regs[7] = (unsigned short)(int)pc; 195 /* set up psl with condition codes */ 196 /* a UNIX-32V monitor patch is required to not clear condition codes */ 197 psl = 0x83c00000 | (scp->sc_ps & 017); 198 sigsetmask(scp->sc_mask); 199 /* pick out the appropriate action for this illegal instruction */ 200 switch(instr>>8){ 201 202 case TRAPS: 203 dotrap(instr & 0377); 204 break; 205 206 case EMTS: 207 if (sigvals[SIGEMT] && ((sigvals[SIGEMT]%2) != 1)) { 208 dosig(SIGEMT, pc); 209 break; 210 } 211 doemt(instr & 0377); 212 break; 213 214 default: 215 if (instr >= 075000 && instr < 075040) { 216 /* fis instructions */ 217 if (dofloat(instr) == 0) 218 break; 219 } 220 if (instr >= 0170000) { 221 /* floating point unit instructions */ 222 if (dofloat(instr) == 0) 223 break; 224 } 225 /* genuine illegal instruction */ 226 /* if signal trap set go to user's trap location */ 227 if (sigvals[SIGILL] && ((sigvals[SIGILL]%2) != 1)) { 228 dosig(SIGILL, pc); 229 break; 230 } 231 /* ignore uncaught setd instructions */ 232 if (instr == SETD) 233 break; 234 /* otherwise put out a message and quit */ 235 printf("Illegal instruction, psl 0x%08x, pc 0%04o\n",psl,pc-1); 236 for (i = 0; i < 7; i++) 237 printf("0x%04x ",regs[i]); 238 printf("0x%04x -> 0%o\n",pc-1,instr); 239 /* set up to dump on illegal instruction */ 240 signal(SIGILL,SIG_DFL); 241 /* set pc back to bad instruction */ 242 pc--; 243 /* go do it again for dump */ 244 compat(); 245 } 246 /* go back to compatability mode */ 247 incompat++; 248 compat(); 249 } 250