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