1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)tracestop.c 1.1 01/18/82";
4 
5 /*
6  * Handle trace and stop commands.
7  */
8 
9 #include "defs.h"
10 #include "breakpoint.h"
11 #include "sym.h"
12 #include "tree.h"
13 #include "runtime.h"
14 #include "source.h"
15 #include "object.h"
16 #include "mappings.h"
17 #include "machine.h"
18 #include "tree.rep"
19 
20 LOCAL SYM *tcontainer();
21 
22 /*
23  * Process a trace/untrace command, basically checking arguments
24  * and translate to a call of the appropriate routine.
25  */
26 
27 trace(cmd, exp, where, cond)
28 int cmd;
29 NODE *exp;
30 NODE *where;
31 NODE *cond;
32 {
33 	if (exp == NIL) {
34 		traceall(cmd, where, cond);
35 	} else if (exp->op == O_LCON || exp->op == O_QLINE) {
36 		traceinst(cmd, exp, where, cond);
37 	} else if (where!=NIL && (where->op==O_QLINE || where->op==O_LCON)) {
38 		traceat(cmd, exp, where, cond);
39 	} else {
40 		tracedata(cmd, exp, where, cond);
41 	}
42 	if (where != NIL) {
43 		tfree(where);
44 	}
45 }
46 
47 /*
48  * Set a breakpoint that will turn on tracing.
49  *
50  * A line number of 0 in the breakpoint information structure
51  * means it's a normal trace.
52  *
53  * A line number of -1 indicates that we want to trace at the instruction
54  * rather than source line level.
55  *
56  * If location is NIL, turn on tracing because if the user
57  * has the program stopped somewhere and says "trace",
58  * he/she wants to see tracing after continuing execution.
59  */
60 
61 LOCAL traceall(cmd, where, cond)
62 int cmd;
63 NODE *where;
64 NODE *cond;
65 {
66 	SYM *s;
67 	LINENO line;
68 
69 	if (where != NIL && where->op != O_NAME) {
70 		error("bad location for trace");
71 	}
72 	if (cmd == O_TRACE) {
73 		line = 0;
74 	} else {
75 		line = -1;
76 	}
77 	if (where == NIL) {
78 		switch (cmd) {
79 			case O_TRACE:
80 				if (tracing != 0) {
81 					error("already tracing lines");
82 				}
83 				tracing++;
84 				addcond(TRPRINT, cond);
85 				break;
86 
87 			case O_TRACEI:
88 				if (inst_tracing != 0) {
89 					error("already tracing instructions");
90 				}
91 				inst_tracing++;
92 				addcond(TRPRINT, cond);
93 				break;
94 
95 			default:
96 				panic("bad cmd in traceall");
97 				break;
98 		}
99 		s = program;
100 	} else if (where->op != O_NAME) {
101 		trerror("found %t, expected procedure or function", where);
102 	} else {
103 		s = where->nameval;
104 		if (!isblock(s)) {
105 			error("\"%s\" is not a procedure or function", name(s));
106 		}
107 	}
108 	addbp(codeloc(s), ALL_ON, s, cond, NIL, line);
109 }
110 
111 /*
112  * Set up the appropriate breakpoint for tracing an instruction.
113  */
114 
115 LOCAL traceinst(cmd, exp, where, cond)
116 int cmd;
117 NODE *exp;
118 NODE *where;
119 NODE *cond;
120 {
121 	LINENO line;
122 	ADDRESS addr;
123 
124 	if (where != NIL) {
125 		error("unexpected \"at\" or \"in\"");
126 	}
127 	if (cmd == O_TRACEI) {
128 		if (exp->op == O_QLINE) {
129 			addr = (ADDRESS) exp->right->lconval;
130 		} else if (exp->op == O_LCON) {
131 			addr = (ADDRESS) exp->lconval;
132 		} else {
133 			trerror("expected integer constant, found %t", exp);
134 		}
135 		line = -1;
136 	} else {
137 		if (exp->op == O_QLINE) {
138 			line = (LINENO) exp->right->lconval;
139 			addr = objaddr(line, exp->left->sconval);
140 		} else {
141 			line = (LINENO) exp->lconval;
142 			addr = objaddr(line, cursource);
143 		}
144 		if (addr == (ADDRESS) -1) {
145 			error("can't trace line %d", line);
146 		}
147 	}
148 	tfree(exp);
149 	addbp(addr, INST, NIL, cond, NIL, line);
150 }
151 
152 /*
153  * set a breakpoint to print an expression at a given line or address
154  */
155 
156 LOCAL traceat(cmd, exp, where, cond)
157 int cmd;
158 NODE *exp;
159 NODE *where;
160 NODE *cond;
161 {
162 	LINENO line;
163 	ADDRESS addr;
164 
165 	if (cmd == O_TRACEI) {
166 		if (where->op != O_LCON) {
167 			trerror("expected integer constant, found %t", where);
168 		}
169 		line = -1;
170 		addr = (ADDRESS) where->lconval;
171 	} else {
172 		line = (LINENO) where->right->lconval;
173 		addr = objaddr(line, where->left->sconval);
174 		if (addr == (ADDRESS) -1) {
175 			error("can't trace at line %d", line);
176 		}
177 	}
178 	addbp(addr, AT_BP, NIL, cond, exp, line);
179 }
180 
181 /*
182  * Set up breakpoint for tracing data.
183  *
184  * The tracing of blocks lies somewhere between instruction and data;
185  * it's here since a block cannot be distinguished from other terms.
186  *
187  * As in "traceall", if the "block" is the main program then the
188  * user didn't actually specify a block.  This means we want to
189  * turn tracing on ourselves because if the program is stopped
190  * we want to be on regardless of whether they say "cont" or "run".
191  */
192 
193 LOCAL tracedata(cmd, exp, block, cond)
194 int cmd;
195 NODE *exp;
196 NODE *block;
197 NODE *cond;
198 {
199 	SYM *s, *t;
200 
201 	if (exp->op != O_RVAL && exp->op != O_CALL) {
202 		error("can't trace expressions");
203 	}
204 	if (block == NIL) {
205 		t = tcontainer(exp->left);
206 	} else if (block->op == O_NAME) {
207 		t = block->nameval;
208 	} else {
209 		trerror("found %t, expected procedure or function", block);
210 	}
211 	if (exp->left->op == O_NAME) {
212 		s = exp->left->nameval;
213 		if (isblock(s)) {
214 			addbp(codeloc(t), BLOCK_ON, t, cond, exp->left, 0);
215 			if (t == program) {
216 				addbp(codeloc(s), CALL, s, cond, NIL, 0);
217 			}
218 			return;
219 		}
220 	}
221 	addbp(codeloc(t), TERM_ON, t, cond, exp, 0);
222 	if (curfunc == t) {
223 		var_tracing++;
224 		addvar(TRPRINT, exp, cond);
225 		addbp(return_addr(), TERM_OFF, t, cond, exp, 0);
226 	}
227 }
228 
229 /*
230  * Setting and unsetting of stops.
231  */
232 
233 stop(cmd, exp, where, cond)
234 int cmd;
235 NODE *exp;
236 NODE *where;
237 NODE *cond;
238 {
239 	SYM *s;
240 	LINENO n;
241 
242 	if (exp != NIL) {
243 		stopvar(cmd, exp, where, cond);
244 	} else if (cond != NIL) {
245 		if (where == NIL) {
246 			s = program;
247 		} else if (where->op == O_NAME) {
248 			s = where->nameval;
249 		} else {
250 			error("bad location for stop");
251 		}
252 		n = codeloc(s);
253 		addbp(n, STOP_ON, s, cond, NIL, n);
254 		addcond(TRSTOP, cond);
255 		var_tracing++;
256 	} else if (where->op == O_NAME) {
257 		s = where->nameval;
258 		if (!isblock(s)) {
259 			error("\"%s\" is not a procedure or function", name(s));
260 		}
261 		n = codeloc(s);
262 		addbp(n, STOP_BP, s, cond, NIL, srcline(firstline(s)));
263 	} else {
264 		stopinst(cmd, where, cond);
265 	}
266 	if (where != NIL) {
267 		tfree(where);
268 	}
269 }
270 
271 LOCAL stopinst(cmd, where, cond)
272 int cmd;
273 NODE *where;
274 NODE *cond;
275 {
276 	LINENO line;
277 	ADDRESS addr;
278 
279 	if (where->op != O_QLINE) {
280 		error("expected line number");
281 	}
282 	if (cmd == O_STOP) {
283 		line = (LINENO) where->right->lconval;
284 		addr = objaddr(line, where->left->sconval);
285 		if (addr == (ADDRESS) -1) {
286 			error("can't stop at that line");
287 		}
288 	} else {
289 		line = -1;
290 		addr = (ADDRESS) where->right->lconval;
291 	}
292 	addbp(addr, STOP_BP, NIL, cond, NIL, line);
293 }
294 
295 /*
296  * Implement stopping on assignment to a variable by adding it to
297  * the variable list.
298  */
299 
300 LOCAL stopvar(cmd, exp, where, cond)
301 int cmd;
302 NODE *exp;
303 NODE *where;
304 NODE *cond;
305 {
306 	SYM *s;
307 
308 	if (exp->op != O_RVAL) {
309 		trerror("found %t, expected variable", exp);
310 	}
311 	if (cmd == O_STOPI) {
312 		inst_tracing++;
313 	}
314 	var_tracing++;
315 	addvar(TRSTOP, exp, cond);
316 	if (where == NIL) {
317 		s = program;
318 	} else if (where->op == O_NAME) {
319 		s = where->nameval;
320 	} else {
321 		error("bad location for stop");
322 	}
323 	addbp(codeloc(s), STOP_ON, s, cond, exp, 0);
324 }
325 
326 /*
327  * Figure out the block that contains the symbols
328  * in the given variable expression.
329  */
330 
331 LOCAL SYM *tcontainer(var)
332 NODE *var;
333 {
334 	NODE *p;
335 
336 	p = var;
337 	while (p->op != O_NAME) {
338 		if (isleaf(p->op)) {
339 			panic("unexpected op %d in tcontainer", p->op);
340 			/* NOTREACHED */
341 		}
342 		p = p->left;
343 	}
344 	return container(p->nameval);
345 }
346