|
|
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.1 (Berkeley) 6/6/85"; ! 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: if (exp->op != O_RVAL && exp->op != O_CALL) { ! 208: error("can't trace expressions"); ! 209: } ! 210: if (block == NIL) { ! 211: t = tcontainer(exp->left); ! 212: } else if (block->op == O_NAME) { ! 213: t = block->nameval; ! 214: } else { ! 215: trerror("found %t, expected procedure or function", block); ! 216: } ! 217: if (exp->left->op == O_NAME) { ! 218: s = exp->left->nameval; ! 219: if (isblock(s)) { ! 220: addbp(codeloc(t), BLOCK_ON, t, cond, exp->left, 0); ! 221: if (t == program) { ! 222: addbp(codeloc(s), CALL, s, cond, NIL, 0); ! 223: } ! 224: return; ! 225: } ! 226: } ! 227: addbp(codeloc(t), TERM_ON, t, cond, exp, 0); ! 228: if (curfunc == t) { ! 229: var_tracing++; ! 230: addvar(TRPRINT, exp, cond); ! 231: addbp(return_addr(), TERM_OFF, t, cond, exp, 0); ! 232: } ! 233: } ! 234: ! 235: /* ! 236: * Setting and unsetting of stops. ! 237: */ ! 238: ! 239: stop(cmd, exp, where, cond) ! 240: int cmd; ! 241: NODE *exp; ! 242: NODE *where; ! 243: NODE *cond; ! 244: { ! 245: SYM *s; ! 246: LINENO n; ! 247: ! 248: if (exp != NIL) { ! 249: stopvar(cmd, exp, where, cond); ! 250: } else if (cond != NIL) { ! 251: if (where == NIL) { ! 252: s = program; ! 253: } else if (where->op == O_NAME) { ! 254: s = where->nameval; ! 255: } else { ! 256: error("bad location for stop"); ! 257: } ! 258: n = codeloc(s); ! 259: addbp(n, STOP_ON, s, cond, NIL, n); ! 260: addcond(TRSTOP, cond); ! 261: var_tracing++; ! 262: } else if (where->op == O_NAME) { ! 263: s = where->nameval; ! 264: if (!isblock(s)) { ! 265: error("\"%s\" is not a procedure or function", name(s)); ! 266: } ! 267: n = codeloc(s); ! 268: addbp(n, STOP_BP, s, cond, NIL, srcline(firstline(s))); ! 269: } else { ! 270: stopinst(cmd, where, cond); ! 271: } ! 272: if (where != NIL) { ! 273: tfree(where); ! 274: } ! 275: } ! 276: ! 277: LOCAL stopinst(cmd, where, cond) ! 278: int cmd; ! 279: NODE *where; ! 280: NODE *cond; ! 281: { ! 282: LINENO line; ! 283: ADDRESS addr; ! 284: ! 285: if (where->op != O_QLINE) { ! 286: error("expected line number"); ! 287: } ! 288: if (cmd == O_STOP) { ! 289: line = (LINENO) where->right->lconval; ! 290: addr = objaddr(line, where->left->sconval); ! 291: if (addr == (ADDRESS) -1) { ! 292: error("can't stop at that line"); ! 293: } ! 294: } else { ! 295: line = -1; ! 296: addr = (ADDRESS) where->right->lconval; ! 297: } ! 298: addbp(addr, STOP_BP, NIL, cond, NIL, line); ! 299: } ! 300: ! 301: /* ! 302: * Implement stopping on assignment to a variable by adding it to ! 303: * the variable list. ! 304: */ ! 305: ! 306: LOCAL stopvar(cmd, exp, where, cond) ! 307: int cmd; ! 308: NODE *exp; ! 309: NODE *where; ! 310: NODE *cond; ! 311: { ! 312: SYM *s; ! 313: ! 314: if (exp->op != O_RVAL) { ! 315: trerror("found %t, expected variable", exp); ! 316: } ! 317: if (cmd == O_STOPI) { ! 318: inst_tracing++; ! 319: } ! 320: var_tracing++; ! 321: addvar(TRSTOP, exp, cond); ! 322: if (where == NIL) { ! 323: s = program; ! 324: } else if (where->op == O_NAME) { ! 325: s = where->nameval; ! 326: } else { ! 327: error("bad location for stop"); ! 328: } ! 329: addbp(codeloc(s), STOP_ON, s, cond, exp, 0); ! 330: } ! 331: ! 332: /* ! 333: * Figure out the block that contains the symbols ! 334: * in the given variable expression. ! 335: */ ! 336: ! 337: LOCAL SYM *tcontainer(var) ! 338: NODE *var; ! 339: { ! 340: NODE *p; ! 341: ! 342: p = var; ! 343: while (p->op != O_NAME) { ! 344: if (isleaf(p->op)) { ! 345: panic("unexpected op %d in tcontainer", p->op); ! 346: /* NOTREACHED */ ! 347: } ! 348: p = p->left; ! 349: } ! 350: return container(p->nameval); ! 351: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.