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