1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)nextaddr.c 1.1 01/18/82";
4 
5 /*
6  * Calculate the next address that will be executed from the current one.
7  *
8  * If the next address depends on runtime data (e.g. a conditional
9  * branch will depend on the value on top of the stack),
10  * we must execute up to the given address with "stepto".
11  *
12  * If the second argument is TRUE, we treat a CALL instruction as
13  * straight line rather than following it as a branch.
14  */
15 
16 #include "defs.h"
17 #include "machine.h"
18 #include "process.h"
19 #include "breakpoint.h"
20 #include "sym.h"
21 #include "pxops.h"
22 #include "optab.h"
23 #include "mappings.h"
24 #include "runtime.h"
25 #include "process/pxinfo.h"
26 #include "process/process.rep"
27 
28 LOCAL ADDRESS docase(), dofor();
29 
30 ADDRESS nextaddr(beginaddr, isnext)
31 ADDRESS beginaddr;
32 BOOLEAN isnext;
33 {
34 	register PXOP op;
35 	ADDRESS addr;
36 	short offset;
37 	int nextbyte;
38 	SYM *s;
39 	union {
40 		short word;
41 		char byte[2];
42 	} o;
43 
44 	addr = beginaddr;
45 	iread(&o.word, addr, sizeof(o.word));
46 	op = (PXOP) o.byte[0];
47 	nextbyte = o.byte[1];
48 	addr += sizeof(short);
49 	switch(op) {
50 
51 #	if (isvaxpx)
52 	/*
53 	 * The version of px on the VAX assumes that the instruction
54 	 * at the entry point of a function is a TRA4 to the beginning
55 	 * of the block.
56 	 */
57 #	endif
58 		case O_CALL: {
59 			ADDRESS eaddr;
60 
61 			if (isnext) {
62 				addr += sizeof(int);
63 			} else {
64 #				if (isvaxpx)
65 					iread(&eaddr, addr, sizeof(eaddr));
66 					addr = eaddr + sizeof(short);
67 					iread(&addr, addr, sizeof(addr));
68 #				else
69 					iread(&offset, addr, sizeof(offset));
70 					addr += offset;
71 #				endif
72 				stepto(addr);
73 				if (linelookup(addr) == 0) {
74 					bpact();
75 					addr = pc;
76 				}
77 				if (ss_lines && trcond()) {
78 					s = whatblock(addr);
79 					if (s == NIL) {
80 						panic("bad call addr");
81 					}
82 					printentry(s);
83 				}
84 			}
85 			break;
86 		}
87 
88 #	if (isvaxpx)
89 		case O_FCALL: {
90 			ADDRESS eaddr;
91 			ADDRESS *fparam;
92 
93 			if (!isnext) {
94 				stepto(addr - sizeof(short));
95 				dread(&fparam, process->sp + sizeof(ADDRESS), sizeof(fparam));
96 				dread(&eaddr, fparam, sizeof(eaddr));
97 				addr = eaddr - ENDOFF;
98 				stepto(addr);
99 				if (linelookup(addr) == 0) {
100 					bpact();
101 					addr = pc;
102 				}
103 				if (ss_lines && trcond()) {
104 					s = whatblock(addr);
105 					if (s == NIL) {
106 						panic("bad call addr");
107 					}
108 					printentry(s);
109 				}
110 			}
111 			break;
112 		}
113 #	endif
114 
115 		case O_END:
116 			if ((addr - sizeof(short)) == lastaddr()) {
117 				stepto(addr - sizeof(short));
118 				endprogram();
119 			} else {
120 				addr = return_addr();
121 				s = whatblock(pc);
122 				stepto(addr);
123 				if (ss_lines && trcond()) {
124 					printexit(s);
125 				}
126 				if (linelookup(addr) == 0) {
127 					bpact();
128 					addr = pc;
129 				}
130 			}
131 			break;
132 
133 #	if (isvaxpx)
134 		case O_TRA4:
135 		case O_GOTO:
136 			iread(&addr, addr, sizeof(addr));
137 			break;
138 #	endif
139 
140 		case O_TRA:
141 			iread(&offset, addr, sizeof(offset));
142 			addr += offset;
143 			break;
144 
145 		case O_CASE1OP:
146 			addr = docase(nextbyte, 1, addr);
147 			break;
148 
149 		case O_CASE2OP:
150 			addr = docase(nextbyte, 2, addr);
151 			break;
152 
153 		case O_CASE4OP:
154 			addr = docase(nextbyte, 4, addr);
155 			break;
156 
157 		case O_FOR1U:
158 			addr = dofor(2, addr, nextbyte, 1);
159 			break;
160 
161 		case O_FOR2U:
162 			addr = dofor(2, addr, nextbyte, 1);
163 			break;
164 
165 		case O_FOR4U:
166 			addr = dofor(4, addr, nextbyte, 1);
167 			break;
168 
169 		case O_FOR1D:
170 			addr = dofor(2, addr, nextbyte, -1);
171 			break;
172 
173 		case O_FOR2D:
174 			addr = dofor(2, addr, nextbyte, -1);
175 			break;
176 
177 		case O_FOR4D:
178 			addr = dofor(4, addr, nextbyte, -1);
179 			break;
180 
181 		case O_IF:
182 			stepto(addr - sizeof(short));
183 			dread(&offset, process->sp, sizeof(offset));
184 			if (offset == 0) {
185 				iread(&offset, addr, sizeof(offset));
186 				addr += offset;
187 			} else {
188 				addr += sizeof(offset);
189 			}
190 			break;
191 
192 		default: {
193 #	if (isvaxpx)
194 			int i;
195 
196 			for (i = 0; optab[op].argtype[i] != 0; i++) {
197 				switch(optab[op].argtype[i]) {
198 					case ADDR4:
199 					case LWORD:
200 						addr += 4;
201 						break;
202 
203 					case SUBOP:
204 						break;
205 
206 					case ADDR2:
207 					case HWORD:
208 					case PSUBOP:
209 					case DISP:
210 					case VLEN:
211 						if (i != 0 || nextbyte == 0) {
212 							addr += sizeof(short);
213 						}
214 						break;
215 
216 					case STRING: {
217 						char c;
218 
219 						while (nextbyte > 0) {
220 							iread(&c, addr, 1);
221 							if (c == '\0') {
222 								break;
223 							}
224 							nextbyte--;
225 							addr++;
226 						}
227 						addr++;
228 						if ((addr&1) != 0) {
229 							addr++;
230 						}
231 						break;
232 					}
233 
234 					default:
235 						panic("bad argtype");
236 						/*NOTREACHED*/
237 				}
238 			}
239 #	else
240 			int oplen;
241 
242 			oplen = optab[op].nargs;
243 			if (oplen < 0) {
244 				oplen = (-oplen) - 1;
245 			} else  if (oplen > 0 && nextbyte != 0) {
246 				oplen--;
247 			}
248 			oplen *= sizeof(int);
249 			switch (op) {
250 				case O_BEG:
251 				case O_NODUMP:
252 					oplen += 10;
253 					break;
254 
255 				case O_CON:
256 					oplen += ((nextbyte + 1)&~1);
257 					break;
258 			}
259 			addr += oplen;
260 #	endif
261 			break;
262 		}
263 	}
264 	return addr;
265 }
266 
267 /*
268  * Find the next address that will be executed after the
269  * case statement at the given address.
270  */
271 
272 LOCAL ADDRESS docase(ncases, size, addr)
273 int ncases;
274 int size;
275 ADDRESS addr;
276 {
277 	register ADDRESS i;
278 	ADDRESS firstval, lastval, jmptable;
279 	short offset;
280 	long swtval, caseval;
281 
282 	stepto(addr - 2);
283 	if (ncases == 0) {
284 		iread(&ncases, addr, sizeof(ncases));
285 		addr += sizeof(short);
286 	}
287 	jmptable = addr;
288 	firstval = jmptable + ncases*sizeof(short);
289 	lastval = firstval + ncases*size;
290 	if (size <= 2) {
291 		dread(&swtval, process->sp, 2);
292 	} else {
293 		dread(&swtval, process->sp, size);
294 	}
295 	for (i = firstval; i < lastval; i += size) {
296 		iread(&caseval, i, size);
297 		if (cmp(&swtval, &caseval, size) == 0) {
298 			i = ((i - firstval) / size) * sizeof(offset);
299 			iread(&offset, jmptable + i, sizeof(offset));
300 			addr = jmptable + offset;
301 			return addr;
302 		}
303 	}
304 	return((lastval+1)&~1);
305 }
306 
307 LOCAL ADDRESS dofor(size, addr, subop, incr)
308 int size;
309 ADDRESS addr;
310 short subop;
311 int incr;
312 {
313 	register PROCESS *p;
314 	long i, limit, lower;
315 	ADDRESS valaddr;
316 	short offset;
317 
318 	stepto(addr - sizeof(short));
319 	p = process;
320 	i = limit = 0;
321 	if (subop == 0) {
322 		addr += size;
323 	}
324 	dread(&valaddr, p->sp, sizeof(valaddr));
325 	dread(&i, valaddr, size);
326 	dread(&limit, p->sp + sizeof(valaddr), size);
327 	i += (incr << (8*(sizeof(i) - size)));
328 	addr += size;
329 /*
330  * It is very slow to go through the loop again and again.
331  * So for the time being, we just skip to the end.
332  *
333 	if ((incr > 0 && i < limit) || (incr < 0 && i > limit)) {
334 		iread(&offset, addr, sizeof(offset));
335 		return(addr + offset);
336 	} else {
337  */
338 		return(addr + sizeof(short));
339 /*
340 	}
341  */
342 }
343