19663Slinton /* Copyright (c) 1982 Regents of the University of California */ 29663Slinton 3*16609Ssam static char sccsid[] = "@(#)events.c 1.3 4/8/83"; 49663Slinton 5*16609Ssam static char rcsid[] = "$Header: events.c,v 1.3 84/03/27 10:20:41 linton Exp $"; 6*16609Ssam 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" 19*16609Ssam #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 289663Slinton Boolean inst_tracing; 299663Slinton Boolean single_stepping; 309663Slinton 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; 469663Slinton 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; 569663Slinton }; 579663Slinton 589663Slinton typedef List Eventlist; 599663Slinton typedef List Bplist; 609663Slinton 619663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el) 629663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl) 639663Slinton 649663Slinton private Eventlist eventlist; /* list of active events */ 659663Slinton private Bplist bplist; /* list of active breakpoints */ 669663Slinton private Integer eventid; /* id number of next allocated event */ 679663Slinton private Integer trid; /* id number of next allocated trace */ 689663Slinton 699663Slinton typedef struct Trcmd { 709663Slinton Integer trid; 719663Slinton Event event; 729663Slinton Cmdlist cmdlist; 739663Slinton } *Trcmd; 749663Slinton 759663Slinton private List eachline; /* commands to execute after each line */ 769663Slinton private List eachinst; /* commands to execute after each instruction */ 779663Slinton 789663Slinton private Breakpoint bp_alloc(); 799663Slinton 809663Slinton /* 819663Slinton * Initialize breakpoint information. 829663Slinton */ 839663Slinton 849663Slinton private Symbol builtinsym(str, class, type) 859663Slinton String str; 869663Slinton Symclass class; 879663Slinton Symbol type; 889663Slinton { 899663Slinton Symbol s; 909663Slinton 919663Slinton s = insert(identname(str, true)); 929663Slinton s->language = findlanguage(".s"); 939663Slinton s->class = class; 949663Slinton s->type = type; 959663Slinton return s; 969663Slinton } 979663Slinton 989663Slinton public bpinit() 999663Slinton { 1009663Slinton linesym = builtinsym("$line", VAR, t_int); 1019663Slinton procsym = builtinsym("$proc", PROC, nil); 1029663Slinton pcsym = lookup(identname("$pc", true)); 1039663Slinton if (pcsym == nil) { 1049663Slinton panic("can't find $pc"); 1059663Slinton } 1069663Slinton retaddrsym = builtinsym("$retaddr", VAR, t_int); 1079663Slinton eventlist = list_alloc(); 1089663Slinton bplist = list_alloc(); 1099663Slinton eachline = list_alloc(); 1109663Slinton eachinst = list_alloc(); 1119663Slinton } 1129663Slinton 1139663Slinton /* 1149663Slinton * Trap an event and do the associated commands when it occurs. 1159663Slinton */ 1169663Slinton 1179663Slinton public Event event_alloc(istmp, econd, cmdlist) 1189663Slinton Boolean istmp; 1199663Slinton Node econd; 1209663Slinton Cmdlist cmdlist; 1219663Slinton { 1229663Slinton register Event e; 1239663Slinton 1249663Slinton e = new(Event); 1259663Slinton ++eventid; 1269663Slinton e->id = eventid; 1279663Slinton e->temporary = istmp; 1289663Slinton e->condition = econd; 1299663Slinton e->actions = cmdlist; 1309663Slinton eventlist_append(e, eventlist); 1319663Slinton translate(e); 1329663Slinton return e; 1339663Slinton } 1349663Slinton 1359663Slinton /* 1369663Slinton * Delete the event with the given id. 137*16609Ssam * Returns whether it's successful or not. 1389663Slinton */ 1399663Slinton 140*16609Ssam public boolean delevent (id) 1419663Slinton unsigned int id; 1429663Slinton { 1439663Slinton Event e; 1449663Slinton Breakpoint bp; 1459663Slinton Trcmd t; 146*16609Ssam boolean found; 1479663Slinton 148*16609Ssam found = false; 1499663Slinton foreach (Event, e, eventlist) 1509663Slinton if (e->id == id) { 151*16609Ssam found = true; 1529663Slinton foreach (Breakpoint, bp, bplist) 1539663Slinton if (bp->event == e) { 154*16609Ssam if (tracebpts) { 155*16609Ssam printf("deleting breakpoint at 0x%x\n", bp->bpaddr); 156*16609Ssam fflush(stdout); 157*16609Ssam } 1589663Slinton list_delete(list_curitem(bplist), bplist); 1599663Slinton } 1609663Slinton endfor 161*16609Ssam list_delete(list_curitem(eventlist), eventlist); 1629663Slinton break; 1639663Slinton } 1649663Slinton endfor 1659663Slinton foreach (Trcmd, t, eachline) 1669663Slinton if (t->event->id == id) { 167*16609Ssam found = true; 1689663Slinton printrmtr(t); 1699663Slinton list_delete(list_curitem(eachline), eachline); 1709663Slinton } 1719663Slinton endfor 1729663Slinton foreach (Trcmd, t, eachinst) 1739663Slinton if (t->event->id == id) { 174*16609Ssam found = true; 1759663Slinton printrmtr(t); 1769663Slinton list_delete(list_curitem(eachinst), eachinst); 1779663Slinton } 1789663Slinton endfor 1799663Slinton if (list_size(eachinst) == 0) { 1809663Slinton inst_tracing = false; 1819663Slinton if (list_size(eachline) == 0) { 1829663Slinton single_stepping = false; 1839663Slinton } 1849663Slinton } 185*16609Ssam return found; 1869663Slinton } 1879663Slinton 1889663Slinton /* 1899663Slinton * Translate an event into the appropriate breakpoints and actions. 1909663Slinton * While we're at it, turn on the breakpoints if the condition is true. 1919663Slinton */ 1929663Slinton 1939663Slinton private translate(e) 1949663Slinton Event e; 1959663Slinton { 1969663Slinton Breakpoint bp; 1979663Slinton Symbol s; 1989663Slinton Node place; 1999663Slinton Lineno line; 2009663Slinton Address addr; 2019663Slinton 2029663Slinton checkref(e->condition); 2039663Slinton switch (e->condition->op) { 2049663Slinton case O_EQ: 2059663Slinton if (e->condition->value.arg[0]->op == O_SYM) { 2069663Slinton s = e->condition->value.arg[0]->value.sym; 2079663Slinton place = e->condition->value.arg[1]; 2089663Slinton if (s == linesym) { 2099663Slinton if (place->op == O_QLINE) { 2109663Slinton line = place->value.arg[1]->value.lcon; 211*16609Ssam addr = objaddr(line, place->value.arg[0]->value.scon); 2129663Slinton } else { 2139663Slinton eval(place); 2149663Slinton line = pop(long); 2159663Slinton addr = objaddr(line, cursource); 2169663Slinton } 2179663Slinton if (addr == NOADDR) { 218*16609Ssam if (not delevent(e->id)) { 219*16609Ssam printf("!! dbx.translate: can't undo event %d?\n", 220*16609Ssam e->id); 221*16609Ssam } 2229663Slinton beginerrmsg(); 2239663Slinton fprintf(stderr, "no executable code at line "); 2249663Slinton prtree(stderr, place); 2259663Slinton enderrmsg(); 2269663Slinton } 2279663Slinton bp = bp_alloc(e, addr, line, e->actions); 2289663Slinton } else if (s == procsym) { 2299663Slinton eval(place); 2309663Slinton s = pop(Symbol); 2319663Slinton bp = bp_alloc(e, codeloc(s), 0, e->actions); 2329663Slinton if (isactive(s) and pc != codeloc(program)) { 2339663Slinton evalcmdlist(e->actions); 2349663Slinton } 2359663Slinton } else if (s == pcsym) { 2369663Slinton eval(place); 2379663Slinton bp = bp_alloc(e, pop(Address), 0, e->actions); 2389663Slinton } else { 2399663Slinton condbp(e); 2409663Slinton } 2419663Slinton } else { 2429663Slinton condbp(e); 2439663Slinton } 2449663Slinton break; 2459663Slinton 2469663Slinton /* 2479663Slinton * These should be handled specially. 2489663Slinton * But for now I'm ignoring the problem. 2499663Slinton */ 2509663Slinton case O_AND: 2519663Slinton case O_OR: 2529663Slinton default: 2539663Slinton condbp(e); 2549663Slinton break; 2559663Slinton } 2569663Slinton } 2579663Slinton 2589663Slinton /* 2599663Slinton * Create a breakpoint for a condition that cannot be pinpointed 2609663Slinton * to happening at a particular address, but one for which we 2619663Slinton * must single step and check the condition after each statement. 2629663Slinton */ 2639663Slinton 2649663Slinton private condbp(e) 2659663Slinton Event e; 2669663Slinton { 2679663Slinton Symbol p; 2689663Slinton Breakpoint bp; 2699663Slinton Cmdlist actions; 2709663Slinton 2719663Slinton p = tcontainer(e->condition); 2729663Slinton if (p == nil) { 2739663Slinton p = program; 2749663Slinton } 2759663Slinton actions = buildcmdlist(build(O_IF, e->condition, e->actions)); 2769663Slinton actions = buildcmdlist(build(O_TRACEON, false, actions)); 2779663Slinton bp = bp_alloc(e, codeloc(p), 0, actions); 2789663Slinton } 2799663Slinton 2809663Slinton /* 2819663Slinton * Determine the deepest nested subprogram that still contains 2829663Slinton * all elements in the given expression. 2839663Slinton */ 2849663Slinton 2859663Slinton public Symbol tcontainer(exp) 2869663Slinton Node exp; 2879663Slinton { 2889663Slinton Integer i; 2899663Slinton Symbol s, t, u, v; 2909663Slinton 2919663Slinton checkref(exp); 2929663Slinton s = nil; 2939663Slinton if (exp->op == O_SYM) { 2949663Slinton s = container(exp->value.sym); 2959663Slinton } else if (not isleaf(exp->op)) { 2969663Slinton for (i = 0; i < nargs(exp->op); i++) { 2979663Slinton t = tcontainer(exp->value.arg[i]); 2989663Slinton if (t != nil) { 2999663Slinton if (s == nil) { 3009663Slinton s = t; 3019663Slinton } else { 3029663Slinton u = s; 3039663Slinton v = t; 3049663Slinton while (u != v and u != nil) { 3059663Slinton u = container(u); 3069663Slinton v = container(v); 3079663Slinton } 3089663Slinton if (u == nil) { 3099663Slinton panic("bad ancestry for \"%s\"", symname(s)); 3109663Slinton } else { 3119663Slinton s = u; 3129663Slinton } 3139663Slinton } 3149663Slinton } 3159663Slinton } 3169663Slinton } 3179663Slinton return s; 3189663Slinton } 3199663Slinton 3209663Slinton /* 32111869Slinton * Determine if the given function can be executed at full speed. 32211869Slinton * This can only be done if there are no breakpoints within the function. 32311869Slinton */ 32411869Slinton 32511869Slinton public Boolean canskip(f) 32611869Slinton Symbol f; 32711869Slinton { 32811869Slinton Breakpoint p; 32911869Slinton Boolean ok; 33011869Slinton 33111869Slinton ok = true; 33211869Slinton foreach (Breakpoint, p, bplist) 33311869Slinton if (whatblock(p->bpaddr) == f) { 33411869Slinton ok = false; 33511869Slinton break; 33611869Slinton } 33711869Slinton endfor 33811869Slinton return ok; 33911869Slinton } 34011869Slinton 34111869Slinton /* 3429663Slinton * Print out what's currently being traced by looking at 3439663Slinton * the currently active events. 3449663Slinton * 3459663Slinton * Some convolution here to translate internal representation 3469663Slinton * of events back into something more palatable. 3479663Slinton */ 3489663Slinton 3499663Slinton public status() 3509663Slinton { 3519663Slinton Event e; 3529663Slinton 3539663Slinton foreach (Event, e, eventlist) 3549663Slinton if (not e->temporary) { 35511869Slinton printevent(e); 3569663Slinton } 3579663Slinton endfor 3589663Slinton } 3599663Slinton 36011869Slinton public printevent(e) 36111869Slinton Event e; 36211869Slinton { 36311869Slinton Command cmd; 36411869Slinton 36511869Slinton if (not isredirected()) { 366*16609Ssam printeventid(e->id); 36711869Slinton } 36811869Slinton cmd = list_element(Command, list_head(e->actions)); 36911869Slinton if (cmd->op == O_PRINTCALL) { 37011869Slinton printf("trace "); 37111869Slinton printname(stdout, cmd->value.sym); 37211869Slinton } else { 37311869Slinton if (list_size(e->actions) > 1) { 37411869Slinton printf("{ "); 37511869Slinton } 37611869Slinton foreach (Command, cmd, e->actions) 37711869Slinton printcmd(stdout, cmd); 37811869Slinton if (not list_islast()) { 37911869Slinton printf("; "); 38011869Slinton } 38111869Slinton endfor 38211869Slinton if (list_size(e->actions) > 1) { 38311869Slinton printf(" }"); 38411869Slinton } 38511869Slinton printcond(e->condition); 38611869Slinton } 38711869Slinton printf("\n"); 38811869Slinton } 38911869Slinton 390*16609Ssam private printeventid (id) 391*16609Ssam integer id; 392*16609Ssam { 393*16609Ssam printf("[%d] ", id); 394*16609Ssam } 395*16609Ssam 3969663Slinton /* 3979663Slinton * Print out a condition. 3989663Slinton */ 3999663Slinton 4009663Slinton private printcond(cond) 4019663Slinton Node cond; 4029663Slinton { 4039663Slinton Symbol s; 4049663Slinton Node place; 4059663Slinton 4069663Slinton if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) { 4079663Slinton s = cond->value.arg[0]->value.sym; 4089663Slinton place = cond->value.arg[1]; 4099663Slinton if (s == procsym) { 4109663Slinton if (place->value.sym != program) { 4119663Slinton printf(" in "); 4129663Slinton printname(stdout, place->value.sym); 4139663Slinton } 4149663Slinton } else if (s == linesym) { 4159663Slinton printf(" at "); 4169663Slinton prtree(stdout, place); 4179663Slinton } else if (s == pcsym or s == retaddrsym) { 4189663Slinton printf("i at "); 4199663Slinton prtree(stdout, place); 4209663Slinton } else { 4219663Slinton printf(" when "); 4229663Slinton prtree(stdout, cond); 4239663Slinton } 4249663Slinton } else { 4259663Slinton printf(" when "); 4269663Slinton prtree(stdout, cond); 4279663Slinton } 4289663Slinton } 4299663Slinton 4309663Slinton /* 4319663Slinton * Add a breakpoint to the list and return it. 4329663Slinton */ 4339663Slinton 4349663Slinton private Breakpoint bp_alloc(e, addr, line, actions) 4359663Slinton Event e; 4369663Slinton Address addr; 4379663Slinton Lineno line; 4389663Slinton Cmdlist actions; 4399663Slinton { 4409663Slinton register Breakpoint p; 4419663Slinton 4429663Slinton p = new(Breakpoint); 4439663Slinton p->event = e; 4449663Slinton p->bpaddr = addr; 4459663Slinton p->bpline = line; 4469663Slinton p->actions = actions; 4479663Slinton if (tracebpts) { 448*16609Ssam if (e == nil) { 449*16609Ssam printf("new bp at 0x%x for event ??\n", addr, e->id); 450*16609Ssam } else { 451*16609Ssam printf("new bp at 0x%x for event %d\n", addr, e->id); 452*16609Ssam } 4539663Slinton fflush(stdout); 4549663Slinton } 4559663Slinton bplist_append(p, bplist); 4569663Slinton return p; 4579663Slinton } 4589663Slinton 4599663Slinton /* 4609663Slinton * Free all storage in the event and breakpoint tables. 4619663Slinton */ 4629663Slinton 4639663Slinton public bpfree() 4649663Slinton { 4659663Slinton register Event e; 4669663Slinton 4679663Slinton fixbps(); 4689663Slinton foreach (Event, e, eventlist) 469*16609Ssam if (not delevent(e->id)) { 470*16609Ssam printf("!! dbx.bpfree: can't delete event %d\n", e->id); 471*16609Ssam } 4729663Slinton list_delete(list_curitem(eventlist), eventlist); 4739663Slinton endfor 4749663Slinton } 4759663Slinton 4769663Slinton /* 4779663Slinton * Determine if the program stopped at a known breakpoint 4789663Slinton * and if so do the associated commands. 4799663Slinton */ 4809663Slinton 4819663Slinton public Boolean bpact() 4829663Slinton { 4839663Slinton register Breakpoint p; 4849663Slinton Boolean found; 485*16609Ssam integer eventId; 4869663Slinton 4879663Slinton found = false; 4889663Slinton foreach (Breakpoint, p, bplist) 4899663Slinton if (p->bpaddr == pc) { 4909663Slinton if (tracebpts) { 491*16609Ssam printf("breakpoint for event %d found at location 0x%x\n", 492*16609Ssam p->event->id, pc); 4939663Slinton } 4949663Slinton found = true; 4959663Slinton if (p->event->temporary) { 496*16609Ssam if (not delevent(p->event->id)) { 497*16609Ssam printf("!! dbx.bpact: can't find event %d\n", 498*16609Ssam p->event->id); 499*16609Ssam } 5009663Slinton } 5019663Slinton evalcmdlist(p->actions); 502*16609Ssam if (isstopped) { 503*16609Ssam eventId = p->event->id; 504*16609Ssam } 5059663Slinton } 5069663Slinton endfor 5079663Slinton if (isstopped) { 508*16609Ssam if (found) { 509*16609Ssam printeventid(eventId); 510*16609Ssam } 5119663Slinton printstatus(); 5129663Slinton } 5139663Slinton fflush(stdout); 5149663Slinton return found; 5159663Slinton } 5169663Slinton 5179663Slinton /* 5189663Slinton * Begin single stepping and executing the given commands after each step. 5199663Slinton * If the first argument is true step by instructions, otherwise 5209663Slinton * step by source lines. 5219663Slinton * 5229663Slinton * We automatically set a breakpoint at the end of the current procedure 5239663Slinton * to turn off the given tracing. 5249663Slinton */ 5259663Slinton 5269663Slinton public traceon(inst, event, cmdlist) 5279663Slinton Boolean inst; 5289663Slinton Event event; 5299663Slinton Cmdlist cmdlist; 5309663Slinton { 5319663Slinton register Trcmd trcmd; 5329663Slinton Breakpoint bp; 5339663Slinton Cmdlist actions; 53411869Slinton Address ret; 5359663Slinton 5369663Slinton trcmd = new(Trcmd); 5379663Slinton ++trid; 5389663Slinton trcmd->trid = trid; 5399663Slinton trcmd->event = event; 5409663Slinton trcmd->cmdlist = cmdlist; 5419663Slinton single_stepping = true; 5429663Slinton if (inst) { 5439663Slinton inst_tracing = true; 5449663Slinton list_append(list_item(trcmd), nil, eachinst); 5459663Slinton } else { 5469663Slinton list_append(list_item(trcmd), nil, eachline); 5479663Slinton } 54811869Slinton ret = return_addr(); 54911869Slinton if (ret != 0) { 55011869Slinton actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid)); 551*16609Ssam bp = bp_alloc(event, (Address) ret, 0, actions); 55211869Slinton } 5539663Slinton if (tracebpts) { 5549663Slinton printf("adding trace %d for event %d\n", trcmd->trid, event->id); 5559663Slinton } 5569663Slinton } 5579663Slinton 5589663Slinton /* 5599663Slinton * Turn off some kind of tracing. 5609663Slinton * Strictly an internal command, this cannot be invoked by the user. 5619663Slinton */ 5629663Slinton 5639663Slinton public traceoff(id) 5649663Slinton Integer id; 5659663Slinton { 5669663Slinton register Trcmd t; 5679663Slinton register Boolean found; 5689663Slinton 5699663Slinton found = false; 5709663Slinton foreach (Trcmd, t, eachline) 5719663Slinton if (t->trid == id) { 5729663Slinton printrmtr(t); 5739663Slinton list_delete(list_curitem(eachline), eachline); 5749663Slinton found = true; 5759663Slinton break; 5769663Slinton } 5779663Slinton endfor 5789663Slinton if (not found) { 5799663Slinton foreach (Trcmd, t, eachinst) 5809663Slinton if (t->event->id == id) { 5819663Slinton printrmtr(t); 5829663Slinton list_delete(list_curitem(eachinst), eachinst); 5839663Slinton found = true; 5849663Slinton break; 5859663Slinton } 5869663Slinton endfor 5879663Slinton if (not found) { 5889663Slinton panic("missing trid %d", id); 5899663Slinton } 5909663Slinton } 5919663Slinton if (list_size(eachinst) == 0) { 5929663Slinton inst_tracing = false; 5939663Slinton if (list_size(eachline) == 0) { 5949663Slinton single_stepping = false; 5959663Slinton } 5969663Slinton } 5979663Slinton } 5989663Slinton 5999663Slinton /* 6009663Slinton * If breakpoints are being traced, note that a Trcmd is being deleted. 6019663Slinton */ 6029663Slinton 6039663Slinton private printrmtr(t) 6049663Slinton Trcmd t; 6059663Slinton { 6069663Slinton if (tracebpts) { 60711869Slinton printf("removing trace %d", t->trid); 60811869Slinton if (t->event != nil) { 60911869Slinton printf(" for event %d", t->event->id); 61011869Slinton } 61111869Slinton printf("\n"); 6129663Slinton } 6139663Slinton } 6149663Slinton 6159663Slinton /* 6169663Slinton * Print out news during single step tracing. 6179663Slinton */ 6189663Slinton 6199663Slinton public printnews() 6209663Slinton { 6219663Slinton register Trcmd t; 6229663Slinton 6239663Slinton foreach (Trcmd, t, eachline) 6249663Slinton evalcmdlist(t->cmdlist); 6259663Slinton endfor 6269663Slinton foreach (Trcmd, t, eachinst) 6279663Slinton evalcmdlist(t->cmdlist); 6289663Slinton endfor 6299663Slinton bpact(); 6309663Slinton } 6319663Slinton 6329663Slinton /* 6339663Slinton * A procedure call/return has occurred while single-stepping, 6349663Slinton * note it if we're tracing lines. 6359663Slinton */ 6369663Slinton 6379663Slinton private Boolean chklist(); 6389663Slinton 6399663Slinton public callnews(iscall) 6409663Slinton Boolean iscall; 6419663Slinton { 6429663Slinton if (not chklist(eachline, iscall)) { 6439663Slinton chklist(eachinst, iscall); 6449663Slinton } 6459663Slinton } 6469663Slinton 6479663Slinton private Boolean chklist(list, iscall) 6489663Slinton List list; 6499663Slinton Boolean iscall; 6509663Slinton { 6519663Slinton register Trcmd t; 6529663Slinton register Command cmd; 6539663Slinton 654*16609Ssam setcurfunc(whatblock(pc)); 6559663Slinton foreach (Trcmd, t, list) 6569663Slinton foreach (Command, cmd, t->cmdlist) 6579663Slinton if (cmd->op == O_PRINTSRCPOS and 6589663Slinton (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) { 6599663Slinton if (iscall) { 6609663Slinton printentry(curfunc); 6619663Slinton } else { 6629663Slinton printexit(curfunc); 6639663Slinton } 6649663Slinton return true; 6659663Slinton } 6669663Slinton endfor 6679663Slinton endfor 6689663Slinton return false; 6699663Slinton } 6709663Slinton 6719663Slinton /* 6729663Slinton * When tracing variables we keep a copy of their most recent value 6739663Slinton * and compare it to the current one each time a breakpoint occurs. 6749663Slinton * MAXTRSIZE is the maximum size variable we allow. 6759663Slinton */ 6769663Slinton 6779663Slinton #define MAXTRSIZE 512 6789663Slinton 6799663Slinton /* 6809663Slinton * List of variables being watched. 6819663Slinton */ 6829663Slinton 6839663Slinton typedef struct Trinfo *Trinfo; 6849663Slinton 6859663Slinton struct Trinfo { 6869663Slinton Node variable; 6879663Slinton Address traddr; 6889663Slinton Symbol trblock; 6899663Slinton char *trvalue; 6909663Slinton }; 6919663Slinton 6929663Slinton private List trinfolist; 6939663Slinton 6949663Slinton /* 6959663Slinton * Find the trace information record associated with the given record. 6969663Slinton * If there isn't one then create it and add it to the list. 6979663Slinton */ 6989663Slinton 6999663Slinton private Trinfo findtrinfo(p) 7009663Slinton Node p; 7019663Slinton { 7029663Slinton register Trinfo tp; 7039663Slinton Boolean isnew; 7049663Slinton 7059663Slinton isnew = true; 7069663Slinton if (trinfolist == nil) { 7079663Slinton trinfolist = list_alloc(); 7089663Slinton } else { 7099663Slinton foreach (Trinfo, tp, trinfolist) 7109663Slinton if (tp->variable == p) { 7119663Slinton isnew = false; 7129663Slinton break; 7139663Slinton } 7149663Slinton endfor 7159663Slinton } 7169663Slinton if (isnew) { 7179663Slinton if (tracebpts) { 7189663Slinton printf("adding trinfo for \""); 7199663Slinton prtree(stdout, p); 7209663Slinton printf("\"\n"); 7219663Slinton } 7229663Slinton tp = new(Trinfo); 7239663Slinton tp->variable = p; 7249663Slinton tp->traddr = lval(p); 7259663Slinton tp->trvalue = nil; 7269663Slinton list_append(list_item(tp), nil, trinfolist); 7279663Slinton } 7289663Slinton return tp; 7299663Slinton } 7309663Slinton 7319663Slinton /* 7329663Slinton * Print out the value of a variable if it has changed since the 7339663Slinton * last time we checked. 7349663Slinton */ 7359663Slinton 7369663Slinton public printifchanged(p) 7379663Slinton Node p; 7389663Slinton { 7399663Slinton register Trinfo tp; 7409663Slinton register int n; 7419663Slinton char buff[MAXTRSIZE]; 7429663Slinton static Lineno prevline; 7439663Slinton 7449663Slinton tp = findtrinfo(p); 7459663Slinton n = size(p->nodetype); 7469663Slinton dread(buff, tp->traddr, n); 7479663Slinton if (tp->trvalue == nil) { 7489663Slinton tp->trvalue = newarr(char, n); 7499663Slinton mov(buff, tp->trvalue, n); 7509663Slinton mov(buff, sp, n); 7519663Slinton sp += n; 7529663Slinton printf("initially (at line %d):\t", curline); 7539663Slinton prtree(stdout, p); 7549663Slinton printf(" = "); 7559663Slinton printval(p->nodetype); 7569663Slinton putchar('\n'); 7579663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 7589663Slinton mov(buff, tp->trvalue, n); 7599663Slinton mov(buff, sp, n); 7609663Slinton sp += n; 7619663Slinton printf("after line %d:\t", prevline); 7629663Slinton prtree(stdout, p); 7639663Slinton printf(" = "); 7649663Slinton printval(p->nodetype); 7659663Slinton putchar('\n'); 7669663Slinton } 7679663Slinton prevline = curline; 7689663Slinton } 7699663Slinton 7709663Slinton /* 7719663Slinton * Stop if the value of the given expression has changed. 7729663Slinton */ 7739663Slinton 7749663Slinton public stopifchanged(p) 7759663Slinton Node p; 7769663Slinton { 7779663Slinton register Trinfo tp; 7789663Slinton register int n; 7799663Slinton char buff[MAXTRSIZE]; 7809663Slinton static Lineno prevline; 7819663Slinton 7829663Slinton tp = findtrinfo(p); 7839663Slinton n = size(p->nodetype); 7849663Slinton dread(buff, tp->traddr, n); 7859663Slinton if (tp->trvalue == nil) { 7869663Slinton tp->trvalue = newarr(char, n); 7879663Slinton mov(buff, tp->trvalue, n); 7889663Slinton isstopped = true; 7899663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 7909663Slinton mov(buff, tp->trvalue, n); 791*16609Ssam mov(buff, sp, n); 792*16609Ssam sp += n; 793*16609Ssam printf("after line %d:\t", prevline); 794*16609Ssam prtree(stdout, p); 795*16609Ssam printf(" = "); 796*16609Ssam printval(p->nodetype); 797*16609Ssam putchar('\n'); 7989663Slinton isstopped = true; 7999663Slinton } 8009663Slinton prevline = curline; 8019663Slinton } 8029663Slinton 8039663Slinton /* 8049663Slinton * Free the tracing table. 8059663Slinton */ 8069663Slinton 8079663Slinton public trfree() 8089663Slinton { 8099663Slinton register Trinfo tp; 8109663Slinton 8119663Slinton foreach (Trinfo, tp, trinfolist) 8129663Slinton dispose(tp->trvalue); 8139663Slinton dispose(tp); 8149663Slinton list_delete(list_curitem(trinfolist), trinfolist); 8159663Slinton endfor 8169663Slinton } 8179663Slinton 8189663Slinton /* 8199663Slinton * Fix up breakpoint information before continuing execution. 8209663Slinton * 8219663Slinton * It's necessary to destroy events and breakpoints that were created 8229663Slinton * temporarily and still exist because the program terminated abnormally. 8239663Slinton */ 8249663Slinton 8259663Slinton public fixbps() 8269663Slinton { 8279663Slinton register Event e; 8289663Slinton register Trcmd t; 8299663Slinton 8309663Slinton single_stepping = false; 8319663Slinton inst_tracing = false; 8329663Slinton trfree(); 8339663Slinton foreach (Event, e, eventlist) 8349663Slinton if (e->temporary) { 835*16609Ssam if (not delevent(e->id)) { 836*16609Ssam printf("!! dbx.fixbps: can't find event %d\n", e->id); 837*16609Ssam } 8389663Slinton } 8399663Slinton endfor 8409663Slinton foreach (Trcmd, t, eachline) 8419663Slinton printrmtr(t); 8429663Slinton list_delete(list_curitem(eachline), eachline); 8439663Slinton endfor 8449663Slinton foreach (Trcmd, t, eachinst) 8459663Slinton printrmtr(t); 8469663Slinton list_delete(list_curitem(eachinst), eachinst); 8479663Slinton endfor 8489663Slinton } 8499663Slinton 8509663Slinton /* 8519663Slinton * Set all breakpoints in object code. 8529663Slinton */ 8539663Slinton 8549663Slinton public setallbps() 8559663Slinton { 8569663Slinton register Breakpoint p; 8579663Slinton 8589663Slinton foreach (Breakpoint, p, bplist) 8599663Slinton setbp(p->bpaddr); 8609663Slinton endfor 8619663Slinton } 8629663Slinton 8639663Slinton /* 8649663Slinton * Undo damage done by "setallbps". 8659663Slinton */ 8669663Slinton 8679663Slinton public unsetallbps() 8689663Slinton { 8699663Slinton register Breakpoint p; 8709663Slinton 8719663Slinton foreach (Breakpoint, p, bplist) 8729663Slinton unsetbp(p->bpaddr); 8739663Slinton endfor 8749663Slinton } 875