1*48069Sbostic /*- 2*48069Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*48069Sbostic * All rights reserved. 4*48069Sbostic * 5*48069Sbostic * %sccs.include.redist.c% 622565Sdist */ 75546Slinton 822565Sdist #ifndef lint 9*48069Sbostic static char sccsid[] = "@(#)tracestop.c 5.3 (Berkeley) 04/16/91"; 10*48069Sbostic #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 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 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 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 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 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 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 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 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 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