1*48095Sbostic /*- 2*48095Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*48095Sbostic * All rights reserved. 4*48095Sbostic * 5*48095Sbostic * %sccs.include.redist.c% 622517Sdist */ 75515Slinton 822517Sdist #ifndef lint 9*48095Sbostic static char sccsid[] = "@(#)callproc.c 5.4 (Berkeley) 04/16/91"; 10*48095Sbostic #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 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 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 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 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 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 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 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 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