xref: /csrg-svn/old/dbx/events.c (revision 38105)
121602Sdist /*
2*38105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3*38105Sbostic  * All rights reserved.
4*38105Sbostic  *
5*38105Sbostic  * Redistribution and use in source and binary forms are permitted
6*38105Sbostic  * provided that the above copyright notice and this paragraph are
7*38105Sbostic  * duplicated in all such forms and that any documentation,
8*38105Sbostic  * advertising materials, and other materials related to such
9*38105Sbostic  * distribution and use acknowledge that the software was developed
10*38105Sbostic  * by the University of California, Berkeley.  The name of the
11*38105Sbostic  * University may not be used to endorse or promote products derived
12*38105Sbostic  * from this software without specific prior written permission.
13*38105Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*38105Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*38105Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621602Sdist  */
179663Slinton 
1821602Sdist #ifndef lint
19*38105Sbostic static char sccsid[] = "@(#)events.c	5.4 (Berkeley) 05/23/89";
20*38105Sbostic #endif /* not lint */
219663Slinton 
229663Slinton /*
239663Slinton  * Event/breakpoint managment.
249663Slinton  */
259663Slinton 
269663Slinton #include "defs.h"
279663Slinton #include "events.h"
289663Slinton #include "main.h"
299663Slinton #include "symbols.h"
309663Slinton #include "tree.h"
319663Slinton #include "eval.h"
329663Slinton #include "source.h"
339663Slinton #include "mappings.h"
3416609Ssam #include "runtime.h"
359663Slinton #include "process.h"
369663Slinton #include "machine.h"
379663Slinton #include "lists.h"
389663Slinton 
399663Slinton #ifndef public
4033316Sdonn 
419663Slinton typedef struct Event *Event;
429663Slinton typedef struct Breakpoint *Breakpoint;
439663Slinton 
449663Slinton #include "symbols.h"
459663Slinton 
469663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist)
479663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist)
489663Slinton 
4933316Sdonn /*
5033316Sdonn  * When tracing variables we keep a copy of their most recent value
5133316Sdonn  * and compare it to the current one each time a breakpoint occurs.
5233316Sdonn  * MAXTRSIZE is the maximum size variable we allow.
5333316Sdonn  */
5433316Sdonn 
5533316Sdonn #define MAXTRSIZE 512
5633316Sdonn 
579663Slinton #endif
589663Slinton 
5933316Sdonn public boolean inst_tracing;
6033316Sdonn public boolean single_stepping;
6133316Sdonn public boolean isstopped;
6233316Sdonn 
6333316Sdonn public Symbol linesym;
6433316Sdonn public Symbol procsym;
6533316Sdonn public Symbol pcsym;
6633316Sdonn public Symbol retaddrsym;
6733316Sdonn 
689663Slinton struct Event {
699663Slinton     unsigned int id;
7018218Slinton     boolean temporary;
719663Slinton     Node condition;
729663Slinton     Cmdlist actions;
739663Slinton };
749663Slinton 
759663Slinton struct Breakpoint {
769663Slinton     Event event;
779663Slinton     Address bpaddr;
789663Slinton     Lineno bpline;
799663Slinton     Cmdlist actions;
8018218Slinton     boolean temporary;
819663Slinton };
829663Slinton 
839663Slinton typedef List Eventlist;
849663Slinton typedef List Bplist;
859663Slinton 
869663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el)
879663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)
889663Slinton 
899663Slinton private Eventlist eventlist;		/* list of active events */
909663Slinton private Bplist bplist;			/* list of active breakpoints */
9118218Slinton private Event curevent;			/* most recently created event */
9218218Slinton private integer eventid;		/* id number of current event */
9318218Slinton private integer trid;			/* id number of current trace */
949663Slinton 
959663Slinton typedef struct Trcmd {
969663Slinton     Integer trid;
979663Slinton     Event event;
989663Slinton     Cmdlist cmdlist;
999663Slinton } *Trcmd;
1009663Slinton 
1019663Slinton private List eachline;		/* commands to execute after each line */
1029663Slinton private List eachinst;		/* commands to execute after each instruction */
1039663Slinton 
1049663Slinton private Breakpoint bp_alloc();
1059663Slinton 
1069663Slinton /*
1079663Slinton  * Initialize breakpoint information.
1089663Slinton  */
1099663Slinton 
1109663Slinton private Symbol builtinsym(str, class, type)
1119663Slinton String str;
1129663Slinton Symclass class;
1139663Slinton Symbol type;
1149663Slinton {
1159663Slinton     Symbol s;
1169663Slinton 
1179663Slinton     s = insert(identname(str, true));
1189663Slinton     s->language = findlanguage(".s");
1199663Slinton     s->class = class;
1209663Slinton     s->type = type;
1219663Slinton     return s;
1229663Slinton }
1239663Slinton 
1249663Slinton public bpinit()
1259663Slinton {
1269663Slinton     linesym = builtinsym("$line", VAR, t_int);
1279663Slinton     procsym = builtinsym("$proc", PROC, nil);
1289663Slinton     pcsym = lookup(identname("$pc", true));
1299663Slinton     if (pcsym == nil) {
1309663Slinton 	panic("can't find $pc");
1319663Slinton     }
1329663Slinton     retaddrsym = builtinsym("$retaddr", VAR, t_int);
1339663Slinton     eventlist = list_alloc();
1349663Slinton     bplist = list_alloc();
1359663Slinton     eachline = list_alloc();
1369663Slinton     eachinst = list_alloc();
1379663Slinton }
1389663Slinton 
1399663Slinton /*
1409663Slinton  * Trap an event and do the associated commands when it occurs.
1419663Slinton  */
1429663Slinton 
1439663Slinton public Event event_alloc(istmp, econd, cmdlist)
14418218Slinton boolean istmp;
1459663Slinton Node econd;
1469663Slinton Cmdlist cmdlist;
1479663Slinton {
1489663Slinton     register Event e;
1499663Slinton 
1509663Slinton     e = new(Event);
15118218Slinton     ++eventid;
15218218Slinton     e->id = eventid;
1539663Slinton     e->temporary = istmp;
1549663Slinton     e->condition = econd;
1559663Slinton     e->actions = cmdlist;
1569663Slinton     eventlist_append(e, eventlist);
15718218Slinton     curevent = e;
1589663Slinton     translate(e);
1599663Slinton     return e;
1609663Slinton }
1619663Slinton 
1629663Slinton /*
1639663Slinton  * Delete the event with the given id.
16416609Ssam  * Returns whether it's successful or not.
1659663Slinton  */
1669663Slinton 
16716609Ssam public boolean delevent (id)
1689663Slinton unsigned int id;
1699663Slinton {
1709663Slinton     Event e;
1719663Slinton     Breakpoint bp;
1729663Slinton     Trcmd t;
17316609Ssam     boolean found;
1749663Slinton 
17516609Ssam     found = false;
1769663Slinton     foreach (Event, e, eventlist)
1779663Slinton 	if (e->id == id) {
17816609Ssam 	    found = true;
1799663Slinton 	    foreach (Breakpoint, bp, bplist)
1809663Slinton 		if (bp->event == e) {
18118218Slinton 		    if (tracebpts) {
18218218Slinton 			printf("deleting breakpoint at 0x%x\n", bp->bpaddr);
18318218Slinton 			fflush(stdout);
18418218Slinton 		    }
1859663Slinton 		    list_delete(list_curitem(bplist), bplist);
1869663Slinton 		}
1879663Slinton 	    endfor
18816609Ssam 	    list_delete(list_curitem(eventlist), eventlist);
1899663Slinton 	    break;
1909663Slinton 	}
1919663Slinton     endfor
1929663Slinton     foreach (Trcmd, t, eachline)
1939663Slinton 	if (t->event->id == id) {
19416609Ssam 	    found = true;
1959663Slinton 	    printrmtr(t);
1969663Slinton 	    list_delete(list_curitem(eachline), eachline);
1979663Slinton 	}
1989663Slinton     endfor
1999663Slinton     foreach (Trcmd, t, eachinst)
2009663Slinton 	if (t->event->id == id) {
20116609Ssam 	    found = true;
2029663Slinton 	    printrmtr(t);
2039663Slinton 	    list_delete(list_curitem(eachinst), eachinst);
2049663Slinton 	}
2059663Slinton     endfor
2069663Slinton     if (list_size(eachinst) == 0) {
2079663Slinton 	inst_tracing = false;
2089663Slinton 	if (list_size(eachline) == 0) {
2099663Slinton 	    single_stepping = false;
2109663Slinton 	}
2119663Slinton     }
21216609Ssam     return found;
2139663Slinton }
2149663Slinton 
2159663Slinton /*
2169663Slinton  * Translate an event into the appropriate breakpoints and actions.
2179663Slinton  * While we're at it, turn on the breakpoints if the condition is true.
2189663Slinton  */
2199663Slinton 
2209663Slinton private translate(e)
2219663Slinton Event e;
2229663Slinton {
2239663Slinton     Breakpoint bp;
2249663Slinton     Symbol s;
2259663Slinton     Node place;
2269663Slinton     Lineno line;
2279663Slinton     Address addr;
2289663Slinton 
2299663Slinton     checkref(e->condition);
2309663Slinton     switch (e->condition->op) {
2319663Slinton 	case O_EQ:
2329663Slinton 	    if (e->condition->value.arg[0]->op == O_SYM) {
2339663Slinton 		s = e->condition->value.arg[0]->value.sym;
2349663Slinton 		place = e->condition->value.arg[1];
2359663Slinton 		if (s == linesym) {
2369663Slinton 		    if (place->op == O_QLINE) {
2379663Slinton 			line = place->value.arg[1]->value.lcon;
23816609Ssam 			addr = objaddr(line, place->value.arg[0]->value.scon);
2399663Slinton 		    } else {
2409663Slinton 			eval(place);
2419663Slinton 			line = pop(long);
2429663Slinton 			addr = objaddr(line, cursource);
2439663Slinton 		    }
2449663Slinton 		    if (addr == NOADDR) {
24516609Ssam 			if (not delevent(e->id)) {
24616609Ssam 			    printf("!! dbx.translate: can't undo event %d?\n",
24716609Ssam 				e->id);
24816609Ssam 			}
2499663Slinton 			beginerrmsg();
2509663Slinton 			fprintf(stderr, "no executable code at line ");
2519663Slinton 			prtree(stderr, place);
2529663Slinton 			enderrmsg();
2539663Slinton 		    }
2549663Slinton 		    bp = bp_alloc(e, addr, line, e->actions);
2559663Slinton 		} else if (s == procsym) {
2569663Slinton 		    eval(place);
2579663Slinton 		    s = pop(Symbol);
2589663Slinton 		    bp = bp_alloc(e, codeloc(s), 0, e->actions);
2599663Slinton 		    if (isactive(s) and pc != codeloc(program)) {
2609663Slinton 			evalcmdlist(e->actions);
2619663Slinton 		    }
2629663Slinton 		} else if (s == pcsym) {
2639663Slinton 		    eval(place);
2649663Slinton 		    bp = bp_alloc(e, pop(Address), 0, e->actions);
2659663Slinton 		} else {
2669663Slinton 		    condbp(e);
2679663Slinton 		}
2689663Slinton 	    } else {
2699663Slinton 		condbp(e);
2709663Slinton 	    }
2719663Slinton 	    break;
2729663Slinton 
2739663Slinton 	/*
2749663Slinton 	 * These should be handled specially.
2759663Slinton 	 * But for now I'm ignoring the problem.
2769663Slinton 	 */
2779663Slinton 	case O_AND:
2789663Slinton 	case O_OR:
2799663Slinton 	default:
2809663Slinton 	    condbp(e);
2819663Slinton 	    break;
2829663Slinton     }
2839663Slinton }
2849663Slinton 
2859663Slinton /*
2869663Slinton  * Create a breakpoint for a condition that cannot be pinpointed
2879663Slinton  * to happening at a particular address, but one for which we
2889663Slinton  * must single step and check the condition after each statement.
2899663Slinton  */
2909663Slinton 
2919663Slinton private condbp(e)
2929663Slinton Event e;
2939663Slinton {
2949663Slinton     Symbol p;
2959663Slinton     Breakpoint bp;
2969663Slinton     Cmdlist actions;
2979663Slinton 
2989663Slinton     p = tcontainer(e->condition);
2999663Slinton     if (p == nil) {
3009663Slinton 	p = program;
3019663Slinton     }
3029663Slinton     actions = buildcmdlist(build(O_IF, e->condition, e->actions));
3039663Slinton     actions = buildcmdlist(build(O_TRACEON, false, actions));
3049663Slinton     bp = bp_alloc(e, codeloc(p), 0, actions);
3059663Slinton }
3069663Slinton 
3079663Slinton /*
3089663Slinton  * Determine the deepest nested subprogram that still contains
3099663Slinton  * all elements in the given expression.
3109663Slinton  */
3119663Slinton 
3129663Slinton public Symbol tcontainer(exp)
3139663Slinton Node exp;
3149663Slinton {
3159663Slinton     Integer i;
3169663Slinton     Symbol s, t, u, v;
3179663Slinton 
3189663Slinton     checkref(exp);
3199663Slinton     s = nil;
3209663Slinton     if (exp->op == O_SYM) {
3219663Slinton 	s = container(exp->value.sym);
3229663Slinton     } else if (not isleaf(exp->op)) {
3239663Slinton 	for (i = 0; i < nargs(exp->op); i++) {
3249663Slinton 	    t = tcontainer(exp->value.arg[i]);
3259663Slinton 	    if (t != nil) {
3269663Slinton 		if (s == nil) {
3279663Slinton 		    s = t;
3289663Slinton 		} else {
3299663Slinton 		    u = s;
3309663Slinton 		    v = t;
3319663Slinton 		    while (u != v and u != nil) {
3329663Slinton 			u = container(u);
3339663Slinton 			v = container(v);
3349663Slinton 		    }
3359663Slinton 		    if (u == nil) {
3369663Slinton 			panic("bad ancestry for \"%s\"", symname(s));
3379663Slinton 		    } else {
3389663Slinton 			s = u;
3399663Slinton 		    }
3409663Slinton 		}
3419663Slinton 	    }
3429663Slinton 	}
3439663Slinton     }
3449663Slinton     return s;
3459663Slinton }
3469663Slinton 
3479663Slinton /*
34811869Slinton  * Determine if the given function can be executed at full speed.
34911869Slinton  * This can only be done if there are no breakpoints within the function.
35011869Slinton  */
35111869Slinton 
35218218Slinton public boolean canskip(f)
35311869Slinton Symbol f;
35411869Slinton {
35511869Slinton     Breakpoint p;
35618218Slinton     boolean ok;
35711869Slinton 
35811869Slinton     ok = true;
35911869Slinton     foreach (Breakpoint, p, bplist)
36011869Slinton 	if (whatblock(p->bpaddr) == f) {
36111869Slinton 	    ok = false;
36211869Slinton 	    break;
36311869Slinton 	}
36411869Slinton     endfor
36511869Slinton     return ok;
36611869Slinton }
36711869Slinton 
36811869Slinton /*
3699663Slinton  * Print out what's currently being traced by looking at
3709663Slinton  * the currently active events.
3719663Slinton  *
3729663Slinton  * Some convolution here to translate internal representation
3739663Slinton  * of events back into something more palatable.
3749663Slinton  */
3759663Slinton 
3769663Slinton public status()
3779663Slinton {
3789663Slinton     Event e;
3799663Slinton 
3809663Slinton     foreach (Event, e, eventlist)
3819663Slinton 	if (not e->temporary) {
38211869Slinton 	    printevent(e);
3839663Slinton 	}
3849663Slinton     endfor
3859663Slinton }
3869663Slinton 
38711869Slinton public printevent(e)
38811869Slinton Event e;
38911869Slinton {
39011869Slinton     Command cmd;
39111869Slinton 
39211869Slinton     if (not isredirected()) {
39316609Ssam 	printeventid(e->id);
39411869Slinton     }
39511869Slinton     cmd = list_element(Command, list_head(e->actions));
39611869Slinton     if (cmd->op == O_PRINTCALL) {
39711869Slinton 	printf("trace ");
39811869Slinton 	printname(stdout, cmd->value.sym);
39911869Slinton     } else {
40011869Slinton 	if (list_size(e->actions) > 1) {
40111869Slinton 	    printf("{ ");
40211869Slinton 	}
40311869Slinton 	foreach (Command, cmd, e->actions)
40411869Slinton 	    printcmd(stdout, cmd);
40511869Slinton 	    if (not list_islast()) {
40611869Slinton 		printf("; ");
40711869Slinton 	    }
40811869Slinton 	endfor
40911869Slinton 	if (list_size(e->actions) > 1) {
41011869Slinton 	    printf(" }");
41111869Slinton 	}
41211869Slinton 	printcond(e->condition);
41311869Slinton     }
41411869Slinton     printf("\n");
41511869Slinton }
41611869Slinton 
41716609Ssam private printeventid (id)
41816609Ssam integer id;
41916609Ssam {
42016609Ssam     printf("[%d] ", id);
42116609Ssam }
42216609Ssam 
4239663Slinton /*
4249663Slinton  * Print out a condition.
4259663Slinton  */
4269663Slinton 
4279663Slinton private printcond(cond)
4289663Slinton Node cond;
4299663Slinton {
4309663Slinton     Symbol s;
4319663Slinton     Node place;
4329663Slinton 
4339663Slinton     if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) {
4349663Slinton 	s = cond->value.arg[0]->value.sym;
4359663Slinton 	place = cond->value.arg[1];
4369663Slinton 	if (s == procsym) {
4379663Slinton 	    if (place->value.sym != program) {
4389663Slinton 		printf(" in ");
4399663Slinton 		printname(stdout, place->value.sym);
4409663Slinton 	    }
4419663Slinton 	} else if (s == linesym) {
4429663Slinton 	    printf(" at ");
4439663Slinton 	    prtree(stdout, place);
4449663Slinton 	} else if (s == pcsym or s == retaddrsym) {
4459663Slinton 	    printf("i at ");
4469663Slinton 	    prtree(stdout, place);
4479663Slinton 	} else {
4489663Slinton 	    printf(" when ");
4499663Slinton 	    prtree(stdout, cond);
4509663Slinton 	}
4519663Slinton     } else {
4529663Slinton 	printf(" when ");
4539663Slinton 	prtree(stdout, cond);
4549663Slinton     }
4559663Slinton }
4569663Slinton 
4579663Slinton /*
4589663Slinton  * Add a breakpoint to the list and return it.
4599663Slinton  */
4609663Slinton 
4619663Slinton private Breakpoint bp_alloc(e, addr, line, actions)
4629663Slinton Event e;
4639663Slinton Address addr;
4649663Slinton Lineno line;
4659663Slinton Cmdlist actions;
4669663Slinton {
4679663Slinton     register Breakpoint p;
4689663Slinton 
4699663Slinton     p = new(Breakpoint);
4709663Slinton     p->event = e;
4719663Slinton     p->bpaddr = addr;
4729663Slinton     p->bpline = line;
4739663Slinton     p->actions = actions;
47418218Slinton     p->temporary = false;
47518218Slinton     if (tracebpts) {
47618218Slinton 	if (e == nil) {
47730796Sbostic 	    printf("new bp at 0x%x for event ??\n", addr);
47818218Slinton 	} else {
47918218Slinton 	    printf("new bp at 0x%x for event %d\n", addr, e->id);
48018218Slinton 	}
48118218Slinton 	fflush(stdout);
48218218Slinton     }
4839663Slinton     bplist_append(p, bplist);
4849663Slinton     return p;
4859663Slinton }
4869663Slinton 
4879663Slinton /*
4889663Slinton  * Free all storage in the event and breakpoint tables.
4899663Slinton  */
4909663Slinton 
4919663Slinton public bpfree()
4929663Slinton {
4939663Slinton     register Event e;
4949663Slinton 
4959663Slinton     fixbps();
4969663Slinton     foreach (Event, e, eventlist)
49716609Ssam 	if (not delevent(e->id)) {
49816609Ssam 	    printf("!! dbx.bpfree: can't delete event %d\n", e->id);
49916609Ssam 	}
5009663Slinton 	list_delete(list_curitem(eventlist), eventlist);
5019663Slinton     endfor
5029663Slinton }
5039663Slinton 
5049663Slinton /*
5059663Slinton  * Determine if the program stopped at a known breakpoint
5069663Slinton  * and if so do the associated commands.
5079663Slinton  */
5089663Slinton 
50918218Slinton public boolean bpact()
5109663Slinton {
5119663Slinton     register Breakpoint p;
51218218Slinton     boolean found;
51316609Ssam     integer eventId;
5149663Slinton 
5159663Slinton     found = false;
5169663Slinton     foreach (Breakpoint, p, bplist)
5179663Slinton 	if (p->bpaddr == pc) {
51818218Slinton 	    if (tracebpts) {
51918218Slinton 		printf("breakpoint for event %d found at location 0x%x\n",
52018218Slinton 		    p->event->id, pc);
52118218Slinton 	    }
5229663Slinton 	    found = true;
52318218Slinton 	    if (p->event->temporary) {
52418218Slinton 		if (not delevent(p->event->id)) {
52518218Slinton 		    printf("!! dbx.bpact: can't find event %d\n",
52618218Slinton 			p->event->id);
52718218Slinton 		}
52818218Slinton 	    }
5299663Slinton 	    evalcmdlist(p->actions);
53018218Slinton 	    if (isstopped) {
53118218Slinton 		eventId = p->event->id;
53218218Slinton 	    }
53318218Slinton 	    if (p->temporary) {
53418218Slinton 		list_delete(list_curitem(bplist), bplist);
53518218Slinton 	    }
5369663Slinton 	}
5379663Slinton     endfor
5389663Slinton     if (isstopped) {
53916609Ssam 	if (found) {
54016609Ssam 	    printeventid(eventId);
54116609Ssam 	}
5429663Slinton 	printstatus();
5439663Slinton     }
5449663Slinton     fflush(stdout);
5459663Slinton     return found;
5469663Slinton }
5479663Slinton 
5489663Slinton /*
5499663Slinton  * Begin single stepping and executing the given commands after each step.
5509663Slinton  * If the first argument is true step by instructions, otherwise
5519663Slinton  * step by source lines.
5529663Slinton  *
5539663Slinton  * We automatically set a breakpoint at the end of the current procedure
5549663Slinton  * to turn off the given tracing.
5559663Slinton  */
5569663Slinton 
5579663Slinton public traceon(inst, event, cmdlist)
55818218Slinton boolean inst;
5599663Slinton Event event;
5609663Slinton Cmdlist cmdlist;
5619663Slinton {
5629663Slinton     register Trcmd trcmd;
56318218Slinton     Breakpoint bp;
5649663Slinton     Cmdlist actions;
56511869Slinton     Address ret;
56618218Slinton     Event e;
5679663Slinton 
56818218Slinton     if (event == nil) {
56918218Slinton 	e = curevent;
57018218Slinton     } else {
57118218Slinton 	e = event;
57218218Slinton     }
5739663Slinton     trcmd = new(Trcmd);
57418218Slinton     ++trid;
57518218Slinton     trcmd->trid = trid;
57618218Slinton     trcmd->event = e;
5779663Slinton     trcmd->cmdlist = cmdlist;
5789663Slinton     single_stepping = true;
5799663Slinton     if (inst) {
5809663Slinton 	inst_tracing = true;
5819663Slinton 	list_append(list_item(trcmd), nil, eachinst);
5829663Slinton     } else {
5839663Slinton 	list_append(list_item(trcmd), nil, eachline);
5849663Slinton     }
58511869Slinton     ret = return_addr();
58611869Slinton     if (ret != 0) {
58718218Slinton 	actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid));
58818218Slinton 	bp = bp_alloc(e, (Address) ret, 0, actions);
58918218Slinton 	bp->temporary = true;
59011869Slinton     }
59118218Slinton     if (tracebpts) {
59218218Slinton 	printf("adding trace %d for event %d\n", trcmd->trid, e->id);
59318218Slinton     }
5949663Slinton }
5959663Slinton 
5969663Slinton /*
5979663Slinton  * Turn off some kind of tracing.
5989663Slinton  * Strictly an internal command, this cannot be invoked by the user.
5999663Slinton  */
6009663Slinton 
6019663Slinton public traceoff(id)
6029663Slinton Integer id;
6039663Slinton {
6049663Slinton     register Trcmd t;
60518218Slinton     register boolean found;
6069663Slinton 
6079663Slinton     found = false;
6089663Slinton     foreach (Trcmd, t, eachline)
6099663Slinton 	if (t->trid == id) {
6109663Slinton 	    printrmtr(t);
6119663Slinton 	    list_delete(list_curitem(eachline), eachline);
6129663Slinton 	    found = true;
6139663Slinton 	    break;
6149663Slinton 	}
6159663Slinton     endfor
6169663Slinton     if (not found) {
6179663Slinton 	foreach (Trcmd, t, eachinst)
6189663Slinton 	    if (t->event->id == id) {
6199663Slinton 		printrmtr(t);
6209663Slinton 		list_delete(list_curitem(eachinst), eachinst);
6219663Slinton 		found = true;
6229663Slinton 		break;
6239663Slinton 	    }
6249663Slinton 	endfor
6259663Slinton 	if (not found) {
62618218Slinton 	    beginerrmsg();
62718218Slinton 	    fprintf(stderr, "[internal error: trace id %d not found]\n", id);
6289663Slinton 	}
6299663Slinton     }
6309663Slinton     if (list_size(eachinst) == 0) {
6319663Slinton 	inst_tracing = false;
6329663Slinton 	if (list_size(eachline) == 0) {
6339663Slinton 	    single_stepping = false;
6349663Slinton 	}
6359663Slinton     }
6369663Slinton }
6379663Slinton 
6389663Slinton /*
6399663Slinton  * If breakpoints are being traced, note that a Trcmd is being deleted.
6409663Slinton  */
6419663Slinton 
6429663Slinton private printrmtr(t)
6439663Slinton Trcmd t;
6449663Slinton {
64518218Slinton     if (tracebpts) {
64618218Slinton 	printf("removing trace %d", t->trid);
64718218Slinton 	if (t->event != nil) {
64818218Slinton 	    printf(" for event %d", t->event->id);
64918218Slinton 	}
65018218Slinton 	printf("\n");
6519663Slinton     }
6529663Slinton }
6539663Slinton 
6549663Slinton /*
6559663Slinton  * Print out news during single step tracing.
6569663Slinton  */
6579663Slinton 
6589663Slinton public printnews()
6599663Slinton {
6609663Slinton     register Trcmd t;
6619663Slinton 
6629663Slinton     foreach (Trcmd, t, eachline)
6639663Slinton 	evalcmdlist(t->cmdlist);
6649663Slinton     endfor
6659663Slinton     foreach (Trcmd, t, eachinst)
6669663Slinton 	evalcmdlist(t->cmdlist);
6679663Slinton     endfor
6689663Slinton     bpact();
6699663Slinton }
6709663Slinton 
6719663Slinton /*
6729663Slinton  * A procedure call/return has occurred while single-stepping,
6739663Slinton  * note it if we're tracing lines.
6749663Slinton  */
6759663Slinton 
67618218Slinton private boolean chklist();
6779663Slinton 
6789663Slinton public callnews(iscall)
67918218Slinton boolean iscall;
6809663Slinton {
6819663Slinton     if (not chklist(eachline, iscall)) {
6829663Slinton 	chklist(eachinst, iscall);
6839663Slinton     }
6849663Slinton }
6859663Slinton 
68618218Slinton private boolean chklist(list, iscall)
6879663Slinton List list;
68818218Slinton boolean iscall;
6899663Slinton {
6909663Slinton     register Trcmd t;
6919663Slinton     register Command cmd;
6929663Slinton 
69316609Ssam     setcurfunc(whatblock(pc));
6949663Slinton     foreach (Trcmd, t, list)
6959663Slinton 	foreach (Command, cmd, t->cmdlist)
6969663Slinton 	    if (cmd->op == O_PRINTSRCPOS and
6979663Slinton 	      (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) {
6989663Slinton 		if (iscall) {
6999663Slinton 		    printentry(curfunc);
7009663Slinton 		} else {
7019663Slinton 		    printexit(curfunc);
7029663Slinton 		}
7039663Slinton 		return true;
7049663Slinton 	    }
7059663Slinton 	endfor
7069663Slinton     endfor
7079663Slinton     return false;
7089663Slinton }
7099663Slinton 
7109663Slinton /*
7119663Slinton  * List of variables being watched.
7129663Slinton  */
7139663Slinton 
7149663Slinton typedef struct Trinfo *Trinfo;
7159663Slinton 
7169663Slinton struct Trinfo {
7179663Slinton     Node variable;
7189663Slinton     Address traddr;
7199663Slinton     Symbol trblock;
7209663Slinton     char *trvalue;
7219663Slinton };
7229663Slinton 
7239663Slinton private List trinfolist;
7249663Slinton 
7259663Slinton /*
7269663Slinton  * Find the trace information record associated with the given record.
7279663Slinton  * If there isn't one then create it and add it to the list.
7289663Slinton  */
7299663Slinton 
7309663Slinton private Trinfo findtrinfo(p)
7319663Slinton Node p;
7329663Slinton {
7339663Slinton     register Trinfo tp;
73418218Slinton     boolean isnew;
7359663Slinton 
7369663Slinton     isnew = true;
7379663Slinton     if (trinfolist == nil) {
7389663Slinton 	trinfolist = list_alloc();
7399663Slinton     } else {
7409663Slinton 	foreach (Trinfo, tp, trinfolist)
7419663Slinton 	    if (tp->variable == p) {
7429663Slinton 		isnew = false;
7439663Slinton 		break;
7449663Slinton 	    }
7459663Slinton 	endfor
7469663Slinton     }
7479663Slinton     if (isnew) {
7489663Slinton 	if (tracebpts) {
7499663Slinton 	    printf("adding trinfo for \"");
7509663Slinton 	    prtree(stdout, p);
7519663Slinton 	    printf("\"\n");
7529663Slinton 	}
7539663Slinton 	tp = new(Trinfo);
7549663Slinton 	tp->variable = p;
7559663Slinton 	tp->traddr = lval(p);
7569663Slinton 	tp->trvalue = nil;
7579663Slinton 	list_append(list_item(tp), nil, trinfolist);
7589663Slinton     }
7599663Slinton     return tp;
7609663Slinton }
7619663Slinton 
7629663Slinton /*
7639663Slinton  * Print out the value of a variable if it has changed since the
7649663Slinton  * last time we checked.
7659663Slinton  */
7669663Slinton 
7679663Slinton public printifchanged(p)
7689663Slinton Node p;
7699663Slinton {
7709663Slinton     register Trinfo tp;
7719663Slinton     register int n;
7729663Slinton     char buff[MAXTRSIZE];
77318218Slinton     Filename curfile;
7749663Slinton     static Lineno prevline;
77518218Slinton     static Filename prevfile;
7769663Slinton 
7779663Slinton     tp = findtrinfo(p);
7789663Slinton     n = size(p->nodetype);
77918218Slinton     dread(buff, tp->traddr, n);
78018218Slinton     curfile = srcfilename(pc);
7819663Slinton     if (tp->trvalue == nil) {
7829663Slinton 	tp->trvalue = newarr(char, n);
7839663Slinton 	mov(buff, tp->trvalue, n);
7849663Slinton 	mov(buff, sp, n);
7859663Slinton 	sp += n;
78618218Slinton 	printf("initially (at line %d in \"%s\"):\t", curline, curfile);
7879663Slinton 	prtree(stdout, p);
7889663Slinton 	printf(" = ");
7899663Slinton 	printval(p->nodetype);
7909663Slinton 	putchar('\n');
7919663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
7929663Slinton 	mov(buff, tp->trvalue, n);
7939663Slinton 	mov(buff, sp, n);
7949663Slinton 	sp += n;
79518218Slinton 	printf("after line %d in \"%s\":\t", prevline, prevfile);
7969663Slinton 	prtree(stdout, p);
7979663Slinton 	printf(" = ");
7989663Slinton 	printval(p->nodetype);
7999663Slinton 	putchar('\n');
8009663Slinton     }
8019663Slinton     prevline = curline;
80218218Slinton     prevfile = curfile;
8039663Slinton }
8049663Slinton 
8059663Slinton /*
8069663Slinton  * Stop if the value of the given expression has changed.
8079663Slinton  */
8089663Slinton 
8099663Slinton public stopifchanged(p)
8109663Slinton Node p;
8119663Slinton {
8129663Slinton     register Trinfo tp;
8139663Slinton     register int n;
8149663Slinton     char buff[MAXTRSIZE];
8159663Slinton     static Lineno prevline;
8169663Slinton 
8179663Slinton     tp = findtrinfo(p);
8189663Slinton     n = size(p->nodetype);
8199663Slinton     dread(buff, tp->traddr, n);
8209663Slinton     if (tp->trvalue == nil) {
8219663Slinton 	tp->trvalue = newarr(char, n);
8229663Slinton 	mov(buff, tp->trvalue, n);
8239663Slinton 	isstopped = true;
8249663Slinton     } else if (cmp(tp->trvalue, buff, n) != 0) {
8259663Slinton 	mov(buff, tp->trvalue, n);
82616609Ssam 	mov(buff, sp, n);
82716609Ssam 	sp += n;
82816609Ssam 	printf("after line %d:\t", prevline);
82916609Ssam 	prtree(stdout, p);
83016609Ssam 	printf(" = ");
83116609Ssam 	printval(p->nodetype);
83216609Ssam 	putchar('\n');
8339663Slinton 	isstopped = true;
8349663Slinton     }
8359663Slinton     prevline = curline;
8369663Slinton }
8379663Slinton 
8389663Slinton /*
8399663Slinton  * Free the tracing table.
8409663Slinton  */
8419663Slinton 
8429663Slinton public trfree()
8439663Slinton {
8449663Slinton     register Trinfo tp;
8459663Slinton 
8469663Slinton     foreach (Trinfo, tp, trinfolist)
8479663Slinton 	dispose(tp->trvalue);
8489663Slinton 	dispose(tp);
8499663Slinton 	list_delete(list_curitem(trinfolist), trinfolist);
8509663Slinton     endfor
8519663Slinton }
8529663Slinton 
8539663Slinton /*
8549663Slinton  * Fix up breakpoint information before continuing execution.
8559663Slinton  *
8569663Slinton  * It's necessary to destroy events and breakpoints that were created
8579663Slinton  * temporarily and still exist because the program terminated abnormally.
8589663Slinton  */
8599663Slinton 
8609663Slinton public fixbps()
8619663Slinton {
8629663Slinton     register Event e;
8639663Slinton     register Trcmd t;
8649663Slinton 
8659663Slinton     single_stepping = false;
8669663Slinton     inst_tracing = false;
8679663Slinton     trfree();
8689663Slinton     foreach (Event, e, eventlist)
8699663Slinton 	if (e->temporary) {
87016609Ssam 	    if (not delevent(e->id)) {
87116609Ssam 		printf("!! dbx.fixbps: can't find event %d\n", e->id);
87216609Ssam 	    }
8739663Slinton 	}
8749663Slinton     endfor
8759663Slinton     foreach (Trcmd, t, eachline)
8769663Slinton 	printrmtr(t);
8779663Slinton 	list_delete(list_curitem(eachline), eachline);
8789663Slinton     endfor
8799663Slinton     foreach (Trcmd, t, eachinst)
8809663Slinton 	printrmtr(t);
8819663Slinton 	list_delete(list_curitem(eachinst), eachinst);
8829663Slinton     endfor
8839663Slinton }
8849663Slinton 
8859663Slinton /*
8869663Slinton  * Set all breakpoints in object code.
8879663Slinton  */
8889663Slinton 
8899663Slinton public setallbps()
8909663Slinton {
8919663Slinton     register Breakpoint p;
8929663Slinton 
8939663Slinton     foreach (Breakpoint, p, bplist)
8949663Slinton 	setbp(p->bpaddr);
8959663Slinton     endfor
8969663Slinton }
8979663Slinton 
8989663Slinton /*
8999663Slinton  * Undo damage done by "setallbps".
9009663Slinton  */
9019663Slinton 
9029663Slinton public unsetallbps()
9039663Slinton {
9049663Slinton     register Breakpoint p;
9059663Slinton 
9069663Slinton     foreach (Breakpoint, p, bplist)
9079663Slinton 	unsetbp(p->bpaddr);
9089663Slinton     endfor
9099663Slinton }
910