121602Sdist /* 2*38105Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*38105Sbostic * All rights reserved. 4*38105Sbostic * 5*38105Sbostic * Redistribution and use in source and binary forms are permitted 6*38105Sbostic * provided that the above copyright notice and this paragraph are 7*38105Sbostic * duplicated in all such forms and that any documentation, 8*38105Sbostic * advertising materials, and other materials related to such 9*38105Sbostic * distribution and use acknowledge that the software was developed 10*38105Sbostic * by the University of California, Berkeley. The name of the 11*38105Sbostic * University may not be used to endorse or promote products derived 12*38105Sbostic * from this software without specific prior written permission. 13*38105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38105Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621602Sdist */ 179663Slinton 1821602Sdist #ifndef lint 19*38105Sbostic static char sccsid[] = "@(#)events.c 5.4 (Berkeley) 05/23/89"; 20*38105Sbostic #endif /* not lint */ 219663Slinton 229663Slinton /* 239663Slinton * Event/breakpoint managment. 249663Slinton */ 259663Slinton 269663Slinton #include "defs.h" 279663Slinton #include "events.h" 289663Slinton #include "main.h" 299663Slinton #include "symbols.h" 309663Slinton #include "tree.h" 319663Slinton #include "eval.h" 329663Slinton #include "source.h" 339663Slinton #include "mappings.h" 3416609Ssam #include "runtime.h" 359663Slinton #include "process.h" 369663Slinton #include "machine.h" 379663Slinton #include "lists.h" 389663Slinton 399663Slinton #ifndef public 4033316Sdonn 419663Slinton typedef struct Event *Event; 429663Slinton typedef struct Breakpoint *Breakpoint; 439663Slinton 449663Slinton #include "symbols.h" 459663Slinton 469663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist) 479663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist) 489663Slinton 4933316Sdonn /* 5033316Sdonn * When tracing variables we keep a copy of their most recent value 5133316Sdonn * and compare it to the current one each time a breakpoint occurs. 5233316Sdonn * MAXTRSIZE is the maximum size variable we allow. 5333316Sdonn */ 5433316Sdonn 5533316Sdonn #define MAXTRSIZE 512 5633316Sdonn 579663Slinton #endif 589663Slinton 5933316Sdonn public boolean inst_tracing; 6033316Sdonn public boolean single_stepping; 6133316Sdonn public boolean isstopped; 6233316Sdonn 6333316Sdonn public Symbol linesym; 6433316Sdonn public Symbol procsym; 6533316Sdonn public Symbol pcsym; 6633316Sdonn public Symbol retaddrsym; 6733316Sdonn 689663Slinton struct Event { 699663Slinton unsigned int id; 7018218Slinton boolean temporary; 719663Slinton Node condition; 729663Slinton Cmdlist actions; 739663Slinton }; 749663Slinton 759663Slinton struct Breakpoint { 769663Slinton Event event; 779663Slinton Address bpaddr; 789663Slinton Lineno bpline; 799663Slinton Cmdlist actions; 8018218Slinton boolean temporary; 819663Slinton }; 829663Slinton 839663Slinton typedef List Eventlist; 849663Slinton typedef List Bplist; 859663Slinton 869663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el) 879663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl) 889663Slinton 899663Slinton private Eventlist eventlist; /* list of active events */ 909663Slinton private Bplist bplist; /* list of active breakpoints */ 9118218Slinton private Event curevent; /* most recently created event */ 9218218Slinton private integer eventid; /* id number of current event */ 9318218Slinton private integer trid; /* id number of current trace */ 949663Slinton 959663Slinton typedef struct Trcmd { 969663Slinton Integer trid; 979663Slinton Event event; 989663Slinton Cmdlist cmdlist; 999663Slinton } *Trcmd; 1009663Slinton 1019663Slinton private List eachline; /* commands to execute after each line */ 1029663Slinton private List eachinst; /* commands to execute after each instruction */ 1039663Slinton 1049663Slinton private Breakpoint bp_alloc(); 1059663Slinton 1069663Slinton /* 1079663Slinton * Initialize breakpoint information. 1089663Slinton */ 1099663Slinton 1109663Slinton private Symbol builtinsym(str, class, type) 1119663Slinton String str; 1129663Slinton Symclass class; 1139663Slinton Symbol type; 1149663Slinton { 1159663Slinton Symbol s; 1169663Slinton 1179663Slinton s = insert(identname(str, true)); 1189663Slinton s->language = findlanguage(".s"); 1199663Slinton s->class = class; 1209663Slinton s->type = type; 1219663Slinton return s; 1229663Slinton } 1239663Slinton 1249663Slinton public bpinit() 1259663Slinton { 1269663Slinton linesym = builtinsym("$line", VAR, t_int); 1279663Slinton procsym = builtinsym("$proc", PROC, nil); 1289663Slinton pcsym = lookup(identname("$pc", true)); 1299663Slinton if (pcsym == nil) { 1309663Slinton panic("can't find $pc"); 1319663Slinton } 1329663Slinton retaddrsym = builtinsym("$retaddr", VAR, t_int); 1339663Slinton eventlist = list_alloc(); 1349663Slinton bplist = list_alloc(); 1359663Slinton eachline = list_alloc(); 1369663Slinton eachinst = list_alloc(); 1379663Slinton } 1389663Slinton 1399663Slinton /* 1409663Slinton * Trap an event and do the associated commands when it occurs. 1419663Slinton */ 1429663Slinton 1439663Slinton public Event event_alloc(istmp, econd, cmdlist) 14418218Slinton boolean istmp; 1459663Slinton Node econd; 1469663Slinton Cmdlist cmdlist; 1479663Slinton { 1489663Slinton register Event e; 1499663Slinton 1509663Slinton e = new(Event); 15118218Slinton ++eventid; 15218218Slinton e->id = eventid; 1539663Slinton e->temporary = istmp; 1549663Slinton e->condition = econd; 1559663Slinton e->actions = cmdlist; 1569663Slinton eventlist_append(e, eventlist); 15718218Slinton curevent = e; 1589663Slinton translate(e); 1599663Slinton return e; 1609663Slinton } 1619663Slinton 1629663Slinton /* 1639663Slinton * Delete the event with the given id. 16416609Ssam * Returns whether it's successful or not. 1659663Slinton */ 1669663Slinton 16716609Ssam public boolean delevent (id) 1689663Slinton unsigned int id; 1699663Slinton { 1709663Slinton Event e; 1719663Slinton Breakpoint bp; 1729663Slinton Trcmd t; 17316609Ssam boolean found; 1749663Slinton 17516609Ssam found = false; 1769663Slinton foreach (Event, e, eventlist) 1779663Slinton if (e->id == id) { 17816609Ssam found = true; 1799663Slinton foreach (Breakpoint, bp, bplist) 1809663Slinton if (bp->event == e) { 18118218Slinton if (tracebpts) { 18218218Slinton printf("deleting breakpoint at 0x%x\n", bp->bpaddr); 18318218Slinton fflush(stdout); 18418218Slinton } 1859663Slinton list_delete(list_curitem(bplist), bplist); 1869663Slinton } 1879663Slinton endfor 18816609Ssam list_delete(list_curitem(eventlist), eventlist); 1899663Slinton break; 1909663Slinton } 1919663Slinton endfor 1929663Slinton foreach (Trcmd, t, eachline) 1939663Slinton if (t->event->id == id) { 19416609Ssam found = true; 1959663Slinton printrmtr(t); 1969663Slinton list_delete(list_curitem(eachline), eachline); 1979663Slinton } 1989663Slinton endfor 1999663Slinton foreach (Trcmd, t, eachinst) 2009663Slinton if (t->event->id == id) { 20116609Ssam found = true; 2029663Slinton printrmtr(t); 2039663Slinton list_delete(list_curitem(eachinst), eachinst); 2049663Slinton } 2059663Slinton endfor 2069663Slinton if (list_size(eachinst) == 0) { 2079663Slinton inst_tracing = false; 2089663Slinton if (list_size(eachline) == 0) { 2099663Slinton single_stepping = false; 2109663Slinton } 2119663Slinton } 21216609Ssam return found; 2139663Slinton } 2149663Slinton 2159663Slinton /* 2169663Slinton * Translate an event into the appropriate breakpoints and actions. 2179663Slinton * While we're at it, turn on the breakpoints if the condition is true. 2189663Slinton */ 2199663Slinton 2209663Slinton private translate(e) 2219663Slinton Event e; 2229663Slinton { 2239663Slinton Breakpoint bp; 2249663Slinton Symbol s; 2259663Slinton Node place; 2269663Slinton Lineno line; 2279663Slinton Address addr; 2289663Slinton 2299663Slinton checkref(e->condition); 2309663Slinton switch (e->condition->op) { 2319663Slinton case O_EQ: 2329663Slinton if (e->condition->value.arg[0]->op == O_SYM) { 2339663Slinton s = e->condition->value.arg[0]->value.sym; 2349663Slinton place = e->condition->value.arg[1]; 2359663Slinton if (s == linesym) { 2369663Slinton if (place->op == O_QLINE) { 2379663Slinton line = place->value.arg[1]->value.lcon; 23816609Ssam addr = objaddr(line, place->value.arg[0]->value.scon); 2399663Slinton } else { 2409663Slinton eval(place); 2419663Slinton line = pop(long); 2429663Slinton addr = objaddr(line, cursource); 2439663Slinton } 2449663Slinton if (addr == NOADDR) { 24516609Ssam if (not delevent(e->id)) { 24616609Ssam printf("!! dbx.translate: can't undo event %d?\n", 24716609Ssam e->id); 24816609Ssam } 2499663Slinton beginerrmsg(); 2509663Slinton fprintf(stderr, "no executable code at line "); 2519663Slinton prtree(stderr, place); 2529663Slinton enderrmsg(); 2539663Slinton } 2549663Slinton bp = bp_alloc(e, addr, line, e->actions); 2559663Slinton } else if (s == procsym) { 2569663Slinton eval(place); 2579663Slinton s = pop(Symbol); 2589663Slinton bp = bp_alloc(e, codeloc(s), 0, e->actions); 2599663Slinton if (isactive(s) and pc != codeloc(program)) { 2609663Slinton evalcmdlist(e->actions); 2619663Slinton } 2629663Slinton } else if (s == pcsym) { 2639663Slinton eval(place); 2649663Slinton bp = bp_alloc(e, pop(Address), 0, e->actions); 2659663Slinton } else { 2669663Slinton condbp(e); 2679663Slinton } 2689663Slinton } else { 2699663Slinton condbp(e); 2709663Slinton } 2719663Slinton break; 2729663Slinton 2739663Slinton /* 2749663Slinton * These should be handled specially. 2759663Slinton * But for now I'm ignoring the problem. 2769663Slinton */ 2779663Slinton case O_AND: 2789663Slinton case O_OR: 2799663Slinton default: 2809663Slinton condbp(e); 2819663Slinton break; 2829663Slinton } 2839663Slinton } 2849663Slinton 2859663Slinton /* 2869663Slinton * Create a breakpoint for a condition that cannot be pinpointed 2879663Slinton * to happening at a particular address, but one for which we 2889663Slinton * must single step and check the condition after each statement. 2899663Slinton */ 2909663Slinton 2919663Slinton private condbp(e) 2929663Slinton Event e; 2939663Slinton { 2949663Slinton Symbol p; 2959663Slinton Breakpoint bp; 2969663Slinton Cmdlist actions; 2979663Slinton 2989663Slinton p = tcontainer(e->condition); 2999663Slinton if (p == nil) { 3009663Slinton p = program; 3019663Slinton } 3029663Slinton actions = buildcmdlist(build(O_IF, e->condition, e->actions)); 3039663Slinton actions = buildcmdlist(build(O_TRACEON, false, actions)); 3049663Slinton bp = bp_alloc(e, codeloc(p), 0, actions); 3059663Slinton } 3069663Slinton 3079663Slinton /* 3089663Slinton * Determine the deepest nested subprogram that still contains 3099663Slinton * all elements in the given expression. 3109663Slinton */ 3119663Slinton 3129663Slinton public Symbol tcontainer(exp) 3139663Slinton Node exp; 3149663Slinton { 3159663Slinton Integer i; 3169663Slinton Symbol s, t, u, v; 3179663Slinton 3189663Slinton checkref(exp); 3199663Slinton s = nil; 3209663Slinton if (exp->op == O_SYM) { 3219663Slinton s = container(exp->value.sym); 3229663Slinton } else if (not isleaf(exp->op)) { 3239663Slinton for (i = 0; i < nargs(exp->op); i++) { 3249663Slinton t = tcontainer(exp->value.arg[i]); 3259663Slinton if (t != nil) { 3269663Slinton if (s == nil) { 3279663Slinton s = t; 3289663Slinton } else { 3299663Slinton u = s; 3309663Slinton v = t; 3319663Slinton while (u != v and u != nil) { 3329663Slinton u = container(u); 3339663Slinton v = container(v); 3349663Slinton } 3359663Slinton if (u == nil) { 3369663Slinton panic("bad ancestry for \"%s\"", symname(s)); 3379663Slinton } else { 3389663Slinton s = u; 3399663Slinton } 3409663Slinton } 3419663Slinton } 3429663Slinton } 3439663Slinton } 3449663Slinton return s; 3459663Slinton } 3469663Slinton 3479663Slinton /* 34811869Slinton * Determine if the given function can be executed at full speed. 34911869Slinton * This can only be done if there are no breakpoints within the function. 35011869Slinton */ 35111869Slinton 35218218Slinton public boolean canskip(f) 35311869Slinton Symbol f; 35411869Slinton { 35511869Slinton Breakpoint p; 35618218Slinton boolean ok; 35711869Slinton 35811869Slinton ok = true; 35911869Slinton foreach (Breakpoint, p, bplist) 36011869Slinton if (whatblock(p->bpaddr) == f) { 36111869Slinton ok = false; 36211869Slinton break; 36311869Slinton } 36411869Slinton endfor 36511869Slinton return ok; 36611869Slinton } 36711869Slinton 36811869Slinton /* 3699663Slinton * Print out what's currently being traced by looking at 3709663Slinton * the currently active events. 3719663Slinton * 3729663Slinton * Some convolution here to translate internal representation 3739663Slinton * of events back into something more palatable. 3749663Slinton */ 3759663Slinton 3769663Slinton public status() 3779663Slinton { 3789663Slinton Event e; 3799663Slinton 3809663Slinton foreach (Event, e, eventlist) 3819663Slinton if (not e->temporary) { 38211869Slinton printevent(e); 3839663Slinton } 3849663Slinton endfor 3859663Slinton } 3869663Slinton 38711869Slinton public printevent(e) 38811869Slinton Event e; 38911869Slinton { 39011869Slinton Command cmd; 39111869Slinton 39211869Slinton if (not isredirected()) { 39316609Ssam printeventid(e->id); 39411869Slinton } 39511869Slinton cmd = list_element(Command, list_head(e->actions)); 39611869Slinton if (cmd->op == O_PRINTCALL) { 39711869Slinton printf("trace "); 39811869Slinton printname(stdout, cmd->value.sym); 39911869Slinton } else { 40011869Slinton if (list_size(e->actions) > 1) { 40111869Slinton printf("{ "); 40211869Slinton } 40311869Slinton foreach (Command, cmd, e->actions) 40411869Slinton printcmd(stdout, cmd); 40511869Slinton if (not list_islast()) { 40611869Slinton printf("; "); 40711869Slinton } 40811869Slinton endfor 40911869Slinton if (list_size(e->actions) > 1) { 41011869Slinton printf(" }"); 41111869Slinton } 41211869Slinton printcond(e->condition); 41311869Slinton } 41411869Slinton printf("\n"); 41511869Slinton } 41611869Slinton 41716609Ssam private printeventid (id) 41816609Ssam integer id; 41916609Ssam { 42016609Ssam printf("[%d] ", id); 42116609Ssam } 42216609Ssam 4239663Slinton /* 4249663Slinton * Print out a condition. 4259663Slinton */ 4269663Slinton 4279663Slinton private printcond(cond) 4289663Slinton Node cond; 4299663Slinton { 4309663Slinton Symbol s; 4319663Slinton Node place; 4329663Slinton 4339663Slinton if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) { 4349663Slinton s = cond->value.arg[0]->value.sym; 4359663Slinton place = cond->value.arg[1]; 4369663Slinton if (s == procsym) { 4379663Slinton if (place->value.sym != program) { 4389663Slinton printf(" in "); 4399663Slinton printname(stdout, place->value.sym); 4409663Slinton } 4419663Slinton } else if (s == linesym) { 4429663Slinton printf(" at "); 4439663Slinton prtree(stdout, place); 4449663Slinton } else if (s == pcsym or s == retaddrsym) { 4459663Slinton printf("i at "); 4469663Slinton prtree(stdout, place); 4479663Slinton } else { 4489663Slinton printf(" when "); 4499663Slinton prtree(stdout, cond); 4509663Slinton } 4519663Slinton } else { 4529663Slinton printf(" when "); 4539663Slinton prtree(stdout, cond); 4549663Slinton } 4559663Slinton } 4569663Slinton 4579663Slinton /* 4589663Slinton * Add a breakpoint to the list and return it. 4599663Slinton */ 4609663Slinton 4619663Slinton private Breakpoint bp_alloc(e, addr, line, actions) 4629663Slinton Event e; 4639663Slinton Address addr; 4649663Slinton Lineno line; 4659663Slinton Cmdlist actions; 4669663Slinton { 4679663Slinton register Breakpoint p; 4689663Slinton 4699663Slinton p = new(Breakpoint); 4709663Slinton p->event = e; 4719663Slinton p->bpaddr = addr; 4729663Slinton p->bpline = line; 4739663Slinton p->actions = actions; 47418218Slinton p->temporary = false; 47518218Slinton if (tracebpts) { 47618218Slinton if (e == nil) { 47730796Sbostic printf("new bp at 0x%x for event ??\n", addr); 47818218Slinton } else { 47918218Slinton printf("new bp at 0x%x for event %d\n", addr, e->id); 48018218Slinton } 48118218Slinton fflush(stdout); 48218218Slinton } 4839663Slinton bplist_append(p, bplist); 4849663Slinton return p; 4859663Slinton } 4869663Slinton 4879663Slinton /* 4889663Slinton * Free all storage in the event and breakpoint tables. 4899663Slinton */ 4909663Slinton 4919663Slinton public bpfree() 4929663Slinton { 4939663Slinton register Event e; 4949663Slinton 4959663Slinton fixbps(); 4969663Slinton foreach (Event, e, eventlist) 49716609Ssam if (not delevent(e->id)) { 49816609Ssam printf("!! dbx.bpfree: can't delete event %d\n", e->id); 49916609Ssam } 5009663Slinton list_delete(list_curitem(eventlist), eventlist); 5019663Slinton endfor 5029663Slinton } 5039663Slinton 5049663Slinton /* 5059663Slinton * Determine if the program stopped at a known breakpoint 5069663Slinton * and if so do the associated commands. 5079663Slinton */ 5089663Slinton 50918218Slinton public boolean bpact() 5109663Slinton { 5119663Slinton register Breakpoint p; 51218218Slinton boolean found; 51316609Ssam integer eventId; 5149663Slinton 5159663Slinton found = false; 5169663Slinton foreach (Breakpoint, p, bplist) 5179663Slinton if (p->bpaddr == pc) { 51818218Slinton if (tracebpts) { 51918218Slinton printf("breakpoint for event %d found at location 0x%x\n", 52018218Slinton p->event->id, pc); 52118218Slinton } 5229663Slinton found = true; 52318218Slinton if (p->event->temporary) { 52418218Slinton if (not delevent(p->event->id)) { 52518218Slinton printf("!! dbx.bpact: can't find event %d\n", 52618218Slinton p->event->id); 52718218Slinton } 52818218Slinton } 5299663Slinton evalcmdlist(p->actions); 53018218Slinton if (isstopped) { 53118218Slinton eventId = p->event->id; 53218218Slinton } 53318218Slinton if (p->temporary) { 53418218Slinton list_delete(list_curitem(bplist), bplist); 53518218Slinton } 5369663Slinton } 5379663Slinton endfor 5389663Slinton if (isstopped) { 53916609Ssam if (found) { 54016609Ssam printeventid(eventId); 54116609Ssam } 5429663Slinton printstatus(); 5439663Slinton } 5449663Slinton fflush(stdout); 5459663Slinton return found; 5469663Slinton } 5479663Slinton 5489663Slinton /* 5499663Slinton * Begin single stepping and executing the given commands after each step. 5509663Slinton * If the first argument is true step by instructions, otherwise 5519663Slinton * step by source lines. 5529663Slinton * 5539663Slinton * We automatically set a breakpoint at the end of the current procedure 5549663Slinton * to turn off the given tracing. 5559663Slinton */ 5569663Slinton 5579663Slinton public traceon(inst, event, cmdlist) 55818218Slinton boolean inst; 5599663Slinton Event event; 5609663Slinton Cmdlist cmdlist; 5619663Slinton { 5629663Slinton register Trcmd trcmd; 56318218Slinton Breakpoint bp; 5649663Slinton Cmdlist actions; 56511869Slinton Address ret; 56618218Slinton Event e; 5679663Slinton 56818218Slinton if (event == nil) { 56918218Slinton e = curevent; 57018218Slinton } else { 57118218Slinton e = event; 57218218Slinton } 5739663Slinton trcmd = new(Trcmd); 57418218Slinton ++trid; 57518218Slinton trcmd->trid = trid; 57618218Slinton trcmd->event = e; 5779663Slinton trcmd->cmdlist = cmdlist; 5789663Slinton single_stepping = true; 5799663Slinton if (inst) { 5809663Slinton inst_tracing = true; 5819663Slinton list_append(list_item(trcmd), nil, eachinst); 5829663Slinton } else { 5839663Slinton list_append(list_item(trcmd), nil, eachline); 5849663Slinton } 58511869Slinton ret = return_addr(); 58611869Slinton if (ret != 0) { 58718218Slinton actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid)); 58818218Slinton bp = bp_alloc(e, (Address) ret, 0, actions); 58918218Slinton bp->temporary = true; 59011869Slinton } 59118218Slinton if (tracebpts) { 59218218Slinton printf("adding trace %d for event %d\n", trcmd->trid, e->id); 59318218Slinton } 5949663Slinton } 5959663Slinton 5969663Slinton /* 5979663Slinton * Turn off some kind of tracing. 5989663Slinton * Strictly an internal command, this cannot be invoked by the user. 5999663Slinton */ 6009663Slinton 6019663Slinton public traceoff(id) 6029663Slinton Integer id; 6039663Slinton { 6049663Slinton register Trcmd t; 60518218Slinton register boolean found; 6069663Slinton 6079663Slinton found = false; 6089663Slinton foreach (Trcmd, t, eachline) 6099663Slinton if (t->trid == id) { 6109663Slinton printrmtr(t); 6119663Slinton list_delete(list_curitem(eachline), eachline); 6129663Slinton found = true; 6139663Slinton break; 6149663Slinton } 6159663Slinton endfor 6169663Slinton if (not found) { 6179663Slinton foreach (Trcmd, t, eachinst) 6189663Slinton if (t->event->id == id) { 6199663Slinton printrmtr(t); 6209663Slinton list_delete(list_curitem(eachinst), eachinst); 6219663Slinton found = true; 6229663Slinton break; 6239663Slinton } 6249663Slinton endfor 6259663Slinton if (not found) { 62618218Slinton beginerrmsg(); 62718218Slinton fprintf(stderr, "[internal error: trace id %d not found]\n", id); 6289663Slinton } 6299663Slinton } 6309663Slinton if (list_size(eachinst) == 0) { 6319663Slinton inst_tracing = false; 6329663Slinton if (list_size(eachline) == 0) { 6339663Slinton single_stepping = false; 6349663Slinton } 6359663Slinton } 6369663Slinton } 6379663Slinton 6389663Slinton /* 6399663Slinton * If breakpoints are being traced, note that a Trcmd is being deleted. 6409663Slinton */ 6419663Slinton 6429663Slinton private printrmtr(t) 6439663Slinton Trcmd t; 6449663Slinton { 64518218Slinton if (tracebpts) { 64618218Slinton printf("removing trace %d", t->trid); 64718218Slinton if (t->event != nil) { 64818218Slinton printf(" for event %d", t->event->id); 64918218Slinton } 65018218Slinton printf("\n"); 6519663Slinton } 6529663Slinton } 6539663Slinton 6549663Slinton /* 6559663Slinton * Print out news during single step tracing. 6569663Slinton */ 6579663Slinton 6589663Slinton public printnews() 6599663Slinton { 6609663Slinton register Trcmd t; 6619663Slinton 6629663Slinton foreach (Trcmd, t, eachline) 6639663Slinton evalcmdlist(t->cmdlist); 6649663Slinton endfor 6659663Slinton foreach (Trcmd, t, eachinst) 6669663Slinton evalcmdlist(t->cmdlist); 6679663Slinton endfor 6689663Slinton bpact(); 6699663Slinton } 6709663Slinton 6719663Slinton /* 6729663Slinton * A procedure call/return has occurred while single-stepping, 6739663Slinton * note it if we're tracing lines. 6749663Slinton */ 6759663Slinton 67618218Slinton private boolean chklist(); 6779663Slinton 6789663Slinton public callnews(iscall) 67918218Slinton boolean iscall; 6809663Slinton { 6819663Slinton if (not chklist(eachline, iscall)) { 6829663Slinton chklist(eachinst, iscall); 6839663Slinton } 6849663Slinton } 6859663Slinton 68618218Slinton private boolean chklist(list, iscall) 6879663Slinton List list; 68818218Slinton boolean iscall; 6899663Slinton { 6909663Slinton register Trcmd t; 6919663Slinton register Command cmd; 6929663Slinton 69316609Ssam setcurfunc(whatblock(pc)); 6949663Slinton foreach (Trcmd, t, list) 6959663Slinton foreach (Command, cmd, t->cmdlist) 6969663Slinton if (cmd->op == O_PRINTSRCPOS and 6979663Slinton (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) { 6989663Slinton if (iscall) { 6999663Slinton printentry(curfunc); 7009663Slinton } else { 7019663Slinton printexit(curfunc); 7029663Slinton } 7039663Slinton return true; 7049663Slinton } 7059663Slinton endfor 7069663Slinton endfor 7079663Slinton return false; 7089663Slinton } 7099663Slinton 7109663Slinton /* 7119663Slinton * List of variables being watched. 7129663Slinton */ 7139663Slinton 7149663Slinton typedef struct Trinfo *Trinfo; 7159663Slinton 7169663Slinton struct Trinfo { 7179663Slinton Node variable; 7189663Slinton Address traddr; 7199663Slinton Symbol trblock; 7209663Slinton char *trvalue; 7219663Slinton }; 7229663Slinton 7239663Slinton private List trinfolist; 7249663Slinton 7259663Slinton /* 7269663Slinton * Find the trace information record associated with the given record. 7279663Slinton * If there isn't one then create it and add it to the list. 7289663Slinton */ 7299663Slinton 7309663Slinton private Trinfo findtrinfo(p) 7319663Slinton Node p; 7329663Slinton { 7339663Slinton register Trinfo tp; 73418218Slinton boolean isnew; 7359663Slinton 7369663Slinton isnew = true; 7379663Slinton if (trinfolist == nil) { 7389663Slinton trinfolist = list_alloc(); 7399663Slinton } else { 7409663Slinton foreach (Trinfo, tp, trinfolist) 7419663Slinton if (tp->variable == p) { 7429663Slinton isnew = false; 7439663Slinton break; 7449663Slinton } 7459663Slinton endfor 7469663Slinton } 7479663Slinton if (isnew) { 7489663Slinton if (tracebpts) { 7499663Slinton printf("adding trinfo for \""); 7509663Slinton prtree(stdout, p); 7519663Slinton printf("\"\n"); 7529663Slinton } 7539663Slinton tp = new(Trinfo); 7549663Slinton tp->variable = p; 7559663Slinton tp->traddr = lval(p); 7569663Slinton tp->trvalue = nil; 7579663Slinton list_append(list_item(tp), nil, trinfolist); 7589663Slinton } 7599663Slinton return tp; 7609663Slinton } 7619663Slinton 7629663Slinton /* 7639663Slinton * Print out the value of a variable if it has changed since the 7649663Slinton * last time we checked. 7659663Slinton */ 7669663Slinton 7679663Slinton public printifchanged(p) 7689663Slinton Node p; 7699663Slinton { 7709663Slinton register Trinfo tp; 7719663Slinton register int n; 7729663Slinton char buff[MAXTRSIZE]; 77318218Slinton Filename curfile; 7749663Slinton static Lineno prevline; 77518218Slinton static Filename prevfile; 7769663Slinton 7779663Slinton tp = findtrinfo(p); 7789663Slinton n = size(p->nodetype); 77918218Slinton dread(buff, tp->traddr, n); 78018218Slinton curfile = srcfilename(pc); 7819663Slinton if (tp->trvalue == nil) { 7829663Slinton tp->trvalue = newarr(char, n); 7839663Slinton mov(buff, tp->trvalue, n); 7849663Slinton mov(buff, sp, n); 7859663Slinton sp += n; 78618218Slinton printf("initially (at line %d in \"%s\"):\t", curline, curfile); 7879663Slinton prtree(stdout, p); 7889663Slinton printf(" = "); 7899663Slinton printval(p->nodetype); 7909663Slinton putchar('\n'); 7919663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 7929663Slinton mov(buff, tp->trvalue, n); 7939663Slinton mov(buff, sp, n); 7949663Slinton sp += n; 79518218Slinton printf("after line %d in \"%s\":\t", prevline, prevfile); 7969663Slinton prtree(stdout, p); 7979663Slinton printf(" = "); 7989663Slinton printval(p->nodetype); 7999663Slinton putchar('\n'); 8009663Slinton } 8019663Slinton prevline = curline; 80218218Slinton prevfile = curfile; 8039663Slinton } 8049663Slinton 8059663Slinton /* 8069663Slinton * Stop if the value of the given expression has changed. 8079663Slinton */ 8089663Slinton 8099663Slinton public stopifchanged(p) 8109663Slinton Node p; 8119663Slinton { 8129663Slinton register Trinfo tp; 8139663Slinton register int n; 8149663Slinton char buff[MAXTRSIZE]; 8159663Slinton static Lineno prevline; 8169663Slinton 8179663Slinton tp = findtrinfo(p); 8189663Slinton n = size(p->nodetype); 8199663Slinton dread(buff, tp->traddr, n); 8209663Slinton if (tp->trvalue == nil) { 8219663Slinton tp->trvalue = newarr(char, n); 8229663Slinton mov(buff, tp->trvalue, n); 8239663Slinton isstopped = true; 8249663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 8259663Slinton mov(buff, tp->trvalue, n); 82616609Ssam mov(buff, sp, n); 82716609Ssam sp += n; 82816609Ssam printf("after line %d:\t", prevline); 82916609Ssam prtree(stdout, p); 83016609Ssam printf(" = "); 83116609Ssam printval(p->nodetype); 83216609Ssam putchar('\n'); 8339663Slinton isstopped = true; 8349663Slinton } 8359663Slinton prevline = curline; 8369663Slinton } 8379663Slinton 8389663Slinton /* 8399663Slinton * Free the tracing table. 8409663Slinton */ 8419663Slinton 8429663Slinton public trfree() 8439663Slinton { 8449663Slinton register Trinfo tp; 8459663Slinton 8469663Slinton foreach (Trinfo, tp, trinfolist) 8479663Slinton dispose(tp->trvalue); 8489663Slinton dispose(tp); 8499663Slinton list_delete(list_curitem(trinfolist), trinfolist); 8509663Slinton endfor 8519663Slinton } 8529663Slinton 8539663Slinton /* 8549663Slinton * Fix up breakpoint information before continuing execution. 8559663Slinton * 8569663Slinton * It's necessary to destroy events and breakpoints that were created 8579663Slinton * temporarily and still exist because the program terminated abnormally. 8589663Slinton */ 8599663Slinton 8609663Slinton public fixbps() 8619663Slinton { 8629663Slinton register Event e; 8639663Slinton register Trcmd t; 8649663Slinton 8659663Slinton single_stepping = false; 8669663Slinton inst_tracing = false; 8679663Slinton trfree(); 8689663Slinton foreach (Event, e, eventlist) 8699663Slinton if (e->temporary) { 87016609Ssam if (not delevent(e->id)) { 87116609Ssam printf("!! dbx.fixbps: can't find event %d\n", e->id); 87216609Ssam } 8739663Slinton } 8749663Slinton endfor 8759663Slinton foreach (Trcmd, t, eachline) 8769663Slinton printrmtr(t); 8779663Slinton list_delete(list_curitem(eachline), eachline); 8789663Slinton endfor 8799663Slinton foreach (Trcmd, t, eachinst) 8809663Slinton printrmtr(t); 8819663Slinton list_delete(list_curitem(eachinst), eachinst); 8829663Slinton endfor 8839663Slinton } 8849663Slinton 8859663Slinton /* 8869663Slinton * Set all breakpoints in object code. 8879663Slinton */ 8889663Slinton 8899663Slinton public setallbps() 8909663Slinton { 8919663Slinton register Breakpoint p; 8929663Slinton 8939663Slinton foreach (Breakpoint, p, bplist) 8949663Slinton setbp(p->bpaddr); 8959663Slinton endfor 8969663Slinton } 8979663Slinton 8989663Slinton /* 8999663Slinton * Undo damage done by "setallbps". 9009663Slinton */ 9019663Slinton 9029663Slinton public unsetallbps() 9039663Slinton { 9049663Slinton register Breakpoint p; 9059663Slinton 9069663Slinton foreach (Breakpoint, p, bplist) 9079663Slinton unsetbp(p->bpaddr); 9089663Slinton endfor 9099663Slinton } 910