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