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