xref: /csrg-svn/old/dbx/events.c (revision 16609)
19663Slinton /* Copyright (c) 1982 Regents of the University of California */
29663Slinton 
3*16609Ssam static char sccsid[] = "@(#)events.c 1.3 4/8/83";
49663Slinton 
5*16609Ssam static char rcsid[] = "$Header: events.c,v 1.3 84/03/27 10:20:41 linton Exp $";
6*16609Ssam 
79663Slinton /*
89663Slinton  * Event/breakpoint managment.
99663Slinton  */
109663Slinton 
119663Slinton #include "defs.h"
129663Slinton #include "events.h"
139663Slinton #include "main.h"
149663Slinton #include "symbols.h"
159663Slinton #include "tree.h"
169663Slinton #include "eval.h"
179663Slinton #include "source.h"
189663Slinton #include "mappings.h"
19*16609Ssam #include "runtime.h"
209663Slinton #include "process.h"
219663Slinton #include "machine.h"
229663Slinton #include "lists.h"
239663Slinton 
249663Slinton #ifndef public
259663Slinton typedef struct Event *Event;
269663Slinton typedef struct Breakpoint *Breakpoint;
279663Slinton 
289663Slinton Boolean inst_tracing;
299663Slinton Boolean single_stepping;
309663Slinton Boolean isstopped;
319663Slinton 
329663Slinton #include "symbols.h"
339663Slinton 
349663Slinton Symbol linesym;
359663Slinton Symbol procsym;
369663Slinton Symbol pcsym;
379663Slinton Symbol retaddrsym;
389663Slinton 
399663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist)
409663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist)
419663Slinton 
429663Slinton #endif
439663Slinton 
449663Slinton struct Event {
459663Slinton     unsigned int id;
469663Slinton     Boolean temporary;
479663Slinton     Node condition;
489663Slinton     Cmdlist actions;
499663Slinton };
509663Slinton 
519663Slinton struct Breakpoint {
529663Slinton     Event event;
539663Slinton     Address bpaddr;
549663Slinton     Lineno bpline;
559663Slinton     Cmdlist actions;
569663Slinton };
579663Slinton 
589663Slinton typedef List Eventlist;
599663Slinton typedef List Bplist;
609663Slinton 
619663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el)
629663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)
639663Slinton 
649663Slinton private Eventlist eventlist;		/* list of active events */
659663Slinton private Bplist bplist;			/* list of active breakpoints */
669663Slinton private Integer eventid;		/* id number of next allocated event */
679663Slinton private Integer trid;			/* id number of next allocated trace */
689663Slinton 
699663Slinton typedef struct Trcmd {
709663Slinton     Integer trid;
719663Slinton     Event event;
729663Slinton     Cmdlist cmdlist;
739663Slinton } *Trcmd;
749663Slinton 
759663Slinton private List eachline;		/* commands to execute after each line */
769663Slinton private List eachinst;		/* commands to execute after each instruction */
779663Slinton 
789663Slinton private Breakpoint bp_alloc();
799663Slinton 
809663Slinton /*
819663Slinton  * Initialize breakpoint information.
829663Slinton  */
839663Slinton 
849663Slinton private Symbol builtinsym(str, class, type)
859663Slinton String str;
869663Slinton Symclass class;
879663Slinton Symbol type;
889663Slinton {
899663Slinton     Symbol s;
909663Slinton 
919663Slinton     s = insert(identname(str, true));
929663Slinton     s->language = findlanguage(".s");
939663Slinton     s->class = class;
949663Slinton     s->type = type;
959663Slinton     return s;
969663Slinton }
979663Slinton 
989663Slinton public bpinit()
999663Slinton {
1009663Slinton     linesym = builtinsym("$line", VAR, t_int);
1019663Slinton     procsym = builtinsym("$proc", PROC, nil);
1029663Slinton     pcsym = lookup(identname("$pc", true));
1039663Slinton     if (pcsym == nil) {
1049663Slinton 	panic("can't find $pc");
1059663Slinton     }
1069663Slinton     retaddrsym = builtinsym("$retaddr", VAR, t_int);
1079663Slinton     eventlist = list_alloc();
1089663Slinton     bplist = list_alloc();
1099663Slinton     eachline = list_alloc();
1109663Slinton     eachinst = list_alloc();
1119663Slinton }
1129663Slinton 
1139663Slinton /*
1149663Slinton  * Trap an event and do the associated commands when it occurs.
1159663Slinton  */
1169663Slinton 
1179663Slinton public Event event_alloc(istmp, econd, cmdlist)
1189663Slinton Boolean istmp;
1199663Slinton Node econd;
1209663Slinton Cmdlist cmdlist;
1219663Slinton {
1229663Slinton     register Event e;
1239663Slinton 
1249663Slinton     e = new(Event);
1259663Slinton     ++eventid;
1269663Slinton     e->id = eventid;
1279663Slinton     e->temporary = istmp;
1289663Slinton     e->condition = econd;
1299663Slinton     e->actions = cmdlist;
1309663Slinton     eventlist_append(e, eventlist);
1319663Slinton     translate(e);
1329663Slinton     return e;
1339663Slinton }
1349663Slinton 
1359663Slinton /*
1369663Slinton  * Delete the event with the given id.
137*16609Ssam  * Returns whether it's successful or not.
1389663Slinton  */
1399663Slinton 
140*16609Ssam public boolean delevent (id)
1419663Slinton unsigned int id;
1429663Slinton {
1439663Slinton     Event e;
1449663Slinton     Breakpoint bp;
1459663Slinton     Trcmd t;
146*16609Ssam     boolean found;
1479663Slinton 
148*16609Ssam     found = false;
1499663Slinton     foreach (Event, e, eventlist)
1509663Slinton 	if (e->id == id) {
151*16609Ssam 	    found = true;
1529663Slinton 	    foreach (Breakpoint, bp, bplist)
1539663Slinton 		if (bp->event == e) {
154*16609Ssam 		    if (tracebpts) {
155*16609Ssam 			printf("deleting breakpoint at 0x%x\n", bp->bpaddr);
156*16609Ssam 			fflush(stdout);
157*16609Ssam 		    }
1589663Slinton 		    list_delete(list_curitem(bplist), bplist);
1599663Slinton 		}
1609663Slinton 	    endfor
161*16609Ssam 	    list_delete(list_curitem(eventlist), eventlist);
1629663Slinton 	    break;
1639663Slinton 	}
1649663Slinton     endfor
1659663Slinton     foreach (Trcmd, t, eachline)
1669663Slinton 	if (t->event->id == id) {
167*16609Ssam 	    found = true;
1689663Slinton 	    printrmtr(t);
1699663Slinton 	    list_delete(list_curitem(eachline), eachline);
1709663Slinton 	}
1719663Slinton     endfor
1729663Slinton     foreach (Trcmd, t, eachinst)
1739663Slinton 	if (t->event->id == id) {
174*16609Ssam 	    found = true;
1759663Slinton 	    printrmtr(t);
1769663Slinton 	    list_delete(list_curitem(eachinst), eachinst);
1779663Slinton 	}
1789663Slinton     endfor
1799663Slinton     if (list_size(eachinst) == 0) {
1809663Slinton 	inst_tracing = false;
1819663Slinton 	if (list_size(eachline) == 0) {
1829663Slinton 	    single_stepping = false;
1839663Slinton 	}
1849663Slinton     }
185*16609Ssam     return found;
1869663Slinton }
1879663Slinton 
1889663Slinton /*
1899663Slinton  * Translate an event into the appropriate breakpoints and actions.
1909663Slinton  * While we're at it, turn on the breakpoints if the condition is true.
1919663Slinton  */
1929663Slinton 
1939663Slinton private translate(e)
1949663Slinton Event e;
1959663Slinton {
1969663Slinton     Breakpoint bp;
1979663Slinton     Symbol s;
1989663Slinton     Node place;
1999663Slinton     Lineno line;
2009663Slinton     Address addr;
2019663Slinton 
2029663Slinton     checkref(e->condition);
2039663Slinton     switch (e->condition->op) {
2049663Slinton 	case O_EQ:
2059663Slinton 	    if (e->condition->value.arg[0]->op == O_SYM) {
2069663Slinton 		s = e->condition->value.arg[0]->value.sym;
2079663Slinton 		place = e->condition->value.arg[1];
2089663Slinton 		if (s == linesym) {
2099663Slinton 		    if (place->op == O_QLINE) {
2109663Slinton 			line = place->value.arg[1]->value.lcon;
211*16609Ssam 			addr = objaddr(line, place->value.arg[0]->value.scon);
2129663Slinton 		    } else {
2139663Slinton 			eval(place);
2149663Slinton 			line = pop(long);
2159663Slinton 			addr = objaddr(line, cursource);
2169663Slinton 		    }
2179663Slinton 		    if (addr == NOADDR) {
218*16609Ssam 			if (not delevent(e->id)) {
219*16609Ssam 			    printf("!! dbx.translate: can't undo event %d?\n",
220*16609Ssam 				e->id);
221*16609Ssam 			}
2229663Slinton 			beginerrmsg();
2239663Slinton 			fprintf(stderr, "no executable code at line ");
2249663Slinton 			prtree(stderr, place);
2259663Slinton 			enderrmsg();
2269663Slinton 		    }
2279663Slinton 		    bp = bp_alloc(e, addr, line, e->actions);
2289663Slinton 		} else if (s == procsym) {
2299663Slinton 		    eval(place);
2309663Slinton 		    s = pop(Symbol);
2319663Slinton 		    bp = bp_alloc(e, codeloc(s), 0, e->actions);
2329663Slinton 		    if (isactive(s) and pc != codeloc(program)) {
2339663Slinton 			evalcmdlist(e->actions);
2349663Slinton 		    }
2359663Slinton 		} else if (s == pcsym) {
2369663Slinton 		    eval(place);
2379663Slinton 		    bp = bp_alloc(e, pop(Address), 0, e->actions);
2389663Slinton 		} else {
2399663Slinton 		    condbp(e);
2409663Slinton 		}
2419663Slinton 	    } else {
2429663Slinton 		condbp(e);
2439663Slinton 	    }
2449663Slinton 	    break;
2459663Slinton 
2469663Slinton 	/*
2479663Slinton 	 * These should be handled specially.
2489663Slinton 	 * But for now I'm ignoring the problem.
2499663Slinton 	 */
2509663Slinton 	case O_AND:
2519663Slinton 	case O_OR:
2529663Slinton 	default:
2539663Slinton 	    condbp(e);
2549663Slinton 	    break;
2559663Slinton     }
2569663Slinton }
2579663Slinton 
2589663Slinton /*
2599663Slinton  * Create a breakpoint for a condition that cannot be pinpointed
2609663Slinton  * to happening at a particular address, but one for which we
2619663Slinton  * must single step and check the condition after each statement.
2629663Slinton  */
2639663Slinton 
2649663Slinton private condbp(e)
2659663Slinton Event e;
2669663Slinton {
2679663Slinton     Symbol p;
2689663Slinton     Breakpoint bp;
2699663Slinton     Cmdlist actions;
2709663Slinton 
2719663Slinton     p = tcontainer(e->condition);
2729663Slinton     if (p == nil) {
2739663Slinton 	p = program;
2749663Slinton     }
2759663Slinton     actions = buildcmdlist(build(O_IF, e->condition, e->actions));
2769663Slinton     actions = buildcmdlist(build(O_TRACEON, false, actions));
2779663Slinton     bp = bp_alloc(e, codeloc(p), 0, actions);
2789663Slinton }
2799663Slinton 
2809663Slinton /*
2819663Slinton  * Determine the deepest nested subprogram that still contains
2829663Slinton  * all elements in the given expression.
2839663Slinton  */
2849663Slinton 
2859663Slinton public Symbol tcontainer(exp)
2869663Slinton Node exp;
2879663Slinton {
2889663Slinton     Integer i;
2899663Slinton     Symbol s, t, u, v;
2909663Slinton 
2919663Slinton     checkref(exp);
2929663Slinton     s = nil;
2939663Slinton     if (exp->op == O_SYM) {
2949663Slinton 	s = container(exp->value.sym);
2959663Slinton     } else if (not isleaf(exp->op)) {
2969663Slinton 	for (i = 0; i < nargs(exp->op); i++) {
2979663Slinton 	    t = tcontainer(exp->value.arg[i]);
2989663Slinton 	    if (t != nil) {
2999663Slinton 		if (s == nil) {
3009663Slinton 		    s = t;
3019663Slinton 		} else {
3029663Slinton 		    u = s;
3039663Slinton 		    v = t;
3049663Slinton 		    while (u != v and u != nil) {
3059663Slinton 			u = container(u);
3069663Slinton 			v = container(v);
3079663Slinton 		    }
3089663Slinton 		    if (u == nil) {
3099663Slinton 			panic("bad ancestry for \"%s\"", symname(s));
3109663Slinton 		    } else {
3119663Slinton 			s = u;
3129663Slinton 		    }
3139663Slinton 		}
3149663Slinton 	    }
3159663Slinton 	}
3169663Slinton     }
3179663Slinton     return s;
3189663Slinton }
3199663Slinton 
3209663Slinton /*
32111869Slinton  * Determine if the given function can be executed at full speed.
32211869Slinton  * This can only be done if there are no breakpoints within the function.
32311869Slinton  */
32411869Slinton 
32511869Slinton public Boolean canskip(f)
32611869Slinton Symbol f;
32711869Slinton {
32811869Slinton     Breakpoint p;
32911869Slinton     Boolean ok;
33011869Slinton 
33111869Slinton     ok = true;
33211869Slinton     foreach (Breakpoint, p, bplist)
33311869Slinton 	if (whatblock(p->bpaddr) == f) {
33411869Slinton 	    ok = false;
33511869Slinton 	    break;
33611869Slinton 	}
33711869Slinton     endfor
33811869Slinton     return ok;
33911869Slinton }
34011869Slinton 
34111869Slinton /*
3429663Slinton  * Print out what's currently being traced by looking at
3439663Slinton  * the currently active events.
3449663Slinton  *
3459663Slinton  * Some convolution here to translate internal representation
3469663Slinton  * of events back into something more palatable.
3479663Slinton  */
3489663Slinton 
3499663Slinton public status()
3509663Slinton {
3519663Slinton     Event e;
3529663Slinton 
3539663Slinton     foreach (Event, e, eventlist)
3549663Slinton 	if (not e->temporary) {
35511869Slinton 	    printevent(e);
3569663Slinton 	}
3579663Slinton     endfor
3589663Slinton }
3599663Slinton 
36011869Slinton public printevent(e)
36111869Slinton Event e;
36211869Slinton {
36311869Slinton     Command cmd;
36411869Slinton 
36511869Slinton     if (not isredirected()) {
366*16609Ssam 	printeventid(e->id);
36711869Slinton     }
36811869Slinton     cmd = list_element(Command, list_head(e->actions));
36911869Slinton     if (cmd->op == O_PRINTCALL) {
37011869Slinton 	printf("trace ");
37111869Slinton 	printname(stdout, cmd->value.sym);
37211869Slinton     } else {
37311869Slinton 	if (list_size(e->actions) > 1) {
37411869Slinton 	    printf("{ ");
37511869Slinton 	}
37611869Slinton 	foreach (Command, cmd, e->actions)
37711869Slinton 	    printcmd(stdout, cmd);
37811869Slinton 	    if (not list_islast()) {
37911869Slinton 		printf("; ");
38011869Slinton 	    }
38111869Slinton 	endfor
38211869Slinton 	if (list_size(e->actions) > 1) {
38311869Slinton 	    printf(" }");
38411869Slinton 	}
38511869Slinton 	printcond(e->condition);
38611869Slinton     }
38711869Slinton     printf("\n");
38811869Slinton }
38911869Slinton 
390*16609Ssam private printeventid (id)
391*16609Ssam integer id;
392*16609Ssam {
393*16609Ssam     printf("[%d] ", id);
394*16609Ssam }
395*16609Ssam 
3969663Slinton /*
3979663Slinton  * Print out a condition.
3989663Slinton  */
3999663Slinton 
4009663Slinton private printcond(cond)
4019663Slinton Node cond;
4029663Slinton {
4039663Slinton     Symbol s;
4049663Slinton     Node place;
4059663Slinton 
4069663Slinton     if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) {
4079663Slinton 	s = cond->value.arg[0]->value.sym;
4089663Slinton 	place = cond->value.arg[1];
4099663Slinton 	if (s == procsym) {
4109663Slinton 	    if (place->value.sym != program) {
4119663Slinton 		printf(" in ");
4129663Slinton 		printname(stdout, place->value.sym);
4139663Slinton 	    }
4149663Slinton 	} else if (s == linesym) {
4159663Slinton 	    printf(" at ");
4169663Slinton 	    prtree(stdout, place);
4179663Slinton 	} else if (s == pcsym or s == retaddrsym) {
4189663Slinton 	    printf("i at ");
4199663Slinton 	    prtree(stdout, place);
4209663Slinton 	} else {
4219663Slinton 	    printf(" when ");
4229663Slinton 	    prtree(stdout, cond);
4239663Slinton 	}
4249663Slinton     } else {
4259663Slinton 	printf(" when ");
4269663Slinton 	prtree(stdout, cond);
4279663Slinton     }
4289663Slinton }
4299663Slinton 
4309663Slinton /*
4319663Slinton  * Add a breakpoint to the list and return it.
4329663Slinton  */
4339663Slinton 
4349663Slinton private Breakpoint bp_alloc(e, addr, line, actions)
4359663Slinton Event e;
4369663Slinton Address addr;
4379663Slinton Lineno line;
4389663Slinton Cmdlist actions;
4399663Slinton {
4409663Slinton     register Breakpoint p;
4419663Slinton 
4429663Slinton     p = new(Breakpoint);
4439663Slinton     p->event = e;
4449663Slinton     p->bpaddr = addr;
4459663Slinton     p->bpline = line;
4469663Slinton     p->actions = actions;
4479663Slinton     if (tracebpts) {
448*16609Ssam 	if (e == nil) {
449*16609Ssam 	    printf("new bp at 0x%x for event ??\n", addr, e->id);
450*16609Ssam 	} else {
451*16609Ssam 	    printf("new bp at 0x%x for event %d\n", addr, e->id);
452*16609Ssam 	}
4539663Slinton 	fflush(stdout);
4549663Slinton     }
4559663Slinton     bplist_append(p, bplist);
4569663Slinton     return p;
4579663Slinton }
4589663Slinton 
4599663Slinton /*
4609663Slinton  * Free all storage in the event and breakpoint tables.
4619663Slinton  */
4629663Slinton 
4639663Slinton public bpfree()
4649663Slinton {
4659663Slinton     register Event e;
4669663Slinton 
4679663Slinton     fixbps();
4689663Slinton     foreach (Event, e, eventlist)
469*16609Ssam 	if (not delevent(e->id)) {
470*16609Ssam 	    printf("!! dbx.bpfree: can't delete event %d\n", e->id);
471*16609Ssam 	}
4729663Slinton 	list_delete(list_curitem(eventlist), eventlist);
4739663Slinton     endfor
4749663Slinton }
4759663Slinton 
4769663Slinton /*
4779663Slinton  * Determine if the program stopped at a known breakpoint
4789663Slinton  * and if so do the associated commands.
4799663Slinton  */
4809663Slinton 
4819663Slinton public Boolean bpact()
4829663Slinton {
4839663Slinton     register Breakpoint p;
4849663Slinton     Boolean found;
485*16609Ssam     integer eventId;
4869663Slinton 
4879663Slinton     found = false;
4889663Slinton     foreach (Breakpoint, p, bplist)
4899663Slinton 	if (p->bpaddr == pc) {
4909663Slinton 	    if (tracebpts) {
491*16609Ssam 		printf("breakpoint for event %d found at location 0x%x\n",
492*16609Ssam 		    p->event->id, pc);
4939663Slinton 	    }
4949663Slinton 	    found = true;
4959663Slinton 	    if (p->event->temporary) {
496*16609Ssam 		if (not delevent(p->event->id)) {
497*16609Ssam 		    printf("!! dbx.bpact: can't find event %d\n",
498*16609Ssam 			p->event->id);
499*16609Ssam 		}
5009663Slinton 	    }
5019663Slinton 	    evalcmdlist(p->actions);
502*16609Ssam 	    if (isstopped) {
503*16609Ssam 		eventId = p->event->id;
504*16609Ssam 	    }
5059663Slinton 	}
5069663Slinton     endfor
5079663Slinton     if (isstopped) {
508*16609Ssam 	if (found) {
509*16609Ssam 	    printeventid(eventId);
510*16609Ssam 	}
5119663Slinton 	printstatus();
5129663Slinton     }
5139663Slinton     fflush(stdout);
5149663Slinton     return found;
5159663Slinton }
5169663Slinton 
5179663Slinton /*
5189663Slinton  * Begin single stepping and executing the given commands after each step.
5199663Slinton  * If the first argument is true step by instructions, otherwise
5209663Slinton  * step by source lines.
5219663Slinton  *
5229663Slinton  * We automatically set a breakpoint at the end of the current procedure
5239663Slinton  * to turn off the given tracing.
5249663Slinton  */
5259663Slinton 
5269663Slinton public traceon(inst, event, cmdlist)
5279663Slinton Boolean inst;
5289663Slinton Event event;
5299663Slinton Cmdlist cmdlist;
5309663Slinton {
5319663Slinton     register Trcmd trcmd;
5329663Slinton     Breakpoint bp;
5339663Slinton     Cmdlist actions;
53411869Slinton     Address ret;
5359663Slinton 
5369663Slinton     trcmd = new(Trcmd);
5379663Slinton     ++trid;
5389663Slinton     trcmd->trid = trid;
5399663Slinton     trcmd->event = event;
5409663Slinton     trcmd->cmdlist = cmdlist;
5419663Slinton     single_stepping = true;
5429663Slinton     if (inst) {
5439663Slinton 	inst_tracing = true;
5449663Slinton 	list_append(list_item(trcmd), nil, eachinst);
5459663Slinton     } else {
5469663Slinton 	list_append(list_item(trcmd), nil, eachline);
5479663Slinton     }
54811869Slinton     ret = return_addr();
54911869Slinton     if (ret != 0) {
55011869Slinton 	actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid));
551*16609Ssam 	bp = bp_alloc(event, (Address) ret, 0, actions);
55211869Slinton     }
5539663Slinton     if (tracebpts) {
5549663Slinton 	printf("adding trace %d for event %d\n", trcmd->trid, event->id);
5559663Slinton     }
5569663Slinton }
5579663Slinton 
5589663Slinton /*
5599663Slinton  * Turn off some kind of tracing.
5609663Slinton  * Strictly an internal command, this cannot be invoked by the user.
5619663Slinton  */
5629663Slinton 
5639663Slinton public traceoff(id)
5649663Slinton Integer id;
5659663Slinton {
5669663Slinton     register Trcmd t;
5679663Slinton     register Boolean found;
5689663Slinton 
5699663Slinton     found = false;
5709663Slinton     foreach (Trcmd, t, eachline)
5719663Slinton 	if (t->trid == id) {
5729663Slinton 	    printrmtr(t);
5739663Slinton 	    list_delete(list_curitem(eachline), eachline);
5749663Slinton 	    found = true;
5759663Slinton 	    break;
5769663Slinton 	}
5779663Slinton     endfor
5789663Slinton     if (not found) {
5799663Slinton 	foreach (Trcmd, t, eachinst)
5809663Slinton 	    if (t->event->id == id) {
5819663Slinton 		printrmtr(t);
5829663Slinton 		list_delete(list_curitem(eachinst), eachinst);
5839663Slinton 		found = true;
5849663Slinton 		break;
5859663Slinton 	    }
5869663Slinton 	endfor
5879663Slinton 	if (not found) {
5889663Slinton 	    panic("missing trid %d", id);
5899663Slinton 	}
5909663Slinton     }
5919663Slinton     if (list_size(eachinst) == 0) {
5929663Slinton 	inst_tracing = false;
5939663Slinton 	if (list_size(eachline) == 0) {
5949663Slinton 	    single_stepping = false;
5959663Slinton 	}
5969663Slinton     }
5979663Slinton }
5989663Slinton 
5999663Slinton /*
6009663Slinton  * If breakpoints are being traced, note that a Trcmd is being deleted.
6019663Slinton  */
6029663Slinton 
6039663Slinton private printrmtr(t)
6049663Slinton Trcmd t;
6059663Slinton {
6069663Slinton     if (tracebpts) {
60711869Slinton 	printf("removing trace %d", t->trid);
60811869Slinton 	if (t->event != nil) {
60911869Slinton 	    printf(" for event %d", t->event->id);
61011869Slinton 	}
61111869Slinton 	printf("\n");
6129663Slinton     }
6139663Slinton }
6149663Slinton 
6159663Slinton /*
6169663Slinton  * Print out news during single step tracing.
6179663Slinton  */
6189663Slinton 
6199663Slinton public printnews()
6209663Slinton {
6219663Slinton     register Trcmd t;
6229663Slinton 
6239663Slinton     foreach (Trcmd, t, eachline)
6249663Slinton 	evalcmdlist(t->cmdlist);
6259663Slinton     endfor
6269663Slinton     foreach (Trcmd, t, eachinst)
6279663Slinton 	evalcmdlist(t->cmdlist);
6289663Slinton     endfor
6299663Slinton     bpact();
6309663Slinton }
6319663Slinton 
6329663Slinton /*
6339663Slinton  * A procedure call/return has occurred while single-stepping,
6349663Slinton  * note it if we're tracing lines.
6359663Slinton  */
6369663Slinton 
6379663Slinton private Boolean chklist();
6389663Slinton 
6399663Slinton public callnews(iscall)
6409663Slinton Boolean iscall;
6419663Slinton {
6429663Slinton     if (not chklist(eachline, iscall)) {
6439663Slinton 	chklist(eachinst, iscall);
6449663Slinton     }
6459663Slinton }
6469663Slinton 
6479663Slinton private Boolean chklist(list, iscall)
6489663Slinton List list;
6499663Slinton Boolean iscall;
6509663Slinton {
6519663Slinton     register Trcmd t;
6529663Slinton     register Command cmd;
6539663Slinton 
654*16609Ssam     setcurfunc(whatblock(pc));
6559663Slinton     foreach (Trcmd, t, list)
6569663Slinton 	foreach (Command, cmd, t->cmdlist)
6579663Slinton 	    if (cmd->op == O_PRINTSRCPOS and
6589663Slinton 	      (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) {
6599663Slinton 		if (iscall) {
6609663Slinton 		    printentry(curfunc);
6619663Slinton 		} else {
6629663Slinton 		    printexit(curfunc);
6639663Slinton 		}
6649663Slinton 		return true;
6659663Slinton 	    }
6669663Slinton 	endfor
6679663Slinton     endfor
6689663Slinton     return false;
6699663Slinton }
6709663Slinton 
6719663Slinton /*
6729663Slinton  * When tracing variables we keep a copy of their most recent value
6739663Slinton  * and compare it to the current one each time a breakpoint occurs.
6749663Slinton  * MAXTRSIZE is the maximum size variable we allow.
6759663Slinton  */
6769663Slinton 
6779663Slinton #define MAXTRSIZE 512
6789663Slinton 
6799663Slinton /*
6809663Slinton  * List of variables being watched.
6819663Slinton  */
6829663Slinton 
6839663Slinton typedef struct Trinfo *Trinfo;
6849663Slinton 
6859663Slinton struct Trinfo {
6869663Slinton     Node variable;
6879663Slinton     Address traddr;
6889663Slinton     Symbol trblock;
6899663Slinton     char *trvalue;
6909663Slinton };
6919663Slinton 
6929663Slinton private List trinfolist;
6939663Slinton 
6949663Slinton /*
6959663Slinton  * Find the trace information record associated with the given record.
6969663Slinton  * If there isn't one then create it and add it to the list.
6979663Slinton  */
6989663Slinton 
6999663Slinton private Trinfo findtrinfo(p)
7009663Slinton Node p;
7019663Slinton {
7029663Slinton     register Trinfo tp;
7039663Slinton     Boolean isnew;
7049663Slinton 
7059663Slinton     isnew = true;
7069663Slinton     if (trinfolist == nil) {
7079663Slinton 	trinfolist = list_alloc();
7089663Slinton     } else {
7099663Slinton 	foreach (Trinfo, tp, trinfolist)
7109663Slinton 	    if (tp->variable == p) {
7119663Slinton 		isnew = false;
7129663Slinton 		break;
7139663Slinton 	    }
7149663Slinton 	endfor
7159663Slinton     }
7169663Slinton     if (isnew) {
7179663Slinton 	if (tracebpts) {
7189663Slinton 	    printf("adding trinfo for \"");
7199663Slinton 	    prtree(stdout, p);
7209663Slinton 	    printf("\"\n");
7219663Slinton 	}
7229663Slinton 	tp = new(Trinfo);
7239663Slinton 	tp->variable = p;
7249663Slinton 	tp->traddr = lval(p);
7259663Slinton 	tp->trvalue = nil;
7269663Slinton 	list_append(list_item(tp), nil, trinfolist);
7279663Slinton     }
7289663Slinton     return tp;
7299663Slinton }
7309663Slinton 
7319663Slinton /*
7329663Slinton  * Print out the value of a variable if it has changed since the
7339663Slinton  * last time we checked.
7349663Slinton  */
7359663Slinton 
7369663Slinton public printifchanged(p)
7379663Slinton Node p;
7389663Slinton {
7399663Slinton     register Trinfo tp;
7409663Slinton     register int n;
7419663Slinton     char buff[MAXTRSIZE];
7429663Slinton     static Lineno prevline;
7439663Slinton 
7449663Slinton     tp = findtrinfo(p);
7459663Slinton     n = size(p->nodetype);
7469663Slinton     dread(buff, tp->traddr, n);
7479663Slinton     if (tp->trvalue == nil) {
7489663Slinton 	tp->trvalue = newarr(char, n);
7499663Slinton 	mov(buff, tp->trvalue, n);
7509663Slinton 	mov(buff, sp, n);
7519663Slinton 	sp += n;
7529663Slinton 	printf("initially (at line %d):\t", curline);
7539663Slinton 	prtree(stdout, p);
7549663Slinton 	printf(" = ");
7559663Slinton 	printval(p->nodetype);
7569663Slinton 	putchar('\n');
7579663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
7589663Slinton 	mov(buff, tp->trvalue, n);
7599663Slinton 	mov(buff, sp, n);
7609663Slinton 	sp += n;
7619663Slinton 	printf("after line %d:\t", prevline);
7629663Slinton 	prtree(stdout, p);
7639663Slinton 	printf(" = ");
7649663Slinton 	printval(p->nodetype);
7659663Slinton 	putchar('\n');
7669663Slinton     }
7679663Slinton     prevline = curline;
7689663Slinton }
7699663Slinton 
7709663Slinton /*
7719663Slinton  * Stop if the value of the given expression has changed.
7729663Slinton  */
7739663Slinton 
7749663Slinton public stopifchanged(p)
7759663Slinton Node p;
7769663Slinton {
7779663Slinton     register Trinfo tp;
7789663Slinton     register int n;
7799663Slinton     char buff[MAXTRSIZE];
7809663Slinton     static Lineno prevline;
7819663Slinton 
7829663Slinton     tp = findtrinfo(p);
7839663Slinton     n = size(p->nodetype);
7849663Slinton     dread(buff, tp->traddr, n);
7859663Slinton     if (tp->trvalue == nil) {
7869663Slinton 	tp->trvalue = newarr(char, n);
7879663Slinton 	mov(buff, tp->trvalue, n);
7889663Slinton 	isstopped = true;
7899663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
7909663Slinton 	mov(buff, tp->trvalue, n);
791*16609Ssam 	mov(buff, sp, n);
792*16609Ssam 	sp += n;
793*16609Ssam 	printf("after line %d:\t", prevline);
794*16609Ssam 	prtree(stdout, p);
795*16609Ssam 	printf(" = ");
796*16609Ssam 	printval(p->nodetype);
797*16609Ssam 	putchar('\n');
7989663Slinton 	isstopped = true;
7999663Slinton     }
8009663Slinton     prevline = curline;
8019663Slinton }
8029663Slinton 
8039663Slinton /*
8049663Slinton  * Free the tracing table.
8059663Slinton  */
8069663Slinton 
8079663Slinton public trfree()
8089663Slinton {
8099663Slinton     register Trinfo tp;
8109663Slinton 
8119663Slinton     foreach (Trinfo, tp, trinfolist)
8129663Slinton 	dispose(tp->trvalue);
8139663Slinton 	dispose(tp);
8149663Slinton 	list_delete(list_curitem(trinfolist), trinfolist);
8159663Slinton     endfor
8169663Slinton }
8179663Slinton 
8189663Slinton /*
8199663Slinton  * Fix up breakpoint information before continuing execution.
8209663Slinton  *
8219663Slinton  * It's necessary to destroy events and breakpoints that were created
8229663Slinton  * temporarily and still exist because the program terminated abnormally.
8239663Slinton  */
8249663Slinton 
8259663Slinton public fixbps()
8269663Slinton {
8279663Slinton     register Event e;
8289663Slinton     register Trcmd t;
8299663Slinton 
8309663Slinton     single_stepping = false;
8319663Slinton     inst_tracing = false;
8329663Slinton     trfree();
8339663Slinton     foreach (Event, e, eventlist)
8349663Slinton 	if (e->temporary) {
835*16609Ssam 	    if (not delevent(e->id)) {
836*16609Ssam 		printf("!! dbx.fixbps: can't find event %d\n", e->id);
837*16609Ssam 	    }
8389663Slinton 	}
8399663Slinton     endfor
8409663Slinton     foreach (Trcmd, t, eachline)
8419663Slinton 	printrmtr(t);
8429663Slinton 	list_delete(list_curitem(eachline), eachline);
8439663Slinton     endfor
8449663Slinton     foreach (Trcmd, t, eachinst)
8459663Slinton 	printrmtr(t);
8469663Slinton 	list_delete(list_curitem(eachinst), eachinst);
8479663Slinton     endfor
8489663Slinton }
8499663Slinton 
8509663Slinton /*
8519663Slinton  * Set all breakpoints in object code.
8529663Slinton  */
8539663Slinton 
8549663Slinton public setallbps()
8559663Slinton {
8569663Slinton     register Breakpoint p;
8579663Slinton 
8589663Slinton     foreach (Breakpoint, p, bplist)
8599663Slinton 	setbp(p->bpaddr);
8609663Slinton     endfor
8619663Slinton }
8629663Slinton 
8639663Slinton /*
8649663Slinton  * Undo damage done by "setallbps".
8659663Slinton  */
8669663Slinton 
8679663Slinton public unsetallbps()
8689663Slinton {
8699663Slinton     register Breakpoint p;
8709663Slinton 
8719663Slinton     foreach (Breakpoint, p, bplist)
8729663Slinton 	unsetbp(p->bpaddr);
8739663Slinton     endfor
8749663Slinton }
875