19663Slinton /* Copyright (c) 1982 Regents of the University of California */ 29663Slinton 3*11869Slinton static char sccsid[] = "@(#)events.c 1.3 04/08/83"; 49663Slinton 59663Slinton /* 69663Slinton * Event/breakpoint managment. 79663Slinton */ 89663Slinton 99663Slinton #include "defs.h" 109663Slinton #include "events.h" 119663Slinton #include "main.h" 129663Slinton #include "symbols.h" 139663Slinton #include "tree.h" 149663Slinton #include "eval.h" 159663Slinton #include "source.h" 169663Slinton #include "mappings.h" 179663Slinton #include "process.h" 189663Slinton #include "machine.h" 199663Slinton #include "lists.h" 209663Slinton 219663Slinton #ifndef public 229663Slinton typedef struct Event *Event; 239663Slinton typedef struct Breakpoint *Breakpoint; 249663Slinton 259663Slinton Boolean inst_tracing; 269663Slinton Boolean single_stepping; 279663Slinton Boolean isstopped; 289663Slinton 299663Slinton #include "symbols.h" 309663Slinton 319663Slinton Symbol linesym; 329663Slinton Symbol procsym; 339663Slinton Symbol pcsym; 349663Slinton Symbol retaddrsym; 359663Slinton 369663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist) 379663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist) 389663Slinton 399663Slinton #endif 409663Slinton 419663Slinton struct Event { 429663Slinton unsigned int id; 439663Slinton Boolean temporary; 449663Slinton Node condition; 459663Slinton Cmdlist actions; 469663Slinton }; 479663Slinton 489663Slinton struct Breakpoint { 499663Slinton Event event; 509663Slinton Address bpaddr; 519663Slinton Lineno bpline; 529663Slinton Cmdlist actions; 539663Slinton }; 549663Slinton 559663Slinton typedef List Eventlist; 569663Slinton typedef List Bplist; 579663Slinton 589663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el) 599663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl) 609663Slinton 619663Slinton private Eventlist eventlist; /* list of active events */ 629663Slinton private Bplist bplist; /* list of active breakpoints */ 639663Slinton private Integer eventid; /* id number of next allocated event */ 649663Slinton private Integer trid; /* id number of next allocated trace */ 659663Slinton 669663Slinton typedef struct Trcmd { 679663Slinton Integer trid; 689663Slinton Event event; 699663Slinton Cmdlist cmdlist; 709663Slinton } *Trcmd; 719663Slinton 729663Slinton private List eachline; /* commands to execute after each line */ 739663Slinton private List eachinst; /* commands to execute after each instruction */ 749663Slinton 759663Slinton private Breakpoint bp_alloc(); 769663Slinton 779663Slinton /* 789663Slinton * Initialize breakpoint information. 799663Slinton */ 809663Slinton 819663Slinton private Symbol builtinsym(str, class, type) 829663Slinton String str; 839663Slinton Symclass class; 849663Slinton Symbol type; 859663Slinton { 869663Slinton Symbol s; 879663Slinton 889663Slinton s = insert(identname(str, true)); 899663Slinton s->language = findlanguage(".s"); 909663Slinton s->class = class; 919663Slinton s->type = type; 929663Slinton return s; 939663Slinton } 949663Slinton 959663Slinton public bpinit() 969663Slinton { 979663Slinton linesym = builtinsym("$line", VAR, t_int); 989663Slinton procsym = builtinsym("$proc", PROC, nil); 999663Slinton pcsym = lookup(identname("$pc", true)); 1009663Slinton if (pcsym == nil) { 1019663Slinton panic("can't find $pc"); 1029663Slinton } 1039663Slinton retaddrsym = builtinsym("$retaddr", VAR, t_int); 1049663Slinton eventlist = list_alloc(); 1059663Slinton bplist = list_alloc(); 1069663Slinton eachline = list_alloc(); 1079663Slinton eachinst = list_alloc(); 1089663Slinton } 1099663Slinton 1109663Slinton /* 1119663Slinton * Trap an event and do the associated commands when it occurs. 1129663Slinton */ 1139663Slinton 1149663Slinton public Event event_alloc(istmp, econd, cmdlist) 1159663Slinton Boolean istmp; 1169663Slinton Node econd; 1179663Slinton Cmdlist cmdlist; 1189663Slinton { 1199663Slinton register Event e; 1209663Slinton 1219663Slinton e = new(Event); 1229663Slinton ++eventid; 1239663Slinton e->id = eventid; 1249663Slinton e->temporary = istmp; 1259663Slinton e->condition = econd; 1269663Slinton e->actions = cmdlist; 1279663Slinton eventlist_append(e, eventlist); 1289663Slinton translate(e); 1299663Slinton return e; 1309663Slinton } 1319663Slinton 1329663Slinton /* 1339663Slinton * Delete the event with the given id. 1349663Slinton */ 1359663Slinton 1369663Slinton public delevent(id) 1379663Slinton unsigned int id; 1389663Slinton { 1399663Slinton Event e; 1409663Slinton Breakpoint bp; 1419663Slinton Trcmd t; 1429663Slinton 1439663Slinton foreach (Event, e, eventlist) 1449663Slinton if (e->id == id) { 1459663Slinton list_delete(list_curitem(eventlist), eventlist); 1469663Slinton foreach (Breakpoint, bp, bplist) 1479663Slinton if (bp->event == e) { 1489663Slinton list_delete(list_curitem(bplist), bplist); 1499663Slinton } 1509663Slinton endfor 1519663Slinton break; 1529663Slinton } 1539663Slinton endfor 1549663Slinton foreach (Trcmd, t, eachline) 1559663Slinton if (t->event->id == id) { 1569663Slinton printrmtr(t); 1579663Slinton list_delete(list_curitem(eachline), eachline); 1589663Slinton } 1599663Slinton endfor 1609663Slinton foreach (Trcmd, t, eachinst) 1619663Slinton if (t->event->id == id) { 1629663Slinton printrmtr(t); 1639663Slinton list_delete(list_curitem(eachinst), eachinst); 1649663Slinton } 1659663Slinton endfor 1669663Slinton if (list_size(eachinst) == 0) { 1679663Slinton inst_tracing = false; 1689663Slinton if (list_size(eachline) == 0) { 1699663Slinton single_stepping = false; 1709663Slinton } 1719663Slinton } 1729663Slinton } 1739663Slinton 1749663Slinton /* 1759663Slinton * Translate an event into the appropriate breakpoints and actions. 1769663Slinton * While we're at it, turn on the breakpoints if the condition is true. 1779663Slinton */ 1789663Slinton 1799663Slinton private translate(e) 1809663Slinton Event e; 1819663Slinton { 1829663Slinton Breakpoint bp; 1839663Slinton Symbol s; 1849663Slinton Node place; 1859663Slinton Lineno line; 1869663Slinton Address addr; 1879663Slinton 1889663Slinton checkref(e->condition); 1899663Slinton switch (e->condition->op) { 1909663Slinton case O_EQ: 1919663Slinton if (e->condition->value.arg[0]->op == O_SYM) { 1929663Slinton s = e->condition->value.arg[0]->value.sym; 1939663Slinton place = e->condition->value.arg[1]; 1949663Slinton if (s == linesym) { 1959663Slinton if (place->op == O_QLINE) { 1969663Slinton line = place->value.arg[1]->value.lcon; 1979663Slinton addr = objaddr(line, 1989663Slinton place->value.arg[0]->value.scon); 1999663Slinton } else { 2009663Slinton eval(place); 2019663Slinton line = pop(long); 2029663Slinton addr = objaddr(line, cursource); 2039663Slinton } 2049663Slinton if (addr == NOADDR) { 2059663Slinton delevent(e->id); 2069663Slinton beginerrmsg(); 2079663Slinton fprintf(stderr, "no executable code at line "); 2089663Slinton prtree(stderr, place); 2099663Slinton enderrmsg(); 2109663Slinton } 2119663Slinton bp = bp_alloc(e, addr, line, e->actions); 2129663Slinton } else if (s == procsym) { 2139663Slinton eval(place); 2149663Slinton s = pop(Symbol); 2159663Slinton bp = bp_alloc(e, codeloc(s), 0, e->actions); 2169663Slinton if (isactive(s) and pc != codeloc(program)) { 2179663Slinton evalcmdlist(e->actions); 2189663Slinton } 2199663Slinton } else if (s == pcsym) { 2209663Slinton eval(place); 2219663Slinton bp = bp_alloc(e, pop(Address), 0, e->actions); 2229663Slinton } else { 2239663Slinton condbp(e); 2249663Slinton } 2259663Slinton } else { 2269663Slinton condbp(e); 2279663Slinton } 2289663Slinton break; 2299663Slinton 2309663Slinton /* 2319663Slinton * These should be handled specially. 2329663Slinton * But for now I'm ignoring the problem. 2339663Slinton */ 2349663Slinton case O_AND: 2359663Slinton case O_OR: 2369663Slinton default: 2379663Slinton condbp(e); 2389663Slinton break; 2399663Slinton } 2409663Slinton } 2419663Slinton 2429663Slinton /* 2439663Slinton * Create a breakpoint for a condition that cannot be pinpointed 2449663Slinton * to happening at a particular address, but one for which we 2459663Slinton * must single step and check the condition after each statement. 2469663Slinton */ 2479663Slinton 2489663Slinton private condbp(e) 2499663Slinton Event e; 2509663Slinton { 2519663Slinton Symbol p; 2529663Slinton Breakpoint bp; 2539663Slinton Cmdlist actions; 2549663Slinton 2559663Slinton p = tcontainer(e->condition); 2569663Slinton if (p == nil) { 2579663Slinton p = program; 2589663Slinton } 2599663Slinton actions = buildcmdlist(build(O_IF, e->condition, e->actions)); 2609663Slinton actions = buildcmdlist(build(O_TRACEON, false, actions)); 2619663Slinton bp = bp_alloc(e, codeloc(p), 0, actions); 2629663Slinton } 2639663Slinton 2649663Slinton /* 2659663Slinton * Determine the deepest nested subprogram that still contains 2669663Slinton * all elements in the given expression. 2679663Slinton */ 2689663Slinton 2699663Slinton public Symbol tcontainer(exp) 2709663Slinton Node exp; 2719663Slinton { 2729663Slinton Integer i; 2739663Slinton Symbol s, t, u, v; 2749663Slinton 2759663Slinton checkref(exp); 2769663Slinton s = nil; 2779663Slinton if (exp->op == O_SYM) { 2789663Slinton s = container(exp->value.sym); 2799663Slinton } else if (not isleaf(exp->op)) { 2809663Slinton for (i = 0; i < nargs(exp->op); i++) { 2819663Slinton t = tcontainer(exp->value.arg[i]); 2829663Slinton if (t != nil) { 2839663Slinton if (s == nil) { 2849663Slinton s = t; 2859663Slinton } else { 2869663Slinton u = s; 2879663Slinton v = t; 2889663Slinton while (u != v and u != nil) { 2899663Slinton u = container(u); 2909663Slinton v = container(v); 2919663Slinton } 2929663Slinton if (u == nil) { 2939663Slinton panic("bad ancestry for \"%s\"", symname(s)); 2949663Slinton } else { 2959663Slinton s = u; 2969663Slinton } 2979663Slinton } 2989663Slinton } 2999663Slinton } 3009663Slinton } 3019663Slinton return s; 3029663Slinton } 3039663Slinton 3049663Slinton /* 305*11869Slinton * Determine if the given function can be executed at full speed. 306*11869Slinton * This can only be done if there are no breakpoints within the function. 307*11869Slinton */ 308*11869Slinton 309*11869Slinton public Boolean canskip(f) 310*11869Slinton Symbol f; 311*11869Slinton { 312*11869Slinton Breakpoint p; 313*11869Slinton Boolean ok; 314*11869Slinton 315*11869Slinton ok = true; 316*11869Slinton foreach (Breakpoint, p, bplist) 317*11869Slinton if (whatblock(p->bpaddr) == f) { 318*11869Slinton ok = false; 319*11869Slinton break; 320*11869Slinton } 321*11869Slinton endfor 322*11869Slinton return ok; 323*11869Slinton } 324*11869Slinton 325*11869Slinton /* 3269663Slinton * Print out what's currently being traced by looking at 3279663Slinton * the currently active events. 3289663Slinton * 3299663Slinton * Some convolution here to translate internal representation 3309663Slinton * of events back into something more palatable. 3319663Slinton */ 3329663Slinton 3339663Slinton public status() 3349663Slinton { 3359663Slinton Event e; 3369663Slinton 3379663Slinton foreach (Event, e, eventlist) 3389663Slinton if (not e->temporary) { 339*11869Slinton printevent(e); 3409663Slinton } 3419663Slinton endfor 3429663Slinton } 3439663Slinton 344*11869Slinton public printevent(e) 345*11869Slinton Event e; 346*11869Slinton { 347*11869Slinton Command cmd; 348*11869Slinton 349*11869Slinton if (not isredirected()) { 350*11869Slinton printf("(%d) ", e->id); 351*11869Slinton } 352*11869Slinton cmd = list_element(Command, list_head(e->actions)); 353*11869Slinton if (cmd->op == O_PRINTCALL) { 354*11869Slinton printf("trace "); 355*11869Slinton printname(stdout, cmd->value.sym); 356*11869Slinton } else { 357*11869Slinton if (list_size(e->actions) > 1) { 358*11869Slinton printf("{ "); 359*11869Slinton } 360*11869Slinton foreach (Command, cmd, e->actions) 361*11869Slinton printcmd(stdout, cmd); 362*11869Slinton if (not list_islast()) { 363*11869Slinton printf("; "); 364*11869Slinton } 365*11869Slinton endfor 366*11869Slinton if (list_size(e->actions) > 1) { 367*11869Slinton printf(" }"); 368*11869Slinton } 369*11869Slinton printcond(e->condition); 370*11869Slinton } 371*11869Slinton printf("\n"); 372*11869Slinton } 373*11869Slinton 3749663Slinton /* 3759663Slinton * Print out a condition. 3769663Slinton */ 3779663Slinton 3789663Slinton private printcond(cond) 3799663Slinton Node cond; 3809663Slinton { 3819663Slinton Symbol s; 3829663Slinton Node place; 3839663Slinton 3849663Slinton if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) { 3859663Slinton s = cond->value.arg[0]->value.sym; 3869663Slinton place = cond->value.arg[1]; 3879663Slinton if (s == procsym) { 3889663Slinton if (place->value.sym != program) { 3899663Slinton printf(" in "); 3909663Slinton printname(stdout, place->value.sym); 3919663Slinton } 3929663Slinton } else if (s == linesym) { 3939663Slinton printf(" at "); 3949663Slinton prtree(stdout, place); 3959663Slinton } else if (s == pcsym or s == retaddrsym) { 3969663Slinton printf("i at "); 3979663Slinton prtree(stdout, place); 3989663Slinton } else { 3999663Slinton printf(" when "); 4009663Slinton prtree(stdout, cond); 4019663Slinton } 4029663Slinton } else { 4039663Slinton printf(" when "); 4049663Slinton prtree(stdout, cond); 4059663Slinton } 4069663Slinton } 4079663Slinton 4089663Slinton /* 4099663Slinton * Add a breakpoint to the list and return it. 4109663Slinton */ 4119663Slinton 4129663Slinton private Breakpoint bp_alloc(e, addr, line, actions) 4139663Slinton Event e; 4149663Slinton Address addr; 4159663Slinton Lineno line; 4169663Slinton Cmdlist actions; 4179663Slinton { 4189663Slinton register Breakpoint p; 4199663Slinton 4209663Slinton p = new(Breakpoint); 4219663Slinton p->event = e; 4229663Slinton p->bpaddr = addr; 4239663Slinton p->bpline = line; 4249663Slinton p->actions = actions; 4259663Slinton if (tracebpts) { 4269663Slinton printf("new bp at 0x%x\n", addr); 4279663Slinton fflush(stdout); 4289663Slinton } 4299663Slinton bplist_append(p, bplist); 4309663Slinton return p; 4319663Slinton } 4329663Slinton 4339663Slinton /* 4349663Slinton * Free all storage in the event and breakpoint tables. 4359663Slinton */ 4369663Slinton 4379663Slinton public bpfree() 4389663Slinton { 4399663Slinton register Event e; 4409663Slinton 4419663Slinton fixbps(); 4429663Slinton foreach (Event, e, eventlist) 4439663Slinton delevent(e->id); 4449663Slinton list_delete(list_curitem(eventlist), eventlist); 4459663Slinton endfor 4469663Slinton } 4479663Slinton 4489663Slinton /* 4499663Slinton * Determine if the program stopped at a known breakpoint 4509663Slinton * and if so do the associated commands. 4519663Slinton */ 4529663Slinton 4539663Slinton public Boolean bpact() 4549663Slinton { 4559663Slinton register Breakpoint p; 4569663Slinton Boolean found; 4579663Slinton 4589663Slinton found = false; 4599663Slinton foreach (Breakpoint, p, bplist) 4609663Slinton if (p->bpaddr == pc) { 4619663Slinton if (tracebpts) { 4629663Slinton printf("breakpoint found at location 0x%x\n", pc); 4639663Slinton } 4649663Slinton found = true; 4659663Slinton if (p->event->temporary) { 4669663Slinton delevent(p->event->id); 4679663Slinton } 4689663Slinton evalcmdlist(p->actions); 4699663Slinton } 4709663Slinton endfor 4719663Slinton if (isstopped) { 4729663Slinton printstatus(); 4739663Slinton } 4749663Slinton fflush(stdout); 4759663Slinton return found; 4769663Slinton } 4779663Slinton 4789663Slinton /* 4799663Slinton * Begin single stepping and executing the given commands after each step. 4809663Slinton * If the first argument is true step by instructions, otherwise 4819663Slinton * step by source lines. 4829663Slinton * 4839663Slinton * We automatically set a breakpoint at the end of the current procedure 4849663Slinton * to turn off the given tracing. 4859663Slinton */ 4869663Slinton 4879663Slinton public traceon(inst, event, cmdlist) 4889663Slinton Boolean inst; 4899663Slinton Event event; 4909663Slinton Cmdlist cmdlist; 4919663Slinton { 4929663Slinton register Trcmd trcmd; 4939663Slinton Breakpoint bp; 4949663Slinton Node until; 4959663Slinton Cmdlist actions; 496*11869Slinton Address ret; 4979663Slinton 4989663Slinton trcmd = new(Trcmd); 4999663Slinton ++trid; 5009663Slinton trcmd->trid = trid; 5019663Slinton trcmd->event = event; 5029663Slinton trcmd->cmdlist = cmdlist; 5039663Slinton single_stepping = true; 5049663Slinton if (inst) { 5059663Slinton inst_tracing = true; 5069663Slinton list_append(list_item(trcmd), nil, eachinst); 5079663Slinton } else { 5089663Slinton list_append(list_item(trcmd), nil, eachline); 5099663Slinton } 510*11869Slinton ret = return_addr(); 511*11869Slinton if (ret != 0) { 512*11869Slinton until = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, ret)); 513*11869Slinton actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid)); 514*11869Slinton event_once(until, actions); 515*11869Slinton } 5169663Slinton if (tracebpts) { 5179663Slinton printf("adding trace %d for event %d\n", trcmd->trid, event->id); 5189663Slinton } 5199663Slinton } 5209663Slinton 5219663Slinton /* 5229663Slinton * Turn off some kind of tracing. 5239663Slinton * Strictly an internal command, this cannot be invoked by the user. 5249663Slinton */ 5259663Slinton 5269663Slinton public traceoff(id) 5279663Slinton Integer id; 5289663Slinton { 5299663Slinton register Trcmd t; 5309663Slinton register Boolean found; 5319663Slinton 5329663Slinton found = false; 5339663Slinton foreach (Trcmd, t, eachline) 5349663Slinton if (t->trid == id) { 5359663Slinton printrmtr(t); 5369663Slinton list_delete(list_curitem(eachline), eachline); 5379663Slinton found = true; 5389663Slinton break; 5399663Slinton } 5409663Slinton endfor 5419663Slinton if (not found) { 5429663Slinton foreach (Trcmd, t, eachinst) 5439663Slinton if (t->event->id == id) { 5449663Slinton printrmtr(t); 5459663Slinton list_delete(list_curitem(eachinst), eachinst); 5469663Slinton found = true; 5479663Slinton break; 5489663Slinton } 5499663Slinton endfor 5509663Slinton if (not found) { 5519663Slinton panic("missing trid %d", id); 5529663Slinton } 5539663Slinton } 5549663Slinton if (list_size(eachinst) == 0) { 5559663Slinton inst_tracing = false; 5569663Slinton if (list_size(eachline) == 0) { 5579663Slinton single_stepping = false; 5589663Slinton } 5599663Slinton } 5609663Slinton } 5619663Slinton 5629663Slinton /* 5639663Slinton * If breakpoints are being traced, note that a Trcmd is being deleted. 5649663Slinton */ 5659663Slinton 5669663Slinton private printrmtr(t) 5679663Slinton Trcmd t; 5689663Slinton { 5699663Slinton if (tracebpts) { 570*11869Slinton printf("removing trace %d", t->trid); 571*11869Slinton if (t->event != nil) { 572*11869Slinton printf(" for event %d", t->event->id); 573*11869Slinton } 574*11869Slinton printf("\n"); 5759663Slinton } 5769663Slinton } 5779663Slinton 5789663Slinton /* 5799663Slinton * Print out news during single step tracing. 5809663Slinton */ 5819663Slinton 5829663Slinton public printnews() 5839663Slinton { 5849663Slinton register Trcmd t; 5859663Slinton 5869663Slinton foreach (Trcmd, t, eachline) 5879663Slinton evalcmdlist(t->cmdlist); 5889663Slinton endfor 5899663Slinton foreach (Trcmd, t, eachinst) 5909663Slinton evalcmdlist(t->cmdlist); 5919663Slinton endfor 5929663Slinton bpact(); 5939663Slinton } 5949663Slinton 5959663Slinton /* 5969663Slinton * A procedure call/return has occurred while single-stepping, 5979663Slinton * note it if we're tracing lines. 5989663Slinton */ 5999663Slinton 6009663Slinton private Boolean chklist(); 6019663Slinton 6029663Slinton public callnews(iscall) 6039663Slinton Boolean iscall; 6049663Slinton { 6059663Slinton if (not chklist(eachline, iscall)) { 6069663Slinton chklist(eachinst, iscall); 6079663Slinton } 6089663Slinton } 6099663Slinton 6109663Slinton private Boolean chklist(list, iscall) 6119663Slinton List list; 6129663Slinton Boolean iscall; 6139663Slinton { 6149663Slinton register Trcmd t; 6159663Slinton register Command cmd; 6169663Slinton 617*11869Slinton curfunc = whatblock(pc); 6189663Slinton foreach (Trcmd, t, list) 6199663Slinton foreach (Command, cmd, t->cmdlist) 6209663Slinton if (cmd->op == O_PRINTSRCPOS and 6219663Slinton (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) { 6229663Slinton if (iscall) { 6239663Slinton printentry(curfunc); 6249663Slinton } else { 6259663Slinton printexit(curfunc); 6269663Slinton } 6279663Slinton return true; 6289663Slinton } 6299663Slinton endfor 6309663Slinton endfor 6319663Slinton return false; 6329663Slinton } 6339663Slinton 6349663Slinton /* 6359663Slinton * When tracing variables we keep a copy of their most recent value 6369663Slinton * and compare it to the current one each time a breakpoint occurs. 6379663Slinton * MAXTRSIZE is the maximum size variable we allow. 6389663Slinton */ 6399663Slinton 6409663Slinton #define MAXTRSIZE 512 6419663Slinton 6429663Slinton /* 6439663Slinton * List of variables being watched. 6449663Slinton */ 6459663Slinton 6469663Slinton typedef struct Trinfo *Trinfo; 6479663Slinton 6489663Slinton struct Trinfo { 6499663Slinton Node variable; 6509663Slinton Address traddr; 6519663Slinton Symbol trblock; 6529663Slinton char *trvalue; 6539663Slinton }; 6549663Slinton 6559663Slinton private List trinfolist; 6569663Slinton 6579663Slinton /* 6589663Slinton * Find the trace information record associated with the given record. 6599663Slinton * If there isn't one then create it and add it to the list. 6609663Slinton */ 6619663Slinton 6629663Slinton private Trinfo findtrinfo(p) 6639663Slinton Node p; 6649663Slinton { 6659663Slinton register Trinfo tp; 6669663Slinton Boolean isnew; 6679663Slinton 6689663Slinton isnew = true; 6699663Slinton if (trinfolist == nil) { 6709663Slinton trinfolist = list_alloc(); 6719663Slinton } else { 6729663Slinton foreach (Trinfo, tp, trinfolist) 6739663Slinton if (tp->variable == p) { 6749663Slinton isnew = false; 6759663Slinton break; 6769663Slinton } 6779663Slinton endfor 6789663Slinton } 6799663Slinton if (isnew) { 6809663Slinton if (tracebpts) { 6819663Slinton printf("adding trinfo for \""); 6829663Slinton prtree(stdout, p); 6839663Slinton printf("\"\n"); 6849663Slinton } 6859663Slinton tp = new(Trinfo); 6869663Slinton tp->variable = p; 6879663Slinton tp->traddr = lval(p); 6889663Slinton tp->trvalue = nil; 6899663Slinton list_append(list_item(tp), nil, trinfolist); 6909663Slinton } 6919663Slinton return tp; 6929663Slinton } 6939663Slinton 6949663Slinton /* 6959663Slinton * Print out the value of a variable if it has changed since the 6969663Slinton * last time we checked. 6979663Slinton */ 6989663Slinton 6999663Slinton public printifchanged(p) 7009663Slinton Node p; 7019663Slinton { 7029663Slinton register Trinfo tp; 7039663Slinton register int n; 7049663Slinton char buff[MAXTRSIZE]; 7059663Slinton static Lineno prevline; 7069663Slinton 7079663Slinton tp = findtrinfo(p); 7089663Slinton n = size(p->nodetype); 7099663Slinton dread(buff, tp->traddr, n); 7109663Slinton if (tp->trvalue == nil) { 7119663Slinton tp->trvalue = newarr(char, n); 7129663Slinton mov(buff, tp->trvalue, n); 7139663Slinton mov(buff, sp, n); 7149663Slinton sp += n; 7159663Slinton printf("initially (at line %d):\t", curline); 7169663Slinton prtree(stdout, p); 7179663Slinton printf(" = "); 7189663Slinton printval(p->nodetype); 7199663Slinton putchar('\n'); 7209663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 7219663Slinton mov(buff, tp->trvalue, n); 7229663Slinton mov(buff, sp, n); 7239663Slinton sp += n; 7249663Slinton printf("after line %d:\t", prevline); 7259663Slinton prtree(stdout, p); 7269663Slinton printf(" = "); 7279663Slinton printval(p->nodetype); 7289663Slinton putchar('\n'); 7299663Slinton } 7309663Slinton prevline = curline; 7319663Slinton } 7329663Slinton 7339663Slinton /* 7349663Slinton * Stop if the value of the given expression has changed. 7359663Slinton */ 7369663Slinton 7379663Slinton public stopifchanged(p) 7389663Slinton Node p; 7399663Slinton { 7409663Slinton register Trinfo tp; 7419663Slinton register int n; 7429663Slinton char buff[MAXTRSIZE]; 7439663Slinton static Lineno prevline; 7449663Slinton 7459663Slinton tp = findtrinfo(p); 7469663Slinton n = size(p->nodetype); 7479663Slinton dread(buff, tp->traddr, n); 7489663Slinton if (tp->trvalue == nil) { 7499663Slinton tp->trvalue = newarr(char, n); 7509663Slinton mov(buff, tp->trvalue, n); 7519663Slinton isstopped = true; 7529663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 7539663Slinton mov(buff, tp->trvalue, n); 7549663Slinton isstopped = true; 7559663Slinton } 7569663Slinton prevline = curline; 7579663Slinton } 7589663Slinton 7599663Slinton /* 7609663Slinton * Free the tracing table. 7619663Slinton */ 7629663Slinton 7639663Slinton public trfree() 7649663Slinton { 7659663Slinton register Trinfo tp; 7669663Slinton 7679663Slinton foreach (Trinfo, tp, trinfolist) 7689663Slinton dispose(tp->trvalue); 7699663Slinton dispose(tp); 7709663Slinton list_delete(list_curitem(trinfolist), trinfolist); 7719663Slinton endfor 7729663Slinton } 7739663Slinton 7749663Slinton /* 7759663Slinton * Fix up breakpoint information before continuing execution. 7769663Slinton * 7779663Slinton * It's necessary to destroy events and breakpoints that were created 7789663Slinton * temporarily and still exist because the program terminated abnormally. 7799663Slinton */ 7809663Slinton 7819663Slinton public fixbps() 7829663Slinton { 7839663Slinton register Event e; 7849663Slinton register Trcmd t; 7859663Slinton 7869663Slinton single_stepping = false; 7879663Slinton inst_tracing = false; 7889663Slinton trfree(); 7899663Slinton foreach (Event, e, eventlist) 7909663Slinton if (e->temporary) { 7919663Slinton delevent(e->id); 7929663Slinton } 7939663Slinton endfor 7949663Slinton foreach (Trcmd, t, eachline) 7959663Slinton printrmtr(t); 7969663Slinton list_delete(list_curitem(eachline), eachline); 7979663Slinton endfor 7989663Slinton foreach (Trcmd, t, eachinst) 7999663Slinton printrmtr(t); 8009663Slinton list_delete(list_curitem(eachinst), eachinst); 8019663Slinton endfor 8029663Slinton } 8039663Slinton 8049663Slinton /* 8059663Slinton * Set all breakpoints in object code. 8069663Slinton */ 8079663Slinton 8089663Slinton public setallbps() 8099663Slinton { 8109663Slinton register Breakpoint p; 8119663Slinton 8129663Slinton foreach (Breakpoint, p, bplist) 8139663Slinton setbp(p->bpaddr); 8149663Slinton endfor 8159663Slinton } 8169663Slinton 8179663Slinton /* 8189663Slinton * Undo damage done by "setallbps". 8199663Slinton */ 8209663Slinton 8219663Slinton public unsetallbps() 8229663Slinton { 8239663Slinton register Breakpoint p; 8249663Slinton 8259663Slinton foreach (Breakpoint, p, bplist) 8269663Slinton unsetbp(p->bpaddr); 8279663Slinton endfor 8289663Slinton } 829