/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:print.c 12.0$ */
/* $ACIS:print.c 12.0$ */
/* $Source: /ibm/acis/usr/src/bin/adb_ca/RCS/print.c,v $ */

#ifndef lint
static char *rcsid = "$Header:print.c 12.0$";
#endif
/*
 *
 *      UNIX debugger
 *
 */
#ifdef __HIGHC__
pragma off(prototype_override_warnings);
#endif

#include <frame.h>
#include <sys/signal.h>
#include <machine/sigframe.h>
#include <machine/reg.h>
#include <machine/float.h>
#include <machine/vmparam.h>
#undef SP
#include "defs.h"


MSG             LONGFIL;
MSG             NOTOPEN;
MSG             BADMOD;
MAP             txtmap;
MAP             datmap;
INT             infile;
INT             outfile;
CHAR            *lp;
INT		warnflag;
L_INT           maxoff;
L_INT           maxpos;
INT             radix;
/* symbol management */
L_INT           localval;

/* breakpoints */
BKPTR           bkpthead;
REGLIST reglist [] = {		/* Non-contiguous user elements */
	"ucode", U_CODE, ri_abs,  (int *)1,
	"stack", U_SSIZE, ri_abs, (int *)1,
	"data",  U_DSIZE, ri_abs, (int *)1,
        "p1lr", P1LR,   ri_abs, &user.u_pcb.pcb_p1lr,
        "p1br", P1BR,   ri_abs, (int *)&user.u_pcb.pcb_p1br,
        "p0lr", P0LR,   ri_abs, &user.u_pcb.pcb_p0lr,
        "p0br", P0BR,   ri_abs, (int *)&user.u_pcb.pcb_p0br,
        "error",UERROR, ri_abs, 0,
				/* Start contiguous elements (sys/ca/reg.h) */
        "icscs",0,	ri_cc,  &user.u_pcb.pcb_icscs,	
        "iar",  0,	ri_sym, &Kernel_iar, /* roffs must initally be zero! */
        "mq",   0,	ri_abs, 0,
        "r15",  0,	ri_sym, &user.u_pcb.pcb_r15,
        "r14",  0,	ri_sym, &user.u_pcb.pcb_r14,
        "r13",  0,	ri_sym, &user.u_pcb.pcb_r13,
        "r12",  0,	ri_sym, &user.u_pcb.pcb_r12,
        "r11",  0,	ri_sym, &user.u_pcb.pcb_r11,
        "r10",  0,	ri_sym, &user.u_pcb.pcb_r10,
        "r9",   0,	ri_sym, &user.u_pcb.pcb_r9,
        "r8",   0,	ri_sym, &user.u_pcb.pcb_r8,
        "r7",   0,	ri_sym, &user.u_pcb.pcb_r7,
        "r6",   0,	ri_sym, &user.u_pcb.pcb_r6,
        "r5",   0,	ri_sym, &user.u_pcb.pcb_r5,
        "r4",   0,	ri_sym, &user.u_pcb.pcb_r4,
        "r3",   0,	ri_sym, &user.u_pcb.pcb_r3,
        "r2",   0,	ri_sym, &user.u_pcb.pcb_r2,
        "r1",   0,	ri_sym, &user.u_pcb.pcb_r1,
        "r0",   0,	ri_sym, &user.u_pcb.pcb_r0
};
int NumReglistElements = sizeof(reglist) / sizeof(struct reglist);
char            lastc;
INT             fcor;
INT             signo;
INT             sigcode;
L_INT           dot;
L_INT           var[];
STRING          symfil;
STRING          corfil;
INT             pid;
L_INT           adrval;
INT             adrflg;
L_INT           cntval;
INT             cntflg;
STRING          signals[] = {
                "",
                "hangup",
                "interrupt",
                "quit",
                "illegal instruction",
                "trace/BPT",
                "IOT",
                "EMT",
                "floating exception",
                "killed",
                "bus error",
                "memory fault",
                "bad system call",
                "broken pipe",
                "alarm call",
                "terminated",
                "signal 16",
                "stop (signal)",
                "stop (tty)",
                "continue (signal)",
                "child termination",
                "stop (tty input)",
                "stop (tty output)",
                "input available (signal)",
                "cpu timelimit",
                "file sizelimit",
                "signal 26",
                "signal 27",
                "signal 28",
                "signal 29",
                "signal 30",
                "signal 31",
};

char Error_buf[128];

/* Opcodes and masks fully left shifted and word aligned. */
#define SHORTOP_MASK	0xf0000000
#define OP_MASK		0xff000000
#define AI_OPCODE	0xc1000000
#define B_OPCODE	0x88000000
#define CAL_OPCODE	0xc8000000
#define CAS_OPCODE	0x60000000
#define ST_OPCODE	0xdd000000
#define STM_OPCODE	0xd9000000
#define STS_OPCODE	0x30000000

#define MAX_SHORT_OP	0x70000000
#define NFPREGS		64

#define BALA_OPCODE	0x8b000000
#define BALAX_OPCODE	0x8a000000
#define BALI_OPCODE	0x8c000000
#define BALIX_OPCODE	0x8d000000
#define BALR_OPCODE	0xec000000
#define BALRX_OPCODE	0xed000000

			/* Table used to search for the branch and link
			 * that gave us our present return address
			 */
struct balTest {
	unsigned int	instr;	/* opcode value */
	int 		backiar;/* distance from opcode to return addr */
} balTest[] = {			/* Order may be important. */
	BALIX_OPCODE,	8,
	BALRX_OPCODE,	6,
	BALAX_OPCODE,	8,
	BALI_OPCODE,	4,
	BALR_OPCODE,	2,
	BALA_OPCODE, 	4,
};

/*
#define SIGN_EXTEND_INSTR_WORD(instr)\
	((((0x000fffff & (instr)) ^ 0x00080000) - 0x00080000) << 1)
*/

L_INT	RegArr[MAXREGNO];	/* Scratch array to hold a frame's registers */

/* Number of words we are will search down instruction space for tracetable */
#define MAXTRACECNT	4000

/* Get left and right nibbles of a char. */
#define LNIBBLE(c)	((((c) & 0xF0) >> 4) & 0x0F)
#define RNIBBLE(c)	((c) & 0x0F)

#define NOT		!
#define ERROR_OK	1

/* Over estimate of trace table size in words. */
#define TTSIZE	4
static union TTbuf {		/* Buffer to offload t-table from text. */
	L_INT	tt_wbuf[TTSIZE];			/* Word access. */
	char	tt_cbuf[TTSIZE * sizeof(L_INT)];	/* Byte access. */
} TTbuf;

		/* Max no. word pairs to search up stack before quitting.
		 * Multiply by 2 for number of words. */
#define MAXFRAMESIZ	1500
extern int errno;


#define UPPERSTACK	(pid ? (USRSTACK)  : datmap.e2)
#define LOWERSTACK	(pid ? getRegByName("stack") : datmap.b2)
	/* Is the address x a valid stack address? */
#define inStack(x)	(LOWERSTACK <= (x) && (x) < UPPERSTACK)

#define UPPERDATA	(pid ? txtmap.e2 : datmap.e1)
#define LOWERDATA	(pid ? txtmap.b2 : datmap.b1)
	/* Is the address x a valid data address? */
