* Copyright (c) 1980 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)tracestop.c 5.3 (Berkeley) 4/16/91";
* Handle trace and stop commands.
* Process a trace/untrace command, basically checking arguments
* and translate to a call of the appropriate routine.
trace(cmd
, exp
, where
, cond
)
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
);
tracedata(cmd
, exp
, where
, cond
);
* 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
)
if (where
!= NIL
&& where
->op
!= O_NAME
) {
error("bad location for trace");
error("already tracing lines");
error("already tracing instructions");
panic("bad cmd in traceall");
} else if (where
->op
!= O_NAME
) {
trerror("found %t, expected procedure or function", where
);
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
)
error("unexpected \"at\" or \"in\"");
if (exp
->op
== O_QLINE
) {
addr
= (ADDRESS
) exp
->right
->lconval
;
} else if (exp
->op
== O_LCON
) {
addr
= (ADDRESS
) exp
->lconval
;
trerror("expected integer constant, found %t", exp
);
if (exp
->op
== O_QLINE
) {
line
= (LINENO
) exp
->right
->lconval
;
addr
= objaddr(line
, exp
->left
->sconval
);
line
= (LINENO
) exp
->lconval
;
addr
= objaddr(line
, cursource
);
if (addr
== (ADDRESS
) -1) {
error("can't trace line %d", line
);
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
)
if (where
->op
!= O_LCON
) {
trerror("expected integer constant, found %t", where
);
addr
= (ADDRESS
) where
->lconval
;
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
)
if (exp
->op
!= O_RVAL
&& exp
->op
!= O_CALL
) {
error("can't trace expressions");
t
= tcontainer(exp
->left
);
} else if (block
->op
== O_NAME
) {
trerror("found %t, expected procedure or function", block
);
if (exp
->left
->op
== O_NAME
) {
addbp(codeloc(t
), BLOCK_ON
, t
, cond
, exp
->left
, 0);
addbp(codeloc(s
), CALL
, s
, cond
, NIL
, 0);
addbp(codeloc(t
), TERM_ON
, t
, cond
, exp
, 0);
addvar(TRPRINT
, exp
, cond
);
addbp(return_addr(), TERM_OFF
, t
, cond
, exp
, 0);
* Setting and unsetting of stops.
stop(cmd
, exp
, where
, cond
)
stopvar(cmd
, exp
, where
, cond
);
} else if (cond
!= NIL
) {
} else if (where
->op
== O_NAME
) {
error("bad location for stop");
addbp(n
, STOP_ON
, s
, cond
, NIL
, n
);
} else if (where
->op
== O_NAME
) {
error("\"%s\" is not a procedure or function", name(s
));
addbp(n
, STOP_BP
, s
, cond
, NIL
, srcline(firstline(s
)));
stopinst(cmd
, where
, cond
);
LOCAL
stopinst(cmd
, where
, cond
)
if (where
->op
!= O_QLINE
) {
error("expected line number");
line
= (LINENO
) where
->right
->lconval
;
addr
= objaddr(line
, where
->left
->sconval
);
if (addr
== (ADDRESS
) -1) {
error("can't stop at that line");
addr
= (ADDRESS
) where
->right
->lconval
;
addbp(addr
, STOP_BP
, NIL
, cond
, NIL
, line
);
* Implement stopping on assignment to a variable by adding it to
LOCAL
stopvar(cmd
, exp
, where
, cond
)
trerror("found %t, expected variable", exp
);
addvar(TRSTOP
, exp
, cond
);
} else if (where
->op
== O_NAME
) {
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
)
while (p
->op
!= O_NAME
) {
panic("unexpected op %d in tcontainer", p
->op
);
return container(p
->nameval
);