19663Slinton /* Copyright (c) 1982 Regents of the University of California */ 29663Slinton 3*18218Slinton static char sccsid[] = "@(#)events.c 1.7 (Berkeley) 03/01/85"; 49663Slinton 5*18218Slinton static char rcsid[] = "$Header: events.c,v 1.5 84/12/26 10:39:26 linton Exp $"; 6*18218Slinton 79663Slinton /* 89663Slinton * Event/breakpoint managment. 99663Slinton */ 109663Slinton 119663Slinton #include "defs.h" 129663Slinton #include "events.h" 139663Slinton #include "main.h" 149663Slinton #include "symbols.h" 159663Slinton #include "tree.h" 169663Slinton #include "eval.h" 179663Slinton #include "source.h" 189663Slinton #include "mappings.h" 1916609Ssam #include "runtime.h" 209663Slinton #include "process.h" 219663Slinton #include "machine.h" 229663Slinton #include "lists.h" 239663Slinton 249663Slinton #ifndef public 259663Slinton typedef struct Event *Event; 269663Slinton typedef struct Breakpoint *Breakpoint; 279663Slinton 28*18218Slinton boolean inst_tracing; 29*18218Slinton boolean single_stepping; 30*18218Slinton boolean isstopped; 319663Slinton 329663Slinton #include "symbols.h" 339663Slinton 349663Slinton Symbol linesym; 359663Slinton Symbol procsym; 369663Slinton Symbol pcsym; 379663Slinton Symbol retaddrsym; 389663Slinton 399663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist) 409663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist) 419663Slinton 429663Slinton #endif 439663Slinton 449663Slinton struct Event { 459663Slinton unsigned int id; 46*18218Slinton boolean temporary; 479663Slinton Node condition; 489663Slinton Cmdlist actions; 499663Slinton }; 509663Slinton 519663Slinton struct Breakpoint { 529663Slinton Event event; 539663Slinton Address bpaddr; 549663Slinton Lineno bpline; 559663Slinton Cmdlist actions; 56*18218Slinton boolean temporary; 579663Slinton }; 589663Slinton 599663Slinton typedef List Eventlist; 609663Slinton typedef List Bplist; 619663Slinton 629663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el) 639663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl) 649663Slinton 659663Slinton private Eventlist eventlist; /* list of active events */ 669663Slinton private Bplist bplist; /* list of active breakpoints */ 67*18218Slinton private Event curevent; /* most recently created event */ 68*18218Slinton private integer eventid; /* id number of current event */ 69*18218Slinton private integer trid; /* id number of current trace */ 709663Slinton 719663Slinton typedef struct Trcmd { 729663Slinton Integer trid; 739663Slinton Event event; 749663Slinton Cmdlist cmdlist; 759663Slinton } *Trcmd; 769663Slinton 779663Slinton private List eachline; /* commands to execute after each line */ 789663Slinton private List eachinst; /* commands to execute after each instruction */ 799663Slinton 809663Slinton private Breakpoint bp_alloc(); 819663Slinton 829663Slinton /* 839663Slinton * Initialize breakpoint information. 849663Slinton */ 859663Slinton 869663Slinton private Symbol builtinsym(str, class, type) 879663Slinton String str; 889663Slinton Symclass class; 899663Slinton Symbol type; 909663Slinton { 919663Slinton Symbol s; 929663Slinton 939663Slinton s = insert(identname(str, true)); 949663Slinton s->language = findlanguage(".s"); 959663Slinton s->class = class; 969663Slinton s->type = type; 979663Slinton return s; 989663Slinton } 999663Slinton 1009663Slinton public bpinit() 1019663Slinton { 1029663Slinton linesym = builtinsym("$line", VAR, t_int); 1039663Slinton procsym = builtinsym("$proc", PROC, nil); 1049663Slinton pcsym = lookup(identname("$pc", true)); 1059663Slinton if (pcsym == nil) { 1069663Slinton panic("can't find $pc"); 1079663Slinton } 1089663Slinton retaddrsym = builtinsym("$retaddr", VAR, t_int); 1099663Slinton eventlist = list_alloc(); 1109663Slinton bplist = list_alloc(); 1119663Slinton eachline = list_alloc(); 1129663Slinton eachinst = list_alloc(); 1139663Slinton } 1149663Slinton 1159663Slinton /* 1169663Slinton * Trap an event and do the associated commands when it occurs. 1179663Slinton */ 1189663Slinton 1199663Slinton public Event event_alloc(istmp, econd, cmdlist) 120*18218Slinton boolean istmp; 1219663Slinton Node econd; 1229663Slinton Cmdlist cmdlist; 1239663Slinton { 1249663Slinton register Event e; 1259663Slinton 1269663Slinton e = new(Event); 127*18218Slinton ++eventid; 128*18218Slinton e->id = eventid; 1299663Slinton e->temporary = istmp; 1309663Slinton e->condition = econd; 1319663Slinton e->actions = cmdlist; 1329663Slinton eventlist_append(e, eventlist); 133*18218Slinton curevent = e; 1349663Slinton translate(e); 1359663Slinton return e; 1369663Slinton } 1379663Slinton 1389663Slinton /* 1399663Slinton * Delete the event with the given id. 14016609Ssam * Returns whether it's successful or not. 1419663Slinton */ 1429663Slinton 14316609Ssam public boolean delevent (id) 1449663Slinton unsigned int id; 1459663Slinton { 1469663Slinton Event e; 1479663Slinton Breakpoint bp; 1489663Slinton Trcmd t; 14916609Ssam boolean found; 1509663Slinton 15116609Ssam found = false; 1529663Slinton foreach (Event, e, eventlist) 1539663Slinton if (e->id == id) { 15416609Ssam found = true; 1559663Slinton foreach (Breakpoint, bp, bplist) 1569663Slinton if (bp->event == e) { 157*18218Slinton if (tracebpts) { 158*18218Slinton printf("deleting breakpoint at 0x%x\n", bp->bpaddr); 159*18218Slinton fflush(stdout); 160*18218Slinton } 1619663Slinton list_delete(list_curitem(bplist), bplist); 1629663Slinton } 1639663Slinton endfor 16416609Ssam list_delete(list_curitem(eventlist), eventlist); 1659663Slinton break; 1669663Slinton } 1679663Slinton endfor 1689663Slinton foreach (Trcmd, t, eachline) 1699663Slinton if (t->event->id == id) { 17016609Ssam found = true; 1719663Slinton printrmtr(t); 1729663Slinton list_delete(list_curitem(eachline), eachline); 1739663Slinton } 1749663Slinton endfor 1759663Slinton foreach (Trcmd, t, eachinst) 1769663Slinton if (t->event->id == id) { 17716609Ssam found = true; 1789663Slinton printrmtr(t); 1799663Slinton list_delete(list_curitem(eachinst), eachinst); 1809663Slinton } 1819663Slinton endfor 1829663Slinton if (list_size(eachinst) == 0) { 1839663Slinton inst_tracing = false; 1849663Slinton if (list_size(eachline) == 0) { 1859663Slinton single_stepping = false; 1869663Slinton } 1879663Slinton } 18816609Ssam return found; 1899663Slinton } 1909663Slinton 1919663Slinton /* 1929663Slinton * Translate an event into the appropriate breakpoints and actions. 1939663Slinton * While we're at it, turn on the breakpoints if the condition is true. 1949663Slinton */ 1959663Slinton 1969663Slinton private translate(e) 1979663Slinton Event e; 1989663Slinton { 1999663Slinton Breakpoint bp; 2009663Slinton Symbol s; 2019663Slinton Node place; 2029663Slinton Lineno line; 2039663Slinton Address addr; 2049663Slinton 2059663Slinton checkref(e->condition); 2069663Slinton switch (e->condition->op) { 2079663Slinton case O_EQ: 2089663Slinton if (e->condition->value.arg[0]->op == O_SYM) { 2099663Slinton s = e->condition->value.arg[0]->value.sym; 2109663Slinton place = e->condition->value.arg[1]; 2119663Slinton if (s == linesym) { 2129663Slinton if (place->op == O_QLINE) { 2139663Slinton line = place->value.arg[1]->value.lcon; 21416609Ssam addr = objaddr(line, place->value.arg[0]->value.scon); 2159663Slinton } else { 2169663Slinton eval(place); 2179663Slinton line = pop(long); 2189663Slinton addr = objaddr(line, cursource); 2199663Slinton } 2209663Slinton if (addr == NOADDR) { 22116609Ssam if (not delevent(e->id)) { 22216609Ssam printf("!! dbx.translate: can't undo event %d?\n", 22316609Ssam e->id); 22416609Ssam } 2259663Slinton beginerrmsg(); 2269663Slinton fprintf(stderr, "no executable code at line "); 2279663Slinton prtree(stderr, place); 2289663Slinton enderrmsg(); 2299663Slinton } 2309663Slinton bp = bp_alloc(e, addr, line, e->actions); 2319663Slinton } else if (s == procsym) { 2329663Slinton eval(place); 2339663Slinton s = pop(Symbol); 2349663Slinton bp = bp_alloc(e, codeloc(s), 0, e->actions); 2359663Slinton if (isactive(s) and pc != codeloc(program)) { 2369663Slinton evalcmdlist(e->actions); 2379663Slinton } 2389663Slinton } else if (s == pcsym) { 2399663Slinton eval(place); 2409663Slinton bp = bp_alloc(e, pop(Address), 0, e->actions); 2419663Slinton } else { 2429663Slinton condbp(e); 2439663Slinton } 2449663Slinton } else { 2459663Slinton condbp(e); 2469663Slinton } 2479663Slinton break; 2489663Slinton 2499663Slinton /* 2509663Slinton * These should be handled specially. 2519663Slinton * But for now I'm ignoring the problem. 2529663Slinton */ 2539663Slinton case O_AND: 2549663Slinton case O_OR: 2559663Slinton default: 2569663Slinton condbp(e); 2579663Slinton break; 2589663Slinton } 2599663Slinton } 2609663Slinton 2619663Slinton /* 2629663Slinton * Create a breakpoint for a condition that cannot be pinpointed 2639663Slinton * to happening at a particular address, but one for which we 2649663Slinton * must single step and check the condition after each statement. 2659663Slinton */ 2669663Slinton 2679663Slinton private condbp(e) 2689663Slinton Event e; 2699663Slinton { 2709663Slinton Symbol p; 2719663Slinton Breakpoint bp; 2729663Slinton Cmdlist actions; 2739663Slinton 2749663Slinton p = tcontainer(e->condition); 2759663Slinton if (p == nil) { 2769663Slinton p = program; 2779663Slinton } 2789663Slinton actions = buildcmdlist(build(O_IF, e->condition, e->actions)); 2799663Slinton actions = buildcmdlist(build(O_TRACEON, false, actions)); 2809663Slinton bp = bp_alloc(e, codeloc(p), 0, actions); 2819663Slinton } 2829663Slinton 2839663Slinton /* 2849663Slinton * Determine the deepest nested subprogram that still contains 2859663Slinton * all elements in the given expression. 2869663Slinton */ 2879663Slinton 2889663Slinton public Symbol tcontainer(exp) 2899663Slinton Node exp; 2909663Slinton { 2919663Slinton Integer i; 2929663Slinton Symbol s, t, u, v; 2939663Slinton 2949663Slinton checkref(exp); 2959663Slinton s = nil; 2969663Slinton if (exp->op == O_SYM) { 2979663Slinton s = container(exp->value.sym); 2989663Slinton } else if (not isleaf(exp->op)) { 2999663Slinton for (i = 0; i < nargs(exp->op); i++) { 3009663Slinton t = tcontainer(exp->value.arg[i]); 3019663Slinton if (t != nil) { 3029663Slinton if (s == nil) { 3039663Slinton s = t; 3049663Slinton } else { 3059663Slinton u = s; 3069663Slinton v = t; 3079663Slinton while (u != v and u != nil) { 3089663Slinton u = container(u); 3099663Slinton v = container(v); 3109663Slinton } 3119663Slinton if (u == nil) { 3129663Slinton panic("bad ancestry for \"%s\"", symname(s)); 3139663Slinton } else { 3149663Slinton s = u; 3159663Slinton } 3169663Slinton } 3179663Slinton } 3189663Slinton } 3199663Slinton } 3209663Slinton return s; 3219663Slinton } 3229663Slinton 3239663Slinton /* 32411869Slinton * Determine if the given function can be executed at full speed. 32511869Slinton * This can only be done if there are no breakpoints within the function. 32611869Slinton */ 32711869Slinton 328*18218Slinton public boolean canskip(f) 32911869Slinton Symbol f; 33011869Slinton { 33111869Slinton Breakpoint p; 332*18218Slinton boolean ok; 33311869Slinton 33411869Slinton ok = true; 33511869Slinton foreach (Breakpoint, p, bplist) 33611869Slinton if (whatblock(p->bpaddr) == f) { 33711869Slinton ok = false; 33811869Slinton break; 33911869Slinton } 34011869Slinton endfor 34111869Slinton return ok; 34211869Slinton } 34311869Slinton 34411869Slinton /* 3459663Slinton * Print out what's currently being traced by looking at 3469663Slinton * the currently active events. 3479663Slinton * 3489663Slinton * Some convolution here to translate internal representation 3499663Slinton * of events back into something more palatable. 3509663Slinton */ 3519663Slinton 3529663Slinton public status() 3539663Slinton { 3549663Slinton Event e; 3559663Slinton 3569663Slinton foreach (Event, e, eventlist) 3579663Slinton if (not e->temporary) { 35811869Slinton printevent(e); 3599663Slinton } 3609663Slinton endfor 3619663Slinton } 3629663Slinton 36311869Slinton public printevent(e) 36411869Slinton Event e; 36511869Slinton { 36611869Slinton Command cmd; 36711869Slinton 36811869Slinton if (not isredirected()) { 36916609Ssam printeventid(e->id); 37011869Slinton } 37111869Slinton cmd = list_element(Command, list_head(e->actions)); 37211869Slinton if (cmd->op == O_PRINTCALL) { 37311869Slinton printf("trace "); 37411869Slinton printname(stdout, cmd->value.sym); 37511869Slinton } else { 37611869Slinton if (list_size(e->actions) > 1) { 37711869Slinton printf("{ "); 37811869Slinton } 37911869Slinton foreach (Command, cmd, e->actions) 38011869Slinton printcmd(stdout, cmd); 38111869Slinton if (not list_islast()) { 38211869Slinton printf("; "); 38311869Slinton } 38411869Slinton endfor 38511869Slinton if (list_size(e->actions) > 1) { 38611869Slinton printf(" }"); 38711869Slinton } 38811869Slinton printcond(e->condition); 38911869Slinton } 39011869Slinton printf("\n"); 39111869Slinton } 39211869Slinton 39316609Ssam private printeventid (id) 39416609Ssam integer id; 39516609Ssam { 39616609Ssam printf("[%d] ", id); 39716609Ssam } 39816609Ssam 3999663Slinton /* 4009663Slinton * Print out a condition. 4019663Slinton */ 4029663Slinton 4039663Slinton private printcond(cond) 4049663Slinton Node cond; 4059663Slinton { 4069663Slinton Symbol s; 4079663Slinton Node place; 4089663Slinton 4099663Slinton if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) { 4109663Slinton s = cond->value.arg[0]->value.sym; 4119663Slinton place = cond->value.arg[1]; 4129663Slinton if (s == procsym) { 4139663Slinton if (place->value.sym != program) { 4149663Slinton printf(" in "); 4159663Slinton printname(stdout, place->value.sym); 4169663Slinton } 4179663Slinton } else if (s == linesym) { 4189663Slinton printf(" at "); 4199663Slinton prtree(stdout, place); 4209663Slinton } else if (s == pcsym or s == retaddrsym) { 4219663Slinton printf("i at "); 4229663Slinton prtree(stdout, place); 4239663Slinton } else { 4249663Slinton printf(" when "); 4259663Slinton prtree(stdout, cond); 4269663Slinton } 4279663Slinton } else { 4289663Slinton printf(" when "); 4299663Slinton prtree(stdout, cond); 4309663Slinton } 4319663Slinton } 4329663Slinton 4339663Slinton /* 4349663Slinton * Add a breakpoint to the list and return it. 4359663Slinton */ 4369663Slinton 4379663Slinton private Breakpoint bp_alloc(e, addr, line, actions) 4389663Slinton Event e; 4399663Slinton Address addr; 4409663Slinton Lineno line; 4419663Slinton Cmdlist actions; 4429663Slinton { 4439663Slinton register Breakpoint p; 4449663Slinton 4459663Slinton p = new(Breakpoint); 4469663Slinton p->event = e; 4479663Slinton p->bpaddr = addr; 4489663Slinton p->bpline = line; 4499663Slinton p->actions = actions; 450*18218Slinton p->temporary = false; 451*18218Slinton if (tracebpts) { 452*18218Slinton if (e == nil) { 453*18218Slinton printf("new bp at 0x%x for event ??\n", addr, e->id); 454*18218Slinton } else { 455*18218Slinton printf("new bp at 0x%x for event %d\n", addr, e->id); 456*18218Slinton } 457*18218Slinton fflush(stdout); 458*18218Slinton } 4599663Slinton bplist_append(p, bplist); 4609663Slinton return p; 4619663Slinton } 4629663Slinton 4639663Slinton /* 4649663Slinton * Free all storage in the event and breakpoint tables. 4659663Slinton */ 4669663Slinton 4679663Slinton public bpfree() 4689663Slinton { 4699663Slinton register Event e; 4709663Slinton 4719663Slinton fixbps(); 4729663Slinton foreach (Event, e, eventlist) 47316609Ssam if (not delevent(e->id)) { 47416609Ssam printf("!! dbx.bpfree: can't delete event %d\n", e->id); 47516609Ssam } 4769663Slinton list_delete(list_curitem(eventlist), eventlist); 4779663Slinton endfor 4789663Slinton } 4799663Slinton 4809663Slinton /* 4819663Slinton * Determine if the program stopped at a known breakpoint 4829663Slinton * and if so do the associated commands. 4839663Slinton */ 4849663Slinton 485*18218Slinton public boolean bpact() 4869663Slinton { 4879663Slinton register Breakpoint p; 488*18218Slinton boolean found; 48916609Ssam integer eventId; 4909663Slinton 4919663Slinton found = false; 4929663Slinton foreach (Breakpoint, p, bplist) 4939663Slinton if (p->bpaddr == pc) { 494*18218Slinton if (tracebpts) { 495*18218Slinton printf("breakpoint for event %d found at location 0x%x\n", 496*18218Slinton p->event->id, pc); 497*18218Slinton } 4989663Slinton found = true; 499*18218Slinton if (p->event->temporary) { 500*18218Slinton if (not delevent(p->event->id)) { 501*18218Slinton printf("!! dbx.bpact: can't find event %d\n", 502*18218Slinton p->event->id); 503*18218Slinton } 504*18218Slinton } 5059663Slinton evalcmdlist(p->actions); 506*18218Slinton if (isstopped) { 507*18218Slinton eventId = p->event->id; 508*18218Slinton } 509*18218Slinton if (p->temporary) { 510*18218Slinton list_delete(list_curitem(bplist), bplist); 511*18218Slinton } 5129663Slinton } 5139663Slinton endfor 5149663Slinton if (isstopped) { 51516609Ssam if (found) { 51616609Ssam printeventid(eventId); 51716609Ssam } 5189663Slinton printstatus(); 5199663Slinton } 5209663Slinton fflush(stdout); 5219663Slinton return found; 5229663Slinton } 5239663Slinton 5249663Slinton /* 5259663Slinton * Begin single stepping and executing the given commands after each step. 5269663Slinton * If the first argument is true step by instructions, otherwise 5279663Slinton * step by source lines. 5289663Slinton * 5299663Slinton * We automatically set a breakpoint at the end of the current procedure 5309663Slinton * to turn off the given tracing. 5319663Slinton */ 5329663Slinton 5339663Slinton public traceon(inst, event, cmdlist) 534*18218Slinton boolean inst; 5359663Slinton Event event; 5369663Slinton Cmdlist cmdlist; 5379663Slinton { 5389663Slinton register Trcmd trcmd; 539*18218Slinton Breakpoint bp; 5409663Slinton Cmdlist actions; 54111869Slinton Address ret; 542*18218Slinton Event e; 5439663Slinton 544*18218Slinton if (event == nil) { 545*18218Slinton e = curevent; 546*18218Slinton } else { 547*18218Slinton e = event; 548*18218Slinton } 5499663Slinton trcmd = new(Trcmd); 550*18218Slinton ++trid; 551*18218Slinton trcmd->trid = trid; 552*18218Slinton trcmd->event = e; 5539663Slinton trcmd->cmdlist = cmdlist; 5549663Slinton single_stepping = true; 5559663Slinton if (inst) { 5569663Slinton inst_tracing = true; 5579663Slinton list_append(list_item(trcmd), nil, eachinst); 5589663Slinton } else { 5599663Slinton list_append(list_item(trcmd), nil, eachline); 5609663Slinton } 56111869Slinton ret = return_addr(); 56211869Slinton if (ret != 0) { 563*18218Slinton actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid)); 564*18218Slinton bp = bp_alloc(e, (Address) ret, 0, actions); 565*18218Slinton bp->temporary = true; 56611869Slinton } 567*18218Slinton if (tracebpts) { 568*18218Slinton printf("adding trace %d for event %d\n", trcmd->trid, e->id); 569*18218Slinton } 5709663Slinton } 5719663Slinton 5729663Slinton /* 5739663Slinton * Turn off some kind of tracing. 5749663Slinton * Strictly an internal command, this cannot be invoked by the user. 5759663Slinton */ 5769663Slinton 5779663Slinton public traceoff(id) 5789663Slinton Integer id; 5799663Slinton { 5809663Slinton register Trcmd t; 581*18218Slinton register boolean found; 5829663Slinton 5839663Slinton found = false; 5849663Slinton foreach (Trcmd, t, eachline) 5859663Slinton if (t->trid == id) { 5869663Slinton printrmtr(t); 5879663Slinton list_delete(list_curitem(eachline), eachline); 5889663Slinton found = true; 5899663Slinton break; 5909663Slinton } 5919663Slinton endfor 5929663Slinton if (not found) { 5939663Slinton foreach (Trcmd, t, eachinst) 5949663Slinton if (t->event->id == id) { 5959663Slinton printrmtr(t); 5969663Slinton list_delete(list_curitem(eachinst), eachinst); 5979663Slinton found = true; 5989663Slinton break; 5999663Slinton } 6009663Slinton endfor 6019663Slinton if (not found) { 602*18218Slinton beginerrmsg(); 603*18218Slinton fprintf(stderr, "[internal error: trace id %d not found]\n", id); 6049663Slinton } 6059663Slinton } 6069663Slinton if (list_size(eachinst) == 0) { 6079663Slinton inst_tracing = false; 6089663Slinton if (list_size(eachline) == 0) { 6099663Slinton single_stepping = false; 6109663Slinton } 6119663Slinton } 6129663Slinton } 6139663Slinton 6149663Slinton /* 6159663Slinton * If breakpoints are being traced, note that a Trcmd is being deleted. 6169663Slinton */ 6179663Slinton 6189663Slinton private printrmtr(t) 6199663Slinton Trcmd t; 6209663Slinton { 621*18218Slinton if (tracebpts) { 622*18218Slinton printf("removing trace %d", t->trid); 623*18218Slinton if (t->event != nil) { 624*18218Slinton printf(" for event %d", t->event->id); 625*18218Slinton } 626*18218Slinton printf("\n"); 6279663Slinton } 6289663Slinton } 6299663Slinton 6309663Slinton /* 6319663Slinton * Print out news during single step tracing. 6329663Slinton */ 6339663Slinton 6349663Slinton public printnews() 6359663Slinton { 6369663Slinton register Trcmd t; 6379663Slinton 6389663Slinton foreach (Trcmd, t, eachline) 6399663Slinton evalcmdlist(t->cmdlist); 6409663Slinton endfor 6419663Slinton foreach (Trcmd, t, eachinst) 6429663Slinton evalcmdlist(t->cmdlist); 6439663Slinton endfor 6449663Slinton bpact(); 6459663Slinton } 6469663Slinton 6479663Slinton /* 6489663Slinton * A procedure call/return has occurred while single-stepping, 6499663Slinton * note it if we're tracing lines. 6509663Slinton */ 6519663Slinton 652*18218Slinton private boolean chklist(); 6539663Slinton 6549663Slinton public callnews(iscall) 655*18218Slinton boolean iscall; 6569663Slinton { 6579663Slinton if (not chklist(eachline, iscall)) { 6589663Slinton chklist(eachinst, iscall); 6599663Slinton } 6609663Slinton } 6619663Slinton 662*18218Slinton private boolean chklist(list, iscall) 6639663Slinton List list; 664*18218Slinton boolean iscall; 6659663Slinton { 6669663Slinton register Trcmd t; 6679663Slinton register Command cmd; 6689663Slinton 66916609Ssam setcurfunc(whatblock(pc)); 6709663Slinton foreach (Trcmd, t, list) 6719663Slinton foreach (Command, cmd, t->cmdlist) 6729663Slinton if (cmd->op == O_PRINTSRCPOS and 6739663Slinton (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) { 6749663Slinton if (iscall) { 6759663Slinton printentry(curfunc); 6769663Slinton } else { 6779663Slinton printexit(curfunc); 6789663Slinton } 6799663Slinton return true; 6809663Slinton } 6819663Slinton endfor 6829663Slinton endfor 6839663Slinton return false; 6849663Slinton } 6859663Slinton 6869663Slinton /* 6879663Slinton * When tracing variables we keep a copy of their most recent value 6889663Slinton * and compare it to the current one each time a breakpoint occurs. 6899663Slinton * MAXTRSIZE is the maximum size variable we allow. 6909663Slinton */ 6919663Slinton 6929663Slinton #define MAXTRSIZE 512 6939663Slinton 6949663Slinton /* 6959663Slinton * List of variables being watched. 6969663Slinton */ 6979663Slinton 6989663Slinton typedef struct Trinfo *Trinfo; 6999663Slinton 7009663Slinton struct Trinfo { 7019663Slinton Node variable; 7029663Slinton Address traddr; 7039663Slinton Symbol trblock; 7049663Slinton char *trvalue; 7059663Slinton }; 7069663Slinton 7079663Slinton private List trinfolist; 7089663Slinton 7099663Slinton /* 7109663Slinton * Find the trace information record associated with the given record. 7119663Slinton * If there isn't one then create it and add it to the list. 7129663Slinton */ 7139663Slinton 7149663Slinton private Trinfo findtrinfo(p) 7159663Slinton Node p; 7169663Slinton { 7179663Slinton register Trinfo tp; 718*18218Slinton boolean isnew; 7199663Slinton 7209663Slinton isnew = true; 7219663Slinton if (trinfolist == nil) { 7229663Slinton trinfolist = list_alloc(); 7239663Slinton } else { 7249663Slinton foreach (Trinfo, tp, trinfolist) 7259663Slinton if (tp->variable == p) { 7269663Slinton isnew = false; 7279663Slinton break; 7289663Slinton } 7299663Slinton endfor 7309663Slinton } 7319663Slinton if (isnew) { 7329663Slinton if (tracebpts) { 7339663Slinton printf("adding trinfo for \""); 7349663Slinton prtree(stdout, p); 7359663Slinton printf("\"\n"); 7369663Slinton } 7379663Slinton tp = new(Trinfo); 7389663Slinton tp->variable = p; 7399663Slinton tp->traddr = lval(p); 7409663Slinton tp->trvalue = nil; 7419663Slinton list_append(list_item(tp), nil, trinfolist); 7429663Slinton } 7439663Slinton return tp; 7449663Slinton } 7459663Slinton 7469663Slinton /* 7479663Slinton * Print out the value of a variable if it has changed since the 7489663Slinton * last time we checked. 7499663Slinton */ 7509663Slinton 7519663Slinton public printifchanged(p) 7529663Slinton Node p; 7539663Slinton { 7549663Slinton register Trinfo tp; 7559663Slinton register int n; 7569663Slinton char buff[MAXTRSIZE]; 757*18218Slinton Filename curfile; 7589663Slinton static Lineno prevline; 759*18218Slinton static Filename prevfile; 7609663Slinton 7619663Slinton tp = findtrinfo(p); 7629663Slinton n = size(p->nodetype); 763*18218Slinton dread(buff, tp->traddr, n); 764*18218Slinton curfile = srcfilename(pc); 7659663Slinton if (tp->trvalue == nil) { 7669663Slinton tp->trvalue = newarr(char, n); 7679663Slinton mov(buff, tp->trvalue, n); 7689663Slinton mov(buff, sp, n); 7699663Slinton sp += n; 770*18218Slinton printf("initially (at line %d in \"%s\"):\t", curline, curfile); 7719663Slinton prtree(stdout, p); 7729663Slinton printf(" = "); 7739663Slinton printval(p->nodetype); 7749663Slinton putchar('\n'); 7759663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 7769663Slinton mov(buff, tp->trvalue, n); 7779663Slinton mov(buff, sp, n); 7789663Slinton sp += n; 779*18218Slinton printf("after line %d in \"%s\":\t", prevline, prevfile); 7809663Slinton prtree(stdout, p); 7819663Slinton printf(" = "); 7829663Slinton printval(p->nodetype); 7839663Slinton putchar('\n'); 7849663Slinton } 7859663Slinton prevline = curline; 786*18218Slinton prevfile = curfile; 7879663Slinton } 7889663Slinton 7899663Slinton /* 7909663Slinton * Stop if the value of the given expression has changed. 7919663Slinton */ 7929663Slinton 7939663Slinton public stopifchanged(p) 7949663Slinton Node p; 7959663Slinton { 7969663Slinton register Trinfo tp; 7979663Slinton register int n; 7989663Slinton char buff[MAXTRSIZE]; 7999663Slinton static Lineno prevline; 8009663Slinton 8019663Slinton tp = findtrinfo(p); 8029663Slinton n = size(p->nodetype); 8039663Slinton dread(buff, tp->traddr, n); 8049663Slinton if (tp->trvalue == nil) { 8059663Slinton tp->trvalue = newarr(char, n); 8069663Slinton mov(buff, tp->trvalue, n); 8079663Slinton isstopped = true; 8089663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 8099663Slinton mov(buff, tp->trvalue, n); 81016609Ssam mov(buff, sp, n); 81116609Ssam sp += n; 81216609Ssam printf("after line %d:\t", prevline); 81316609Ssam prtree(stdout, p); 81416609Ssam printf(" = "); 81516609Ssam printval(p->nodetype); 81616609Ssam putchar('\n'); 8179663Slinton isstopped = true; 8189663Slinton } 8199663Slinton prevline = curline; 8209663Slinton } 8219663Slinton 8229663Slinton /* 8239663Slinton * Free the tracing table. 8249663Slinton */ 8259663Slinton 8269663Slinton public trfree() 8279663Slinton { 8289663Slinton register Trinfo tp; 8299663Slinton 8309663Slinton foreach (Trinfo, tp, trinfolist) 8319663Slinton dispose(tp->trvalue); 8329663Slinton dispose(tp); 8339663Slinton list_delete(list_curitem(trinfolist), trinfolist); 8349663Slinton endfor 8359663Slinton } 8369663Slinton 8379663Slinton /* 8389663Slinton * Fix up breakpoint information before continuing execution. 8399663Slinton * 8409663Slinton * It's necessary to destroy events and breakpoints that were created 8419663Slinton * temporarily and still exist because the program terminated abnormally. 8429663Slinton */ 8439663Slinton 8449663Slinton public fixbps() 8459663Slinton { 8469663Slinton register Event e; 8479663Slinton register Trcmd t; 8489663Slinton 8499663Slinton single_stepping = false; 8509663Slinton inst_tracing = false; 8519663Slinton trfree(); 8529663Slinton foreach (Event, e, eventlist) 8539663Slinton if (e->temporary) { 85416609Ssam if (not delevent(e->id)) { 85516609Ssam printf("!! dbx.fixbps: can't find event %d\n", e->id); 85616609Ssam } 8579663Slinton } 8589663Slinton endfor 8599663Slinton foreach (Trcmd, t, eachline) 8609663Slinton printrmtr(t); 8619663Slinton list_delete(list_curitem(eachline), eachline); 8629663Slinton endfor 8639663Slinton foreach (Trcmd, t, eachinst) 8649663Slinton printrmtr(t); 8659663Slinton list_delete(list_curitem(eachinst), eachinst); 8669663Slinton endfor 8679663Slinton } 8689663Slinton 8699663Slinton /* 8709663Slinton * Set all breakpoints in object code. 8719663Slinton */ 8729663Slinton 8739663Slinton public setallbps() 8749663Slinton { 8759663Slinton register Breakpoint p; 8769663Slinton 8779663Slinton foreach (Breakpoint, p, bplist) 8789663Slinton setbp(p->bpaddr); 8799663Slinton endfor 8809663Slinton } 8819663Slinton 8829663Slinton /* 8839663Slinton * Undo damage done by "setallbps". 8849663Slinton */ 8859663Slinton 8869663Slinton public unsetallbps() 8879663Slinton { 8889663Slinton register Breakpoint p; 8899663Slinton 8909663Slinton foreach (Breakpoint, p, bplist) 8919663Slinton unsetbp(p->bpaddr); 8929663Slinton endfor 8939663Slinton } 894