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