#define inData(x)	(LOWERDATA <= (x) && (x) < UPPERDATA)

#define UPPERINSTR	txtmap.e1
#define LOWERINSTR	txtmap.b1
	/* Is the address x a valid instruction address? */
#define inInstr(x)	(LOWERINSTR <= (x) && (x) < UPPERINSTR)

int getwordCounter;	/* Debugging and profiling adb. */

/* MAXTRACE is the max number of tracebacks to take if cntval has
 * not been set by user (e.g.  ,N$c). */
#define MAXTRACE	24

#define	r0		0
#define	r1		1	/* stack register; bottom of stack frame */
#define	r2		2
#define r3		3
#define	r4		4
#define r5		5
#define r6		6
#define r6		6
#define r7		7
#define r8		8
#define r9		9
#define r10		10
#define r11		11
#define r12		12
#define r13		13
#define r14		14	/* usually addresses fn's data area
				 * ("constant pool")
				 */
#define r15		15	/* link register; address of caller */

/* Absolute max num of autos to print. For pretty sakes, make it multple
 * of 8. */
#define MAXAUTOWORDS	64
#define MINSYMTOPRINT	0x80	/* Arbitrary lower limit for register values
				   to be printed symbolically	*/

/* {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{
 *		global structures and function prototypes
 */

			/* Filled mostly by call to getFuncName;
			 * called_from_addr set by validSavedLink 
			 */
struct funcName { 			/* info about current function. */
	char *		fn_name;	/* Function's name. */
	struct nlist *	fn_symPtr;	/* Ptr to functions symtab entry. */
	ADDR		entry_point;
	ADDR		called_from_addr;
} FN;
/* Everything we would want to know from the current routine's trace
 * table, plus some derived info.
 */
			/* Filled by call to getTraceTable */
typedef struct {
	int	rtype;			/* type: 2, 3, or 7 at present */
	int	first_gpr;		/* First saved register. */
	int	param_words;		/* Number of parameter words. */
	int	local_offset;		/* Bytes from frame ptr to frame top.*/
	int	frame_reg;		/* Register containing frame ptr. */
	char	wflg;			/* w field present if !0. */
	char	xflg;			/* x field present if !0. */
	char	yflg;			/* y field present if !0. */
	char	zflg;			/* z field present if !0. */
	ADDR	where;			/* text address of trace table */
} TTABLE;

TTABLE TT;	/* The trace table. */

			/* Filled by call to eatProlog */
struct {
	ADDR	return_addr;
	ADDR	frame_top;
/*	ADDR	const_tbl_ptr; */
	int	did_stm;
	L_INT	argLoc[4];	/* Reg no, or negative */
} PI;

#ifdef __STDC__
int printtrace(int modif);
int printmap(STRING s, MAP *amap);
int printregs(void);
int printFpRegs(void);
int getRegByName(char *name);
int getreg(int regnam);
int printpc(void);
int sigprint(void);
int traceFromStackAddr(ADDR stackAddr, int maxTrace, int modif);
int traceFromRegs(int maxTrace, int modif);
void stackWalk(int maxTrace, int modif);
void getFuncName(ADDR pc);
void printArgs(void);
void eatProlog(ADDR entryAddr, ADDR endpc);
ADDR getRegVal(int regNum);
int printAutosandRegs(void);
ADDR pcOffStack(ADDR addr);
ADDR srchForRegs(ADDR saddr);
ADDR validSavedLink(ADDR returnAddr, int errorOk, ADDR prevSp);
int tryBal(ADDR returnAddr, struct balTest);
ADDR printSigFrame();
void getTraceTable(ADDR pc);
int scanForTable(ADDR pc);
int unPack(ADDR pc, union TTbuf *ttBuf);
int setDefaults(void);
void getNameFromText(ADDR pc);
int fillRegArray(void);
int printexception(void);
int print_ecr(int ecr_count, int ecr_addr);
char *xtod(unsigned int[3]);
#endif

/* }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} */

#ifdef DEBUG
printFN() 
{
	printf("FN: fn_name %s, fn_symPtr %X, entry_point %X, called_from_addr %X\n",
	FN.fn_name, FN.fn_symPtr, FN.entry_point, FN.called_from_addr);
}
printTT() { dumpTraceTable(&TT); }

printPI()
{
	printf("PI: return_addr %X, argLoc %d %d %d %d\n",
	PI.return_addr, PI.argLoc[0], PI.argLoc[1], PI.argLoc[2], PI.argLoc[3]);
}

#endif

/* Test for determining if in the frame of a signal handler */
#define inSigHandler(returnAddr)\
		((returnAddr) >= UAREA && (returnAddr) < ENDOFP1)

/* Macro to get to top of current frame. */
#define topOfFrame(fp,offset) (RegArr[fp] + (offset))

/* Get stack address of a saved register. */
#define getSavedRegAddr(frame_top,regnum)\
	(frame_top+ REG_OFFSET + (regnum) * sizeof(int))

/* GETWORD is identical to get(), apparently for historical reasons. */
#define GETWORD(addr,space)	(access(RD, (addr), (space), 0))
#define WORDEQ(w1,w2,mask)	(((w1) & (mask)) == (w2))

	/* Sanity check - frame pointers are always in these registers: */
#define validFrameRegNum(frameRegNum) ((frameRegNum) == 1 || (frameRegNum) == 13)


/* Adb will do tracebacks only through functions with particular
 * trace table types. This macro tests for these. */
#define validRtype(rtype) ((rtype) == 2 || (rtype) == 3 || (rtype) == 7)

/* Based on the tracetable rtype, is the iar in a function which
 * buys no frame. */
#define funcHasNoFrame(rtype)	((rtype) == 2)

	/* Sanity check - given a number, can it be a register number? */
#define validRegNum(regnum)	(0 <= (regnum) && (regnum) <= 15)

	/* Location of regnum in the relist array. */
#define regInRegList(regnum)	(NumReglistElements - 1 - (regnum))
	
ADDR CallersFp;		/* Fp of previous function, via r15. */
L_INT ConstTblPtr;	/* Data ptr from register or stack. */

