added quit routine
[unix-history] / usr / src / usr.bin / pascal / pdx / tree / tracestop.c
CommitLineData
0068337c
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
3static char sccsid[] = "@(#)tracestop.c 1.1 %G%";
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
20LOCAL 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
27trace(cmd, exp, where, cond)
28int cmd;
29NODE *exp;
30NODE *where;
31NODE *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
61LOCAL traceall(cmd, where, cond)
62int cmd;
63NODE *where;
64NODE *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
115LOCAL traceinst(cmd, exp, where, cond)
116int cmd;
117NODE *exp;
118NODE *where;
119NODE *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
156LOCAL traceat(cmd, exp, where, cond)
157int cmd;
158NODE *exp;
159NODE *where;
160NODE *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
193LOCAL tracedata(cmd, exp, block, cond)
194int cmd;
195NODE *exp;
196NODE *block;
197NODE *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
233stop(cmd, exp, where, cond)
234int cmd;
235NODE *exp;
236NODE *where;
237NODE *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
271LOCAL stopinst(cmd, where, cond)
272int cmd;
273NODE *where;
274NODE *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
300LOCAL stopvar(cmd, exp, where, cond)
301int cmd;
302NODE *exp;
303NODE *where;
304NODE *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
331LOCAL SYM *tcontainer(var)
332NODE *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}