4.4BSD/usr/src/old/dbx/sun.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1983 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@(#)sun.c	5.2 (Berkeley) 6/1/90";
#endif /* not lint */

/*
 * Target machine dependent stuff.
 */

#include "defs.h"
#include "machine.h"
#include "process.h"
#include "runtime.h"
#include "events.h"
#include "main.h"
#include "symbols.h"
#include "source.h"
#include "mappings.h"
#include "object.h"
#include "tree.h"
#include "eval.h"
#include "keywords.h"
#include "ops.h"

#ifndef public
typedef unsigned int Address;
typedef unsigned char Byte;
typedef unsigned int Word;

/*
 * On the 68000, the pc isn't in a register, but we make believe
 * so there's one more register.
 *
 * Note that there's also no argument pointer, this means code
 * involving "ARGP" should always be #ifdef'd.
 *
 * The address corresponding to the beginning of a function is recorded
 * as the address + FUNCOFFSET (skip the link instruction so that
 * local information is available).
 */

#define NREG 17

#define FRP 14
#define STKP 15
#define PROGCTR 16

#define CALL_RETADDR	0x800c		/* Return address for 'call' command */
#define FUNCOFFSET 4

#ifdef sun
#    define CODESTART 0x8000
#else /* IRIS */
#   define CODESTART 0x1000
#endif

#define optab_init()

#define BITSPERBYTE 8
#define BITSPERWORD (BITSPERBYTE * sizeof(Word))

/*
 * This magic macro enables us to look at the process' registers
 * in its user structure.
 */

#define regloc(reg)	(ctob(UPAGES) + (sizeof(Word) * ((reg) - PC)) - 10)

#include "source.h"
#include "symbols.h"
#include <signal.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <machine/psl.h>
#include <machine/pte.h>
#include <sys/user.h>
#undef DELETE /* XXX */
#include <sys/vm.h>
#include <machine/reg.h>

Address pc;
Address prtaddr;

#endif

/*
 * Indices into u. for use in collecting registers values.
 */
public int rloc[] ={
#ifdef sun
    R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5, AR6, AR7, PC
#else /* IRIS */
    R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5, AR6, AR7, 16
#endif
};

private Address printop();

/*
 * Decode and print the instructions within the given address range.
 */

public printinst(lowaddr, highaddr)
Address lowaddr;
Address highaddr;
{
    register Address addr;

    for (addr = lowaddr; addr <= highaddr; ) {
	addr = printop(addr);
    }
    prtaddr = addr;
}

/*
 * Another approach:  print n instructions starting at the given address.
 */

public printninst(count, addr)
int count;
Address addr;
{
    register Integer i;
    register Address newaddr;

    if (count <= 0) {
	error("non-positive repetition count");
    } else {
	newaddr = addr;
	for (i = 0; i < count; i++) {
	    newaddr = printop(newaddr);
	}
	prtaddr = newaddr;
    }
}

/*
 * Print the contents of the addresses within the given range
 * according to the given format.
 */

typedef struct {
    String name;
    String printfstring;
    int length;
} Format;

private Format fmt[] = {
    { "d", " %d", sizeof(short) },
    { "D", " %ld", sizeof(long) },
    { "o", " %o", sizeof(short) },
    { "O", " %lo", sizeof(long) },
    { "x", " %04x", sizeof(short) },
    { "X", " %08x", sizeof(long) },
    { "b", " \\%o", sizeof(char) },
    { "c", " '%c'", sizeof(char) },
    { "s", "%c", sizeof(char) },
    { "f", " %f", sizeof(float) },
    { "g", " %g", sizeof(double) },
    { nil, nil, 0 }
};

private Format *findformat(s)
String s;
{
    register Format *f;

    f = &fmt[0];
    while (f->name != nil and not streq(f->name, s)) {
	++f;
    }
    if (f->name == nil) {
	error("bad print format \"%s\"", s);
    }
    return f;
}

/*
 * Retrieve and print out the appropriate data in the given format.
 * Floats have to be handled specially to allow the compiler to
 * convert them to doubles when passing to printf.
 */

private printformat (f, addr)
Format *f;
Address addr;
{
    union {
	char charv;
	short shortv;
	int intv;
	float floatv;
	double doublev;
    } value;

    value.intv = 0;
    dread(&value, addr, f->length);
    if (streq(f->name, "f")) {
	printf(f->printfstring, value.floatv);
    } else {
	printf(f->printfstring, value);
    }
}

public Address printdata(lowaddr, highaddr, format)
Address lowaddr;
Address highaddr;
String format;
{
    int n;
    register Address addr;
    Format *f;

    if (lowaddr > highaddr) {
	error("first address larger than second");
    }
    f = findformat(format);
    n = 0;
    for (addr = lowaddr; addr <= highaddr; addr += f->length) {
	if (n == 0) {
	    printf("%08x: ", addr);
	}
	printformat(f, addr);
	++n;
	if (n >= (16 div f->length)) {
	    printf("\n");
	    n = 0;
	}
    }
    if (n != 0) {
	printf("\n");
    }
    prtaddr = addr;
    return addr;
}

/*
 * The other approach is to print n items starting with a given address.
 */

public printndata(count, startaddr, format)
int count;
Address startaddr;
String format;
{
    int i, n;
    Address addr;
    Format *f;
    Boolean isstring;
    char c;

    if (count <= 0) {
	error("non-positive repetition count");
    }
    f = findformat(format);
    isstring = (Boolean) streq(f->name, "s");
    n = 0;
    addr = startaddr;
    for (i = 0; i < count; i++) {
	if (n == 0) {
	    printf("%08x: ", addr);
	}
	if (isstring) {
	    printf("\"");
	    dread(&c, addr, sizeof(char));
	    while (c != '\0') {
		printchar(c);
		++addr;
		dread(&c, addr, sizeof(char));
	    }
	    printf("\"\n");
	    n = 0;
	    addr += sizeof(String);
	} else {
	    printformat(f, addr);
	    ++n;
	    if (n >= (16 div f->length)) {
		printf("\n");
		n = 0;
	    }
	    addr += f->length;
	}
    }
    if (n != 0) {
	printf("\n");
    }
    prtaddr = addr;
}

/*
 * Print out a value according to the given format.
 */

public printvalue(v, format)
long v;
String format;
{
    Format *f;
    char *p, *q;

    f = findformat(format);
    if (streq(f->name, "s")) {
	putchar('"');
	p = (char *) &v;
	q = p + sizeof(v);
	while (p < q) {
	    printchar(*p);
	    ++p;
	}
	putchar('"');
    } else {
	printf(f->printfstring, v);
    }
    putchar('\n');
}

/*
 * Print out an execution time error.
 * Assumes the source position of the error has been calculated.
 *
 * Have to check if the -r option was specified; if so then
 * the object file information hasn't been read in yet.
 */

public printerror()
{
    extern Integer sys_nsig;
    extern String sys_siglist[];
    integer err;

    if (isfinished(process)) {
	err = exitcode(process);
	if (err == 0) {
	    printf("\"%s\" terminated normally\n", objname);
	} else {
	    printf("\"%s\" terminated abnormally (exit code %d)\n",
		objname, err
	    );
	}
	erecover();
    }
    err = errnum(process);
    putchar('\n');
    printsig(err);
    putchar(' ');
    printloc();
    putchar('\n');
    if (curline > 0) {
	printlines(curline, curline);
    } else {
	printinst(pc, pc);
    }
    erecover();
}

/*
 * Print out a signal.
 */

private String illinames[] = {
    "reserved addressing fault",
    "privileged instruction fault",
    "reserved operand fault"
};

private String fpenames[] = {
    nil,
    "integer overflow trap",
    "integer divide by zero trap",
    "floating overflow trap",
    "floating/decimal divide by zero trap",
    "floating underflow trap",
    "decimal overflow trap",
    "subscript out of range trap",
    "floating overflow fault",
    "floating divide by zero fault",
    "floating underflow fault"
};

public printsig (signo)
integer signo;
{
    integer code;

    if (signo < 0 or signo > sys_nsig) {
	printf("[signal %d]", signo);
    } else {
	printf("%s", sys_siglist[signo]);
    }
    code = errcode(process);
    if (signo == SIGILL) {
	if (code >= 0 and code < sizeof(illinames) / sizeof(illinames[0])) {
	    printf(" (%s)", illinames[code]);
	}
    } else if (signo == SIGFPE) {
	if (code > 0 and code < sizeof(fpenames) / sizeof(fpenames[0])) {
	    printf(" (%s)", fpenames[code]);
	}
    }
}

/*
 * Note the termination of the program.  We do this so as to avoid
 * having the process exit, which would make the values of variables
 * inaccessible.  We do want to flush all output buffers here,
 * otherwise it'll never get done.
 */

public endprogram()
{
    Integer exitcode;

    stepto(nextaddr(pc, true));
    printnews();
    exitcode = argn(1, nil);
    if (exitcode != 0) {
	printf("\nexecution completed (exit code %d)\n", exitcode);
    } else {
	printf("\nexecution completed\n");
    }
    getsrcpos();
    erecover();
}

/*
 * Single step the machine a source line (or instruction if "inst_tracing"
 * is true).  If "isnext" is true, skip over procedure calls.
 */

private Address getcall();

public dostep(isnext)
Boolean isnext;
{
    register Address addr;
    register Lineno line;
    String filename;
    Address startaddr;

    startaddr = pc;
    addr = nextaddr(pc, isnext);
    if (not inst_tracing and nlhdr.nlines != 0) {
	line = linelookup(addr);
	while (line == 0) {
	    addr = nextaddr(addr, isnext);
	    line = linelookup(addr);
	}
	curline = line;
    } else {
	curline = 0;
    }
    stepto(addr);
    filename = srcfilename(addr);
    setsource(filename);
}

typedef short Bpinst;

extern Bpinst BP_OP;
#ifdef sun
	asm("_BP_OP: trap #15");
#else /* IRIS */
	asm("_BP_OP: trap #1");
#endif

#define BP_ERRNO    SIGTRAP     /* signal received at a breakpoint */

/*
 * Setting a breakpoint at a location consists of saving
 * the word at the location and poking a BP_OP there.
 *
 * We save the locations and words on a list for use in unsetting.
 */

typedef struct Savelist *Savelist;

struct Savelist {
    Address location;
    Bpinst save;
    short refcount;
    Savelist link;
};

private Savelist savelist;

/*
 * Set a breakpoint at the given address.  Only save the word there
 * if it's not already a breakpoint.
 */

public setbp(addr)
Address addr;
{
    Bpinst w, save;
    register Savelist newsave, s;

    for (s = savelist; s != nil; s = s->link) {
	if (s->location == addr) {
	    s->refcount++;
	    return;
	}
    }
    iread(&save, addr, sizeof(save));
    newsave = new(Savelist);
    newsave->location = addr;
    newsave->save = save;
    newsave->refcount = 1;
    newsave->link = savelist;
    savelist = newsave;
    w = BP_OP;
    iwrite(&w, addr, sizeof(w));
}

/*
 * Unset a breakpoint; unfortunately we have to search the SAVELIST
 * to find the saved value.  The assumption is that the SAVELIST will
 * usually be quite small.
 */

public unsetbp(addr)
Address addr;
{
    register Savelist s, prev;

    prev = nil;
    for (s = savelist; s != nil; s = s->link) {
	if (s->location == addr) {
	    iwrite(&s->save, addr, sizeof(s->save));
	    s->refcount--;
	    if (s->refcount == 0) {
		if (prev == nil) {
		    savelist = s->link;
		} else {
		    prev->link = s->link;
		}
		dispose(s);
	    }
	    return;
	}
	prev = s;
    }
    panic("unsetbp: couldn't find address %d", addr);
}

/*
 * Instruction decoding routines for 68000, derived from adb.
 *
 * The shared boolean variable "printing" is true if the decoded
 * instruction is to be printed, false if not.  In either case,
 * the address of the next instruction after the given one is returned.
 */

private Boolean printing;
private Boolean following;
private Boolean followcalls;
private Address instaddr;

#define instread(var) \
{ \
    iread(&var, instaddr, sizeof(var)); \
    instaddr += sizeof(var); \
}

private Optab *decode(inst, addr)
Word inst;
Address addr;
{
    register Optab *o;

    o = &optab[0];
    while (o->mask != 0 and (inst&o->mask) != o->match) {
	++o;
    }
    return o;
}

private Address printop(addr)
Address addr;
{
    Optab *o;
    short inst;

    printf("%08x  ", addr);
    iread(&inst, addr, sizeof(inst));
    o = decode(inst, addr);
    if (o->mask == 0) {
	printf("\tbadop");
	instaddr = addr + sizeof(inst);
    } else {
	printing = true;
	following = false;
	instaddr = addr + sizeof(inst);
	(*o->opfun)(inst, o->farg);
	printing = false;
    }
    printf("\n");
    return instaddr;
}

/*
 * Quickly find the return address of the current procedure or function
 * while single stepping.  Just get the word pointed at by sp.
 */

private Address currtnaddr ()
{
    Address retaddr;

    dread(&retaddr, reg(STKP), sizeof(retaddr));
    return retaddr;
}

/*
 * Print out the effective address for the given parameters.
 */

private printea(mode, reg, size)
long mode, reg;
int size;
{
    long index, disp;
    static char *aregs[] = { "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp" };
    Byte b;
    short w;
    long l;

    switch ((int)(mode)) {
	case 0:
	    if (printing) {
		printf("d%D", reg);
	    }
	    break;

	case 1:
	    if (printing) {
		printf("%s", aregs[reg]);
	    }
	    break;

	case 2:
	    if (printing) {
		printf("%s@", aregs[reg]);
	    }
	    break;

	case 3:
	    if (printing) {
		printf("%s@+", aregs[reg]);
	    }
	    break;

	case 4:
	    if (printing) {
		printf("%s@-", aregs[reg]);
	    }
	    break;

	case 5:
	    instread(w);
	    if (printing) {
		printf("%s@(%D)", aregs[reg], w);
	    }
	    break;

	case 6:
	    instread(w);
	    if (printing) {
		index = w;
		disp = (char)(index&0377);
		printf("%s@(%d,%c%D:%c)", aregs[reg], disp,
		    (index&0100000)?'a':'d',(index>>12)&07,
		    (index&04000)?'l':'w');
	    }
	    break;

	case 7:
	    switch ((int)(reg)) {
		case 0:
		    instread(w);
		    if (printing) {
			index = w;
			psymoff(index);
		    }
		    break;

		case 1:
		    instread(l);
		    if (printing) {
			index = l;
			psymoff(index);
		    }
		    break;

		case 2:	
		    instread(w);
		    if (printing) {
			disp = w;
			psymoff(disp + instaddr);
		    }
		    break;

		case 3:
		    instread(w);
		    if (printing) {
			index = w;
			disp = (char)(index&0377);
			printf("pc@(%D,%c%D:%c)", disp,
			    (index&0100000)?'a':'d',(index>>12)&07,
			    (index&04000)?'l':'w');
		    }
		    break;

		case 4:
		    switch (size) {
			case sizeof(b):
			    instread(w);
			    index = (w&0xff);
			    break;

			case sizeof(w):
			    instread(w);
			    index = w;
			    break;

			case sizeof(l):
			    instread(l);
			    index = l;
			    break;

			default:
			    if (printing) {
			    	printf("unexpected size %d in printea\n", size);
			    }
			    instread(l);
			    index = l;
			    break;
		    }
		    if (printing) {
			printf(IMDF, index);
		    }
		    break;

		default:
		    if (printing) {
			printf("???");
		    }
		    break;
	    }
	    break;

	default:
	    if (printing) {
		printf("???");
	    }
	    break;
    }
}

private printEA(ea, size)
long ea;
int size;
{
    printea((ea>>3)&07, ea&07, size);
}

private mapsize(inst)
register long inst;
{
    int m;

    inst >>= 6;
    inst &= 03;
    switch (inst) {
	case 0:
	    m = 1;
	    break;

	case 1:
	    m = 2;
	    break;

	case 2:
	    m = 4;
	    break;

	default:
	    m = -1;
	    break;
    }
    return m;
}

private char suffix(size)
int size;
{
    char c;

    switch (size) {
	case 1:
	    c = 'b';
	    break;

	case 2:
	    c = 'w';
	    break;

	case 4:
	    c = 'l';
	    break;

	default:
	    panic("bad size %d in suffix", size);
    }
    return c;
}

/*
 * Print an address offset.  Eventually this should attempt to be symbolic,
 * but for now its just printed in hex.
 */

private psymoff (off)
Word off;
{
    Symbol f;

    f = whatblock((Address) (off + FUNCOFFSET));
    if (codeloc(f) == off + FUNCOFFSET) {
	printf("%s", symname(f));
    } else {
	printf("0x%x", off);
    }
}

/*
 * Instruction class specific routines.
 */

public omove(inst, s)
long inst;
String s;
{
    register int c;
    int size;

    c = s[0];
    if (printing) {
	printf("\tmov%c\t", c);
    }
    size = ((c == 'b') ? 1 : (c == 'w') ? 2 : 4);
    printea((inst>>3)&07, inst&07, size);
    if (printing) {
	printf(",");
    }
    printea((inst>>6)&07, (inst>>9)&07, size);
}

/* 
 * Two types: bsr (4 bytes) and bsrs (2 bytes)
 */

public obranch(inst, dummy)
long inst;
{
    long disp;
    String s; 
    short w;
    Address startingaddr;	/* address of branch instruction */
    int branchtype;		/* type of branch (0 = unconditional) */
    Address dest;
    Address retaddr;		/* for bsr instruction */

    startingaddr = instaddr - 2;
    disp = inst&0377;
    s = "s ";
    if (disp == 0) {
	retaddr = startingaddr + 4;
    } else {
	retaddr = startingaddr + 2;
    }
    if (disp > 127) {
	disp |= ~0377;
    } else if (disp == 0){
	s = " ";
	instread(w);
	disp = w;
    }
    branchtype = (int)((inst>>8)&017);
    dest = startingaddr + 2 + disp;
    if (printing) {
	printf("\tb%s%s\t", bname[branchtype], s);
	psymoff(dest);
    }
    if (following) {
	/*
	 * If we're to follow the dynamic flow of instructions,
	 * we must see where the branch leads.  A branchtype of 0
	 * indicates an unconditional branch which we simply take
	 * as the new instruction address.  For a conditional branch,
	 * we continue execution up to the current address, single step,
	 * and keep going.
	 */
	if (branchtype == 0) {
	    instaddr = dest;
	} else if (branchtype == 01) {		/* bsr */
	    if (followcalls) {
		steppast(startingaddr);
		curfunc = whatblock(pc, true);
		if (not isbperr()) {
		    printstatus();
		    /* NOTREACHED */
		}
		bpact();
		if (nosource(curfunc) and canskip(curfunc) and
		  nlhdr.nlines != 0) {
		    stepto(retaddr);
		    instaddr = pc;
		    bpact();
		} else {
		    callnews(/* iscall = */ true);
		}
	    }
	} else {
	    steppast(startingaddr);
	}
    }
}

public odbcc(inst, form)
long inst;
String form;
{
    long disp;
    short w;

    instread(w);
    if (printing) {
    	printf(form, dbname[(int)((inst>>8)&017)], inst&07);
	psymoff(w + sizeof(w));
    }
}

public oscc(inst, dummy)
long inst;
long dummy;
{
    if (printing) {
	printf("\ts%s\t", cname[(int)((inst>>8)&017)]);
    }
    printea((inst>>3)&07, inst&07, 1);
}

public biti(inst, dummy)
long inst;
long dummy;
{
    short w;

    if (printing) {
	printf("\t%s\t", bit[(int)((inst>>6)&03)]);
    }
    if (inst&0x0100) {
	if (printing) {
	    printf("d%D,", inst>>9);
	}
    } else {
	instread(w);
	if (printing) {
	    printf(IMDF, w);
	    printf(",");
	}
    }
    printEA(inst);
}

public opmode(inst, opcode)
long inst;
long opcode;
{
    register int opmode;
    register int reg;
    int size;

    opmode = (int)((inst>>6) & 07);
    reg = (int)((inst>>9) & 07);
    if (opmode == 0 or opmode == 4) {
	size = 1;
    } else if (opmode == 1 or opmode == 3 or opmode == 5) {
	size = 2;
    } else {
	size = 4;
    }
    if (printing) {
	printf("\t%s%c\t", opcode, suffix(size));
    }
    if (opmode >= 4 and opmode <= 6) {
	if (printing) {
	    printf("d%d,", reg);
	}
	printea((inst>>3)&07, inst&07, size);
    } else {
	printea((inst>>3)&07, inst&07, size);
	if (printing) {
	    printf(",%c%d",(opmode<=2) ? 'd' : 'a', reg);
	}
    }
}

public shroi(inst, ds)
long inst;
String ds;
{
    int rx, ry;
    String opcode;

    if ((inst & 0xC0) == 0xC0) {
	opcode = shro[(int)((inst>>9)&03)];
	if (printing) {
	    printf("\t%s%s\t", opcode, ds);
	}
	printEA(inst);
    } else {
	if (printing) {
	    opcode = shro[(int)((inst>>3)&03)];
	    printf("\t%s%s%c\t", opcode, ds, suffix(mapsize(inst)));
	    rx = (int)((inst>>9)&07); ry = (int)(inst&07);
	    if ((inst>>5)&01) {
		printf("d%d,d%d", rx, ry);
	    } else {
		printf(IMDF, (rx ? rx : 8));
		printf(",d%d", ry);
	    }
	}
    }
}		

public oimmed(inst, opcode)
long inst;
register String opcode;
{
    register int size;
    long const;
    short w;

    size = mapsize(inst);
    if (size > 0) {
	if (size == 4) {
	    instread(const);
	} else {
	    instread(w);
	    const = w;
	}
	if (printing) {
	    printf("\t%s%c\t", opcode, suffix(size));
	    printf(IMDF, const);
	    printf(",");
	}
	printEA(inst, size);
    } else {
	if (printing) {
	    printf("\tbadop");
	}
    }
}

public oreg(inst, opcode)
long inst;
register String opcode;
{
    if (printing) {
	printf(opcode, (inst & 07));
    }
}

public extend(inst, opcode)
long inst;
String opcode;
{
    register int size;
    int ry, rx;
    char c;

    if (printing) {
	size = mapsize(inst);
	ry = (inst&07);
	rx = ((inst>>9)&07);
	c = ((inst & 0x1000) ? suffix(size) : ' ');
	printf("\t%s%c\t", opcode, c);
	if (opcode[0] == 'e') {
	    if (inst & 0x0080) {
		printf("d%D,a%D", rx, ry);
	    } else if (inst & 0x0008) {
		printf("a%D,a%D", rx, ry);
	    } else {
		printf("d%D,d%D", rx, ry);
	    }
	} else if ((inst & 0xF000) == 0xB000) {
	    printf("a%D@+,a%D@+", ry, rx);
	} else if (inst & 0x8) {
	    printf("a%D@-,a%D@-", ry, rx);
	} else {
	    printf("d%D,d%D", ry, rx);
	}
    }
}

public olink(inst, dummy)
long inst;
long dummy;
{
    short w;

    instread(w);
    if (printing) {
	printf("\tlink\ta%D,", inst&07);
	printf(IMDF, w);
    }
}

public otrap(inst, dummy)
long inst;
{
    if (printing) {
	printf("\ttrap\t");
	printf(IMDF, inst&017);
    }
}

public oneop(inst, opcode)
long inst;
register String opcode;
{
    if (printing) {
	printf("\t%s",opcode);
    }
    printEA(inst);
}

public jsrop(inst, opcode)
long inst;
register String opcode;
{
    Address startingaddr;	/* beginning of jsr instruction */
    Address retaddr; /* can't call return_addr (frame not set up yet) */

    startingaddr = instaddr - 2;
    switch ((inst >> 3) & 07) {
	case 2:
	    retaddr = instaddr;		/* two byte instruction */
	    break;
	case 5:
	case 6:
	    retaddr = instaddr + 2;	/* four byte instruction */
	    break;
	case 7:
	default:
	    switch (inst & 07) {
		case 0:
		case 2:
		case 3:
		    retaddr = instaddr + 2;
		    break;
		case 1:
		default:
		    retaddr = instaddr + 4;	/* six byte instruction */
		    break;
	    }
	    break;
    }
    if (printing) {
	printf("\t%s",opcode);
    }
    printEA(inst);
    if (following and followcalls) {
	steppast(startingaddr);
	curfunc = whatblock(pc, true);
	if (not isbperr()) {
	    printstatus();
	    /* NOTREACHED */
	}
	bpact();
	if (nosource(curfunc) and canskip(curfunc) and nlhdr.nlines != 0) {
	    stepto(retaddr);
	    instaddr = pc;
	    bpact();
	} else {
	    callnews(/* iscall = */ true);
	}
    }
}

public jmpop(inst, opcode)
long inst;
register String opcode;
{
    Address startingaddr;	/* beginning of jump instruction */

    startingaddr = instaddr - 2;
    if (printing) {
	printf("\t%s",opcode);
    }
    printEA(inst);
    if (following) {
	steppast(startingaddr);
    }
}

public pregmask(mask)
register int mask;
{
    register int i;
    register int flag = 0;

    if (printing) {
	printf("#<");
	for (i=0; i<16; i++) {
	    if (mask&1) {
		if (flag) {
		    printf(",");
		} else {
		    ++flag;
		}
		printf("%c%d",(i<8) ? 'd' : 'a', i&07);
	    }
	    mask >>= 1;
	}
	printf(">");
    }
}

public omovem(inst, dummy)
long inst;
long dummy;
{
    register int i, list, mask;
    register int reglist;
    short w;

    i = 0;
    list = 0;
    mask = 0100000;
    instread(w);
    reglist = w;
    if ((inst & 070) == 040) {	/* predecrement */
	for (i = 15; i > 0; i -= 2) {
	    list |= ((mask & reglist) >> i);
	    mask >>= 1;
	}
	for (i = 1; i < 16; i += 2) {
	    list |= ((mask & reglist) << i);
	    mask >>= 1;
	}
	reglist = list;
    }
    if (printing) {
	printf("\tmovem%c\t",(inst&100)?'l':'w');
    }
    if (inst&02000) {
	printEA(inst);
	if (printing) {
	    printf(",");
	}
	pregmask(reglist);
    } else {
	pregmask(reglist);
	if (printing) {
	    printf(",");
	}
	printEA(inst);
    }
}

public ochk(inst, opcode)
long inst;
register String opcode;
{
    if (printing) {
	printf("\t%s\t", opcode);
    }
    printEA(inst, sizeof(Byte));
    if (printing) {
	printf(",%c%D", (opcode[0] == 'l') ? 'a' : 'd', (inst>>9)&07);
    }
}

public soneop(inst, opcode)
long inst;
register String opcode;
{
    register int size;

    size = mapsize(inst);
    if (size > 0) {
	if (printing) {
	    printf("\t%s%c\t", opcode, suffix(size));
	}
	printEA(inst);
    } else {
	if (printing) {
	    printf("\tbadop");
	}
    }
}

public oquick(inst, opcode)
long inst;
register String opcode;
{
    register int size;
    register int data;

    size = mapsize(inst);
    data = (int)((inst>>9) & 07);
    if (data == 0) {
	data = 8;
    }
    if (size > 0) {
	if (printing) {
	    printf("\t%s%c\t", opcode, suffix(size));
	    printf(IMDF, data);
	    printf(",");
	}
	printEA(inst);
    } else {
	if (printing) {
	    printf("\tbadop");
	}
    }
}

public omoveq(inst, dummy)
long inst;
long dummy;
{
    register int data;

    if (printing) {
	data = (int)(inst & 0377);
	if (data > 127) {
	    data |= ~0377;
	}
	printf("\tmoveq\t");
	printf(IMDF, data);
	printf(",d%D", (inst>>9)&07);
    }
}

public oprint(inst, opcode)
long inst;
register String opcode;
{
    if (printing) {
	printf("\t%s",opcode);
    }
}

public ostop(inst, opcode)
long inst;
register String opcode;
{
    short w;

    instread(w);
    if (printing) {
	printf(opcode, w);
    }
}

public orts(inst, opcode)
long inst;
register String opcode;
{
    Address addr;

    if (following) {
	callnews(/* iscall = */ false);
    	if (inst_tracing) {
	    addr = currtnaddr();
    	} else {
	    addr = return_addr();
	    if (addr == 0) {
		stepto(instaddr - 2);
		addr = currtnaddr();
	    }
	}
	stepto(addr);
	instaddr = pc;
    }
    if (printing) {
	printf("\t%s",opcode);
    }
}

/*
 * Not used by C compiler; does an rts but before doing so, pops
 * arg bytes from the stack.
 */

public ortspop(inst, opcode)
long inst;
register String opcode;
{
    Address addr;
    short w;

    instread(w);
    if (following) {
	callnews(/* iscall = */ false);
    	if (inst_tracing) {
	    addr = currtnaddr();
    	} else {
	    addr = return_addr();
	}
	stepto(addr);
	instaddr = pc;
    }
    if (printing) {
	printf(opcode, w);
    }
}

public omovs(inst, opcode)
long inst;
String opcode;
{
    register int size;
    register unsigned int controlword;
    short w;

    size = mapsize(inst);
    instread(w);
    controlword = w >> 11;
    if (printing) {
	printf("\t%s%c\t", opcode, suffix(size));
    }
    if (controlword & 1){
	controlword >>= 1;
	if (printing) {
	    printf((controlword&0x8) ? "a%D," : "d%D,", controlword&7 );
	}
	printEA(inst&0xff, size);
    } else {
	controlword >>= 1;
	printEA(inst&0xff, size);
	if (printing) {
	    printf((controlword&0x8) ? ",a%D" : ",d%D", controlword&7);
	}
    }
}

public omovc(inst, opcode)
long inst;
String opcode;
{
    register unsigned int controlword;
    String creg;
    short w;

    instread(w);
    if (printing) {
	controlword = w;
	switch (controlword & 0xfff) {
	    case 0:
		creg = "sfc";
		break;

	    case 1:
		creg = "dfc";
		break;

	    case 0x800:
		creg = "usp";
		break;

	    case 0x801:
		creg = "vbr";
		break;

	    default:
		creg = "???";
		break;
	}
	controlword >>= 12;
	if (inst & 1){
	    printf((controlword&0x8) ? "%sa%D,%s" : "%sd%D,%s",
		opcode, controlword&7, creg );
	} else {
	    printf((controlword&0x8) ? "%s%s,a%D" : "%s%s,d%D",
		opcode, creg, controlword&7 );
	}
    }
}

/*
 * Compute the next address that will be executed from the given one.
 * If "isnext" is true then consider a procedure call as straight line code.
 *
 * Unconditional branches we just follow, for conditional branches
 * we continue execution to the current location and then single step
 * the machine.
 */

public Address nextaddr(startaddr, isnext)
Address startaddr;
Boolean isnext;
{
    Optab *o;
    short inst;

    instaddr = usignal(process);
    if (instaddr == 0 or instaddr == 1) {
	following = true;
	followcalls = (Boolean) (not isnext);
	printing = false;
	iread(&inst, startaddr, sizeof(inst));
	instaddr = startaddr + sizeof(inst);
	o = decode(inst, startaddr);
	if (o->mask == 0) {
	    fprintf(stderr,
		"[internal error: undecodable op at 0x%x]\n", startaddr);
	    fflush(stderr);
	} else {
	    (*o->opfun)(inst, o->farg);
	}
	following = false;
    }
    return instaddr;
}

/*
 * Step to the given address and then execute one instruction past it.
 * Set instaddr to the new instruction address.
 */

private steppast(addr)
Address addr;
{
    stepto(addr);
    pstep(process, DEFSIG);
    pc = reg(PROGCTR);
    instaddr = pc;
}

/*
 * Enter a procedure by creating and executing a call instruction.
 */

#define CALLSIZE 6	/* size of call instruction */

public beginproc(p)
Symbol p;
{
    char save[CALLSIZE];
    struct {
	short op;
	char addr[sizeof(long)];	/* unaligned long */
    } call;
    long dest;

    pc = CODESTART + 6;
    iread(save, pc, sizeof(save));
    call.op = 0x4eb9;			/* jsr */
    dest = codeloc(p) - FUNCOFFSET;
    mov(&dest, call.addr, sizeof(call.addr));
    iwrite(&call, pc, sizeof(call));
    setreg(PROGCTR, pc);
    pstep(process, DEFSIG);
    iwrite(save, pc, sizeof(save));
    pc = reg(PROGCTR);
    if (not isbperr()) {
	printstatus();
    }
    /*
     * Execute link instruction so the return addr is visible.
     */
    pstep(process, DEFSIG);
    pc = reg(PROGCTR);
    if (not isbperr()) {
	printstatus();
    }
}

/*
 * Special variables for debugging the kernel.
 */

public integer masterpcbb;
public integer slr;
public struct pte *sbr;
private struct pcb pcb;

public getpcb ()
{
    integer i;

    fseek(corefile, masterpcbb & ~0x80000000, 0);
    get(corefile, pcb);
    pcb.pcb_p0lr &= ~AST_CLR;
    printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n",
	pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr
    );
#   ifdef sun
    for (i = 0; i < 14; i++) {
	setreg(i, pcb.pcb_regs.val[i]);
    }
#   else /* IRIS */
    for (i = 0; i < 14; i++) {
	setreg(i, pcb.pcb_regs[i]);
    }
#   endif
}

