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