|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char sccsid[] = "@(#)tracestop.c 5.2 (Berkeley) 4/6/87"; ! 9: #endif not lint ! 10: ! 11: /* ! 12: * Handle trace and stop commands. ! 13: */ ! 14: ! 15: #include "defs.h" ! 16: #include "breakpoint.h" ! 17: #include "sym.h" ! 18: #include "tree.h" ! 19: #include "runtime.h" ! 20: #include "source.h" ! 21: #include "object.h" ! 22: #include "mappings.h" ! 23: #include "machine.h" ! 24: #include "tree.rep" ! 25: ! 26: LOCAL SYM *tcontainer(); ! 27: ! 28: /* ! 29: * Process a trace/untrace command, basically checking arguments ! 30: * and translate to a call of the appropriate routine. ! 31: */ ! 32: ! 33: trace(cmd, exp, where, cond) ! 34: int cmd; ! 35: NODE *exp; ! 36: NODE *where; ! 37: NODE *cond; ! 38: { ! 39: if (exp == NIL) { ! 40: traceall(cmd, where, cond); ! 41: } else if (exp->op == O_LCON || exp->op == O_QLINE) { ! 42: traceinst(cmd, exp, where, cond); ! 43: } else if (where!=NIL && (where->op==O_QLINE || where->op==O_LCON)) { ! 44: traceat(cmd, exp, where, cond); ! 45: } else { ! 46: tracedata(cmd, exp, where, cond); ! 47: } ! 48: if (where != NIL) { ! 49: tfree(where); ! 50: } ! 51: } ! 52: ! 53: /* ! 54: * Set a breakpoint that will turn on tracing. ! 55: * ! 56: * A line number of 0 in the breakpoint information structure ! 57: * means it's a normal trace. ! 58: * ! 59: * A line number of -1 indicates that we want to trace at the instruction ! 60: * rather than source line level. ! 61: * ! 62: * If location is NIL, turn on tracing because if the user ! 63: * has the program stopped somewhere and says "trace", ! 64: * he/she wants to see tracing after continuing execution. ! 65: */ ! 66: ! 67: LOCAL traceall(cmd, where, cond) ! 68: int cmd; ! 69: NODE *where; ! 70: NODE *cond; ! 71: { ! 72: SYM *s; ! 73: LINENO line; ! 74: ! 75: if (where != NIL && where->op != O_NAME) { ! 76: error("bad location for trace"); ! 77: } ! 78: if (cmd == O_TRACE) { ! 79: line = 0; ! 80: } else { ! 81: line = -1; ! 82: } ! 83: if (where == NIL) { ! 84: switch (cmd) { ! 85: case O_TRACE: ! 86: if (tracing != 0) { ! 87: error("already tracing lines"); ! 88: } ! 89: tracing++; ! 90: addcond(TRPRINT, cond); ! 91: break; ! 92: ! 93: case O_TRACEI: ! 94: if (inst_tracing != 0) { ! 95: error("already tracing instructions"); ! 96: } ! 97: inst_tracing++; ! 98: addcond(TRPRINT, cond); ! 99: break; ! 100: ! 101: default: ! 102: panic("bad cmd in traceall"); ! 103: break; ! 104: } ! 105: s = program; ! 106: } else if (where->op != O_NAME) { ! 107: trerror("found %t, expected procedure or function", where); ! 108: } else { ! 109: s = where->nameval; ! 110: if (!isblock(s)) { ! 111: error("\"%s\" is not a procedure or function", name(s)); ! 112: } ! 113: } ! 114: addbp(codeloc(s), ALL_ON, s, cond, NIL, line); ! 115: } ! 116: ! 117: /* ! 118: * Set up the appropriate breakpoint for tracing an instruction. ! 119: */ ! 120: ! 121: LOCAL traceinst(cmd, exp, where, cond) ! 122: int cmd; ! 123: NODE *exp; ! 124: NODE *where; ! 125: NODE *cond; ! 126: { ! 127: LINENO line; ! 128: ADDRESS addr; ! 129: ! 130: if (where != NIL) { ! 131: error("unexpected \"at\" or \"in\""); ! 132: } ! 133: if (cmd == O_TRACEI) { ! 134: if (exp->op == O_QLINE) { ! 135: addr = (ADDRESS) exp->right->lconval; ! 136: } else if (exp->op == O_LCON) { ! 137: addr = (ADDRESS) exp->lconval; ! 138: } else { ! 139: trerror("expected integer constant, found %t", exp); ! 140: } ! 141: line = -1; ! 142: } else { ! 143: if (exp->op == O_QLINE) { ! 144: line = (LINENO) exp->right->lconval; ! 145: addr = objaddr(line, exp->left->sconval); ! 146: } else { ! 147: line = (LINENO) exp->lconval; ! 148: addr = objaddr(line, cursource); ! 149: } ! 150: if (addr == (ADDRESS) -1) { ! 151: error("can't trace line %d", line); ! 152: } ! 153: } ! 154: tfree(exp); ! 155: addbp(addr, INST, NIL, cond, NIL, line); ! 156: } ! 157: ! 158: /* ! 159: * set a breakpoint to print an expression at a given line or address ! 160: */ ! 161: ! 162: LOCAL traceat(cmd, exp, where, cond) ! 163: int cmd; ! 164: NODE *exp; ! 165: NODE *where; ! 166: NODE *cond; ! 167: { ! 168: LINENO line; ! 169: ADDRESS addr; ! 170: ! 171: if (cmd == O_TRACEI) { ! 172: if (where->op != O_LCON) { ! 173: trerror("expected integer constant, found %t", where); ! 174: } ! 175: line = -1; ! 176: addr = (ADDRESS) where->lconval; ! 177: } else { ! 178: line = (LINENO) where->right->lconval; ! 179: addr = objaddr(line, where->left->sconval); ! 180: if (addr == (ADDRESS) -1) { ! 181: error("can't trace at line %d", line); ! 182: } ! 183: } ! 184: addbp(addr, AT_BP, NIL, cond, exp, line); ! 185: } ! 186: ! 187: /* ! 188: * Set up breakpoint for tracing data. ! 189: * ! 190: * The tracing of blocks lies somewhere between instruction and data; ! 191: * it's here since a block cannot be distinguished from other terms. ! 192: * ! 193: * As in "traceall", if the "block" is the main program then the ! 194: * user didn't actually specify a block. This means we want to ! 195: * turn tracing on ourselves because if the program is stopped ! 196: * we want to be on regardless of whether they say "cont" or "run". ! 197: */ ! 198: ! 199: LOCAL tracedata(cmd, exp, block, cond) ! 200: int cmd; ! 201: NODE *exp; ! 202: NODE *block; ! 203: NODE *cond; ! 204: { ! 205: SYM *s, *t; ! 206: ! 207: #ifdef lint ! 208: cmd = cmd; ! 209: #endif ! 210: if (exp->op != O_RVAL && exp->op != O_CALL) { ! 211: error("can't trace expressions"); ! 212: } ! 213: if (block == NIL) { ! 214: t = tcontainer(exp->left); ! 215: } else if (block->op == O_NAME) { ! 216: t = block->nameval; ! 217: } else { ! 218: trerror("found %t, expected procedure or function", block); ! 219: } ! 220: if (exp->left->op == O_NAME) { ! 221: s = exp->left->nameval; ! 222: if (isblock(s)) { ! 223: addbp(codeloc(t), BLOCK_ON, t, cond, exp->left, 0); ! 224: if (t == program) { ! 225: addbp(codeloc(s), CALL, s, cond, NIL, 0); ! 226: } ! 227: return; ! 228: } ! 229: } ! 230: addbp(codeloc(t), TERM_ON, t, cond, exp, 0); ! 231: if (curfunc == t) { ! 232: var_tracing++; ! 233: addvar(TRPRINT, exp, cond); ! 234: addbp(return_addr(), TERM_OFF, t, cond, exp, 0); ! 235: } ! 236: } ! 237: ! 238: /* ! 239: * Setting and unsetting of stops. ! 240: */ ! 241: ! 242: stop(cmd, exp, where, cond) ! 243: int cmd; ! 244: NODE *exp; ! 245: NODE *where; ! 246: NODE *cond; ! 247: { ! 248: SYM *s; ! 249: LINENO n; ! 250: ! 251: if (exp != NIL) { ! 252: stopvar(cmd, exp, where, cond); ! 253: } else if (cond != NIL) { ! 254: if (where == NIL) { ! 255: s = program; ! 256: } else if (where->op == O_NAME) { ! 257: s = where->nameval; ! 258: } else { ! 259: error("bad location for stop"); ! 260: } ! 261: n = codeloc(s); ! 262: addbp(n, STOP_ON, s, cond, NIL, n); ! 263: addcond(TRSTOP, cond); ! 264: var_tracing++; ! 265: } else if (where->op == O_NAME) { ! 266: s = where->nameval; ! 267: if (!isblock(s)) { ! 268: error("\"%s\" is not a procedure or function", name(s)); ! 269: } ! 270: n = codeloc(s); ! 271: addbp(n, STOP_BP, s, cond, NIL, srcline(firstline(s))); ! 272: } else { ! 273: stopinst(cmd, where, cond); ! 274: } ! 275: if (where != NIL) { ! 276: tfree(where); ! 277: } ! 278: } ! 279: ! 280: LOCAL stopinst(cmd, where, cond) ! 281: int cmd; ! 282: NODE *where; ! 283: NODE *cond; ! 284: { ! 285: LINENO line; ! 286: ADDRESS addr; ! 287: ! 288: if (where->op != O_QLINE) { ! 289: error("expected line number"); ! 290: } ! 291: if (cmd == O_STOP) { ! 292: line = (LINENO) where->right->lconval; ! 293: addr = objaddr(line, where->left->sconval); ! 294: if (addr == (ADDRESS) -1) { ! 295: error("can't stop at that line"); ! 296: } ! 297: } else { ! 298: line = -1; ! 299: addr = (ADDRESS) where->right->lconval; ! 300: } ! 301: addbp(addr, STOP_BP, NIL, cond, NIL, line); ! 302: } ! 303: ! 304: /* ! 305: * Implement stopping on assignment to a variable by adding it to ! 306: * the variable list. ! 307: */ ! 308: ! 309: LOCAL stopvar(cmd, exp, where, cond) ! 310: int cmd; ! 311: NODE *exp; ! 312: NODE *where; ! 313: NODE *cond; ! 314: { ! 315: SYM *s; ! 316: ! 317: if (exp->op != O_RVAL) { ! 318: trerror("found %t, expected variable", exp); ! 319: } ! 320: if (cmd == O_STOPI) { ! 321: inst_tracing++; ! 322: } ! 323: var_tracing++; ! 324: addvar(TRSTOP, exp, cond); ! 325: if (where == NIL) { ! 326: s = program; ! 327: } else if (where->op == O_NAME) { ! 328: s = where->nameval; ! 329: } else { ! 330: error("bad location for stop"); ! 331: } ! 332: addbp(codeloc(s), STOP_ON, s, cond, exp, 0); ! 333: } ! 334: ! 335: /* ! 336: * Figure out the block that contains the symbols ! 337: * in the given variable expression. ! 338: */ ! 339: ! 340: LOCAL SYM *tcontainer(var) ! 341: NODE *var; ! 342: { ! 343: NODE *p; ! 344: ! 345: p = var; ! 346: while (p->op != O_NAME) { ! 347: if (isleaf(p->op)) { ! 348: panic("unexpected op %d in tcontainer", p->op); ! 349: /* NOTREACHED */ ! 350: } ! 351: p = p->left; ! 352: } ! 353: return container(p->nameval); ! 354: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.