/* general printing routines ($) */
printtrace(modif)
{
        INT             i;
        REG BKPTR       bkptr;
        STRING          comptr;
        register struct nlist *sp;
        INT             stack;
        IF cntflg==0 THEN cntval = -1; FI
        switch (modif) {
            case '<':
                IF cntval == 0
                THEN    WHILE readchar() != EOR
                        DO OD
                        lp--;
                        break;
                FI
                IF rdc() == '<'
                THEN    stack = 1;
                ELSE    stack = 0; lp--;
                FI
                                                        /* fall through */
            case '>':
                {CHAR           file[64];
                CHAR            Ifile[128];
                extern CHAR     *Ipath;
                INT             index;
                index=0;
                IF rdc()!=EOR
                THEN    REP file[index++]=lastc;
                            IF index>=63 THEN error(LONGFIL); FI
                        PER readchar()!=EOR DONE
                        file[index]=0;
                        IF modif=='<'
                        THEN    IF Ipath THEN
                                        (void) strcpy(Ifile, Ipath);
                                        (void) strcat(Ifile, "/");
                                        (void) strcat(Ifile, file);
                                FI
                                IF strcmp(file, "-")!=0
                                THEN    iclose(stack, 0);
                                        infile=open(file,0);
                                        IF infile<0
                                        THEN    infile=open(Ifile,0);
                                        FI
                                ELSE    lseek(infile, 0L, 0);
                                FI
                                IF infile<0
                                THEN    infile=0; error(NOTOPEN);
                                ELSE    IF cntflg
                                        THEN    var[9] = cntval;
                                        ELSE    var[9] = 1;
                                        FI
                                FI
                        ELSE    oclose();
                                outfile=open(file,1);
                                IF outfile<0
                                THEN    outfile=creat(file,0644);
#ifndef EDDT
                                ELSE    lseek(outfile,0L,2);
#endif
                                FI
                        FI
                ELSE    IF modif == '<'
                        THEN    iclose(-1, 0);
                        ELSE    oclose();
                        FI
                FI
                lp--;
                }
                break;
            case 'p':
                IF kernel == 0 THEN
                        printf("not debugging kernel\n");
                ELSE
#ifdef vax
                        IF adrflg THEN
                                int pte = access(RD, dot, DSP, 0);
                                masterpcbb = (pte&PG_PFNUM)*512;
                        FI
                        getpcb();
#endif
#ifdef ibm032
                        IF adrflg THEN
                                masterpcbb = dot;
#ifdef DEBUG
				if (debug) printf("masterpcbb = %X\n", masterpcbb);
#endif
                        FI
                        getproc();
#endif
                FI
                break;
            case 'd':
                if (adrflg) {
                        if (adrval<2 || adrval>16){
				printf("must have 2 <= radix <= 16");
				break;
			}
                        printf("radix=%d base ten",radix=adrval);
                }
                break;
            case 'q': case 'Q': case '%':
                done();
            case 'w': case 'W':
                maxpos=(adrflg?adrval:MAXPOS);
                break;
            case 's': case 'S':
                maxoff=(adrflg?adrval:MAXOFF);
                break;
            case 'v': case 'V':
                prints("variables\n");
                FOR i=0;i<=35;i++
                DO IF var[i]
                   THEN printc((i<=9 ? '0' : 'a'-10) + i);
                        printf(" = %X\n",var[i]);
                   FI
                OD
                break;
            case 'm': case 'M':
                printmap("? map",&txtmap);
                printmap("/ map",&datmap);
                break;
            case 0: case '?':
                IF pid
                THEN printf("pcs id = %d\n",pid);
                ELSE prints("no process\n");
                FI
		printexception();
                sigprint(); flushbuf();
            case 'r': case 'R':
               	printregs();
                break;
	    case 'z':
		printexception();
		break;
	
#ifdef DEBUG
case 'Y':
	{
	int t;
	errno = 0;
	t = GETWORD(adrval,ISP);
	printf("errno=%d word=%d\n", errno, t);
	}
	break;

case 'X':	/* Hindsight:should use the adrval to set debug levels. */
	debug = !debug;		/* Switch debug off/on */
	break;
#endif
	case 'D':		/* Dump entire symbol table(D). */
	{
		struct nlist *sp;
		for (sp = symtab; sp < esymtab; sp++) {
			int type = sp->n_type;
			printf("%-18s %10X %d ",
					sp->n_un.n_name,sp->n_value,type);
			if((type & 0xfe) == 0x1f)
				printf("%s", "filename");
			else {
				if((type & 0xfe) == 0x2)
					printf("%s","abs ");
				else if((type & 0xfe) == 0x4)
					printf("%s", "text");
				else if((type & 0xfe) == 0x6)
					printf("%s", "data");
				else if((type & 0xfe) == 0x8)
					printf("%s", "bss ");
				else if((type & 0xfe) == 0x12)
					printf("%s", "comm");
				if((type & 0x1) == 0x1)
					printf("%s", " extern");
			}
			printf("\n");		
		}
	}
	break;

	case 'P':
		if(adrflg) {
			masterpcbb = adrval;
			getproc();
		}
		break;
	case 'f':
		    printFpRegs();
		    break;
	case 'c':	/* Backtrace */
	case 'C':	/* Backtrace and print autos */
		{
		int maxTrace = cntval >= 0 ? cntval : MAXTRACE;
		if(adrflg)
			(void) traceFromStackAddr(adrval, maxTrace, modif);
		else
			(void) traceFromRegs(maxTrace,modif);
		break;
		}
	
	case 'e':  case 'E':
              for (sp = symtab; sp < esymtab; sp++) {
                 if (sp->n_type==(N_DATA|N_EXT) ORF sp->n_type==(N_BSS|N_EXT))
                      printf("%s:%12t%R\n",
				sp->n_un.n_name, GETWORD(sp->n_value,DSP));
              }
              break;
            case 'a': case 'A':
                error("No algol 68 here");
            /*print breakpoints*/
            case 'b': case 'B':
                printf("breakpoints\ncount%8tbkpt%24tcommand\n");
                for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt)
                        if (bkptr->flag) {
                                printf("%-8.8d",bkptr->count);
                                psymoff(bkptr->loc,ISYM,"%24t");
                                comptr=bkptr->comm;
                                WHILE *comptr DO printc(*comptr++); OD
                        }
                break;
            default: error(BADMOD);
        }
}
printmap(s,amap)
STRING  s; MAP *amap;
{
        int file;
        file=amap->ufd;
        printf("%s%12t`%s'\n",s,(file<0 ? "-" : (file==fcor ? corfil : symfil)));
        printf("b1 = %-16R",amap->b1);
        printf("e1 = %-16R",amap->e1);
        printf("f1 = %-16R",amap->f1);
        printf("\nb2 = %-16R",amap->b2);
        printf("e2 = %-16R",amap->e2);
        printf("f2 = %-16R",amap->f2);
        printc(EOR);
}

printregs()
{
        REG REGPTR      p;
        REG L_INT       v;
	REG int		firstreg, lastreg;
	if(!kcore && !adrflg) {
		printf("%s%6t%R -> %R\n", "stack",
			USRSTACK,(pid?StackBottom:datmap.b2));
		printf("%s%6t%R -> %R\n",
			"data", DATABASE, (pid?DataTop:datmap.e2));
	}

	if(adrflg) {
		lastreg = cntflg ? (adrval + cntval) : (adrval + 1);
		if(!validRegNum(adrval) || !validRegNum(lastreg-1)) {
			printf("Error: %D-%D not in range.\n",adrval,lastreg);
			return;
		}
			/* Note: regs in descending order in reglist */
		firstreg = regInRegList(adrval) + 1;	/* Last printed. */
		lastreg = cntflg ? (adrval + cntval) : (adrval + 1);
		lastreg = regInRegList(lastreg) + 1;	/* 1st printed. */
	}
	else {
		    /* First means low end of the register values, not 1st printed */
		firstreg = NumReglistElements;
		lastreg  = 0;	/* All C arrays start at zero. */
	}
        FOR p = &reglist[lastreg]; p < &reglist[firstreg]; p++
       	DO      v = kcore ? *p->rkern:*(ADDR *)(((ADDR)&u)+p->roffs);
		if(!kcore && p->rkern == (int *)1)
		    continue;
		if(kcore && p->rkern == 0)
			continue;
               	printf("%s%6t%R %16t", p->rname, v);
		if (p->rinterp == ri_cc) {
		    char* ccnames= "lt\0eq\0gt\0c0\0rs\0ov\0tb ";
		    int m=v;
		    char delim='[';
		    while (m=(m<<1)&0xff) {
			if (m&0x80) {
			    printc(delim);
			    delim=',';
			    prints(ccnames);
			}
			ccnames +=3;
		    }
		    if (delim!='[') printc(']');
		}
		else if (p->rinterp == ri_sym && v >= MINSYMTOPRINT) 
		    (void) valpr(v,(p->roffs==User_iar?ISYM:DSYM));
       	        printc(EOR);
        OD
	if (!adrflg) {
		printexception();
		printpc();
	}
}

	/* Print the floating point registers. */