public copyregs (savreg, reg)
Word savreg[], reg[];
{
    reg[0] = savreg[R0];
    reg[1] = savreg[R1];
    reg[2] = savreg[R2];
    reg[3] = savreg[R3];
    reg[4] = savreg[R4];
    reg[5] = savreg[R5];
    reg[6] = savreg[R6];
    reg[7] = savreg[R7];
    reg[8] = savreg[AR0];
    reg[9] = savreg[AR1];
    reg[10] = savreg[AR2];
    reg[11] = savreg[AR3];
    reg[12] = savreg[AR4];
    reg[13] = savreg[AR5];
    reg[14] = savreg[AR6];
    reg[15] = savreg[AR7];
    reg[PROGCTR] = savreg[PC];
}

/*
 * Map a virtual address to a physical address.
 * XXX THIS CAN'T BE RIGHT... XXX
 */

public Address vmap (addr)
Address addr;
{
    Address r;
    integer v, n;
    struct pte pte;

    r = addr & ~0xc0000000;
    v = btop(r);
    switch (addr&0xc0000000) {
	case 0xc0000000:
	case 0x80000000:
	    /*
	     * In system space, so get system pte.
	     * If it is valid or reclaimable then the physical address
	     * is the combination of its page number and the page offset
	     * of the original address.
	     */
	    if (v >= slr) {
		error("address %x out of segment", addr);
	    }
	    r = ((long) (sbr + v)) & ~0x80000000;
	    goto simple;

	case 0x40000000:
	    /*
	     * In p1 space, must not be in shadow region.
	     */
	    if (v < pcb.pcb_p1lr) {
		error("address %x out of segment", addr);
	    }
	    r = (Address) (pcb.pcb_p1br + v);
	    break;

	case 0x00000000:
	    /*
	     * In p0 space, must not be off end of region.
	     */
	    if (v >= pcb.pcb_p0lr) {
		error("address %x out of segment", addr);
	    }
	    r = (Address) (pcb.pcb_p0br + v);
	    break;

	default:
	    /* do nothing */
	    break;
    }
    /*
     * For p0/p1 address, user-level page table should be in
     * kernel virtual memory.  Do second-level indirect by recursing.
     */
    if ((r & 0x80000000) == 0) {
	error("bad p0br or p1br in pcb");
    }
    r = vmap(r);
simple:
    /*
     * "r" is now the address of the pte of the page
     * we are interested in; get the pte and paste up the physical address.
     */
    fseek(corefile, r, 0);
    n = fread(&pte, sizeof(pte), 1, corefile);
    if (n != 1) {
	error("page table botch (fread at %x returns %d)", r, n);
    }
    if (pte.pg_v == 0 and (pte.pg_fod != 0 or pte.pg_pfnum == 0)) {
	error("page no valid or reclamable");
    }
    return (addr&PGOFSET) + ((Address) ptob(pte.pg_pfnum));
}

