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