/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)tracestop.c 5.1 (Berkeley) 6/6/85"; #endif not lint /* * Handle trace and stop commands. */ #include "defs.h" #include "breakpoint.h" #include "sym.h" #include "tree.h" #include "runtime.h" #include "source.h" #include "object.h" #include "mappings.h" #include "machine.h" #include "tree.rep" LOCAL SYM *tcontainer(); /* * Process a trace/untrace command, basically checking arguments * and translate to a call of the appropriate routine. */ trace(cmd, exp, where, cond) int cmd; NODE *exp; NODE *where; NODE *cond; { if (exp == NIL) { traceall(cmd, where, cond); } else if (exp->op == O_LCON || exp->op == O_QLINE) { traceinst(cmd, exp, where, cond); } else if (where!=NIL && (where->op==O_QLINE || where->op==O_LCON)) { traceat(cmd, exp, where, cond); } else { tracedata(cmd, exp, where, cond); } if (where != NIL) { tfree(where); } } /* * Set a breakpoint that will turn on tracing. * * A line number of 0 in the breakpoint information structure * means it's a normal trace. * * A line number of -1 indicates that we want to trace at the instruction * rather than source line level. * * If location is NIL, turn on tracing because if the user * has the program stopped somewhere and says "trace", * he/she wants to see tracing after continuing execution. */ LOCAL traceall(cmd, where, cond) int cmd; NODE *where; NODE *cond; { SYM *s; LINENO line; if (where != NIL && where->op != O_NAME) { error("bad location for trace"); } if (cmd == O_TRACE) { line = 0; } else { line = -1; } if (where == NIL) { switch (cmd) { case O_TRACE: if (tracing != 0) { error("already tracing lines"); } tracing++; addcond(TRPRINT, cond); break; case O_TRACEI: if (inst_tracing != 0) { error("already tracing instructions"); } inst_tracing++; addcond(TRPRINT, cond); break; default: panic("bad cmd in traceall"); break; } s = program; } else if (where->op != O_NAME) { trerror("found %t, expected procedure or function", where); } else { s = where->nameval; if (!isblock(s)) { error("\"%s\" is not a procedure or function", name(s)); } } addbp(codeloc(s), ALL_ON, s, cond, NIL, line); } /* * Set up the appropriate breakpoint for tracing an instruction. */ LOCAL traceinst(cmd, exp, where, cond) int cmd; NODE *exp; NODE *where; NODE *cond; { LINENO line; ADDRESS addr; if (where != NIL) { error("unexpected \"at\" or \"in\""); } if (cmd == O_TRACEI) { if (exp->op == O_QLINE) { addr = (ADDRESS) exp->right->lconval; } else if (exp->op == O_LCON) { addr = (ADDRESS) exp->lconval; } else { trerror("expected integer constant, found %t", exp); } line = -1; } else { if (exp->op == O_QLINE) { line = (LINENO) exp->right->lconval; addr = objaddr(line, exp->left->sconval); } else { line = (LINENO) exp->lconval; addr = objaddr(line, cursource); } if (addr == (ADDRESS) -1) { error("can't trace line %d", line); } } tfree(exp); addbp(addr, INST, NIL, cond, NIL, line); } /* * set a breakpoint to print an expression at a given line or address */ LOCAL traceat(cmd, exp, where, cond) int cmd; NODE *exp; NODE *where; NODE *cond; { LINENO line; ADDRESS addr; if (cmd == O_TRACEI) { if (where->op != O_LCON) { trerror("expected integer constant, found %t", where); } line = -1; addr = (ADDRESS) where->lconval; } else { line = (LINENO) where->right->lconval; addr = objaddr(line, where->left->sconval); if (addr == (ADDRESS) -1) { error("can't trace at line %d", line); } } addbp(addr, AT_BP, NIL, cond, exp, line); } /* * Set up breakpoint for tracing data. * * The tracing of blocks lies somewhere between instruction and data; * it's here since a block cannot be distinguished from other terms. * * As in "traceall", if the "block" is the main program then the * user didn't actually specify a block. This means we want to * turn tracing on ourselves because if the program is stopped * we want to be on regardless of whether they say "cont" or "run". */ LOCAL tracedata(cmd, exp, block, cond) int cmd; NODE *exp; NODE *block; NODE *cond; { SYM *s, *t; if (exp->op != O_RVAL && exp->op != O_CALL) { error("can't trace expressions"); } if (block == NIL) { t = tcontainer(exp->left); } else if (block->op == O_NAME) { t = block->nameval; } else { trerror("found %t, expected procedure or function", block); } if (exp->left->op == O_NAME) { s = exp->left->nameval; if (isblock(s)) { addbp(codeloc(t), BLOCK_ON, t, cond, exp->left, 0); if (t == program) { addbp(codeloc(s), CALL, s, cond, NIL, 0); } return; } } addbp(codeloc(t), TERM_ON, t, cond, exp, 0); if (curfunc == t) { var_tracing++; addvar(TRPRINT, exp, cond); addbp(return_addr(), TERM_OFF, t, cond, exp, 0); } } /* * Setting and unsetting of stops. */ stop(cmd, exp, where, cond) int cmd; NODE *exp; NODE *where; NODE *cond; { SYM *s; LINENO n; if (exp != NIL) { stopvar(cmd, exp, where, cond); } else if (cond != NIL) { if (where == NIL) { s = program; } else if (where->op == O_NAME) { s = where->nameval; } else { error("bad location for stop"); } n = codeloc(s); addbp(n, STOP_ON, s, cond, NIL, n); addcond(TRSTOP, cond); var_tracing++; } else if (where->op == O_NAME) { s = where->nameval; if (!isblock(s)) { error("\"%s\" is not a procedure or function", name(s)); } n = codeloc(s); addbp(n, STOP_BP, s, cond, NIL, srcline(firstline(s))); } else { stopinst(cmd, where, cond); } if (where != NIL) { tfree(where); } } LOCAL stopinst(cmd, where, cond) int cmd; NODE *where; NODE *cond; { LINENO line; ADDRESS addr; if (where->op != O_QLINE) { error("expected line number"); } if (cmd == O_STOP) { line = (LINENO) where->right->lconval; addr = objaddr(line, where->left->sconval); if (addr == (ADDRESS) -1) { error("can't stop at that line"); } } else { line = -1; addr = (ADDRESS) where->right->lconval; } addbp(addr, STOP_BP, NIL, cond, NIL, line); } /* * Implement stopping on assignment to a variable by adding it to * the variable list. */ LOCAL stopvar(cmd, exp, where, cond) int cmd; NODE *exp; NODE *where; NODE *cond; { SYM *s; if (exp->op != O_RVAL) { trerror("found %t, expected variable", exp); } if (cmd == O_STOPI) { inst_tracing++; } var_tracing++; addvar(TRSTOP, exp, cond); if (where == NIL) { s = program; } else if (where->op == O_NAME) { s = where->nameval; } else { error("bad location for stop"); } addbp(codeloc(s), STOP_ON, s, cond, exp, 0); } /* * Figure out the block that contains the symbols * in the given variable expression. */ LOCAL SYM *tcontainer(var) NODE *var; { NODE *p; p = var; while (p->op != O_NAME) { if (isleaf(p->op)) { panic("unexpected op %d in tcontainer", p->op); /* NOTREACHED */ } p = p->left; } return container(p->nameval); }