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