xref: /csrg-svn/old/dbx/events.c (revision 9663)
1*9663Slinton /* Copyright (c) 1982 Regents of the University of California */
2*9663Slinton 
3*9663Slinton static char sccsid[] = "@(#)@(#)events.c 1.1 12/15/82";
4*9663Slinton 
5*9663Slinton /*
6*9663Slinton  * Event/breakpoint managment.
7*9663Slinton  */
8*9663Slinton 
9*9663Slinton #include "defs.h"
10*9663Slinton #include "events.h"
11*9663Slinton #include "main.h"
12*9663Slinton #include "symbols.h"
13*9663Slinton #include "tree.h"
14*9663Slinton #include "eval.h"
15*9663Slinton #include "source.h"
16*9663Slinton #include "mappings.h"
17*9663Slinton #include "process.h"
18*9663Slinton #include "machine.h"
19*9663Slinton #include "lists.h"
20*9663Slinton 
21*9663Slinton #ifndef public
22*9663Slinton typedef struct Event *Event;
23*9663Slinton typedef struct Breakpoint *Breakpoint;
24*9663Slinton 
25*9663Slinton Boolean inst_tracing;
26*9663Slinton Boolean single_stepping;
27*9663Slinton Boolean isstopped;
28*9663Slinton 
29*9663Slinton #include "symbols.h"
30*9663Slinton 
31*9663Slinton Symbol linesym;
32*9663Slinton Symbol procsym;
33*9663Slinton Symbol pcsym;
34*9663Slinton Symbol retaddrsym;
35*9663Slinton 
36*9663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist)
37*9663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist)
38*9663Slinton 
39*9663Slinton #endif
40*9663Slinton 
41*9663Slinton struct Event {
42*9663Slinton     unsigned int id;
43*9663Slinton     Boolean temporary;
44*9663Slinton     Node condition;
45*9663Slinton     Cmdlist actions;
46*9663Slinton };
47*9663Slinton 
48*9663Slinton struct Breakpoint {
49*9663Slinton     Event event;
50*9663Slinton     Address bpaddr;
51*9663Slinton     Lineno bpline;
52*9663Slinton     Cmdlist actions;
53*9663Slinton };
54*9663Slinton 
55*9663Slinton typedef List Eventlist;
56*9663Slinton typedef List Bplist;
57*9663Slinton 
58*9663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el)
59*9663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)
60*9663Slinton 
61*9663Slinton private Eventlist eventlist;		/* list of active events */
62*9663Slinton private Bplist bplist;			/* list of active breakpoints */
63*9663Slinton private Integer eventid;		/* id number of next allocated event */
64*9663Slinton private Integer trid;			/* id number of next allocated trace */
65*9663Slinton 
66*9663Slinton typedef struct Trcmd {
67*9663Slinton     Integer trid;
68*9663Slinton     Event event;
69*9663Slinton     Cmdlist cmdlist;
70*9663Slinton } *Trcmd;
71*9663Slinton 
72*9663Slinton private List eachline;		/* commands to execute after each line */
73*9663Slinton private List eachinst;		/* commands to execute after each instruction */
74*9663Slinton 
75*9663Slinton private Breakpoint bp_alloc();
76*9663Slinton 
77*9663Slinton /*
78*9663Slinton  * Initialize breakpoint information.
79*9663Slinton  */
80*9663Slinton 
81*9663Slinton private Symbol builtinsym(str, class, type)
82*9663Slinton String str;
83*9663Slinton Symclass class;
84*9663Slinton Symbol type;
85*9663Slinton {
86*9663Slinton     Symbol s;
87*9663Slinton 
88*9663Slinton     s = insert(identname(str, true));
89*9663Slinton     s->language = findlanguage(".s");
90*9663Slinton     s->class = class;
91*9663Slinton     s->type = type;
92*9663Slinton     return s;
93*9663Slinton }
94*9663Slinton 
95*9663Slinton public bpinit()
96*9663Slinton {
97*9663Slinton     linesym = builtinsym("$line", VAR, t_int);
98*9663Slinton     procsym = builtinsym("$proc", PROC, nil);
99*9663Slinton     pcsym = lookup(identname("$pc", true));
100*9663Slinton     if (pcsym == nil) {
101*9663Slinton 	panic("can't find $pc");
102*9663Slinton     }
103*9663Slinton     retaddrsym = builtinsym("$retaddr", VAR, t_int);
104*9663Slinton     eventlist = list_alloc();
105*9663Slinton     bplist = list_alloc();
106*9663Slinton     eachline = list_alloc();
107*9663Slinton     eachinst = list_alloc();
108*9663Slinton }
109*9663Slinton 
110*9663Slinton /*
111*9663Slinton  * Trap an event and do the associated commands when it occurs.
112*9663Slinton  */
113*9663Slinton 
114*9663Slinton public Event event_alloc(istmp, econd, cmdlist)
115*9663Slinton Boolean istmp;
116*9663Slinton Node econd;
117*9663Slinton Cmdlist cmdlist;
118*9663Slinton {
119*9663Slinton     register Event e;
120*9663Slinton 
121*9663Slinton     e = new(Event);
122*9663Slinton     ++eventid;
123*9663Slinton     e->id = eventid;
124*9663Slinton     e->temporary = istmp;
125*9663Slinton     e->condition = econd;
126*9663Slinton     e->actions = cmdlist;
127*9663Slinton     eventlist_append(e, eventlist);
128*9663Slinton     translate(e);
129*9663Slinton     return e;
130*9663Slinton }
131*9663Slinton 
132*9663Slinton /*
133*9663Slinton  * Delete the event with the given id.
134*9663Slinton  */
135*9663Slinton 
136*9663Slinton public delevent(id)
137*9663Slinton unsigned int id;
138*9663Slinton {
139*9663Slinton     Event e;
140*9663Slinton     Breakpoint bp;
141*9663Slinton     Trcmd t;
142*9663Slinton 
143*9663Slinton     foreach (Event, e, eventlist)
144*9663Slinton 	if (e->id == id) {
145*9663Slinton 	    list_delete(list_curitem(eventlist), eventlist);
146*9663Slinton 	    foreach (Breakpoint, bp, bplist)
147*9663Slinton 		if (bp->event == e) {
148*9663Slinton 		    list_delete(list_curitem(bplist), bplist);
149*9663Slinton 		}
150*9663Slinton 	    endfor
151*9663Slinton 	    break;
152*9663Slinton 	}
153*9663Slinton     endfor
154*9663Slinton     foreach (Trcmd, t, eachline)
155*9663Slinton 	if (t->event->id == id) {
156*9663Slinton 	    printrmtr(t);
157*9663Slinton 	    list_delete(list_curitem(eachline), eachline);
158*9663Slinton 	}
159*9663Slinton     endfor
160*9663Slinton     foreach (Trcmd, t, eachinst)
161*9663Slinton 	if (t->event->id == id) {
162*9663Slinton 	    printrmtr(t);
163*9663Slinton 	    list_delete(list_curitem(eachinst), eachinst);
164*9663Slinton 	}
165*9663Slinton     endfor
166*9663Slinton     if (list_size(eachinst) == 0) {
167*9663Slinton 	inst_tracing = false;
168*9663Slinton 	if (list_size(eachline) == 0) {
169*9663Slinton 	    single_stepping = false;
170*9663Slinton 	}
171*9663Slinton     }
172*9663Slinton }
173*9663Slinton 
174*9663Slinton /*
175*9663Slinton  * Translate an event into the appropriate breakpoints and actions.
176*9663Slinton  * While we're at it, turn on the breakpoints if the condition is true.
177*9663Slinton  */
178*9663Slinton 
179*9663Slinton private translate(e)
180*9663Slinton Event e;
181*9663Slinton {
182*9663Slinton     Breakpoint bp;
183*9663Slinton     Symbol s;
184*9663Slinton     Node place;
185*9663Slinton     Lineno line;
186*9663Slinton     Address addr;
187*9663Slinton 
188*9663Slinton     checkref(e->condition);
189*9663Slinton     switch (e->condition->op) {
190*9663Slinton 	case O_EQ:
191*9663Slinton 	    if (e->condition->value.arg[0]->op == O_SYM) {
192*9663Slinton 		s = e->condition->value.arg[0]->value.sym;
193*9663Slinton 		place = e->condition->value.arg[1];
194*9663Slinton 		if (s == linesym) {
195*9663Slinton 		    if (place->op == O_QLINE) {
196*9663Slinton 			line = place->value.arg[1]->value.lcon;
197*9663Slinton 			addr = objaddr(line,
198*9663Slinton 			    place->value.arg[0]->value.scon);
199*9663Slinton 		    } else {
200*9663Slinton 			eval(place);
201*9663Slinton 			line = pop(long);
202*9663Slinton 			addr = objaddr(line, cursource);
203*9663Slinton 		    }
204*9663Slinton 		    if (addr == NOADDR) {
205*9663Slinton 			delevent(e->id);
206*9663Slinton 			beginerrmsg();
207*9663Slinton 			fprintf(stderr, "no executable code at line ");
208*9663Slinton 			prtree(stderr, place);
209*9663Slinton 			enderrmsg();
210*9663Slinton 		    }
211*9663Slinton 		    bp = bp_alloc(e, addr, line, e->actions);
212*9663Slinton 		} else if (s == procsym) {
213*9663Slinton 		    eval(place);
214*9663Slinton 		    s = pop(Symbol);
215*9663Slinton 		    bp = bp_alloc(e, codeloc(s), 0, e->actions);
216*9663Slinton 		    if (isactive(s) and pc != codeloc(program)) {
217*9663Slinton 			evalcmdlist(e->actions);
218*9663Slinton 		    }
219*9663Slinton 		} else if (s == pcsym) {
220*9663Slinton 		    eval(place);
221*9663Slinton 		    bp = bp_alloc(e, pop(Address), 0, e->actions);
222*9663Slinton 		} else {
223*9663Slinton 		    condbp(e);
224*9663Slinton 		}
225*9663Slinton 	    } else {
226*9663Slinton 		condbp(e);
227*9663Slinton 	    }
228*9663Slinton 	    break;
229*9663Slinton 
230*9663Slinton 	/*
231*9663Slinton 	 * These should be handled specially.
232*9663Slinton 	 * But for now I'm ignoring the problem.
233*9663Slinton 	 */
234*9663Slinton 	case O_AND:
235*9663Slinton 	case O_OR:
236*9663Slinton 	default:
237*9663Slinton 	    condbp(e);
238*9663Slinton 	    break;
239*9663Slinton     }
240*9663Slinton }
241*9663Slinton 
242*9663Slinton /*
243*9663Slinton  * Create a breakpoint for a condition that cannot be pinpointed
244*9663Slinton  * to happening at a particular address, but one for which we
245*9663Slinton  * must single step and check the condition after each statement.
246*9663Slinton  */
247*9663Slinton 
248*9663Slinton private condbp(e)
249*9663Slinton Event e;
250*9663Slinton {
251*9663Slinton     Symbol p;
252*9663Slinton     Breakpoint bp;
253*9663Slinton     Cmdlist actions;
254*9663Slinton 
255*9663Slinton     p = tcontainer(e->condition);
256*9663Slinton     if (p == nil) {
257*9663Slinton 	p = program;
258*9663Slinton     }
259*9663Slinton     actions = buildcmdlist(build(O_IF, e->condition, e->actions));
260*9663Slinton     actions = buildcmdlist(build(O_TRACEON, false, actions));
261*9663Slinton     bp = bp_alloc(e, codeloc(p), 0, actions);
262*9663Slinton }
263*9663Slinton 
264*9663Slinton /*
265*9663Slinton  * Determine the deepest nested subprogram that still contains
266*9663Slinton  * all elements in the given expression.
267*9663Slinton  */
268*9663Slinton 
269*9663Slinton public Symbol tcontainer(exp)
270*9663Slinton Node exp;
271*9663Slinton {
272*9663Slinton     Integer i;
273*9663Slinton     Symbol s, t, u, v;
274*9663Slinton 
275*9663Slinton     checkref(exp);
276*9663Slinton     s = nil;
277*9663Slinton     if (exp->op == O_SYM) {
278*9663Slinton 	s = container(exp->value.sym);
279*9663Slinton     } else if (not isleaf(exp->op)) {
280*9663Slinton 	for (i = 0; i < nargs(exp->op); i++) {
281*9663Slinton 	    t = tcontainer(exp->value.arg[i]);
282*9663Slinton 	    if (t != nil) {
283*9663Slinton 		if (s == nil) {
284*9663Slinton 		    s = t;
285*9663Slinton 		} else {
286*9663Slinton 		    u = s;
287*9663Slinton 		    v = t;
288*9663Slinton 		    while (u != v and u != nil) {
289*9663Slinton 			u = container(u);
290*9663Slinton 			v = container(v);
291*9663Slinton 		    }
292*9663Slinton 		    if (u == nil) {
293*9663Slinton 			panic("bad ancestry for \"%s\"", symname(s));
294*9663Slinton 		    } else {
295*9663Slinton 			s = u;
296*9663Slinton 		    }
297*9663Slinton 		}
298*9663Slinton 	    }
299*9663Slinton 	}
300*9663Slinton     }
301*9663Slinton     return s;
302*9663Slinton }
303*9663Slinton 
304*9663Slinton /*
305*9663Slinton  * Print out what's currently being traced by looking at
306*9663Slinton  * the currently active events.
307*9663Slinton  *
308*9663Slinton  * Some convolution here to translate internal representation
309*9663Slinton  * of events back into something more palatable.
310*9663Slinton  */
311*9663Slinton 
312*9663Slinton public status()
313*9663Slinton {
314*9663Slinton     Event e;
315*9663Slinton     Command cmd;
316*9663Slinton 
317*9663Slinton     foreach (Event, e, eventlist)
318*9663Slinton 	if (not e->temporary) {
319*9663Slinton 	    if (not isredirected()) {
320*9663Slinton 		printf("(%d) ", e->id);
321*9663Slinton 	    }
322*9663Slinton 	    cmd = list_element(Command, list_head(e->actions));
323*9663Slinton 	    if (cmd->op == O_PRINTCALL) {
324*9663Slinton 		printf("trace ");
325*9663Slinton 		printname(stdout, cmd->value.sym);
326*9663Slinton 	    } else {
327*9663Slinton 		if (list_size(e->actions) > 1) {
328*9663Slinton 		    printf("{ ");
329*9663Slinton 		}
330*9663Slinton 		foreach (Command, cmd, e->actions)
331*9663Slinton 		    printcmd(stdout, cmd);
332*9663Slinton 		    if (not list_islast()) {
333*9663Slinton 			printf("; ");
334*9663Slinton 		    }
335*9663Slinton 		endfor
336*9663Slinton 		if (list_size(e->actions) > 1) {
337*9663Slinton 		    printf(" }");
338*9663Slinton 		}
339*9663Slinton 		printcond(e->condition);
340*9663Slinton 	    }
341*9663Slinton 	    printf("\n");
342*9663Slinton 	}
343*9663Slinton     endfor
344*9663Slinton }
345*9663Slinton 
346*9663Slinton /*
347*9663Slinton  * Print out a condition.
348*9663Slinton  */
349*9663Slinton 
350*9663Slinton private printcond(cond)
351*9663Slinton Node cond;
352*9663Slinton {
353*9663Slinton     Symbol s;
354*9663Slinton     Node place;
355*9663Slinton 
356*9663Slinton     if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) {
357*9663Slinton 	s = cond->value.arg[0]->value.sym;
358*9663Slinton 	place = cond->value.arg[1];
359*9663Slinton 	if (s == procsym) {
360*9663Slinton 	    if (place->value.sym != program) {
361*9663Slinton 		printf(" in ");
362*9663Slinton 		printname(stdout, place->value.sym);
363*9663Slinton 	    }
364*9663Slinton 	} else if (s == linesym) {
365*9663Slinton 	    printf(" at ");
366*9663Slinton 	    prtree(stdout, place);
367*9663Slinton 	} else if (s == pcsym or s == retaddrsym) {
368*9663Slinton 	    printf("i at ");
369*9663Slinton 	    prtree(stdout, place);
370*9663Slinton 	} else {
371*9663Slinton 	    printf(" when ");
372*9663Slinton 	    prtree(stdout, cond);
373*9663Slinton 	}
374*9663Slinton     } else {
375*9663Slinton 	printf(" when ");
376*9663Slinton 	prtree(stdout, cond);
377*9663Slinton     }
378*9663Slinton }
379*9663Slinton 
380*9663Slinton /*
381*9663Slinton  * Add a breakpoint to the list and return it.
382*9663Slinton  */
383*9663Slinton 
384*9663Slinton private Breakpoint bp_alloc(e, addr, line, actions)
385*9663Slinton Event e;
386*9663Slinton Address addr;
387*9663Slinton Lineno line;
388*9663Slinton Cmdlist actions;
389*9663Slinton {
390*9663Slinton     register Breakpoint p;
391*9663Slinton 
392*9663Slinton     p = new(Breakpoint);
393*9663Slinton     p->event = e;
394*9663Slinton     p->bpaddr = addr;
395*9663Slinton     p->bpline = line;
396*9663Slinton     p->actions = actions;
397*9663Slinton     if (tracebpts) {
398*9663Slinton 	printf("new bp at 0x%x\n", addr);
399*9663Slinton 	fflush(stdout);
400*9663Slinton     }
401*9663Slinton     bplist_append(p, bplist);
402*9663Slinton     return p;
403*9663Slinton }
404*9663Slinton 
405*9663Slinton /*
406*9663Slinton  * Free all storage in the event and breakpoint tables.
407*9663Slinton  */
408*9663Slinton 
409*9663Slinton public bpfree()
410*9663Slinton {
411*9663Slinton     register Event e;
412*9663Slinton 
413*9663Slinton     fixbps();
414*9663Slinton     foreach (Event, e, eventlist)
415*9663Slinton 	delevent(e->id);
416*9663Slinton 	list_delete(list_curitem(eventlist), eventlist);
417*9663Slinton     endfor
418*9663Slinton }
419*9663Slinton 
420*9663Slinton /*
421*9663Slinton  * Determine if the program stopped at a known breakpoint
422*9663Slinton  * and if so do the associated commands.
423*9663Slinton  */
424*9663Slinton 
425*9663Slinton public Boolean bpact()
426*9663Slinton {
427*9663Slinton     register Breakpoint p;
428*9663Slinton     Boolean found;
429*9663Slinton 
430*9663Slinton     found = false;
431*9663Slinton     foreach (Breakpoint, p, bplist)
432*9663Slinton 	if (p->bpaddr == pc) {
433*9663Slinton 	    if (tracebpts) {
434*9663Slinton 		printf("breakpoint found at location 0x%x\n", pc);
435*9663Slinton 	    }
436*9663Slinton 	    found = true;
437*9663Slinton 	    if (p->event->temporary) {
438*9663Slinton 		delevent(p->event->id);
439*9663Slinton 	    }
440*9663Slinton 	    evalcmdlist(p->actions);
441*9663Slinton 	}
442*9663Slinton     endfor
443*9663Slinton     if (isstopped) {
444*9663Slinton 	printstatus();
445*9663Slinton     }
446*9663Slinton     fflush(stdout);
447*9663Slinton     return found;
448*9663Slinton }
449*9663Slinton 
450*9663Slinton /*
451*9663Slinton  * Begin single stepping and executing the given commands after each step.
452*9663Slinton  * If the first argument is true step by instructions, otherwise
453*9663Slinton  * step by source lines.
454*9663Slinton  *
455*9663Slinton  * We automatically set a breakpoint at the end of the current procedure
456*9663Slinton  * to turn off the given tracing.
457*9663Slinton  */
458*9663Slinton 
459*9663Slinton public traceon(inst, event, cmdlist)
460*9663Slinton Boolean inst;
461*9663Slinton Event event;
462*9663Slinton Cmdlist cmdlist;
463*9663Slinton {
464*9663Slinton     register Trcmd trcmd;
465*9663Slinton     Breakpoint bp;
466*9663Slinton     Node until;
467*9663Slinton     Cmdlist actions;
468*9663Slinton 
469*9663Slinton     trcmd = new(Trcmd);
470*9663Slinton     ++trid;
471*9663Slinton     trcmd->trid = trid;
472*9663Slinton     trcmd->event = event;
473*9663Slinton     trcmd->cmdlist = cmdlist;
474*9663Slinton     single_stepping = true;
475*9663Slinton     if (inst) {
476*9663Slinton 	inst_tracing = true;
477*9663Slinton 	list_append(list_item(trcmd), nil, eachinst);
478*9663Slinton     } else {
479*9663Slinton 	list_append(list_item(trcmd), nil, eachline);
480*9663Slinton     }
481*9663Slinton     until = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, return_addr()));
482*9663Slinton     actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid));
483*9663Slinton     event_once(until, actions);
484*9663Slinton     if (tracebpts) {
485*9663Slinton 	printf("adding trace %d for event %d\n", trcmd->trid, event->id);
486*9663Slinton     }
487*9663Slinton }
488*9663Slinton 
489*9663Slinton /*
490*9663Slinton  * Turn off some kind of tracing.
491*9663Slinton  * Strictly an internal command, this cannot be invoked by the user.
492*9663Slinton  */
493*9663Slinton 
494*9663Slinton public traceoff(id)
495*9663Slinton Integer id;
496*9663Slinton {
497*9663Slinton     register Trcmd t;
498*9663Slinton     register Boolean found;
499*9663Slinton 
500*9663Slinton     found = false;
501*9663Slinton     foreach (Trcmd, t, eachline)
502*9663Slinton 	if (t->trid == id) {
503*9663Slinton 	    printrmtr(t);
504*9663Slinton 	    list_delete(list_curitem(eachline), eachline);
505*9663Slinton 	    found = true;
506*9663Slinton 	    break;
507*9663Slinton 	}
508*9663Slinton     endfor
509*9663Slinton     if (not found) {
510*9663Slinton 	foreach (Trcmd, t, eachinst)
511*9663Slinton 	    if (t->event->id == id) {
512*9663Slinton 		printrmtr(t);
513*9663Slinton 		list_delete(list_curitem(eachinst), eachinst);
514*9663Slinton 		found = true;
515*9663Slinton 		break;
516*9663Slinton 	    }
517*9663Slinton 	endfor
518*9663Slinton 	if (not found) {
519*9663Slinton 	    panic("missing trid %d", id);
520*9663Slinton 	}
521*9663Slinton     }
522*9663Slinton     if (list_size(eachinst) == 0) {
523*9663Slinton 	inst_tracing = false;
524*9663Slinton 	if (list_size(eachline) == 0) {
525*9663Slinton 	    single_stepping = false;
526*9663Slinton 	}
527*9663Slinton     }
528*9663Slinton }
529*9663Slinton 
530*9663Slinton /*
531*9663Slinton  * If breakpoints are being traced, note that a Trcmd is being deleted.
532*9663Slinton  */
533*9663Slinton 
534*9663Slinton private printrmtr(t)
535*9663Slinton Trcmd t;
536*9663Slinton {
537*9663Slinton     if (tracebpts) {
538*9663Slinton 	printf("removing trace %d for event %d\n", t->trid, t->event->id);
539*9663Slinton     }
540*9663Slinton }
541*9663Slinton 
542*9663Slinton /*
543*9663Slinton  * Print out news during single step tracing.
544*9663Slinton  */
545*9663Slinton 
546*9663Slinton public printnews()
547*9663Slinton {
548*9663Slinton     register Trcmd t;
549*9663Slinton 
550*9663Slinton     foreach (Trcmd, t, eachline)
551*9663Slinton 	evalcmdlist(t->cmdlist);
552*9663Slinton     endfor
553*9663Slinton     foreach (Trcmd, t, eachinst)
554*9663Slinton 	evalcmdlist(t->cmdlist);
555*9663Slinton     endfor
556*9663Slinton     bpact();
557*9663Slinton }
558*9663Slinton 
559*9663Slinton /*
560*9663Slinton  * A procedure call/return has occurred while single-stepping,
561*9663Slinton  * note it if we're tracing lines.
562*9663Slinton  */
563*9663Slinton 
564*9663Slinton private Boolean chklist();
565*9663Slinton 
566*9663Slinton public callnews(iscall)
567*9663Slinton Boolean iscall;
568*9663Slinton {
569*9663Slinton     if (not chklist(eachline, iscall)) {
570*9663Slinton 	chklist(eachinst, iscall);
571*9663Slinton     }
572*9663Slinton }
573*9663Slinton 
574*9663Slinton private Boolean chklist(list, iscall)
575*9663Slinton List list;
576*9663Slinton Boolean iscall;
577*9663Slinton {
578*9663Slinton     register Trcmd t;
579*9663Slinton     register Command cmd;
580*9663Slinton 
581*9663Slinton     foreach (Trcmd, t, list)
582*9663Slinton 	foreach (Command, cmd, t->cmdlist)
583*9663Slinton 	    if (cmd->op == O_PRINTSRCPOS and
584*9663Slinton 	      (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) {
585*9663Slinton 		curfunc = whatblock(pc);
586*9663Slinton 		if (iscall) {
587*9663Slinton 		    printentry(curfunc);
588*9663Slinton 		} else {
589*9663Slinton 		    printexit(curfunc);
590*9663Slinton 		}
591*9663Slinton 		return true;
592*9663Slinton 	    }
593*9663Slinton 	endfor
594*9663Slinton     endfor
595*9663Slinton     return false;
596*9663Slinton }
597*9663Slinton 
598*9663Slinton /*
599*9663Slinton  * When tracing variables we keep a copy of their most recent value
600*9663Slinton  * and compare it to the current one each time a breakpoint occurs.
601*9663Slinton  * MAXTRSIZE is the maximum size variable we allow.
602*9663Slinton  */
603*9663Slinton 
604*9663Slinton #define MAXTRSIZE 512
605*9663Slinton 
606*9663Slinton /*
607*9663Slinton  * List of variables being watched.
608*9663Slinton  */
609*9663Slinton 
610*9663Slinton typedef struct Trinfo *Trinfo;
611*9663Slinton 
612*9663Slinton struct Trinfo {
613*9663Slinton     Node variable;
614*9663Slinton     Address traddr;
615*9663Slinton     Symbol trblock;
616*9663Slinton     char *trvalue;
617*9663Slinton };
618*9663Slinton 
619*9663Slinton private List trinfolist;
620*9663Slinton 
621*9663Slinton /*
622*9663Slinton  * Find the trace information record associated with the given record.
623*9663Slinton  * If there isn't one then create it and add it to the list.
624*9663Slinton  */
625*9663Slinton 
626*9663Slinton private Trinfo findtrinfo(p)
627*9663Slinton Node p;
628*9663Slinton {
629*9663Slinton     register Trinfo tp;
630*9663Slinton     Boolean isnew;
631*9663Slinton 
632*9663Slinton     isnew = true;
633*9663Slinton     if (trinfolist == nil) {
634*9663Slinton 	trinfolist = list_alloc();
635*9663Slinton     } else {
636*9663Slinton 	foreach (Trinfo, tp, trinfolist)
637*9663Slinton 	    if (tp->variable == p) {
638*9663Slinton 		isnew = false;
639*9663Slinton 		break;
640*9663Slinton 	    }
641*9663Slinton 	endfor
642*9663Slinton     }
643*9663Slinton     if (isnew) {
644*9663Slinton 	if (tracebpts) {
645*9663Slinton 	    printf("adding trinfo for \"");
646*9663Slinton 	    prtree(stdout, p);
647*9663Slinton 	    printf("\"\n");
648*9663Slinton 	}
649*9663Slinton 	tp = new(Trinfo);
650*9663Slinton 	tp->variable = p;
651*9663Slinton 	tp->traddr = lval(p);
652*9663Slinton 	tp->trvalue = nil;
653*9663Slinton 	list_append(list_item(tp), nil, trinfolist);
654*9663Slinton     }
655*9663Slinton     return tp;
656*9663Slinton }
657*9663Slinton 
658*9663Slinton /*
659*9663Slinton  * Print out the value of a variable if it has changed since the
660*9663Slinton  * last time we checked.
661*9663Slinton  */
662*9663Slinton 
663*9663Slinton public printifchanged(p)
664*9663Slinton Node p;
665*9663Slinton {
666*9663Slinton     register Trinfo tp;
667*9663Slinton     register int n;
668*9663Slinton     char buff[MAXTRSIZE];
669*9663Slinton     static Lineno prevline;
670*9663Slinton 
671*9663Slinton     tp = findtrinfo(p);
672*9663Slinton     n = size(p->nodetype);
673*9663Slinton     dread(buff, tp->traddr, n);
674*9663Slinton     if (tp->trvalue == nil) {
675*9663Slinton 	tp->trvalue = newarr(char, n);
676*9663Slinton 	mov(buff, tp->trvalue, n);
677*9663Slinton 	mov(buff, sp, n);
678*9663Slinton 	sp += n;
679*9663Slinton 	printf("initially (at line %d):\t", curline);
680*9663Slinton 	prtree(stdout, p);
681*9663Slinton 	printf(" = ");
682*9663Slinton 	printval(p->nodetype);
683*9663Slinton 	putchar('\n');
684*9663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
685*9663Slinton 	mov(buff, tp->trvalue, n);
686*9663Slinton 	mov(buff, sp, n);
687*9663Slinton 	sp += n;
688*9663Slinton 	printf("after line %d:\t", prevline);
689*9663Slinton 	prtree(stdout, p);
690*9663Slinton 	printf(" = ");
691*9663Slinton 	printval(p->nodetype);
692*9663Slinton 	putchar('\n');
693*9663Slinton     }
694*9663Slinton     prevline = curline;
695*9663Slinton }
696*9663Slinton 
697*9663Slinton /*
698*9663Slinton  * Stop if the value of the given expression has changed.
699*9663Slinton  */
700*9663Slinton 
701*9663Slinton public stopifchanged(p)
702*9663Slinton Node p;
703*9663Slinton {
704*9663Slinton     register Trinfo tp;
705*9663Slinton     register int n;
706*9663Slinton     char buff[MAXTRSIZE];
707*9663Slinton     static Lineno prevline;
708*9663Slinton 
709*9663Slinton     tp = findtrinfo(p);
710*9663Slinton     n = size(p->nodetype);
711*9663Slinton     dread(buff, tp->traddr, n);
712*9663Slinton     if (tp->trvalue == nil) {
713*9663Slinton 	tp->trvalue = newarr(char, n);
714*9663Slinton 	mov(buff, tp->trvalue, n);
715*9663Slinton 	isstopped = true;
716*9663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
717*9663Slinton 	mov(buff, tp->trvalue, n);
718*9663Slinton 	isstopped = true;
719*9663Slinton     }
720*9663Slinton     prevline = curline;
721*9663Slinton }
722*9663Slinton 
723*9663Slinton /*
724*9663Slinton  * Free the tracing table.
725*9663Slinton  */
726*9663Slinton 
727*9663Slinton public trfree()
728*9663Slinton {
729*9663Slinton     register Trinfo tp;
730*9663Slinton 
731*9663Slinton     foreach (Trinfo, tp, trinfolist)
732*9663Slinton 	dispose(tp->trvalue);
733*9663Slinton 	dispose(tp);
734*9663Slinton 	list_delete(list_curitem(trinfolist), trinfolist);
735*9663Slinton     endfor
736*9663Slinton }
737*9663Slinton 
738*9663Slinton /*
739*9663Slinton  * Fix up breakpoint information before continuing execution.
740*9663Slinton  *
741*9663Slinton  * It's necessary to destroy events and breakpoints that were created
742*9663Slinton  * temporarily and still exist because the program terminated abnormally.
743*9663Slinton  */
744*9663Slinton 
745*9663Slinton public fixbps()
746*9663Slinton {
747*9663Slinton     register Event e;
748*9663Slinton     register Trcmd t;
749*9663Slinton 
750*9663Slinton     single_stepping = false;
751*9663Slinton     inst_tracing = false;
752*9663Slinton     trfree();
753*9663Slinton     foreach (Event, e, eventlist)
754*9663Slinton 	if (e->temporary) {
755*9663Slinton 	    delevent(e->id);
756*9663Slinton 	}
757*9663Slinton     endfor
758*9663Slinton     foreach (Trcmd, t, eachline)
759*9663Slinton 	printrmtr(t);
760*9663Slinton 	list_delete(list_curitem(eachline), eachline);
761*9663Slinton     endfor
762*9663Slinton     foreach (Trcmd, t, eachinst)
763*9663Slinton 	printrmtr(t);
764*9663Slinton 	list_delete(list_curitem(eachinst), eachinst);
765*9663Slinton     endfor
766*9663Slinton }
767*9663Slinton 
768*9663Slinton /*
769*9663Slinton  * Set all breakpoints in object code.
770*9663Slinton  */
771*9663Slinton 
772*9663Slinton public setallbps()
773*9663Slinton {
774*9663Slinton     register Breakpoint p;
775*9663Slinton 
776*9663Slinton     foreach (Breakpoint, p, bplist)
777*9663Slinton 	setbp(p->bpaddr);
778*9663Slinton     endfor
779*9663Slinton }
780*9663Slinton 
781*9663Slinton /*
782*9663Slinton  * Undo damage done by "setallbps".
783*9663Slinton  */
784*9663Slinton 
785*9663Slinton public unsetallbps()
786*9663Slinton {
787*9663Slinton     register Breakpoint p;
788*9663Slinton 
789*9663Slinton     foreach (Breakpoint, p, bplist)
790*9663Slinton 	unsetbp(p->bpaddr);
791*9663Slinton     endfor
792*9663Slinton }
793