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