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