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
nextaddr(beginaddr,isnext)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
docase(ncases,size,addr)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
dofor(size,addr,subop,incr)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
isendofproc(addr)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