xref: /csrg-svn/old/dbx/events.c (revision 42683)
121602Sdist /*
238105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42683Sbostic  * %sccs.include.redist.c%
621602Sdist  */
79663Slinton 
821602Sdist #ifndef lint
9*42683Sbostic static char sccsid[] = "@(#)events.c	5.5 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
119663Slinton 
129663Slinton /*
139663Slinton  * Event/breakpoint managment.
149663Slinton  */
159663Slinton 
169663Slinton #include "defs.h"
179663Slinton #include "events.h"
189663Slinton #include "main.h"
199663Slinton #include "symbols.h"
209663Slinton #include "tree.h"
219663Slinton #include "eval.h"
229663Slinton #include "source.h"
239663Slinton #include "mappings.h"
2416609Ssam #include "runtime.h"
259663Slinton #include "process.h"
269663Slinton #include "machine.h"
279663Slinton #include "lists.h"
289663Slinton 
299663Slinton #ifndef public
3033316Sdonn 
319663Slinton typedef struct Event *Event;
329663Slinton typedef struct Breakpoint *Breakpoint;
339663Slinton 
349663Slinton #include "symbols.h"
359663Slinton 
369663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist)
379663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist)
389663Slinton 
3933316Sdonn /*
4033316Sdonn  * When tracing variables we keep a copy of their most recent value
4133316Sdonn  * and compare it to the current one each time a breakpoint occurs.
4233316Sdonn  * MAXTRSIZE is the maximum size variable we allow.
4333316Sdonn  */
4433316Sdonn 
4533316Sdonn #define MAXTRSIZE 512
4633316Sdonn 
479663Slinton #endif
489663Slinton 
4933316Sdonn public boolean inst_tracing;
5033316Sdonn public boolean single_stepping;
5133316Sdonn public boolean isstopped;
5233316Sdonn 
5333316Sdonn public Symbol linesym;
5433316Sdonn public Symbol procsym;
5533316Sdonn public Symbol pcsym;
5633316Sdonn public Symbol retaddrsym;
5733316Sdonn 
589663Slinton struct Event {
599663Slinton     unsigned int id;
6018218Slinton     boolean temporary;
619663Slinton     Node condition;
629663Slinton     Cmdlist actions;
639663Slinton };
649663Slinton 
659663Slinton struct Breakpoint {
669663Slinton     Event event;
679663Slinton     Address bpaddr;
689663Slinton     Lineno bpline;
699663Slinton     Cmdlist actions;
7018218Slinton     boolean temporary;
719663Slinton };
729663Slinton 
739663Slinton typedef List Eventlist;
749663Slinton typedef List Bplist;
759663Slinton 
769663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el)
779663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)
789663Slinton 
799663Slinton private Eventlist eventlist;		/* list of active events */
809663Slinton private Bplist bplist;			/* list of active breakpoints */
8118218Slinton private Event curevent;			/* most recently created event */
8218218Slinton private integer eventid;		/* id number of current event */
8318218Slinton private integer trid;			/* id number of current trace */
849663Slinton 
859663Slinton typedef struct Trcmd {
869663Slinton     Integer trid;
879663Slinton     Event event;
889663Slinton     Cmdlist cmdlist;
899663Slinton } *Trcmd;
909663Slinton 
919663Slinton private List eachline;		/* commands to execute after each line */
929663Slinton private List eachinst;		/* commands to execute after each instruction */
939663Slinton 
949663Slinton private Breakpoint bp_alloc();
959663Slinton 
969663Slinton /*
979663Slinton  * Initialize breakpoint information.
989663Slinton  */
999663Slinton 
builtinsym(str,class,type)1009663Slinton private Symbol builtinsym(str, class, type)
1019663Slinton String str;
1029663Slinton Symclass class;
1039663Slinton Symbol type;
1049663Slinton {
1059663Slinton     Symbol s;
1069663Slinton 
1079663Slinton     s = insert(identname(str, true));
1089663Slinton     s->language = findlanguage(".s");
1099663Slinton     s->class = class;
1109663Slinton     s->type = type;
1119663Slinton     return s;
1129663Slinton }
1139663Slinton 
bpinit()1149663Slinton public bpinit()
1159663Slinton {
1169663Slinton     linesym = builtinsym("$line", VAR, t_int);
1179663Slinton     procsym = builtinsym("$proc", PROC, nil);
1189663Slinton     pcsym = lookup(identname("$pc", true));
1199663Slinton     if (pcsym == nil) {
1209663Slinton 	panic("can't find $pc");
1219663Slinton     }
1229663Slinton     retaddrsym = builtinsym("$retaddr", VAR, t_int);
1239663Slinton     eventlist = list_alloc();
1249663Slinton     bplist = list_alloc();
1259663Slinton     eachline = list_alloc();
1269663Slinton     eachinst = list_alloc();
1279663Slinton }
1289663Slinton 
1299663Slinton /*
1309663Slinton  * Trap an event and do the associated commands when it occurs.
1319663Slinton  */
1329663Slinton 
event_alloc(istmp,econd,cmdlist)1339663Slinton public Event event_alloc(istmp, econd, cmdlist)
13418218Slinton boolean istmp;
1359663Slinton Node econd;
1369663Slinton Cmdlist cmdlist;
1379663Slinton {
1389663Slinton     register Event e;
1399663Slinton 
1409663Slinton     e = new(Event);
14118218Slinton     ++eventid;
14218218Slinton     e->id = eventid;
1439663Slinton     e->temporary = istmp;
1449663Slinton     e->condition = econd;
1459663Slinton     e->actions = cmdlist;
1469663Slinton     eventlist_append(e, eventlist);
14718218Slinton     curevent = e;
1489663Slinton     translate(e);
1499663Slinton     return e;
1509663Slinton }
1519663Slinton 
1529663Slinton /*
1539663Slinton  * Delete the event with the given id.
15416609Ssam  * Returns whether it's successful or not.
1559663Slinton  */
1569663Slinton 
delevent(id)15716609Ssam public boolean delevent (id)
1589663Slinton unsigned int id;
1599663Slinton {
1609663Slinton     Event e;
1619663Slinton     Breakpoint bp;
1629663Slinton     Trcmd t;
16316609Ssam     boolean found;
1649663Slinton 
16516609Ssam     found = false;
1669663Slinton     foreach (Event, e, eventlist)
1679663Slinton 	if (e->id == id) {
16816609Ssam 	    found = true;
1699663Slinton 	    foreach (Breakpoint, bp, bplist)
1709663Slinton 		if (bp->event == e) {
17118218Slinton 		    if (tracebpts) {
17218218Slinton 			printf("deleting breakpoint at 0x%x\n", bp->bpaddr);
17318218Slinton 			fflush(stdout);
17418218Slinton 		    }
1759663Slinton 		    list_delete(list_curitem(bplist), bplist);
1769663Slinton 		}
1779663Slinton 	    endfor
17816609Ssam 	    list_delete(list_curitem(eventlist), eventlist);
1799663Slinton 	    break;
1809663Slinton 	}
1819663Slinton     endfor
1829663Slinton     foreach (Trcmd, t, eachline)
1839663Slinton 	if (t->event->id == id) {
18416609Ssam 	    found = true;
1859663Slinton 	    printrmtr(t);
1869663Slinton 	    list_delete(list_curitem(eachline), eachline);
1879663Slinton 	}
1889663Slinton     endfor
1899663Slinton     foreach (Trcmd, t, eachinst)
1909663Slinton 	if (t->event->id == id) {
19116609Ssam 	    found = true;
1929663Slinton 	    printrmtr(t);
1939663Slinton 	    list_delete(list_curitem(eachinst), eachinst);
1949663Slinton 	}
1959663Slinton     endfor
1969663Slinton     if (list_size(eachinst) == 0) {
1979663Slinton 	inst_tracing = false;
1989663Slinton 	if (list_size(eachline) == 0) {
1999663Slinton 	    single_stepping = false;
2009663Slinton 	}
2019663Slinton     }
20216609Ssam     return found;
2039663Slinton }
2049663Slinton 
2059663Slinton /*
2069663Slinton  * Translate an event into the appropriate breakpoints and actions.
2079663Slinton  * While we're at it, turn on the breakpoints if the condition is true.
2089663Slinton  */
2099663Slinton 
translate(e)2109663Slinton private translate(e)
2119663Slinton Event e;
2129663Slinton {
2139663Slinton     Breakpoint bp;
2149663Slinton     Symbol s;
2159663Slinton     Node place;
2169663Slinton     Lineno line;
2179663Slinton     Address addr;
2189663Slinton 
2199663Slinton     checkref(e->condition);
2209663Slinton     switch (e->condition->op) {
2219663Slinton 	case O_EQ:
2229663Slinton 	    if (e->condition->value.arg[0]->op == O_SYM) {
2239663Slinton 		s = e->condition->value.arg[0]->value.sym;
2249663Slinton 		place = e->condition->value.arg[1];
2259663Slinton 		if (s == linesym) {
2269663Slinton 		    if (place->op == O_QLINE) {
2279663Slinton 			line = place->value.arg[1]->value.lcon;
22816609Ssam 			addr = objaddr(line, place->value.arg[0]->value.scon);
2299663Slinton 		    } else {
2309663Slinton 			eval(place);
2319663Slinton 			line = pop(long);
2329663Slinton 			addr = objaddr(line, cursource);
2339663Slinton 		    }
2349663Slinton 		    if (addr == NOADDR) {
23516609Ssam 			if (not delevent(e->id)) {
23616609Ssam 			    printf("!! dbx.translate: can't undo event %d?\n",
23716609Ssam 				e->id);
23816609Ssam 			}
2399663Slinton 			beginerrmsg();
2409663Slinton 			fprintf(stderr, "no executable code at line ");
2419663Slinton 			prtree(stderr, place);
2429663Slinton 			enderrmsg();
2439663Slinton 		    }
2449663Slinton 		    bp = bp_alloc(e, addr, line, e->actions);
2459663Slinton 		} else if (s == procsym) {
2469663Slinton 		    eval(place);
2479663Slinton 		    s = pop(Symbol);
2489663Slinton 		    bp = bp_alloc(e, codeloc(s), 0, e->actions);
2499663Slinton 		    if (isactive(s) and pc != codeloc(program)) {
2509663Slinton 			evalcmdlist(e->actions);
2519663Slinton 		    }
2529663Slinton 		} else if (s == pcsym) {
2539663Slinton 		    eval(place);
2549663Slinton 		    bp = bp_alloc(e, pop(Address), 0, e->actions);
2559663Slinton 		} else {
2569663Slinton 		    condbp(e);
2579663Slinton 		}
2589663Slinton 	    } else {
2599663Slinton 		condbp(e);
2609663Slinton 	    }
2619663Slinton 	    break;
2629663Slinton 
2639663Slinton 	/*
2649663Slinton 	 * These should be handled specially.
2659663Slinton 	 * But for now I'm ignoring the problem.
2669663Slinton 	 */
2679663Slinton 	case O_AND:
2689663Slinton 	case O_OR:
2699663Slinton 	default:
2709663Slinton 	    condbp(e);
2719663Slinton 	    break;
2729663Slinton     }
2739663Slinton }
2749663Slinton 
2759663Slinton /*
2769663Slinton  * Create a breakpoint for a condition that cannot be pinpointed
2779663Slinton  * to happening at a particular address, but one for which we
2789663Slinton  * must single step and check the condition after each statement.
2799663Slinton  */
2809663Slinton 
condbp(e)2819663Slinton private condbp(e)
2829663Slinton Event e;
2839663Slinton {
2849663Slinton     Symbol p;
2859663Slinton     Breakpoint bp;
2869663Slinton     Cmdlist actions;
2879663Slinton 
2889663Slinton     p = tcontainer(e->condition);
2899663Slinton     if (p == nil) {
2909663Slinton 	p = program;
2919663Slinton     }
2929663Slinton     actions = buildcmdlist(build(O_IF, e->condition, e->actions));
2939663Slinton     actions = buildcmdlist(build(O_TRACEON, false, actions));
2949663Slinton     bp = bp_alloc(e, codeloc(p), 0, actions);
2959663Slinton }
2969663Slinton 
2979663Slinton /*
2989663Slinton  * Determine the deepest nested subprogram that still contains
2999663Slinton  * all elements in the given expression.
3009663Slinton  */
3019663Slinton 
tcontainer(exp)3029663Slinton public Symbol tcontainer(exp)
3039663Slinton Node exp;
3049663Slinton {
3059663Slinton     Integer i;
3069663Slinton     Symbol s, t, u, v;
3079663Slinton 
3089663Slinton     checkref(exp);
3099663Slinton     s = nil;
3109663Slinton     if (exp->op == O_SYM) {
3119663Slinton 	s = container(exp->value.sym);
3129663Slinton     } else if (not isleaf(exp->op)) {
3139663Slinton 	for (i = 0; i < nargs(exp->op); i++) {
3149663Slinton 	    t = tcontainer(exp->value.arg[i]);
3159663Slinton 	    if (t != nil) {
3169663Slinton 		if (s == nil) {
3179663Slinton 		    s = t;
3189663Slinton 		} else {
3199663Slinton 		    u = s;
3209663Slinton 		    v = t;
3219663Slinton 		    while (u != v and u != nil) {
3229663Slinton 			u = container(u);
3239663Slinton 			v = container(v);
3249663Slinton 		    }
3259663Slinton 		    if (u == nil) {
3269663Slinton 			panic("bad ancestry for \"%s\"", symname(s));
3279663Slinton 		    } else {
3289663Slinton 			s = u;
3299663Slinton 		    }
3309663Slinton 		}
3319663Slinton 	    }
3329663Slinton 	}
3339663Slinton     }
3349663Slinton     return s;
3359663Slinton }
3369663Slinton 
3379663Slinton /*
33811869Slinton  * Determine if the given function can be executed at full speed.
33911869Slinton  * This can only be done if there are no breakpoints within the function.
34011869Slinton  */
34111869Slinton 
canskip(f)34218218Slinton public boolean canskip(f)
34311869Slinton Symbol f;
34411869Slinton {
34511869Slinton     Breakpoint p;
34618218Slinton     boolean ok;
34711869Slinton 
34811869Slinton     ok = true;
34911869Slinton     foreach (Breakpoint, p, bplist)
35011869Slinton 	if (whatblock(p->bpaddr) == f) {
35111869Slinton 	    ok = false;
35211869Slinton 	    break;
35311869Slinton 	}
35411869Slinton     endfor
35511869Slinton     return ok;
35611869Slinton }
35711869Slinton 
35811869Slinton /*
3599663Slinton  * Print out what's currently being traced by looking at
3609663Slinton  * the currently active events.
3619663Slinton  *
3629663Slinton  * Some convolution here to translate internal representation
3639663Slinton  * of events back into something more palatable.
3649663Slinton  */
3659663Slinton 
status()3669663Slinton public status()
3679663Slinton {
3689663Slinton     Event e;
3699663Slinton 
3709663Slinton     foreach (Event, e, eventlist)
3719663Slinton 	if (not e->temporary) {
37211869Slinton 	    printevent(e);
3739663Slinton 	}
3749663Slinton     endfor
3759663Slinton }
3769663Slinton 
printevent(e)37711869Slinton public printevent(e)
37811869Slinton Event e;
37911869Slinton {
38011869Slinton     Command cmd;
38111869Slinton 
38211869Slinton     if (not isredirected()) {
38316609Ssam 	printeventid(e->id);
38411869Slinton     }
38511869Slinton     cmd = list_element(Command, list_head(e->actions));
38611869Slinton     if (cmd->op == O_PRINTCALL) {
38711869Slinton 	printf("trace ");
38811869Slinton 	printname(stdout, cmd->value.sym);
38911869Slinton     } else {
39011869Slinton 	if (list_size(e->actions) > 1) {
39111869Slinton 	    printf("{ ");
39211869Slinton 	}
39311869Slinton 	foreach (Command, cmd, e->actions)
39411869Slinton 	    printcmd(stdout, cmd);
39511869Slinton 	    if (not list_islast()) {
39611869Slinton 		printf("; ");
39711869Slinton 	    }
39811869Slinton 	endfor
39911869Slinton 	if (list_size(e->actions) > 1) {
40011869Slinton 	    printf(" }");
40111869Slinton 	}
40211869Slinton 	printcond(e->condition);
40311869Slinton     }
40411869Slinton     printf("\n");
40511869Slinton }
40611869Slinton 
printeventid(id)40716609Ssam private printeventid (id)
40816609Ssam integer id;
40916609Ssam {
41016609Ssam     printf("[%d] ", id);
41116609Ssam }
41216609Ssam 
4139663Slinton /*
4149663Slinton  * Print out a condition.
4159663Slinton  */
4169663Slinton 
printcond(cond)4179663Slinton private printcond(cond)
4189663Slinton Node cond;
4199663Slinton {
4209663Slinton     Symbol s;
4219663Slinton     Node place;
4229663Slinton 
4239663Slinton     if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) {
4249663Slinton 	s = cond->value.arg[0]->value.sym;
4259663Slinton 	place = cond->value.arg[1];
4269663Slinton 	if (s == procsym) {
4279663Slinton 	    if (place->value.sym != program) {
4289663Slinton 		printf(" in ");
4299663Slinton 		printname(stdout, place->value.sym);
4309663Slinton 	    }
4319663Slinton 	} else if (s == linesym) {
4329663Slinton 	    printf(" at ");
4339663Slinton 	    prtree(stdout, place);
4349663Slinton 	} else if (s == pcsym or s == retaddrsym) {
4359663Slinton 	    printf("i at ");
4369663Slinton 	    prtree(stdout, place);
4379663Slinton 	} else {
4389663Slinton 	    printf(" when ");
4399663Slinton 	    prtree(stdout, cond);
4409663Slinton 	}
4419663Slinton     } else {
4429663Slinton 	printf(" when ");
4439663Slinton 	prtree(stdout, cond);
4449663Slinton     }
4459663Slinton }
4469663Slinton 
4479663Slinton /*
4489663Slinton  * Add a breakpoint to the list and return it.
4499663Slinton  */
4509663Slinton 
bp_alloc(e,addr,line,actions)4519663Slinton private Breakpoint bp_alloc(e, addr, line, actions)
4529663Slinton Event e;
4539663Slinton Address addr;
4549663Slinton Lineno line;
4559663Slinton Cmdlist actions;
4569663Slinton {
4579663Slinton     register Breakpoint p;
4589663Slinton 
4599663Slinton     p = new(Breakpoint);
4609663Slinton     p->event = e;
4619663Slinton     p->bpaddr = addr;
4629663Slinton     p->bpline = line;
4639663Slinton     p->actions = actions;
46418218Slinton     p->temporary = false;
46518218Slinton     if (tracebpts) {
46618218Slinton 	if (e == nil) {
46730796Sbostic 	    printf("new bp at 0x%x for event ??\n", addr);
46818218Slinton 	} else {
46918218Slinton 	    printf("new bp at 0x%x for event %d\n", addr, e->id);
47018218Slinton 	}
47118218Slinton 	fflush(stdout);
47218218Slinton     }
4739663Slinton     bplist_append(p, bplist);
4749663Slinton     return p;
4759663Slinton }
4769663Slinton 
4779663Slinton /*
4789663Slinton  * Free all storage in the event and breakpoint tables.
4799663Slinton  */
4809663Slinton 
bpfree()4819663Slinton public bpfree()
4829663Slinton {
4839663Slinton     register Event e;
4849663Slinton 
4859663Slinton     fixbps();
4869663Slinton     foreach (Event, e, eventlist)
48716609Ssam 	if (not delevent(e->id)) {
48816609Ssam 	    printf("!! dbx.bpfree: can't delete event %d\n", e->id);
48916609Ssam 	}
4909663Slinton 	list_delete(list_curitem(eventlist), eventlist);
4919663Slinton     endfor
4929663Slinton }
4939663Slinton 
4949663Slinton /*
4959663Slinton  * Determine if the program stopped at a known breakpoint
4969663Slinton  * and if so do the associated commands.
4979663Slinton  */
4989663Slinton 
bpact()49918218Slinton public boolean bpact()
5009663Slinton {
5019663Slinton     register Breakpoint p;
50218218Slinton     boolean found;
50316609Ssam     integer eventId;
5049663Slinton 
5059663Slinton     found = false;
5069663Slinton     foreach (Breakpoint, p, bplist)
5079663Slinton 	if (p->bpaddr == pc) {
50818218Slinton 	    if (tracebpts) {
50918218Slinton 		printf("breakpoint for event %d found at location 0x%x\n",
51018218Slinton 		    p->event->id, pc);
51118218Slinton 	    }
5129663Slinton 	    found = true;
51318218Slinton 	    if (p->event->temporary) {
51418218Slinton 		if (not delevent(p->event->id)) {
51518218Slinton 		    printf("!! dbx.bpact: can't find event %d\n",
51618218Slinton 			p->event->id);
51718218Slinton 		}
51818218Slinton 	    }
5199663Slinton 	    evalcmdlist(p->actions);
52018218Slinton 	    if (isstopped) {
52118218Slinton 		eventId = p->event->id;
52218218Slinton 	    }
52318218Slinton 	    if (p->temporary) {
52418218Slinton 		list_delete(list_curitem(bplist), bplist);
52518218Slinton 	    }
5269663Slinton 	}
5279663Slinton     endfor
5289663Slinton     if (isstopped) {
52916609Ssam 	if (found) {
53016609Ssam 	    printeventid(eventId);
53116609Ssam 	}
5329663Slinton 	printstatus();
5339663Slinton     }
5349663Slinton     fflush(stdout);
5359663Slinton     return found;
5369663Slinton }
5379663Slinton 
5389663Slinton /*
5399663Slinton  * Begin single stepping and executing the given commands after each step.
5409663Slinton  * If the first argument is true step by instructions, otherwise
5419663Slinton  * step by source lines.
5429663Slinton  *
5439663Slinton  * We automatically set a breakpoint at the end of the current procedure
5449663Slinton  * to turn off the given tracing.
5459663Slinton  */
5469663Slinton 
traceon(inst,event,cmdlist)5479663Slinton public traceon(inst, event, cmdlist)
54818218Slinton boolean inst;
5499663Slinton Event event;
5509663Slinton Cmdlist cmdlist;
5519663Slinton {
5529663Slinton     register Trcmd trcmd;
55318218Slinton     Breakpoint bp;
5549663Slinton     Cmdlist actions;
55511869Slinton     Address ret;
55618218Slinton     Event e;
5579663Slinton 
55818218Slinton     if (event == nil) {
55918218Slinton 	e = curevent;
56018218Slinton     } else {
56118218Slinton 	e = event;
56218218Slinton     }
5639663Slinton     trcmd = new(Trcmd);
56418218Slinton     ++trid;
56518218Slinton     trcmd->trid = trid;
56618218Slinton     trcmd->event = e;
5679663Slinton     trcmd->cmdlist = cmdlist;
5689663Slinton     single_stepping = true;
5699663Slinton     if (inst) {
5709663Slinton 	inst_tracing = true;
5719663Slinton 	list_append(list_item(trcmd), nil, eachinst);
5729663Slinton     } else {
5739663Slinton 	list_append(list_item(trcmd), nil, eachline);
5749663Slinton     }
57511869Slinton     ret = return_addr();
57611869Slinton     if (ret != 0) {
57718218Slinton 	actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid));
57818218Slinton 	bp = bp_alloc(e, (Address) ret, 0, actions);
57918218Slinton 	bp->temporary = true;
58011869Slinton     }
58118218Slinton     if (tracebpts) {
58218218Slinton 	printf("adding trace %d for event %d\n", trcmd->trid, e->id);
58318218Slinton     }
5849663Slinton }
5859663Slinton 
5869663Slinton /*
5879663Slinton  * Turn off some kind of tracing.
5889663Slinton  * Strictly an internal command, this cannot be invoked by the user.
5899663Slinton  */
5909663Slinton 
traceoff(id)5919663Slinton public traceoff(id)
5929663Slinton Integer id;
5939663Slinton {
5949663Slinton     register Trcmd t;
59518218Slinton     register boolean found;
5969663Slinton 
5979663Slinton     found = false;
5989663Slinton     foreach (Trcmd, t, eachline)
5999663Slinton 	if (t->trid == id) {
6009663Slinton 	    printrmtr(t);
6019663Slinton 	    list_delete(list_curitem(eachline), eachline);
6029663Slinton 	    found = true;
6039663Slinton 	    break;
6049663Slinton 	}
6059663Slinton     endfor
6069663Slinton     if (not found) {
6079663Slinton 	foreach (Trcmd, t, eachinst)
6089663Slinton 	    if (t->event->id == id) {
6099663Slinton 		printrmtr(t);
6109663Slinton 		list_delete(list_curitem(eachinst), eachinst);
6119663Slinton 		found = true;
6129663Slinton 		break;
6139663Slinton 	    }
6149663Slinton 	endfor
6159663Slinton 	if (not found) {
61618218Slinton 	    beginerrmsg();
61718218Slinton 	    fprintf(stderr, "[internal error: trace id %d not found]\n", id);
6189663Slinton 	}
6199663Slinton     }
6209663Slinton     if (list_size(eachinst) == 0) {
6219663Slinton 	inst_tracing = false;
6229663Slinton 	if (list_size(eachline) == 0) {
6239663Slinton 	    single_stepping = false;
6249663Slinton 	}
6259663Slinton     }
6269663Slinton }
6279663Slinton 
6289663Slinton /*
6299663Slinton  * If breakpoints are being traced, note that a Trcmd is being deleted.
6309663Slinton  */
6319663Slinton 
printrmtr(t)6329663Slinton private printrmtr(t)
6339663Slinton Trcmd t;
6349663Slinton {
63518218Slinton     if (tracebpts) {
63618218Slinton 	printf("removing trace %d", t->trid);
63718218Slinton 	if (t->event != nil) {
63818218Slinton 	    printf(" for event %d", t->event->id);
63918218Slinton 	}
64018218Slinton 	printf("\n");
6419663Slinton     }
6429663Slinton }
6439663Slinton 
6449663Slinton /*
6459663Slinton  * Print out news during single step tracing.
6469663Slinton  */
6479663Slinton 
printnews()6489663Slinton public printnews()
6499663Slinton {
6509663Slinton     register Trcmd t;
6519663Slinton 
6529663Slinton     foreach (Trcmd, t, eachline)
6539663Slinton 	evalcmdlist(t->cmdlist);
6549663Slinton     endfor
6559663Slinton     foreach (Trcmd, t, eachinst)
6569663Slinton 	evalcmdlist(t->cmdlist);
6579663Slinton     endfor
6589663Slinton     bpact();
6599663Slinton }
6609663Slinton 
6619663Slinton /*
6629663Slinton  * A procedure call/return has occurred while single-stepping,
6639663Slinton  * note it if we're tracing lines.
6649663Slinton  */
6659663Slinton 
66618218Slinton private boolean chklist();
6679663Slinton 
callnews(iscall)6689663Slinton public callnews(iscall)
66918218Slinton boolean iscall;
6709663Slinton {
6719663Slinton     if (not chklist(eachline, iscall)) {
6729663Slinton 	chklist(eachinst, iscall);
6739663Slinton     }
6749663Slinton }
6759663Slinton 
chklist(list,iscall)67618218Slinton private boolean chklist(list, iscall)
6779663Slinton List list;
67818218Slinton boolean iscall;
6799663Slinton {
6809663Slinton     register Trcmd t;
6819663Slinton     register Command cmd;
6829663Slinton 
68316609Ssam     setcurfunc(whatblock(pc));
6849663Slinton     foreach (Trcmd, t, list)
6859663Slinton 	foreach (Command, cmd, t->cmdlist)
6869663Slinton 	    if (cmd->op == O_PRINTSRCPOS and
6879663Slinton 	      (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) {
6889663Slinton 		if (iscall) {
6899663Slinton 		    printentry(curfunc);
6909663Slinton 		} else {
6919663Slinton 		    printexit(curfunc);
6929663Slinton 		}
6939663Slinton 		return true;
6949663Slinton 	    }
6959663Slinton 	endfor
6969663Slinton     endfor
6979663Slinton     return false;
6989663Slinton }
6999663Slinton 
7009663Slinton /*
7019663Slinton  * List of variables being watched.
7029663Slinton  */
7039663Slinton 
7049663Slinton typedef struct Trinfo *Trinfo;
7059663Slinton 
7069663Slinton struct Trinfo {
7079663Slinton     Node variable;
7089663Slinton     Address traddr;
7099663Slinton     Symbol trblock;
7109663Slinton     char *trvalue;
7119663Slinton };
7129663Slinton 
7139663Slinton private List trinfolist;
7149663Slinton 
7159663Slinton /*
7169663Slinton  * Find the trace information record associated with the given record.
7179663Slinton  * If there isn't one then create it and add it to the list.
7189663Slinton  */
7199663Slinton 
findtrinfo(p)7209663Slinton private Trinfo findtrinfo(p)
7219663Slinton Node p;
7229663Slinton {
7239663Slinton     register Trinfo tp;
72418218Slinton     boolean isnew;
7259663Slinton 
7269663Slinton     isnew = true;
7279663Slinton     if (trinfolist == nil) {
7289663Slinton 	trinfolist = list_alloc();
7299663Slinton     } else {
7309663Slinton 	foreach (Trinfo, tp, trinfolist)
7319663Slinton 	    if (tp->variable == p) {
7329663Slinton 		isnew = false;
7339663Slinton 		break;
7349663Slinton 	    }
7359663Slinton 	endfor
7369663Slinton     }
7379663Slinton     if (isnew) {
7389663Slinton 	if (tracebpts) {
7399663Slinton 	    printf("adding trinfo for \"");
7409663Slinton 	    prtree(stdout, p);
7419663Slinton 	    printf("\"\n");
7429663Slinton 	}
7439663Slinton 	tp = new(Trinfo);
7449663Slinton 	tp->variable = p;
7459663Slinton 	tp->traddr = lval(p);
7469663Slinton 	tp->trvalue = nil;
7479663Slinton 	list_append(list_item(tp), nil, trinfolist);
7489663Slinton     }
7499663Slinton     return tp;
7509663Slinton }
7519663Slinton 
7529663Slinton /*
7539663Slinton  * Print out the value of a variable if it has changed since the
7549663Slinton  * last time we checked.
7559663Slinton  */
7569663Slinton 
printifchanged(p)7579663Slinton public printifchanged(p)
7589663Slinton Node p;
7599663Slinton {
7609663Slinton     register Trinfo tp;
7619663Slinton     register int n;
7629663Slinton     char buff[MAXTRSIZE];
76318218Slinton     Filename curfile;
7649663Slinton     static Lineno prevline;
76518218Slinton     static Filename prevfile;
7669663Slinton 
7679663Slinton     tp = findtrinfo(p);
7689663Slinton     n = size(p->nodetype);
76918218Slinton     dread(buff, tp->traddr, n);
77018218Slinton     curfile = srcfilename(pc);
7719663Slinton     if (tp->trvalue == nil) {
7729663Slinton 	tp->trvalue = newarr(char, n);
7739663Slinton 	mov(buff, tp->trvalue, n);
7749663Slinton 	mov(buff, sp, n);
7759663Slinton 	sp += n;
77618218Slinton 	printf("initially (at line %d in \"%s\"):\t", curline, curfile);
7779663Slinton 	prtree(stdout, p);
7789663Slinton 	printf(" = ");
7799663Slinton 	printval(p->nodetype);
7809663Slinton 	putchar('\n');
7819663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
7829663Slinton 	mov(buff, tp->trvalue, n);
7839663Slinton 	mov(buff, sp, n);
7849663Slinton 	sp += n;
78518218Slinton 	printf("after line %d in \"%s\":\t", prevline, prevfile);
7869663Slinton 	prtree(stdout, p);
7879663Slinton 	printf(" = ");
7889663Slinton 	printval(p->nodetype);
7899663Slinton 	putchar('\n');
7909663Slinton     }
7919663Slinton     prevline = curline;
79218218Slinton     prevfile = curfile;
7939663Slinton }
7949663Slinton 
7959663Slinton /*
7969663Slinton  * Stop if the value of the given expression has changed.
7979663Slinton  */
7989663Slinton 
stopifchanged(p)7999663Slinton public stopifchanged(p)
8009663Slinton Node p;
8019663Slinton {
8029663Slinton     register Trinfo tp;
8039663Slinton     register int n;
8049663Slinton     char buff[MAXTRSIZE];
8059663Slinton     static Lineno prevline;
8069663Slinton 
8079663Slinton     tp = findtrinfo(p);
8089663Slinton     n = size(p->nodetype);
8099663Slinton     dread(buff, tp->traddr, n);
8109663Slinton     if (tp->trvalue == nil) {
8119663Slinton 	tp->trvalue = newarr(char, n);
8129663Slinton 	mov(buff, tp->trvalue, n);
8139663Slinton 	isstopped = true;
8149663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
8159663Slinton 	mov(buff, tp->trvalue, n);
81616609Ssam 	mov(buff, sp, n);
81716609Ssam 	sp += n;
81816609Ssam 	printf("after line %d:\t", prevline);
81916609Ssam 	prtree(stdout, p);
82016609Ssam 	printf(" = ");
82116609Ssam 	printval(p->nodetype);
82216609Ssam 	putchar('\n');
8239663Slinton 	isstopped = true;
8249663Slinton     }
8259663Slinton     prevline = curline;
8269663Slinton }
8279663Slinton 
8289663Slinton /*
8299663Slinton  * Free the tracing table.
8309663Slinton  */
8319663Slinton 
trfree()8329663Slinton public trfree()
8339663Slinton {
8349663Slinton     register Trinfo tp;
8359663Slinton 
8369663Slinton     foreach (Trinfo, tp, trinfolist)
8379663Slinton 	dispose(tp->trvalue);
8389663Slinton 	dispose(tp);
8399663Slinton 	list_delete(list_curitem(trinfolist), trinfolist);
8409663Slinton     endfor
8419663Slinton }
8429663Slinton 
8439663Slinton /*
8449663Slinton  * Fix up breakpoint information before continuing execution.
8459663Slinton  *
8469663Slinton  * It's necessary to destroy events and breakpoints that were created
8479663Slinton  * temporarily and still exist because the program terminated abnormally.
8489663Slinton  */
8499663Slinton 
fixbps()8509663Slinton public fixbps()
8519663Slinton {
8529663Slinton     register Event e;
8539663Slinton     register Trcmd t;
8549663Slinton 
8559663Slinton     single_stepping = false;
8569663Slinton     inst_tracing = false;
8579663Slinton     trfree();
8589663Slinton     foreach (Event, e, eventlist)
8599663Slinton 	if (e->temporary) {
86016609Ssam 	    if (not delevent(e->id)) {
86116609Ssam 		printf("!! dbx.fixbps: can't find event %d\n", e->id);
86216609Ssam 	    }
8639663Slinton 	}
8649663Slinton     endfor
8659663Slinton     foreach (Trcmd, t, eachline)
8669663Slinton 	printrmtr(t);
8679663Slinton 	list_delete(list_curitem(eachline), eachline);
8689663Slinton     endfor
8699663Slinton     foreach (Trcmd, t, eachinst)
8709663Slinton 	printrmtr(t);
8719663Slinton 	list_delete(list_curitem(eachinst), eachinst);
8729663Slinton     endfor
8739663Slinton }
8749663Slinton 
8759663Slinton /*
8769663Slinton  * Set all breakpoints in object code.
8779663Slinton  */
8789663Slinton 
setallbps()8799663Slinton public setallbps()
8809663Slinton {
8819663Slinton     register Breakpoint p;
8829663Slinton 
8839663Slinton     foreach (Breakpoint, p, bplist)
8849663Slinton 	setbp(p->bpaddr);
8859663Slinton     endfor
8869663Slinton }
8879663Slinton 
8889663Slinton /*
8899663Slinton  * Undo damage done by "setallbps".
8909663Slinton  */
8919663Slinton 
unsetallbps()8929663Slinton public unsetallbps()
8939663Slinton {
8949663Slinton     register Breakpoint p;
8959663Slinton 
8969663Slinton     foreach (Breakpoint, p, bplist)
8979663Slinton 	unsetbp(p->bpaddr);
8989663Slinton     endfor
8999663Slinton }
900