printFpRegs() {
	register int i, j;
	int fpa_dev_regs;
	union fpPair {
		unsigned int fp_ia[NFPREGS];
		double fp_da[NFPREGS/2];
	} fpReg;	/* place for ptrace to put fp regs. */

	dprintf((" printFpRegs: Beginning of routine\n"));

		/* test for floating point hardware and modify fpa_dev_regs */

	fpa_dev_regs = -1;

	dprintf(("printFpRegs: begin testing for floating point hardware \n"));
	dprintf(("printFpRegs: user.u_floatmask = %d\n",user.u_floatmask));

	if (float_has_emul(user.u_floatmask))
		{
		fpa_dev_regs=16;
		printf((" emul registers:\n"));
		}

	else if (float_has_fpa(user.u_floatmask)) 
		{
		fpa_dev_regs=16;
		printf((" fpa registers:\n"));
		}

	else if (float_has_881(user.u_floatmask)) 
		{
		fpa_dev_regs=24;
		printf((" mc881 registers:\n"));
		}

	else if (float_has_afpa(user.u_floatmask)) 
		{
		fpa_dev_regs=64;
		printf((" afpa registers:\n"));
		}

	if (fpa_dev_regs == -1)
		{
		printf(" No floating point registers have been allocated.\n");
		return;
		}
	errno = 0;	/* for ptrace checks */	
	if (pid) {
	    for(i=0; i < fpa_dev_regs; i++) {
		if((fpReg.fp_ia[i] = ptrace(PT_READ_F, pid, i, 0)) == -1
		&& errno) 
		    break;
	    }
	} else {
	    int *user_regs = (int *)USER_FPM;
	    for (i=0; i<fpa_dev_regs; i++) {
		fpReg.fp_ia[i] = user_regs[i];
	    }
	}
	if(errno != EIO || fpReg.fp_ia[i] != -1)
	switch(fpa_dev_regs) {
	case 0: 
		printf("No fp registers allocated.\n");
		break;
	case 16:
			/* Not all fp regs contain floating point values. */
		for(j=0; j < 16-2; j++) {
			printf("fpr%d%6t%X%6t%16f",
				j, fpReg.fp_ia[j], *((float *)&fpReg.fp_ia[j]));
			if(j % 2 == 0)
			    printf("%8t%F", fpReg.fp_da[j/2]);
			printf("\n");
		}
			/* Print fp regs containing status info. */
		for(; j < i; j++)
			printf("fpr%d%6t%X\n", j, fpReg.fp_ia[j]);
		break;
	case 24:
		for(i=j=0; j < 24; i++,j += 3)
			printf("fpr%d %6t %X %X %X %6t %s\n",
				i,
				fpReg.fp_ia[j],
				fpReg.fp_ia[j+1],
				fpReg.fp_ia[j+2],
				xtod(&fpReg.fp_ia[j]));
		break;
	case 64:
		for(j=0; j < 16; j++) {
			printf("fpr%d%6t%X%6t%16f",
				j, fpReg.fp_ia[j], *((float *)&fpReg.fp_ia[j]));
			if(j % 2 == 0)
			    printf("%8t%F", fpReg.fp_da[j/2]);
			printf("\n");
		}
		break;
	default:
		printf("Assertion botch:unexpected number of fp registers, "
			"got %d\n",fpa_dev_regs);
		break;
	}
}

    /* Given a rname string (in reglist), return the offset */
getRegByName(name)
register char *name;
{
	register REGPTR p;
	char buf[100];
	for(p = reglist; p < &reglist[NumReglistElements]; p++) {
	    if(strcmp(p->rname,name) == 0) {
		return((int)p->roffs);
	    }
	}
	sprintf(buf,"getRegByName internal error trying to find '%s'",name);
	error(buf);
}

getreg(regnam) {
        REG REGPTR      p;
        REG STRING      regptr;
        CHAR    *olp;
        olp=lp;
        FOR p=reglist; p < &reglist[NumReglistElements]; p++
        DO      regptr=p->rname;
                IF (regnam == *regptr++)
                THEN
                        WHILE *regptr
                        DO IF (readchar()) != *regptr++
                                THEN --regptr; break;
                                FI
                        OD
                        IF *regptr
                        THEN lp=olp;
                        ELSE
                                int i = kcore ? (int)p->rkern : p->roffs;
                                return (i);
                        FI
                FI
        OD
        lp=olp;
        return(0);
}
printpc()
{
        dot = kcore ? Kernel_iar : User_iar;
        psymoff(dot,ISYM,":%16t"); printins(dot,chkget(dot,ISP));
        printc(EOR);
}
char    *illinames[] = {
        "reserved addressing fault",
        "priviliged instruction fault",
        "reserved operand fault"
};
char    *fpenames[] = {
	"floating operation invalid",
	"floating overflow exception",
	"floating underflow exception",
	"floating divide by zero exception",
	"floating inexact result exception",
	"integer divide by zero exception"
};
sigprint()
{
	dprintf(("sigprint: Beginning of routine\n"));
	dprintf(("sigprint: signo =%d\n",signo));
	dprintf(("sigprint: sigcode =%d\n",sigcode));
        IF (signo>=0) ANDF (signo<sizeof signals/sizeof signals[0])
        THEN prints(signals[signo]); FI
        switch (signo) {
        case SIGFPE:
                IF (sigcode >= 0 &&
                    sigcode < sizeof fpenames / sizeof fpenames[0]) THEN
                        prints(" ("); prints(fpenames[sigcode]); prints(")");
                FI
                break;
        case SIGILL:
                IF (sigcode >= 0 &&
                    sigcode < sizeof illinames / sizeof illinames[0]) THEN
                        prints(" ("); prints(illinames[sigcode]); prints(")");
                FI
                break;
        }
}


/* Set up for a stackWalk. Starting at stackAddr, scan up stack to find a
 * stored r14/r15 combo. Pass off info to stackWalk(). */
traceFromStackAddr(stackAddr, maxTrace, modif)
ADDR stackAddr;
int maxTrace, modif;
{
	register ADDR pc;			/* Text address. */
	/*ADDR stackPtr;				/* frame's stackptr. */
	
					/* Scan up stack for r14/r15 pair. */
	if((pc = pcOffStack(stackAddr)) == 0) {
		printf("Can't trace - absurd stack!\n");
		return(0);
	}
	
	getTraceTable(pc);		/* Calls error if no TT found */
					/* Try to walk up stack. */
	/* Debugging gunk */
	dprintf(("===> STARTING TRACEBACK FROM r14/r15 PAIR FROM STACK<==\n"));

	stackWalk(maxTrace, modif);
}

