148095Sbostic /*-
2*62145Sbostic * Copyright (c) 1980, 1993
3*62145Sbostic * The Regents of the University of California. All rights reserved.
448095Sbostic *
548095Sbostic * %sccs.include.redist.c%
622517Sdist */
75515Slinton
822517Sdist #ifndef lint
9*62145Sbostic static char sccsid[] = "@(#)callproc.c 8.1 (Berkeley) 06/06/93";
1048095Sbostic #endif /* not lint */
1130849Smckusick
125515Slinton /*
135515Slinton * Evaluate a call to a procedure.
145515Slinton *
155515Slinton * This file is a botch as far as modularity is concerned.
1636535Smckusick *
1736535Smckusick * In fact, FIXME, it does not work on either the Vax or Tahoe
1836535Smckusick * at this point (Sep 22, 1988). It possibly doesn't work because
1936535Smckusick * the ptrace interface never sets "pc" back into the interpreter's
2036535Smckusick * program counter location.
2136535Smckusick *
2236535Smckusick * Due to portability changes
2336535Smckusick * in px for ANSI C, it is now even further broken, since the operand
2436535Smckusick * stack is no longer the system stack and since the interpreter's
2536535Smckusick * "pc" that we see is never read by the interpreter. We could fix
2636535Smckusick * this, and increase the modularity, by:
2736535Smckusick *
2836535Smckusick * * changing this whole module to build a string of bytecodes
2936535Smckusick * that would: push a series of constant parameters, then call a
3036535Smckusick * procedure, then take a breakpoint.
3136535Smckusick * * Having px allocate a place for us to do this, and pass us the
3236535Smckusick * address of this (otherwise unused) variable.
3336535Smckusick * * Creating an entry point into the px interpreter which would
3436535Smckusick * pick up the pc value from "*addrpc" and then enter the main loop.
3536535Smckusick * Currently we never pick up *addrpc for speed.
3636535Smckusick * * Fix the code below to use the new entry point rather than "loopaddr".
3736535Smckusick *
3836535Smckusick * But I suspect this code is dead enough that nobody will ever get
3936535Smckusick * around to it. -- gnu@toad.com, 22Sep88
405515Slinton */
415515Slinton
425515Slinton #include "defs.h"
435515Slinton #include "runtime.h"
445515Slinton #include "sym.h"
455515Slinton #include "tree.h"
465515Slinton #include "breakpoint.h"
475515Slinton #include "machine.h"
485515Slinton #include "process.h"
495515Slinton #include "source.h"
505515Slinton #include "frame.rep"
515515Slinton #include "sym/classes.h"
525515Slinton #include "sym/sym.rep"
535515Slinton #include "tree/tree.rep"
545515Slinton #include "process/process.rep"
555515Slinton #include "process/pxinfo.h"
565515Slinton
575515Slinton LOCAL ADDRESS retaddr;
5830849Smckusick #ifdef tahoe
5930849Smckusick BOOLEAN didret;
6030849Smckusick #endif
615515Slinton
625515Slinton /*
635515Slinton * Controlling logic of procedure calling.
645515Slinton * Calling a procedure before ever executing the program must
655515Slinton * be special cased.
665515Slinton */
675515Slinton
callproc(procnode,arglist)685515Slinton callproc(procnode, arglist)
695515Slinton NODE *procnode;
705515Slinton NODE *arglist;
715515Slinton {
7230849Smckusick register SYM *proc;
7330849Smckusick #ifdef tahoe
7430849Smckusick register int tmpsp, tmptmp;
7530849Smckusick extern BOOLEAN shouldrestart;
765515Slinton
7730849Smckusick if (shouldrestart) {
7830849Smckusick initstart();
7930849Smckusick }
8030849Smckusick #endif
815515Slinton if (pc == 0) {
825515Slinton curline = firstline(program);
835515Slinton setbp(curline);
845515Slinton resume();
855515Slinton unsetbp(curline);
865515Slinton }
875515Slinton proc = procnode->nameval;
885515Slinton if (!isblock(proc)) {
895515Slinton error("\"%s\" is not a procedure or function", proc->symbol);
905515Slinton }
9130849Smckusick #ifdef tahoe
9230849Smckusick doret(process);
9330849Smckusick tmpsp = process->sp;
9430849Smckusick #endif
955659Slinton pushargs(proc, arglist);
9630849Smckusick #ifdef tahoe
9730849Smckusick tmptmp = tmpsp;
9830849Smckusick tmpsp = process->sp;
9930849Smckusick process->sp = tmptmp;
10030849Smckusick #endif
1015515Slinton pushenv(proc->symvalue.funcv.codeloc);
10230849Smckusick #ifdef tahoe
10330849Smckusick process->sp = tmpsp;
10430849Smckusick #endif
1055515Slinton pushframe(proc->blkno);
1065515Slinton execute(proc);
1075515Slinton /* NOTREACHED */
1085515Slinton }
1095515Slinton
1105515Slinton /*
1115515Slinton * Push the arguments on the process' stack. We do this by first
1125515Slinton * evaluating them on the "eval" stack, then copying into the process'
1135515Slinton * space.
1145515Slinton */
1155515Slinton
pushargs(proc,arglist)1165515Slinton LOCAL pushargs(proc, arglist)
1175515Slinton SYM *proc;
1185515Slinton NODE *arglist;
1195515Slinton {
1205515Slinton STACK *savesp;
1215515Slinton int args_size;
1225515Slinton
1235515Slinton savesp = sp;
12430849Smckusick #ifdef tahoe
12530849Smckusick /*
12630849Smckusick * evalargs hopefully keeps stack aligned, so we won't bother
12730849Smckusick * aligning it afterwards, neither will we align process->sp
12830849Smckusick * after subtracting args_size.
12930849Smckusick */
13030849Smckusick #endif
1315515Slinton evalargs(proc->symbol, proc->chain, arglist);
1325515Slinton args_size = sp - savesp;
1335515Slinton process->sp -= args_size;
1345515Slinton dwrite(savesp, process->sp, args_size);
1355515Slinton sp = savesp;
1365515Slinton }
1375515Slinton
1385515Slinton /*
1395515Slinton * Evaluate arguments right-to-left because the eval stack
1405515Slinton * grows up, px's stack grows down.
1415515Slinton */
1425515Slinton
evalargs(procname,arg,explist)1435515Slinton LOCAL evalargs(procname, arg, explist)
1445515Slinton char *procname;
1455515Slinton SYM *arg;
1465515Slinton NODE *explist;
1475515Slinton {
1485515Slinton NODE *exp;
1495515Slinton STACK *savesp;
1505515Slinton ADDRESS addr;
1515515Slinton
1525515Slinton if (arg == NIL) {
1535515Slinton if (explist != NIL) {
1545515Slinton error("too many parameters to \"%s\"", procname);
1555515Slinton }
1565515Slinton } else if (explist == NIL) {
1575515Slinton error("not enough parameters to \"%s\"", procname);
1585515Slinton } else {
1595515Slinton if (explist->op != O_COMMA) {
1605515Slinton panic("evalargs: arglist missing comma");
1615515Slinton }
1625515Slinton savesp = sp;
1635515Slinton evalargs(procname, arg->chain, explist->right);
1645515Slinton exp = explist->left;
1655515Slinton if (!compatible(arg->type, exp->nodetype)) {
1665515Slinton sp = savesp;
1675515Slinton trerror("%t is not the same type as parameter \"%s\"",
1685515Slinton exp, arg->symbol);
1695515Slinton }
1705515Slinton if (arg->class == REF) {
1715515Slinton if (exp->op != O_RVAL) {
1725515Slinton sp = savesp;
1735515Slinton error("variable expected for parameter \"%s\"", arg->symbol);
1745515Slinton }
1755515Slinton addr = lval(exp->left);
1765515Slinton push(ADDRESS, addr);
1775515Slinton } else {
1785515Slinton eval(exp);
1795515Slinton }
1805515Slinton }
1815515Slinton }
1825515Slinton
1835515Slinton /*
1845515Slinton * Simulate a CALL instruction by pushing the appropriate
1855515Slinton * stack frame information.
1865515Slinton *
18730849Smckusick * Massage register 10 or 11 appropriately since it contains the
1885515Slinton * stack frame pointer.
1895515Slinton */
1905515Slinton
pushframe(b)1915515Slinton LOCAL pushframe(b)
1925515Slinton int b;
1935515Slinton {
1945515Slinton ADDRESS *newdp;
1955515Slinton FRAME callframe;
1965515Slinton
1975515Slinton retaddr = program->symvalue.funcv.codeloc;
1985515Slinton
1995515Slinton /*
2005515Slinton * This stuff is set by the callee, just here to take up space.
2015515Slinton */
2025515Slinton callframe.stackref = 0;
2035515Slinton callframe.file = 0;
2045515Slinton callframe.blockp = 0;
2055515Slinton callframe.save_loc = NIL;
2065515Slinton callframe.save_disp = NIL;
2075515Slinton
2085515Slinton /*
2095515Slinton * This is the useful stuff.
2105515Slinton */
2115515Slinton callframe.save_dp = curdp();
2125515Slinton callframe.save_pc = retaddr + ENDOFF;
2135515Slinton callframe.save_lino = 0;
2145515Slinton newdp = DISPLAY + (2 * b);
2155515Slinton dwrite(&newdp, DP, sizeof(newdp));
2165515Slinton process->sp -= sizeof(callframe);
2175515Slinton dwrite(&callframe, process->sp, sizeof(callframe));
21830849Smckusick #ifdef tahoe
21930849Smckusick process->reg[11] = process->sp;
22030849Smckusick #else
2215515Slinton process->reg[10] = process->sp;
22230849Smckusick #endif
2235515Slinton }
2245515Slinton
2255515Slinton /*
2265515Slinton * Execute the procedure. This routine does NOT return because it
2275515Slinton * calls "cont", which doesn't return. We set a CALLPROC breakpoint
2285515Slinton * at "retaddr", the address where the called routine will return.
2295515Slinton *
2305515Slinton * The action for a CALLPROC is to call "procreturn" where we restore
2315515Slinton * the environment.
2325515Slinton */
2335515Slinton
execute(f)2345515Slinton LOCAL execute(f)
2355515Slinton SYM *f;
2365515Slinton {
2375515Slinton isstopped = TRUE;
2385515Slinton addbp(retaddr, CALLPROC, f, NIL, NIL, 0);
2395515Slinton cont();
2405515Slinton /* NOTREACHED */
2415515Slinton }
2425515Slinton
procreturn(f)2435515Slinton procreturn(f)
2445515Slinton SYM *f;
2455515Slinton {
2465515Slinton int len;
2475515Slinton
24830849Smckusick #ifdef tahoe
24930849Smckusick doret(process);
25030849Smckusick #endif
2515515Slinton printf("%s returns ", f->symbol);
2525515Slinton if (f->class == FUNC) {
2535515Slinton len = size(f->type);
2545515Slinton dread(sp, process->sp, len);
25530849Smckusick #ifdef tahoe
25630849Smckusick len = (len + 3) & ~3;
25730849Smckusick #endif
2585515Slinton sp += len;
2595515Slinton printval(f->type);
2605515Slinton putchar('\n');
2615515Slinton } else {
2625515Slinton printf("successfully\n");
2635515Slinton }
2645515Slinton popenv();
2655515Slinton }
2665515Slinton
2675515Slinton /*
2685515Slinton * Push the current environment.
2695515Slinton *
2705515Slinton * This involves both saving pdx and interpreter values.
2715515Slinton * LOOPADDR is the address of the main interpreter loop.
2725515Slinton */
2735515Slinton
pushenv(newpc)2745515Slinton LOCAL pushenv(newpc)
2755515Slinton ADDRESS newpc;
2765515Slinton {
27730849Smckusick #ifdef tahoe
27830849Smckusick /* this should be done somewhere else, but... */
27930849Smckusick INTFP = process->fp;
28030849Smckusick #endif
2815515Slinton push(ADDRESS, pc);
2825515Slinton push(LINENO, curline);
2835515Slinton push(char *, cursource);
2845515Slinton push(BOOLEAN, isstopped);
2855515Slinton push(SYM *, curfunc);
2865515Slinton push(WORD, process->pc);
2875515Slinton push(WORD, process->sp);
2885515Slinton process->pc = LOOPADDR;
2895515Slinton pc = newpc;
29030849Smckusick #ifdef tahoe
29130849Smckusick process->reg[12] = pc + ENDOFF;
29230849Smckusick #else
2935515Slinton process->reg[11] = pc + ENDOFF;
29430849Smckusick #endif
2955515Slinton }
2965515Slinton
2975515Slinton /*
2985515Slinton * Pop back to the real world.
2995515Slinton */
3005515Slinton
popenv()3015515Slinton popenv()
3025515Slinton {
3035515Slinton register PROCESS *p;
3045515Slinton char *filename;
3055515Slinton
3065515Slinton p = process;
3075515Slinton p->sp = pop(WORD);
3085515Slinton p->pc = pop(WORD);
3095515Slinton curfunc = pop(SYM *);
3105515Slinton isstopped = pop(BOOLEAN);
3115515Slinton filename = pop(char *);
3125515Slinton curline = pop(LINENO);
3135515Slinton pc = pop(ADDRESS);
31430849Smckusick #ifdef tahoe
31530849Smckusick p->reg[12] = pc + 1 + ENDOFF;
31630849Smckusick #endif
3175515Slinton if (filename != cursource) {
3185515Slinton skimsource(filename);
3195515Slinton }
3205515Slinton }
321