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