/* Set up for a stack walk using register and stack info as starting point.
 */
traceFromRegs(maxTrace, modif)
int maxTrace, modif;
{
	int i;
	register ADDR linkAddr, returnAddr, currentIar;

	currentIar = (kcore ? Kernel_iar : User_iar);
	returnAddr = getRegVal(r15);
	if (!inInstr(currentIar) && (inInstr(returnAddr)))
	{
		/* RTFL or a dynamic linker may have put the iar in data.
		 * We can backtrace only if r15 tells us who branched
		 * to data; we will assume the code in data bought no frame.
		 */
		printf("iar at %X, assumed called from ",currentIar);
		psymoff(returnAddr, ISP, "");
		printf("\n");
		currentIar=returnAddr;
	}

	/* RegArr will hold, for each frame, that function's notion
	 * of the values in r1 and r6-r15.  Initialize it.
	 */

	for (i=0; i < MAXREGNO; i++) 
		RegArr[i] = getRegVal(i);

	getFuncName(currentIar);
	getTraceTable(currentIar);	/* Calls error if no TT found */

	eatProlog(FN.entry_point,currentIar);

	if(funcHasNoFrame(TT.rtype)) {	
		/* A type 2 function with no stack frame should appear only at
		 * the top of the stack.  Handle it here and set up to call
		 * stackWalk with the caller's stack frame.
		 */

			/* Get return address */
		returnAddr = getRegVal(r15);
		
			/* "Normal" type2 should not have linkreg in stack,
			 * but if r15 does not look reasonable, then
			 * try to get link addr off stack and see if it looks
			 * reasonable. */
		if(validSavedLink(returnAddr,ERROR_OK, 0) == 0) {
			returnAddr = GETWORD(getSavedRegAddr(PI.frame_top,
				r15), DSP);
			
				/* Test for reasonable return address. */
			validSavedLink(returnAddr, NOT ERROR_OK, 0);
		}
		printArgs();

				/* Get caller's tracetable. */
		getFuncName(returnAddr);
		getTraceTable(returnAddr);	/* Calls error if no TT */
		eatProlog(FN.entry_point,returnAddr);
	} /* end type 2 */

		/* Validate return address and locate bal instruction */
		validSavedLink(PI.return_addr, NOT ERROR_OK, PI.frame_top);

	dprintf(("===> STARTING A TRACEBACK FROM EXISTING REGISTERS <==\n"));

		/* Walk up stack, printing info on each frame */
	stackWalk(maxTrace, modif);
}
	
/* Given the entry point of a function, the associated frame pointer and
 * trace table, march up to top of stack printing available info. 
*/
void
stackWalk(maxTrace, modif)
int maxTrace;			/* Max no. frames to walk up. */
int modif;			/* Has to be 'c' or 'C'. */
{
	register int activeFrame;
	ADDR currentIar;
	ADDR pc;


 	for(activeFrame=0; activeFrame < maxTrace; ++activeFrame) {

#ifdef DEBUG
if (debug) {
printf("\n Top of stackwalk:\n");
printPI();
printFN();
printTT();
}
#endif
		 /* Print fn name and arguments and 'called from' */
		printArgs();
		if (TT.rtype == 3) return;
		if(modif == 'C') 
			printAutosandRegs();

/* Get new values for next frame on stack */
/* Next frame's stackPtr is top of current frame. */

		fillRegArray();
		RegArr[r1] = PI.frame_top;
		currentIar = RegArr[r15];
		if (inSigHandler(currentIar))
			currentIar = printSigFrame();
		getFuncName(currentIar);
		getTraceTable(currentIar);	/* No return if error */
		eatProlog(FN.entry_point,currentIar);
		
/* Trace back termination condition for kernel stack. */

		if(kcore && (PI.frame_top + sizeof(int) > KERNSTACK))
			return;

		validSavedLink(PI.return_addr, NOT ERROR_OK, PI.frame_top);
	}

dprintf(("==> STACK TRACE BACK COMPLETE <==\n")); 
	return;
}


/* Given a text address, find the name of the function. */
void
getFuncName(pc)
register ADDR pc;
{
	static char nameBuf[16];	/* Holds 10 hex chars (0x00000000). */

	if (symTableIsPresent() && (staticSym(pc), cursym!=(struct nlist *)0)) {
		/* staticSym sets cursym as side effect */
		FN.fn_symPtr = cursym;	
		FN.fn_name = cursym->n_un.n_name;
		FN.entry_point = cursym->n_value;
	}
	else {
		FN.fn_symPtr = (struct nlist *) 0;
		getNameFromText(pc);	 /* Sets fn_name and entry_point */
	}
	return;
}

/* The call of eatProlog previously has set up the argLoc vector to describe
 * args 1-4.
 * A positive value is a register number;
 * a negative value indicates storage in the arglist on the stack.
 */

void
printArgs()
{
	register ADDR argAddress =
		PI.frame_top - ARG_SAVE_SZ;
	register L_INT argVal;
	register int i;

dprintf((" printArgs: Beginning of routine\n"));
	printf("%s(", FN.fn_name);

	for(i = 1; i <= TT.param_words; i++) {
		if (i <= 4 && PI.argLoc[i-1]>0) {
			printf("r%d=",PI.argLoc[i-1]);
			argVal = RegArr[PI.argLoc[i-1]];
		}
		else
			argVal = GETWORD(argAddress,DSP);
		printf("%X", argVal);
		if(i < TT.param_words)
			printf((i&3)!=3 ? ", " : ",\n\t");
		argAddress += sizeof(int);
	}
	if (TT.rtype == 3) {		/* Hit the end of the stack */
		printf(")\n");
		return;
	}
	if (inSigHandler(FN.called_from_addr)) 
		printf(")  signal handler");
	else {
		printf(")  from ");
		psymoff(FN.called_from_addr, ISP, "");
	}
	printf("\n");
}

/* Chew through the code at the putative entry point, garnering useful
 * information into struct PI, until the code stops looking like a prolog.
 * Top-of-stack frame processing needs to know how much of prolog has
 * been executed; all frame processing needs to know where arguments
 * got stashed.  
 * Return_addr and frame_top get recalculated each time we discover that
 * one more crucial prolog instruction was executed.
 * Be fairly relaxed about what might appear in a prolog.  The goal is
 * to find out what happened to the key registers, even in the presence
 * unusual instruction sequences.  (We do consider the prolog to have
 * ended at the first unrecognized opcode.)
 *
 *	Sets:
 *		return_addr from current r15 or from saved r15 if stm'd
 *		frame_top
 *		argLoc[0-3] positive, reg no. of argument i+1
 *			or  negative if arg 1-4 stored in stack arglist.
 */
