xref: /csrg-svn/old/dbx/events.c (revision 30796)
121602Sdist /*
221602Sdist  * Copyright (c) 1983 Regents of the University of California.
321602Sdist  * All rights reserved.  The Berkeley software License Agreement
421602Sdist  * specifies the terms and conditions for redistribution.
521602Sdist  */
69663Slinton 
721602Sdist #ifndef lint
8*30796Sbostic static char sccsid[] = "@(#)events.c	5.2 (Berkeley) 04/06/87";
921602Sdist #endif not lint
109663Slinton 
1118218Slinton static char rcsid[] = "$Header: events.c,v 1.5 84/12/26 10:39:26 linton Exp $";
1218218Slinton 
139663Slinton /*
149663Slinton  * Event/breakpoint managment.
159663Slinton  */
169663Slinton 
179663Slinton #include "defs.h"
189663Slinton #include "events.h"
199663Slinton #include "main.h"
209663Slinton #include "symbols.h"
219663Slinton #include "tree.h"
229663Slinton #include "eval.h"
239663Slinton #include "source.h"
249663Slinton #include "mappings.h"
2516609Ssam #include "runtime.h"
269663Slinton #include "process.h"
279663Slinton #include "machine.h"
289663Slinton #include "lists.h"
299663Slinton 
309663Slinton #ifndef public
319663Slinton typedef struct Event *Event;
329663Slinton typedef struct Breakpoint *Breakpoint;
339663Slinton 
3418218Slinton boolean inst_tracing;
3518218Slinton boolean single_stepping;
3618218Slinton boolean isstopped;
379663Slinton 
389663Slinton #include "symbols.h"
399663Slinton 
409663Slinton Symbol linesym;
419663Slinton Symbol procsym;
429663Slinton Symbol pcsym;
439663Slinton Symbol retaddrsym;
449663Slinton 
459663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist)
469663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist)
479663Slinton 
489663Slinton #endif
499663Slinton 
509663Slinton struct Event {
519663Slinton     unsigned int id;
5218218Slinton     boolean temporary;
539663Slinton     Node condition;
549663Slinton     Cmdlist actions;
559663Slinton };
569663Slinton 
579663Slinton struct Breakpoint {
589663Slinton     Event event;
599663Slinton     Address bpaddr;
609663Slinton     Lineno bpline;
619663Slinton     Cmdlist actions;
6218218Slinton     boolean temporary;
639663Slinton };
649663Slinton 
659663Slinton typedef List Eventlist;
669663Slinton typedef List Bplist;
679663Slinton 
689663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el)
699663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)
709663Slinton 
719663Slinton private Eventlist eventlist;		/* list of active events */
729663Slinton private Bplist bplist;			/* list of active breakpoints */
7318218Slinton private Event curevent;			/* most recently created event */
7418218Slinton private integer eventid;		/* id number of current event */
7518218Slinton private integer trid;			/* id number of current trace */
769663Slinton 
779663Slinton typedef struct Trcmd {
789663Slinton     Integer trid;
799663Slinton     Event event;
809663Slinton     Cmdlist cmdlist;
819663Slinton } *Trcmd;
829663Slinton 
839663Slinton private List eachline;		/* commands to execute after each line */
849663Slinton private List eachinst;		/* commands to execute after each instruction */
859663Slinton 
869663Slinton private Breakpoint bp_alloc();
879663Slinton 
889663Slinton /*
899663Slinton  * Initialize breakpoint information.
909663Slinton  */
919663Slinton 
929663Slinton private Symbol builtinsym(str, class, type)
939663Slinton String str;
949663Slinton Symclass class;
959663Slinton Symbol type;
969663Slinton {
979663Slinton     Symbol s;
989663Slinton 
999663Slinton     s = insert(identname(str, true));
1009663Slinton     s->language = findlanguage(".s");
1019663Slinton     s->class = class;
1029663Slinton     s->type = type;
1039663Slinton     return s;
1049663Slinton }
1059663Slinton 
1069663Slinton public bpinit()
1079663Slinton {
1089663Slinton     linesym = builtinsym("$line", VAR, t_int);
1099663Slinton     procsym = builtinsym("$proc", PROC, nil);
1109663Slinton     pcsym = lookup(identname("$pc", true));
1119663Slinton     if (pcsym == nil) {
1129663Slinton 	panic("can't find $pc");
1139663Slinton     }
1149663Slinton     retaddrsym = builtinsym("$retaddr", VAR, t_int);
1159663Slinton     eventlist = list_alloc();
1169663Slinton     bplist = list_alloc();
1179663Slinton     eachline = list_alloc();
1189663Slinton     eachinst = list_alloc();
1199663Slinton }
1209663Slinton 
1219663Slinton /*
1229663Slinton  * Trap an event and do the associated commands when it occurs.
1239663Slinton  */
1249663Slinton 
1259663Slinton public Event event_alloc(istmp, econd, cmdlist)
12618218Slinton boolean istmp;
1279663Slinton Node econd;
1289663Slinton Cmdlist cmdlist;
1299663Slinton {
1309663Slinton     register Event e;
1319663Slinton 
1329663Slinton     e = new(Event);
13318218Slinton     ++eventid;
13418218Slinton     e->id = eventid;
1359663Slinton     e->temporary = istmp;
1369663Slinton     e->condition = econd;
1379663Slinton     e->actions = cmdlist;
1389663Slinton     eventlist_append(e, eventlist);
13918218Slinton     curevent = e;
1409663Slinton     translate(e);
1419663Slinton     return e;
1429663Slinton }
1439663Slinton 
1449663Slinton /*
1459663Slinton  * Delete the event with the given id.
14616609Ssam  * Returns whether it's successful or not.
1479663Slinton  */
1489663Slinton 
14916609Ssam public boolean delevent (id)
1509663Slinton unsigned int id;
1519663Slinton {
1529663Slinton     Event e;
1539663Slinton     Breakpoint bp;
1549663Slinton     Trcmd t;
15516609Ssam     boolean found;
1569663Slinton 
15716609Ssam     found = false;
1589663Slinton     foreach (Event, e, eventlist)
1599663Slinton 	if (e->id == id) {
16016609Ssam 	    found = true;
1619663Slinton 	    foreach (Breakpoint, bp, bplist)
1629663Slinton 		if (bp->event == e) {
16318218Slinton 		    if (tracebpts) {
16418218Slinton 			printf("deleting breakpoint at 0x%x\n", bp->bpaddr);
16518218Slinton 			fflush(stdout);
16618218Slinton 		    }
1679663Slinton 		    list_delete(list_curitem(bplist), bplist);
1689663Slinton 		}
1699663Slinton 	    endfor
17016609Ssam 	    list_delete(list_curitem(eventlist), eventlist);
1719663Slinton 	    break;
1729663Slinton 	}
1739663Slinton     endfor
1749663Slinton     foreach (Trcmd, t, eachline)
1759663Slinton 	if (t->event->id == id) {
17616609Ssam 	    found = true;
1779663Slinton 	    printrmtr(t);
1789663Slinton 	    list_delete(list_curitem(eachline), eachline);
1799663Slinton 	}
1809663Slinton     endfor
1819663Slinton     foreach (Trcmd, t, eachinst)
1829663Slinton 	if (t->event->id == id) {
18316609Ssam 	    found = true;
1849663Slinton 	    printrmtr(t);
1859663Slinton 	    list_delete(list_curitem(eachinst), eachinst);
1869663Slinton 	}
1879663Slinton     endfor
1889663Slinton     if (list_size(eachinst) == 0) {
1899663Slinton 	inst_tracing = false;
1909663Slinton 	if (list_size(eachline) == 0) {
1919663Slinton 	    single_stepping = false;
1929663Slinton 	}
1939663Slinton     }
19416609Ssam     return found;
1959663Slinton }
1969663Slinton 
1979663Slinton /*
1989663Slinton  * Translate an event into the appropriate breakpoints and actions.
1999663Slinton  * While we're at it, turn on the breakpoints if the condition is true.
2009663Slinton  */
2019663Slinton 
2029663Slinton private translate(e)
2039663Slinton Event e;
2049663Slinton {
2059663Slinton     Breakpoint bp;
2069663Slinton     Symbol s;
2079663Slinton     Node place;
2089663Slinton     Lineno line;
2099663Slinton     Address addr;
2109663Slinton 
2119663Slinton     checkref(e->condition);
2129663Slinton     switch (e->condition->op) {
2139663Slinton 	case O_EQ:
2149663Slinton 	    if (e->condition->value.arg[0]->op == O_SYM) {
2159663Slinton 		s = e->condition->value.arg[0]->value.sym;
2169663Slinton 		place = e->condition->value.arg[1];
2179663Slinton 		if (s == linesym) {
2189663Slinton 		    if (place->op == O_QLINE) {
2199663Slinton 			line = place->value.arg[1]->value.lcon;
22016609Ssam 			addr = objaddr(line, place->value.arg[0]->value.scon);
2219663Slinton 		    } else {
2229663Slinton 			eval(place);
2239663Slinton 			line = pop(long);
2249663Slinton 			addr = objaddr(line, cursource);
2259663Slinton 		    }
2269663Slinton 		    if (addr == NOADDR) {
22716609Ssam 			if (not delevent(e->id)) {
22816609Ssam 			    printf("!! dbx.translate: can't undo event %d?\n",
22916609Ssam 				e->id);
23016609Ssam 			}
2319663Slinton 			beginerrmsg();
2329663Slinton 			fprintf(stderr, "no executable code at line ");
2339663Slinton 			prtree(stderr, place);
2349663Slinton 			enderrmsg();
2359663Slinton 		    }
2369663Slinton 		    bp = bp_alloc(e, addr, line, e->actions);
2379663Slinton 		} else if (s == procsym) {
2389663Slinton 		    eval(place);
2399663Slinton 		    s = pop(Symbol);
2409663Slinton 		    bp = bp_alloc(e, codeloc(s), 0, e->actions);
2419663Slinton 		    if (isactive(s) and pc != codeloc(program)) {
2429663Slinton 			evalcmdlist(e->actions);
2439663Slinton 		    }
2449663Slinton 		} else if (s == pcsym) {
2459663Slinton 		    eval(place);
2469663Slinton 		    bp = bp_alloc(e, pop(Address), 0, e->actions);
2479663Slinton 		} else {
2489663Slinton 		    condbp(e);
2499663Slinton 		}
2509663Slinton 	    } else {
2519663Slinton 		condbp(e);
2529663Slinton 	    }
2539663Slinton 	    break;
2549663Slinton 
2559663Slinton 	/*
2569663Slinton 	 * These should be handled specially.
2579663Slinton 	 * But for now I'm ignoring the problem.
2589663Slinton 	 */
2599663Slinton 	case O_AND:
2609663Slinton 	case O_OR:
2619663Slinton 	default:
2629663Slinton 	    condbp(e);
2639663Slinton 	    break;
2649663Slinton     }
2659663Slinton }
2669663Slinton 
2679663Slinton /*
2689663Slinton  * Create a breakpoint for a condition that cannot be pinpointed
2699663Slinton  * to happening at a particular address, but one for which we
2709663Slinton  * must single step and check the condition after each statement.
2719663Slinton  */
2729663Slinton 
2739663Slinton private condbp(e)
2749663Slinton Event e;
2759663Slinton {
2769663Slinton     Symbol p;
2779663Slinton     Breakpoint bp;
2789663Slinton     Cmdlist actions;
2799663Slinton 
2809663Slinton     p = tcontainer(e->condition);
2819663Slinton     if (p == nil) {
2829663Slinton 	p = program;
2839663Slinton     }
2849663Slinton     actions = buildcmdlist(build(O_IF, e->condition, e->actions));
2859663Slinton     actions = buildcmdlist(build(O_TRACEON, false, actions));
2869663Slinton     bp = bp_alloc(e, codeloc(p), 0, actions);
2879663Slinton }
2889663Slinton 
2899663Slinton /*
2909663Slinton  * Determine the deepest nested subprogram that still contains
2919663Slinton  * all elements in the given expression.
2929663Slinton  */
2939663Slinton 
2949663Slinton public Symbol tcontainer(exp)
2959663Slinton Node exp;
2969663Slinton {
2979663Slinton     Integer i;
2989663Slinton     Symbol s, t, u, v;
2999663Slinton 
3009663Slinton     checkref(exp);
3019663Slinton     s = nil;
3029663Slinton     if (exp->op == O_SYM) {
3039663Slinton 	s = container(exp->value.sym);
3049663Slinton     } else if (not isleaf(exp->op)) {
3059663Slinton 	for (i = 0; i < nargs(exp->op); i++) {
3069663Slinton 	    t = tcontainer(exp->value.arg[i]);
3079663Slinton 	    if (t != nil) {
3089663Slinton 		if (s == nil) {
3099663Slinton 		    s = t;
3109663Slinton 		} else {
3119663Slinton 		    u = s;
3129663Slinton 		    v = t;
3139663Slinton 		    while (u != v and u != nil) {
3149663Slinton 			u = container(u);
3159663Slinton 			v = container(v);
3169663Slinton 		    }
3179663Slinton 		    if (u == nil) {
3189663Slinton 			panic("bad ancestry for \"%s\"", symname(s));
3199663Slinton 		    } else {
3209663Slinton 			s = u;
3219663Slinton 		    }
3229663Slinton 		}
3239663Slinton 	    }
3249663Slinton 	}
3259663Slinton     }
3269663Slinton     return s;
3279663Slinton }
3289663Slinton 
3299663Slinton /*
33011869Slinton  * Determine if the given function can be executed at full speed.
33111869Slinton  * This can only be done if there are no breakpoints within the function.
33211869Slinton  */
33311869Slinton 
33418218Slinton public boolean canskip(f)
33511869Slinton Symbol f;
33611869Slinton {
33711869Slinton     Breakpoint p;
33818218Slinton     boolean ok;
33911869Slinton 
34011869Slinton     ok = true;
34111869Slinton     foreach (Breakpoint, p, bplist)
34211869Slinton 	if (whatblock(p->bpaddr) == f) {
34311869Slinton 	    ok = false;
34411869Slinton 	    break;
34511869Slinton 	}
34611869Slinton     endfor
34711869Slinton     return ok;
34811869Slinton }
34911869Slinton 
35011869Slinton /*
3519663Slinton  * Print out what's currently being traced by looking at
3529663Slinton  * the currently active events.
3539663Slinton  *
3549663Slinton  * Some convolution here to translate internal representation
3559663Slinton  * of events back into something more palatable.
3569663Slinton  */
3579663Slinton 
3589663Slinton public status()
3599663Slinton {
3609663Slinton     Event e;
3619663Slinton 
3629663Slinton     foreach (Event, e, eventlist)
3639663Slinton 	if (not e->temporary) {
36411869Slinton 	    printevent(e);
3659663Slinton 	}
3669663Slinton     endfor
3679663Slinton }
3689663Slinton 
36911869Slinton public printevent(e)
37011869Slinton Event e;
37111869Slinton {
37211869Slinton     Command cmd;
37311869Slinton 
37411869Slinton     if (not isredirected()) {
37516609Ssam 	printeventid(e->id);
37611869Slinton     }
37711869Slinton     cmd = list_element(Command, list_head(e->actions));
37811869Slinton     if (cmd->op == O_PRINTCALL) {
37911869Slinton 	printf("trace ");
38011869Slinton 	printname(stdout, cmd->value.sym);
38111869Slinton     } else {
38211869Slinton 	if (list_size(e->actions) > 1) {
38311869Slinton 	    printf("{ ");
38411869Slinton 	}
38511869Slinton 	foreach (Command, cmd, e->actions)
38611869Slinton 	    printcmd(stdout, cmd);
38711869Slinton 	    if (not list_islast()) {
38811869Slinton 		printf("; ");
38911869Slinton 	    }
39011869Slinton 	endfor
39111869Slinton 	if (list_size(e->actions) > 1) {
39211869Slinton 	    printf(" }");
39311869Slinton 	}
39411869Slinton 	printcond(e->condition);
39511869Slinton     }
39611869Slinton     printf("\n");
39711869Slinton }
39811869Slinton 
39916609Ssam private printeventid (id)
40016609Ssam integer id;
40116609Ssam {
40216609Ssam     printf("[%d] ", id);
40316609Ssam }
40416609Ssam 
4059663Slinton /*
4069663Slinton  * Print out a condition.
4079663Slinton  */
4089663Slinton 
4099663Slinton private printcond(cond)
4109663Slinton Node cond;
4119663Slinton {
4129663Slinton     Symbol s;
4139663Slinton     Node place;
4149663Slinton 
4159663Slinton     if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) {
4169663Slinton 	s = cond->value.arg[0]->value.sym;
4179663Slinton 	place = cond->value.arg[1];
4189663Slinton 	if (s == procsym) {
4199663Slinton 	    if (place->value.sym != program) {
4209663Slinton 		printf(" in ");
4219663Slinton 		printname(stdout, place->value.sym);
4229663Slinton 	    }
4239663Slinton 	} else if (s == linesym) {
4249663Slinton 	    printf(" at ");
4259663Slinton 	    prtree(stdout, place);
4269663Slinton 	} else if (s == pcsym or s == retaddrsym) {
4279663Slinton 	    printf("i at ");
4289663Slinton 	    prtree(stdout, place);
4299663Slinton 	} else {
4309663Slinton 	    printf(" when ");
4319663Slinton 	    prtree(stdout, cond);
4329663Slinton 	}
4339663Slinton     } else {
4349663Slinton 	printf(" when ");
4359663Slinton 	prtree(stdout, cond);
4369663Slinton     }
4379663Slinton }
4389663Slinton 
4399663Slinton /*
4409663Slinton  * Add a breakpoint to the list and return it.
4419663Slinton  */
4429663Slinton 
4439663Slinton private Breakpoint bp_alloc(e, addr, line, actions)
4449663Slinton Event e;
4459663Slinton Address addr;
4469663Slinton Lineno line;
4479663Slinton Cmdlist actions;
4489663Slinton {
4499663Slinton     register Breakpoint p;
4509663Slinton 
4519663Slinton     p = new(Breakpoint);
4529663Slinton     p->event = e;
4539663Slinton     p->bpaddr = addr;
4549663Slinton     p->bpline = line;
4559663Slinton     p->actions = actions;
45618218Slinton     p->temporary = false;
45718218Slinton     if (tracebpts) {
45818218Slinton 	if (e == nil) {
459*30796Sbostic 	    printf("new bp at 0x%x for event ??\n", addr);
46018218Slinton 	} else {
46118218Slinton 	    printf("new bp at 0x%x for event %d\n", addr, e->id);
46218218Slinton 	}
46318218Slinton 	fflush(stdout);
46418218Slinton     }
4659663Slinton     bplist_append(p, bplist);
4669663Slinton     return p;
4679663Slinton }
4689663Slinton 
4699663Slinton /*
4709663Slinton  * Free all storage in the event and breakpoint tables.
4719663Slinton  */
4729663Slinton 
4739663Slinton public bpfree()
4749663Slinton {
4759663Slinton     register Event e;
4769663Slinton 
4779663Slinton     fixbps();
4789663Slinton     foreach (Event, e, eventlist)
47916609Ssam 	if (not delevent(e->id)) {
48016609Ssam 	    printf("!! dbx.bpfree: can't delete event %d\n", e->id);
48116609Ssam 	}
4829663Slinton 	list_delete(list_curitem(eventlist), eventlist);
4839663Slinton     endfor
4849663Slinton }
4859663Slinton 
4869663Slinton /*
4879663Slinton  * Determine if the program stopped at a known breakpoint
4889663Slinton  * and if so do the associated commands.
4899663Slinton  */
4909663Slinton 
49118218Slinton public boolean bpact()
4929663Slinton {
4939663Slinton     register Breakpoint p;
49418218Slinton     boolean found;
49516609Ssam     integer eventId;
4969663Slinton 
4979663Slinton     found = false;
4989663Slinton     foreach (Breakpoint, p, bplist)
4999663Slinton 	if (p->bpaddr == pc) {
50018218Slinton 	    if (tracebpts) {
50118218Slinton 		printf("breakpoint for event %d found at location 0x%x\n",
50218218Slinton 		    p->event->id, pc);
50318218Slinton 	    }
5049663Slinton 	    found = true;
50518218Slinton 	    if (p->event->temporary) {
50618218Slinton 		if (not delevent(p->event->id)) {
50718218Slinton 		    printf("!! dbx.bpact: can't find event %d\n",
50818218Slinton 			p->event->id);
50918218Slinton 		}
51018218Slinton 	    }
5119663Slinton 	    evalcmdlist(p->actions);
51218218Slinton 	    if (isstopped) {
51318218Slinton 		eventId = p->event->id;
51418218Slinton 	    }
51518218Slinton 	    if (p->temporary) {
51618218Slinton 		list_delete(list_curitem(bplist), bplist);
51718218Slinton 	    }
5189663Slinton 	}
5199663Slinton     endfor
5209663Slinton     if (isstopped) {
52116609Ssam 	if (found) {
52216609Ssam 	    printeventid(eventId);
52316609Ssam 	}
5249663Slinton 	printstatus();
5259663Slinton     }
5269663Slinton     fflush(stdout);
5279663Slinton     return found;
5289663Slinton }
5299663Slinton 
5309663Slinton /*
5319663Slinton  * Begin single stepping and executing the given commands after each step.
5329663Slinton  * If the first argument is true step by instructions, otherwise
5339663Slinton  * step by source lines.
5349663Slinton  *
5359663Slinton  * We automatically set a breakpoint at the end of the current procedure
5369663Slinton  * to turn off the given tracing.
5379663Slinton  */
5389663Slinton 
5399663Slinton public traceon(inst, event, cmdlist)
54018218Slinton boolean inst;
5419663Slinton Event event;
5429663Slinton Cmdlist cmdlist;
5439663Slinton {
5449663Slinton     register Trcmd trcmd;
54518218Slinton     Breakpoint bp;
5469663Slinton     Cmdlist actions;
54711869Slinton     Address ret;
54818218Slinton     Event e;
5499663Slinton 
55018218Slinton     if (event == nil) {
55118218Slinton 	e = curevent;
55218218Slinton     } else {
55318218Slinton 	e = event;
55418218Slinton     }
5559663Slinton     trcmd = new(Trcmd);
55618218Slinton     ++trid;
55718218Slinton     trcmd->trid = trid;
55818218Slinton     trcmd->event = e;
5599663Slinton     trcmd->cmdlist = cmdlist;
5609663Slinton     single_stepping = true;
5619663Slinton     if (inst) {
5629663Slinton 	inst_tracing = true;
5639663Slinton 	list_append(list_item(trcmd), nil, eachinst);
5649663Slinton     } else {
5659663Slinton 	list_append(list_item(trcmd), nil, eachline);
5669663Slinton     }
56711869Slinton     ret = return_addr();
56811869Slinton     if (ret != 0) {
56918218Slinton 	actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid));
57018218Slinton 	bp = bp_alloc(e, (Address) ret, 0, actions);
57118218Slinton 	bp->temporary = true;
57211869Slinton     }
57318218Slinton     if (tracebpts) {
57418218Slinton 	printf("adding trace %d for event %d\n", trcmd->trid, e->id);
57518218Slinton     }
5769663Slinton }
5779663Slinton 
5789663Slinton /*
5799663Slinton  * Turn off some kind of tracing.
5809663Slinton  * Strictly an internal command, this cannot be invoked by the user.
5819663Slinton  */
5829663Slinton 
5839663Slinton public traceoff(id)
5849663Slinton Integer id;
5859663Slinton {
5869663Slinton     register Trcmd t;
58718218Slinton     register boolean found;
5889663Slinton 
5899663Slinton     found = false;
5909663Slinton     foreach (Trcmd, t, eachline)
5919663Slinton 	if (t->trid == id) {
5929663Slinton 	    printrmtr(t);
5939663Slinton 	    list_delete(list_curitem(eachline), eachline);
5949663Slinton 	    found = true;
5959663Slinton 	    break;
5969663Slinton 	}
5979663Slinton     endfor
5989663Slinton     if (not found) {
5999663Slinton 	foreach (Trcmd, t, eachinst)
6009663Slinton 	    if (t->event->id == id) {
6019663Slinton 		printrmtr(t);
6029663Slinton 		list_delete(list_curitem(eachinst), eachinst);
6039663Slinton 		found = true;
6049663Slinton 		break;
6059663Slinton 	    }
6069663Slinton 	endfor
6079663Slinton 	if (not found) {
60818218Slinton 	    beginerrmsg();
60918218Slinton 	    fprintf(stderr, "[internal error: trace id %d not found]\n", id);
6109663Slinton 	}
6119663Slinton     }
6129663Slinton     if (list_size(eachinst) == 0) {
6139663Slinton 	inst_tracing = false;
6149663Slinton 	if (list_size(eachline) == 0) {
6159663Slinton 	    single_stepping = false;
6169663Slinton 	}
6179663Slinton     }
6189663Slinton }
6199663Slinton 
6209663Slinton /*
6219663Slinton  * If breakpoints are being traced, note that a Trcmd is being deleted.
6229663Slinton  */
6239663Slinton 
6249663Slinton private printrmtr(t)
6259663Slinton Trcmd t;
6269663Slinton {
62718218Slinton     if (tracebpts) {
62818218Slinton 	printf("removing trace %d", t->trid);
62918218Slinton 	if (t->event != nil) {
63018218Slinton 	    printf(" for event %d", t->event->id);
63118218Slinton 	}
63218218Slinton 	printf("\n");
6339663Slinton     }
6349663Slinton }
6359663Slinton 
6369663Slinton /*
6379663Slinton  * Print out news during single step tracing.
6389663Slinton  */
6399663Slinton 
6409663Slinton public printnews()
6419663Slinton {
6429663Slinton     register Trcmd t;
6439663Slinton 
6449663Slinton     foreach (Trcmd, t, eachline)
6459663Slinton 	evalcmdlist(t->cmdlist);
6469663Slinton     endfor
6479663Slinton     foreach (Trcmd, t, eachinst)
6489663Slinton 	evalcmdlist(t->cmdlist);
6499663Slinton     endfor
6509663Slinton     bpact();
6519663Slinton }
6529663Slinton 
6539663Slinton /*
6549663Slinton  * A procedure call/return has occurred while single-stepping,
6559663Slinton  * note it if we're tracing lines.
6569663Slinton  */
6579663Slinton 
65818218Slinton private boolean chklist();
6599663Slinton 
6609663Slinton public callnews(iscall)
66118218Slinton boolean iscall;
6629663Slinton {
6639663Slinton     if (not chklist(eachline, iscall)) {
6649663Slinton 	chklist(eachinst, iscall);
6659663Slinton     }
6669663Slinton }
6679663Slinton 
66818218Slinton private boolean chklist(list, iscall)
6699663Slinton List list;
67018218Slinton boolean iscall;
6719663Slinton {
6729663Slinton     register Trcmd t;
6739663Slinton     register Command cmd;
6749663Slinton 
67516609Ssam     setcurfunc(whatblock(pc));
6769663Slinton     foreach (Trcmd, t, list)
6779663Slinton 	foreach (Command, cmd, t->cmdlist)
6789663Slinton 	    if (cmd->op == O_PRINTSRCPOS and
6799663Slinton 	      (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) {
6809663Slinton 		if (iscall) {
6819663Slinton 		    printentry(curfunc);
6829663Slinton 		} else {
6839663Slinton 		    printexit(curfunc);
6849663Slinton 		}
6859663Slinton 		return true;
6869663Slinton 	    }
6879663Slinton 	endfor
6889663Slinton     endfor
6899663Slinton     return false;
6909663Slinton }
6919663Slinton 
6929663Slinton /*
6939663Slinton  * When tracing variables we keep a copy of their most recent value
6949663Slinton  * and compare it to the current one each time a breakpoint occurs.
6959663Slinton  * MAXTRSIZE is the maximum size variable we allow.
6969663Slinton  */
6979663Slinton 
6989663Slinton #define MAXTRSIZE 512
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 
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 
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 
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 
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 
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 
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 
8929663Slinton public unsetallbps()
8939663Slinton {
8949663Slinton     register Breakpoint p;
8959663Slinton 
8969663Slinton     foreach (Breakpoint, p, bplist)
8979663Slinton 	unsetbp(p->bpaddr);
8989663Slinton     endfor
8999663Slinton }
900