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) 04/06/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 } 355