void
eatProlog(entryAddr, endpc)
ADDR entryAddr, endpc;
{
	ADDR	pc = entryAddr;
	unsigned int w, op;
	int	ra, rb, rc;

		/* Following assignments are valid only if we're stopped
		 * at the entry point.  We will overwrite them later if
		 * it appears that execution progressed further.
		 * Assumption: a non-topmost function is not stopped
		 * in prolog code (else how could it have called another?)
		 */
	PI.argLoc[0]=r2;
	PI.argLoc[1]=r3;
	PI.argLoc[2]=r4;
	PI.argLoc[3]=r5;
	PI.return_addr = RegArr[r15]; 
	PI.frame_top = RegArr[r1];  
	PI.did_stm = 0;
	if (funcHasNoFrame(TT.rtype)) return;

	for(; pc!=endpc; pc+=2) {
		
		w = GETWORD(pc, ISP);
		    dprintf(("\t+eatProlog: w=%X pc=%X\n",w,pc));
		op = w & SHORTOP_MASK;
		if (op > MAX_SHORT_OP)		/* 4-bit opcodes are 0-7 */
			op = w & OP_MASK;	/* 8-bit opcodes are 8x-fx */
		ra = ((w & 0x0f000000) >> 24) ; /* reg a */
		rb = ((w & 0x00f00000) >> 20) ; /* reg b */
		rc = ((w & 0x000f0000) >> 16) ; /* reg c */
				/* ra,rb,rc are valid only for certain ops */
		switch (op) {

			/* Fortran prologs have branches in them.
			 * Swallow the branch and continue eating prolog.
			 */
    case B_OPCODE:
		if (ra != 8) return;	/* accept only unconditional branch */
		pc += (signed)(w<<12)>>11;
		if (!inInstr(pc)) return;	/* wild branch out of text */
		pc -= 2;		/* Defeat pc-bumping at top */
		break;
    case ST_OPCODE:
		pc += 2;
    case STS_OPCODE:

		if (rb >= r2 && rb <= r5) 
			/* Assume that the code is storing argument regs
			 * in the argument list at the end of the frame.
			 * This may not be valid; it may be a simple
			 * assignment to a local variable, in which case
			 * we guessed wrong.
			 */
			PI.argLoc[rb-r2] = (rb-6)*sizeof(int);
		if (rb != r15) break;
				/* st r15 is ok alternative to  stm r15  */
		pc -= 2;
    case STM_OPCODE:
		if (PI.did_stm) return;	/* Not the prolog's stm */
		PI.return_addr =
			GETWORD(getSavedRegAddr(PI.frame_top, r15), DSP);
		PI.did_stm = 1;
		pc += 2;
		break;
	
    case CAS_OPCODE:
		if (rb == r1) {
			/* Found  mr rn,r1; rn must be frame-ptr register */
			PI.frame_top = RegArr[TT.frame_reg] + TT.local_offset;
			PI.return_addr = GETWORD(getSavedRegAddr(PI.frame_top,
				r15), DSP);
		}
		else if (ra >= r2 && ra <= r5) {
			/* Moving an argument register to a permanent home */
			PI.argLoc[ra-r2] = rb;
		}
		break;

    case CAL_OPCODE:
    case AI_OPCODE:
		if (rc == r1) {		/* stack-ptr or frame-ptr adjust */
			if (rb == TT.frame_reg) {
			PI.frame_top = RegArr[TT.frame_reg] + TT.local_offset;
			PI.return_addr = GETWORD(getSavedRegAddr(PI.frame_top,
				r15), DSP);
			}
		}
		pc += 2;
		break;

    default:	return;			/* Certainly not in prolog */
		}
	}
}

/* Get the value stored in registerN. There are 8 reglist elements into
 * reglist[] to r15 element. */
ADDR
getRegVal(regNum)
register int regNum;
{
	register REGLIST *p = &reglist[regInRegList(regNum)];
	return(kcore ? *p->rkern : *(ADDR *)(((ADDR)&u) + p->roffs));
}

/* Print stack frame address limits, autos, and values of
 * nonvolatile registers at the bal* instruction.
 */
printAutosandRegs()
{
	register ADDR fromAddr, toAddr, stackPtr = RegArr[r1];
	register int i;

	if (stackPtr>=PI.frame_top) {
		printf("   No stack frame\n");
		return;
	}
	printf("   Frame limits     %X to %X\n",stackPtr,PI.frame_top);

		/* Upper limit is last word before regsave area */
	toAddr = getSavedRegAddr(PI.frame_top,TT.first_gpr);
	fromAddr = toAddr - MAXAUTOWORDS * sizeof(int);
	fromAddr = stackPtr > fromAddr ? stackPtr : fromAddr;
	
	for(i=0; fromAddr < toAddr; fromAddr += sizeof(int), ++i) {
		if(i == 0)
			printf("   Automatics from  %X to %X",
					fromAddr, toAddr);
		if (i%4 == 0) printf("\n\t");
		printf("%X  ",GETWORD(fromAddr,DSP));
	}
		/* Print values of nonvolatile registers (r6-r15) */
	printf("\n   r6:  %X  %X  %X  %X  %X\n   r11: %X  %X  %X  %X  %X\n\n",
	    RegArr[r6], RegArr[r7], RegArr[r8], RegArr[r9], RegArr[r10],
	    RegArr[r11], RegArr[r12], RegArr[r13], RegArr[r14], RegArr[r15]); 
}


/* Given a stack addr, return entry address of the function that is
 * using what appears to be the frame immediately above the input
 * address. Frame determination is made by looking for a r14/r15 save
 * combination on the stack. The r15 (link register) is dereferenced
 * into the callers text to get the entry address of the called
 * function (operand of bal* instruction). */
ADDR
pcOffStack(addr)
ADDR addr;
{
	ADDR entryVal;
	dprintf((" pcOffStack: Beginning of Routine\n"));
	dprintf(("\t+Looking for pc on stack, start srch at %X\n",addr));
	entryVal = srchForRegs(addr);
	dprintf(("\t+stack wrds read to r14-15 combo=%D\n",getwordCounter));
	return(entryVal);
}
	
/* Search up stack for plausible r14 and r15 starting at stack
 * address == saddr. Leap frog 2 words at a time to save time.
 * Return entry point of function on whose frame is the stored r15. */
ADDR
srchForRegs(saddr)
register ADDR saddr;
{
	register ADDR w, w1, w2;
	register int i = MAXFRAMESIZ;
	ADDR oldAddr = saddr;
	getwordCounter=0;
	saddr = WORDALIGN(saddr);
	if(!inStack(saddr)) {
		sprintf(Error_buf,"Error:%X not in stack range %X to %X\n",
			saddr, UPPERSTACK-sizeof(int), LOWERSTACK);
		error(Error_buf);
	}
	errno = 0;
	for(i=0; saddr < USRSTACK && --i; saddr += sizeof(int) * 2) {
#ifdef DEBUG
		++getwordCounter;
#endif
		w = GETWORD(saddr, DSP);
			/* Observation: stacks can contain lots of zeroes.
			 * The srch values never zero so ignore 0s. */
		if(w == 0)
			continue;
			/* Check errno from ptrace in access(). */
		if(w == -1 && errno != 0)
			break;
#ifdef DEBUG
		debug_printtype(w,saddr);
#endif
		if(inInstr(w)) {
			ConstTblPtr = w1 = GETWORD(saddr - sizeof(int), DSP);
			if(inData(w1) && 
					(w2=validSavedLink(w,NOT ERROR_OK,0))) {
				dprintf(("\t+!FOUND:stack addr=%X",saddr));
				dprintf((" link addr on stack(r15)=%X", w));
				dprintf((" data addr on stack(r14)=%X",w1));
				dprintf((" link addr points to %X\n",w2));
				return(w2);
			}
		}
		if(inData(w)) {
			ConstTblPtr = w;
			w1 = GETWORD(saddr + sizeof(int), DSP);
			if(inInstr(w1) &&
					(w2=validSavedLink(w1,NOT ERROR_OK,0))){
				dprintf(("\t+!FOUND:stack addr=%X",saddr));
				dprintf((" link addr on stack(r15)=%X", w1));
				dprintf((" data addr on stack(r14)=%X",w));
				dprintf((" link addr points to %X\n",w2));
				return(w2);
			}
		}
	}

/* Error-Warning msgs: */
	dprintf(("\t+reg search broke %D %X %X\n",i,saddr,w));
	if(i == 0)
		printf("Searched %d word pairs on stack - no r14-r15 pair",
			MAXFRAMESIZ);
	if(errno && w == -1)
		printf("stack scan from %X to non-stack address=%X",
			oldAddr, saddr);
	if(saddr >= USRSTACK)
		printf("Hit the top of the stack");
	error("Back trace attempt halted!");
	/* NOTREACHED */
}

