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*30796Sbostic static char sccsid[] = "@(#)events.c 5.2 (Berkeley) 04/06/87"; 921602Sdist #endif not lint 109663Slinton 1118218Slinton static char rcsid[] = "$Header: events.c,v 1.5 84/12/26 10:39:26 linton 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 319663Slinton typedef struct Event *Event; 329663Slinton typedef struct Breakpoint *Breakpoint; 339663Slinton 3418218Slinton boolean inst_tracing; 3518218Slinton boolean single_stepping; 3618218Slinton boolean isstopped; 379663Slinton 389663Slinton #include "symbols.h" 399663Slinton 409663Slinton Symbol linesym; 419663Slinton Symbol procsym; 429663Slinton Symbol pcsym; 439663Slinton Symbol retaddrsym; 449663Slinton 459663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist) 469663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist) 479663Slinton 489663Slinton #endif 499663Slinton 509663Slinton struct Event { 519663Slinton unsigned int id; 5218218Slinton boolean temporary; 539663Slinton Node condition; 549663Slinton Cmdlist actions; 559663Slinton }; 569663Slinton 579663Slinton struct Breakpoint { 589663Slinton Event event; 599663Slinton Address bpaddr; 609663Slinton Lineno bpline; 619663Slinton Cmdlist actions; 6218218Slinton boolean temporary; 639663Slinton }; 649663Slinton 659663Slinton typedef List Eventlist; 669663Slinton typedef List Bplist; 679663Slinton 689663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el) 699663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl) 709663Slinton 719663Slinton private Eventlist eventlist; /* list of active events */ 729663Slinton private Bplist bplist; /* list of active breakpoints */ 7318218Slinton private Event curevent; /* most recently created event */ 7418218Slinton private integer eventid; /* id number of current event */ 7518218Slinton private integer trid; /* id number of current trace */ 769663Slinton 779663Slinton typedef struct Trcmd { 789663Slinton Integer trid; 799663Slinton Event event; 809663Slinton Cmdlist cmdlist; 819663Slinton } *Trcmd; 829663Slinton 839663Slinton private List eachline; /* commands to execute after each line */ 849663Slinton private List eachinst; /* commands to execute after each instruction */ 859663Slinton 869663Slinton private Breakpoint bp_alloc(); 879663Slinton 889663Slinton /* 899663Slinton * Initialize breakpoint information. 909663Slinton */ 919663Slinton 929663Slinton private Symbol builtinsym(str, class, type) 939663Slinton String str; 949663Slinton Symclass class; 959663Slinton Symbol type; 969663Slinton { 979663Slinton Symbol s; 989663Slinton 999663Slinton s = insert(identname(str, true)); 1009663Slinton s->language = findlanguage(".s"); 1019663Slinton s->class = class; 1029663Slinton s->type = type; 1039663Slinton return s; 1049663Slinton } 1059663Slinton 1069663Slinton public bpinit() 1079663Slinton { 1089663Slinton linesym = builtinsym("$line", VAR, t_int); 1099663Slinton procsym = builtinsym("$proc", PROC, nil); 1109663Slinton pcsym = lookup(identname("$pc", true)); 1119663Slinton if (pcsym == nil) { 1129663Slinton panic("can't find $pc"); 1139663Slinton } 1149663Slinton retaddrsym = builtinsym("$retaddr", VAR, t_int); 1159663Slinton eventlist = list_alloc(); 1169663Slinton bplist = list_alloc(); 1179663Slinton eachline = list_alloc(); 1189663Slinton eachinst = list_alloc(); 1199663Slinton } 1209663Slinton 1219663Slinton /* 1229663Slinton * Trap an event and do the associated commands when it occurs. 1239663Slinton */ 1249663Slinton 1259663Slinton public Event event_alloc(istmp, econd, cmdlist) 12618218Slinton boolean istmp; 1279663Slinton Node econd; 1289663Slinton Cmdlist cmdlist; 1299663Slinton { 1309663Slinton register Event e; 1319663Slinton 1329663Slinton e = new(Event); 13318218Slinton ++eventid; 13418218Slinton e->id = eventid; 1359663Slinton e->temporary = istmp; 1369663Slinton e->condition = econd; 1379663Slinton e->actions = cmdlist; 1389663Slinton eventlist_append(e, eventlist); 13918218Slinton curevent = e; 1409663Slinton translate(e); 1419663Slinton return e; 1429663Slinton } 1439663Slinton 1449663Slinton /* 1459663Slinton * Delete the event with the given id. 14616609Ssam * Returns whether it's successful or not. 1479663Slinton */ 1489663Slinton 14916609Ssam public boolean delevent (id) 1509663Slinton unsigned int id; 1519663Slinton { 1529663Slinton Event e; 1539663Slinton Breakpoint bp; 1549663Slinton Trcmd t; 15516609Ssam boolean found; 1569663Slinton 15716609Ssam found = false; 1589663Slinton foreach (Event, e, eventlist) 1599663Slinton if (e->id == id) { 16016609Ssam found = true; 1619663Slinton foreach (Breakpoint, bp, bplist) 1629663Slinton if (bp->event == e) { 16318218Slinton if (tracebpts) { 16418218Slinton printf("deleting breakpoint at 0x%x\n", bp->bpaddr); 16518218Slinton fflush(stdout); 16618218Slinton } 1679663Slinton list_delete(list_curitem(bplist), bplist); 1689663Slinton } 1699663Slinton endfor 17016609Ssam list_delete(list_curitem(eventlist), eventlist); 1719663Slinton break; 1729663Slinton } 1739663Slinton endfor 1749663Slinton foreach (Trcmd, t, eachline) 1759663Slinton if (t->event->id == id) { 17616609Ssam found = true; 1779663Slinton printrmtr(t); 1789663Slinton list_delete(list_curitem(eachline), eachline); 1799663Slinton } 1809663Slinton endfor 1819663Slinton foreach (Trcmd, t, eachinst) 1829663Slinton if (t->event->id == id) { 18316609Ssam found = true; 1849663Slinton printrmtr(t); 1859663Slinton list_delete(list_curitem(eachinst), eachinst); 1869663Slinton } 1879663Slinton endfor 1889663Slinton if (list_size(eachinst) == 0) { 1899663Slinton inst_tracing = false; 1909663Slinton if (list_size(eachline) == 0) { 1919663Slinton single_stepping = false; 1929663Slinton } 1939663Slinton } 19416609Ssam return found; 1959663Slinton } 1969663Slinton 1979663Slinton /* 1989663Slinton * Translate an event into the appropriate breakpoints and actions. 1999663Slinton * While we're at it, turn on the breakpoints if the condition is true. 2009663Slinton */ 2019663Slinton 2029663Slinton private translate(e) 2039663Slinton Event e; 2049663Slinton { 2059663Slinton Breakpoint bp; 2069663Slinton Symbol s; 2079663Slinton Node place; 2089663Slinton Lineno line; 2099663Slinton Address addr; 2109663Slinton 2119663Slinton checkref(e->condition); 2129663Slinton switch (e->condition->op) { 2139663Slinton case O_EQ: 2149663Slinton if (e->condition->value.arg[0]->op == O_SYM) { 2159663Slinton s = e->condition->value.arg[0]->value.sym; 2169663Slinton place = e->condition->value.arg[1]; 2179663Slinton if (s == linesym) { 2189663Slinton if (place->op == O_QLINE) { 2199663Slinton line = place->value.arg[1]->value.lcon; 22016609Ssam addr = objaddr(line, place->value.arg[0]->value.scon); 2219663Slinton } else { 2229663Slinton eval(place); 2239663Slinton line = pop(long); 2249663Slinton addr = objaddr(line, cursource); 2259663Slinton } 2269663Slinton if (addr == NOADDR) { 22716609Ssam if (not delevent(e->id)) { 22816609Ssam printf("!! dbx.translate: can't undo event %d?\n", 22916609Ssam e->id); 23016609Ssam } 2319663Slinton beginerrmsg(); 2329663Slinton fprintf(stderr, "no executable code at line "); 2339663Slinton prtree(stderr, place); 2349663Slinton enderrmsg(); 2359663Slinton } 2369663Slinton bp = bp_alloc(e, addr, line, e->actions); 2379663Slinton } else if (s == procsym) { 2389663Slinton eval(place); 2399663Slinton s = pop(Symbol); 2409663Slinton bp = bp_alloc(e, codeloc(s), 0, e->actions); 2419663Slinton if (isactive(s) and pc != codeloc(program)) { 2429663Slinton evalcmdlist(e->actions); 2439663Slinton } 2449663Slinton } else if (s == pcsym) { 2459663Slinton eval(place); 2469663Slinton bp = bp_alloc(e, pop(Address), 0, e->actions); 2479663Slinton } else { 2489663Slinton condbp(e); 2499663Slinton } 2509663Slinton } else { 2519663Slinton condbp(e); 2529663Slinton } 2539663Slinton break; 2549663Slinton 2559663Slinton /* 2569663Slinton * These should be handled specially. 2579663Slinton * But for now I'm ignoring the problem. 2589663Slinton */ 2599663Slinton case O_AND: 2609663Slinton case O_OR: 2619663Slinton default: 2629663Slinton condbp(e); 2639663Slinton break; 2649663Slinton } 2659663Slinton } 2669663Slinton 2679663Slinton /* 2689663Slinton * Create a breakpoint for a condition that cannot be pinpointed 2699663Slinton * to happening at a particular address, but one for which we 2709663Slinton * must single step and check the condition after each statement. 2719663Slinton */ 2729663Slinton 2739663Slinton private condbp(e) 2749663Slinton Event e; 2759663Slinton { 2769663Slinton Symbol p; 2779663Slinton Breakpoint bp; 2789663Slinton Cmdlist actions; 2799663Slinton 2809663Slinton p = tcontainer(e->condition); 2819663Slinton if (p == nil) { 2829663Slinton p = program; 2839663Slinton } 2849663Slinton actions = buildcmdlist(build(O_IF, e->condition, e->actions)); 2859663Slinton actions = buildcmdlist(build(O_TRACEON, false, actions)); 2869663Slinton bp = bp_alloc(e, codeloc(p), 0, actions); 2879663Slinton } 2889663Slinton 2899663Slinton /* 2909663Slinton * Determine the deepest nested subprogram that still contains 2919663Slinton * all elements in the given expression. 2929663Slinton */ 2939663Slinton 2949663Slinton public Symbol tcontainer(exp) 2959663Slinton Node exp; 2969663Slinton { 2979663Slinton Integer i; 2989663Slinton Symbol s, t, u, v; 2999663Slinton 3009663Slinton checkref(exp); 3019663Slinton s = nil; 3029663Slinton if (exp->op == O_SYM) { 3039663Slinton s = container(exp->value.sym); 3049663Slinton } else if (not isleaf(exp->op)) { 3059663Slinton for (i = 0; i < nargs(exp->op); i++) { 3069663Slinton t = tcontainer(exp->value.arg[i]); 3079663Slinton if (t != nil) { 3089663Slinton if (s == nil) { 3099663Slinton s = t; 3109663Slinton } else { 3119663Slinton u = s; 3129663Slinton v = t; 3139663Slinton while (u != v and u != nil) { 3149663Slinton u = container(u); 3159663Slinton v = container(v); 3169663Slinton } 3179663Slinton if (u == nil) { 3189663Slinton panic("bad ancestry for \"%s\"", symname(s)); 3199663Slinton } else { 3209663Slinton s = u; 3219663Slinton } 3229663Slinton } 3239663Slinton } 3249663Slinton } 3259663Slinton } 3269663Slinton return s; 3279663Slinton } 3289663Slinton 3299663Slinton /* 33011869Slinton * Determine if the given function can be executed at full speed. 33111869Slinton * This can only be done if there are no breakpoints within the function. 33211869Slinton */ 33311869Slinton 33418218Slinton public boolean canskip(f) 33511869Slinton Symbol f; 33611869Slinton { 33711869Slinton Breakpoint p; 33818218Slinton boolean ok; 33911869Slinton 34011869Slinton ok = true; 34111869Slinton foreach (Breakpoint, p, bplist) 34211869Slinton if (whatblock(p->bpaddr) == f) { 34311869Slinton ok = false; 34411869Slinton break; 34511869Slinton } 34611869Slinton endfor 34711869Slinton return ok; 34811869Slinton } 34911869Slinton 35011869Slinton /* 3519663Slinton * Print out what's currently being traced by looking at 3529663Slinton * the currently active events. 3539663Slinton * 3549663Slinton * Some convolution here to translate internal representation 3559663Slinton * of events back into something more palatable. 3569663Slinton */ 3579663Slinton 3589663Slinton public status() 3599663Slinton { 3609663Slinton Event e; 3619663Slinton 3629663Slinton foreach (Event, e, eventlist) 3639663Slinton if (not e->temporary) { 36411869Slinton printevent(e); 3659663Slinton } 3669663Slinton endfor 3679663Slinton } 3689663Slinton 36911869Slinton public printevent(e) 37011869Slinton Event e; 37111869Slinton { 37211869Slinton Command cmd; 37311869Slinton 37411869Slinton if (not isredirected()) { 37516609Ssam printeventid(e->id); 37611869Slinton } 37711869Slinton cmd = list_element(Command, list_head(e->actions)); 37811869Slinton if (cmd->op == O_PRINTCALL) { 37911869Slinton printf("trace "); 38011869Slinton printname(stdout, cmd->value.sym); 38111869Slinton } else { 38211869Slinton if (list_size(e->actions) > 1) { 38311869Slinton printf("{ "); 38411869Slinton } 38511869Slinton foreach (Command, cmd, e->actions) 38611869Slinton printcmd(stdout, cmd); 38711869Slinton if (not list_islast()) { 38811869Slinton printf("; "); 38911869Slinton } 39011869Slinton endfor 39111869Slinton if (list_size(e->actions) > 1) { 39211869Slinton printf(" }"); 39311869Slinton } 39411869Slinton printcond(e->condition); 39511869Slinton } 39611869Slinton printf("\n"); 39711869Slinton } 39811869Slinton 39916609Ssam private printeventid (id) 40016609Ssam integer id; 40116609Ssam { 40216609Ssam printf("[%d] ", id); 40316609Ssam } 40416609Ssam 4059663Slinton /* 4069663Slinton * Print out a condition. 4079663Slinton */ 4089663Slinton 4099663Slinton private printcond(cond) 4109663Slinton Node cond; 4119663Slinton { 4129663Slinton Symbol s; 4139663Slinton Node place; 4149663Slinton 4159663Slinton if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) { 4169663Slinton s = cond->value.arg[0]->value.sym; 4179663Slinton place = cond->value.arg[1]; 4189663Slinton if (s == procsym) { 4199663Slinton if (place->value.sym != program) { 4209663Slinton printf(" in "); 4219663Slinton printname(stdout, place->value.sym); 4229663Slinton } 4239663Slinton } else if (s == linesym) { 4249663Slinton printf(" at "); 4259663Slinton prtree(stdout, place); 4269663Slinton } else if (s == pcsym or s == retaddrsym) { 4279663Slinton printf("i at "); 4289663Slinton prtree(stdout, place); 4299663Slinton } else { 4309663Slinton printf(" when "); 4319663Slinton prtree(stdout, cond); 4329663Slinton } 4339663Slinton } else { 4349663Slinton printf(" when "); 4359663Slinton prtree(stdout, cond); 4369663Slinton } 4379663Slinton } 4389663Slinton 4399663Slinton /* 4409663Slinton * Add a breakpoint to the list and return it. 4419663Slinton */ 4429663Slinton 4439663Slinton private Breakpoint bp_alloc(e, addr, line, actions) 4449663Slinton Event e; 4459663Slinton Address addr; 4469663Slinton Lineno line; 4479663Slinton Cmdlist actions; 4489663Slinton { 4499663Slinton register Breakpoint p; 4509663Slinton 4519663Slinton p = new(Breakpoint); 4529663Slinton p->event = e; 4539663Slinton p->bpaddr = addr; 4549663Slinton p->bpline = line; 4559663Slinton p->actions = actions; 45618218Slinton p->temporary = false; 45718218Slinton if (tracebpts) { 45818218Slinton if (e == nil) { 459*30796Sbostic printf("new bp at 0x%x for event ??\n", addr); 46018218Slinton } else { 46118218Slinton printf("new bp at 0x%x for event %d\n", addr, e->id); 46218218Slinton } 46318218Slinton fflush(stdout); 46418218Slinton } 4659663Slinton bplist_append(p, bplist); 4669663Slinton return p; 4679663Slinton } 4689663Slinton 4699663Slinton /* 4709663Slinton * Free all storage in the event and breakpoint tables. 4719663Slinton */ 4729663Slinton 4739663Slinton public bpfree() 4749663Slinton { 4759663Slinton register Event e; 4769663Slinton 4779663Slinton fixbps(); 4789663Slinton foreach (Event, e, eventlist) 47916609Ssam if (not delevent(e->id)) { 48016609Ssam printf("!! dbx.bpfree: can't delete event %d\n", e->id); 48116609Ssam } 4829663Slinton list_delete(list_curitem(eventlist), eventlist); 4839663Slinton endfor 4849663Slinton } 4859663Slinton 4869663Slinton /* 4879663Slinton * Determine if the program stopped at a known breakpoint 4889663Slinton * and if so do the associated commands. 4899663Slinton */ 4909663Slinton 49118218Slinton public boolean bpact() 4929663Slinton { 4939663Slinton register Breakpoint p; 49418218Slinton boolean found; 49516609Ssam integer eventId; 4969663Slinton 4979663Slinton found = false; 4989663Slinton foreach (Breakpoint, p, bplist) 4999663Slinton if (p->bpaddr == pc) { 50018218Slinton if (tracebpts) { 50118218Slinton printf("breakpoint for event %d found at location 0x%x\n", 50218218Slinton p->event->id, pc); 50318218Slinton } 5049663Slinton found = true; 50518218Slinton if (p->event->temporary) { 50618218Slinton if (not delevent(p->event->id)) { 50718218Slinton printf("!! dbx.bpact: can't find event %d\n", 50818218Slinton p->event->id); 50918218Slinton } 51018218Slinton } 5119663Slinton evalcmdlist(p->actions); 51218218Slinton if (isstopped) { 51318218Slinton eventId = p->event->id; 51418218Slinton } 51518218Slinton if (p->temporary) { 51618218Slinton list_delete(list_curitem(bplist), bplist); 51718218Slinton } 5189663Slinton } 5199663Slinton endfor 5209663Slinton if (isstopped) { 52116609Ssam if (found) { 52216609Ssam printeventid(eventId); 52316609Ssam } 5249663Slinton printstatus(); 5259663Slinton } 5269663Slinton fflush(stdout); 5279663Slinton return found; 5289663Slinton } 5299663Slinton 5309663Slinton /* 5319663Slinton * Begin single stepping and executing the given commands after each step. 5329663Slinton * If the first argument is true step by instructions, otherwise 5339663Slinton * step by source lines. 5349663Slinton * 5359663Slinton * We automatically set a breakpoint at the end of the current procedure 5369663Slinton * to turn off the given tracing. 5379663Slinton */ 5389663Slinton 5399663Slinton public traceon(inst, event, cmdlist) 54018218Slinton boolean inst; 5419663Slinton Event event; 5429663Slinton Cmdlist cmdlist; 5439663Slinton { 5449663Slinton register Trcmd trcmd; 54518218Slinton Breakpoint bp; 5469663Slinton Cmdlist actions; 54711869Slinton Address ret; 54818218Slinton Event e; 5499663Slinton 55018218Slinton if (event == nil) { 55118218Slinton e = curevent; 55218218Slinton } else { 55318218Slinton e = event; 55418218Slinton } 5559663Slinton trcmd = new(Trcmd); 55618218Slinton ++trid; 55718218Slinton trcmd->trid = trid; 55818218Slinton trcmd->event = e; 5599663Slinton trcmd->cmdlist = cmdlist; 5609663Slinton single_stepping = true; 5619663Slinton if (inst) { 5629663Slinton inst_tracing = true; 5639663Slinton list_append(list_item(trcmd), nil, eachinst); 5649663Slinton } else { 5659663Slinton list_append(list_item(trcmd), nil, eachline); 5669663Slinton } 56711869Slinton ret = return_addr(); 56811869Slinton if (ret != 0) { 56918218Slinton actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid)); 57018218Slinton bp = bp_alloc(e, (Address) ret, 0, actions); 57118218Slinton bp->temporary = true; 57211869Slinton } 57318218Slinton if (tracebpts) { 57418218Slinton printf("adding trace %d for event %d\n", trcmd->trid, e->id); 57518218Slinton } 5769663Slinton } 5779663Slinton 5789663Slinton /* 5799663Slinton * Turn off some kind of tracing. 5809663Slinton * Strictly an internal command, this cannot be invoked by the user. 5819663Slinton */ 5829663Slinton 5839663Slinton public traceoff(id) 5849663Slinton Integer id; 5859663Slinton { 5869663Slinton register Trcmd t; 58718218Slinton register boolean found; 5889663Slinton 5899663Slinton found = false; 5909663Slinton foreach (Trcmd, t, eachline) 5919663Slinton if (t->trid == id) { 5929663Slinton printrmtr(t); 5939663Slinton list_delete(list_curitem(eachline), eachline); 5949663Slinton found = true; 5959663Slinton break; 5969663Slinton } 5979663Slinton endfor 5989663Slinton if (not found) { 5999663Slinton foreach (Trcmd, t, eachinst) 6009663Slinton if (t->event->id == id) { 6019663Slinton printrmtr(t); 6029663Slinton list_delete(list_curitem(eachinst), eachinst); 6039663Slinton found = true; 6049663Slinton break; 6059663Slinton } 6069663Slinton endfor 6079663Slinton if (not found) { 60818218Slinton beginerrmsg(); 60918218Slinton fprintf(stderr, "[internal error: trace id %d not found]\n", id); 6109663Slinton } 6119663Slinton } 6129663Slinton if (list_size(eachinst) == 0) { 6139663Slinton inst_tracing = false; 6149663Slinton if (list_size(eachline) == 0) { 6159663Slinton single_stepping = false; 6169663Slinton } 6179663Slinton } 6189663Slinton } 6199663Slinton 6209663Slinton /* 6219663Slinton * If breakpoints are being traced, note that a Trcmd is being deleted. 6229663Slinton */ 6239663Slinton 6249663Slinton private printrmtr(t) 6259663Slinton Trcmd t; 6269663Slinton { 62718218Slinton if (tracebpts) { 62818218Slinton printf("removing trace %d", t->trid); 62918218Slinton if (t->event != nil) { 63018218Slinton printf(" for event %d", t->event->id); 63118218Slinton } 63218218Slinton printf("\n"); 6339663Slinton } 6349663Slinton } 6359663Slinton 6369663Slinton /* 6379663Slinton * Print out news during single step tracing. 6389663Slinton */ 6399663Slinton 6409663Slinton public printnews() 6419663Slinton { 6429663Slinton register Trcmd t; 6439663Slinton 6449663Slinton foreach (Trcmd, t, eachline) 6459663Slinton evalcmdlist(t->cmdlist); 6469663Slinton endfor 6479663Slinton foreach (Trcmd, t, eachinst) 6489663Slinton evalcmdlist(t->cmdlist); 6499663Slinton endfor 6509663Slinton bpact(); 6519663Slinton } 6529663Slinton 6539663Slinton /* 6549663Slinton * A procedure call/return has occurred while single-stepping, 6559663Slinton * note it if we're tracing lines. 6569663Slinton */ 6579663Slinton 65818218Slinton private boolean chklist(); 6599663Slinton 6609663Slinton public callnews(iscall) 66118218Slinton boolean iscall; 6629663Slinton { 6639663Slinton if (not chklist(eachline, iscall)) { 6649663Slinton chklist(eachinst, iscall); 6659663Slinton } 6669663Slinton } 6679663Slinton 66818218Slinton private boolean chklist(list, iscall) 6699663Slinton List list; 67018218Slinton boolean iscall; 6719663Slinton { 6729663Slinton register Trcmd t; 6739663Slinton register Command cmd; 6749663Slinton 67516609Ssam setcurfunc(whatblock(pc)); 6769663Slinton foreach (Trcmd, t, list) 6779663Slinton foreach (Command, cmd, t->cmdlist) 6789663Slinton if (cmd->op == O_PRINTSRCPOS and 6799663Slinton (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) { 6809663Slinton if (iscall) { 6819663Slinton printentry(curfunc); 6829663Slinton } else { 6839663Slinton printexit(curfunc); 6849663Slinton } 6859663Slinton return true; 6869663Slinton } 6879663Slinton endfor 6889663Slinton endfor 6899663Slinton return false; 6909663Slinton } 6919663Slinton 6929663Slinton /* 6939663Slinton * When tracing variables we keep a copy of their most recent value 6949663Slinton * and compare it to the current one each time a breakpoint occurs. 6959663Slinton * MAXTRSIZE is the maximum size variable we allow. 6969663Slinton */ 6979663Slinton 6989663Slinton #define MAXTRSIZE 512 6999663Slinton 7009663Slinton /* 7019663Slinton * List of variables being watched. 7029663Slinton */ 7039663Slinton 7049663Slinton typedef struct Trinfo *Trinfo; 7059663Slinton 7069663Slinton struct Trinfo { 7079663Slinton Node variable; 7089663Slinton Address traddr; 7099663Slinton Symbol trblock; 7109663Slinton char *trvalue; 7119663Slinton }; 7129663Slinton 7139663Slinton private List trinfolist; 7149663Slinton 7159663Slinton /* 7169663Slinton * Find the trace information record associated with the given record. 7179663Slinton * If there isn't one then create it and add it to the list. 7189663Slinton */ 7199663Slinton 7209663Slinton private Trinfo findtrinfo(p) 7219663Slinton Node p; 7229663Slinton { 7239663Slinton register Trinfo tp; 72418218Slinton boolean isnew; 7259663Slinton 7269663Slinton isnew = true; 7279663Slinton if (trinfolist == nil) { 7289663Slinton trinfolist = list_alloc(); 7299663Slinton } else { 7309663Slinton foreach (Trinfo, tp, trinfolist) 7319663Slinton if (tp->variable == p) { 7329663Slinton isnew = false; 7339663Slinton break; 7349663Slinton } 7359663Slinton endfor 7369663Slinton } 7379663Slinton if (isnew) { 7389663Slinton if (tracebpts) { 7399663Slinton printf("adding trinfo for \""); 7409663Slinton prtree(stdout, p); 7419663Slinton printf("\"\n"); 7429663Slinton } 7439663Slinton tp = new(Trinfo); 7449663Slinton tp->variable = p; 7459663Slinton tp->traddr = lval(p); 7469663Slinton tp->trvalue = nil; 7479663Slinton list_append(list_item(tp), nil, trinfolist); 7489663Slinton } 7499663Slinton return tp; 7509663Slinton } 7519663Slinton 7529663Slinton /* 7539663Slinton * Print out the value of a variable if it has changed since the 7549663Slinton * last time we checked. 7559663Slinton */ 7569663Slinton 7579663Slinton public printifchanged(p) 7589663Slinton Node p; 7599663Slinton { 7609663Slinton register Trinfo tp; 7619663Slinton register int n; 7629663Slinton char buff[MAXTRSIZE]; 76318218Slinton Filename curfile; 7649663Slinton static Lineno prevline; 76518218Slinton static Filename prevfile; 7669663Slinton 7679663Slinton tp = findtrinfo(p); 7689663Slinton n = size(p->nodetype); 76918218Slinton dread(buff, tp->traddr, n); 77018218Slinton curfile = srcfilename(pc); 7719663Slinton if (tp->trvalue == nil) { 7729663Slinton tp->trvalue = newarr(char, n); 7739663Slinton mov(buff, tp->trvalue, n); 7749663Slinton mov(buff, sp, n); 7759663Slinton sp += n; 77618218Slinton printf("initially (at line %d in \"%s\"):\t", curline, curfile); 7779663Slinton prtree(stdout, p); 7789663Slinton printf(" = "); 7799663Slinton printval(p->nodetype); 7809663Slinton putchar('\n'); 7819663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 7829663Slinton mov(buff, tp->trvalue, n); 7839663Slinton mov(buff, sp, n); 7849663Slinton sp += n; 78518218Slinton printf("after line %d in \"%s\":\t", prevline, prevfile); 7869663Slinton prtree(stdout, p); 7879663Slinton printf(" = "); 7889663Slinton printval(p->nodetype); 7899663Slinton putchar('\n'); 7909663Slinton } 7919663Slinton prevline = curline; 79218218Slinton prevfile = curfile; 7939663Slinton } 7949663Slinton 7959663Slinton /* 7969663Slinton * Stop if the value of the given expression has changed. 7979663Slinton */ 7989663Slinton 7999663Slinton public stopifchanged(p) 8009663Slinton Node p; 8019663Slinton { 8029663Slinton register Trinfo tp; 8039663Slinton register int n; 8049663Slinton char buff[MAXTRSIZE]; 8059663Slinton static Lineno prevline; 8069663Slinton 8079663Slinton tp = findtrinfo(p); 8089663Slinton n = size(p->nodetype); 8099663Slinton dread(buff, tp->traddr, n); 8109663Slinton if (tp->trvalue == nil) { 8119663Slinton tp->trvalue = newarr(char, n); 8129663Slinton mov(buff, tp->trvalue, n); 8139663Slinton isstopped = true; 8149663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 8159663Slinton mov(buff, tp->trvalue, n); 81616609Ssam mov(buff, sp, n); 81716609Ssam sp += n; 81816609Ssam printf("after line %d:\t", prevline); 81916609Ssam prtree(stdout, p); 82016609Ssam printf(" = "); 82116609Ssam printval(p->nodetype); 82216609Ssam putchar('\n'); 8239663Slinton isstopped = true; 8249663Slinton } 8259663Slinton prevline = curline; 8269663Slinton } 8279663Slinton 8289663Slinton /* 8299663Slinton * Free the tracing table. 8309663Slinton */ 8319663Slinton 8329663Slinton public trfree() 8339663Slinton { 8349663Slinton register Trinfo tp; 8359663Slinton 8369663Slinton foreach (Trinfo, tp, trinfolist) 8379663Slinton dispose(tp->trvalue); 8389663Slinton dispose(tp); 8399663Slinton list_delete(list_curitem(trinfolist), trinfolist); 8409663Slinton endfor 8419663Slinton } 8429663Slinton 8439663Slinton /* 8449663Slinton * Fix up breakpoint information before continuing execution. 8459663Slinton * 8469663Slinton * It's necessary to destroy events and breakpoints that were created 8479663Slinton * temporarily and still exist because the program terminated abnormally. 8489663Slinton */ 8499663Slinton 8509663Slinton public fixbps() 8519663Slinton { 8529663Slinton register Event e; 8539663Slinton register Trcmd t; 8549663Slinton 8559663Slinton single_stepping = false; 8569663Slinton inst_tracing = false; 8579663Slinton trfree(); 8589663Slinton foreach (Event, e, eventlist) 8599663Slinton if (e->temporary) { 86016609Ssam if (not delevent(e->id)) { 86116609Ssam printf("!! dbx.fixbps: can't find event %d\n", e->id); 86216609Ssam } 8639663Slinton } 8649663Slinton endfor 8659663Slinton foreach (Trcmd, t, eachline) 8669663Slinton printrmtr(t); 8679663Slinton list_delete(list_curitem(eachline), eachline); 8689663Slinton endfor 8699663Slinton foreach (Trcmd, t, eachinst) 8709663Slinton printrmtr(t); 8719663Slinton list_delete(list_curitem(eachinst), eachinst); 8729663Slinton endfor 8739663Slinton } 8749663Slinton 8759663Slinton /* 8769663Slinton * Set all breakpoints in object code. 8779663Slinton */ 8789663Slinton 8799663Slinton public setallbps() 8809663Slinton { 8819663Slinton register Breakpoint p; 8829663Slinton 8839663Slinton foreach (Breakpoint, p, bplist) 8849663Slinton setbp(p->bpaddr); 8859663Slinton endfor 8869663Slinton } 8879663Slinton 8889663Slinton /* 8899663Slinton * Undo damage done by "setallbps". 8909663Slinton */ 8919663Slinton 8929663Slinton public unsetallbps() 8939663Slinton { 8949663Slinton register Breakpoint p; 8959663Slinton 8969663Slinton foreach (Breakpoint, p, bplist) 8979663Slinton unsetbp(p->bpaddr); 8989663Slinton endfor 8999663Slinton } 900