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