/* Sanity check to see if return address looks reasonable.
 * Input: a link value (as in a saved r15 off stack) and
 * a pointer into a function's data (const) area (global).
 * Return the entry address of the function on whose frame we
 * found the stored r15. Return zero if something is wrong.
 * Set the address of the bal* instruction we were called from
 * in FN.called_from_addr as a side effect. */

ADDR
validSavedLink(return_addr, errorOk, prevSp)
register ADDR return_addr;
register int errorOk;
register ADDR prevSp;	/* Caller's stack ptr, = PI.frame_top I think */
{
	register int i;

	dprintf((" validSavedLink: In beginning of routine \n"));

	if (inSigHandler(return_addr)) {
		FN.called_from_addr = return_addr;
		return;
	}

	/* Look for branch and link instruction in halfwords immediately
	 * preceding the return address.  If none found, return_addr is
	 * suspect.
	 */
	for(i=0; i < sizeof(balTest)/sizeof(struct balTest); i++) {
		if (tryBal(return_addr,balTest[i])) {
			return(1);
		}
	}
dprintf(("validSavedLink: link does not appear to be valid address\n"));
	if(errorOk)	
		return((ADDR) 0);
	sprintf(Error_buf, "returns to %X with stack frame at %X;\n"
		"traceback can't continue.\n", return_addr, prevSp);
	error(Error_buf);
	/* NOTREACHED */
}

int
tryBal(returnAddr, balTest)
ADDR returnAddr;
struct balTest balTest;
{
	register L_INT bal_instr;

	FN.called_from_addr = returnAddr - balTest.backiar;
	errno = 0;
	bal_instr = GETWORD(FN.called_from_addr, ISP);
	dprintf(("\t+tryBal: %X at %X == %X ?\n",
		bal_instr, FN.called_from_addr, balTest.instr));
	if (errno) {
		if(warnflag)
			printf("error return from getword(%X, ISP)\n",
				FN.called_from_addr);
	}
	else if (WORDEQ(bal_instr, balTest.instr, 0xff000000)) {
		dprintf(("\t+tryBal: yes!\n"));
		return(1);
	}
	return(0);
}

#ifdef DEBUG
debug_printtype(w,saddr)
ADDR w, saddr;
{
	dprintf(("\t+testing for r15/r14 combo: "));
	if(debug && inInstr(w))
		printf("text address in stack=%X stackaddr=%X\n",w,saddr);
	if(debug && inData(w))
		printf("data address in stack=%X stackaddr=%X\n",w,saddr);
	if(debug && inStack(w))
		printf("stack address in stack=%X stckaddr%X\n",w,saddr);
}
#endif


/* The current function's return address disclosed that there's a signal
 * stack frame just above.  Print its special information, refill
 * RegArr from its save area, and return the interruptee's iar
 * so that stackWalk will continue with the frame above the signal.
 */
ADDR
printSigFrame() 
{
	int i; 
	struct sigframe *sf = (struct sigframe *)PI.frame_top;
		/* beware using sf->member to access the sigframe!
		 * You will get adb's memory, not the child process'.
		 */

	for(i=0; i < MAXREGNO; i++) 
		RegArr[i] = GETWORD(&sf->sf_sc.sc_regs[i], DSP);

	i = GETWORD(&sf->sf_signum,DSP);
	printf("Signal %d (%s), with sigframe at %X, which interrupted ...\n",
		 i,(i<sizeof(signals)/sizeof(signals[0]))? signals[i]: "???",
		RegArr[r1]);
	return GETWORD(&sf->sf_sc.sc_iar,DSP);
}


/* Find a trace table in text. Start scan at pc. */
/* Instead of calling error, check for no entry pts. between pc and tt. */
void
getTraceTable(pc)
ADDR pc;
{
	ADDR oldPc = pc;
	setDefaults();	
	
	if((pc = scanForTable(pc)) == 0) {
		sprintf(Error_buf,"Trace table missing after %X", oldPc);
		error(Error_buf);
	}
	
	unPack(pc, &TTbuf);
	
#ifdef DEBUG
	if(debug) dumpTraceTable(&TT);
#endif	
	return;
}

/* Search forward in text starting at pc for a trace table.
 * Trace tables are identified by 0xdf??, 0xdf??,
 * df being an illegal opcode.  Matching two consecutive halfwords
 * avoids spurious matches on an immediate field.  
 * Note reliance on GETWORD's ability to do unaligned fetches. 
 */
scanForTable(pc)
ADDR pc;
{
	L_INT w;
	dprintf(("\t+Starting TT search at pc=%x\n",pc));
	for(; pc <= UPPERINSTR; pc += 4) {
		w = GETWORD(pc, ISP);
		if (WORDEQ(w, 0xdf00df00, 0xff00ff00)) return pc;
		if (WORDEQ(w, 0x0000df00, 0x0000ff00)) pc -= 2;
	}
	return 0;
}

/* Read in the trace table from text into the ttbuf. Unpack from
 * ttbuf into the global trace table structure.
 * Unpacking is relative to the byte containing the routine-type.
 */
