* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)eval.c 5.5 (Berkeley) %G%";
static char rcsid
[] = "$Header: eval.c,v 1.2 87/03/25 19:48:33 donn Exp $";
#define push(type, value) { \
((type *) (sp += sizeof(type)))[-1] = (value); \
(*((type *) (sp -= sizeof(type)))) \
#define popn(n, dest) { \
sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
public Stack stack
[STACKSIZE
];
public Stack
*sp
= &stack
[0];
public Boolean useInstLoc
= false;
panic("stack underflow"); \
#define poparg(n, r, fr) { \
if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
} else if (isint(p->op)) { \
r = popsmall(p->value.arg[n]->nodetype); \
#define Boolrep char /* underlying representation type for booleans */
* Command-level evaluation.
fprintf(stderr
, "topeval(");
* Evaluate a parse tree leaving the value on the top of the stack.
fprintf(stderr
, "begin eval %s\n", opname(p
->op
));
push(long, return_addr());
} else if (isvariable(s
)) {
if (s
!= program
and not isactive(container(s
))) {
error("\"%s\" is not active", symname(s
));
if (isvarparam(s
) and not isopenarray(s
)) {
rpush(address(s
, nil
), sizeof(Address
));
push(Address
, address(s
, nil
));
error("can't evaluate a %s", classname(s
));
pushsmall(p
->nodetype
, r0
);
push(double, p
->value
.fcon
);
mov(p
->value
.scon
, sp
, len
);
s
= p
->value
.arg
[0]->nodetype
;
p
->value
.arg
[0]->nodetype
= t_addr
;
p
->value
.arg
[0]->nodetype
= s
;
evalindex(s
, n
, popsmall(p
->value
.arg
[1]->nodetype
));
s
= p
->value
.arg
[1]->value
.sym
;
push(long, n
+ (s
->symvalue
.field
.offset div
8));
* Get the value of the expression addressed by the top of the stack.
* Push the result back on the stack.
error("reference through nil pointer");
loophole(size(p
->value
.arg
[0]->nodetype
), size(p
->nodetype
));
if (p
->value
.arg
[1] != nil
) {
push(double, (double) r0
);
error("error: division by 0");
error("error: div by 0");
error("error: mod by 0");
push(Boolrep
, fr0
< fr1
);
push(Boolrep
, fr0
<= fr1
);
push(Boolrep
, fr0
> fr1
);
push(Boolrep
, fr0
== fr1
);
push(Boolrep
, fr0
!= fr1
);
push(Boolrep
, r0
and r1
);
assign(p
->value
.arg
[0], p
->value
.arg
[1]);
if (p
->value
.scon
== nil
) {
printf("%s\n", cursource
);
file
= opensource(p
->value
.scon
);
error("can't read \"%s\"", p
->value
.scon
);
setsource(p
->value
.scon
);
eval(p
->value
.examine
.beginaddr
);
if (p
->value
.examine
.endaddr
== nil
) {
n
= p
->value
.examine
.count
;
printvalue(r0
, p
->value
.examine
.mode
);
} else if (streq(p
->value
.examine
.mode
, "i")) {
printninst(n
, (Address
) r0
);
printndata(n
, (Address
) r0
, p
->value
.examine
.mode
);
eval(p
->value
.examine
.endaddr
);
if (streq(p
->value
.examine
.mode
, "i")) {
printinst((Address
)r0
, (Address
)r1
);
printdata((Address
)r0
, (Address
)r1
, p
->value
.examine
.mode
);
for (n1
= p
->value
.arg
[0]; n1
!= nil
; n1
= n1
->value
.arg
[1]) {
printval(n1
->value
.arg
[0]->nodetype
);
if (p
->value
.arg
[0]->op
== O_SYM
) {
psym(p
->value
.arg
[0]->value
.sym
);
psym(p
->value
.arg
[0]->nodetype
);
inst_tracing
= (Boolean
) (not p
->value
.step
.source
);
if (p
->value
.step
.skipcalls
) {
useInstLoc
= (Boolean
) (not p
->value
.step
.source
);
if (p
->value
.arg
[0]->op
== O_SYM
) {
printdecl(p
->value
.arg
[0]->value
.sym
);
printdecl(p
->value
.arg
[0]->nodetype
);
if (p
->value
.arg
[0]->op
== O_SYM
) {
printwhereis(stdout
, p
->value
.arg
[0]->value
.sym
);
printwhereis(stdout
, p
->value
.arg
[0]->nodetype
);
if (p
->value
.arg
[0]->op
== O_SYM
) {
printwhich(stdout
, p
->value
.arg
[0]->value
.sym
);
printwhich(stdout
, p
->value
.arg
[0]->nodetype
);
alias(n1
->value
.name
, nil
, nil
);
} else if (n2
->op
== O_NAME
) {
str
= ident(n2
->value
.name
);
alias(n1
->value
.name
, nil
, strdup(str
));
n1
->value
.arg
[0]->value
.name
,
alias(n1
->value
.name
, nil
, n2
->value
.scon
);
unalias(p
->value
.arg
[0]->value
.name
);
if (p
->value
.lcon
== 0) {
printsigscaught(process
);
psigtrace(process
, p
->value
.lcon
, true);
checkref(p
->value
.arg
[0]);
assert(p
->value
.arg
[0]->op
== O_LCON
);
down(p
->value
.arg
[0]->value
.lcon
);
if (p
->value
.arg
[0] == nil
) {
s
= p
->value
.arg
[0]->value
.sym
;
if (p
->value
.lcon
== 0) {
printsigsignored(process
);
psigtrace(process
, p
->value
.lcon
, false);
if (p
->value
.arg
[0] == nil
) {
assert(p
->value
.arg
[0]->op
== O_SYM
);
rtnfunc(p
->value
.arg
[0]->value
.sym
);
set(p
->value
.arg
[0], p
->value
.arg
[1]);
search(p
->value
.arg
[0]->value
.lcon
, p
->value
.arg
[1]->value
.scon
);
undefvar(p
->value
.arg
[0]->value
.name
);
checkref(p
->value
.arg
[0]);
assert(p
->value
.arg
[0]->op
== O_LCON
);
up(p
->value
.arg
[0]->value
.lcon
);
addevent(p
->value
.event
.cond
, p
->value
.event
.actions
);
while (n1
->op
== O_COMMA
) {
assert(n2
->op
== O_LCON
);
if (not delevent((unsigned int) n2
->value
.lcon
)) {
error("unknown event %ld", n2
->value
.lcon
);
assert(n1
->op
== O_LCON
);
if (not delevent((unsigned int) n1
->value
.lcon
)) {
error("unknown event %ld", n1
->value
.lcon
);
if (cond(p
->value
.event
.cond
)) {
evalcmdlist(p
->value
.event
.actions
);
event_once(p
->value
.event
.cond
, p
->value
.event
.actions
);
printcall(p
->value
.sym
, whatblock(return_addr()));
printifchanged(p
->value
.arg
[0]);
if (p
->value
.arg
[0] == nil
) {
printlines(curline
, curline
);
} else if (p
->value
.arg
[0]->op
== O_QLINE
) {
if (p
->value
.arg
[0]->value
.arg
[1]->value
.lcon
== 0) {
printlines(curline
, curline
);
prtree(stdout
, p
->value
.arg
[0]);
printval(p
->value
.arg
[0]->nodetype
);
procreturn(p
->value
.sym
);
stopifchanged(p
->value
.arg
[0]);
traceon(p
->value
.trace
.inst
, p
->value
.trace
.event
,
panic("eval: bad op %d", p
->op
);
fprintf(stderr
, "end eval %s\n", opname(p
->op
));
* Evaluate a list of commands.
* Push "len" bytes onto the expression stack from address "addr"
* in the process. If there isn't room on the stack, print an error message.
error("expression too large to evaluate");
* Check if the stack has n bytes available.
public Boolean
canpush(n
)
return (Boolean
) (sp
+ n
< &stack
[STACKSIZE
]);
* Push a small scalar of the given type onto the stack.
panic("bad size %d in popsmall", s
);
* Pop an item of the given type which is assumed to be no larger
* than a long and return it expanded into a long.
if (t
->class == RANGE
and t
->symvalue
.rangev
.lower
>= 0) {
r
= (long) pop(unsigned char);
} else if (n
== sizeof(short)) {
if (t
->class == RANGE
and t
->symvalue
.rangev
.lower
>= 0) {
r
= (long) pop(unsigned short);
} else if (n
== sizeof(long)) {
error("[internal error: size %d in popsmall]", n
);
* Evaluate a conditional expression.
* Return the address corresponding to a given tree.
return (Address
) (pop(long));
* Process a trace command, translating into the appropriate events
* and associated actions.
traceall(p
->op
, place
, cond
);
} else if (exp
->op
== O_QLINE
or exp
->op
== O_LCON
) {
traceinst(p
->op
, exp
, cond
);
} else if (place
!= nil
and place
->op
== O_QLINE
) {
traceat(p
->op
, exp
, place
, cond
);
if (left
->op
== O_RVAL
or left
->op
== O_CALL
) {
left
= left
->value
.arg
[0];
if (left
->op
== O_SYM
and isblock(left
->value
.sym
)) {
traceproc(p
->op
, left
->value
.sym
, place
, cond
);
tracedata(p
->op
, exp
, place
, cond
);
* Set a breakpoint that will turn on tracing.
private traceall(op
, place
, cond
)
event
= build(O_EQ
, build(O_SYM
, procsym
), build(O_SYM
, s
));
action
= build(O_PRINTSRCPOS
,
build(O_QLINE
, nil
, build(O_LCON
, (op
== O_TRACE
) ? 1 : 0)));
action
= build(O_IF
, cond
, buildcmdlist(action
));
action
= build(O_TRACEON
, (op
== O_TRACEI
), buildcmdlist(action
));
action
->value
.trace
.event
= addevent(event
, buildcmdlist(action
));
printevent(action
->value
.trace
.event
);
* Set up the appropriate breakpoint for tracing an instruction.
private traceinst(op
, exp
, cond
)
wh
= build(O_QLINE
, build(O_SCON
, strdup(cursource
)), exp
);
event
= build(O_EQ
, build(O_SYM
, pcsym
), wh
);
event
= build(O_EQ
, build(O_SYM
, linesym
), wh
);
action
= build(O_PRINTSRCPOS
, wh
);
action
= build(O_IF
, cond
, buildcmdlist(action
));
e
= addevent(event
, buildcmdlist(action
));
* Set a breakpoint to print an expression at a given line or address.
private traceat(op
, exp
, place
, cond
)
event
= build(O_EQ
, build(O_SYM
, pcsym
), place
);
event
= build(O_EQ
, build(O_SYM
, linesym
), place
);
action
= build(O_PRINTSRCPOS
, exp
);
action
= build(O_IF
, cond
, buildcmdlist(action
));
e
= addevent(event
, buildcmdlist(action
));
* Construct event for tracing a procedure.
* Note that "once" is like "when" except that the event
* deletes itself as part of its associated action.
private traceproc(op
, p
, place
, cond
)
action
= build(O_PRINTCALL
, p
);
actionlist
= list_alloc();
cmdlist_append(action
, actionlist
);
event
= build(O_EQ
, build(O_SYM
, pcsym
), build(O_SYM
, retaddrsym
));
action
= build(O_ONCE
, event
, buildcmdlist(build(O_PRINTRTN
, p
)));
cmdlist_append(action
, actionlist
);
actionlist
= buildcmdlist(build(O_IF
, cond
, actionlist
));
event
= build(O_EQ
, build(O_SYM
, procsym
), build(O_SYM
, p
));
e
= addevent(event
, actionlist
);
* Set up breakpoint for tracing data.
private tracedata(op
, exp
, place
, cond
)
if (size(exp
->nodetype
) > MAXTRSIZE
) {
error("expression too large to trace (limit is %d bytes)", MAXTRSIZE
);
p
= (place
== nil
) ? tcontainer(exp
) : place
->value
.sym
;
action
= build(O_PRINTIFCHANGED
, exp
);
action
= build(O_IF
, cond
, buildcmdlist(action
));
action
= build(O_TRACEON
, (op
== O_TRACEI
), buildcmdlist(action
));
event
= build(O_EQ
, build(O_SYM
, procsym
), build(O_SYM
, p
));
action
->value
.trace
.event
= addevent(event
, buildcmdlist(action
));
printevent(action
->value
.trace
.event
);
* Setting and unsetting of stops.
Node exp
, place
, cond
, t
;
stopvar(p
->op
, exp
, place
, cond
);
action
= build(O_IF
, cond
, buildcmdlist(action
));
if (place
== nil
or place
->op
== O_SYM
) {
t
= build(O_EQ
, build(O_SYM
, procsym
), build(O_SYM
, s
));
action
= build(O_TRACEON
, (p
->op
== O_STOPI
),
e
= addevent(t
, buildcmdlist(action
));
action
->value
.trace
.event
= e
;
e
= addevent(t
, buildcmdlist(action
));
stopinst(p
->op
, place
, cond
, action
);
private stopinst(op
, place
, cond
, action
)
event
= build(O_EQ
, build(O_SYM
, linesym
), place
);
event
= build(O_EQ
, build(O_SYM
, pcsym
), place
);
e
= addevent(event
, buildcmdlist(action
));
* Implement stopping on assignment to a variable by adding it to
private stopvar(op
, exp
, place
, cond
)
if (size(exp
->nodetype
) > MAXTRSIZE
) {
error("expression too large to trace (limit is %d bytes)", MAXTRSIZE
);
action
= build(O_STOPIFCHANGED
, exp
);
action
= build(O_IF
, cond
, buildcmdlist(action
));
action
= build(O_TRACEON
, (op
== O_STOPI
), buildcmdlist(action
));
event
= build(O_EQ
, build(O_SYM
, procsym
), build(O_SYM
, p
));
action
->value
.trace
.event
= addevent(event
, buildcmdlist(action
));
printevent(action
->value
.trace
.event
);
* Assign the value of an expression to a variable (or term).
integer varsize
, expsize
;
if (var
->op
== O_SYM
and regnum(var
->value
.sym
) != -1) {
setreg(regnum(var
->value
.sym
), pop(Address
));
varsize
= size(var
->nodetype
);
expsize
= size(exp
->nodetype
);
if (varsize
== sizeof(float) and expsize
== sizeof(double)) {
fvalue
= (float) pop(double);
dwrite(&fvalue
, addr
, sizeof(fvalue
));
if (varsize
< sizeof(long)) {
if (varsize
== sizeof(char)) {
dwrite(&cvalue
, addr
, sizeof(cvalue
));
} else if (varsize
== sizeof(short)) {
dwrite(&svalue
, addr
, sizeof(svalue
));
error("[internal error: bad size %d in assign]", varsize
);
if (expsize
<= varsize
) {
dwrite(sp
, addr
, expsize
);
dwrite(sp
, addr
, varsize
);
* Set a debugger variable.
defvar(var
->value
.name
, nil
);
} else if (var
->value
.name
== identname("$frame", true)) {
if (not compatible(t
, t_int
) and not compatible(t
, t_addr
)) {
error("$frame must be an address");
getnewregs(pop(Address
));
defvar(var
->value
.name
, unrval(exp
));
* Execute a list command.
if (p
->value
.arg
[0]->op
== O_SYM
) {
f
= p
->value
.arg
[0]->value
.sym
;
error("no source lines for \"%s\"", symname(f
));
setsource(srcfilename(addr
));
getsrcwindow(line
, &l1
, &l2
);
l1
= (Lineno
) (pop(long));
l2
= (Lineno
) (pop(long));
* Execute a func command.
printname(stdout
, curfunc
);
find(f
, s
->name
) where
isroutine(f
) endfind(f
);
error("%s is not a procedure or function", symname(s
));
setsource(srcfilename(addr
));
cursrcline
= srcline(addr
);
* Send a message to the current support person.
extern int versionNumber
;
puts("Type control-D to end your message. Be sure to include");
puts("your name and the name of the file you are debugging.");
old
= signal(SIGINT
, SIG_DFL
);
sprintf(subject
, "dbx (version 3.%d) gripe", versionNumber
);
pid
= back("Mail", stdin
, stdout
, "-s", subject
, MAINTAINER
, nil
);
puts("\nMail not sent.");
puts("Sorry, no dbx maintainer available to gripe to.");
puts("Try contacting your system manager.");
* Give the user some help.
puts("run - begin execution of the program");
puts("print <exp> - print the value of the expression");
puts("where - print currently active procedures");
puts("stop at <line> - suspend execution at the line");
puts("stop in <proc> - suspend execution when <proc> is called");
puts("cont - continue execution");
puts("step - single step one line");
puts("next - step to next line (skip over calls)");
puts("trace <line#> - trace execution of the line");
puts("trace <proc> - trace calls to the procedure");
puts("trace <var> - trace changes to the variable");
puts("trace <exp> at <line#> - print <exp> when <line> is reached");
puts("status - print trace/stop's in effect");
puts("delete <number> - remove trace or stop of given number");
puts("call <proc> - call a procedure in program");
puts("whatis <name> - print the declaration of the name");
puts("list <line>, <line> - list source lines");
puts("gripe - send mail to the person in charge of dbx");
* Divert output to the given file name.
* Cannot redirect to an existing file.
private Boolean notstdout
;
f
= fopen(filename
, "r");
error("%s: file already exists", filename
);
if (creat(filename
, 0666) == nil
) {
error("can't create %s", filename
);
* Revert output to standard output.
panic("standard out dup failed");
* Determine is standard output is currently being redirected
* to a file (as far as we know).
public Boolean
isredirected()