new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / pascal / pdx / breakpoint / bpact.c
/*-
* Copyright (c) 1980 The Regents of the University of California.
* All rights reserved.
*
* %sccs.include.redist.c%
*/
#ifndef lint
static char sccsid[] = "@(#)bpact.c 5.2 (Berkeley) %G%";
#endif /* not lint */
/*
* Routines for doing the right thing when a breakpoint is reached.
*/
#include "defs.h"
#include "breakpoint.h"
#include "sym.h"
#include "tree.h"
#include "source.h"
#include "mappings.h"
#include "runtime.h"
#include "process.h"
#include "machine.h"
#include "main.h"
#include "bp.rep"
#include "tree/tree.rep"
typedef enum { SAVE, NOSAVE } SAVEBP;
LOCAL SAVEBP handlebp();
/*
* A "delayed" breakpoint is one that has an action involving execution
* of code, e.g. at a CALL we want to step from the beginning of the
* procedure to the first line before printing parameters.
*/
LOCAL short delayed;
#define NONE 0
#define DELAY_CALL 1
#define DELAY_STOP 2
/*
* Take action at a breakpoint; if it's not a breakpoint return FALSE.
*
* As we go through the list of breakpoints, we have to remember
* the previous one so that "handlebp" can delete breakpoints on
* the fly if necessary.
*
* If the breakpoint is a STOP_BP, handlebp will set "isstopped". After
* going through the loop, bpact checks if "isstopped" is set and calls
* printstatus if it is. This is so multiple breakpoints at the same
* address, one of which is a STOP_BP, still work.
*/
#define isswitch(bptype) ( \
bptype == ALL_ON || bptype == ALL_OFF || \
bptype == TERM_ON || bptype == TERM_OFF || \
bptype == BLOCK_ON || bptype == BLOCK_OFF || \
bptype == STOP_ON || bptype == STOP_OFF \
)
BOOLEAN bpact()
{
register BPINFO *p;
BPINFO *prev, *next;
BOOLEAN found;
ADDRESS oldpc;
delayed = NONE;
found = FALSE;
prev = NIL;
for (p = bphead; p != NIL; p = next) {
next = p->bpnext;
if (p->bpaddr == pc) {
prbpfound(p);
found = TRUE;
if (p->bpcond == NIL || isswitch(p->bptype) || cond(p->bpcond)) {
prbphandled();
if (handlebp(p) == NOSAVE) {
prbpnosave();
if (prev == NIL) {
bphead = next;
} else {
prev->bpnext = next;
}
dispose(p);
} else {
prbpsave();
prev = p;
}
} else {
prev = p;
}
} else {
prev = p;
}
}
if (delayed != NONE) {
oldpc = pc;
runtofirst();
if ((delayed&DELAY_CALL) == DELAY_CALL) {
SYM *s, *t;
s = curfunc;
t = whatblock(return_addr());
if (t == NIL) {
panic("can't find block for caller addr %d", caller_addr());
}
printcall(s, t);
addbp(return_addr(), RETURN, s, NIL, NIL, 0);
}
if (pc != oldpc) {
bpact();
}
if (isstopped) {
printstatus();
}
} else {
if (isstopped) {
printstatus();
}
}
fflush(stdout);
return(found);
}
/*
* Handle an expected breakpoint appropriately, return whether
* or not to save the breakpoint.
*/
LOCAL SAVEBP handlebp(p)
BPINFO *p;
{
register SYM *s, *t;
SAVEBP r;
r = SAVE;
switch(p->bptype) {
case ALL_ON:
curfunc = p->bpblock;
addcond(TRPRINT, p->bpcond);
if (p->bpline >= 0) {
tracing++;
} else {
inst_tracing++;
}
addbp(return_addr(), ALL_OFF, curfunc, p->bpcond, NIL, 0);
break;
case ALL_OFF:
r = NOSAVE;
if (p->bpline >= 0) {
tracing--;
} else {
inst_tracing--;
}
delcond(TRPRINT, p->bpcond);
curfunc = p->bpblock;
break;
case STOP_ON:
var_tracing++;
curfunc = p->bpblock;
if (p->bpnode != NIL) {
addvar(TRSTOP, p->bpnode, p->bpcond);
} else if (p->bpcond != NIL) {
addcond(TRSTOP, p->bpcond);
}
addbp(return_addr(), STOP_OFF, curfunc, p->bpcond, p->bpnode, 0);
break;
case STOP_OFF:
r = NOSAVE;
delcond(TRSTOP, p->bpcond);
var_tracing--;
curfunc = p->bpblock;
break;
case INST:
curline = p->bpline;
if (curline > 0) {
printf("trace: ");
printlines(curline, curline);
} else {
printf("inst trace: ");
printinst(pc, pc);
}
break;
case STOP_BP:
if (p->bpblock != NIL) {
delayed |= DELAY_STOP;
curfunc = p->bpblock;
}
curline = p->bpline;
isstopped = TRUE;
break;
case BLOCK_ON: {
BPINFO *nbp;
s = p->bpblock;
t = p->bpnode->nameval;
nbp = newbp(codeloc(t), CALL, t, p->bpcond, NIL, 0);
addbp(return_addr(), BLOCK_OFF, (SYM *) nbp, NIL, NIL, 0);
break;
}
case BLOCK_OFF: {
BPINFO *oldbp;
r = NOSAVE;
oldbp = (BPINFO *) p->bpblock;
delbp(oldbp->bpid);
break;
}
case CALL:
delayed |= DELAY_CALL;
curfunc = p->bpblock;
break;
case RETURN:
r = NOSAVE;
s = p->bpblock;
printrtn(s);
break;
case TERM_ON: {
ADDRESS addr;
curfunc = p->bpblock;
addvar(TRPRINT, p->bpnode, p->bpcond);
addr = return_addr();
addbp(addr, TERM_OFF, curfunc, p->bpcond, p->bpnode, 0);
var_tracing++;
break;
}
case TERM_OFF:
r = NOSAVE;
var_tracing--;
delvar(TRPRINT, p->bpnode, p->bpcond);
curfunc = p->bpblock;
break;
case AT_BP:
printf("at line %d: ", p->bpline);
eval(p->bpnode);
prtree(p->bpnode);
printf(" = ");
printval(p->bpnode->nodetype);
putchar('\n');
break;
/*
* Returning from a called procedure.
* Further breakpoint processing is not done, since if
* there were any it wouldn't be associated with the call.
*/
case CALLPROC:
procreturn(p->bpblock);
delbp(p->bpid);
erecover();
/* NOTREACHED */
case END_BP:
r = NOSAVE;
endprogram();
default:
panic("unknown bptype %d in cont", p->bptype);
/* NOTREACHED */
}
return(r);
}
/*
* Internal trace routines.
*/
LOCAL char *prbptype[] ={
"ALL_ON", "ALL_OFF", "INST", "CALL", "RETURN", "BLOCK_ON", "BLOCK_OFF",
"TERM_ON", "TERM_OFF", "AT_BP", "STOP_BP", "CALLPROC", "END_BP",
"STOP_ON", "STOP_OFF",
};
LOCAL prbpfound(p)
BPINFO *p;
{
if (option('b')) {
printf("%s breakpoint found at pc %d, line %d -- ",
prbptype[(int) p->bptype], p->bpaddr, p->bpline);
}
}
LOCAL prbphandled()
{
if (option('b')) {
printf("handled, ");
}
}
LOCAL prbpnosave()
{
if (option('b')) {
printf("not saved\n");
fflush(stdout);
}
}
LOCAL prbpsave()
{
if (option('b')) {
printf("saved\n");
fflush(stdout);
}
}