unPack(pc, ttBuf)
register ADDR pc;
register union TTbuf *ttBuf;
{
	register int i;
	int offset_size;

	char *flgNotImplemented="%c Trace flag found, but not implemented!\n";
	int size;
	
	TT.where = pc;
				/* Read in trace table and a little extra. */
	for(i=0; i < TTSIZE; i++, pc += sizeof(int))
		ttBuf->tt_wbuf[i] = GETWORD(pc, ISP);
	
						/* Unpack. */
	TT.rtype = ttBuf->tt_cbuf[1];
			/* Magic constants should be in a syswide .h file.
			 * 2 = function with no stack frame and no stm.
			 * 3 = 'start' in crt0 (trace back termination).
			 * 7 = function with normal stack frame.
			 */
	if(!validRtype(TT.rtype)) {
		sprintf(Error_buf,"Undefined trace table type %d ",
				TT.rtype);
		error(Error_buf);
	}
	if (funcHasNoFrame(TT.rtype)) {
		return;		/* Type 2 trace tables hold no information */
	}
	i = 3; 
	TT.first_gpr =	LNIBBLE(ttBuf->tt_cbuf[i]);
	TT.wflg =	RNIBBLE(ttBuf->tt_cbuf[i]) & 0x8;
	TT.xflg =	RNIBBLE(ttBuf->tt_cbuf[i]) & 0x4;
	TT.yflg =	RNIBBLE(ttBuf->tt_cbuf[i]) & 0x2;

	if(TT.wflg) {
		++i;
		TT.param_words =	LNIBBLE(ttBuf->tt_cbuf[i]);
		TT.frame_reg =		RNIBBLE(ttBuf->tt_cbuf[i]);
	}
	else 			/* Something is wrong! */
		printf("no frame register number in trace table!\n");

	if(!validFrameRegNum(TT.frame_reg)) {
		char buf[256];
		sprintf(buf,"Bad frame register number in trace table-got %x",
			TT.frame_reg);
		error(buf);
	}
	
	if(TT.xflg) ++i;

	if(TT.yflg) ++i;	

	if(TT.zflg) {		/* z flag for future use. */
		++i;
		printf(flgNotImplemented, 'z');
	}
	
			/* bits 0 and 1 right shifted 6 is offset_size. */
	offset_size = ((ttBuf->tt_cbuf[++i] & 0xc0) >> 6);
	
			/* Bits 2-7 always present for local offset. */
	dprintf(("\t+offset byte byte[%d] = %x\n", i,ttBuf->tt_cbuf[i]));
	TT.local_offset = ttBuf->tt_cbuf[i] & 0x3f;
	
			/* If size !0, then get remaining offset bits. */
	for(size = offset_size; size--; ) {
		++i;
		dprintf(("\t+offset byte byte[%d]=%x\n",i,ttBuf->tt_cbuf[i]));
		TT.local_offset=(TT.local_offset << 8) | ttBuf->tt_cbuf[i];
	}
	
		/* Local offset in words, make it bytes. */
	TT.local_offset <<= 2;
}


/* Put reasonable defaults in trace table structure fields.*/
setDefaults()
{
	TT.rtype = -1;		/* If < 0, then other fields invalid. */
	TT.param_words = 0;
	TT.frame_reg = -1;	/* Maybe someday there will be a r-1?? */
	TT.wflg  =  0;
	TT.xflg  =  0;
	TT.yflg  =  0;
	TT.zflg  =  0;
}

#ifdef DEBUG
dumpTraceTable(TTABLE * tt)
{
	if(debug) {
		int i;
		printf("TT: rtype %d, first_gpr %d, param_words %d, "
		"local_offset %X, frame_reg %d, "
		"w %d, x %d, y %d, z %d, where %X\n",
		tt->rtype, tt->first_gpr, tt->param_words, tt->local_offset,
		tt->frame_reg, tt->wflg, tt->xflg,
		tt->yflg, tt->zflg, tt->where);
		for(i=0; i < TTSIZE; i++)
			printf("%X ", GETWORD(tt->where+i*sizeof(int),ISP));
		printf("\n");
	}
}
#endif


/* MAXNAMEWORDS*sizeof(int) is a few chars smaller than the max name length 
 * of a function's name in text. */
#define MAXNAMEWORDS 20
#define MAXNAMECHARS (MAXNAMEWORDS * sizeof(int))

union WordBuf {
	char	charname[MAXNAMECHARS];
	int	intname [MAXNAMEWORDS];
} Wbuf;

/* This a.out was stripped; there's no symbol table to help map the pc to a
 * function name.  Look for "<functionname>" just before the entry point.
 * Function names in text is a peculiarity of pcc .o's.
 * At a minimum, try to identify a stm so at least we've got the entry point.
 */
void
getNameFromText(pc)
register ADDR pc;
{
	register int i, c;
	register char *s;	/* Function name pointer. */
	register char *e;	/* End address to look for '>' char. */
	L_INT w;
	int found;
	static char namebuf[15];

	FN.entry_point = -1;
	for (; pc>=LOWERINSTR; pc-=2) {
		w = GETWORD(pc, ISP);
		if (WORDEQ(w, STM_OPCODE|0x00010000, 0xff0f0000) &&
		    (0xffff & w) == (0xffff & (REG_OFFSET +
			sizeof(int) * (w>>20 & 0xf)))) {
			FN.entry_point = pc;
			break;
		}
	}
	sprintf(namebuf, "%#x", FN.entry_point);
	FN.fn_name = namebuf;
}

/* Overlay current registers in RegArr by values saved at entry to this
 * stack level, to produce the caller's register values.
 * Only r6-r15 are considered; someone else must update saved r1.
 */
fillRegArray()
{
	register int fromreg = TT.first_gpr;

	if (funcHasNoFrame(TT.rtype) || !PI.did_stm) return;
	for(; fromreg < MAXREGNO; ++fromreg) {
		RegArr[fromreg] =
			GETWORD(getSavedRegAddr(PI.frame_top, fromreg),DSP) ;
	}
}

printexception()
{
	int roff = getRegByName("r0") + ECR_COUNT * sizeof (int);
	int regs[8];		/* room for 2 packets */
	int count;
	int i;

	if (pid) {
		count = ptrace(RUREGS, pid, roff, 0);
/*		printf("exception: roff=%x %d packets",roff,count); /* DEBUG */
		if (count != 1 && count != 2)
			return;
		for (i=0; i<count*4; ++i)
			regs[i] = ptrace(RUREGS, pid, roff += 4, 0);
	} else {
       		count = *(ADDR *)(((ADDR)&u)+roff);
/*		printf("exception: roff=%x %d packets",roff,count); /* DEBUG */
		if (count != 1 && count != 2)
			return;
		for (i=0; i<count*4; ++i)
			regs[i] = *(ADDR *)(((ADDR)&u)+(roff += 4));
	}
	print_ecr(count, (int) regs);
}

static char *ec_length[] = { "c", "h", "", "ts" };
static char *ec_ops[] = { "l", "lm", "ior", "la", "st", "stm", "iow", "-" };
static char *ec_cancel[] = { "", "-" };

print_ecr(ecr_count,ecr_addr)
{
	if (ecr_count) {
		printf("exception stack(%d):\n",ecr_count);
		for (; ecr_count-- > 0; ecr_addr += 16) {
			int reg = * (unsigned short *)(ecr_addr+2);
			
			printf("\t%s%s%s\tr%d,%R ",
				ec_cancel[reg&1],	/* cancelled? */
				ec_ops[(reg>>3)&0x07],	/* storage operation */
				ec_length[(reg>>6)&0x03],	/* operation length */
				(reg>>8)&0x0f,		/* register number */
				* (int *)(ecr_addr+4)	/* address */
				);
			if (reg&(0x04<<3))
				printf("[%R] ", * (int *)(ecr_addr+8));	/* data value */
			printf("%24t");
					/* address */
			(void) valpr(* (int *)(ecr_addr+4),DSYM);
			if (reg&(0x04<<3)) {
				printf(" [");

				(void) valpr(* (int *)(ecr_addr+8),DSYM);
				printf("]");
			}
			printf("\n");
		}
	}
}
