1*9663Slinton /* Copyright (c) 1982 Regents of the University of California */ 2*9663Slinton 3*9663Slinton static char sccsid[] = "@(#)@(#)events.c 1.1 12/15/82"; 4*9663Slinton 5*9663Slinton /* 6*9663Slinton * Event/breakpoint managment. 7*9663Slinton */ 8*9663Slinton 9*9663Slinton #include "defs.h" 10*9663Slinton #include "events.h" 11*9663Slinton #include "main.h" 12*9663Slinton #include "symbols.h" 13*9663Slinton #include "tree.h" 14*9663Slinton #include "eval.h" 15*9663Slinton #include "source.h" 16*9663Slinton #include "mappings.h" 17*9663Slinton #include "process.h" 18*9663Slinton #include "machine.h" 19*9663Slinton #include "lists.h" 20*9663Slinton 21*9663Slinton #ifndef public 22*9663Slinton typedef struct Event *Event; 23*9663Slinton typedef struct Breakpoint *Breakpoint; 24*9663Slinton 25*9663Slinton Boolean inst_tracing; 26*9663Slinton Boolean single_stepping; 27*9663Slinton Boolean isstopped; 28*9663Slinton 29*9663Slinton #include "symbols.h" 30*9663Slinton 31*9663Slinton Symbol linesym; 32*9663Slinton Symbol procsym; 33*9663Slinton Symbol pcsym; 34*9663Slinton Symbol retaddrsym; 35*9663Slinton 36*9663Slinton #define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist) 37*9663Slinton #define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist) 38*9663Slinton 39*9663Slinton #endif 40*9663Slinton 41*9663Slinton struct Event { 42*9663Slinton unsigned int id; 43*9663Slinton Boolean temporary; 44*9663Slinton Node condition; 45*9663Slinton Cmdlist actions; 46*9663Slinton }; 47*9663Slinton 48*9663Slinton struct Breakpoint { 49*9663Slinton Event event; 50*9663Slinton Address bpaddr; 51*9663Slinton Lineno bpline; 52*9663Slinton Cmdlist actions; 53*9663Slinton }; 54*9663Slinton 55*9663Slinton typedef List Eventlist; 56*9663Slinton typedef List Bplist; 57*9663Slinton 58*9663Slinton #define eventlist_append(event, el) list_append(list_item(event), nil, el) 59*9663Slinton #define bplist_append(bp, bl) list_append(list_item(bp), nil, bl) 60*9663Slinton 61*9663Slinton private Eventlist eventlist; /* list of active events */ 62*9663Slinton private Bplist bplist; /* list of active breakpoints */ 63*9663Slinton private Integer eventid; /* id number of next allocated event */ 64*9663Slinton private Integer trid; /* id number of next allocated trace */ 65*9663Slinton 66*9663Slinton typedef struct Trcmd { 67*9663Slinton Integer trid; 68*9663Slinton Event event; 69*9663Slinton Cmdlist cmdlist; 70*9663Slinton } *Trcmd; 71*9663Slinton 72*9663Slinton private List eachline; /* commands to execute after each line */ 73*9663Slinton private List eachinst; /* commands to execute after each instruction */ 74*9663Slinton 75*9663Slinton private Breakpoint bp_alloc(); 76*9663Slinton 77*9663Slinton /* 78*9663Slinton * Initialize breakpoint information. 79*9663Slinton */ 80*9663Slinton 81*9663Slinton private Symbol builtinsym(str, class, type) 82*9663Slinton String str; 83*9663Slinton Symclass class; 84*9663Slinton Symbol type; 85*9663Slinton { 86*9663Slinton Symbol s; 87*9663Slinton 88*9663Slinton s = insert(identname(str, true)); 89*9663Slinton s->language = findlanguage(".s"); 90*9663Slinton s->class = class; 91*9663Slinton s->type = type; 92*9663Slinton return s; 93*9663Slinton } 94*9663Slinton 95*9663Slinton public bpinit() 96*9663Slinton { 97*9663Slinton linesym = builtinsym("$line", VAR, t_int); 98*9663Slinton procsym = builtinsym("$proc", PROC, nil); 99*9663Slinton pcsym = lookup(identname("$pc", true)); 100*9663Slinton if (pcsym == nil) { 101*9663Slinton panic("can't find $pc"); 102*9663Slinton } 103*9663Slinton retaddrsym = builtinsym("$retaddr", VAR, t_int); 104*9663Slinton eventlist = list_alloc(); 105*9663Slinton bplist = list_alloc(); 106*9663Slinton eachline = list_alloc(); 107*9663Slinton eachinst = list_alloc(); 108*9663Slinton } 109*9663Slinton 110*9663Slinton /* 111*9663Slinton * Trap an event and do the associated commands when it occurs. 112*9663Slinton */ 113*9663Slinton 114*9663Slinton public Event event_alloc(istmp, econd, cmdlist) 115*9663Slinton Boolean istmp; 116*9663Slinton Node econd; 117*9663Slinton Cmdlist cmdlist; 118*9663Slinton { 119*9663Slinton register Event e; 120*9663Slinton 121*9663Slinton e = new(Event); 122*9663Slinton ++eventid; 123*9663Slinton e->id = eventid; 124*9663Slinton e->temporary = istmp; 125*9663Slinton e->condition = econd; 126*9663Slinton e->actions = cmdlist; 127*9663Slinton eventlist_append(e, eventlist); 128*9663Slinton translate(e); 129*9663Slinton return e; 130*9663Slinton } 131*9663Slinton 132*9663Slinton /* 133*9663Slinton * Delete the event with the given id. 134*9663Slinton */ 135*9663Slinton 136*9663Slinton public delevent(id) 137*9663Slinton unsigned int id; 138*9663Slinton { 139*9663Slinton Event e; 140*9663Slinton Breakpoint bp; 141*9663Slinton Trcmd t; 142*9663Slinton 143*9663Slinton foreach (Event, e, eventlist) 144*9663Slinton if (e->id == id) { 145*9663Slinton list_delete(list_curitem(eventlist), eventlist); 146*9663Slinton foreach (Breakpoint, bp, bplist) 147*9663Slinton if (bp->event == e) { 148*9663Slinton list_delete(list_curitem(bplist), bplist); 149*9663Slinton } 150*9663Slinton endfor 151*9663Slinton break; 152*9663Slinton } 153*9663Slinton endfor 154*9663Slinton foreach (Trcmd, t, eachline) 155*9663Slinton if (t->event->id == id) { 156*9663Slinton printrmtr(t); 157*9663Slinton list_delete(list_curitem(eachline), eachline); 158*9663Slinton } 159*9663Slinton endfor 160*9663Slinton foreach (Trcmd, t, eachinst) 161*9663Slinton if (t->event->id == id) { 162*9663Slinton printrmtr(t); 163*9663Slinton list_delete(list_curitem(eachinst), eachinst); 164*9663Slinton } 165*9663Slinton endfor 166*9663Slinton if (list_size(eachinst) == 0) { 167*9663Slinton inst_tracing = false; 168*9663Slinton if (list_size(eachline) == 0) { 169*9663Slinton single_stepping = false; 170*9663Slinton } 171*9663Slinton } 172*9663Slinton } 173*9663Slinton 174*9663Slinton /* 175*9663Slinton * Translate an event into the appropriate breakpoints and actions. 176*9663Slinton * While we're at it, turn on the breakpoints if the condition is true. 177*9663Slinton */ 178*9663Slinton 179*9663Slinton private translate(e) 180*9663Slinton Event e; 181*9663Slinton { 182*9663Slinton Breakpoint bp; 183*9663Slinton Symbol s; 184*9663Slinton Node place; 185*9663Slinton Lineno line; 186*9663Slinton Address addr; 187*9663Slinton 188*9663Slinton checkref(e->condition); 189*9663Slinton switch (e->condition->op) { 190*9663Slinton case O_EQ: 191*9663Slinton if (e->condition->value.arg[0]->op == O_SYM) { 192*9663Slinton s = e->condition->value.arg[0]->value.sym; 193*9663Slinton place = e->condition->value.arg[1]; 194*9663Slinton if (s == linesym) { 195*9663Slinton if (place->op == O_QLINE) { 196*9663Slinton line = place->value.arg[1]->value.lcon; 197*9663Slinton addr = objaddr(line, 198*9663Slinton place->value.arg[0]->value.scon); 199*9663Slinton } else { 200*9663Slinton eval(place); 201*9663Slinton line = pop(long); 202*9663Slinton addr = objaddr(line, cursource); 203*9663Slinton } 204*9663Slinton if (addr == NOADDR) { 205*9663Slinton delevent(e->id); 206*9663Slinton beginerrmsg(); 207*9663Slinton fprintf(stderr, "no executable code at line "); 208*9663Slinton prtree(stderr, place); 209*9663Slinton enderrmsg(); 210*9663Slinton } 211*9663Slinton bp = bp_alloc(e, addr, line, e->actions); 212*9663Slinton } else if (s == procsym) { 213*9663Slinton eval(place); 214*9663Slinton s = pop(Symbol); 215*9663Slinton bp = bp_alloc(e, codeloc(s), 0, e->actions); 216*9663Slinton if (isactive(s) and pc != codeloc(program)) { 217*9663Slinton evalcmdlist(e->actions); 218*9663Slinton } 219*9663Slinton } else if (s == pcsym) { 220*9663Slinton eval(place); 221*9663Slinton bp = bp_alloc(e, pop(Address), 0, e->actions); 222*9663Slinton } else { 223*9663Slinton condbp(e); 224*9663Slinton } 225*9663Slinton } else { 226*9663Slinton condbp(e); 227*9663Slinton } 228*9663Slinton break; 229*9663Slinton 230*9663Slinton /* 231*9663Slinton * These should be handled specially. 232*9663Slinton * But for now I'm ignoring the problem. 233*9663Slinton */ 234*9663Slinton case O_AND: 235*9663Slinton case O_OR: 236*9663Slinton default: 237*9663Slinton condbp(e); 238*9663Slinton break; 239*9663Slinton } 240*9663Slinton } 241*9663Slinton 242*9663Slinton /* 243*9663Slinton * Create a breakpoint for a condition that cannot be pinpointed 244*9663Slinton * to happening at a particular address, but one for which we 245*9663Slinton * must single step and check the condition after each statement. 246*9663Slinton */ 247*9663Slinton 248*9663Slinton private condbp(e) 249*9663Slinton Event e; 250*9663Slinton { 251*9663Slinton Symbol p; 252*9663Slinton Breakpoint bp; 253*9663Slinton Cmdlist actions; 254*9663Slinton 255*9663Slinton p = tcontainer(e->condition); 256*9663Slinton if (p == nil) { 257*9663Slinton p = program; 258*9663Slinton } 259*9663Slinton actions = buildcmdlist(build(O_IF, e->condition, e->actions)); 260*9663Slinton actions = buildcmdlist(build(O_TRACEON, false, actions)); 261*9663Slinton bp = bp_alloc(e, codeloc(p), 0, actions); 262*9663Slinton } 263*9663Slinton 264*9663Slinton /* 265*9663Slinton * Determine the deepest nested subprogram that still contains 266*9663Slinton * all elements in the given expression. 267*9663Slinton */ 268*9663Slinton 269*9663Slinton public Symbol tcontainer(exp) 270*9663Slinton Node exp; 271*9663Slinton { 272*9663Slinton Integer i; 273*9663Slinton Symbol s, t, u, v; 274*9663Slinton 275*9663Slinton checkref(exp); 276*9663Slinton s = nil; 277*9663Slinton if (exp->op == O_SYM) { 278*9663Slinton s = container(exp->value.sym); 279*9663Slinton } else if (not isleaf(exp->op)) { 280*9663Slinton for (i = 0; i < nargs(exp->op); i++) { 281*9663Slinton t = tcontainer(exp->value.arg[i]); 282*9663Slinton if (t != nil) { 283*9663Slinton if (s == nil) { 284*9663Slinton s = t; 285*9663Slinton } else { 286*9663Slinton u = s; 287*9663Slinton v = t; 288*9663Slinton while (u != v and u != nil) { 289*9663Slinton u = container(u); 290*9663Slinton v = container(v); 291*9663Slinton } 292*9663Slinton if (u == nil) { 293*9663Slinton panic("bad ancestry for \"%s\"", symname(s)); 294*9663Slinton } else { 295*9663Slinton s = u; 296*9663Slinton } 297*9663Slinton } 298*9663Slinton } 299*9663Slinton } 300*9663Slinton } 301*9663Slinton return s; 302*9663Slinton } 303*9663Slinton 304*9663Slinton /* 305*9663Slinton * Print out what's currently being traced by looking at 306*9663Slinton * the currently active events. 307*9663Slinton * 308*9663Slinton * Some convolution here to translate internal representation 309*9663Slinton * of events back into something more palatable. 310*9663Slinton */ 311*9663Slinton 312*9663Slinton public status() 313*9663Slinton { 314*9663Slinton Event e; 315*9663Slinton Command cmd; 316*9663Slinton 317*9663Slinton foreach (Event, e, eventlist) 318*9663Slinton if (not e->temporary) { 319*9663Slinton if (not isredirected()) { 320*9663Slinton printf("(%d) ", e->id); 321*9663Slinton } 322*9663Slinton cmd = list_element(Command, list_head(e->actions)); 323*9663Slinton if (cmd->op == O_PRINTCALL) { 324*9663Slinton printf("trace "); 325*9663Slinton printname(stdout, cmd->value.sym); 326*9663Slinton } else { 327*9663Slinton if (list_size(e->actions) > 1) { 328*9663Slinton printf("{ "); 329*9663Slinton } 330*9663Slinton foreach (Command, cmd, e->actions) 331*9663Slinton printcmd(stdout, cmd); 332*9663Slinton if (not list_islast()) { 333*9663Slinton printf("; "); 334*9663Slinton } 335*9663Slinton endfor 336*9663Slinton if (list_size(e->actions) > 1) { 337*9663Slinton printf(" }"); 338*9663Slinton } 339*9663Slinton printcond(e->condition); 340*9663Slinton } 341*9663Slinton printf("\n"); 342*9663Slinton } 343*9663Slinton endfor 344*9663Slinton } 345*9663Slinton 346*9663Slinton /* 347*9663Slinton * Print out a condition. 348*9663Slinton */ 349*9663Slinton 350*9663Slinton private printcond(cond) 351*9663Slinton Node cond; 352*9663Slinton { 353*9663Slinton Symbol s; 354*9663Slinton Node place; 355*9663Slinton 356*9663Slinton if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) { 357*9663Slinton s = cond->value.arg[0]->value.sym; 358*9663Slinton place = cond->value.arg[1]; 359*9663Slinton if (s == procsym) { 360*9663Slinton if (place->value.sym != program) { 361*9663Slinton printf(" in "); 362*9663Slinton printname(stdout, place->value.sym); 363*9663Slinton } 364*9663Slinton } else if (s == linesym) { 365*9663Slinton printf(" at "); 366*9663Slinton prtree(stdout, place); 367*9663Slinton } else if (s == pcsym or s == retaddrsym) { 368*9663Slinton printf("i at "); 369*9663Slinton prtree(stdout, place); 370*9663Slinton } else { 371*9663Slinton printf(" when "); 372*9663Slinton prtree(stdout, cond); 373*9663Slinton } 374*9663Slinton } else { 375*9663Slinton printf(" when "); 376*9663Slinton prtree(stdout, cond); 377*9663Slinton } 378*9663Slinton } 379*9663Slinton 380*9663Slinton /* 381*9663Slinton * Add a breakpoint to the list and return it. 382*9663Slinton */ 383*9663Slinton 384*9663Slinton private Breakpoint bp_alloc(e, addr, line, actions) 385*9663Slinton Event e; 386*9663Slinton Address addr; 387*9663Slinton Lineno line; 388*9663Slinton Cmdlist actions; 389*9663Slinton { 390*9663Slinton register Breakpoint p; 391*9663Slinton 392*9663Slinton p = new(Breakpoint); 393*9663Slinton p->event = e; 394*9663Slinton p->bpaddr = addr; 395*9663Slinton p->bpline = line; 396*9663Slinton p->actions = actions; 397*9663Slinton if (tracebpts) { 398*9663Slinton printf("new bp at 0x%x\n", addr); 399*9663Slinton fflush(stdout); 400*9663Slinton } 401*9663Slinton bplist_append(p, bplist); 402*9663Slinton return p; 403*9663Slinton } 404*9663Slinton 405*9663Slinton /* 406*9663Slinton * Free all storage in the event and breakpoint tables. 407*9663Slinton */ 408*9663Slinton 409*9663Slinton public bpfree() 410*9663Slinton { 411*9663Slinton register Event e; 412*9663Slinton 413*9663Slinton fixbps(); 414*9663Slinton foreach (Event, e, eventlist) 415*9663Slinton delevent(e->id); 416*9663Slinton list_delete(list_curitem(eventlist), eventlist); 417*9663Slinton endfor 418*9663Slinton } 419*9663Slinton 420*9663Slinton /* 421*9663Slinton * Determine if the program stopped at a known breakpoint 422*9663Slinton * and if so do the associated commands. 423*9663Slinton */ 424*9663Slinton 425*9663Slinton public Boolean bpact() 426*9663Slinton { 427*9663Slinton register Breakpoint p; 428*9663Slinton Boolean found; 429*9663Slinton 430*9663Slinton found = false; 431*9663Slinton foreach (Breakpoint, p, bplist) 432*9663Slinton if (p->bpaddr == pc) { 433*9663Slinton if (tracebpts) { 434*9663Slinton printf("breakpoint found at location 0x%x\n", pc); 435*9663Slinton } 436*9663Slinton found = true; 437*9663Slinton if (p->event->temporary) { 438*9663Slinton delevent(p->event->id); 439*9663Slinton } 440*9663Slinton evalcmdlist(p->actions); 441*9663Slinton } 442*9663Slinton endfor 443*9663Slinton if (isstopped) { 444*9663Slinton printstatus(); 445*9663Slinton } 446*9663Slinton fflush(stdout); 447*9663Slinton return found; 448*9663Slinton } 449*9663Slinton 450*9663Slinton /* 451*9663Slinton * Begin single stepping and executing the given commands after each step. 452*9663Slinton * If the first argument is true step by instructions, otherwise 453*9663Slinton * step by source lines. 454*9663Slinton * 455*9663Slinton * We automatically set a breakpoint at the end of the current procedure 456*9663Slinton * to turn off the given tracing. 457*9663Slinton */ 458*9663Slinton 459*9663Slinton public traceon(inst, event, cmdlist) 460*9663Slinton Boolean inst; 461*9663Slinton Event event; 462*9663Slinton Cmdlist cmdlist; 463*9663Slinton { 464*9663Slinton register Trcmd trcmd; 465*9663Slinton Breakpoint bp; 466*9663Slinton Node until; 467*9663Slinton Cmdlist actions; 468*9663Slinton 469*9663Slinton trcmd = new(Trcmd); 470*9663Slinton ++trid; 471*9663Slinton trcmd->trid = trid; 472*9663Slinton trcmd->event = event; 473*9663Slinton trcmd->cmdlist = cmdlist; 474*9663Slinton single_stepping = true; 475*9663Slinton if (inst) { 476*9663Slinton inst_tracing = true; 477*9663Slinton list_append(list_item(trcmd), nil, eachinst); 478*9663Slinton } else { 479*9663Slinton list_append(list_item(trcmd), nil, eachline); 480*9663Slinton } 481*9663Slinton until = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, return_addr())); 482*9663Slinton actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid)); 483*9663Slinton event_once(until, actions); 484*9663Slinton if (tracebpts) { 485*9663Slinton printf("adding trace %d for event %d\n", trcmd->trid, event->id); 486*9663Slinton } 487*9663Slinton } 488*9663Slinton 489*9663Slinton /* 490*9663Slinton * Turn off some kind of tracing. 491*9663Slinton * Strictly an internal command, this cannot be invoked by the user. 492*9663Slinton */ 493*9663Slinton 494*9663Slinton public traceoff(id) 495*9663Slinton Integer id; 496*9663Slinton { 497*9663Slinton register Trcmd t; 498*9663Slinton register Boolean found; 499*9663Slinton 500*9663Slinton found = false; 501*9663Slinton foreach (Trcmd, t, eachline) 502*9663Slinton if (t->trid == id) { 503*9663Slinton printrmtr(t); 504*9663Slinton list_delete(list_curitem(eachline), eachline); 505*9663Slinton found = true; 506*9663Slinton break; 507*9663Slinton } 508*9663Slinton endfor 509*9663Slinton if (not found) { 510*9663Slinton foreach (Trcmd, t, eachinst) 511*9663Slinton if (t->event->id == id) { 512*9663Slinton printrmtr(t); 513*9663Slinton list_delete(list_curitem(eachinst), eachinst); 514*9663Slinton found = true; 515*9663Slinton break; 516*9663Slinton } 517*9663Slinton endfor 518*9663Slinton if (not found) { 519*9663Slinton panic("missing trid %d", id); 520*9663Slinton } 521*9663Slinton } 522*9663Slinton if (list_size(eachinst) == 0) { 523*9663Slinton inst_tracing = false; 524*9663Slinton if (list_size(eachline) == 0) { 525*9663Slinton single_stepping = false; 526*9663Slinton } 527*9663Slinton } 528*9663Slinton } 529*9663Slinton 530*9663Slinton /* 531*9663Slinton * If breakpoints are being traced, note that a Trcmd is being deleted. 532*9663Slinton */ 533*9663Slinton 534*9663Slinton private printrmtr(t) 535*9663Slinton Trcmd t; 536*9663Slinton { 537*9663Slinton if (tracebpts) { 538*9663Slinton printf("removing trace %d for event %d\n", t->trid, t->event->id); 539*9663Slinton } 540*9663Slinton } 541*9663Slinton 542*9663Slinton /* 543*9663Slinton * Print out news during single step tracing. 544*9663Slinton */ 545*9663Slinton 546*9663Slinton public printnews() 547*9663Slinton { 548*9663Slinton register Trcmd t; 549*9663Slinton 550*9663Slinton foreach (Trcmd, t, eachline) 551*9663Slinton evalcmdlist(t->cmdlist); 552*9663Slinton endfor 553*9663Slinton foreach (Trcmd, t, eachinst) 554*9663Slinton evalcmdlist(t->cmdlist); 555*9663Slinton endfor 556*9663Slinton bpact(); 557*9663Slinton } 558*9663Slinton 559*9663Slinton /* 560*9663Slinton * A procedure call/return has occurred while single-stepping, 561*9663Slinton * note it if we're tracing lines. 562*9663Slinton */ 563*9663Slinton 564*9663Slinton private Boolean chklist(); 565*9663Slinton 566*9663Slinton public callnews(iscall) 567*9663Slinton Boolean iscall; 568*9663Slinton { 569*9663Slinton if (not chklist(eachline, iscall)) { 570*9663Slinton chklist(eachinst, iscall); 571*9663Slinton } 572*9663Slinton } 573*9663Slinton 574*9663Slinton private Boolean chklist(list, iscall) 575*9663Slinton List list; 576*9663Slinton Boolean iscall; 577*9663Slinton { 578*9663Slinton register Trcmd t; 579*9663Slinton register Command cmd; 580*9663Slinton 581*9663Slinton foreach (Trcmd, t, list) 582*9663Slinton foreach (Command, cmd, t->cmdlist) 583*9663Slinton if (cmd->op == O_PRINTSRCPOS and 584*9663Slinton (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) { 585*9663Slinton curfunc = whatblock(pc); 586*9663Slinton if (iscall) { 587*9663Slinton printentry(curfunc); 588*9663Slinton } else { 589*9663Slinton printexit(curfunc); 590*9663Slinton } 591*9663Slinton return true; 592*9663Slinton } 593*9663Slinton endfor 594*9663Slinton endfor 595*9663Slinton return false; 596*9663Slinton } 597*9663Slinton 598*9663Slinton /* 599*9663Slinton * When tracing variables we keep a copy of their most recent value 600*9663Slinton * and compare it to the current one each time a breakpoint occurs. 601*9663Slinton * MAXTRSIZE is the maximum size variable we allow. 602*9663Slinton */ 603*9663Slinton 604*9663Slinton #define MAXTRSIZE 512 605*9663Slinton 606*9663Slinton /* 607*9663Slinton * List of variables being watched. 608*9663Slinton */ 609*9663Slinton 610*9663Slinton typedef struct Trinfo *Trinfo; 611*9663Slinton 612*9663Slinton struct Trinfo { 613*9663Slinton Node variable; 614*9663Slinton Address traddr; 615*9663Slinton Symbol trblock; 616*9663Slinton char *trvalue; 617*9663Slinton }; 618*9663Slinton 619*9663Slinton private List trinfolist; 620*9663Slinton 621*9663Slinton /* 622*9663Slinton * Find the trace information record associated with the given record. 623*9663Slinton * If there isn't one then create it and add it to the list. 624*9663Slinton */ 625*9663Slinton 626*9663Slinton private Trinfo findtrinfo(p) 627*9663Slinton Node p; 628*9663Slinton { 629*9663Slinton register Trinfo tp; 630*9663Slinton Boolean isnew; 631*9663Slinton 632*9663Slinton isnew = true; 633*9663Slinton if (trinfolist == nil) { 634*9663Slinton trinfolist = list_alloc(); 635*9663Slinton } else { 636*9663Slinton foreach (Trinfo, tp, trinfolist) 637*9663Slinton if (tp->variable == p) { 638*9663Slinton isnew = false; 639*9663Slinton break; 640*9663Slinton } 641*9663Slinton endfor 642*9663Slinton } 643*9663Slinton if (isnew) { 644*9663Slinton if (tracebpts) { 645*9663Slinton printf("adding trinfo for \""); 646*9663Slinton prtree(stdout, p); 647*9663Slinton printf("\"\n"); 648*9663Slinton } 649*9663Slinton tp = new(Trinfo); 650*9663Slinton tp->variable = p; 651*9663Slinton tp->traddr = lval(p); 652*9663Slinton tp->trvalue = nil; 653*9663Slinton list_append(list_item(tp), nil, trinfolist); 654*9663Slinton } 655*9663Slinton return tp; 656*9663Slinton } 657*9663Slinton 658*9663Slinton /* 659*9663Slinton * Print out the value of a variable if it has changed since the 660*9663Slinton * last time we checked. 661*9663Slinton */ 662*9663Slinton 663*9663Slinton public printifchanged(p) 664*9663Slinton Node p; 665*9663Slinton { 666*9663Slinton register Trinfo tp; 667*9663Slinton register int n; 668*9663Slinton char buff[MAXTRSIZE]; 669*9663Slinton static Lineno prevline; 670*9663Slinton 671*9663Slinton tp = findtrinfo(p); 672*9663Slinton n = size(p->nodetype); 673*9663Slinton dread(buff, tp->traddr, n); 674*9663Slinton if (tp->trvalue == nil) { 675*9663Slinton tp->trvalue = newarr(char, n); 676*9663Slinton mov(buff, tp->trvalue, n); 677*9663Slinton mov(buff, sp, n); 678*9663Slinton sp += n; 679*9663Slinton printf("initially (at line %d):\t", curline); 680*9663Slinton prtree(stdout, p); 681*9663Slinton printf(" = "); 682*9663Slinton printval(p->nodetype); 683*9663Slinton putchar('\n'); 684*9663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 685*9663Slinton mov(buff, tp->trvalue, n); 686*9663Slinton mov(buff, sp, n); 687*9663Slinton sp += n; 688*9663Slinton printf("after line %d:\t", prevline); 689*9663Slinton prtree(stdout, p); 690*9663Slinton printf(" = "); 691*9663Slinton printval(p->nodetype); 692*9663Slinton putchar('\n'); 693*9663Slinton } 694*9663Slinton prevline = curline; 695*9663Slinton } 696*9663Slinton 697*9663Slinton /* 698*9663Slinton * Stop if the value of the given expression has changed. 699*9663Slinton */ 700*9663Slinton 701*9663Slinton public stopifchanged(p) 702*9663Slinton Node p; 703*9663Slinton { 704*9663Slinton register Trinfo tp; 705*9663Slinton register int n; 706*9663Slinton char buff[MAXTRSIZE]; 707*9663Slinton static Lineno prevline; 708*9663Slinton 709*9663Slinton tp = findtrinfo(p); 710*9663Slinton n = size(p->nodetype); 711*9663Slinton dread(buff, tp->traddr, n); 712*9663Slinton if (tp->trvalue == nil) { 713*9663Slinton tp->trvalue = newarr(char, n); 714*9663Slinton mov(buff, tp->trvalue, n); 715*9663Slinton isstopped = true; 716*9663Slinton } else if (cmp(tp->trvalue, buff, n) != 0) { 717*9663Slinton mov(buff, tp->trvalue, n); 718*9663Slinton isstopped = true; 719*9663Slinton } 720*9663Slinton prevline = curline; 721*9663Slinton } 722*9663Slinton 723*9663Slinton /* 724*9663Slinton * Free the tracing table. 725*9663Slinton */ 726*9663Slinton 727*9663Slinton public trfree() 728*9663Slinton { 729*9663Slinton register Trinfo tp; 730*9663Slinton 731*9663Slinton foreach (Trinfo, tp, trinfolist) 732*9663Slinton dispose(tp->trvalue); 733*9663Slinton dispose(tp); 734*9663Slinton list_delete(list_curitem(trinfolist), trinfolist); 735*9663Slinton endfor 736*9663Slinton } 737*9663Slinton 738*9663Slinton /* 739*9663Slinton * Fix up breakpoint information before continuing execution. 740*9663Slinton * 741*9663Slinton * It's necessary to destroy events and breakpoints that were created 742*9663Slinton * temporarily and still exist because the program terminated abnormally. 743*9663Slinton */ 744*9663Slinton 745*9663Slinton public fixbps() 746*9663Slinton { 747*9663Slinton register Event e; 748*9663Slinton register Trcmd t; 749*9663Slinton 750*9663Slinton single_stepping = false; 751*9663Slinton inst_tracing = false; 752*9663Slinton trfree(); 753*9663Slinton foreach (Event, e, eventlist) 754*9663Slinton if (e->temporary) { 755*9663Slinton delevent(e->id); 756*9663Slinton } 757*9663Slinton endfor 758*9663Slinton foreach (Trcmd, t, eachline) 759*9663Slinton printrmtr(t); 760*9663Slinton list_delete(list_curitem(eachline), eachline); 761*9663Slinton endfor 762*9663Slinton foreach (Trcmd, t, eachinst) 763*9663Slinton printrmtr(t); 764*9663Slinton list_delete(list_curitem(eachinst), eachinst); 765*9663Slinton endfor 766*9663Slinton } 767*9663Slinton 768*9663Slinton /* 769*9663Slinton * Set all breakpoints in object code. 770*9663Slinton */ 771*9663Slinton 772*9663Slinton public setallbps() 773*9663Slinton { 774*9663Slinton register Breakpoint p; 775*9663Slinton 776*9663Slinton foreach (Breakpoint, p, bplist) 777*9663Slinton setbp(p->bpaddr); 778*9663Slinton endfor 779*9663Slinton } 780*9663Slinton 781*9663Slinton /* 782*9663Slinton * Undo damage done by "setallbps". 783*9663Slinton */ 784*9663Slinton 785*9663Slinton public unsetallbps() 786*9663Slinton { 787*9663Slinton register Breakpoint p; 788*9663Slinton 789*9663Slinton foreach (Breakpoint, p, bplist) 790*9663Slinton unsetbp(p->bpaddr); 791*9663Slinton endfor 792*9663Slinton } 793