/*
 * Extract a bit field from an integer.
 */

public integer extractField (s)
Symbol s;
{
    integer nbytes, nbits, n, r, off, len;

    off = s->symvalue.field.offset;
    len = s->symvalue.field.length;
    nbytes = size(s);
    n = 0;
    if (nbytes > sizeof(n)) {
	printf("[bad size in extractField -- word assumed]\n");
	nbytes = sizeof(n);
    }
    popn(nbytes, ((char *) &n) + (sizeof(Word) - nbytes));
    nbits = nbytes * BITSPERBYTE;
    r = n >> (nbits - ((off mod nbits) + len));
    r &= ((1 << len) - 1);
    return r;
}

/*
 * Change the length of a value in memory according to a given difference
 * in the lengths of its new and old types.
 */

public loophole (oldlen, newlen)
integer oldlen, newlen;
{
    integer i, n;
    Stack *oldsp;

    n = newlen - oldlen;
    oldsp = sp - oldlen;
    if (n > 0) {
	for (i = oldlen - 1; i >= 0; i--) {
	    oldsp[n + i] = oldsp[i];
	}
	for (i = 0; i < n; i++) {
	    oldsp[i] = '\0';
	}
    } else {
	for (i = 0; i < newlen; i++) {
	    oldsp[i] = oldsp[i - n];
	}
    }
    sp += n;
}