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