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: }