121602Sdist /* 221602Sdist * Copyright (c) 1983 Regents of the University of California. 321602Sdist * All rights reserved. The Berkeley software License Agreement 421602Sdist * specifies the terms and conditions for redistribution. 521602Sdist */ 69663Slinton 721602Sdist #ifndef lint 8*33316Sdonn static char sccsid[] = "@(#)events.c 5.3 (Berkeley) 01/12/88"; 921602Sdist #endif not lint 109663Slinton 11*33316Sdonn static char rcsid[] = "$Header: events.c,v 1.3 87/07/08 18:46:02 donn Exp $"; 1218218Slinton 139663Slinton /* 149663Slinton * Event/breakpoint managment. 159663Slinton */ 169663Slinton 179663Slinton #include "defs.h" 189663Slinton #include "events.h" 199663Slinton #include "main.h" 209663Slinton #include "symbols.h" 219663Slinton #include "tree.h" 229663Slinton #include "eval.h" 239663Slinton #include "source.h" 249663Slinton #include "mappings.h" 2516609Ssam #include "runtime.h" 269663Slinton #include "process.h" 279663Slinton #include "machine.h" 289663Slinton #include "lists.h" 299663Slinton 309663Slinton #ifndef public 31*33316Sdonn 329663Slinton typedef struct Event *Event; 339663Slinton typedef struct Breakpoint *Breakpoint; 349663Slinton 359663Slinton #include "symbols.h" 369663Slinton 379663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist) 389663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist) 399663Slinton 40*33316Sdonn /* 41*33316Sdonn * When tracing variables we keep a copy of their most recent value 42*33316Sdonn * and compare it to the current one each time a breakpoint occurs. 43*33316Sdonn * MAXTRSIZE is the maximum size variable we allow. 44*33316Sdonn */ 45*33316Sdonn 46*33316Sdonn #define MAXTRSIZE 512 47*33316Sdonn 489663Slinton #endif 499663Slinton 50*33316Sdonn public boolean inst_tracing; 51*33316Sdonn public boolean single_stepping; 52*33316Sdonn public boolean isstopped; 53*33316Sdonn 54*33316Sdonn public Symbol linesym; 55*33316Sdonn public Symbol procsym; 56*33316Sdonn public Symbol pcsym; 57*33316Sdonn public Symbol retaddrsym; 58*33316Sdonn 599663Slinton struct Event { 609663Slinton unsigned int id; 6118218Slinton boolean temporary; 629663Slinton Node condition; 639663Slinton Cmdlist actions; 649663Slinton }; 659663Slinton 669663Slinton struct Breakpoint { 679663Slinton Event event; 689663Slinton Address bpaddr; 699663Slinton Lineno bpline; 709663Slinton Cmdlist actions; 7118218Slinton boolean temporary; 729663Slinton }; 739663Slinton 749663Slinton typedef List Eventlist; 759663Slinton typedef List Bplist; 769663Slinton 779663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el) 789663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl) 799663Slinton 809663Slinton private Eventlist eventlist; /* list of active events */ 819663Slinton private Bplist bplist; /* list of active breakpoints */ 8218218Slinton private Event curevent; /* most recently created event */ 8318218Slinton private integer eventid; /* id number of current event */ 8418218Slinton private integer trid; /* id number of current trace */ 859663Slinton 869663Slinton typedef struct Trcmd { 879663Slinton Integer trid; 889663Slinton Event event; 899663Slinton Cmdlist cmdlist; 909663Slinton } *Trcmd; 919663Slinton 929663Slinton private List eachline; /* commands to execute after each line */ 939663Slinton private List eachinst; /* commands to execute after each instruction */ 949663Slinton 959663Slinton private Breakpoint bp_alloc(); 969663Slinton 979663Slinton /* 989663Slinton * Initialize breakpoint information. 999663Slinton */ 1009663Slinton 1019663Slinton private Symbol builtinsym(str, class, type) 1029663Slinton String str; 1039663Slinton Symclass class; 1049663Slinton Symbol type; 1059663Slinton { 1069663Slinton Symbol s; 1079663Slinton 1089663Slinton s = insert(identname(str, true)); 1099663Slinton s->language = findlanguage(".s"); 1109663Slinton s->class = class; 1119663Slinton s->type = type; 1129663Slinton return s; 1139663Slinton } 1149663Slinton 1159663Slinton public bpinit() 1169663Slinton { 1179663Slinton linesym = builtinsym("$line", VAR, t_int); 1189663Slinton procsym = builtinsym("$proc", PROC, nil); 1199663Slinton pcsym = lookup(identname("$pc", true)); 1209663Slinton if (pcsym == nil) { 1219663Slinton panic("can't find $pc"); 1229663Slinton } 1239663Slinton retaddrsym = builtinsym("$retaddr", VAR, t_int); 1249663Slinton eventlist = list_alloc(); 1259663Slinton bplist = list_alloc(); 1269663Slinton eachline = list_alloc(); 1279663Slinton eachinst = list_alloc(); 1289663Slinton } 1299663Slinton 1309663Slinton /* 1319663Slinton * Trap an event and do the associated commands when it occurs. 1329663Slinton */ 1339663Slinton 1349663Slinton public Event event_alloc(istmp, econd, cmdlist) 13518218Slinton boolean istmp; 1369663Slinton Node econd; 1379663Slinton Cmdlist cmdlist; 1389663Slinton { 1399663Slinton register Event e; 1409663Slinton 1419663Slinton e = new(Event); 14218218Slinton ++eventid; 14318218Slinton e->id = eventid; 1449663Slinton e->temporary = istmp; 1459663Slinton e->condition = econd; 1469663Slinton e->actions = cmdlist; 1479663Slinton eventlist_append(e, eventlist); 14818218Slinton curevent = e; 1499663Slinton translate(e); 1509663Slinton return e; 1519663Slinton } 1529663Slinton 1539663Slinton /* 1549663Slinton * Delete the event with the given id. 15516609Ssam * Returns whether it's successful or not. 1569663Slinton */ 1579663Slinton 15816609Ssam public boolean delevent (id) 1599663Slinton unsigned int id; 1609663Slinton { 1619663Slinton Event e; 1629663Slinton Breakpoint bp; 1639663Slinton Trcmd t; 16416609Ssam boolean found; 1659663Slinton 16616609Ssam found = false; 1679663Slinton foreach (Event, e, eventlist) 1689663Slinton if (e->id == id) { 16916609Ssam found = true; 1709663Slinton foreach (Breakpoint, bp, bplist) 1719663Slinton if (bp->event == e) { 17218218Slinton if (tracebpts) { 17318218Slinton printf("deleting breakpoint at 0x%x\n", bp->bpaddr); 17418218Slinton fflush(stdout); 17518218Slinton } 1769663Slinton list_delete(list_curitem(bplist), bplist); 1779663Slinton } 1789663Slinton endfor 17916609Ssam list_delete(list_curitem(eventlist), eventlist); 1809663Slinton break; 1819663Slinton } 1829663Slinton endfor 1839663Slinton foreach (Trcmd, t, eachline) 1849663Slinton if (t->event->id == id) { 18516609Ssam found = true; 1869663Slinton printrmtr(t); 1879663Slinton list_delete(list_curitem(eachline), eachline); 1889663Slinton } 1899663Slinton endfor 1909663Slinton foreach (Trcmd, t, eachinst) 1919663Slinton if (t->event->id == id) { 19216609Ssam found = true; 1939663Slinton printrmtr(t); 1949663Slinton list_delete(list_curitem(eachinst), eachinst); 1959663Slinton } 1969663Slinton endfor 1979663Slinton if (list_size(eachinst) == 0) { 1989663Slinton inst_tracing = false; 1999663Slinton if (list_size(eachline) == 0) { 2009663Slinton single_stepping = false; 2019663Slinton } 2029663Slinton } 20316609Ssam return found; 2049663Slinton } 2059663Slinton 2069663Slinton /* 2079663Slinton * Translate an event into the appropriate breakpoints and actions. 2089663Slinton * While we're at it, turn on the breakpoints if the condition is true. 2099663Slinton */ 2109663Slinton 2119663Slinton private translate(e) 2129663Slinton Event e; 2139663Slinton { 2149663Slinton Breakpoint bp; 2159663Slinton Symbol s; 2169663Slinton Node place; 2179663Slinton Lineno line; 2189663Slinton Address addr; 2199663Slinton 2209663Slinton checkref(e->condition); 2219663Slinton switch (e->condition->op) { 2229663Slinton case O_EQ: 2239663Slinton if (e->condition->value.arg[0]->op == O_SYM) { 2249663Slinton s = e->condition->value.arg[0]->value.sym; 2259663Slinton place = e->condition->value.arg[1]; 2269663Slinton if (s == linesym) { 2279663Slinton if (place->op == O_QLINE) { 2289663Slinton line = place->value.arg[1]->value.lcon; 22916609Ssam addr = objaddr(line, place->value.arg[0]->value.scon); 2309663Slinton } else { 2319663Slinton eval(place); 2329663Slinton line = pop(long); 2339663Slinton addr = objaddr(line, cursource); 2349663Slinton } 2359663Slinton if (addr == NOADDR) { 23616609Ssam if (not delevent(e->id)) { 23716609Ssam printf("!! dbx.translate: can't undo event %d?\n", 23816609Ssam e->id); 23916609Ssam } 2409663Slinton beginerrmsg(); 2419663Slinton fprintf(stderr, "no executable code at line "); 2429663Slinton prtree(stderr, place); 2439663Slinton enderrmsg(); 2449663Slinton } 2459663Slinton bp = bp_alloc(e, addr, line, e->actions); 2469663Slinton } else if (s == procsym) { 2479663Slinton eval(place); 2489663Slinton s = pop(Symbol); 2499663Slinton bp = bp_alloc(e, codeloc(s), 0, e->actions); 2509663Slinton if (isactive(s) and pc != codeloc(program)) { 2519663Slinton evalcmdlist(e->actions); 2529663Slinton } 2539663Slinton } else if (s == pcsym) { 2549663Slinton eval(place); 2559663Slinton bp = bp_alloc(e, pop(Address), 0, e->actions); 2569663Slinton } else { 2579663Slinton condbp(e); 2589663Slinton } 2599663Slinton } else { 2609663Slinton condbp(e); 2619663Slinton } 2629663Slinton break; 2639663Slinton 2649663Slinton /* 2659663Slinton * These should be handled specially. 2669663Slinton * But for now I'm ignoring the problem. 2679663Slinton */ 2689663Slinton case O_AND: 2699663Slinton case O_OR: 2709663Slinton default: 2719663Slinton condbp(e); 2729663Slinton break; 2739663Slinton } 2749663Slinton } 2759663Slinton 2769663Slinton /* 2779663Slinton * Create a breakpoint for a condition that cannot be pinpointed 2789663Slinton * to happening at a particular address, but one for which we 2799663Slinton * must single step and check the condition after each statement. 2809663Slinton */ 2819663Slinton 2829663Slinton private condbp(e) 2839663Slinton Event e; 2849663Slinton { 2859663Slinton Symbol p; 2869663Slinton Breakpoint bp; 2879663Slinton Cmdlist actions; 2889663Slinton 2899663Slinton p = tcontainer(e->condition); 2909663Slinton if (p == nil) { 2919663Slinton p = program; 2929663Slinton } 2939663Slinton actions = buildcmdlist(build(O_IF, e->condition, e->actions)); 2949663Slinton actions = buildcmdlist(build(O_TRACEON, false, actions)); 2959663Slinton bp = bp_alloc(e, codeloc(p), 0, actions); 2969663Slinton } 2979663Slinton 2989663Slinton /* 2999663Slinton * Determine the deepest nested subprogram that still contains 3009663Slinton * all elements in the given expression. 3019663Slinton */ 3029663Slinton 3039663Slinton public Symbol tcontainer(exp) 3049663Slinton Node exp; 3059663Slinton { 3069663Slinton Integer i; 3079663Slinton Symbol s, t, u, v; 3089663Slinton 3099663Slinton checkref(exp); 3109663Slinton s = nil; 3119663Slinton if (exp->op == O_SYM) { 3129663Slinton s = container(exp->value.sym); 3139663Slinton } else if (not isleaf(exp->op)) { 3149663Slinton for (i = 0; i < nargs(exp->op); i++) { 3159663Slinton t = tcontainer(exp->value.arg[i]); 3169663Slinton if (t != nil) { 3179663Slinton if (s == nil) { 3189663Slinton s = t; 3199663Slinton } else { 3209663Slinton u = s; 3219663Slinton v = t; 3229663Slinton while (u != v and u != nil) { 3239663Slinton u = container(u); 3249663Slinton v = container(v); 3259663Slinton } 3269663Slinton if (u == nil) { 3279663Slinton panic("bad ancestry for \"%s\"", symname(s)); 3289663Slinton } else { 3299663Slinton s = u; 3309663Slinton } 3319663Slinton } 3329663Slinton } 3339663Slinton } 3349663Slinton } 3359663Slinton return s; 3369663Slinton } 3379663Slinton 3389663Slinton /* 33911869Slinton * Determine if the given function can be executed at full speed. 34011869Slinton * This can only be done if there are no breakpoints within the function. 34111869Slinton */ 34211869Slinton 34318218Slinton public boolean canskip(f) 34411869Slinton Symbol f; 34511869Slinton { 34611869Slinton Breakpoint p; 34718218Slinton boolean ok; 34811869Slinton 34911869Slinton ok = true; 35011869Slinton foreach (Breakpoint, p, bplist) 35111869Slinton if (whatblock(p->bpaddr) == f) { 35211869Slinton ok = false; 35311869Slinton break; 35411869Slinton } 35511869Slinton endfor 35611869Slinton return ok; 35711869Slinton } 35811869Slinton 35911869Slinton /* 3609663Slinton * Print out what's currently being traced by looking at 3619663Slinton * the currently active events. 3629663Slinton * 3639663Slinton * Some convolution here to translate internal representation 3649663Slinton * of events back into something more palatable. 3659663Slinton */ 3669663Slinton 3679663Slinton public status() 3689663Slinton { 3699663Slinton Event e; 3709663Slinton 3719663Slinton foreach (Event, e, eventlist) 3729663Slinton if (not e->temporary) { 37311869Slinton printevent(e); 3749663Slinton } 3759663Slinton endfor 3769663Slinton } 3779663Slinton 37811869Slinton public printevent(e) 37911869Slinton Event e; 38011869Slinton { 38111869Slinton Command cmd; 38211869Slinton 38311869Slinton if (not isredirected()) { 38416609Ssam printeventid(e->id); 38511869Slinton } 38611869Slinton cmd = list_element(Command, list_head(e->actions)); 38711869Slinton if (cmd->op == O_PRINTCALL) { 38811869Slinton printf("trace "); 38911869Slinton printname(stdout, cmd->value.sym); 39011869Slinton } else { 39111869Slinton if (list_size(e->actions) > 1) { 39211869Slinton printf("{ "); 39311869Slinton } 39411869Slinton foreach (Command, cmd, e->actions) 39511869Slinton printcmd(stdout, cmd); 39611869Slinton if (not list_islast()) { 39711869Slinton printf("; "); 39811869Slinton } 39911869Slinton endfor 40011869Slinton if (list_size(e->actions) > 1) { 40111869Slinton printf(" }"); 40211869Slinton } 40311869Slinton printcond(e->condition); 40411869Slinton } 40511869Slinton printf("\n"); 40611869Slinton } 40711869Slinton 40816609Ssam private printeventid (id) 40916609Ssam integer id; 41016609Ssam { 41116609Ssam printf("[%d] ", id); 41216609Ssam } 41316609Ssam 4149663Slinton /* 4159663Slinton * Print out a condition. 4169663Slinton */ 4179663Slinton 4189663Slinton private printcond(cond) 4199663Slinton Node cond; 4209663Slinton { 4219663Slinton Symbol s; 4229663Slinton Node place; 4239663Slinton 4249663Slinton if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) { 4259663Slinton s = cond->value.arg[0]->value.sym; 4269663Slinton place = cond->value.arg[1]; 4279663Slinton if (s == procsym) { 4289663Slinton if (place->value.sym != program) { 4299663Slinton printf(" in "); 4309663Slinton printname(stdout, place->value.sym); 4319663Slinton } 4329663Slinton } else if (s == linesym) { 4339663Slinton printf(" at "); 4349663Slinton prtree(stdout, place); 4359663Slinton } else if (s == pcsym or s == retaddrsym) { 4369663Slinton printf("i at "); 4379663Slinton prtree(stdout, place); 4389663Slinton } else { 4399663Slinton printf(" when "); 4409663Slinton prtree(stdout, cond); 4419663Slinton } 4429663Slinton } else { 4439663Slinton printf(" when "); 4449663Slinton prtree(stdout, cond); 4459663Slinton } 4469663Slinton } 4479663Slinton 4489663Slinton /* 4499663Slinton * Add a breakpoint to the list and return it. 4509663Slinton */ 4519663Slinton 4529663Slinton private Breakpoint bp_alloc(e, addr, line, actions) 4539663Slinton Event e; 4549663Slinton Address addr; 4559663Slinton Lineno line; 4569663Slinton Cmdlist actions; 4579663Slinton { 4589663Slinton register Breakpoint p; 4599663Slinton 4609663Slinton p = new(Breakpoint); 4619663Slinton p->event = e; 4629663Slinton p->bpaddr = addr; 4639663Slinton p->bpline = line; 4649663Slinton p->actions = actions; 46518218Slinton p->temporary = false; 46618218Slinton if (tracebpts) { 46718218Slinton if (e == nil) { 46830796Sbostic printf("new bp at 0x%x for event ??\n", addr); 46918218Slinton } else { 47018218Slinton printf("new bp at 0x%x for event %d\n", addr, e->id); 47118218Slinton } 47218218Slinton fflush(stdout); 47318218Slinton } 4749663Slinton bplist_append(p, bplist); 4759663Slinton return p; 4769663Slinton } 4779663Slinton 4789663Slinton /* 4799663Slinton * Free all storage in the event and breakpoint tables. 4809663Slinton */ 4819663Slinton 4829663Slinton public bpfree() 4839663Slinton { 4849663Slinton register Event e; 4859663Slinton 4869663Slinton fixbps(); 4879663Slinton foreach (Event, e, eventlist) 48816609Ssam if (not delevent(e->id)) { 48916609Ssam printf("!! dbx.bpfree: can't delete event %d\n", e->id); 49016609Ssam } 4919663Slinton list_delete(list_curitem(eventlist), eventlist); 4929663Slinton endfor 4939663Slinton } 4949663Slinton 4959663Slinton /* 4969663Slinton * Determine if the program stopped at a known breakpoint 4979663Slinton * and if so do the associated commands. 4989663Slinton */ 4999663Slinton 50018218Slinton public boolean bpact() 5019663Slinton { 5029663Slinton register Breakpoint p; 50318218Slinton boolean found; 50416609Ssam integer eventId; 5059663Slinton 5069663Slinton found = false; 5079663Slinton foreach (Breakpoint, p, bplist) 5089663Slinton if (p->bpaddr == pc) { 50918218Slinton if (tracebpts) { 51018218Slinton printf("breakpoint for event %d found at location 0x%x\n", 51118218Slinton p->event->id, pc); 51218218Slinton } 5139663Slinton found = true; 51418218Slinton if (p->event->temporary) { 51518218Slinton if (not delevent(p->event->id)) { 51618218Slinton printf("!! dbx.bpact: can't find event %d\n", 51718218Slinton p->event->id); 51818218Slinton } 51918218Slinton } 5209663Slinton evalcmdlist(p->actions); 52118218Slinton if (isstopped) { 52218218Slinton eventId = p->event->id; 52318218Slinton } 52418218Slinton if (p->temporary) { 52518218Slinton list_delete(list_curitem(bplist), bplist); 52618218Slinton } 5279663Slinton } 5289663Slinton endfor 5299663Slinton if (isstopped) { 53016609Ssam if (found) { 53116609Ssam printeventid(eventId); 53216609Ssam } 5339663Slinton printstatus(); 5349663Slinton } 5359663Slinton fflush(stdout); 5369663Slinton return found; 5379663Slinton } 5389663Slinton 5399663Slinton /* 5409663Slinton * Begin single stepping and executing the given commands after each step. 5419663Slinton * If the first argument is true step by instructions, otherwise 5429663Slinton * step by source lines. 5439663Slinton * 5449663Slinton * We automatically set a breakpoint at the end of the current procedure 5459663Slinton * to turn off the given tracing. 5469663Slinton */ 5479663Slinton 5489663Slinton public traceon(inst, event, cmdlist) 54918218Slinton boolean inst; 5509663Slinton Event event; 5519663Slinton Cmdlist cmdlist; 5529663Slinton { 5539663Slinton register Trcmd trcmd; 55418218Slinton Breakpoint bp; 5559663Slinton Cmdlist actions; 55611869Slinton Address ret; 55718218Slinton Event e; 5589663Slinton 55918218Slinton if (event == nil) { 56018218Slinton e = curevent; 56118218Slinton } else { 56218218Slinton e = event; 56318218Slinton } 5649663Slinton trcmd = new(Trcmd); 56518218Slinton ++trid; 56618218Slinton trcmd->trid = trid; 56718218Slinton trcmd->event = e; 5689663Slinton trcmd->cmdlist = cmdlist; 5699663Slinton single_stepping = true; 5709663Slinton if (inst) { 5719663Slinton inst_tracing = true; 5729663Slinton list_append(list_item(trcmd), nil, eachinst); 5739663Slinton } else { 5749663Slinton list_append(list_item(trcmd), nil, eachline); 5759663Slinton } 57611869Slinton ret = return_addr(); 57711869Slinton if (ret != 0) { 57818218Slinton actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid)); 57918218Slinton bp = bp_alloc(e, (Address) ret, 0, actions); 58018218Slinton bp->temporary = true; 58111869Slinton } 58218218Slinton if (tracebpts) { 58318218Slinton printf("adding trace %d for event %d\n", trcmd->trid, e->id); 58418218Slinton } 5859663Slinton } 5869663Slinton 5879663Slinton /* 5889663Slinton * Turn off some kind of tracing. 5899663Slinton * Strictly an internal command, this cannot be invoked by the user. 5909663Slinton */ 5919663Slinton 5929663Slinton public traceoff(id) 5939663Slinton Integer id; 5949663Slinton { 5959663Slinton register Trcmd t; 59618218Slinton register boolean found; 5979663Slinton 5989663Slinton found = false; 5999663Slinton foreach (Trcmd, t, eachline) 6009663Slinton if (t->trid == id) { 6019663Slinton printrmtr(t); 6029663Slinton list_delete(list_curitem(eachline), eachline); 6039663Slinton found = true; 6049663Slinton break; 6059663Slinton } 6069663Slinton endfor 6079663Slinton if (not found) { 6089663Slinton foreach (Trcmd, t, eachinst) 6099663Slinton if (t->event->id == id) { 6109663Slinton printrmtr(t); 6119663Slinton list_delete(list_curitem(eachinst), eachinst); 6129663Slinton found = true; 6139663Slinton break; 6149663Slinton } 6159663Slinton endfor 6169663Slinton if (not found) { 61718218Slinton beginerrmsg(); 61818218Slinton fprintf(stderr, "[internal error: trace id %d not found]\n", id); 6199663Slinton } 6209663Slinton } 6219663Slinton if (list_size(eachinst) == 0) { 6229663Slinton inst_tracing = false; 6239663Slinton if (list_size(eachline) == 0) { 6249663Slinton single_stepping = false; 6259663Slinton } 6269663Slinton } 6279663Slinton } 6289663Slinton 6299663Slinton /* 6309663Slinton * If breakpoints are being traced, note that a Trcmd is being deleted. 6319663Slinton */ 6329663Slinton 6339663Slinton private printrmtr(t) 6349663Slinton Trcmd t; 6359663Slinton { 63618218Slinton if (tracebpts) { 63718218Slinton printf("removing trace %d", t->trid); 63818218Slinton if (t->event != nil) { 63918218Slinton printf(" for event %d", t->event->id); 64018218Slinton } 64118218Slinton printf("\n"); 6429663Slinton } 6439663Slinton } 6449663Slinton 6459663Slinton /* 6469663Slinton * Print out news during single step tracing. 6479663Slinton */ 6489663Slinton 6499663Slinton public printnews() 6509663Slinton { 6519663Slinton register Trcmd t; 6529663Slinton 6539663Slinton foreach (Trcmd, t, eachline) 6549663Slinton evalcmdlist(t->cmdlist); 6559663Slinton endfor 6569663Slinton foreach (Trcmd, t, eachinst) 6579663Slinton evalcmdlist(t->cmdlist); 6589663Slinton endfor 6599663Slinton bpact(); 6609663Slinton } 6619663Slinton 6629663Slinton /* 6639663Slinton * A procedure call/return has occurred while single-stepping, 6649663Slinton * note it if we're tracing lines. 6659663Slinton */ 6669663Slinton 66718218Slinton private boolean chklist(); 6689663Slinton 6699663Slinton public callnews(iscall) 67018218Slinton boolean iscall; 6719663Slinton { 6729663Slinton if (not chklist(eachline, iscall)) { 6739663Slinton chklist(eachinst, iscall); 6749663Slinton } 6759663Slinton } 6769663Slinton 67718218Slinton private boolean chklist(list, iscall) 6789663Slinton List list; 67918218Slinton boolean iscall; 6809663Slinton { 6819663Slinton register Trcmd t; 6829663Slinton register Command cmd; 6839663Slinton 68416609Ssam setcurfunc(whatblock(pc)); 6859663Slinton foreach (Trcmd, t, list) 6869663Slinton foreach (Command, cmd, t->cmdlist) 6879663Slinton if (cmd->op == O_PRINTSRCPOS and 6889663Slinton (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) { 6899663Slinton if (iscall) { 6909663Slinton printentry(curfunc); 6919663Slinton } else { 6929663Slinton printexit(curfunc); 6939663Slinton } 6949663Slinton return true; 6959663Slinton } 6969663Slinton endfor 6979663Slinton endfor 6989663Slinton return false; 6999663Slinton } 7009663Slinton 7019663Slinton /* 7029663Slinton * List of variables being watched. 7039663Slinton */ 7049663Slinton 7059663Slinton typedef struct Trinfo *Trinfo; 7069663Slinton 7079663Slinton struct Trinfo { 7089663Slinton Node variable; 7099663Slinton Address traddr; 7109663Slinton Symbol trblock; 7119663Slinton char *trvalue; 7129663Slinton }; 7139663Slinton 7149663Slinton private List trinfolist; 7159663Slinton 7169663Slinton /* 7179663Slinton * Find the trace information record associated with the given record. 7189663Slinton * If there isn't one then create it and add it to the list. 7199663Slinton */ 7209663Slinton 7219663Slinton private Trinfo findtrinfo(p) 7229663Slinton Node p; 7239663Slinton { 7249663Slinton register Trinfo tp; 72518218Slinton boolean isnew; 7269663Slinton 7279663Slinton isnew = true; 7289663Slinton if (trinfolist == nil) { 7299663Slinton trinfolist = list_alloc(); 7309663Slinton } else { 7319663Slinton foreach (Trinfo, tp, trinfolist) 7329663Slinton if (tp->variable == p) { 7339663Slinton isnew = false; 7349663Slinton break; 7359663Slinton } 7369663Slinton endfor 7379663Slinton } 7389663Slinton if (isnew) { 7399663Slinton if (tracebpts) { 7409663Slinton printf("adding trinfo for \""); 7419663Slinton prtree(stdout, p); 7429663Slinton printf("\"\n"); 7439663Slinton } 7449663Slinton tp = new(Trinfo); 7459663Slinton tp->variable = p; 7469663Slinton tp->traddr = lval(p); 7479663Slinton tp->trvalue = nil; 7489663Slinton list_append(list_item(tp), nil, trinfolist); 7499663Slinton } 7509663Slinton return tp; 7519663Slinton } 7529663Slinton 7539663Slinton /* 7549663Slinton * Print out the value of a variable if it has changed since the 7559663Slinton * last time we checked. 7569663Slinton */ 7579663Slinton 7589663Slinton public printifchanged(p) 7599663Slinton Node p; 7609663Slinton { 7619663Slinton register Trinfo tp; 7629663Slinton register int n; 7639663Slinton char buff[MAXTRSIZE]; 76418218Slinton Filename curfile; 7659663Slinton static Lineno prevline; 76618218Slinton static Filename prevfile; 7679663Slinton 7689663Slinton tp = findtrinfo(p); 7699663Slinton n = size(p->nodetype); 77018218Slinton dread(buff, tp->traddr, n); 77118218Slinton curfile = srcfilename(pc); 7729663Slinton if (tp->trvalue == nil) { 7739663Slinton tp->trvalue = newarr(char, n); 7749663Slinton mov(buff, tp->trvalue, n); 7759663Slinton mov(buff, sp, n); 7769663Slinton sp += n; 77718218Slinton printf("initially (at line %d in \"%s\"):\t", curline, curfile); 7789663Slinton prtree(stdout, p); 7799663Slinton printf(" = "); 7809663Slinton printval(p->nodetype); 7819663Slinton putchar('\n'); 7829663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 7839663Slinton mov(buff, tp->trvalue, n); 7849663Slinton mov(buff, sp, n); 7859663Slinton sp += n; 78618218Slinton printf("after line %d in \"%s\":\t", prevline, prevfile); 7879663Slinton prtree(stdout, p); 7889663Slinton printf(" = "); 7899663Slinton printval(p->nodetype); 7909663Slinton putchar('\n'); 7919663Slinton } 7929663Slinton prevline = curline; 79318218Slinton prevfile = curfile; 7949663Slinton } 7959663Slinton 7969663Slinton /* 7979663Slinton * Stop if the value of the given expression has changed. 7989663Slinton */ 7999663Slinton 8009663Slinton public stopifchanged(p) 8019663Slinton Node p; 8029663Slinton { 8039663Slinton register Trinfo tp; 8049663Slinton register int n; 8059663Slinton char buff[MAXTRSIZE]; 8069663Slinton static Lineno prevline; 8079663Slinton 8089663Slinton tp = findtrinfo(p); 8099663Slinton n = size(p->nodetype); 8109663Slinton dread(buff, tp->traddr, n); 8119663Slinton if (tp->trvalue == nil) { 8129663Slinton tp->trvalue = newarr(char, n); 8139663Slinton mov(buff, tp->trvalue, n); 8149663Slinton isstopped = true; 8159663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 8169663Slinton mov(buff, tp->trvalue, n); 81716609Ssam mov(buff, sp, n); 81816609Ssam sp += n; 81916609Ssam printf("after line %d:\t", prevline); 82016609Ssam prtree(stdout, p); 82116609Ssam printf(" = "); 82216609Ssam printval(p->nodetype); 82316609Ssam putchar('\n'); 8249663Slinton isstopped = true; 8259663Slinton } 8269663Slinton prevline = curline; 8279663Slinton } 8289663Slinton 8299663Slinton /* 8309663Slinton * Free the tracing table. 8319663Slinton */ 8329663Slinton 8339663Slinton public trfree() 8349663Slinton { 8359663Slinton register Trinfo tp; 8369663Slinton 8379663Slinton foreach (Trinfo, tp, trinfolist) 8389663Slinton dispose(tp->trvalue); 8399663Slinton dispose(tp); 8409663Slinton list_delete(list_curitem(trinfolist), trinfolist); 8419663Slinton endfor 8429663Slinton } 8439663Slinton 8449663Slinton /* 8459663Slinton * Fix up breakpoint information before continuing execution. 8469663Slinton * 8479663Slinton * It's necessary to destroy events and breakpoints that were created 8489663Slinton * temporarily and still exist because the program terminated abnormally. 8499663Slinton */ 8509663Slinton 8519663Slinton public fixbps() 8529663Slinton { 8539663Slinton register Event e; 8549663Slinton register Trcmd t; 8559663Slinton 8569663Slinton single_stepping = false; 8579663Slinton inst_tracing = false; 8589663Slinton trfree(); 8599663Slinton foreach (Event, e, eventlist) 8609663Slinton if (e->temporary) { 86116609Ssam if (not delevent(e->id)) { 86216609Ssam printf("!! dbx.fixbps: can't find event %d\n", e->id); 86316609Ssam } 8649663Slinton } 8659663Slinton endfor 8669663Slinton foreach (Trcmd, t, eachline) 8679663Slinton printrmtr(t); 8689663Slinton list_delete(list_curitem(eachline), eachline); 8699663Slinton endfor 8709663Slinton foreach (Trcmd, t, eachinst) 8719663Slinton printrmtr(t); 8729663Slinton list_delete(list_curitem(eachinst), eachinst); 8739663Slinton endfor 8749663Slinton } 8759663Slinton 8769663Slinton /* 8779663Slinton * Set all breakpoints in object code. 8789663Slinton */ 8799663Slinton 8809663Slinton public setallbps() 8819663Slinton { 8829663Slinton register Breakpoint p; 8839663Slinton 8849663Slinton foreach (Breakpoint, p, bplist) 8859663Slinton setbp(p->bpaddr); 8869663Slinton endfor 8879663Slinton } 8889663Slinton 8899663Slinton /* 8909663Slinton * Undo damage done by "setallbps". 8919663Slinton */ 8929663Slinton 8939663Slinton public unsetallbps() 8949663Slinton { 8959663Slinton register Breakpoint p; 8969663Slinton 8979663Slinton foreach (Breakpoint, p, bplist) 8989663Slinton unsetbp(p->bpaddr); 8999663Slinton endfor 9009663Slinton } 901