xref: /csrg-svn/old/dbx/iris.c (revision 38105)
133318Sdonn /*
2*38105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3*38105Sbostic  * All rights reserved.
4*38105Sbostic  *
5*38105Sbostic  * Redistribution and use in source and binary forms are permitted
6*38105Sbostic  * provided that the above copyright notice and this paragraph are
7*38105Sbostic  * duplicated in all such forms and that any documentation,
8*38105Sbostic  * advertising materials, and other materials related to such
9*38105Sbostic  * distribution and use acknowledge that the software was developed
10*38105Sbostic  * by the University of California, Berkeley.  The name of the
11*38105Sbostic  * University may not be used to endorse or promote products derived
12*38105Sbostic  * from this software without specific prior written permission.
13*38105Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*38105Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*38105Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633318Sdonn  */
1733318Sdonn 
1833318Sdonn #ifndef lint
19*38105Sbostic static char sccsid[] = "@(#)iris.c	5.2 (Berkeley) 05/23/89";
20*38105Sbostic #endif /* not lint */
2133318Sdonn 
2233318Sdonn /*
2333318Sdonn  * Target machine dependent stuff.
2433318Sdonn  */
2533318Sdonn 
2633318Sdonn #include "defs.h"
2733318Sdonn #include "machine.h"
2833318Sdonn #include "process.h"
2933318Sdonn #include "runtime.h"
3033318Sdonn #include "events.h"
3133318Sdonn #include "main.h"
3233318Sdonn #include "symbols.h"
3333318Sdonn #include "source.h"
3433318Sdonn #include "mappings.h"
3533318Sdonn #include "object.h"
3633318Sdonn #include "tree.h"
3733318Sdonn #include "eval.h"
3833318Sdonn #include "keywords.h"
3933318Sdonn #include "ops.h"
4033318Sdonn 
4133318Sdonn #ifndef public
4233318Sdonn typedef unsigned int Address;
4333318Sdonn typedef unsigned char Byte;
4433318Sdonn typedef unsigned int Word;
4533318Sdonn 
4633318Sdonn /*
4733318Sdonn  * On the 68000, the pc isn't in a register, but we make believe
4833318Sdonn  * so there's one more register.
4933318Sdonn  *
5033318Sdonn  * Note that there's also no argument pointer, this means code
5133318Sdonn  * involving "ARGP" should always be #ifdef'd.
5233318Sdonn  *
5333318Sdonn  * The address corresponding to the beginning of a function is recorded
5433318Sdonn  * as the address + FUNCOFFSET (skip the link instruction so that
5533318Sdonn  * local information is available).
5633318Sdonn  */
5733318Sdonn 
5833318Sdonn #define NREG 17
5933318Sdonn 
6033318Sdonn #define FRP 14
6133318Sdonn #define STKP 15
6233318Sdonn #define PROGCTR 16
6333318Sdonn 
6433318Sdonn #define CALL_RETADDR	0x800c		/* Return address for 'call' command */
6533318Sdonn #define FUNCOFFSET 4
6633318Sdonn 
6733318Sdonn #ifdef sun
6833318Sdonn #    define CODESTART 0x8000
6933318Sdonn #else /* IRIS */
7033318Sdonn #   define CODESTART 0x1000
7133318Sdonn #endif
7233318Sdonn 
7333318Sdonn #define optab_init()
7433318Sdonn 
7533318Sdonn #define BITSPERBYTE 8
7633318Sdonn #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
7733318Sdonn 
7833318Sdonn /*
7933318Sdonn  * This magic macro enables us to look at the process' registers
8033318Sdonn  * in its user structure.
8133318Sdonn  */
8233318Sdonn 
8333318Sdonn #define regloc(reg)	(ctob(UPAGES) + (sizeof(Word) * ((reg) - PC)) - 10)
8433318Sdonn 
8533318Sdonn #include "source.h"
8633318Sdonn #include "symbols.h"
8733318Sdonn #include <signal.h>
8833318Sdonn #include <sys/param.h>
8933318Sdonn #include <sys/dir.h>
9033318Sdonn #include <machine/psl.h>
9133318Sdonn #include <machine/pte.h>
9233318Sdonn #include <sys/user.h>
9333318Sdonn #undef DELETE /* XXX */
9433318Sdonn #include <sys/vm.h>
9533318Sdonn #include <machine/reg.h>
9633318Sdonn 
9733318Sdonn Address pc;
9833318Sdonn Address prtaddr;
9933318Sdonn 
10033318Sdonn #endif
10133318Sdonn 
10233318Sdonn /*
10333318Sdonn  * Indices into u. for use in collecting registers values.
10433318Sdonn  */
10533318Sdonn public int rloc[] ={
10633318Sdonn #ifdef sun
10733318Sdonn     R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5, AR6, AR7, PC
10833318Sdonn #else /* IRIS */
10933318Sdonn     R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5, AR6, AR7, 16
11033318Sdonn #endif
11133318Sdonn };
11233318Sdonn 
11333318Sdonn private Address printop();
11433318Sdonn 
11533318Sdonn /*
11633318Sdonn  * Decode and print the instructions within the given address range.
11733318Sdonn  */
11833318Sdonn 
11933318Sdonn public printinst(lowaddr, highaddr)
12033318Sdonn Address lowaddr;
12133318Sdonn Address highaddr;
12233318Sdonn {
12333318Sdonn     register Address addr;
12433318Sdonn 
12533318Sdonn     for (addr = lowaddr; addr <= highaddr; ) {
12633318Sdonn 	addr = printop(addr);
12733318Sdonn     }
12833318Sdonn     prtaddr = addr;
12933318Sdonn }
13033318Sdonn 
13133318Sdonn /*
13233318Sdonn  * Another approach:  print n instructions starting at the given address.
13333318Sdonn  */
13433318Sdonn 
13533318Sdonn public printninst(count, addr)
13633318Sdonn int count;
13733318Sdonn Address addr;
13833318Sdonn {
13933318Sdonn     register Integer i;
14033318Sdonn     register Address newaddr;
14133318Sdonn 
14233318Sdonn     if (count <= 0) {
14333318Sdonn 	error("non-positive repetition count");
14433318Sdonn     } else {
14533318Sdonn 	newaddr = addr;
14633318Sdonn 	for (i = 0; i < count; i++) {
14733318Sdonn 	    newaddr = printop(newaddr);
14833318Sdonn 	}
14933318Sdonn 	prtaddr = newaddr;
15033318Sdonn     }
15133318Sdonn }
15233318Sdonn 
15333318Sdonn /*
15433318Sdonn  * Print the contents of the addresses within the given range
15533318Sdonn  * according to the given format.
15633318Sdonn  */
15733318Sdonn 
15833318Sdonn typedef struct {
15933318Sdonn     String name;
16033318Sdonn     String printfstring;
16133318Sdonn     int length;
16233318Sdonn } Format;
16333318Sdonn 
16433318Sdonn private Format fmt[] = {
16533318Sdonn     { "d", " %d", sizeof(short) },
16633318Sdonn     { "D", " %ld", sizeof(long) },
16733318Sdonn     { "o", " %o", sizeof(short) },
16833318Sdonn     { "O", " %lo", sizeof(long) },
16933318Sdonn     { "x", " %04x", sizeof(short) },
17033318Sdonn     { "X", " %08x", sizeof(long) },
17133318Sdonn     { "b", " \\%o", sizeof(char) },
17233318Sdonn     { "c", " '%c'", sizeof(char) },
17333318Sdonn     { "s", "%c", sizeof(char) },
17433318Sdonn     { "f", " %f", sizeof(float) },
17533318Sdonn     { "g", " %g", sizeof(double) },
17633318Sdonn     { nil, nil, 0 }
17733318Sdonn };
17833318Sdonn 
17933318Sdonn private Format *findformat(s)
18033318Sdonn String s;
18133318Sdonn {
18233318Sdonn     register Format *f;
18333318Sdonn 
18433318Sdonn     f = &fmt[0];
18533318Sdonn     while (f->name != nil and not streq(f->name, s)) {
18633318Sdonn 	++f;
18733318Sdonn     }
18833318Sdonn     if (f->name == nil) {
18933318Sdonn 	error("bad print format \"%s\"", s);
19033318Sdonn     }
19133318Sdonn     return f;
19233318Sdonn }
19333318Sdonn 
19433318Sdonn /*
19533318Sdonn  * Retrieve and print out the appropriate data in the given format.
19633318Sdonn  * Floats have to be handled specially to allow the compiler to
19733318Sdonn  * convert them to doubles when passing to printf.
19833318Sdonn  */
19933318Sdonn 
20033318Sdonn private printformat (f, addr)
20133318Sdonn Format *f;
20233318Sdonn Address addr;
20333318Sdonn {
20433318Sdonn     union {
20533318Sdonn 	char charv;
20633318Sdonn 	short shortv;
20733318Sdonn 	int intv;
20833318Sdonn 	float floatv;
20933318Sdonn 	double doublev;
21033318Sdonn     } value;
21133318Sdonn 
21233318Sdonn     value.intv = 0;
21333318Sdonn     dread(&value, addr, f->length);
21433318Sdonn     if (streq(f->name, "f")) {
21533318Sdonn 	printf(f->printfstring, value.floatv);
21633318Sdonn     } else {
21733318Sdonn 	printf(f->printfstring, value);
21833318Sdonn     }
21933318Sdonn }
22033318Sdonn 
22133318Sdonn public Address printdata(lowaddr, highaddr, format)
22233318Sdonn Address lowaddr;
22333318Sdonn Address highaddr;
22433318Sdonn String format;
22533318Sdonn {
22633318Sdonn     int n;
22733318Sdonn     register Address addr;
22833318Sdonn     Format *f;
22933318Sdonn 
23033318Sdonn     if (lowaddr > highaddr) {
23133318Sdonn 	error("first address larger than second");
23233318Sdonn     }
23333318Sdonn     f = findformat(format);
23433318Sdonn     n = 0;
23533318Sdonn     for (addr = lowaddr; addr <= highaddr; addr += f->length) {
23633318Sdonn 	if (n == 0) {
23733318Sdonn 	    printf("%08x: ", addr);
23833318Sdonn 	}
23933318Sdonn 	printformat(f, addr);
24033318Sdonn 	++n;
24133318Sdonn 	if (n >= (16 div f->length)) {
24233318Sdonn 	    printf("\n");
24333318Sdonn 	    n = 0;
24433318Sdonn 	}
24533318Sdonn     }
24633318Sdonn     if (n != 0) {
24733318Sdonn 	printf("\n");
24833318Sdonn     }
24933318Sdonn     prtaddr = addr;
25033318Sdonn     return addr;
25133318Sdonn }
25233318Sdonn 
25333318Sdonn /*
25433318Sdonn  * The other approach is to print n items starting with a given address.
25533318Sdonn  */
25633318Sdonn 
25733318Sdonn public printndata(count, startaddr, format)
25833318Sdonn int count;
25933318Sdonn Address startaddr;
26033318Sdonn String format;
26133318Sdonn {
26233318Sdonn     int i, n;
26333318Sdonn     Address addr;
26433318Sdonn     Format *f;
26533318Sdonn     Boolean isstring;
26633318Sdonn     char c;
26733318Sdonn 
26833318Sdonn     if (count <= 0) {
26933318Sdonn 	error("non-positive repetition count");
27033318Sdonn     }
27133318Sdonn     f = findformat(format);
27233318Sdonn     isstring = (Boolean) streq(f->name, "s");
27333318Sdonn     n = 0;
27433318Sdonn     addr = startaddr;
27533318Sdonn     for (i = 0; i < count; i++) {
27633318Sdonn 	if (n == 0) {
27733318Sdonn 	    printf("%08x: ", addr);
27833318Sdonn 	}
27933318Sdonn 	if (isstring) {
28033318Sdonn 	    printf("\"");
28133318Sdonn 	    dread(&c, addr, sizeof(char));
28233318Sdonn 	    while (c != '\0') {
28333318Sdonn 		printchar(c);
28433318Sdonn 		++addr;
28533318Sdonn 		dread(&c, addr, sizeof(char));
28633318Sdonn 	    }
28733318Sdonn 	    printf("\"\n");
28833318Sdonn 	    n = 0;
28933318Sdonn 	    addr += sizeof(String);
29033318Sdonn 	} else {
29133318Sdonn 	    printformat(f, addr);
29233318Sdonn 	    ++n;
29333318Sdonn 	    if (n >= (16 div f->length)) {
29433318Sdonn 		printf("\n");
29533318Sdonn 		n = 0;
29633318Sdonn 	    }
29733318Sdonn 	    addr += f->length;
29833318Sdonn 	}
29933318Sdonn     }
30033318Sdonn     if (n != 0) {
30133318Sdonn 	printf("\n");
30233318Sdonn     }
30333318Sdonn     prtaddr = addr;
30433318Sdonn }
30533318Sdonn 
30633318Sdonn /*
30733318Sdonn  * Print out a value according to the given format.
30833318Sdonn  */
30933318Sdonn 
31033318Sdonn public printvalue(v, format)
31133318Sdonn long v;
31233318Sdonn String format;
31333318Sdonn {
31433318Sdonn     Format *f;
31533318Sdonn     char *p, *q;
31633318Sdonn 
31733318Sdonn     f = findformat(format);
31833318Sdonn     if (streq(f->name, "s")) {
31933318Sdonn 	putchar('"');
32033318Sdonn 	p = (char *) &v;
32133318Sdonn 	q = p + sizeof(v);
32233318Sdonn 	while (p < q) {
32333318Sdonn 	    printchar(*p);
32433318Sdonn 	    ++p;
32533318Sdonn 	}
32633318Sdonn 	putchar('"');
32733318Sdonn     } else {
32833318Sdonn 	printf(f->printfstring, v);
32933318Sdonn     }
33033318Sdonn     putchar('\n');
33133318Sdonn }
33233318Sdonn 
33333318Sdonn /*
33433318Sdonn  * Print out an execution time error.
33533318Sdonn  * Assumes the source position of the error has been calculated.
33633318Sdonn  *
33733318Sdonn  * Have to check if the -r option was specified; if so then
33833318Sdonn  * the object file information hasn't been read in yet.
33933318Sdonn  */
34033318Sdonn 
34133318Sdonn public printerror()
34233318Sdonn {
34333318Sdonn     extern Integer sys_nsig;
34433318Sdonn     extern String sys_siglist[];
34533318Sdonn     integer err;
34633318Sdonn 
34733318Sdonn     if (isfinished(process)) {
34833318Sdonn 	err = exitcode(process);
34933318Sdonn 	if (err == 0) {
35033318Sdonn 	    printf("\"%s\" terminated normally\n", objname);
35133318Sdonn 	} else {
35233318Sdonn 	    printf("\"%s\" terminated abnormally (exit code %d)\n",
35333318Sdonn 		objname, err
35433318Sdonn 	    );
35533318Sdonn 	}
35633318Sdonn 	erecover();
35733318Sdonn     }
35833318Sdonn     err = errnum(process);
35933318Sdonn     putchar('\n');
36033318Sdonn     printsig(err);
36133318Sdonn     putchar(' ');
36233318Sdonn     printloc();
36333318Sdonn     putchar('\n');
36433318Sdonn     if (curline > 0) {
36533318Sdonn 	printlines(curline, curline);
36633318Sdonn     } else {
36733318Sdonn 	printinst(pc, pc);
36833318Sdonn     }
36933318Sdonn     erecover();
37033318Sdonn }
37133318Sdonn 
37233318Sdonn /*
37333318Sdonn  * Print out a signal.
37433318Sdonn  */
37533318Sdonn 
37633318Sdonn private String illinames[] = {
37733318Sdonn     "reserved addressing fault",
37833318Sdonn     "privileged instruction fault",
37933318Sdonn     "reserved operand fault"
38033318Sdonn };
38133318Sdonn 
38233318Sdonn private String fpenames[] = {
38333318Sdonn     nil,
38433318Sdonn     "integer overflow trap",
38533318Sdonn     "integer divide by zero trap",
38633318Sdonn     "floating overflow trap",
38733318Sdonn     "floating/decimal divide by zero trap",
38833318Sdonn     "floating underflow trap",
38933318Sdonn     "decimal overflow trap",
39033318Sdonn     "subscript out of range trap",
39133318Sdonn     "floating overflow fault",
39233318Sdonn     "floating divide by zero fault",
39333318Sdonn     "floating underflow fault"
39433318Sdonn };
39533318Sdonn 
39633318Sdonn public printsig (signo)
39733318Sdonn integer signo;
39833318Sdonn {
39933318Sdonn     integer code;
40033318Sdonn 
40133318Sdonn     if (signo < 0 or signo > sys_nsig) {
40233318Sdonn 	printf("[signal %d]", signo);
40333318Sdonn     } else {
40433318Sdonn 	printf("%s", sys_siglist[signo]);
40533318Sdonn     }
40633318Sdonn     code = errcode(process);
40733318Sdonn     if (signo == SIGILL) {
40833318Sdonn 	if (code >= 0 and code < sizeof(illinames) / sizeof(illinames[0])) {
40933318Sdonn 	    printf(" (%s)", illinames[code]);
41033318Sdonn 	}
41133318Sdonn     } else if (signo == SIGFPE) {
41233318Sdonn 	if (code > 0 and code < sizeof(fpenames) / sizeof(fpenames[0])) {
41333318Sdonn 	    printf(" (%s)", fpenames[code]);
41433318Sdonn 	}
41533318Sdonn     }
41633318Sdonn }
41733318Sdonn 
41833318Sdonn /*
41933318Sdonn  * Note the termination of the program.  We do this so as to avoid
42033318Sdonn  * having the process exit, which would make the values of variables
42133318Sdonn  * inaccessible.  We do want to flush all output buffers here,
42233318Sdonn  * otherwise it'll never get done.
42333318Sdonn  */
42433318Sdonn 
42533318Sdonn public endprogram()
42633318Sdonn {
42733318Sdonn     Integer exitcode;
42833318Sdonn 
42933318Sdonn     stepto(nextaddr(pc, true));
43033318Sdonn     printnews();
43133318Sdonn     exitcode = argn(1, nil);
43233318Sdonn     if (exitcode != 0) {
43333318Sdonn 	printf("\nexecution completed (exit code %d)\n", exitcode);
43433318Sdonn     } else {
43533318Sdonn 	printf("\nexecution completed\n");
43633318Sdonn     }
43733318Sdonn     getsrcpos();
43833318Sdonn     erecover();
43933318Sdonn }
44033318Sdonn 
44133318Sdonn /*
44233318Sdonn  * Single step the machine a source line (or instruction if "inst_tracing"
44333318Sdonn  * is true).  If "isnext" is true, skip over procedure calls.
44433318Sdonn  */
44533318Sdonn 
44633318Sdonn private Address getcall();
44733318Sdonn 
44833318Sdonn public dostep(isnext)
44933318Sdonn Boolean isnext;
45033318Sdonn {
45133318Sdonn     register Address addr;
45233318Sdonn     register Lineno line;
45333318Sdonn     String filename;
45433318Sdonn     Address startaddr;
45533318Sdonn 
45633318Sdonn     startaddr = pc;
45733318Sdonn     addr = nextaddr(pc, isnext);
45833318Sdonn     if (not inst_tracing and nlhdr.nlines != 0) {
45933318Sdonn 	line = linelookup(addr);
46033318Sdonn 	while (line == 0) {
46133318Sdonn 	    addr = nextaddr(addr, isnext);
46233318Sdonn 	    line = linelookup(addr);
46333318Sdonn 	}
46433318Sdonn 	curline = line;
46533318Sdonn     } else {
46633318Sdonn 	curline = 0;
46733318Sdonn     }
46833318Sdonn     stepto(addr);
46933318Sdonn     filename = srcfilename(addr);
47033318Sdonn     setsource(filename);
47133318Sdonn }
47233318Sdonn 
47333318Sdonn typedef short Bpinst;
47433318Sdonn 
47533318Sdonn extern Bpinst BP_OP;
47633318Sdonn #ifdef sun
47733318Sdonn 	asm("_BP_OP: trap #15");
47833318Sdonn #else /* IRIS */
47933318Sdonn 	asm("_BP_OP: trap #1");
48033318Sdonn #endif
48133318Sdonn 
48233318Sdonn #define BP_ERRNO    SIGTRAP     /* signal received at a breakpoint */
48333318Sdonn 
48433318Sdonn /*
48533318Sdonn  * Setting a breakpoint at a location consists of saving
48633318Sdonn  * the word at the location and poking a BP_OP there.
48733318Sdonn  *
48833318Sdonn  * We save the locations and words on a list for use in unsetting.
48933318Sdonn  */
49033318Sdonn 
49133318Sdonn typedef struct Savelist *Savelist;
49233318Sdonn 
49333318Sdonn struct Savelist {
49433318Sdonn     Address location;
49533318Sdonn     Bpinst save;
49633318Sdonn     short refcount;
49733318Sdonn     Savelist link;
49833318Sdonn };
49933318Sdonn 
50033318Sdonn private Savelist savelist;
50133318Sdonn 
50233318Sdonn /*
50333318Sdonn  * Set a breakpoint at the given address.  Only save the word there
50433318Sdonn  * if it's not already a breakpoint.
50533318Sdonn  */
50633318Sdonn 
50733318Sdonn public setbp(addr)
50833318Sdonn Address addr;
50933318Sdonn {
51033318Sdonn     Bpinst w, save;
51133318Sdonn     register Savelist newsave, s;
51233318Sdonn 
51333318Sdonn     for (s = savelist; s != nil; s = s->link) {
51433318Sdonn 	if (s->location == addr) {
51533318Sdonn 	    s->refcount++;
51633318Sdonn 	    return;
51733318Sdonn 	}
51833318Sdonn     }
51933318Sdonn     iread(&save, addr, sizeof(save));
52033318Sdonn     newsave = new(Savelist);
52133318Sdonn     newsave->location = addr;
52233318Sdonn     newsave->save = save;
52333318Sdonn     newsave->refcount = 1;
52433318Sdonn     newsave->link = savelist;
52533318Sdonn     savelist = newsave;
52633318Sdonn     w = BP_OP;
52733318Sdonn     iwrite(&w, addr, sizeof(w));
52833318Sdonn }
52933318Sdonn 
53033318Sdonn /*
53133318Sdonn  * Unset a breakpoint; unfortunately we have to search the SAVELIST
53233318Sdonn  * to find the saved value.  The assumption is that the SAVELIST will
53333318Sdonn  * usually be quite small.
53433318Sdonn  */
53533318Sdonn 
53633318Sdonn public unsetbp(addr)
53733318Sdonn Address addr;
53833318Sdonn {
53933318Sdonn     register Savelist s, prev;
54033318Sdonn 
54133318Sdonn     prev = nil;
54233318Sdonn     for (s = savelist; s != nil; s = s->link) {
54333318Sdonn 	if (s->location == addr) {
54433318Sdonn 	    iwrite(&s->save, addr, sizeof(s->save));
54533318Sdonn 	    s->refcount--;
54633318Sdonn 	    if (s->refcount == 0) {
54733318Sdonn 		if (prev == nil) {
54833318Sdonn 		    savelist = s->link;
54933318Sdonn 		} else {
55033318Sdonn 		    prev->link = s->link;
55133318Sdonn 		}
55233318Sdonn 		dispose(s);
55333318Sdonn 	    }
55433318Sdonn 	    return;
55533318Sdonn 	}
55633318Sdonn 	prev = s;
55733318Sdonn     }
55833318Sdonn     panic("unsetbp: couldn't find address %d", addr);
55933318Sdonn }
56033318Sdonn 
56133318Sdonn /*
56233318Sdonn  * Instruction decoding routines for 68000, derived from adb.
56333318Sdonn  *
56433318Sdonn  * The shared boolean variable "printing" is true if the decoded
56533318Sdonn  * instruction is to be printed, false if not.  In either case,
56633318Sdonn  * the address of the next instruction after the given one is returned.
56733318Sdonn  */
56833318Sdonn 
56933318Sdonn private Boolean printing;
57033318Sdonn private Boolean following;
57133318Sdonn private Boolean followcalls;
57233318Sdonn private Address instaddr;
57333318Sdonn 
57433318Sdonn #define instread(var) \
57533318Sdonn { \
57633318Sdonn     iread(&var, instaddr, sizeof(var)); \
57733318Sdonn     instaddr += sizeof(var); \
57833318Sdonn }
57933318Sdonn 
58033318Sdonn private Optab *decode(inst, addr)
58133318Sdonn Word inst;
58233318Sdonn Address addr;
58333318Sdonn {
58433318Sdonn     register Optab *o;
58533318Sdonn 
58633318Sdonn     o = &optab[0];
58733318Sdonn     while (o->mask != 0 and (inst&o->mask) != o->match) {
58833318Sdonn 	++o;
58933318Sdonn     }
59033318Sdonn     return o;
59133318Sdonn }
59233318Sdonn 
59333318Sdonn private Address printop(addr)
59433318Sdonn Address addr;
59533318Sdonn {
59633318Sdonn     Optab *o;
59733318Sdonn     short inst;
59833318Sdonn 
59933318Sdonn     printf("%08x  ", addr);
60033318Sdonn     iread(&inst, addr, sizeof(inst));
60133318Sdonn     o = decode(inst, addr);
60233318Sdonn     if (o->mask == 0) {
60333318Sdonn 	printf("\tbadop");
60433318Sdonn 	instaddr = addr + sizeof(inst);
60533318Sdonn     } else {
60633318Sdonn 	printing = true;
60733318Sdonn 	following = false;
60833318Sdonn 	instaddr = addr + sizeof(inst);
60933318Sdonn 	(*o->opfun)(inst, o->farg);
61033318Sdonn 	printing = false;
61133318Sdonn     }
61233318Sdonn     printf("\n");
61333318Sdonn     return instaddr;
61433318Sdonn }
61533318Sdonn 
61633318Sdonn /*
61733318Sdonn  * Quickly find the return address of the current procedure or function
61833318Sdonn  * while single stepping.  Just get the word pointed at by sp.
61933318Sdonn  */
62033318Sdonn 
62133318Sdonn private Address currtnaddr ()
62233318Sdonn {
62333318Sdonn     Address retaddr;
62433318Sdonn 
62533318Sdonn     dread(&retaddr, reg(STKP), sizeof(retaddr));
62633318Sdonn     return retaddr;
62733318Sdonn }
62833318Sdonn 
62933318Sdonn /*
63033318Sdonn  * Print out the effective address for the given parameters.
63133318Sdonn  */
63233318Sdonn 
63333318Sdonn private printea(mode, reg, size)
63433318Sdonn long mode, reg;
63533318Sdonn int size;
63633318Sdonn {
63733318Sdonn     long index, disp;
63833318Sdonn     static char *aregs[] = { "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp" };
63933318Sdonn     Byte b;
64033318Sdonn     short w;
64133318Sdonn     long l;
64233318Sdonn 
64333318Sdonn     switch ((int)(mode)) {
64433318Sdonn 	case 0:
64533318Sdonn 	    if (printing) {
64633318Sdonn 		printf("d%D", reg);
64733318Sdonn 	    }
64833318Sdonn 	    break;
64933318Sdonn 
65033318Sdonn 	case 1:
65133318Sdonn 	    if (printing) {
65233318Sdonn 		printf("%s", aregs[reg]);
65333318Sdonn 	    }
65433318Sdonn 	    break;
65533318Sdonn 
65633318Sdonn 	case 2:
65733318Sdonn 	    if (printing) {
65833318Sdonn 		printf("%s@", aregs[reg]);
65933318Sdonn 	    }
66033318Sdonn 	    break;
66133318Sdonn 
66233318Sdonn 	case 3:
66333318Sdonn 	    if (printing) {
66433318Sdonn 		printf("%s@+", aregs[reg]);
66533318Sdonn 	    }
66633318Sdonn 	    break;
66733318Sdonn 
66833318Sdonn 	case 4:
66933318Sdonn 	    if (printing) {
67033318Sdonn 		printf("%s@-", aregs[reg]);
67133318Sdonn 	    }
67233318Sdonn 	    break;
67333318Sdonn 
67433318Sdonn 	case 5:
67533318Sdonn 	    instread(w);
67633318Sdonn 	    if (printing) {
67733318Sdonn 		printf("%s@(%D)", aregs[reg], w);
67833318Sdonn 	    }
67933318Sdonn 	    break;
68033318Sdonn 
68133318Sdonn 	case 6:
68233318Sdonn 	    instread(w);
68333318Sdonn 	    if (printing) {
68433318Sdonn 		index = w;
68533318Sdonn 		disp = (char)(index&0377);
68633318Sdonn 		printf("%s@(%d,%c%D:%c)", aregs[reg], disp,
68733318Sdonn 		    (index&0100000)?'a':'d',(index>>12)&07,
68833318Sdonn 		    (index&04000)?'l':'w');
68933318Sdonn 	    }
69033318Sdonn 	    break;
69133318Sdonn 
69233318Sdonn 	case 7:
69333318Sdonn 	    switch ((int)(reg)) {
69433318Sdonn 		case 0:
69533318Sdonn 		    instread(w);
69633318Sdonn 		    if (printing) {
69733318Sdonn 			index = w;
69833318Sdonn 			psymoff(index);
69933318Sdonn 		    }
70033318Sdonn 		    break;
70133318Sdonn 
70233318Sdonn 		case 1:
70333318Sdonn 		    instread(l);
70433318Sdonn 		    if (printing) {
70533318Sdonn 			index = l;
70633318Sdonn 			psymoff(index);
70733318Sdonn 		    }
70833318Sdonn 		    break;
70933318Sdonn 
71033318Sdonn 		case 2:
71133318Sdonn 		    instread(w);
71233318Sdonn 		    if (printing) {
71333318Sdonn 			disp = w;
71433318Sdonn 			psymoff(disp + instaddr);
71533318Sdonn 		    }
71633318Sdonn 		    break;
71733318Sdonn 
71833318Sdonn 		case 3:
71933318Sdonn 		    instread(w);
72033318Sdonn 		    if (printing) {
72133318Sdonn 			index = w;
72233318Sdonn 			disp = (char)(index&0377);
72333318Sdonn 			printf("pc@(%D,%c%D:%c)", disp,
72433318Sdonn 			    (index&0100000)?'a':'d',(index>>12)&07,
72533318Sdonn 			    (index&04000)?'l':'w');
72633318Sdonn 		    }
72733318Sdonn 		    break;
72833318Sdonn 
72933318Sdonn 		case 4:
73033318Sdonn 		    switch (size) {
73133318Sdonn 			case sizeof(b):
73233318Sdonn 			    instread(w);
73333318Sdonn 			    index = (w&0xff);
73433318Sdonn 			    break;
73533318Sdonn 
73633318Sdonn 			case sizeof(w):
73733318Sdonn 			    instread(w);
73833318Sdonn 			    index = w;
73933318Sdonn 			    break;
74033318Sdonn 
74133318Sdonn 			case sizeof(l):
74233318Sdonn 			    instread(l);
74333318Sdonn 			    index = l;
74433318Sdonn 			    break;
74533318Sdonn 
74633318Sdonn 			default:
74733318Sdonn 			    if (printing) {
74833318Sdonn 			    	printf("unexpected size %d in printea\n", size);
74933318Sdonn 			    }
75033318Sdonn 			    instread(l);
75133318Sdonn 			    index = l;
75233318Sdonn 			    break;
75333318Sdonn 		    }
75433318Sdonn 		    if (printing) {
75533318Sdonn 			printf(IMDF, index);
75633318Sdonn 		    }
75733318Sdonn 		    break;
75833318Sdonn 
75933318Sdonn 		default:
76033318Sdonn 		    if (printing) {
76133318Sdonn 			printf("???");
76233318Sdonn 		    }
76333318Sdonn 		    break;
76433318Sdonn 	    }
76533318Sdonn 	    break;
76633318Sdonn 
76733318Sdonn 	default:
76833318Sdonn 	    if (printing) {
76933318Sdonn 		printf("???");
77033318Sdonn 	    }
77133318Sdonn 	    break;
77233318Sdonn     }
77333318Sdonn }
77433318Sdonn 
77533318Sdonn private printEA(ea, size)
77633318Sdonn long ea;
77733318Sdonn int size;
77833318Sdonn {
77933318Sdonn     printea((ea>>3)&07, ea&07, size);
78033318Sdonn }
78133318Sdonn 
78233318Sdonn private mapsize(inst)
78333318Sdonn register long inst;
78433318Sdonn {
78533318Sdonn     int m;
78633318Sdonn 
78733318Sdonn     inst >>= 6;
78833318Sdonn     inst &= 03;
78933318Sdonn     switch (inst) {
79033318Sdonn 	case 0:
79133318Sdonn 	    m = 1;
79233318Sdonn 	    break;
79333318Sdonn 
79433318Sdonn 	case 1:
79533318Sdonn 	    m = 2;
79633318Sdonn 	    break;
79733318Sdonn 
79833318Sdonn 	case 2:
79933318Sdonn 	    m = 4;
80033318Sdonn 	    break;
80133318Sdonn 
80233318Sdonn 	default:
80333318Sdonn 	    m = -1;
80433318Sdonn 	    break;
80533318Sdonn     }
80633318Sdonn     return m;
80733318Sdonn }
80833318Sdonn 
80933318Sdonn private char suffix(size)
81033318Sdonn int size;
81133318Sdonn {
81233318Sdonn     char c;
81333318Sdonn 
81433318Sdonn     switch (size) {
81533318Sdonn 	case 1:
81633318Sdonn 	    c = 'b';
81733318Sdonn 	    break;
81833318Sdonn 
81933318Sdonn 	case 2:
82033318Sdonn 	    c = 'w';
82133318Sdonn 	    break;
82233318Sdonn 
82333318Sdonn 	case 4:
82433318Sdonn 	    c = 'l';
82533318Sdonn 	    break;
82633318Sdonn 
82733318Sdonn 	default:
82833318Sdonn 	    panic("bad size %d in suffix", size);
82933318Sdonn     }
83033318Sdonn     return c;
83133318Sdonn }
83233318Sdonn 
83333318Sdonn /*
83433318Sdonn  * Print an address offset.  Eventually this should attempt to be symbolic,
83533318Sdonn  * but for now its just printed in hex.
83633318Sdonn  */
83733318Sdonn 
83833318Sdonn private psymoff (off)
83933318Sdonn Word off;
84033318Sdonn {
84133318Sdonn     Symbol f;
84233318Sdonn 
84333318Sdonn     f = whatblock((Address) (off + FUNCOFFSET));
84433318Sdonn     if (codeloc(f) == off + FUNCOFFSET) {
84533318Sdonn 	printf("%s", symname(f));
84633318Sdonn     } else {
84733318Sdonn 	printf("0x%x", off);
84833318Sdonn     }
84933318Sdonn }
85033318Sdonn 
85133318Sdonn /*
85233318Sdonn  * Instruction class specific routines.
85333318Sdonn  */
85433318Sdonn 
85533318Sdonn public omove(inst, s)
85633318Sdonn long inst;
85733318Sdonn String s;
85833318Sdonn {
85933318Sdonn     register int c;
86033318Sdonn     int size;
86133318Sdonn 
86233318Sdonn     c = s[0];
86333318Sdonn     if (printing) {
86433318Sdonn 	printf("\tmov%c\t", c);
86533318Sdonn     }
86633318Sdonn     size = ((c == 'b') ? 1 : (c == 'w') ? 2 : 4);
86733318Sdonn     printea((inst>>3)&07, inst&07, size);
86833318Sdonn     if (printing) {
86933318Sdonn 	printf(",");
87033318Sdonn     }
87133318Sdonn     printea((inst>>6)&07, (inst>>9)&07, size);
87233318Sdonn }
87333318Sdonn 
87433318Sdonn /*
87533318Sdonn  * Two types: bsr (4 bytes) and bsrs (2 bytes)
87633318Sdonn  */
87733318Sdonn 
87833318Sdonn public obranch(inst, dummy)
87933318Sdonn long inst;
88033318Sdonn {
88133318Sdonn     long disp;
88233318Sdonn     String s;
88333318Sdonn     short w;
88433318Sdonn     Address startingaddr;	/* address of branch instruction */
88533318Sdonn     int branchtype;		/* type of branch (0 = unconditional) */
88633318Sdonn     Address dest;
88733318Sdonn     Address retaddr;		/* for bsr instruction */
88833318Sdonn 
88933318Sdonn     startingaddr = instaddr - 2;
89033318Sdonn     disp = inst&0377;
89133318Sdonn     s = "s ";
89233318Sdonn     if (disp == 0) {
89333318Sdonn 	retaddr = startingaddr + 4;
89433318Sdonn     } else {
89533318Sdonn 	retaddr = startingaddr + 2;
89633318Sdonn     }
89733318Sdonn     if (disp > 127) {
89833318Sdonn 	disp |= ~0377;
89933318Sdonn     } else if (disp == 0){
90033318Sdonn 	s = " ";
90133318Sdonn 	instread(w);
90233318Sdonn 	disp = w;
90333318Sdonn     }
90433318Sdonn     branchtype = (int)((inst>>8)&017);
90533318Sdonn     dest = startingaddr + 2 + disp;
90633318Sdonn     if (printing) {
90733318Sdonn 	printf("\tb%s%s\t", bname[branchtype], s);
90833318Sdonn 	psymoff(dest);
90933318Sdonn     }
91033318Sdonn     if (following) {
91133318Sdonn 	/*
91233318Sdonn 	 * If we're to follow the dynamic flow of instructions,
91333318Sdonn 	 * we must see where the branch leads.  A branchtype of 0
91433318Sdonn 	 * indicates an unconditional branch which we simply take
91533318Sdonn 	 * as the new instruction address.  For a conditional branch,
91633318Sdonn 	 * we continue execution up to the current address, single step,
91733318Sdonn 	 * and keep going.
91833318Sdonn 	 */
91933318Sdonn 	if (branchtype == 0) {
92033318Sdonn 	    instaddr = dest;
92133318Sdonn 	} else if (branchtype == 01) {		/* bsr */
92233318Sdonn 	    if (followcalls) {
92333318Sdonn 		steppast(startingaddr);
92433318Sdonn 		curfunc = whatblock(pc, true);
92533318Sdonn 		if (not isbperr()) {
92633318Sdonn 		    printstatus();
92733318Sdonn 		    /* NOTREACHED */
92833318Sdonn 		}
92933318Sdonn 		bpact();
93033318Sdonn 		if (nosource(curfunc) and canskip(curfunc) and
93133318Sdonn 		  nlhdr.nlines != 0) {
93233318Sdonn 		    stepto(retaddr);
93333318Sdonn 		    instaddr = pc;
93433318Sdonn 		    bpact();
93533318Sdonn 		} else {
93633318Sdonn 		    callnews(/* iscall = */ true);
93733318Sdonn 		}
93833318Sdonn 	    }
93933318Sdonn 	} else {
94033318Sdonn 	    steppast(startingaddr);
94133318Sdonn 	}
94233318Sdonn     }
94333318Sdonn }
94433318Sdonn 
94533318Sdonn public odbcc(inst, form)
94633318Sdonn long inst;
94733318Sdonn String form;
94833318Sdonn {
94933318Sdonn     long disp;
95033318Sdonn     short w;
95133318Sdonn 
95233318Sdonn     instread(w);
95333318Sdonn     if (printing) {
95433318Sdonn     	printf(form, dbname[(int)((inst>>8)&017)], inst&07);
95533318Sdonn 	psymoff(w + sizeof(w));
95633318Sdonn     }
95733318Sdonn }
95833318Sdonn 
95933318Sdonn public oscc(inst, dummy)
96033318Sdonn long inst;
96133318Sdonn long dummy;
96233318Sdonn {
96333318Sdonn     if (printing) {
96433318Sdonn 	printf("\ts%s\t", cname[(int)((inst>>8)&017)]);
96533318Sdonn     }
96633318Sdonn     printea((inst>>3)&07, inst&07, 1);
96733318Sdonn }
96833318Sdonn 
96933318Sdonn public biti(inst, dummy)
97033318Sdonn long inst;
97133318Sdonn long dummy;
97233318Sdonn {
97333318Sdonn     short w;
97433318Sdonn 
97533318Sdonn     if (printing) {
97633318Sdonn 	printf("\t%s\t", bit[(int)((inst>>6)&03)]);
97733318Sdonn     }
97833318Sdonn     if (inst&0x0100) {
97933318Sdonn 	if (printing) {
98033318Sdonn 	    printf("d%D,", inst>>9);
98133318Sdonn 	}
98233318Sdonn     } else {
98333318Sdonn 	instread(w);
98433318Sdonn 	if (printing) {
98533318Sdonn 	    printf(IMDF, w);
98633318Sdonn 	    printf(",");
98733318Sdonn 	}
98833318Sdonn     }
98933318Sdonn     printEA(inst);
99033318Sdonn }
99133318Sdonn 
99233318Sdonn public opmode(inst, opcode)
99333318Sdonn long inst;
99433318Sdonn long opcode;
99533318Sdonn {
99633318Sdonn     register int opmode;
99733318Sdonn     register int reg;
99833318Sdonn     int size;
99933318Sdonn 
100033318Sdonn     opmode = (int)((inst>>6) & 07);
100133318Sdonn     reg = (int)((inst>>9) & 07);
100233318Sdonn     if (opmode == 0 or opmode == 4) {
100333318Sdonn 	size = 1;
100433318Sdonn     } else if (opmode == 1 or opmode == 3 or opmode == 5) {
100533318Sdonn 	size = 2;
100633318Sdonn     } else {
100733318Sdonn 	size = 4;
100833318Sdonn     }
100933318Sdonn     if (printing) {
101033318Sdonn 	printf("\t%s%c\t", opcode, suffix(size));
101133318Sdonn     }
101233318Sdonn     if (opmode >= 4 and opmode <= 6) {
101333318Sdonn 	if (printing) {
101433318Sdonn 	    printf("d%d,", reg);
101533318Sdonn 	}
101633318Sdonn 	printea((inst>>3)&07, inst&07, size);
101733318Sdonn     } else {
101833318Sdonn 	printea((inst>>3)&07, inst&07, size);
101933318Sdonn 	if (printing) {
102033318Sdonn 	    printf(",%c%d",(opmode<=2) ? 'd' : 'a', reg);
102133318Sdonn 	}
102233318Sdonn     }
102333318Sdonn }
102433318Sdonn 
102533318Sdonn public shroi(inst, ds)
102633318Sdonn long inst;
102733318Sdonn String ds;
102833318Sdonn {
102933318Sdonn     int rx, ry;
103033318Sdonn     String opcode;
103133318Sdonn 
103233318Sdonn     if ((inst & 0xC0) == 0xC0) {
103333318Sdonn 	opcode = shro[(int)((inst>>9)&03)];
103433318Sdonn 	if (printing) {
103533318Sdonn 	    printf("\t%s%s\t", opcode, ds);
103633318Sdonn 	}
103733318Sdonn 	printEA(inst);
103833318Sdonn     } else {
103933318Sdonn 	if (printing) {
104033318Sdonn 	    opcode = shro[(int)((inst>>3)&03)];
104133318Sdonn 	    printf("\t%s%s%c\t", opcode, ds, suffix(mapsize(inst)));
104233318Sdonn 	    rx = (int)((inst>>9)&07); ry = (int)(inst&07);
104333318Sdonn 	    if ((inst>>5)&01) {
104433318Sdonn 		printf("d%d,d%d", rx, ry);
104533318Sdonn 	    } else {
104633318Sdonn 		printf(IMDF, (rx ? rx : 8));
104733318Sdonn 		printf(",d%d", ry);
104833318Sdonn 	    }
104933318Sdonn 	}
105033318Sdonn     }
105133318Sdonn }
105233318Sdonn 
105333318Sdonn public oimmed(inst, opcode)
105433318Sdonn long inst;
105533318Sdonn register String opcode;
105633318Sdonn {
105733318Sdonn     register int size;
105833318Sdonn     long const;
105933318Sdonn     short w;
106033318Sdonn 
106133318Sdonn     size = mapsize(inst);
106233318Sdonn     if (size > 0) {
106333318Sdonn 	if (size == 4) {
106433318Sdonn 	    instread(const);
106533318Sdonn 	} else {
106633318Sdonn 	    instread(w);
106733318Sdonn 	    const = w;
106833318Sdonn 	}
106933318Sdonn 	if (printing) {
107033318Sdonn 	    printf("\t%s%c\t", opcode, suffix(size));
107133318Sdonn 	    printf(IMDF, const);
107233318Sdonn 	    printf(",");
107333318Sdonn 	}
107433318Sdonn 	printEA(inst, size);
107533318Sdonn     } else {
107633318Sdonn 	if (printing) {
107733318Sdonn 	    printf("\tbadop");
107833318Sdonn 	}
107933318Sdonn     }
108033318Sdonn }
108133318Sdonn 
108233318Sdonn public oreg(inst, opcode)
108333318Sdonn long inst;
108433318Sdonn register String opcode;
108533318Sdonn {
108633318Sdonn     if (printing) {
108733318Sdonn 	printf(opcode, (inst & 07));
108833318Sdonn     }
108933318Sdonn }
109033318Sdonn 
109133318Sdonn public extend(inst, opcode)
109233318Sdonn long inst;
109333318Sdonn String opcode;
109433318Sdonn {
109533318Sdonn     register int size;
109633318Sdonn     int ry, rx;
109733318Sdonn     char c;
109833318Sdonn 
109933318Sdonn     if (printing) {
110033318Sdonn 	size = mapsize(inst);
110133318Sdonn 	ry = (inst&07);
110233318Sdonn 	rx = ((inst>>9)&07);
110333318Sdonn 	c = ((inst & 0x1000) ? suffix(size) : ' ');
110433318Sdonn 	printf("\t%s%c\t", opcode, c);
110533318Sdonn 	if (opcode[0] == 'e') {
110633318Sdonn 	    if (inst & 0x0080) {
110733318Sdonn 		printf("d%D,a%D", rx, ry);
110833318Sdonn 	    } else if (inst & 0x0008) {
110933318Sdonn 		printf("a%D,a%D", rx, ry);
111033318Sdonn 	    } else {
111133318Sdonn 		printf("d%D,d%D", rx, ry);
111233318Sdonn 	    }
111333318Sdonn 	} else if ((inst & 0xF000) == 0xB000) {
111433318Sdonn 	    printf("a%D@+,a%D@+", ry, rx);
111533318Sdonn 	} else if (inst & 0x8) {
111633318Sdonn 	    printf("a%D@-,a%D@-", ry, rx);
111733318Sdonn 	} else {
111833318Sdonn 	    printf("d%D,d%D", ry, rx);
111933318Sdonn 	}
112033318Sdonn     }
112133318Sdonn }
112233318Sdonn 
112333318Sdonn public olink(inst, dummy)
112433318Sdonn long inst;
112533318Sdonn long dummy;
112633318Sdonn {
112733318Sdonn     short w;
112833318Sdonn 
112933318Sdonn     instread(w);
113033318Sdonn     if (printing) {
113133318Sdonn 	printf("\tlink\ta%D,", inst&07);
113233318Sdonn 	printf(IMDF, w);
113333318Sdonn     }
113433318Sdonn }
113533318Sdonn 
113633318Sdonn public otrap(inst, dummy)
113733318Sdonn long inst;
113833318Sdonn {
113933318Sdonn     if (printing) {
114033318Sdonn 	printf("\ttrap\t");
114133318Sdonn 	printf(IMDF, inst&017);
114233318Sdonn     }
114333318Sdonn }
114433318Sdonn 
114533318Sdonn public oneop(inst, opcode)
114633318Sdonn long inst;
114733318Sdonn register String opcode;
114833318Sdonn {
114933318Sdonn     if (printing) {
115033318Sdonn 	printf("\t%s",opcode);
115133318Sdonn     }
115233318Sdonn     printEA(inst);
115333318Sdonn }
115433318Sdonn 
115533318Sdonn public jsrop(inst, opcode)
115633318Sdonn long inst;
115733318Sdonn register String opcode;
115833318Sdonn {
115933318Sdonn     Address startingaddr;	/* beginning of jsr instruction */
116033318Sdonn     Address retaddr; /* can't call return_addr (frame not set up yet) */
116133318Sdonn 
116233318Sdonn     startingaddr = instaddr - 2;
116333318Sdonn     switch ((inst >> 3) & 07) {
116433318Sdonn 	case 2:
116533318Sdonn 	    retaddr = instaddr;		/* two byte instruction */
116633318Sdonn 	    break;
116733318Sdonn 	case 5:
116833318Sdonn 	case 6:
116933318Sdonn 	    retaddr = instaddr + 2;	/* four byte instruction */
117033318Sdonn 	    break;
117133318Sdonn 	case 7:
117233318Sdonn 	default:
117333318Sdonn 	    switch (inst & 07) {
117433318Sdonn 		case 0:
117533318Sdonn 		case 2:
117633318Sdonn 		case 3:
117733318Sdonn 		    retaddr = instaddr + 2;
117833318Sdonn 		    break;
117933318Sdonn 		case 1:
118033318Sdonn 		default:
118133318Sdonn 		    retaddr = instaddr + 4;	/* six byte instruction */
118233318Sdonn 		    break;
118333318Sdonn 	    }
118433318Sdonn 	    break;
118533318Sdonn     }
118633318Sdonn     if (printing) {
118733318Sdonn 	printf("\t%s",opcode);
118833318Sdonn     }
118933318Sdonn     printEA(inst);
119033318Sdonn     if (following and followcalls) {
119133318Sdonn 	steppast(startingaddr);
119233318Sdonn 	curfunc = whatblock(pc, true);
119333318Sdonn 	if (not isbperr()) {
119433318Sdonn 	    printstatus();
119533318Sdonn 	    /* NOTREACHED */
119633318Sdonn 	}
119733318Sdonn 	bpact();
119833318Sdonn 	if (nosource(curfunc) and canskip(curfunc) and nlhdr.nlines != 0) {
119933318Sdonn 	    stepto(retaddr);
120033318Sdonn 	    instaddr = pc;
120133318Sdonn 	    bpact();
120233318Sdonn 	} else {
120333318Sdonn 	    callnews(/* iscall = */ true);
120433318Sdonn 	}
120533318Sdonn     }
120633318Sdonn }
120733318Sdonn 
120833318Sdonn public jmpop(inst, opcode)
120933318Sdonn long inst;
121033318Sdonn register String opcode;
121133318Sdonn {
121233318Sdonn     Address startingaddr;	/* beginning of jump instruction */
121333318Sdonn 
121433318Sdonn     startingaddr = instaddr - 2;
121533318Sdonn     if (printing) {
121633318Sdonn 	printf("\t%s",opcode);
121733318Sdonn     }
121833318Sdonn     printEA(inst);
121933318Sdonn     if (following) {
122033318Sdonn 	steppast(startingaddr);
122133318Sdonn     }
122233318Sdonn }
122333318Sdonn 
122433318Sdonn public pregmask(mask)
122533318Sdonn register int mask;
122633318Sdonn {
122733318Sdonn     register int i;
122833318Sdonn     register int flag = 0;
122933318Sdonn 
123033318Sdonn     if (printing) {
123133318Sdonn 	printf("#<");
123233318Sdonn 	for (i=0; i<16; i++) {
123333318Sdonn 	    if (mask&1) {
123433318Sdonn 		if (flag) {
123533318Sdonn 		    printf(",");
123633318Sdonn 		} else {
123733318Sdonn 		    ++flag;
123833318Sdonn 		}
123933318Sdonn 		printf("%c%d",(i<8) ? 'd' : 'a', i&07);
124033318Sdonn 	    }
124133318Sdonn 	    mask >>= 1;
124233318Sdonn 	}
124333318Sdonn 	printf(">");
124433318Sdonn     }
124533318Sdonn }
124633318Sdonn 
124733318Sdonn public omovem(inst, dummy)
124833318Sdonn long inst;
124933318Sdonn long dummy;
125033318Sdonn {
125133318Sdonn     register int i, list, mask;
125233318Sdonn     register int reglist;
125333318Sdonn     short w;
125433318Sdonn 
125533318Sdonn     i = 0;
125633318Sdonn     list = 0;
125733318Sdonn     mask = 0100000;
125833318Sdonn     instread(w);
125933318Sdonn     reglist = w;
126033318Sdonn     if ((inst & 070) == 040) {	/* predecrement */
126133318Sdonn 	for (i = 15; i > 0; i -= 2) {
126233318Sdonn 	    list |= ((mask & reglist) >> i);
126333318Sdonn 	    mask >>= 1;
126433318Sdonn 	}
126533318Sdonn 	for (i = 1; i < 16; i += 2) {
126633318Sdonn 	    list |= ((mask & reglist) << i);
126733318Sdonn 	    mask >>= 1;
126833318Sdonn 	}
126933318Sdonn 	reglist = list;
127033318Sdonn     }
127133318Sdonn     if (printing) {
127233318Sdonn 	printf("\tmovem%c\t",(inst&100)?'l':'w');
127333318Sdonn     }
127433318Sdonn     if (inst&02000) {
127533318Sdonn 	printEA(inst);
127633318Sdonn 	if (printing) {
127733318Sdonn 	    printf(",");
127833318Sdonn 	}
127933318Sdonn 	pregmask(reglist);
128033318Sdonn     } else {
128133318Sdonn 	pregmask(reglist);
128233318Sdonn 	if (printing) {
128333318Sdonn 	    printf(",");
128433318Sdonn 	}
128533318Sdonn 	printEA(inst);
128633318Sdonn     }
128733318Sdonn }
128833318Sdonn 
128933318Sdonn public ochk(inst, opcode)
129033318Sdonn long inst;
129133318Sdonn register String opcode;
129233318Sdonn {
129333318Sdonn     if (printing) {
129433318Sdonn 	printf("\t%s\t", opcode);
129533318Sdonn     }
129633318Sdonn     printEA(inst, sizeof(Byte));
129733318Sdonn     if (printing) {
129833318Sdonn 	printf(",%c%D", (opcode[0] == 'l') ? 'a' : 'd', (inst>>9)&07);
129933318Sdonn     }
130033318Sdonn }
130133318Sdonn 
130233318Sdonn public soneop(inst, opcode)
130333318Sdonn long inst;
130433318Sdonn register String opcode;
130533318Sdonn {
130633318Sdonn     register int size;
130733318Sdonn 
130833318Sdonn     size = mapsize(inst);
130933318Sdonn     if (size > 0) {
131033318Sdonn 	if (printing) {
131133318Sdonn 	    printf("\t%s%c\t", opcode, suffix(size));
131233318Sdonn 	}
131333318Sdonn 	printEA(inst);
131433318Sdonn     } else {
131533318Sdonn 	if (printing) {
131633318Sdonn 	    printf("\tbadop");
131733318Sdonn 	}
131833318Sdonn     }
131933318Sdonn }
132033318Sdonn 
132133318Sdonn public oquick(inst, opcode)
132233318Sdonn long inst;
132333318Sdonn register String opcode;
132433318Sdonn {
132533318Sdonn     register int size;
132633318Sdonn     register int data;
132733318Sdonn 
132833318Sdonn     size = mapsize(inst);
132933318Sdonn     data = (int)((inst>>9) & 07);
133033318Sdonn     if (data == 0) {
133133318Sdonn 	data = 8;
133233318Sdonn     }
133333318Sdonn     if (size > 0) {
133433318Sdonn 	if (printing) {
133533318Sdonn 	    printf("\t%s%c\t", opcode, suffix(size));
133633318Sdonn 	    printf(IMDF, data);
133733318Sdonn 	    printf(",");
133833318Sdonn 	}
133933318Sdonn 	printEA(inst);
134033318Sdonn     } else {
134133318Sdonn 	if (printing) {
134233318Sdonn 	    printf("\tbadop");
134333318Sdonn 	}
134433318Sdonn     }
134533318Sdonn }
134633318Sdonn 
134733318Sdonn public omoveq(inst, dummy)
134833318Sdonn long inst;
134933318Sdonn long dummy;
135033318Sdonn {
135133318Sdonn     register int data;
135233318Sdonn 
135333318Sdonn     if (printing) {
135433318Sdonn 	data = (int)(inst & 0377);
135533318Sdonn 	if (data > 127) {
135633318Sdonn 	    data |= ~0377;
135733318Sdonn 	}
135833318Sdonn 	printf("\tmoveq\t");
135933318Sdonn 	printf(IMDF, data);
136033318Sdonn 	printf(",d%D", (inst>>9)&07);
136133318Sdonn     }
136233318Sdonn }
136333318Sdonn 
136433318Sdonn public oprint(inst, opcode)
136533318Sdonn long inst;
136633318Sdonn register String opcode;
136733318Sdonn {
136833318Sdonn     if (printing) {
136933318Sdonn 	printf("\t%s",opcode);
137033318Sdonn     }
137133318Sdonn }
137233318Sdonn 
137333318Sdonn public ostop(inst, opcode)
137433318Sdonn long inst;
137533318Sdonn register String opcode;
137633318Sdonn {
137733318Sdonn     short w;
137833318Sdonn 
137933318Sdonn     instread(w);
138033318Sdonn     if (printing) {
138133318Sdonn 	printf(opcode, w);
138233318Sdonn     }
138333318Sdonn }
138433318Sdonn 
138533318Sdonn public orts(inst, opcode)
138633318Sdonn long inst;
138733318Sdonn register String opcode;
138833318Sdonn {
138933318Sdonn     Address addr;
139033318Sdonn 
139133318Sdonn     if (following) {
139233318Sdonn 	callnews(/* iscall = */ false);
139333318Sdonn     	if (inst_tracing) {
139433318Sdonn 	    addr = currtnaddr();
139533318Sdonn     	} else {
139633318Sdonn 	    addr = return_addr();
139733318Sdonn 	    if (addr == 0) {
139833318Sdonn 		stepto(instaddr - 2);
139933318Sdonn 		addr = currtnaddr();
140033318Sdonn 	    }
140133318Sdonn 	}
140233318Sdonn 	stepto(addr);
140333318Sdonn 	instaddr = pc;
140433318Sdonn     }
140533318Sdonn     if (printing) {
140633318Sdonn 	printf("\t%s",opcode);
140733318Sdonn     }
140833318Sdonn }
140933318Sdonn 
141033318Sdonn /*
141133318Sdonn  * Not used by C compiler; does an rts but before doing so, pops
141233318Sdonn  * arg bytes from the stack.
141333318Sdonn  */
141433318Sdonn 
141533318Sdonn public ortspop(inst, opcode)
141633318Sdonn long inst;
141733318Sdonn register String opcode;
141833318Sdonn {
141933318Sdonn     Address addr;
142033318Sdonn     short w;
142133318Sdonn 
142233318Sdonn     instread(w);
142333318Sdonn     if (following) {
142433318Sdonn 	callnews(/* iscall = */ false);
142533318Sdonn     	if (inst_tracing) {
142633318Sdonn 	    addr = currtnaddr();
142733318Sdonn     	} else {
142833318Sdonn 	    addr = return_addr();
142933318Sdonn 	}
143033318Sdonn 	stepto(addr);
143133318Sdonn 	instaddr = pc;
143233318Sdonn     }
143333318Sdonn     if (printing) {
143433318Sdonn 	printf(opcode, w);
143533318Sdonn     }
143633318Sdonn }
143733318Sdonn 
143833318Sdonn public omovs(inst, opcode)
143933318Sdonn long inst;
144033318Sdonn String opcode;
144133318Sdonn {
144233318Sdonn     register int size;
144333318Sdonn     register unsigned int controlword;
144433318Sdonn     short w;
144533318Sdonn 
144633318Sdonn     size = mapsize(inst);
144733318Sdonn     instread(w);
144833318Sdonn     controlword = w >> 11;
144933318Sdonn     if (printing) {
145033318Sdonn 	printf("\t%s%c\t", opcode, suffix(size));
145133318Sdonn     }
145233318Sdonn     if (controlword & 1){
145333318Sdonn 	controlword >>= 1;
145433318Sdonn 	if (printing) {
145533318Sdonn 	    printf((controlword&0x8) ? "a%D," : "d%D,", controlword&7 );
145633318Sdonn 	}
145733318Sdonn 	printEA(inst&0xff, size);
145833318Sdonn     } else {
145933318Sdonn 	controlword >>= 1;
146033318Sdonn 	printEA(inst&0xff, size);
146133318Sdonn 	if (printing) {
146233318Sdonn 	    printf((controlword&0x8) ? ",a%D" : ",d%D", controlword&7);
146333318Sdonn 	}
146433318Sdonn     }
146533318Sdonn }
146633318Sdonn 
146733318Sdonn public omovc(inst, opcode)
146833318Sdonn long inst;
146933318Sdonn String opcode;
147033318Sdonn {
147133318Sdonn     register unsigned int controlword;
147233318Sdonn     String creg;
147333318Sdonn     short w;
147433318Sdonn 
147533318Sdonn     instread(w);
147633318Sdonn     if (printing) {
147733318Sdonn 	controlword = w;
147833318Sdonn 	switch (controlword & 0xfff) {
147933318Sdonn 	    case 0:
148033318Sdonn 		creg = "sfc";
148133318Sdonn 		break;
148233318Sdonn 
148333318Sdonn 	    case 1:
148433318Sdonn 		creg = "dfc";
148533318Sdonn 		break;
148633318Sdonn 
148733318Sdonn 	    case 0x800:
148833318Sdonn 		creg = "usp";
148933318Sdonn 		break;
149033318Sdonn 
149133318Sdonn 	    case 0x801:
149233318Sdonn 		creg = "vbr";
149333318Sdonn 		break;
149433318Sdonn 
149533318Sdonn 	    default:
149633318Sdonn 		creg = "???";
149733318Sdonn 		break;
149833318Sdonn 	}
149933318Sdonn 	controlword >>= 12;
150033318Sdonn 	if (inst & 1){
150133318Sdonn 	    printf((controlword&0x8) ? "%sa%D,%s" : "%sd%D,%s",
150233318Sdonn 		opcode, controlword&7, creg );
150333318Sdonn 	} else {
150433318Sdonn 	    printf((controlword&0x8) ? "%s%s,a%D" : "%s%s,d%D",
150533318Sdonn 		opcode, creg, controlword&7 );
150633318Sdonn 	}
150733318Sdonn     }
150833318Sdonn }
150933318Sdonn 
151033318Sdonn /*
151133318Sdonn  * Compute the next address that will be executed from the given one.
151233318Sdonn  * If "isnext" is true then consider a procedure call as straight line code.
151333318Sdonn  *
151433318Sdonn  * Unconditional branches we just follow, for conditional branches
151533318Sdonn  * we continue execution to the current location and then single step
151633318Sdonn  * the machine.
151733318Sdonn  */
151833318Sdonn 
151933318Sdonn public Address nextaddr(startaddr, isnext)
152033318Sdonn Address startaddr;
152133318Sdonn Boolean isnext;
152233318Sdonn {
152333318Sdonn     Optab *o;
152433318Sdonn     short inst;
152533318Sdonn 
152633318Sdonn     instaddr = usignal(process);
152733318Sdonn     if (instaddr == 0 or instaddr == 1) {
152833318Sdonn 	following = true;
152933318Sdonn 	followcalls = (Boolean) (not isnext);
153033318Sdonn 	printing = false;
153133318Sdonn 	iread(&inst, startaddr, sizeof(inst));
153233318Sdonn 	instaddr = startaddr + sizeof(inst);
153333318Sdonn 	o = decode(inst, startaddr);
153433318Sdonn 	if (o->mask == 0) {
153533318Sdonn 	    fprintf(stderr,
153633318Sdonn 		"[internal error: undecodable op at 0x%x]\n", startaddr);
153733318Sdonn 	    fflush(stderr);
153833318Sdonn 	} else {
153933318Sdonn 	    (*o->opfun)(inst, o->farg);
154033318Sdonn 	}
154133318Sdonn 	following = false;
154233318Sdonn     }
154333318Sdonn     return instaddr;
154433318Sdonn }
154533318Sdonn 
154633318Sdonn /*
154733318Sdonn  * Step to the given address and then execute one instruction past it.
154833318Sdonn  * Set instaddr to the new instruction address.
154933318Sdonn  */
155033318Sdonn 
155133318Sdonn private steppast(addr)
155233318Sdonn Address addr;
155333318Sdonn {
155433318Sdonn     stepto(addr);
155533318Sdonn     pstep(process, DEFSIG);
155633318Sdonn     pc = reg(PROGCTR);
155733318Sdonn     instaddr = pc;
155833318Sdonn }
155933318Sdonn 
156033318Sdonn /*
156133318Sdonn  * Enter a procedure by creating and executing a call instruction.
156233318Sdonn  */
156333318Sdonn 
156433318Sdonn #define CALLSIZE 6	/* size of call instruction */
156533318Sdonn 
156633318Sdonn public beginproc(p)
156733318Sdonn Symbol p;
156833318Sdonn {
156933318Sdonn     char save[CALLSIZE];
157033318Sdonn     struct {
157133318Sdonn 	short op;
157233318Sdonn 	char addr[sizeof(long)];	/* unaligned long */
157333318Sdonn     } call;
157433318Sdonn     long dest;
157533318Sdonn 
157633318Sdonn     pc = CODESTART + 6;
157733318Sdonn     iread(save, pc, sizeof(save));
157833318Sdonn     call.op = 0x4eb9;			/* jsr */
157933318Sdonn     dest = codeloc(p) - FUNCOFFSET;
158033318Sdonn     mov(&dest, call.addr, sizeof(call.addr));
158133318Sdonn     iwrite(&call, pc, sizeof(call));
158233318Sdonn     setreg(PROGCTR, pc);
158333318Sdonn     pstep(process, DEFSIG);
158433318Sdonn     iwrite(save, pc, sizeof(save));
158533318Sdonn     pc = reg(PROGCTR);
158633318Sdonn     if (not isbperr()) {
158733318Sdonn 	printstatus();
158833318Sdonn     }
158933318Sdonn     /*
159033318Sdonn      * Execute link instruction so the return addr is visible.
159133318Sdonn      */
159233318Sdonn     pstep(process, DEFSIG);
159333318Sdonn     pc = reg(PROGCTR);
159433318Sdonn     if (not isbperr()) {
159533318Sdonn 	printstatus();
159633318Sdonn     }
159733318Sdonn }
159833318Sdonn 
159933318Sdonn /*
160033318Sdonn  * Special variables for debugging the kernel.
160133318Sdonn  */
160233318Sdonn 
160333318Sdonn public integer masterpcbb;
160433318Sdonn public integer slr;
160533318Sdonn public struct pte *sbr;
160633318Sdonn private struct pcb pcb;
160733318Sdonn 
160833318Sdonn public getpcb ()
160933318Sdonn {
161033318Sdonn     integer i;
161133318Sdonn 
161233318Sdonn     fseek(corefile, masterpcbb & ~0x80000000, 0);
161333318Sdonn     get(corefile, pcb);
161433318Sdonn     pcb.pcb_p0lr &= ~AST_CLR;
161533318Sdonn     printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n",
161633318Sdonn 	pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr
161733318Sdonn     );
161833318Sdonn #   ifdef sun
161933318Sdonn     for (i = 0; i < 14; i++) {
162033318Sdonn 	setreg(i, pcb.pcb_regs.val[i]);
162133318Sdonn     }
162233318Sdonn #   else /* IRIS */
162333318Sdonn     for (i = 0; i < 14; i++) {
162433318Sdonn 	setreg(i, pcb.pcb_regs[i]);
162533318Sdonn     }
162633318Sdonn #   endif
162733318Sdonn }
162833318Sdonn 
162933318Sdonn public copyregs (savreg, reg)
163033318Sdonn Word savreg[], reg[];
163133318Sdonn {
163233318Sdonn     reg[0] = savreg[R0];
163333318Sdonn     reg[1] = savreg[R1];
163433318Sdonn     reg[2] = savreg[R2];
163533318Sdonn     reg[3] = savreg[R3];
163633318Sdonn     reg[4] = savreg[R4];
163733318Sdonn     reg[5] = savreg[R5];
163833318Sdonn     reg[6] = savreg[R6];
163933318Sdonn     reg[7] = savreg[R7];
164033318Sdonn     reg[8] = savreg[AR0];
164133318Sdonn     reg[9] = savreg[AR1];
164233318Sdonn     reg[10] = savreg[AR2];
164333318Sdonn     reg[11] = savreg[AR3];
164433318Sdonn     reg[12] = savreg[AR4];
164533318Sdonn     reg[13] = savreg[AR5];
164633318Sdonn     reg[14] = savreg[AR6];
164733318Sdonn     reg[15] = savreg[AR7];
164833318Sdonn     reg[PROGCTR] = savreg[PC];
164933318Sdonn }
165033318Sdonn 
165133318Sdonn /*
165233318Sdonn  * Map a virtual address to a physical address.
165333318Sdonn  * XXX THIS CAN'T BE RIGHT... XXX
165433318Sdonn  */
165533318Sdonn 
165633318Sdonn public Address vmap (addr)
165733318Sdonn Address addr;
165833318Sdonn {
165933318Sdonn     Address r;
166033318Sdonn     integer v, n;
166133318Sdonn     struct pte pte;
166233318Sdonn 
166333318Sdonn     r = addr & ~0xc0000000;
166433318Sdonn     v = btop(r);
166533318Sdonn     switch (addr&0xc0000000) {
166633318Sdonn 	case 0xc0000000:
166733318Sdonn 	case 0x80000000:
166833318Sdonn 	    /*
166933318Sdonn 	     * In system space, so get system pte.
167033318Sdonn 	     * If it is valid or reclaimable then the physical address
167133318Sdonn 	     * is the combination of its page number and the page offset
167233318Sdonn 	     * of the original address.
167333318Sdonn 	     */
167433318Sdonn 	    if (v >= slr) {
167533318Sdonn 		error("address %x out of segment", addr);
167633318Sdonn 	    }
167733318Sdonn 	    r = ((long) (sbr + v)) & ~0x80000000;
167833318Sdonn 	    goto simple;
167933318Sdonn 
168033318Sdonn 	case 0x40000000:
168133318Sdonn 	    /*
168233318Sdonn 	     * In p1 space, must not be in shadow region.
168333318Sdonn 	     */
168433318Sdonn 	    if (v < pcb.pcb_p1lr) {
168533318Sdonn 		error("address %x out of segment", addr);
168633318Sdonn 	    }
168733318Sdonn 	    r = (Address) (pcb.pcb_p1br + v);
168833318Sdonn 	    break;
168933318Sdonn 
169033318Sdonn 	case 0x00000000:
169133318Sdonn 	    /*
169233318Sdonn 	     * In p0 space, must not be off end of region.
169333318Sdonn 	     */
169433318Sdonn 	    if (v >= pcb.pcb_p0lr) {
169533318Sdonn 		error("address %x out of segment", addr);
169633318Sdonn 	    }
169733318Sdonn 	    r = (Address) (pcb.pcb_p0br + v);
169833318Sdonn 	    break;
169933318Sdonn 
170033318Sdonn 	default:
170133318Sdonn 	    /* do nothing */
170233318Sdonn 	    break;
170333318Sdonn     }
170433318Sdonn     /*
170533318Sdonn      * For p0/p1 address, user-level page table should be in
170633318Sdonn      * kernel virtual memory.  Do second-level indirect by recursing.
170733318Sdonn      */
170833318Sdonn     if ((r & 0x80000000) == 0) {
170933318Sdonn 	error("bad p0br or p1br in pcb");
171033318Sdonn     }
171133318Sdonn     r = vmap(r);
171233318Sdonn simple:
171333318Sdonn     /*
171433318Sdonn      * "r" is now the address of the pte of the page
171533318Sdonn      * we are interested in; get the pte and paste up the physical address.
171633318Sdonn      */
171733318Sdonn     fseek(corefile, r, 0);
171833318Sdonn     n = fread(&pte, sizeof(pte), 1, corefile);
171933318Sdonn     if (n != 1) {
172033318Sdonn 	error("page table botch (fread at %x returns %d)", r, n);
172133318Sdonn     }
172233318Sdonn     if (pte.pg_v == 0 and (pte.pg_fod != 0 or pte.pg_pfnum == 0)) {
172333318Sdonn 	error("page no valid or reclamable");
172433318Sdonn     }
172533318Sdonn     return (addr&PGOFSET) + ((Address) ptob(pte.pg_pfnum));
172633318Sdonn }
172733318Sdonn 
172833318Sdonn /*
172933318Sdonn  * Extract a bit field from an integer.
173033318Sdonn  */
173133318Sdonn 
173233318Sdonn public integer extractField (s)
173333318Sdonn Symbol s;
173433318Sdonn {
173533318Sdonn     integer nbytes, nbits, n, r, off, len;
173633318Sdonn 
173733318Sdonn     off = s->symvalue.field.offset;
173833318Sdonn     len = s->symvalue.field.length;
173933318Sdonn     nbytes = size(s);
174033318Sdonn     n = 0;
174133318Sdonn     if (nbytes > sizeof(n)) {
174233318Sdonn 	printf("[bad size in extractField -- word assumed]\n");
174333318Sdonn 	nbytes = sizeof(n);
174433318Sdonn     }
174533318Sdonn     popn(nbytes, ((char *) &n) + (sizeof(Word) - nbytes));
174633318Sdonn     nbits = nbytes * BITSPERBYTE;
174733318Sdonn     r = n >> (nbits - ((off mod nbits) + len));
174833318Sdonn     r &= ((1 << len) - 1);
174933318Sdonn     return r;
175033318Sdonn }
175133318Sdonn 
175233318Sdonn /*
175333318Sdonn  * Change the length of a value in memory according to a given difference
175433318Sdonn  * in the lengths of its new and old types.
175533318Sdonn  */
175633318Sdonn 
175733318Sdonn public loophole (oldlen, newlen)
175833318Sdonn integer oldlen, newlen;
175933318Sdonn {
176033318Sdonn     integer i, n;
176133318Sdonn     Stack *oldsp;
176233318Sdonn 
176333318Sdonn     n = newlen - oldlen;
176433318Sdonn     oldsp = sp - oldlen;
176533318Sdonn     if (n > 0) {
176633318Sdonn 	for (i = oldlen - 1; i >= 0; i--) {
176733318Sdonn 	    oldsp[n + i] = oldsp[i];
176833318Sdonn 	}
176933318Sdonn 	for (i = 0; i < n; i++) {
177033318Sdonn 	    oldsp[i] = '\0';
177133318Sdonn 	}
177233318Sdonn     } else {
177333318Sdonn 	for (i = 0; i < newlen; i++) {
177433318Sdonn 	    oldsp[i] = oldsp[i - n];
177533318Sdonn 	}
177633318Sdonn     }
177733318Sdonn     sp += n;
177833318Sdonn }
1779