148069Sbostic /*-
2*62163Sbostic * Copyright (c) 1980, 1993
3*62163Sbostic * The Regents of the University of California. All rights reserved.
448069Sbostic *
548069Sbostic * %sccs.include.redist.c%
622565Sdist */
75546Slinton
822565Sdist #ifndef lint
9*62163Sbostic static char sccsid[] = "@(#)tracestop.c 8.1 (Berkeley) 06/06/93";
1048069Sbostic #endif /* not lint */
115546Slinton
125546Slinton /*
135546Slinton * Handle trace and stop commands.
145546Slinton */
155546Slinton
165546Slinton #include "defs.h"
175546Slinton #include "breakpoint.h"
185546Slinton #include "sym.h"
195546Slinton #include "tree.h"
205546Slinton #include "runtime.h"
215546Slinton #include "source.h"
225546Slinton #include "object.h"
235546Slinton #include "mappings.h"
245546Slinton #include "machine.h"
255546Slinton #include "tree.rep"
265546Slinton
275546Slinton LOCAL SYM *tcontainer();
285546Slinton
295546Slinton /*
305546Slinton * Process a trace/untrace command, basically checking arguments
315546Slinton * and translate to a call of the appropriate routine.
325546Slinton */
335546Slinton
trace(cmd,exp,where,cond)345546Slinton trace(cmd, exp, where, cond)
355546Slinton int cmd;
365546Slinton NODE *exp;
375546Slinton NODE *where;
385546Slinton NODE *cond;
395546Slinton {
405546Slinton if (exp == NIL) {
415546Slinton traceall(cmd, where, cond);
425546Slinton } else if (exp->op == O_LCON || exp->op == O_QLINE) {
435546Slinton traceinst(cmd, exp, where, cond);
445546Slinton } else if (where!=NIL && (where->op==O_QLINE || where->op==O_LCON)) {
455546Slinton traceat(cmd, exp, where, cond);
465546Slinton } else {
475546Slinton tracedata(cmd, exp, where, cond);
485546Slinton }
495546Slinton if (where != NIL) {
505546Slinton tfree(where);
515546Slinton }
525546Slinton }
535546Slinton
545546Slinton /*
555546Slinton * Set a breakpoint that will turn on tracing.
565546Slinton *
575546Slinton * A line number of 0 in the breakpoint information structure
585546Slinton * means it's a normal trace.
595546Slinton *
605546Slinton * A line number of -1 indicates that we want to trace at the instruction
615546Slinton * rather than source line level.
625546Slinton *
635546Slinton * If location is NIL, turn on tracing because if the user
645546Slinton * has the program stopped somewhere and says "trace",
655546Slinton * he/she wants to see tracing after continuing execution.
665546Slinton */
675546Slinton
traceall(cmd,where,cond)685546Slinton LOCAL traceall(cmd, where, cond)
695546Slinton int cmd;
705546Slinton NODE *where;
715546Slinton NODE *cond;
725546Slinton {
735546Slinton SYM *s;
745546Slinton LINENO line;
755546Slinton
765546Slinton if (where != NIL && where->op != O_NAME) {
775546Slinton error("bad location for trace");
785546Slinton }
795546Slinton if (cmd == O_TRACE) {
805546Slinton line = 0;
815546Slinton } else {
825546Slinton line = -1;
835546Slinton }
845546Slinton if (where == NIL) {
855546Slinton switch (cmd) {
865546Slinton case O_TRACE:
875546Slinton if (tracing != 0) {
885546Slinton error("already tracing lines");
895546Slinton }
905546Slinton tracing++;
915546Slinton addcond(TRPRINT, cond);
925546Slinton break;
935546Slinton
945546Slinton case O_TRACEI:
955546Slinton if (inst_tracing != 0) {
965546Slinton error("already tracing instructions");
975546Slinton }
985546Slinton inst_tracing++;
995546Slinton addcond(TRPRINT, cond);
1005546Slinton break;
1015546Slinton
1025546Slinton default:
1035546Slinton panic("bad cmd in traceall");
1045546Slinton break;
1055546Slinton }
1065546Slinton s = program;
1075546Slinton } else if (where->op != O_NAME) {
1085546Slinton trerror("found %t, expected procedure or function", where);
1095546Slinton } else {
1105546Slinton s = where->nameval;
1115546Slinton if (!isblock(s)) {
1125546Slinton error("\"%s\" is not a procedure or function", name(s));
1135546Slinton }
1145546Slinton }
1155546Slinton addbp(codeloc(s), ALL_ON, s, cond, NIL, line);
1165546Slinton }
1175546Slinton
1185546Slinton /*
1195546Slinton * Set up the appropriate breakpoint for tracing an instruction.
1205546Slinton */
1215546Slinton
traceinst(cmd,exp,where,cond)1225546Slinton LOCAL traceinst(cmd, exp, where, cond)
1235546Slinton int cmd;
1245546Slinton NODE *exp;
1255546Slinton NODE *where;
1265546Slinton NODE *cond;
1275546Slinton {
1285546Slinton LINENO line;
1295546Slinton ADDRESS addr;
1305546Slinton
1315546Slinton if (where != NIL) {
1325546Slinton error("unexpected \"at\" or \"in\"");
1335546Slinton }
1345546Slinton if (cmd == O_TRACEI) {
1355546Slinton if (exp->op == O_QLINE) {
1365546Slinton addr = (ADDRESS) exp->right->lconval;
1375546Slinton } else if (exp->op == O_LCON) {
1385546Slinton addr = (ADDRESS) exp->lconval;
1395546Slinton } else {
1405546Slinton trerror("expected integer constant, found %t", exp);
1415546Slinton }
1425546Slinton line = -1;
1435546Slinton } else {
1445546Slinton if (exp->op == O_QLINE) {
1455546Slinton line = (LINENO) exp->right->lconval;
1465546Slinton addr = objaddr(line, exp->left->sconval);
1475546Slinton } else {
1485546Slinton line = (LINENO) exp->lconval;
1495546Slinton addr = objaddr(line, cursource);
1505546Slinton }
1515546Slinton if (addr == (ADDRESS) -1) {
1525546Slinton error("can't trace line %d", line);
1535546Slinton }
1545546Slinton }
1555546Slinton tfree(exp);
1565546Slinton addbp(addr, INST, NIL, cond, NIL, line);
1575546Slinton }
1585546Slinton
1595546Slinton /*
1605546Slinton * set a breakpoint to print an expression at a given line or address
1615546Slinton */
1625546Slinton
traceat(cmd,exp,where,cond)1635546Slinton LOCAL traceat(cmd, exp, where, cond)
1645546Slinton int cmd;
1655546Slinton NODE *exp;
1665546Slinton NODE *where;
1675546Slinton NODE *cond;
1685546Slinton {
1695546Slinton LINENO line;
1705546Slinton ADDRESS addr;
1715546Slinton
1725546Slinton if (cmd == O_TRACEI) {
1735546Slinton if (where->op != O_LCON) {
1745546Slinton trerror("expected integer constant, found %t", where);
1755546Slinton }
1765546Slinton line = -1;
1775546Slinton addr = (ADDRESS) where->lconval;
1785546Slinton } else {
1795546Slinton line = (LINENO) where->right->lconval;
1805546Slinton addr = objaddr(line, where->left->sconval);
1815546Slinton if (addr == (ADDRESS) -1) {
1825546Slinton error("can't trace at line %d", line);
1835546Slinton }
1845546Slinton }
1855546Slinton addbp(addr, AT_BP, NIL, cond, exp, line);
1865546Slinton }
1875546Slinton
1885546Slinton /*
1895546Slinton * Set up breakpoint for tracing data.
1905546Slinton *
1915546Slinton * The tracing of blocks lies somewhere between instruction and data;
1925546Slinton * it's here since a block cannot be distinguished from other terms.
1935546Slinton *
1945546Slinton * As in "traceall", if the "block" is the main program then the
1955546Slinton * user didn't actually specify a block. This means we want to
1965546Slinton * turn tracing on ourselves because if the program is stopped
1975546Slinton * we want to be on regardless of whether they say "cont" or "run".
1985546Slinton */
1995546Slinton
tracedata(cmd,exp,block,cond)2005546Slinton LOCAL tracedata(cmd, exp, block, cond)
2015546Slinton int cmd;
2025546Slinton NODE *exp;
2035546Slinton NODE *block;
2045546Slinton NODE *cond;
2055546Slinton {
2065546Slinton SYM *s, *t;
2075546Slinton
20830829Smckusick #ifdef lint
20930829Smckusick cmd = cmd;
21030829Smckusick #endif
2115546Slinton if (exp->op != O_RVAL && exp->op != O_CALL) {
2125546Slinton error("can't trace expressions");
2135546Slinton }
2145546Slinton if (block == NIL) {
2155546Slinton t = tcontainer(exp->left);
2165546Slinton } else if (block->op == O_NAME) {
2175546Slinton t = block->nameval;
2185546Slinton } else {
2195546Slinton trerror("found %t, expected procedure or function", block);
2205546Slinton }
2215546Slinton if (exp->left->op == O_NAME) {
2225546Slinton s = exp->left->nameval;
2235546Slinton if (isblock(s)) {
2245546Slinton addbp(codeloc(t), BLOCK_ON, t, cond, exp->left, 0);
2255546Slinton if (t == program) {
2265546Slinton addbp(codeloc(s), CALL, s, cond, NIL, 0);
2275546Slinton }
2285546Slinton return;
2295546Slinton }
2305546Slinton }
2315546Slinton addbp(codeloc(t), TERM_ON, t, cond, exp, 0);
2325546Slinton if (curfunc == t) {
2335546Slinton var_tracing++;
2345546Slinton addvar(TRPRINT, exp, cond);
2355546Slinton addbp(return_addr(), TERM_OFF, t, cond, exp, 0);
2365546Slinton }
2375546Slinton }
2385546Slinton
2395546Slinton /*
2405546Slinton * Setting and unsetting of stops.
2415546Slinton */
2425546Slinton
stop(cmd,exp,where,cond)2435546Slinton stop(cmd, exp, where, cond)
2445546Slinton int cmd;
2455546Slinton NODE *exp;
2465546Slinton NODE *where;
2475546Slinton NODE *cond;
2485546Slinton {
2495546Slinton SYM *s;
2505546Slinton LINENO n;
2515546Slinton
2525546Slinton if (exp != NIL) {
2535546Slinton stopvar(cmd, exp, where, cond);
2545546Slinton } else if (cond != NIL) {
2555546Slinton if (where == NIL) {
2565546Slinton s = program;
2575546Slinton } else if (where->op == O_NAME) {
2585546Slinton s = where->nameval;
2595546Slinton } else {
2605546Slinton error("bad location for stop");
2615546Slinton }
2625546Slinton n = codeloc(s);
2635546Slinton addbp(n, STOP_ON, s, cond, NIL, n);
2645546Slinton addcond(TRSTOP, cond);
2655546Slinton var_tracing++;
2665546Slinton } else if (where->op == O_NAME) {
2675546Slinton s = where->nameval;
2685546Slinton if (!isblock(s)) {
2695546Slinton error("\"%s\" is not a procedure or function", name(s));
2705546Slinton }
2715546Slinton n = codeloc(s);
2725546Slinton addbp(n, STOP_BP, s, cond, NIL, srcline(firstline(s)));
2735546Slinton } else {
2745546Slinton stopinst(cmd, where, cond);
2755546Slinton }
2765546Slinton if (where != NIL) {
2775546Slinton tfree(where);
2785546Slinton }
2795546Slinton }
2805546Slinton
stopinst(cmd,where,cond)2815546Slinton LOCAL stopinst(cmd, where, cond)
2825546Slinton int cmd;
2835546Slinton NODE *where;
2845546Slinton NODE *cond;
2855546Slinton {
2865546Slinton LINENO line;
2875546Slinton ADDRESS addr;
2885546Slinton
2895546Slinton if (where->op != O_QLINE) {
2905546Slinton error("expected line number");
2915546Slinton }
2925546Slinton if (cmd == O_STOP) {
2935546Slinton line = (LINENO) where->right->lconval;
2945546Slinton addr = objaddr(line, where->left->sconval);
2955546Slinton if (addr == (ADDRESS) -1) {
2965546Slinton error("can't stop at that line");
2975546Slinton }
2985546Slinton } else {
2995546Slinton line = -1;
3005546Slinton addr = (ADDRESS) where->right->lconval;
3015546Slinton }
3025546Slinton addbp(addr, STOP_BP, NIL, cond, NIL, line);
3035546Slinton }
3045546Slinton
3055546Slinton /*
3065546Slinton * Implement stopping on assignment to a variable by adding it to
3075546Slinton * the variable list.
3085546Slinton */
3095546Slinton
stopvar(cmd,exp,where,cond)3105546Slinton LOCAL stopvar(cmd, exp, where, cond)
3115546Slinton int cmd;
3125546Slinton NODE *exp;
3135546Slinton NODE *where;
3145546Slinton NODE *cond;
3155546Slinton {
3165546Slinton SYM *s;
3175546Slinton
3185546Slinton if (exp->op != O_RVAL) {
3195546Slinton trerror("found %t, expected variable", exp);
3205546Slinton }
3215546Slinton if (cmd == O_STOPI) {
3225546Slinton inst_tracing++;
3235546Slinton }
3245546Slinton var_tracing++;
3255546Slinton addvar(TRSTOP, exp, cond);
3265546Slinton if (where == NIL) {
3275546Slinton s = program;
3285546Slinton } else if (where->op == O_NAME) {
3295546Slinton s = where->nameval;
3305546Slinton } else {
3315546Slinton error("bad location for stop");
3325546Slinton }
3335546Slinton addbp(codeloc(s), STOP_ON, s, cond, exp, 0);
3345546Slinton }
3355546Slinton
3365546Slinton /*
3375546Slinton * Figure out the block that contains the symbols
3385546Slinton * in the given variable expression.
3395546Slinton */
3405546Slinton
tcontainer(var)3415546Slinton LOCAL SYM *tcontainer(var)
3425546Slinton NODE *var;
3435546Slinton {
3445546Slinton NODE *p;
3455546Slinton
3465546Slinton p = var;
3475546Slinton while (p->op != O_NAME) {
3485546Slinton if (isleaf(p->op)) {
3495546Slinton panic("unexpected op %d in tcontainer", p->op);
3505546Slinton /* NOTREACHED */
3515546Slinton }
3525546Slinton p = p->left;
3535546Slinton }
3545546Slinton return container(p->nameval);
3555546Slinton }
356