xref: /csrg-svn/old/dbx/events.c (revision 18218)
19663Slinton /* Copyright (c) 1982 Regents of the University of California */
29663Slinton 
3*18218Slinton static	char sccsid[] = "@(#)events.c	1.7 (Berkeley) 03/01/85";
49663Slinton 
5*18218Slinton static char rcsid[] = "$Header: events.c,v 1.5 84/12/26 10:39:26 linton Exp $";
6*18218Slinton 
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"
1916609Ssam #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 
28*18218Slinton boolean inst_tracing;
29*18218Slinton boolean single_stepping;
30*18218Slinton 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;
46*18218Slinton     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;
56*18218Slinton     boolean temporary;
579663Slinton };
589663Slinton 
599663Slinton typedef List Eventlist;
609663Slinton typedef List Bplist;
619663Slinton 
629663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el)
639663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)
649663Slinton 
659663Slinton private Eventlist eventlist;		/* list of active events */
669663Slinton private Bplist bplist;			/* list of active breakpoints */
67*18218Slinton private Event curevent;			/* most recently created event */
68*18218Slinton private integer eventid;		/* id number of current event */
69*18218Slinton private integer trid;			/* id number of current trace */
709663Slinton 
719663Slinton typedef struct Trcmd {
729663Slinton     Integer trid;
739663Slinton     Event event;
749663Slinton     Cmdlist cmdlist;
759663Slinton } *Trcmd;
769663Slinton 
779663Slinton private List eachline;		/* commands to execute after each line */
789663Slinton private List eachinst;		/* commands to execute after each instruction */
799663Slinton 
809663Slinton private Breakpoint bp_alloc();
819663Slinton 
829663Slinton /*
839663Slinton  * Initialize breakpoint information.
849663Slinton  */
859663Slinton 
869663Slinton private Symbol builtinsym(str, class, type)
879663Slinton String str;
889663Slinton Symclass class;
899663Slinton Symbol type;
909663Slinton {
919663Slinton     Symbol s;
929663Slinton 
939663Slinton     s = insert(identname(str, true));
949663Slinton     s->language = findlanguage(".s");
959663Slinton     s->class = class;
969663Slinton     s->type = type;
979663Slinton     return s;
989663Slinton }
999663Slinton 
1009663Slinton public bpinit()
1019663Slinton {
1029663Slinton     linesym = builtinsym("$line", VAR, t_int);
1039663Slinton     procsym = builtinsym("$proc", PROC, nil);
1049663Slinton     pcsym = lookup(identname("$pc", true));
1059663Slinton     if (pcsym == nil) {
1069663Slinton 	panic("can't find $pc");
1079663Slinton     }
1089663Slinton     retaddrsym = builtinsym("$retaddr", VAR, t_int);
1099663Slinton     eventlist = list_alloc();
1109663Slinton     bplist = list_alloc();
1119663Slinton     eachline = list_alloc();
1129663Slinton     eachinst = list_alloc();
1139663Slinton }
1149663Slinton 
1159663Slinton /*
1169663Slinton  * Trap an event and do the associated commands when it occurs.
1179663Slinton  */
1189663Slinton 
1199663Slinton public Event event_alloc(istmp, econd, cmdlist)
120*18218Slinton boolean istmp;
1219663Slinton Node econd;
1229663Slinton Cmdlist cmdlist;
1239663Slinton {
1249663Slinton     register Event e;
1259663Slinton 
1269663Slinton     e = new(Event);
127*18218Slinton     ++eventid;
128*18218Slinton     e->id = eventid;
1299663Slinton     e->temporary = istmp;
1309663Slinton     e->condition = econd;
1319663Slinton     e->actions = cmdlist;
1329663Slinton     eventlist_append(e, eventlist);
133*18218Slinton     curevent = e;
1349663Slinton     translate(e);
1359663Slinton     return e;
1369663Slinton }
1379663Slinton 
1389663Slinton /*
1399663Slinton  * Delete the event with the given id.
14016609Ssam  * Returns whether it's successful or not.
1419663Slinton  */
1429663Slinton 
14316609Ssam public boolean delevent (id)
1449663Slinton unsigned int id;
1459663Slinton {
1469663Slinton     Event e;
1479663Slinton     Breakpoint bp;
1489663Slinton     Trcmd t;
14916609Ssam     boolean found;
1509663Slinton 
15116609Ssam     found = false;
1529663Slinton     foreach (Event, e, eventlist)
1539663Slinton 	if (e->id == id) {
15416609Ssam 	    found = true;
1559663Slinton 	    foreach (Breakpoint, bp, bplist)
1569663Slinton 		if (bp->event == e) {
157*18218Slinton 		    if (tracebpts) {
158*18218Slinton 			printf("deleting breakpoint at 0x%x\n", bp->bpaddr);
159*18218Slinton 			fflush(stdout);
160*18218Slinton 		    }
1619663Slinton 		    list_delete(list_curitem(bplist), bplist);
1629663Slinton 		}
1639663Slinton 	    endfor
16416609Ssam 	    list_delete(list_curitem(eventlist), eventlist);
1659663Slinton 	    break;
1669663Slinton 	}
1679663Slinton     endfor
1689663Slinton     foreach (Trcmd, t, eachline)
1699663Slinton 	if (t->event->id == id) {
17016609Ssam 	    found = true;
1719663Slinton 	    printrmtr(t);
1729663Slinton 	    list_delete(list_curitem(eachline), eachline);
1739663Slinton 	}
1749663Slinton     endfor
1759663Slinton     foreach (Trcmd, t, eachinst)
1769663Slinton 	if (t->event->id == id) {
17716609Ssam 	    found = true;
1789663Slinton 	    printrmtr(t);
1799663Slinton 	    list_delete(list_curitem(eachinst), eachinst);
1809663Slinton 	}
1819663Slinton     endfor
1829663Slinton     if (list_size(eachinst) == 0) {
1839663Slinton 	inst_tracing = false;
1849663Slinton 	if (list_size(eachline) == 0) {
1859663Slinton 	    single_stepping = false;
1869663Slinton 	}
1879663Slinton     }
18816609Ssam     return found;
1899663Slinton }
1909663Slinton 
1919663Slinton /*
1929663Slinton  * Translate an event into the appropriate breakpoints and actions.
1939663Slinton  * While we're at it, turn on the breakpoints if the condition is true.
1949663Slinton  */
1959663Slinton 
1969663Slinton private translate(e)
1979663Slinton Event e;
1989663Slinton {
1999663Slinton     Breakpoint bp;
2009663Slinton     Symbol s;
2019663Slinton     Node place;
2029663Slinton     Lineno line;
2039663Slinton     Address addr;
2049663Slinton 
2059663Slinton     checkref(e->condition);
2069663Slinton     switch (e->condition->op) {
2079663Slinton 	case O_EQ:
2089663Slinton 	    if (e->condition->value.arg[0]->op == O_SYM) {
2099663Slinton 		s = e->condition->value.arg[0]->value.sym;
2109663Slinton 		place = e->condition->value.arg[1];
2119663Slinton 		if (s == linesym) {
2129663Slinton 		    if (place->op == O_QLINE) {
2139663Slinton 			line = place->value.arg[1]->value.lcon;
21416609Ssam 			addr = objaddr(line, place->value.arg[0]->value.scon);
2159663Slinton 		    } else {
2169663Slinton 			eval(place);
2179663Slinton 			line = pop(long);
2189663Slinton 			addr = objaddr(line, cursource);
2199663Slinton 		    }
2209663Slinton 		    if (addr == NOADDR) {
22116609Ssam 			if (not delevent(e->id)) {
22216609Ssam 			    printf("!! dbx.translate: can't undo event %d?\n",
22316609Ssam 				e->id);
22416609Ssam 			}
2259663Slinton 			beginerrmsg();
2269663Slinton 			fprintf(stderr, "no executable code at line ");
2279663Slinton 			prtree(stderr, place);
2289663Slinton 			enderrmsg();
2299663Slinton 		    }
2309663Slinton 		    bp = bp_alloc(e, addr, line, e->actions);
2319663Slinton 		} else if (s == procsym) {
2329663Slinton 		    eval(place);
2339663Slinton 		    s = pop(Symbol);
2349663Slinton 		    bp = bp_alloc(e, codeloc(s), 0, e->actions);
2359663Slinton 		    if (isactive(s) and pc != codeloc(program)) {
2369663Slinton 			evalcmdlist(e->actions);
2379663Slinton 		    }
2389663Slinton 		} else if (s == pcsym) {
2399663Slinton 		    eval(place);
2409663Slinton 		    bp = bp_alloc(e, pop(Address), 0, e->actions);
2419663Slinton 		} else {
2429663Slinton 		    condbp(e);
2439663Slinton 		}
2449663Slinton 	    } else {
2459663Slinton 		condbp(e);
2469663Slinton 	    }
2479663Slinton 	    break;
2489663Slinton 
2499663Slinton 	/*
2509663Slinton 	 * These should be handled specially.
2519663Slinton 	 * But for now I'm ignoring the problem.
2529663Slinton 	 */
2539663Slinton 	case O_AND:
2549663Slinton 	case O_OR:
2559663Slinton 	default:
2569663Slinton 	    condbp(e);
2579663Slinton 	    break;
2589663Slinton     }
2599663Slinton }
2609663Slinton 
2619663Slinton /*
2629663Slinton  * Create a breakpoint for a condition that cannot be pinpointed
2639663Slinton  * to happening at a particular address, but one for which we
2649663Slinton  * must single step and check the condition after each statement.
2659663Slinton  */
2669663Slinton 
2679663Slinton private condbp(e)
2689663Slinton Event e;
2699663Slinton {
2709663Slinton     Symbol p;
2719663Slinton     Breakpoint bp;
2729663Slinton     Cmdlist actions;
2739663Slinton 
2749663Slinton     p = tcontainer(e->condition);
2759663Slinton     if (p == nil) {
2769663Slinton 	p = program;
2779663Slinton     }
2789663Slinton     actions = buildcmdlist(build(O_IF, e->condition, e->actions));
2799663Slinton     actions = buildcmdlist(build(O_TRACEON, false, actions));
2809663Slinton     bp = bp_alloc(e, codeloc(p), 0, actions);
2819663Slinton }
2829663Slinton 
2839663Slinton /*
2849663Slinton  * Determine the deepest nested subprogram that still contains
2859663Slinton  * all elements in the given expression.
2869663Slinton  */
2879663Slinton 
2889663Slinton public Symbol tcontainer(exp)
2899663Slinton Node exp;
2909663Slinton {
2919663Slinton     Integer i;
2929663Slinton     Symbol s, t, u, v;
2939663Slinton 
2949663Slinton     checkref(exp);
2959663Slinton     s = nil;
2969663Slinton     if (exp->op == O_SYM) {
2979663Slinton 	s = container(exp->value.sym);
2989663Slinton     } else if (not isleaf(exp->op)) {
2999663Slinton 	for (i = 0; i < nargs(exp->op); i++) {
3009663Slinton 	    t = tcontainer(exp->value.arg[i]);
3019663Slinton 	    if (t != nil) {
3029663Slinton 		if (s == nil) {
3039663Slinton 		    s = t;
3049663Slinton 		} else {
3059663Slinton 		    u = s;
3069663Slinton 		    v = t;
3079663Slinton 		    while (u != v and u != nil) {
3089663Slinton 			u = container(u);
3099663Slinton 			v = container(v);
3109663Slinton 		    }
3119663Slinton 		    if (u == nil) {
3129663Slinton 			panic("bad ancestry for \"%s\"", symname(s));
3139663Slinton 		    } else {
3149663Slinton 			s = u;
3159663Slinton 		    }
3169663Slinton 		}
3179663Slinton 	    }
3189663Slinton 	}
3199663Slinton     }
3209663Slinton     return s;
3219663Slinton }
3229663Slinton 
3239663Slinton /*
32411869Slinton  * Determine if the given function can be executed at full speed.
32511869Slinton  * This can only be done if there are no breakpoints within the function.
32611869Slinton  */
32711869Slinton 
328*18218Slinton public boolean canskip(f)
32911869Slinton Symbol f;
33011869Slinton {
33111869Slinton     Breakpoint p;
332*18218Slinton     boolean ok;
33311869Slinton 
33411869Slinton     ok = true;
33511869Slinton     foreach (Breakpoint, p, bplist)
33611869Slinton 	if (whatblock(p->bpaddr) == f) {
33711869Slinton 	    ok = false;
33811869Slinton 	    break;
33911869Slinton 	}
34011869Slinton     endfor
34111869Slinton     return ok;
34211869Slinton }
34311869Slinton 
34411869Slinton /*
3459663Slinton  * Print out what's currently being traced by looking at
3469663Slinton  * the currently active events.
3479663Slinton  *
3489663Slinton  * Some convolution here to translate internal representation
3499663Slinton  * of events back into something more palatable.
3509663Slinton  */
3519663Slinton 
3529663Slinton public status()
3539663Slinton {
3549663Slinton     Event e;
3559663Slinton 
3569663Slinton     foreach (Event, e, eventlist)
3579663Slinton 	if (not e->temporary) {
35811869Slinton 	    printevent(e);
3599663Slinton 	}
3609663Slinton     endfor
3619663Slinton }
3629663Slinton 
36311869Slinton public printevent(e)
36411869Slinton Event e;
36511869Slinton {
36611869Slinton     Command cmd;
36711869Slinton 
36811869Slinton     if (not isredirected()) {
36916609Ssam 	printeventid(e->id);
37011869Slinton     }
37111869Slinton     cmd = list_element(Command, list_head(e->actions));
37211869Slinton     if (cmd->op == O_PRINTCALL) {
37311869Slinton 	printf("trace ");
37411869Slinton 	printname(stdout, cmd->value.sym);
37511869Slinton     } else {
37611869Slinton 	if (list_size(e->actions) > 1) {
37711869Slinton 	    printf("{ ");
37811869Slinton 	}
37911869Slinton 	foreach (Command, cmd, e->actions)
38011869Slinton 	    printcmd(stdout, cmd);
38111869Slinton 	    if (not list_islast()) {
38211869Slinton 		printf("; ");
38311869Slinton 	    }
38411869Slinton 	endfor
38511869Slinton 	if (list_size(e->actions) > 1) {
38611869Slinton 	    printf(" }");
38711869Slinton 	}
38811869Slinton 	printcond(e->condition);
38911869Slinton     }
39011869Slinton     printf("\n");
39111869Slinton }
39211869Slinton 
39316609Ssam private printeventid (id)
39416609Ssam integer id;
39516609Ssam {
39616609Ssam     printf("[%d] ", id);
39716609Ssam }
39816609Ssam 
3999663Slinton /*
4009663Slinton  * Print out a condition.
4019663Slinton  */
4029663Slinton 
4039663Slinton private printcond(cond)
4049663Slinton Node cond;
4059663Slinton {
4069663Slinton     Symbol s;
4079663Slinton     Node place;
4089663Slinton 
4099663Slinton     if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) {
4109663Slinton 	s = cond->value.arg[0]->value.sym;
4119663Slinton 	place = cond->value.arg[1];
4129663Slinton 	if (s == procsym) {
4139663Slinton 	    if (place->value.sym != program) {
4149663Slinton 		printf(" in ");
4159663Slinton 		printname(stdout, place->value.sym);
4169663Slinton 	    }
4179663Slinton 	} else if (s == linesym) {
4189663Slinton 	    printf(" at ");
4199663Slinton 	    prtree(stdout, place);
4209663Slinton 	} else if (s == pcsym or s == retaddrsym) {
4219663Slinton 	    printf("i at ");
4229663Slinton 	    prtree(stdout, place);
4239663Slinton 	} else {
4249663Slinton 	    printf(" when ");
4259663Slinton 	    prtree(stdout, cond);
4269663Slinton 	}
4279663Slinton     } else {
4289663Slinton 	printf(" when ");
4299663Slinton 	prtree(stdout, cond);
4309663Slinton     }
4319663Slinton }
4329663Slinton 
4339663Slinton /*
4349663Slinton  * Add a breakpoint to the list and return it.
4359663Slinton  */
4369663Slinton 
4379663Slinton private Breakpoint bp_alloc(e, addr, line, actions)
4389663Slinton Event e;
4399663Slinton Address addr;
4409663Slinton Lineno line;
4419663Slinton Cmdlist actions;
4429663Slinton {
4439663Slinton     register Breakpoint p;
4449663Slinton 
4459663Slinton     p = new(Breakpoint);
4469663Slinton     p->event = e;
4479663Slinton     p->bpaddr = addr;
4489663Slinton     p->bpline = line;
4499663Slinton     p->actions = actions;
450*18218Slinton     p->temporary = false;
451*18218Slinton     if (tracebpts) {
452*18218Slinton 	if (e == nil) {
453*18218Slinton 	    printf("new bp at 0x%x for event ??\n", addr, e->id);
454*18218Slinton 	} else {
455*18218Slinton 	    printf("new bp at 0x%x for event %d\n", addr, e->id);
456*18218Slinton 	}
457*18218Slinton 	fflush(stdout);
458*18218Slinton     }
4599663Slinton     bplist_append(p, bplist);
4609663Slinton     return p;
4619663Slinton }
4629663Slinton 
4639663Slinton /*
4649663Slinton  * Free all storage in the event and breakpoint tables.
4659663Slinton  */
4669663Slinton 
4679663Slinton public bpfree()
4689663Slinton {
4699663Slinton     register Event e;
4709663Slinton 
4719663Slinton     fixbps();
4729663Slinton     foreach (Event, e, eventlist)
47316609Ssam 	if (not delevent(e->id)) {
47416609Ssam 	    printf("!! dbx.bpfree: can't delete event %d\n", e->id);
47516609Ssam 	}
4769663Slinton 	list_delete(list_curitem(eventlist), eventlist);
4779663Slinton     endfor
4789663Slinton }
4799663Slinton 
4809663Slinton /*
4819663Slinton  * Determine if the program stopped at a known breakpoint
4829663Slinton  * and if so do the associated commands.
4839663Slinton  */
4849663Slinton 
485*18218Slinton public boolean bpact()
4869663Slinton {
4879663Slinton     register Breakpoint p;
488*18218Slinton     boolean found;
48916609Ssam     integer eventId;
4909663Slinton 
4919663Slinton     found = false;
4929663Slinton     foreach (Breakpoint, p, bplist)
4939663Slinton 	if (p->bpaddr == pc) {
494*18218Slinton 	    if (tracebpts) {
495*18218Slinton 		printf("breakpoint for event %d found at location 0x%x\n",
496*18218Slinton 		    p->event->id, pc);
497*18218Slinton 	    }
4989663Slinton 	    found = true;
499*18218Slinton 	    if (p->event->temporary) {
500*18218Slinton 		if (not delevent(p->event->id)) {
501*18218Slinton 		    printf("!! dbx.bpact: can't find event %d\n",
502*18218Slinton 			p->event->id);
503*18218Slinton 		}
504*18218Slinton 	    }
5059663Slinton 	    evalcmdlist(p->actions);
506*18218Slinton 	    if (isstopped) {
507*18218Slinton 		eventId = p->event->id;
508*18218Slinton 	    }
509*18218Slinton 	    if (p->temporary) {
510*18218Slinton 		list_delete(list_curitem(bplist), bplist);
511*18218Slinton 	    }
5129663Slinton 	}
5139663Slinton     endfor
5149663Slinton     if (isstopped) {
51516609Ssam 	if (found) {
51616609Ssam 	    printeventid(eventId);
51716609Ssam 	}
5189663Slinton 	printstatus();
5199663Slinton     }
5209663Slinton     fflush(stdout);
5219663Slinton     return found;
5229663Slinton }
5239663Slinton 
5249663Slinton /*
5259663Slinton  * Begin single stepping and executing the given commands after each step.
5269663Slinton  * If the first argument is true step by instructions, otherwise
5279663Slinton  * step by source lines.
5289663Slinton  *
5299663Slinton  * We automatically set a breakpoint at the end of the current procedure
5309663Slinton  * to turn off the given tracing.
5319663Slinton  */
5329663Slinton 
5339663Slinton public traceon(inst, event, cmdlist)
534*18218Slinton boolean inst;
5359663Slinton Event event;
5369663Slinton Cmdlist cmdlist;
5379663Slinton {
5389663Slinton     register Trcmd trcmd;
539*18218Slinton     Breakpoint bp;
5409663Slinton     Cmdlist actions;
54111869Slinton     Address ret;
542*18218Slinton     Event e;
5439663Slinton 
544*18218Slinton     if (event == nil) {
545*18218Slinton 	e = curevent;
546*18218Slinton     } else {
547*18218Slinton 	e = event;
548*18218Slinton     }
5499663Slinton     trcmd = new(Trcmd);
550*18218Slinton     ++trid;
551*18218Slinton     trcmd->trid = trid;
552*18218Slinton     trcmd->event = e;
5539663Slinton     trcmd->cmdlist = cmdlist;
5549663Slinton     single_stepping = true;
5559663Slinton     if (inst) {
5569663Slinton 	inst_tracing = true;
5579663Slinton 	list_append(list_item(trcmd), nil, eachinst);
5589663Slinton     } else {
5599663Slinton 	list_append(list_item(trcmd), nil, eachline);
5609663Slinton     }
56111869Slinton     ret = return_addr();
56211869Slinton     if (ret != 0) {
563*18218Slinton 	actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid));
564*18218Slinton 	bp = bp_alloc(e, (Address) ret, 0, actions);
565*18218Slinton 	bp->temporary = true;
56611869Slinton     }
567*18218Slinton     if (tracebpts) {
568*18218Slinton 	printf("adding trace %d for event %d\n", trcmd->trid, e->id);
569*18218Slinton     }
5709663Slinton }
5719663Slinton 
5729663Slinton /*
5739663Slinton  * Turn off some kind of tracing.
5749663Slinton  * Strictly an internal command, this cannot be invoked by the user.
5759663Slinton  */
5769663Slinton 
5779663Slinton public traceoff(id)
5789663Slinton Integer id;
5799663Slinton {
5809663Slinton     register Trcmd t;
581*18218Slinton     register boolean found;
5829663Slinton 
5839663Slinton     found = false;
5849663Slinton     foreach (Trcmd, t, eachline)
5859663Slinton 	if (t->trid == id) {
5869663Slinton 	    printrmtr(t);
5879663Slinton 	    list_delete(list_curitem(eachline), eachline);
5889663Slinton 	    found = true;
5899663Slinton 	    break;
5909663Slinton 	}
5919663Slinton     endfor
5929663Slinton     if (not found) {
5939663Slinton 	foreach (Trcmd, t, eachinst)
5949663Slinton 	    if (t->event->id == id) {
5959663Slinton 		printrmtr(t);
5969663Slinton 		list_delete(list_curitem(eachinst), eachinst);
5979663Slinton 		found = true;
5989663Slinton 		break;
5999663Slinton 	    }
6009663Slinton 	endfor
6019663Slinton 	if (not found) {
602*18218Slinton 	    beginerrmsg();
603*18218Slinton 	    fprintf(stderr, "[internal error: trace id %d not found]\n", id);
6049663Slinton 	}
6059663Slinton     }
6069663Slinton     if (list_size(eachinst) == 0) {
6079663Slinton 	inst_tracing = false;
6089663Slinton 	if (list_size(eachline) == 0) {
6099663Slinton 	    single_stepping = false;
6109663Slinton 	}
6119663Slinton     }
6129663Slinton }
6139663Slinton 
6149663Slinton /*
6159663Slinton  * If breakpoints are being traced, note that a Trcmd is being deleted.
6169663Slinton  */
6179663Slinton 
6189663Slinton private printrmtr(t)
6199663Slinton Trcmd t;
6209663Slinton {
621*18218Slinton     if (tracebpts) {
622*18218Slinton 	printf("removing trace %d", t->trid);
623*18218Slinton 	if (t->event != nil) {
624*18218Slinton 	    printf(" for event %d", t->event->id);
625*18218Slinton 	}
626*18218Slinton 	printf("\n");
6279663Slinton     }
6289663Slinton }
6299663Slinton 
6309663Slinton /*
6319663Slinton  * Print out news during single step tracing.
6329663Slinton  */
6339663Slinton 
6349663Slinton public printnews()
6359663Slinton {
6369663Slinton     register Trcmd t;
6379663Slinton 
6389663Slinton     foreach (Trcmd, t, eachline)
6399663Slinton 	evalcmdlist(t->cmdlist);
6409663Slinton     endfor
6419663Slinton     foreach (Trcmd, t, eachinst)
6429663Slinton 	evalcmdlist(t->cmdlist);
6439663Slinton     endfor
6449663Slinton     bpact();
6459663Slinton }
6469663Slinton 
6479663Slinton /*
6489663Slinton  * A procedure call/return has occurred while single-stepping,
6499663Slinton  * note it if we're tracing lines.
6509663Slinton  */
6519663Slinton 
652*18218Slinton private boolean chklist();
6539663Slinton 
6549663Slinton public callnews(iscall)
655*18218Slinton boolean iscall;
6569663Slinton {
6579663Slinton     if (not chklist(eachline, iscall)) {
6589663Slinton 	chklist(eachinst, iscall);
6599663Slinton     }
6609663Slinton }
6619663Slinton 
662*18218Slinton private boolean chklist(list, iscall)
6639663Slinton List list;
664*18218Slinton boolean iscall;
6659663Slinton {
6669663Slinton     register Trcmd t;
6679663Slinton     register Command cmd;
6689663Slinton 
66916609Ssam     setcurfunc(whatblock(pc));
6709663Slinton     foreach (Trcmd, t, list)
6719663Slinton 	foreach (Command, cmd, t->cmdlist)
6729663Slinton 	    if (cmd->op == O_PRINTSRCPOS and
6739663Slinton 	      (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) {
6749663Slinton 		if (iscall) {
6759663Slinton 		    printentry(curfunc);
6769663Slinton 		} else {
6779663Slinton 		    printexit(curfunc);
6789663Slinton 		}
6799663Slinton 		return true;
6809663Slinton 	    }
6819663Slinton 	endfor
6829663Slinton     endfor
6839663Slinton     return false;
6849663Slinton }
6859663Slinton 
6869663Slinton /*
6879663Slinton  * When tracing variables we keep a copy of their most recent value
6889663Slinton  * and compare it to the current one each time a breakpoint occurs.
6899663Slinton  * MAXTRSIZE is the maximum size variable we allow.
6909663Slinton  */
6919663Slinton 
6929663Slinton #define MAXTRSIZE 512
6939663Slinton 
6949663Slinton /*
6959663Slinton  * List of variables being watched.
6969663Slinton  */
6979663Slinton 
6989663Slinton typedef struct Trinfo *Trinfo;
6999663Slinton 
7009663Slinton struct Trinfo {
7019663Slinton     Node variable;
7029663Slinton     Address traddr;
7039663Slinton     Symbol trblock;
7049663Slinton     char *trvalue;
7059663Slinton };
7069663Slinton 
7079663Slinton private List trinfolist;
7089663Slinton 
7099663Slinton /*
7109663Slinton  * Find the trace information record associated with the given record.
7119663Slinton  * If there isn't one then create it and add it to the list.
7129663Slinton  */
7139663Slinton 
7149663Slinton private Trinfo findtrinfo(p)
7159663Slinton Node p;
7169663Slinton {
7179663Slinton     register Trinfo tp;
718*18218Slinton     boolean isnew;
7199663Slinton 
7209663Slinton     isnew = true;
7219663Slinton     if (trinfolist == nil) {
7229663Slinton 	trinfolist = list_alloc();
7239663Slinton     } else {
7249663Slinton 	foreach (Trinfo, tp, trinfolist)
7259663Slinton 	    if (tp->variable == p) {
7269663Slinton 		isnew = false;
7279663Slinton 		break;
7289663Slinton 	    }
7299663Slinton 	endfor
7309663Slinton     }
7319663Slinton     if (isnew) {
7329663Slinton 	if (tracebpts) {
7339663Slinton 	    printf("adding trinfo for \"");
7349663Slinton 	    prtree(stdout, p);
7359663Slinton 	    printf("\"\n");
7369663Slinton 	}
7379663Slinton 	tp = new(Trinfo);
7389663Slinton 	tp->variable = p;
7399663Slinton 	tp->traddr = lval(p);
7409663Slinton 	tp->trvalue = nil;
7419663Slinton 	list_append(list_item(tp), nil, trinfolist);
7429663Slinton     }
7439663Slinton     return tp;
7449663Slinton }
7459663Slinton 
7469663Slinton /*
7479663Slinton  * Print out the value of a variable if it has changed since the
7489663Slinton  * last time we checked.
7499663Slinton  */
7509663Slinton 
7519663Slinton public printifchanged(p)
7529663Slinton Node p;
7539663Slinton {
7549663Slinton     register Trinfo tp;
7559663Slinton     register int n;
7569663Slinton     char buff[MAXTRSIZE];
757*18218Slinton     Filename curfile;
7589663Slinton     static Lineno prevline;
759*18218Slinton     static Filename prevfile;
7609663Slinton 
7619663Slinton     tp = findtrinfo(p);
7629663Slinton     n = size(p->nodetype);
763*18218Slinton     dread(buff, tp->traddr, n);
764*18218Slinton     curfile = srcfilename(pc);
7659663Slinton     if (tp->trvalue == nil) {
7669663Slinton 	tp->trvalue = newarr(char, n);
7679663Slinton 	mov(buff, tp->trvalue, n);
7689663Slinton 	mov(buff, sp, n);
7699663Slinton 	sp += n;
770*18218Slinton 	printf("initially (at line %d in \"%s\"):\t", curline, curfile);
7719663Slinton 	prtree(stdout, p);
7729663Slinton 	printf(" = ");
7739663Slinton 	printval(p->nodetype);
7749663Slinton 	putchar('\n');
7759663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
7769663Slinton 	mov(buff, tp->trvalue, n);
7779663Slinton 	mov(buff, sp, n);
7789663Slinton 	sp += n;
779*18218Slinton 	printf("after line %d in \"%s\":\t", prevline, prevfile);
7809663Slinton 	prtree(stdout, p);
7819663Slinton 	printf(" = ");
7829663Slinton 	printval(p->nodetype);
7839663Slinton 	putchar('\n');
7849663Slinton     }
7859663Slinton     prevline = curline;
786*18218Slinton     prevfile = curfile;
7879663Slinton }
7889663Slinton 
7899663Slinton /*
7909663Slinton  * Stop if the value of the given expression has changed.
7919663Slinton  */
7929663Slinton 
7939663Slinton public stopifchanged(p)
7949663Slinton Node p;
7959663Slinton {
7969663Slinton     register Trinfo tp;
7979663Slinton     register int n;
7989663Slinton     char buff[MAXTRSIZE];
7999663Slinton     static Lineno prevline;
8009663Slinton 
8019663Slinton     tp = findtrinfo(p);
8029663Slinton     n = size(p->nodetype);
8039663Slinton     dread(buff, tp->traddr, n);
8049663Slinton     if (tp->trvalue == nil) {
8059663Slinton 	tp->trvalue = newarr(char, n);
8069663Slinton 	mov(buff, tp->trvalue, n);
8079663Slinton 	isstopped = true;
8089663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
8099663Slinton 	mov(buff, tp->trvalue, n);
81016609Ssam 	mov(buff, sp, n);
81116609Ssam 	sp += n;
81216609Ssam 	printf("after line %d:\t", prevline);
81316609Ssam 	prtree(stdout, p);
81416609Ssam 	printf(" = ");
81516609Ssam 	printval(p->nodetype);
81616609Ssam 	putchar('\n');
8179663Slinton 	isstopped = true;
8189663Slinton     }
8199663Slinton     prevline = curline;
8209663Slinton }
8219663Slinton 
8229663Slinton /*
8239663Slinton  * Free the tracing table.
8249663Slinton  */
8259663Slinton 
8269663Slinton public trfree()
8279663Slinton {
8289663Slinton     register Trinfo tp;
8299663Slinton 
8309663Slinton     foreach (Trinfo, tp, trinfolist)
8319663Slinton 	dispose(tp->trvalue);
8329663Slinton 	dispose(tp);
8339663Slinton 	list_delete(list_curitem(trinfolist), trinfolist);
8349663Slinton     endfor
8359663Slinton }
8369663Slinton 
8379663Slinton /*
8389663Slinton  * Fix up breakpoint information before continuing execution.
8399663Slinton  *
8409663Slinton  * It's necessary to destroy events and breakpoints that were created
8419663Slinton  * temporarily and still exist because the program terminated abnormally.
8429663Slinton  */
8439663Slinton 
8449663Slinton public fixbps()
8459663Slinton {
8469663Slinton     register Event e;
8479663Slinton     register Trcmd t;
8489663Slinton 
8499663Slinton     single_stepping = false;
8509663Slinton     inst_tracing = false;
8519663Slinton     trfree();
8529663Slinton     foreach (Event, e, eventlist)
8539663Slinton 	if (e->temporary) {
85416609Ssam 	    if (not delevent(e->id)) {
85516609Ssam 		printf("!! dbx.fixbps: can't find event %d\n", e->id);
85616609Ssam 	    }
8579663Slinton 	}
8589663Slinton     endfor
8599663Slinton     foreach (Trcmd, t, eachline)
8609663Slinton 	printrmtr(t);
8619663Slinton 	list_delete(list_curitem(eachline), eachline);
8629663Slinton     endfor
8639663Slinton     foreach (Trcmd, t, eachinst)
8649663Slinton 	printrmtr(t);
8659663Slinton 	list_delete(list_curitem(eachinst), eachinst);
8669663Slinton     endfor
8679663Slinton }
8689663Slinton 
8699663Slinton /*
8709663Slinton  * Set all breakpoints in object code.
8719663Slinton  */
8729663Slinton 
8739663Slinton public setallbps()
8749663Slinton {
8759663Slinton     register Breakpoint p;
8769663Slinton 
8779663Slinton     foreach (Breakpoint, p, bplist)
8789663Slinton 	setbp(p->bpaddr);
8799663Slinton     endfor
8809663Slinton }
8819663Slinton 
8829663Slinton /*
8839663Slinton  * Undo damage done by "setallbps".
8849663Slinton  */
8859663Slinton 
8869663Slinton public unsetallbps()
8879663Slinton {
8889663Slinton     register Breakpoint p;
8899663Slinton 
8909663Slinton     foreach (Breakpoint, p, bplist)
8919663Slinton 	unsetbp(p->bpaddr);
8929663Slinton     endfor
8939663Slinton }
894