xref: /csrg-svn/old/dbx/events.c (revision 33316)
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*33316Sdonn static char sccsid[] = "@(#)events.c	5.3 (Berkeley) 01/12/88";
921602Sdist #endif not lint
109663Slinton 
11*33316Sdonn static char rcsid[] = "$Header: events.c,v 1.3 87/07/08 18:46:02 donn 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
31*33316Sdonn 
329663Slinton typedef struct Event *Event;
339663Slinton typedef struct Breakpoint *Breakpoint;
349663Slinton 
359663Slinton #include "symbols.h"
369663Slinton 
379663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist)
389663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist)
399663Slinton 
40*33316Sdonn /*
41*33316Sdonn  * When tracing variables we keep a copy of their most recent value
42*33316Sdonn  * and compare it to the current one each time a breakpoint occurs.
43*33316Sdonn  * MAXTRSIZE is the maximum size variable we allow.
44*33316Sdonn  */
45*33316Sdonn 
46*33316Sdonn #define MAXTRSIZE 512
47*33316Sdonn 
489663Slinton #endif
499663Slinton 
50*33316Sdonn public boolean inst_tracing;
51*33316Sdonn public boolean single_stepping;
52*33316Sdonn public boolean isstopped;
53*33316Sdonn 
54*33316Sdonn public Symbol linesym;
55*33316Sdonn public Symbol procsym;
56*33316Sdonn public Symbol pcsym;
57*33316Sdonn public Symbol retaddrsym;
58*33316Sdonn 
599663Slinton struct Event {
609663Slinton     unsigned int id;
6118218Slinton     boolean temporary;
629663Slinton     Node condition;
639663Slinton     Cmdlist actions;
649663Slinton };
659663Slinton 
669663Slinton struct Breakpoint {
679663Slinton     Event event;
689663Slinton     Address bpaddr;
699663Slinton     Lineno bpline;
709663Slinton     Cmdlist actions;
7118218Slinton     boolean temporary;
729663Slinton };
739663Slinton 
749663Slinton typedef List Eventlist;
759663Slinton typedef List Bplist;
769663Slinton 
779663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el)
789663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)
799663Slinton 
809663Slinton private Eventlist eventlist;		/* list of active events */
819663Slinton private Bplist bplist;			/* list of active breakpoints */
8218218Slinton private Event curevent;			/* most recently created event */
8318218Slinton private integer eventid;		/* id number of current event */
8418218Slinton private integer trid;			/* id number of current trace */
859663Slinton 
869663Slinton typedef struct Trcmd {
879663Slinton     Integer trid;
889663Slinton     Event event;
899663Slinton     Cmdlist cmdlist;
909663Slinton } *Trcmd;
919663Slinton 
929663Slinton private List eachline;		/* commands to execute after each line */
939663Slinton private List eachinst;		/* commands to execute after each instruction */
949663Slinton 
959663Slinton private Breakpoint bp_alloc();
969663Slinton 
979663Slinton /*
989663Slinton  * Initialize breakpoint information.
999663Slinton  */
1009663Slinton 
1019663Slinton private Symbol builtinsym(str, class, type)
1029663Slinton String str;
1039663Slinton Symclass class;
1049663Slinton Symbol type;
1059663Slinton {
1069663Slinton     Symbol s;
1079663Slinton 
1089663Slinton     s = insert(identname(str, true));
1099663Slinton     s->language = findlanguage(".s");
1109663Slinton     s->class = class;
1119663Slinton     s->type = type;
1129663Slinton     return s;
1139663Slinton }
1149663Slinton 
1159663Slinton public bpinit()
1169663Slinton {
1179663Slinton     linesym = builtinsym("$line", VAR, t_int);
1189663Slinton     procsym = builtinsym("$proc", PROC, nil);
1199663Slinton     pcsym = lookup(identname("$pc", true));
1209663Slinton     if (pcsym == nil) {
1219663Slinton 	panic("can't find $pc");
1229663Slinton     }
1239663Slinton     retaddrsym = builtinsym("$retaddr", VAR, t_int);
1249663Slinton     eventlist = list_alloc();
1259663Slinton     bplist = list_alloc();
1269663Slinton     eachline = list_alloc();
1279663Slinton     eachinst = list_alloc();
1289663Slinton }
1299663Slinton 
1309663Slinton /*
1319663Slinton  * Trap an event and do the associated commands when it occurs.
1329663Slinton  */
1339663Slinton 
1349663Slinton public Event event_alloc(istmp, econd, cmdlist)
13518218Slinton boolean istmp;
1369663Slinton Node econd;
1379663Slinton Cmdlist cmdlist;
1389663Slinton {
1399663Slinton     register Event e;
1409663Slinton 
1419663Slinton     e = new(Event);
14218218Slinton     ++eventid;
14318218Slinton     e->id = eventid;
1449663Slinton     e->temporary = istmp;
1459663Slinton     e->condition = econd;
1469663Slinton     e->actions = cmdlist;
1479663Slinton     eventlist_append(e, eventlist);
14818218Slinton     curevent = e;
1499663Slinton     translate(e);
1509663Slinton     return e;
1519663Slinton }
1529663Slinton 
1539663Slinton /*
1549663Slinton  * Delete the event with the given id.
15516609Ssam  * Returns whether it's successful or not.
1569663Slinton  */
1579663Slinton 
15816609Ssam public boolean delevent (id)
1599663Slinton unsigned int id;
1609663Slinton {
1619663Slinton     Event e;
1629663Slinton     Breakpoint bp;
1639663Slinton     Trcmd t;
16416609Ssam     boolean found;
1659663Slinton 
16616609Ssam     found = false;
1679663Slinton     foreach (Event, e, eventlist)
1689663Slinton 	if (e->id == id) {
16916609Ssam 	    found = true;
1709663Slinton 	    foreach (Breakpoint, bp, bplist)
1719663Slinton 		if (bp->event == e) {
17218218Slinton 		    if (tracebpts) {
17318218Slinton 			printf("deleting breakpoint at 0x%x\n", bp->bpaddr);
17418218Slinton 			fflush(stdout);
17518218Slinton 		    }
1769663Slinton 		    list_delete(list_curitem(bplist), bplist);
1779663Slinton 		}
1789663Slinton 	    endfor
17916609Ssam 	    list_delete(list_curitem(eventlist), eventlist);
1809663Slinton 	    break;
1819663Slinton 	}
1829663Slinton     endfor
1839663Slinton     foreach (Trcmd, t, eachline)
1849663Slinton 	if (t->event->id == id) {
18516609Ssam 	    found = true;
1869663Slinton 	    printrmtr(t);
1879663Slinton 	    list_delete(list_curitem(eachline), eachline);
1889663Slinton 	}
1899663Slinton     endfor
1909663Slinton     foreach (Trcmd, t, eachinst)
1919663Slinton 	if (t->event->id == id) {
19216609Ssam 	    found = true;
1939663Slinton 	    printrmtr(t);
1949663Slinton 	    list_delete(list_curitem(eachinst), eachinst);
1959663Slinton 	}
1969663Slinton     endfor
1979663Slinton     if (list_size(eachinst) == 0) {
1989663Slinton 	inst_tracing = false;
1999663Slinton 	if (list_size(eachline) == 0) {
2009663Slinton 	    single_stepping = false;
2019663Slinton 	}
2029663Slinton     }
20316609Ssam     return found;
2049663Slinton }
2059663Slinton 
2069663Slinton /*
2079663Slinton  * Translate an event into the appropriate breakpoints and actions.
2089663Slinton  * While we're at it, turn on the breakpoints if the condition is true.
2099663Slinton  */
2109663Slinton 
2119663Slinton private translate(e)
2129663Slinton Event e;
2139663Slinton {
2149663Slinton     Breakpoint bp;
2159663Slinton     Symbol s;
2169663Slinton     Node place;
2179663Slinton     Lineno line;
2189663Slinton     Address addr;
2199663Slinton 
2209663Slinton     checkref(e->condition);
2219663Slinton     switch (e->condition->op) {
2229663Slinton 	case O_EQ:
2239663Slinton 	    if (e->condition->value.arg[0]->op == O_SYM) {
2249663Slinton 		s = e->condition->value.arg[0]->value.sym;
2259663Slinton 		place = e->condition->value.arg[1];
2269663Slinton 		if (s == linesym) {
2279663Slinton 		    if (place->op == O_QLINE) {
2289663Slinton 			line = place->value.arg[1]->value.lcon;
22916609Ssam 			addr = objaddr(line, place->value.arg[0]->value.scon);
2309663Slinton 		    } else {
2319663Slinton 			eval(place);
2329663Slinton 			line = pop(long);
2339663Slinton 			addr = objaddr(line, cursource);
2349663Slinton 		    }
2359663Slinton 		    if (addr == NOADDR) {
23616609Ssam 			if (not delevent(e->id)) {
23716609Ssam 			    printf("!! dbx.translate: can't undo event %d?\n",
23816609Ssam 				e->id);
23916609Ssam 			}
2409663Slinton 			beginerrmsg();
2419663Slinton 			fprintf(stderr, "no executable code at line ");
2429663Slinton 			prtree(stderr, place);
2439663Slinton 			enderrmsg();
2449663Slinton 		    }
2459663Slinton 		    bp = bp_alloc(e, addr, line, e->actions);
2469663Slinton 		} else if (s == procsym) {
2479663Slinton 		    eval(place);
2489663Slinton 		    s = pop(Symbol);
2499663Slinton 		    bp = bp_alloc(e, codeloc(s), 0, e->actions);
2509663Slinton 		    if (isactive(s) and pc != codeloc(program)) {
2519663Slinton 			evalcmdlist(e->actions);
2529663Slinton 		    }
2539663Slinton 		} else if (s == pcsym) {
2549663Slinton 		    eval(place);
2559663Slinton 		    bp = bp_alloc(e, pop(Address), 0, e->actions);
2569663Slinton 		} else {
2579663Slinton 		    condbp(e);
2589663Slinton 		}
2599663Slinton 	    } else {
2609663Slinton 		condbp(e);
2619663Slinton 	    }
2629663Slinton 	    break;
2639663Slinton 
2649663Slinton 	/*
2659663Slinton 	 * These should be handled specially.
2669663Slinton 	 * But for now I'm ignoring the problem.
2679663Slinton 	 */
2689663Slinton 	case O_AND:
2699663Slinton 	case O_OR:
2709663Slinton 	default:
2719663Slinton 	    condbp(e);
2729663Slinton 	    break;
2739663Slinton     }
2749663Slinton }
2759663Slinton 
2769663Slinton /*
2779663Slinton  * Create a breakpoint for a condition that cannot be pinpointed
2789663Slinton  * to happening at a particular address, but one for which we
2799663Slinton  * must single step and check the condition after each statement.
2809663Slinton  */
2819663Slinton 
2829663Slinton private condbp(e)
2839663Slinton Event e;
2849663Slinton {
2859663Slinton     Symbol p;
2869663Slinton     Breakpoint bp;
2879663Slinton     Cmdlist actions;
2889663Slinton 
2899663Slinton     p = tcontainer(e->condition);
2909663Slinton     if (p == nil) {
2919663Slinton 	p = program;
2929663Slinton     }
2939663Slinton     actions = buildcmdlist(build(O_IF, e->condition, e->actions));
2949663Slinton     actions = buildcmdlist(build(O_TRACEON, false, actions));
2959663Slinton     bp = bp_alloc(e, codeloc(p), 0, actions);
2969663Slinton }
2979663Slinton 
2989663Slinton /*
2999663Slinton  * Determine the deepest nested subprogram that still contains
3009663Slinton  * all elements in the given expression.
3019663Slinton  */
3029663Slinton 
3039663Slinton public Symbol tcontainer(exp)
3049663Slinton Node exp;
3059663Slinton {
3069663Slinton     Integer i;
3079663Slinton     Symbol s, t, u, v;
3089663Slinton 
3099663Slinton     checkref(exp);
3109663Slinton     s = nil;
3119663Slinton     if (exp->op == O_SYM) {
3129663Slinton 	s = container(exp->value.sym);
3139663Slinton     } else if (not isleaf(exp->op)) {
3149663Slinton 	for (i = 0; i < nargs(exp->op); i++) {
3159663Slinton 	    t = tcontainer(exp->value.arg[i]);
3169663Slinton 	    if (t != nil) {
3179663Slinton 		if (s == nil) {
3189663Slinton 		    s = t;
3199663Slinton 		} else {
3209663Slinton 		    u = s;
3219663Slinton 		    v = t;
3229663Slinton 		    while (u != v and u != nil) {
3239663Slinton 			u = container(u);
3249663Slinton 			v = container(v);
3259663Slinton 		    }
3269663Slinton 		    if (u == nil) {
3279663Slinton 			panic("bad ancestry for \"%s\"", symname(s));
3289663Slinton 		    } else {
3299663Slinton 			s = u;
3309663Slinton 		    }
3319663Slinton 		}
3329663Slinton 	    }
3339663Slinton 	}
3349663Slinton     }
3359663Slinton     return s;
3369663Slinton }
3379663Slinton 
3389663Slinton /*
33911869Slinton  * Determine if the given function can be executed at full speed.
34011869Slinton  * This can only be done if there are no breakpoints within the function.
34111869Slinton  */
34211869Slinton 
34318218Slinton public boolean canskip(f)
34411869Slinton Symbol f;
34511869Slinton {
34611869Slinton     Breakpoint p;
34718218Slinton     boolean ok;
34811869Slinton 
34911869Slinton     ok = true;
35011869Slinton     foreach (Breakpoint, p, bplist)
35111869Slinton 	if (whatblock(p->bpaddr) == f) {
35211869Slinton 	    ok = false;
35311869Slinton 	    break;
35411869Slinton 	}
35511869Slinton     endfor
35611869Slinton     return ok;
35711869Slinton }
35811869Slinton 
35911869Slinton /*
3609663Slinton  * Print out what's currently being traced by looking at
3619663Slinton  * the currently active events.
3629663Slinton  *
3639663Slinton  * Some convolution here to translate internal representation
3649663Slinton  * of events back into something more palatable.
3659663Slinton  */
3669663Slinton 
3679663Slinton public status()
3689663Slinton {
3699663Slinton     Event e;
3709663Slinton 
3719663Slinton     foreach (Event, e, eventlist)
3729663Slinton 	if (not e->temporary) {
37311869Slinton 	    printevent(e);
3749663Slinton 	}
3759663Slinton     endfor
3769663Slinton }
3779663Slinton 
37811869Slinton public printevent(e)
37911869Slinton Event e;
38011869Slinton {
38111869Slinton     Command cmd;
38211869Slinton 
38311869Slinton     if (not isredirected()) {
38416609Ssam 	printeventid(e->id);
38511869Slinton     }
38611869Slinton     cmd = list_element(Command, list_head(e->actions));
38711869Slinton     if (cmd->op == O_PRINTCALL) {
38811869Slinton 	printf("trace ");
38911869Slinton 	printname(stdout, cmd->value.sym);
39011869Slinton     } else {
39111869Slinton 	if (list_size(e->actions) > 1) {
39211869Slinton 	    printf("{ ");
39311869Slinton 	}
39411869Slinton 	foreach (Command, cmd, e->actions)
39511869Slinton 	    printcmd(stdout, cmd);
39611869Slinton 	    if (not list_islast()) {
39711869Slinton 		printf("; ");
39811869Slinton 	    }
39911869Slinton 	endfor
40011869Slinton 	if (list_size(e->actions) > 1) {
40111869Slinton 	    printf(" }");
40211869Slinton 	}
40311869Slinton 	printcond(e->condition);
40411869Slinton     }
40511869Slinton     printf("\n");
40611869Slinton }
40711869Slinton 
40816609Ssam private printeventid (id)
40916609Ssam integer id;
41016609Ssam {
41116609Ssam     printf("[%d] ", id);
41216609Ssam }
41316609Ssam 
4149663Slinton /*
4159663Slinton  * Print out a condition.
4169663Slinton  */
4179663Slinton 
4189663Slinton private printcond(cond)
4199663Slinton Node cond;
4209663Slinton {
4219663Slinton     Symbol s;
4229663Slinton     Node place;
4239663Slinton 
4249663Slinton     if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) {
4259663Slinton 	s = cond->value.arg[0]->value.sym;
4269663Slinton 	place = cond->value.arg[1];
4279663Slinton 	if (s == procsym) {
4289663Slinton 	    if (place->value.sym != program) {
4299663Slinton 		printf(" in ");
4309663Slinton 		printname(stdout, place->value.sym);
4319663Slinton 	    }
4329663Slinton 	} else if (s == linesym) {
4339663Slinton 	    printf(" at ");
4349663Slinton 	    prtree(stdout, place);
4359663Slinton 	} else if (s == pcsym or s == retaddrsym) {
4369663Slinton 	    printf("i at ");
4379663Slinton 	    prtree(stdout, place);
4389663Slinton 	} else {
4399663Slinton 	    printf(" when ");
4409663Slinton 	    prtree(stdout, cond);
4419663Slinton 	}
4429663Slinton     } else {
4439663Slinton 	printf(" when ");
4449663Slinton 	prtree(stdout, cond);
4459663Slinton     }
4469663Slinton }
4479663Slinton 
4489663Slinton /*
4499663Slinton  * Add a breakpoint to the list and return it.
4509663Slinton  */
4519663Slinton 
4529663Slinton private Breakpoint bp_alloc(e, addr, line, actions)
4539663Slinton Event e;
4549663Slinton Address addr;
4559663Slinton Lineno line;
4569663Slinton Cmdlist actions;
4579663Slinton {
4589663Slinton     register Breakpoint p;
4599663Slinton 
4609663Slinton     p = new(Breakpoint);
4619663Slinton     p->event = e;
4629663Slinton     p->bpaddr = addr;
4639663Slinton     p->bpline = line;
4649663Slinton     p->actions = actions;
46518218Slinton     p->temporary = false;
46618218Slinton     if (tracebpts) {
46718218Slinton 	if (e == nil) {
46830796Sbostic 	    printf("new bp at 0x%x for event ??\n", addr);
46918218Slinton 	} else {
47018218Slinton 	    printf("new bp at 0x%x for event %d\n", addr, e->id);
47118218Slinton 	}
47218218Slinton 	fflush(stdout);
47318218Slinton     }
4749663Slinton     bplist_append(p, bplist);
4759663Slinton     return p;
4769663Slinton }
4779663Slinton 
4789663Slinton /*
4799663Slinton  * Free all storage in the event and breakpoint tables.
4809663Slinton  */
4819663Slinton 
4829663Slinton public bpfree()
4839663Slinton {
4849663Slinton     register Event e;
4859663Slinton 
4869663Slinton     fixbps();
4879663Slinton     foreach (Event, e, eventlist)
48816609Ssam 	if (not delevent(e->id)) {
48916609Ssam 	    printf("!! dbx.bpfree: can't delete event %d\n", e->id);
49016609Ssam 	}
4919663Slinton 	list_delete(list_curitem(eventlist), eventlist);
4929663Slinton     endfor
4939663Slinton }
4949663Slinton 
4959663Slinton /*
4969663Slinton  * Determine if the program stopped at a known breakpoint
4979663Slinton  * and if so do the associated commands.
4989663Slinton  */
4999663Slinton 
50018218Slinton public boolean bpact()
5019663Slinton {
5029663Slinton     register Breakpoint p;
50318218Slinton     boolean found;
50416609Ssam     integer eventId;
5059663Slinton 
5069663Slinton     found = false;
5079663Slinton     foreach (Breakpoint, p, bplist)
5089663Slinton 	if (p->bpaddr == pc) {
50918218Slinton 	    if (tracebpts) {
51018218Slinton 		printf("breakpoint for event %d found at location 0x%x\n",
51118218Slinton 		    p->event->id, pc);
51218218Slinton 	    }
5139663Slinton 	    found = true;
51418218Slinton 	    if (p->event->temporary) {
51518218Slinton 		if (not delevent(p->event->id)) {
51618218Slinton 		    printf("!! dbx.bpact: can't find event %d\n",
51718218Slinton 			p->event->id);
51818218Slinton 		}
51918218Slinton 	    }
5209663Slinton 	    evalcmdlist(p->actions);
52118218Slinton 	    if (isstopped) {
52218218Slinton 		eventId = p->event->id;
52318218Slinton 	    }
52418218Slinton 	    if (p->temporary) {
52518218Slinton 		list_delete(list_curitem(bplist), bplist);
52618218Slinton 	    }
5279663Slinton 	}
5289663Slinton     endfor
5299663Slinton     if (isstopped) {
53016609Ssam 	if (found) {
53116609Ssam 	    printeventid(eventId);
53216609Ssam 	}
5339663Slinton 	printstatus();
5349663Slinton     }
5359663Slinton     fflush(stdout);
5369663Slinton     return found;
5379663Slinton }
5389663Slinton 
5399663Slinton /*
5409663Slinton  * Begin single stepping and executing the given commands after each step.
5419663Slinton  * If the first argument is true step by instructions, otherwise
5429663Slinton  * step by source lines.
5439663Slinton  *
5449663Slinton  * We automatically set a breakpoint at the end of the current procedure
5459663Slinton  * to turn off the given tracing.
5469663Slinton  */
5479663Slinton 
5489663Slinton public traceon(inst, event, cmdlist)
54918218Slinton boolean inst;
5509663Slinton Event event;
5519663Slinton Cmdlist cmdlist;
5529663Slinton {
5539663Slinton     register Trcmd trcmd;
55418218Slinton     Breakpoint bp;
5559663Slinton     Cmdlist actions;
55611869Slinton     Address ret;
55718218Slinton     Event e;
5589663Slinton 
55918218Slinton     if (event == nil) {
56018218Slinton 	e = curevent;
56118218Slinton     } else {
56218218Slinton 	e = event;
56318218Slinton     }
5649663Slinton     trcmd = new(Trcmd);
56518218Slinton     ++trid;
56618218Slinton     trcmd->trid = trid;
56718218Slinton     trcmd->event = e;
5689663Slinton     trcmd->cmdlist = cmdlist;
5699663Slinton     single_stepping = true;
5709663Slinton     if (inst) {
5719663Slinton 	inst_tracing = true;
5729663Slinton 	list_append(list_item(trcmd), nil, eachinst);
5739663Slinton     } else {
5749663Slinton 	list_append(list_item(trcmd), nil, eachline);
5759663Slinton     }
57611869Slinton     ret = return_addr();
57711869Slinton     if (ret != 0) {
57818218Slinton 	actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid));
57918218Slinton 	bp = bp_alloc(e, (Address) ret, 0, actions);
58018218Slinton 	bp->temporary = true;
58111869Slinton     }
58218218Slinton     if (tracebpts) {
58318218Slinton 	printf("adding trace %d for event %d\n", trcmd->trid, e->id);
58418218Slinton     }
5859663Slinton }
5869663Slinton 
5879663Slinton /*
5889663Slinton  * Turn off some kind of tracing.
5899663Slinton  * Strictly an internal command, this cannot be invoked by the user.
5909663Slinton  */
5919663Slinton 
5929663Slinton public traceoff(id)
5939663Slinton Integer id;
5949663Slinton {
5959663Slinton     register Trcmd t;
59618218Slinton     register boolean found;
5979663Slinton 
5989663Slinton     found = false;
5999663Slinton     foreach (Trcmd, t, eachline)
6009663Slinton 	if (t->trid == id) {
6019663Slinton 	    printrmtr(t);
6029663Slinton 	    list_delete(list_curitem(eachline), eachline);
6039663Slinton 	    found = true;
6049663Slinton 	    break;
6059663Slinton 	}
6069663Slinton     endfor
6079663Slinton     if (not found) {
6089663Slinton 	foreach (Trcmd, t, eachinst)
6099663Slinton 	    if (t->event->id == id) {
6109663Slinton 		printrmtr(t);
6119663Slinton 		list_delete(list_curitem(eachinst), eachinst);
6129663Slinton 		found = true;
6139663Slinton 		break;
6149663Slinton 	    }
6159663Slinton 	endfor
6169663Slinton 	if (not found) {
61718218Slinton 	    beginerrmsg();
61818218Slinton 	    fprintf(stderr, "[internal error: trace id %d not found]\n", id);
6199663Slinton 	}
6209663Slinton     }
6219663Slinton     if (list_size(eachinst) == 0) {
6229663Slinton 	inst_tracing = false;
6239663Slinton 	if (list_size(eachline) == 0) {
6249663Slinton 	    single_stepping = false;
6259663Slinton 	}
6269663Slinton     }
6279663Slinton }
6289663Slinton 
6299663Slinton /*
6309663Slinton  * If breakpoints are being traced, note that a Trcmd is being deleted.
6319663Slinton  */
6329663Slinton 
6339663Slinton private printrmtr(t)
6349663Slinton Trcmd t;
6359663Slinton {
63618218Slinton     if (tracebpts) {
63718218Slinton 	printf("removing trace %d", t->trid);
63818218Slinton 	if (t->event != nil) {
63918218Slinton 	    printf(" for event %d", t->event->id);
64018218Slinton 	}
64118218Slinton 	printf("\n");
6429663Slinton     }
6439663Slinton }
6449663Slinton 
6459663Slinton /*
6469663Slinton  * Print out news during single step tracing.
6479663Slinton  */
6489663Slinton 
6499663Slinton public printnews()
6509663Slinton {
6519663Slinton     register Trcmd t;
6529663Slinton 
6539663Slinton     foreach (Trcmd, t, eachline)
6549663Slinton 	evalcmdlist(t->cmdlist);
6559663Slinton     endfor
6569663Slinton     foreach (Trcmd, t, eachinst)
6579663Slinton 	evalcmdlist(t->cmdlist);
6589663Slinton     endfor
6599663Slinton     bpact();
6609663Slinton }
6619663Slinton 
6629663Slinton /*
6639663Slinton  * A procedure call/return has occurred while single-stepping,
6649663Slinton  * note it if we're tracing lines.
6659663Slinton  */
6669663Slinton 
66718218Slinton private boolean chklist();
6689663Slinton 
6699663Slinton public callnews(iscall)
67018218Slinton boolean iscall;
6719663Slinton {
6729663Slinton     if (not chklist(eachline, iscall)) {
6739663Slinton 	chklist(eachinst, iscall);
6749663Slinton     }
6759663Slinton }
6769663Slinton 
67718218Slinton private boolean chklist(list, iscall)
6789663Slinton List list;
67918218Slinton boolean iscall;
6809663Slinton {
6819663Slinton     register Trcmd t;
6829663Slinton     register Command cmd;
6839663Slinton 
68416609Ssam     setcurfunc(whatblock(pc));
6859663Slinton     foreach (Trcmd, t, list)
6869663Slinton 	foreach (Command, cmd, t->cmdlist)
6879663Slinton 	    if (cmd->op == O_PRINTSRCPOS and
6889663Slinton 	      (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) {
6899663Slinton 		if (iscall) {
6909663Slinton 		    printentry(curfunc);
6919663Slinton 		} else {
6929663Slinton 		    printexit(curfunc);
6939663Slinton 		}
6949663Slinton 		return true;
6959663Slinton 	    }
6969663Slinton 	endfor
6979663Slinton     endfor
6989663Slinton     return false;
6999663Slinton }
7009663Slinton 
7019663Slinton /*
7029663Slinton  * List of variables being watched.
7039663Slinton  */
7049663Slinton 
7059663Slinton typedef struct Trinfo *Trinfo;
7069663Slinton 
7079663Slinton struct Trinfo {
7089663Slinton     Node variable;
7099663Slinton     Address traddr;
7109663Slinton     Symbol trblock;
7119663Slinton     char *trvalue;
7129663Slinton };
7139663Slinton 
7149663Slinton private List trinfolist;
7159663Slinton 
7169663Slinton /*
7179663Slinton  * Find the trace information record associated with the given record.
7189663Slinton  * If there isn't one then create it and add it to the list.
7199663Slinton  */
7209663Slinton 
7219663Slinton private Trinfo findtrinfo(p)
7229663Slinton Node p;
7239663Slinton {
7249663Slinton     register Trinfo tp;
72518218Slinton     boolean isnew;
7269663Slinton 
7279663Slinton     isnew = true;
7289663Slinton     if (trinfolist == nil) {
7299663Slinton 	trinfolist = list_alloc();
7309663Slinton     } else {
7319663Slinton 	foreach (Trinfo, tp, trinfolist)
7329663Slinton 	    if (tp->variable == p) {
7339663Slinton 		isnew = false;
7349663Slinton 		break;
7359663Slinton 	    }
7369663Slinton 	endfor
7379663Slinton     }
7389663Slinton     if (isnew) {
7399663Slinton 	if (tracebpts) {
7409663Slinton 	    printf("adding trinfo for \"");
7419663Slinton 	    prtree(stdout, p);
7429663Slinton 	    printf("\"\n");
7439663Slinton 	}
7449663Slinton 	tp = new(Trinfo);
7459663Slinton 	tp->variable = p;
7469663Slinton 	tp->traddr = lval(p);
7479663Slinton 	tp->trvalue = nil;
7489663Slinton 	list_append(list_item(tp), nil, trinfolist);
7499663Slinton     }
7509663Slinton     return tp;
7519663Slinton }
7529663Slinton 
7539663Slinton /*
7549663Slinton  * Print out the value of a variable if it has changed since the
7559663Slinton  * last time we checked.
7569663Slinton  */
7579663Slinton 
7589663Slinton public printifchanged(p)
7599663Slinton Node p;
7609663Slinton {
7619663Slinton     register Trinfo tp;
7629663Slinton     register int n;
7639663Slinton     char buff[MAXTRSIZE];
76418218Slinton     Filename curfile;
7659663Slinton     static Lineno prevline;
76618218Slinton     static Filename prevfile;
7679663Slinton 
7689663Slinton     tp = findtrinfo(p);
7699663Slinton     n = size(p->nodetype);
77018218Slinton     dread(buff, tp->traddr, n);
77118218Slinton     curfile = srcfilename(pc);
7729663Slinton     if (tp->trvalue == nil) {
7739663Slinton 	tp->trvalue = newarr(char, n);
7749663Slinton 	mov(buff, tp->trvalue, n);
7759663Slinton 	mov(buff, sp, n);
7769663Slinton 	sp += n;
77718218Slinton 	printf("initially (at line %d in \"%s\"):\t", curline, curfile);
7789663Slinton 	prtree(stdout, p);
7799663Slinton 	printf(" = ");
7809663Slinton 	printval(p->nodetype);
7819663Slinton 	putchar('\n');
7829663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
7839663Slinton 	mov(buff, tp->trvalue, n);
7849663Slinton 	mov(buff, sp, n);
7859663Slinton 	sp += n;
78618218Slinton 	printf("after line %d in \"%s\":\t", prevline, prevfile);
7879663Slinton 	prtree(stdout, p);
7889663Slinton 	printf(" = ");
7899663Slinton 	printval(p->nodetype);
7909663Slinton 	putchar('\n');
7919663Slinton     }
7929663Slinton     prevline = curline;
79318218Slinton     prevfile = curfile;
7949663Slinton }
7959663Slinton 
7969663Slinton /*
7979663Slinton  * Stop if the value of the given expression has changed.
7989663Slinton  */
7999663Slinton 
8009663Slinton public stopifchanged(p)
8019663Slinton Node p;
8029663Slinton {
8039663Slinton     register Trinfo tp;
8049663Slinton     register int n;
8059663Slinton     char buff[MAXTRSIZE];
8069663Slinton     static Lineno prevline;
8079663Slinton 
8089663Slinton     tp = findtrinfo(p);
8099663Slinton     n = size(p->nodetype);
8109663Slinton     dread(buff, tp->traddr, n);
8119663Slinton     if (tp->trvalue == nil) {
8129663Slinton 	tp->trvalue = newarr(char, n);
8139663Slinton 	mov(buff, tp->trvalue, n);
8149663Slinton 	isstopped = true;
8159663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
8169663Slinton 	mov(buff, tp->trvalue, n);
81716609Ssam 	mov(buff, sp, n);
81816609Ssam 	sp += n;
81916609Ssam 	printf("after line %d:\t", prevline);
82016609Ssam 	prtree(stdout, p);
82116609Ssam 	printf(" = ");
82216609Ssam 	printval(p->nodetype);
82316609Ssam 	putchar('\n');
8249663Slinton 	isstopped = true;
8259663Slinton     }
8269663Slinton     prevline = curline;
8279663Slinton }
8289663Slinton 
8299663Slinton /*
8309663Slinton  * Free the tracing table.
8319663Slinton  */
8329663Slinton 
8339663Slinton public trfree()
8349663Slinton {
8359663Slinton     register Trinfo tp;
8369663Slinton 
8379663Slinton     foreach (Trinfo, tp, trinfolist)
8389663Slinton 	dispose(tp->trvalue);
8399663Slinton 	dispose(tp);
8409663Slinton 	list_delete(list_curitem(trinfolist), trinfolist);
8419663Slinton     endfor
8429663Slinton }
8439663Slinton 
8449663Slinton /*
8459663Slinton  * Fix up breakpoint information before continuing execution.
8469663Slinton  *
8479663Slinton  * It's necessary to destroy events and breakpoints that were created
8489663Slinton  * temporarily and still exist because the program terminated abnormally.
8499663Slinton  */
8509663Slinton 
8519663Slinton public fixbps()
8529663Slinton {
8539663Slinton     register Event e;
8549663Slinton     register Trcmd t;
8559663Slinton 
8569663Slinton     single_stepping = false;
8579663Slinton     inst_tracing = false;
8589663Slinton     trfree();
8599663Slinton     foreach (Event, e, eventlist)
8609663Slinton 	if (e->temporary) {
86116609Ssam 	    if (not delevent(e->id)) {
86216609Ssam 		printf("!! dbx.fixbps: can't find event %d\n", e->id);
86316609Ssam 	    }
8649663Slinton 	}
8659663Slinton     endfor
8669663Slinton     foreach (Trcmd, t, eachline)
8679663Slinton 	printrmtr(t);
8689663Slinton 	list_delete(list_curitem(eachline), eachline);
8699663Slinton     endfor
8709663Slinton     foreach (Trcmd, t, eachinst)
8719663Slinton 	printrmtr(t);
8729663Slinton 	list_delete(list_curitem(eachinst), eachinst);
8739663Slinton     endfor
8749663Slinton }
8759663Slinton 
8769663Slinton /*
8779663Slinton  * Set all breakpoints in object code.
8789663Slinton  */
8799663Slinton 
8809663Slinton public setallbps()
8819663Slinton {
8829663Slinton     register Breakpoint p;
8839663Slinton 
8849663Slinton     foreach (Breakpoint, p, bplist)
8859663Slinton 	setbp(p->bpaddr);
8869663Slinton     endfor
8879663Slinton }
8889663Slinton 
8899663Slinton /*
8909663Slinton  * Undo damage done by "setallbps".
8919663Slinton  */
8929663Slinton 
8939663Slinton public unsetallbps()
8949663Slinton {
8959663Slinton     register Breakpoint p;
8969663Slinton 
8979663Slinton     foreach (Breakpoint, p, bplist)
8989663Slinton 	unsetbp(p->bpaddr);
8999663Slinton     endfor
9009663Slinton }
901