From: adunham@lgc.com (Alan Dunham)
Subject: Crash Tracebacks in 386BSD
Organization: Landmark Graphics Corp., Houston, Tx
Date: Thu, 27 Aug 1992 21:24:18 GMT

Howdy:
  I have ported my crash traceback to 386BSD. (see Doctor Dobbs 
  Journal  September 1992 page 80).  This file includes test.c, a
  small test program, and 386bsdcrash.c, the main code file.
  The test program calls trb_signalinit() to set things up.
  This was a quick port and I haven't tested the hell out of it,
  so if you find any bugs, email me at adunham@ita.lgc.com and
  I'll summarize fixes to the net.

/*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

/* test.c  a small program to test the crash traceback */

#define DEBUGPRINT		/* we don't want debug info */
#ifdef DEBUGPRINT
# define DBPRINT(s) printf s
#else
# define DBPRINT(s)
#endif

void tst_segv(),tst_bus();
void tst_fltdiv(), tst_intdiv(), tst_intoverflow();
void tst_fltoverflow(), tst_fltunderflow();
void tst_lv4(),tst_lv3(),tst_lv2(),tst_lv1();

/*----------------------------------------*/
void tst_segv()
{
  char text[16];
  char *ptr;
  int ii, jj, arr[16];
  strcpy(text,"seg fault");
  DBPRINT((" in segv\n"));
  jj= 4096;
  arr[jj] = ii; 
}

void tst_fltdiv()
{
  char text[16];
  float e,d,f;
/*-------------------------------*/
  strcpy(text,"fltdiv");
  DBPRINT((" in fltdiv \n"));
  f= 127.0;
  e= 0.0;
  d= 126.0;
  f=d/e;
}

void tst_intdiv()
{
  int a,b,c;
  DBPRINT((" in intdiv \n"));
  c=12;
  a=1;
  b=0;
  c=a/b;
}

void tst_intoverflow()
{
  int i,aa,bb,cc;
  char text[16];
  strcpy(text,"intoverflow");
  DBPRINT((" in intoverflow \n"));
  aa= 0x0000ffff;
  for(i=0;i<8;i++)
    {aa= aa*16;
     printf("i=%d aa=0x%x \n",i,aa);
    }
}

void tst_fltoverflow()
{
  int i;
  float ff;
  char text[16];
  strcpy(text,"fltoverflow");
  DBPRINT((" in fltoverflow \n"));
  ff= 6.023e23;
  for(i=0;i<30;i++)
    {ff= ff* 1.0e2;
     printf("i=%d ff=%10.3e \n",i,ff);
    }
}

void tst_fltunderflow()
{
  int i;
  float ff;
  char text[16];
  strcpy(text,"fltunderflow");
  DBPRINT((" in fltunderflow \n"));
  ff= 6.023e-23;
  for(i=0;i<30;i++)
    {ff= ff* 1.0e-2;
     printf("i=%d ff=%10.3e \n",i,ff);
    }
}

void tst_lv4(paramtext)
char *paramtext;
{
  long l4;
  char text[16];
  l4= 0xcafefade;
  strcpy(text,"level4");
  tst_bus(); 
}

void tst_lv3(paramtext)
char *paramtext;
{
  long l3;
  char text[16];
  l3= 0xdeafdead;
  strcpy(text,"level3");
  tst_lv4("call 4");
}

void tst_lv2(paramtext)
char *paramtext;
{
  long l2;
  char text[17];
  l2= 0xfeedface;
  strcpy(text,"level2");
  tst_lv3("call 3");
}

void tst_lv1()
{
  long l1, *lptr;
  char text[16];
  l1= 0xdeedfade;
  lptr= &l1;
  strcpy(text,"level1");
  tst_lv2("call 2");
}

void tst_bus()
{
  char *ptr;
  unsigned long uu;
  char text[16];
  strcpy(text,"bus error");
  ptr= 0x0;
  *ptr=0;
}

void tst_param(ii,ss,ff,dd,cc,uc,us,ul,ui)
int ii;
short ss;
float ff;
double dd;
char cc;
unsigned char uc;
unsigned short us;
unsigned long ul;
unsigned int ui;
{
  tst_bus();
}

void tst_param2(ii,ss,ff,dd,cc,uc,us,ul,ui,ptr)
int *ii;
short *ss;
float *ff;
double *dd;
char *cc;
unsigned char *uc;
unsigned short *us;
unsigned long *ul;
unsigned int *ui;
char *ptr;
{
  tst_bus();
}

main(argc,argv)
int argc;
char *argv[];
{
  int ii;
  char cc;
  long ll;
  short ss;
  float ff;
  double dd;
  unsigned char uc;
  unsigned short us;
  unsigned long ul;
  unsigned int ui;
  int iarr[12];
  float farr[8];
  char text[21];
  int random;
/*--------------------*/
  
  trb_signalinit(argc,argv);

  ll=0xfeeadded;
  strcpy(text,"traceback");

  for(ii=0;ii<12;ii++) iarr[ii]=ii;
  for(ii=0,ff=100;ii<8;ii++,ff++) farr[ii]=ff;

  ii=12;
  cc='q';
  ss=24;
  ff=256.0;
  dd=512.0;
  uc= 65;
  us= -4;
  ul= -8;
  ui= -16;

/* get a random number */
  random= time(0);
  random= random & 7;
  printf("random= %d \n",random);
  switch (random)
    {case 0:	tst_fltoverflow();	/* overflow */
		break;

     case 1:	tst_bus();	/* bus error */
		break;

     case 2:    tst_segv();	/* segmentation fault */ 
		break;

     case 3:    tst_intdiv();			/* integer divide */
		break;

     case 4:    tst_fltdiv(ll,ss,ff,dd);	/* float divide */
		break;

     case 5:    tst_lv1();		/* several call levels */
		break;

     case 6:    tst_param(ii,ss,ff,dd,cc,uc,us,ul,ui);	 /* show parameters */
		break;

     case 7:    tst_param2(&ii,&ss,&ff,&dd,&cc,&uc,&us,&ul,&ui,text);
		break;

     default:	break;
    } /* end of switch */
        
    exit(0);
}


/*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

/* 386bsdcrash.c 	signal handling & stack traceback */

/* 
 * Copyright 1992, Alan Dunham 
 *
 * This code may be copied as long as this copyright notice remains intact 
 * 
 */

#include <stdio.h>
#include <signal.h>		/* for signal definitions */
#include <a.out.h>		/* for NSYMOFF etc */
#include <stab.h>		/* for N_SLINE etc */
#include <string.h>		/* for strtok &strstr */
#include <sys/types.h>          /* for ctime */
/*----------------- local defines --------------------*/
#undef PROTOTYPES 		/* ignore prototype info */
#undef DEBUGPRINT 		/* we want debug info */
#define STACKDUMP 0		/* set to 1 to get 32bit stack dumps */
#define FRAMEDUMP 0		/* set to 1 to dump each stack frame */
#define PARAMDUMP 0		/* set to 1 to get parameter dumps */
#define SYMBOLDUMP 0		/* set to 1 to get local symbol dumps */

#define JUMPPC 1		/* how to find next program counter */
#define JUMPSP 0		/* how to find next stack pointer */
#define MAXLEVEL 40		/* maximum number of nested subroutine calls */
#define MAXPARAM 40		/* maximum number of subroutine parameters */
#define DUMPSIZE 256		/* size of stack dump in longwords */
#define NSIGNAL 31              /* #signals to describe in text array */
#define STREQ(a,b)  (strcmp((a),(b))==0)
#define STRNEQ(a,b) (strcmp((a),(b))!=0)
#define CNULL '\0'

#ifdef PROTOTYPES
# define P_(s) s
#else
# define P_(s) ()
#endif
#ifdef DEBUGPRINT
# define DBPRINT(s) printf s
#else
# define DBPRINT(s) 
#endif

/* defines for data dictionary: basic types */
#define D_INT 1
#define D_CHAR 2
#define D_LONG 3
#define D_UINT 4
#define D_ULONG 5
#define D_SHORT 6
#define D_LONGLONG 7
#define D_USHORT 8
#define D_ULONGLONG 9
#define D_SIGNEDCHAR 10
#define D_UCHAR 11
#define D_FLOAT 12 
#define D_DOUBLE 13
#define D_LONGDOUBLE 14
#define D_VOID 15

/*----------------- external functions --------------------*/
char *malloc();
char *getenv();

/*----------------- internal functions --------------------*/
static void trb_exefind P_((int argc, char *argv));
static void trb_exeinfo();
static void trb_dictionary P_((int ilevel, FILE fp, FILE fp2));
static void trb_symboldump();
static void trb_stackdump P_((unsigned long start, int nn, FILE **fp));
static void trb_framedump P_((unsigned long sp, unsigned long pc,
                             unsigned long fremeend, FILE **fp));
static void trb_getline P_((int nlevel));
static void trb_params P_((int ilevel, FILE fp, FILE fp2));
static void trb_symbols P_((int ilevel, FILE fp, FILE fp2));
static void trb_traceback P_((int nlevel));
void trb_userinfo P_((FILE fp));
void trb_handle P_((int sig,int code,struct sigcontext *scp));
static void trb_sigtextinit();
static char *trb_codetext P_((int sig, int code));
static void trb_signal();
void trb_signalinit P_((int argc, char *argv[]));
static void str_getdelimited P_((char *inttext, char *bounds,
				 char *outtext));
static void str_whiteout P_((char *string, char *chars));

/*----------------- structure definitions -----------------*/
struct levelstr       /* info for each function in traceback */
  {unsigned long stackpointer;    /* start of stack frame */
   unsigned long programcounter;  /* return address */
   unsigned long frameend;        /* end of stack frame (+4) */
   long fileaddr,funcaddr;        /* addresses into string table */
   char funcname[256];            /* name of function */
   char filename[256];            /* name of source file */
   int found;                     /* 0 if function not found */
   int filesymbol;                /* symbol # for start of source file */
   int funcsymbol;                /* symbol # for start of function */
   int line;                      /* line number in source file */
  };

struct exestr      /* information about the executable file */
  {int nsym;             /* number of symbols in symbol table */
   unsigned long magic;  /* the magic number of the file */
   long stroffset;       /* offset to the string table */
   long symoffset;       /* offset to the symbol table */
   char name[256];       /* path to the file */
  };

struct dictstr     /* a dictionary of defined variable types */
  {char match[8];		/* the defined type  */
   char basetype[8];		/* what it is defined from  */
   int code;			/* our base identifier ie D_INT */
   char fullstring[80];		/* as it was read from COFF */
   int ptr;			/* 1 if it is a pointer */
   int lower,upper;		/* array bounds */
  };

  
/*----------------- global variables ----------------------*/
char   sigtext[NSIGNAL+1][64];    /* describe signal values */
struct levelstr level[MAXLEVEL];  /* one per stack frame */
struct exestr exe;
struct dictstr dictionary[200];   /* allow 200 per source file */
int ndict;                        /* number of types per source file */
FILE   *fpcrash,*fpstackdump,*fpframedump;
	      /* pointers to files CRASH, STACKDUMP, FRAMEDUMP */
char description[17][20] = {"???","int","char","long","unsigned int",
                 "unsigned long","short","longlong","unsigned short",
                 "unsigned longlong","signed char","unsigned char",
                 "float","double","longdouble","void","???" };
  
/****************************************************************/
/*	trb_exefind						*/
/*	find the path of the file we are executing		*/
/****************************************************************/
static void trb_exefind(argc,argv)
int argc;
char *argv[];
{
  FILE *fp;
  int ll;
  char name[256],*path;
  char *ptr,trial[256];
/*---------------------------------*/
/* get name of program */
  strcpy(name,argv[0]);
  
/* 1: if name contains a slash, assume it is the direct path */
  ptr= strchr(name,'/');
  if(ptr!=NULL)
    {strcpy(trial,name);
     fp= fopen(trial,"r");
     if(fp!=NULL)
       {fclose(fp);strcpy(exe.name,trial);return;}
    }
      
/* 2: look in the user's path */
  ptr= getenv("PATH");
  ll= strlen(ptr);
  path= malloc(ll+1);
  strcpy(path,ptr);
/* separate path string into its components */
  ptr= strtok(path,":");
  while(ptr!=NULL)
    {strcpy(trial,ptr);
     strcat(trial,"/");
     strcat(trial,name);
     DBPRINT(("trial exe is %s \n",trial));
     fp= fopen(trial,"r");
     if(fp!=NULL) {fclose(fp);strcpy(exe.name,trial);free(path);return;}
     ptr= strtok(NULL,":");
    }

/* 3: try the local directory in case it is not in the path */
  strcpy(trial,"./");
  strcat(trial,name);
  DBPRINT(("trial exe is %s \n",trial));
  fp= fopen(trial,"r");
  if(fp!=NULL){fclose(fp);strcpy(exe.name,trial);return;}

} /* end of trb_exefind */

/****************************************************************/
/*	trb_exeinfo						*/
/*	get needed info from executable file header		*/
/****************************************************************/
static void trb_exeinfo()
{
  int status;
  unsigned long magic;
  FILE *fp;
  struct exec header;	/* exe file header (from a.out.h) */
  struct nlist symbol;	/* symbol table entry */
/*--------------------*/
/* open exe file */
  fp= fopen(exe.name,"r");
  if(fp==NULL)
    {printf("can't open %s\n",exe.name);
     exit(1);}
  
/* read the file header */
  status= fread(&header,sizeof(header),1,fp);
  if(status==0) {printf("could not read header\n"); exit(2);}

/* is the magic number okay ? */
  magic= header.a_magic;
  status= N_BADMAG(header);
  if(status!=0)
    {printf("bad magic number = %ld 0x%lx 0%lo \n",magic,magic,magic);
     exit(3);
    }
  exe.magic= magic;

/* how big is the symbol table */
  exe.nsym= header.a_syms/sizeof(symbol);
  if(exe.nsym==0) exit(4);

/* get file offsets for symbol table & string table */
  exe.symoffset= N_SYMOFF(header);
  exe.stroffset= N_STROFF(header);

  fclose(fp);
} /* end of trb_exeinfo */
  
/****************************************************************/
/*	trb_dictionary						*/
/*	make a "data dictionary" for a source file		*/
/****************************************************************/
static void trb_dictionary(ilevel,fp,fp2)
int ilevel;
FILE *fp, *fp2;
{
  int i,j,status,type,off;
  int low,high,code,pointer;
  int isym;
  struct nlist symbol;	/* symbol table entry */
  long nseek;
  char *ptr, *ptr2;
  char ttext[1024],tempstring[64];
  char symbolname[32],junk1[8],junk2[8],match[8];
/*--------------------*/
  dictionary[0].code=D_INT;
  dictionary[1].code=D_CHAR;
  dictionary[2].code=D_LONG;
  dictionary[3].code=D_UINT;
  dictionary[4].code=D_ULONG;
  dictionary[5].code=D_SHORT;
  dictionary[6].code=D_LONGLONG;
  dictionary[7].code=D_USHORT;
  dictionary[8].code=D_ULONGLONG;
  dictionary[9].code=D_SIGNEDCHAR;
  dictionary[10].code=D_UCHAR;
  dictionary[11].code=D_FLOAT;
  dictionary[12].code=D_DOUBLE;
  dictionary[13].code=D_LONGDOUBLE;
  dictionary[14].code=D_VOID;
  strcpy(dictionary[0].match,"1");
  strcpy(dictionary[1].match,"2");
  strcpy(dictionary[2].match,"3");
  strcpy(dictionary[3].match,"4");
  strcpy(dictionary[4].match,"5");
  strcpy(dictionary[5].match,"6");
  strcpy(dictionary[6].match,"7");
  strcpy(dictionary[7].match,"8");
  strcpy(dictionary[8].match,"9");
  strcpy(dictionary[9].match,"10");
  strcpy(dictionary[10].match,"11");
  strcpy(dictionary[11].match,"12");
  strcpy(dictionary[12].match,"13");
  strcpy(dictionary[13].match,"14");
  strcpy(dictionary[14].match,"15");
  for(i=0;i<15;i++)
    {dictionary[i].ptr=0;
     dictionary[i].lower=0;
     dictionary[i].upper=0;
     dictionary[i].basetype[0]=CNULL;
    }

/* open exe file */
  fp= fopen(exe.name,"r");
  fp2= fopen(exe.name,"r");
  if(fp==NULL)
    {printf("can't open %s\n",exe.name);
     exit(1);}
  ndict=15;
  isym= level[ilevel].filesymbol+1;  /* seek to source files' symbols */
  nseek= exe.symoffset + isym*sizeof(symbol);
  fseek(fp,nseek,0);
  for(i=isym;i<exe.nsym;i++)
    {status= fread(&symbol,sizeof(symbol),1,fp);
     if(status==0) printf("could not read symbol\n");
     type= symbol.n_type;
     if(type==N_SO) return; /* we are at the next source file */
     if(type!=N_LSYM && type!=N_PSYM) continue;  /* local syms & params */
     nseek= exe.stroffset+symbol.n_un.n_strx;
     fseek(fp2,nseek,0);
     ptr= fgets(ttext,sizeof(ttext),fp2);   /* text describing symbol */
     /* ignore structures for now */
     str_getdelimited(ttext,":=",match);
     if(match[0]=='\0') continue; /* new defines are surrounded by := */
     if(match[0]=='t') continue;  /* ignore basic types */
     if(match[0]=='p')   /* remove the p if it is a parameter */
        {strcpy(tempstring,match); strcpy(match,&tempstring[1]);}
     /* extract the symbol name */
     strcpy(tempstring,ttext);
     str_whiteout(tempstring,":=;");
     sscanf(tempstring,"%s",symbolname);
     /* it is a new type, clear some flags */
     dictionary[ndict].ptr= 0;
     dictionary[ndict].code= 0;
     dictionary[ndict].lower= 0;
     dictionary[ndict].upper= 0;
     strcpy(dictionary[ndict].match,match);
     /* is this new type a pointer */       
     ptr2=strstr(ptr,"=*");
     if(ptr2!=NULL)
       {str_getdelimited(ptr2,"*\0",match);
        strcpy(dictionary[ndict].basetype,match);
        dictionary[ndict].ptr= 1;
        for(j=0;j<ndict;j++)
          {if(STREQ(match,dictionary[j].match))
	     {code= dictionary[j].code;
              pointer= dictionary[j].ptr+1;
              dictionary[ndict].code= code;
              dictionary[ndict].ptr= pointer;
              break;
             }
          }
        ndict++;
        continue;
       }
     /* is this new type an array */
     ptr2=strstr(ptr,"=ar");
     if(ptr2!=NULL)
       {strcpy(tempstring,ptr);
	str_whiteout(tempstring,":;()");
	sscanf(tempstring,"%s %s %d %d %s",junk1,junk2,&low,&high,match);
  	strcpy(dictionary[ndict].basetype,match);
        dictionary[ndict].lower= low;
        dictionary[ndict].upper= high;
        code=0;
	for(j=0;j<ndict;j++)
          {if(STREQ(match,dictionary[j].match))
	     {code=dictionary[j].code;
              dictionary[ndict].code=code;
              break;
             }
          }
        ndict++;
        continue;
       }

   }  /* end of loop over all symbols */
  printf("ndict extended to %d \n",ndict);
} /* end of trb_dictionary */
  
/****************************************************************/
/*	trb_translate						*/
/*	what kind of variable is a symbol			*/
/****************************************************************/
static void trb_translate(ttext,code,pointer,array)
char *ttext;
int *code, *pointer, *array;
{
  int i,j,status,type,off;
  int low,high,size;
  int isym;
  struct nlist symbol;	/* symbol table entry */
  long nseek;
  char *ptr, *ptr2;
  char tempstring[64];
  char symbolname[32],junk1[8],junk2[8],match[8];
/*--------------------*/
/* zero the output flags */
  *code= 0;
  *pointer= 0;
  *array= 0;
/* ignore structures for now */
  str_getdelimited(ttext,":=",match);
  if(match[0]=='\0') str_getdelimited(ttext,":\0",match); /* case of var:17 */
  if(match[0]=='p')    /* remove the p if it is a parameter */
    {strcpy(tempstring,match); strcpy(match,&tempstring[1]);}
/* look in the data dictionary */
    {for(j=0;j<ndict;j++)
       {if(STREQ(match,dictionary[j].match))
          {*code= dictionary[j].code;
           *pointer= dictionary[j].ptr;
           size= dictionary[j].upper-dictionary[j].lower+1;
	   if(size>1) *array=size;
           return;
          }
       }
     return;
    }		   
} /* end of trb_translate */

/****************************************************************/
/*	trb_verbalize						*/
/*	print what kind of variable a symbol is			*/
/****************************************************************/
static void trb_verbalize(name,code,pointer,array)
char *name;
int code,pointer,array;
{
  char ttext[80],size[16];
/*------------------------------------------------------*/
  strcpy(ttext,name);	       
  if(pointer>0)
    strcat(ttext," is a pointer to type ");
  else if(array>1)
    strcat(ttext," is an array of type ");
  else
    strcat(ttext," is a variable of type ");
  if(pointer==2) strcat(ttext,"*");
  if(pointer==3) strcat(ttext,"*");
  strcat(ttext,description[code]);

  if(array>1) {sprintf(size," [%d] ",array); strcat(ttext,size); } 
  printf("%s\n",ttext);  
} /* end of trb_verbalize */

/****************************************************************/
/*	trb_symboldump						*/
/*	dump text of local symbols 				*/
/****************************************************************/
static void trb_symboldump()
{
  int i,j,ll,status,type,off,line;
  FILE *fp, *fp2, *fpout;
  struct nlist symbol;	/* symbol table entry */
  long nseek;
  char *ptr, *ptr2;
  char ttext[1024];
  long fileaddr,funcaddr;
  unsigned long address;
  char filename[256],funcname[256];
/*--------------------*/
/* open exe file */
  fp= fopen(exe.name,"r");
  fp2= fopen(exe.name,"r");
  if(fp==NULL)
    {printf("can't open %s\n",exe.name);
     exit(1);}
/* open file SYMBOLDUMP */
  fpout= fopen("SYMBOLDUMP","w");
  if(fpout==NULL)
    {printf("can't open file SYMBOLDUMP for output\n");
     exit(1);}
  trb_userinfo(fpout);
  fseek(fp,exe.symoffset,0);
  for(i=0;i<exe.nsym;i++)
    {status= fread(&symbol,sizeof(symbol),1,fp);
     if(status==0) printf("could not read symbol\n");
     type= symbol.n_type;
     if(type==N_SO)	/* source file name: name,,0,0,address */
       {fileaddr= symbol.n_un.n_strx;
        fseek(fp2,exe.stroffset,0);
        fseek(fp2,fileaddr,1);
        ptr= fgets(filename,sizeof(filename),fp2);
        fprintf(fpout,"filename %s \n",filename);
       }
     else if(type==N_FUN)	/* procedure: name,,0,linenumber,address */
       {funcaddr= symbol.n_un.n_strx;
        fseek(fp2,exe.stroffset,0);
        fseek(fp2,funcaddr,1);
        ptr= fgets(ttext,sizeof(ttext),fp2);
        ptr= strtok(ttext,":");
        ll= strlen(ptr);
        if(ll>250){strncpy(funcname,ptr,250); funcname[250]= CNULL;}
        else strcpy(funcname,ptr);
        fprintf(fpout,"procedure %s \n",funcname);
       }
     else if(type==N_SLINE)		/* src line: 0,,0,linenumber,address */
       {line= symbol.n_desc;
        address= symbol.n_value;
	fprintf(fpout,"line=%d address=%x\n",line,address);
       }
     else if(type==N_LSYM)
       {off= symbol.n_value;
        nseek= exe.stroffset+symbol.n_un.n_strx;
        fseek(fp2,nseek,0);
        ptr= fgets(ttext,sizeof(ttext),fp2);
        fprintf(fpout,"frame offset=%d symbol text: >%s< \n",off,ttext);
       }
     else if(type==N_PSYM)	/* parameter: name,,0,type,offset */
       {off= symbol.n_value;
	nseek=exe.stroffset+symbol.n_un.n_strx;
        fseek(fp2,nseek,0);
        ptr= fgets(ttext,sizeof(ttext),fp2);
        fprintf(fpout,"frame offset=%d param text: >%s< \n",off,ttext);
       }
   }  /* end of loop over all symbols */

  fclose(fp);
  fclose(fp2);
  fclose(fpout);
} /* end of trb_symboldump */
  
/****************************************************************/
/*	trb_stackdump						*/
/*	dump the stack						*/
/****************************************************************/
static void trb_stackdump(start,nn,fp0)
unsigned long start;
int nn;
FILE **fp0;
{
  int i,j;
  FILE *fp;
/*------------------------------------------------------*/
  fp= *fp0;
  if(fp==0)
    {fp= fopen("STACKDUMP","a"); /* open for append */
     if(fp==NULL) fp= stdout; /* if failure, use standard out */
     *fp0= fp;                /* save it in case we have two crashes */
    }
  trb_userinfo(fp);
  for (i=0; i<nn;i++)
    {fprintf(fp,"%08x ", (long)start);
     fprintf(fp,"%08x ", *(unsigned long *)(start));
     for(j=0;j<4;j++,start++)
       fprintf(fp,"%c",   isprint(*(unsigned char *)(start))
             ? *(unsigned char *)(start) : ' ');
     fprintf(fp,"\n");
    }
  fclose(fp);
} /* end of trb_stackdump */

/****************************************************************/
/*	trb_framedump						*/
/*	dump a stack frame					*/
/****************************************************************/
static void trb_framedump(stackpointer,programcounter,frameend,fp0)
unsigned long stackpointer,programcounter,frameend;
FILE **fp0;
{  
  int j;
  unsigned long stackaddress,stackvalue;
  FILE *fp;
/*------------------------------------------------------*/
  fp= *fp0;
  if(fp==0)
    {fp= fopen("FRAMEDUMP","a"); 
     if(fp==NULL) fp= stdout;
     trb_userinfo(fp);
     *fp0= fp;
    }
  fprintf(fp,"-----------------------------------\n");
  fprintf(fp,"sp=%08x pc=%08x\n",stackpointer,programcounter);
  j= 0;
  stackaddress= stackpointer;
  while(stackaddress<frameend)
    {stackvalue= *( (long *)stackaddress);
     fprintf(fp," %8x",stackvalue);
     j++;
     if(j==8) {fprintf(fp,"\n");j= 0;}
     stackaddress= stackaddress+4;
    }
  if(j!=0)fprintf(fp,"\n");
  fprintf(fp,"-----------------------------------\n");
} /* end of trb_framedump */

/****************************************************************/
/*	trb_getline						*/
/*	find file lines matching addresses			*/
/****************************************************************/
static void trb_getline(nlevel)
int nlevel;
{
  FILE *fp,*fp2;
  struct nlist symbol;	/* symbol table entry */
  unsigned long address,match,lastaddress;
  int type,line,funcsymbol,filesymbol;
  int i,j,ll,status;
  long fileaddr,funcaddr,magic;
  int iff;
  char *ptr,ttext[256];
  char funcname[256],filename[256];
/*----------------------*/
/* initialize */
  address= 0; funcsymbol= 0; filesymbol=0;
  lastaddress= 0xFFFF;
  for(i=0;i<MAXLEVEL;i++)level[i].found= 0;
  DBPRINT(("trb_getline: nlevel=%d pc[0]=%x\n",nlevel,level[0].programcounter));

/* use first file pointer to read symbol table */
  fp= fopen(exe.name,"r");
  if(fp==NULL) {printf("can't open %s\n",exe.name);exit(1);}
/* use second file pointer to read the string table */
  fp2= fopen(exe.name,"r");
  
/* read all symbols, look at source lines, file & function names */
  fseek(fp,exe.symoffset,0);
  for(i=0;i<exe.nsym;i++)
    {status= fread(&symbol,sizeof(symbol),1,fp);
     if(status==0) printf("could not read symbol\n");
     type= symbol.n_type;
/* what type of symbol is it */
     if(type==N_SLINE)		/* src line: 0,,0,linenumber,address */
       {line= symbol.n_desc;
        address= symbol.n_value;
	DBPRINT(("line=%d address=%x\n",line,address));
       }
     else if(type==N_FUN)	/* procedure: name,,0,linenumber,address */
       {funcaddr= symbol.n_un.n_strx;
        address= symbol.n_value;
        funcsymbol= i;
        fseek(fp2,exe.stroffset,0);
        fseek(fp2,funcaddr,1);
        ptr= fgets(ttext,sizeof(ttext),fp2);
        ptr= strtok(ttext,":");
        ll= strlen(ptr);
        if(ll>250){strncpy(funcname,ptr,250); funcname[250]= CNULL;}
        else strcpy(funcname,ptr);
        DBPRINT(("procedure %s address=%x\n",funcname,address));
        for(iff=0;iff<nlevel;iff++) /* we matched address, now fill funcname */ 
          if(strcmp(level[iff].funcname,"nextf")==0)
            {strcpy(level[iff].funcname,funcname);
             level[iff].funcsymbol= funcsymbol; /* symbol# of function name */
            }
       }
     else if(type==N_SO)	/* source file name: name,,0,0,address */
       {fileaddr= symbol.n_un.n_strx;
        address= symbol.n_value;
        filesymbol= i;
        fseek(fp2,exe.stroffset,0);
        fseek(fp2,fileaddr,1);
        ptr= fgets(filename,sizeof(filename),fp2);
        DBPRINT(("filename %s address=%x\n",filename,address));
       }

/* does this address match one of ours? */
     for(iff=0;iff<nlevel;iff++)
       {if(level[iff].found==0)
         {match= level[iff].programcounter;
          if(address==match)
            {DBPRINT(("exact match of %x found at line %d\n",match,line));
             level[iff].found= 1;
             level[iff].filesymbol= filesymbol;	/* store symbol# of the file */
             strcpy(level[iff].funcname,"nextf");
             strcpy(level[iff].filename,filename);
             level[iff].line= line;
            }
          else if(address>match && lastaddress<match && lastaddress>(match-64))
            {
             DBPRINT(("match of %x before line %d, lastaddress=%x address=%x\n",
             match,line,lastaddress,address));
             level[iff].found= 1;
             level[iff].filesymbol= filesymbol; /* store symbol# of the file */
             strcpy(level[iff].funcname,"nextf");
             strcpy(level[iff].filename,filename);
             level[iff].line= line-1;
            }
         }
       }
    lastaddress= address;
    } /* end of loop over all nsym */
  fclose(fp2);
  fclose(fp);
      
} /* end of trb_getline */

/****************************************************************/
/*	trb_params						*/
/*	print one level of parameters				*/
/****************************************************************/
static void trb_params(ilevel,fp,fp2)
int ilevel;
FILE *fp, *fp2;
{
  int i,status,type;
  int isym,code,pointer,array;
  int size,middle,sum;
  long addr,off,address,newaddress,stackbase,nseek,contents;
  struct nlist symbol;	/* symbol table entry */
  char *ptr,ttext[1024],symbolname[80],symboltype[80];
  char params[1024],tempstring[1024],outtext[80];
  int ii;
  char cc;
  short ss;
  long ll,l2;
  unsigned char uc;
  unsigned short us;
  unsigned long ul;
  unsigned int ui;
  float ff;
  double dd;
  long vv;
/*------------------------------------*/
  strcpy(params,level[ilevel].funcname);
  strcat(params,"(");
  isym= level[ilevel].funcsymbol+1;
  nseek= exe.symoffset + isym*sizeof(symbol);
/* do a quick loop to get parameter names */
  fseek(fp,nseek,0);
  for(i=isym;i<exe.nsym;i++)
    {status= fread(&symbol,sizeof(symbol),1,fp);
     if(status==0) printf("could not read symbol\n");
     type= symbol.n_type;
     if(type==N_FUN) break;     /* that is all for this function */ 
     else if(type==N_SO) break; /* that is all for this function */
     else if(type==N_PSYM)	/* parameter: name,,0,type,offset */
       {addr= symbol.n_un.n_strx;   /* symbol name in string table */
	fseek(fp2,exe.stroffset,0);
        fseek(fp2,addr,1);
        ptr= fgets(ttext,sizeof(ttext),fp2);
	/* extract the symbol's name */
	strcpy(tempstring,ttext);
	str_whiteout(tempstring,":=;");
	sscanf(tempstring,"%s",symbolname);
	strcat(params,symbolname); strcat(params,",");
       }
    }
/* change the last comma to an )  and print the parameters */
  ll= strlen(params);
  if(params[ll-1]==',') params[ll-1]= ')'; else strcat(params,")");
  fprintf(fpcrash,"%s\n",params);
  
     
/* do a second loop to get values */
  fseek(fp,nseek,0);
  for(i=isym;i<exe.nsym;i++)
    {status= fread(&symbol,sizeof(symbol),1,fp);
     if(status==0) printf("could not read symbol\n");
     type= symbol.n_type;
     if(type==N_FUN) break;     /* that is all for this function */    
     else if(type==N_SO) break; /* that is all for this function */
     else if(type!=N_PSYM)continue;
     addr= symbol.n_un.n_strx;
     off= symbol.n_value;   /* offset from stack frame end */
     fseek(fp2,exe.stroffset,0);
     fseek(fp2,addr,1);
     ptr= fgets(ttext,sizeof(ttext),fp2);
     /* extract the symbol's name */
     strcpy(tempstring,ttext);
     str_whiteout(tempstring,":=;");
     sscanf(tempstring,"%s",symbolname);
     /* extract text we use to get the symbol's type */
     ptr= strchr(ttext,':');
     strcpy(symboltype,ptr);
     stackbase= level[ilevel].frameend;
     stackbase= level[ilevel].stackpointer;
     address= stackbase+off;    /* where the variable's bytes are */
/* find out what kind of symbol it is */
     trb_translate(ttext,&code,&pointer,&array);
#if PARAMDUMP
     printf("param: >%s< off=%d\n",ttext,off);
     trb_verbalize(symbolname,code,pointer,array);
#endif

/* if it is a pointer, print the address & dereference it */
     if(pointer==1)
       {newaddress= *(unsigned long *) address;
        fprintf(fpcrash,"  %s = 0x%x (pointer to %s) \n",
          symbolname, newaddress, description[code]);
        if(newaddress>=0 && newaddress<0x1000) continue;
        else address= newaddress;
       }
     else if(pointer==2)    /* it could be a pointer to a pointer */
       {newaddress= *(unsigned long *) address;
        fprintf(fpcrash,"  %s = 0x%x (pointer to *%s) \n",
          symbolname, newaddress, description[code]);
        if(newaddress>=0 && newaddress<0x1000) continue;
        else address= newaddress;
        newaddress= *(unsigned long *) address;
        if(newaddress>=0 && newaddress<0x1000) continue;
        else address= newaddress;
       }

/* treat a ptr to char as an array */
     if(pointer>0 && code==D_CHAR) goto arrays;  /* written by an ex- */
						 /* fortran programmer */
/* an array of any type */
     if(array>1) goto arrays;

/* int */
     else if(code==D_INT)
       {ii= *(int *)address;
        sprintf(outtext,"%d 0x%x (long)",ii,ii);}
/* char */
     else if(code==D_CHAR)
       {cc= *(char *)address;
        sprintf(outtext,"\'%c\' 0x%x (char)",cc,cc);}
/* long */
     else if(code==D_LONG)
       {ll= *(long *)address;
        sprintf(outtext,"%d 0x%x (long)",ll,ll);}
/* short */
     else if(code==D_SHORT)
       {ss= *(short *)address;
        sprintf(outtext,"%hd 0x%hx (short)",ss,ss);}
/* unsigned char */
     else if(code==D_UCHAR)
       {uc= *(unsigned char *)address;
        sprintf(outtext,"\'%c\' 0x%x (u char)",uc,uc);}
/* unsigned short */
     else if(code==D_USHORT)
       {us= *(unsigned short *)address;
        sprintf(outtext,"%hu 0x%hx (u short)",us,us);}
/* unsigned long */
     else if(code==D_ULONG)
       {ul= *(unsigned long *)address;
        sprintf(outtext,"%u 0x%x (u long)",ul,ul);}
/* unsigned int */
     else if(code==D_UINT)
       {ui= *(unsigned int *)address;
        sprintf(outtext,"%u 0x%x (u int)",ui,ui);}
/* float */
     else if(code==D_FLOAT)
       {ff= *(float *)address;
        ll= *(long *)address;
        sprintf(outtext,"%f 0x%08x (float)",ff,ll);}
/* double */
     else if(code==D_DOUBLE)
       {dd= *(double *)address;
        ll= *(long *)address;
        l2= *(long *)(address+sizeof(long));
        sprintf(outtext,"%f 0x%08x%08x (double)",dd,ll,l2);}
/* void */
     else if(code==D_VOID)
       {vv= *(long *)address;
        sprintf(outtext,"%d 0x%x (void)",vv,vv);}
/* ??? */
     else
       sprintf(outtext," unknown type ");

	
     if(pointer==0)fprintf(fpcrash,"  %s = %s \n",symbolname,outtext);
     else if(pointer==1)fprintf(fpcrash,"  *%s = %s \n",symbolname,outtext);
     else if(pointer==2)fprintf(fpcrash,"  **%s = %s \n",symbolname,outtext);
     continue;
	
/*---------*/
arrays:
/*---------*/
     size= array-1;
     middle= array/2;
/* int or long array */
     if(code==D_INT || code==D_LONG)
       {fprintf(fpcrash,"  %s = an array of type %s \n",
            symbolname,description[code]);
        ii= *(int *)address;
        fprintf(fpcrash,"    %s[0] = %d 0x%x \n", symbolname,ii,ii);
        ii= *(int *) (address+middle*sizeof(int));
        fprintf(fpcrash,"    %s[%d] = %d 0x%x \n", symbolname,middle,ii,ii);
        ii= *(int *) (address+size*sizeof(int));
        fprintf(fpcrash,"    %s[%d] = %d 0x%x \n", symbolname,size,ii,ii);
       }
/* char array */
     else if(code==D_CHAR)
       {sum=pointer;
        if(array>1)sum++;
        else if(sum==1)
          fprintf(fpcrash,"  *%s = \"%s\"\n",symbolname,address);
        else if(sum==2)
          fprintf(fpcrash,"  *%s = \"%s\"\n",symbolname,address);
       }
       
/* float array */
     else if(code==D_FLOAT)
       {fprintf(fpcrash,"  %s = an array of type %s \n",
            symbolname,description[code]);
        ff= *(float *)address;
        fprintf(fpcrash,"    %s[0] = %f 0x%x \n", symbolname,ff,ff);
        ff= *(float *) (address+middle*sizeof(float));
        fprintf(fpcrash,"    %s[%d] = %f 0x%x \n", symbolname,middle,ff,ff);
        ff= *(float *) (address+size*sizeof(float));
        fprintf(fpcrash,"    %s[%d] = %f 0x%x \n", symbolname,size,ff,ff);
       }
/* need to put in other types of arrays */

    } /* end of loop over all nsym */
    
} /* end of trb_params */

/****************************************************************/
/*	trb_symbols						*/
/*	print local symbols in procedure of interest		*/
/****************************************************************/
static void trb_symbols(ilevel,fp,fp2)
int ilevel;
FILE *fp, *fp2;
{
  int i,type,status,isym;
  int code,pointer,array,middle,size;
  long addr,off,address,newaddress,stackbase;
  unsigned long value;
  long nseek;
  struct nlist symbol;	/* symbol table entry */
  char *ptr,ttext[1024],tempstring[1024];
  char symbolname[80],symboltype[80];
  short int jtemp;  unsigned short jtemp2;
  char outtext[80];
  int ii;
  char cc;
  short ss;
  long ll,l2;
  unsigned char uc;
  unsigned short us;
  unsigned long ul;
  unsigned int ui;
  float ff;
  double dd;
  long vv;
/*-----------------------------------*/
  isym= level[ilevel].funcsymbol+1;
  nseek= exe.symoffset + isym*sizeof(symbol);
  fseek(fp,nseek,0);
  stackbase= level[ilevel].stackpointer;
  for(i=isym;i<exe.nsym;i++)
    {status= fread(&symbol,sizeof(symbol),1,fp);
     if(status==0) printf("could not read symbol\n");
     type= symbol.n_type;
     if(type==N_FUN) return;            /* new function */
     else if(type==N_SO) return;        /* new source file */
     else if(type!=N_LSYM) continue;	/* local sym: name,,0,type,offset */
     addr= symbol.n_un.n_strx;          /* pointer to string table */
     off= symbol.n_value;               /* offset from stack frame end */
     fseek(fp2,exe.stroffset,0);
     fseek(fp2,addr,1);
     ptr= fgets(ttext,sizeof(ttext),fp2);
     /* get the symbol's name */
     strcpy(tempstring,ttext);
     str_whiteout(tempstring,":=;");
     sscanf(tempstring,"%s",symbolname);
     /* get text used to find type of symbol */
     ptr= strchr(ttext,':');
     strcpy(symboltype,ptr);
     address= stackbase+off;
/* find out what kind of symbol it is */
     trb_translate(ttext,&code,&pointer,&array);
#if SYMBOLDUMP
     printf("symbol: >%s< off=%d\n",ttext,off);
     trb_verbalize(symbolname,code,pointer,array);
#endif
/* if it is a pointer, print the address & dereference it */
     if(pointer==1)
       {newaddress= *(unsigned long *) address;
        fprintf(fpcrash,"  %s = 0x%x (pointer to %s) \n",
          symbolname, newaddress, description[code]);
        if(newaddress>=0 && newaddress<0x1000) continue;
        else address= newaddress;
       }
     else if(pointer==2)   /* could have pointer to pointer */
       {newaddress= *(unsigned long *) address;
        fprintf(fpcrash,"  %s = 0x%x (pointer to *%s) \n",
          symbolname, newaddress, description[code]);
        if(newaddress>=0 && newaddress<0x1000) continue;
        else address= newaddress;
        newaddress= *(unsigned long *) address;
        if(newaddress>=0 && newaddress<0x1000) continue;
        else address= newaddress;
       }
	
/* treat a ptr to char as an array */
     if(pointer>0 && code==D_CHAR) goto arrays;

/* an array of any type */
     if(array>1) goto arrays;
     
/* int */
     else if(code==D_INT)
       {ii= *(int *)address;
        sprintf(outtext,"%d 0x%x (long)",ii,ii);}
/* char */
     else if(code==D_CHAR)
       {cc= *(char *)address;
        sprintf(outtext,"\'%c\' 0x%x (char)",cc,cc);}
/* long */
     else if(code==D_LONG)
       {ll= *(long *)address;
        sprintf(outtext,"%ld 0x%x (long)",ll,ll);}
/* short */
     else if(code==D_SHORT)
       {ss= *(short *)address;
        sprintf(outtext,"%hd 0x%hx (short)",ss,ss);}
/* unsigned char */
     else if(code==D_UCHAR)
       {uc= *(unsigned char *)address;
        sprintf(outtext,"\'%c\' 0x%x (u char)",uc,uc);}
/* unsigned short */
     else if(code==D_USHORT)
       {us= *(unsigned short *)address;
        sprintf(outtext,"%hu 0x%hx (u short)",us,us);}
/* unsigned long */
     else if(code==D_ULONG)
       {ul= *(unsigned long *)address;
        sprintf(outtext,"%u 0x%x (u long)",ul,ul);}
/* unsigned int */
     else if(code==D_UINT)
       {ui= *(unsigned int *)address;
        sprintf(outtext,"%u 0x%x (u int)",ui,ui);}
/* float */
     else if(code==D_FLOAT)
       {ff= *(float *)address;
        ll= *(long *)address;
        sprintf(outtext,"%f 0x%08x (float)",ff,ll);}
/* double */
     else if(code==D_DOUBLE)
       {dd= *(double *)address;
        ll= *(long *)address;
        l2= *(long *)(address+sizeof(long));
        sprintf(outtext,"%f 0x%08x%08x (double)",dd,ll,l2);}
/* void */
     else if(code==D_VOID)
       {vv= *(long *)address;
        sprintf(outtext,"%d 0x%x (void)",vv,vv);}
/* ??? */
     else
       sprintf(outtext," unknown type ");
	

     if(pointer==0)fprintf(fpcrash,"  %s = %s \n",symbolname,outtext);
     else if(pointer==1)fprintf(fpcrash,"  *%s = %s \n",symbolname,outtext);
     continue;
/*---------*/
arrays:
/*---------*/
     size= array-1;
     middle= array/2;
/* int or long array */
     if(code==D_INT || code==D_LONG)
       {fprintf(fpcrash,"  %s = an array of type %s \n",
            symbolname,description[code]);
        ii= *(int *)address;
        fprintf(fpcrash,"    %s[0] = %d 0x%x \n", symbolname,ii,ii);
        ii= *(int *) (address+middle*sizeof(int));
        fprintf(fpcrash,"    %s[%d] = %d 0x%x \n", symbolname,middle,ii,ii);
        ii= *(int *) (address+size*sizeof(int));
        fprintf(fpcrash,"    %s[%d] = %d 0x%x \n", symbolname,size,ii,ii);
       }
/* char array */
     else if(code==D_CHAR)
       fprintf(fpcrash,"  %s = \"%s\" \n",symbolname,address);
/* float array */
     else if(code==D_FLOAT)
       {fprintf(fpcrash,"  %s = an array of type %s \n",
            symbolname,description[code]);
        ff= *(float *)address;
        ll= *(long *)address;
        fprintf(fpcrash,"    %s[0] = %f 0x%x \n", symbolname,ff,ll);
        ff= *(float *) (address+middle*sizeof(float));
        ll= *(long *) (address+middle*sizeof(float));
        fprintf(fpcrash,"    %s[%d] = %f 0x%x \n", symbolname,middle,ff,ll);
        ff= *(float *) (address+size*sizeof(float));
        ll= *(long *) (address+size*sizeof(float));
        fprintf(fpcrash,"    %s[%d] = %f 0x%x \n", symbolname,size,ff,ll);
       }
/* dump other kinds of arrays */

    } /* end of loop over all nsym */

} /* end of trb_symbols */

/****************************************************************/
/*	trb_traceback						*/
/*	print a traceback 					*/
/****************************************************************/
static void trb_traceback(nlevel)
int nlevel;
{
  int i;
  FILE *fp,*fp2;
/*---------------------------*/
  if(nlevel<1)return;
/* use first file pointer to read the symbol table */
  fp= fopen(exe.name,"r");
  if(fp==NULL) {printf("can't open %s\n",exe.name);exit(1);}
/* use second file pointer to read the string table */
  fp2= fopen(exe.name,"r");

/* print a traceback to the screen */
  fprintf(fpcrash,"---------- traceback ----------\n");
  for(i=0;i<nlevel;i++)
    if(level[i].found!=0)fprintf(fpcrash,"file %s line %d function %s() \n",
       level[i].filename, level[i].line, level[i].funcname);
     else
       fprintf(fpcrash,"address %x \n", level[i].programcounter);

  for(i=0;i<nlevel;i++)
    {
     fprintf(fpcrash,"------------------------------------\n");
     if(level[i].found!=0)
       {
        trb_dictionary(i,fp,fp2);
        trb_params(i,fp,fp2);
        fprintf(fpcrash,"  -- local symbols for %s --\n",level[i].funcname);
        trb_symbols(i,fp,fp2);
       }
    }
  
  fclose(fp2);
  fclose(fp);
       
} /* end of trb_traceback */

/****************************************************************/
/*	trb_userinfo						*/
/*	put program name, user, etc into a file			*/
/****************************************************************/
void trb_userinfo(fp)
FILE *fp;
{
  int ll;
  char *user,host[64],nouser[8];
  time_t timeofday;
  char fulltime[26];
/* get the user's name */
  user= (char *) getlogin();
  if(user==NULL)user= (char *)getpwuid(getuid());
  if(user==NULL){strcpy(nouser,"????"); user=nouser; }
  
/* get the time */
  timeofday=time((time_t *)0);
  strcpy(fulltime,(char *)ctime(&timeofday));
  fulltime[24]=CNULL;
/* get the host */
  gethostname(host,64);
/* write to a file */
  fprintf(fp,"user=%s host=%s date=%s \n", user,host,fulltime);
  fprintf(fp,"program=%s \n", exe.name);
} /* end of trb_userinfo */

/****************************************************************/
/*	trb_handle						*/
/*	handle all signals					*/
/****************************************************************/
void trb_handle(sig,code,scp)
int sig, code;
struct sigcontext *scp;
{
  int i,j,exitflag;
  int nlevel;
  unsigned long programcounter,stackpointer,frameend;
  unsigned long instruction;
  char *ptr;
  char *startdump;
/*--------------------*/
/* write to a file called CRASH */
  if(fpcrash==0) fpcrash= fopen("CRASH","a");	/* open for append */
  if(fpcrash==NULL) fpcrash= stdout;	 /* if failure, use standard output */
  fprintf(fpcrash,"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
  trb_userinfo(fpcrash);
/* print meaningful message for signal */
  fprintf(fpcrash,"%s signal=%d(%d) \n",sigtext[sig],sig,code);
  ptr= trb_codetext(sig,code);
  if(ptr!=NULL) fprintf(fpcrash,"%s\n",ptr);
/* get stack pointer & program counter */
  programcounter= scp->sc_pc;
  stackpointer= scp->sc_fp;
  frameend= *( (long *)stackpointer +JUMPSP);
  DBPRINT((" pc=0x%x sp=0x%x \n", programcounter,stackpointer));

#if STACKDUMP
  startdump= (char *)scp->sc_sp;
  startdump= startdump-128;
  trb_stackdump(startdump,DUMPSIZE,&fpstackdump);
#endif

/* walk the stack, storing stack pointers & program counters */
  nlevel= 0;
  while(stackpointer!=0)
    {level[nlevel].programcounter= programcounter;
     level[nlevel].frameend= frameend;
     level[nlevel].stackpointer= stackpointer;
     if(nlevel<MAXLEVEL)nlevel++;
     DBPRINT(("sp=%08x pc=%08x\n",stackpointer,programcounter));
#if FRAMEDUMP
     trb_framedump(stackpointer,programcounter,frameend,&fpframedump);
#endif
     programcounter= *( (long *)stackpointer +JUMPPC);
     stackpointer= *( (long *)stackpointer +JUMPSP);
     if(stackpointer!=0) frameend= *( (long *)stackpointer +JUMPSP);
     if(frameend==0) stackpointer= 0; /* we are at the end */
    }

  trb_exeinfo();		/* get info from file header */
  trb_getline(nlevel);		/* convert addresses to line numbers */
  trb_traceback(nlevel);	/* print a full traceback */
#if SYMBOLDUMP
  trb_symboldump();
#endif

  exitflag= 0;
  switch(sig)
    {case SIGTRAP:		exitflag= 1;	break;
     case SIGSEGV:		exitflag= 1;	break; 
     case SIGABRT:		exitflag= 1;	break;
     case SIGBUS:		exitflag= 1;	break;
     case SIGILL:		exitflag= 1;	break;
     case SIGFPE:               exitflag= 1;	break;
     default:			
       printf("signal %d sent to trb_handle \n",sig);
       break;
    } /* end of switch on sig */
  fprintf(fpcrash,"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
#if FRAMEDUMP
  fclose(fpframedump);
#endif
  if(exitflag) 
    {if(fpcrash!=stdout) {fclose(fpcrash); system("ls -l CRASH");}
     exit(sig);
    }
  return;
} /* end of trb_handle */

/****************************************************************/
/*	trb_sigtextinit						*/
/*	initialize signal text messages				*/
/****************************************************************/
static void trb_sigtextinit()
{
  strcpy(sigtext[1],  "SIGHUP:  hangup signal received");
  strcpy(sigtext[2],  "SIGINT:  interrupt signal received");
  strcpy(sigtext[3],  "SIGQUIT: quit signal received");
  strcpy(sigtext[4],  "SIGILL:  illegal instruction (not reset when caught)");
  strcpy(sigtext[5],  "SIGTRAP: trace trap (not reset when caught)");
  strcpy(sigtext[6],  "SIGABRT: abort or IOT instruction");
  strcpy(sigtext[7],  "SIGEMT:  EMT instruction");
  strcpy(sigtext[8],  "SIGFPE:  floating point exception");
  strcpy(sigtext[9],  "SIGKILL: kill signal received");
  strcpy(sigtext[10],  "SIGBUS:  bus error");
  strcpy(sigtext[11], "SIGSEGV: segmentation violation");
  strcpy(sigtext[12], "SIGSYS:  bad argument to system call");
  strcpy(sigtext[13], "SIGPIPE: write on a pipe with no one to read it");
  strcpy(sigtext[14], "SIGALRM: alarm clock signal received");
  strcpy(sigtext[15], "SIGTERM: received software termination signal");
  strcpy(sigtext[16], "SIGURG:  urgent condition on IO channel");
  strcpy(sigtext[17], "SIGSTOP: sendable stop signal not from tty");
  strcpy(sigtext[18], "SIGTSTP: received stop signal from tty");
  strcpy(sigtext[19], "SIGCONT: continue a stopped process");
  strcpy(sigtext[20], "SIGCHLD: child process has stopped or exited");
  strcpy(sigtext[21], "SIGTTIN: to readers pgrp upon background tty read");
  strcpy(sigtext[22], "SIGTTOU: like TTIN for output if (tp->t_local&LTOSTOP)");
  strcpy(sigtext[23], "SIGIO:   input/output possible signal");
  strcpy(sigtext[24], "SIGXCPU: exceeded CPU time limit");
  strcpy(sigtext[25], "SIGXFSZ: exceeded file size limit");
  strcpy(sigtext[26], "SIGVTALRM: received virtual time alarm");
  strcpy(sigtext[27], "SIGPROF: received profiling time alarm");
  strcpy(sigtext[28], "SIGWINCH: window changed");
  strcpy(sigtext[29], "SIGLOST: resource lost (eg, record-lock lost)");
  strcpy(sigtext[30], "SIGUSR1: received user defined signal 1");
  strcpy(sigtext[31], "SIGUSR2: received user defined signal 2");
} /* end if trb_sigtextinit */

/****************************************************************/
/*	trb_codetext						*/
/*	return text explanation of signal			*/
/****************************************************************/
static char *trb_codetext(sig,code)
int sig,code;
{
  if(sig==SIGILL)
     return("illegal instruction fault");
    
  else if(sig==SIGFPE)
     {if(code==0)return("float divide by zero or overflow");
      else if(code==2)return("integer divide by zero");
      else return("misc floating point error");
     }
    
  else if(sig==SIGBUS)
     return("hardware alignment error");
    
  else if(sig==SIGSEGV)
     return("no mapping at the fault address");
    
  else
    return(NULL);
} /* end of trb_codetext */

/****************************************************************/
/*	trb_signal						*/
/*	initiate trapping of all signals			*/
/****************************************************************/
static void trb_signal()
{
  int status;
/*---------------------------------------*/
  trb_sigtextinit();
/* trap the important signals */
/*  signal(SIGILL,trb_handle);  
  signal(SIGTRAP,trb_handle); */
  signal(SIGFPE,trb_handle);  	/* floating point errors */
  signal(SIGBUS,trb_handle);  	/* bus errors */
  signal(SIGSEGV,trb_handle); 	/* segmentation faults */
  signal(SIGABRT,trb_handle);  	/* to get integer divide */
/* don't trap the rest */
#if 0
  signal(SIGHUP,trb_handle);  
  signal(SIGINT,trb_handle);  
  signal(SIGQUIT,trb_handle); 
  signal(SIGEMT,trb_handle);  
  signal(SIGKILL,trb_handle);
  signal(SIGSYS,trb_handle);  
  signal(SIGPIPE,trb_handle); 
  signal(SIGALRM,trb_handle); 
  signal(SIGTERM,trb_handle); 
  signal(SIGURG,trb_handle);  
  signal(SIGSTOP,trb_handle); 
  signal(SIGTSTP,trb_handle); 
  signal(SIGCONT,trb_handle); 
  signal(SIGCHLD,trb_handle); 
  signal(SIGTTIN,trb_handle); 
  signal(SIGTTOU,trb_handle); 
  signal(SIGIO,trb_handle);   
  signal(SIGXCPU,trb_handle); 
  signal(SIGXFSZ,trb_handle); 
  signal(SIGVTALRM,trb_handle); 
  signal(SIGPROF,trb_handle); 
  signal(SIGWINCH,trb_handle); 
  signal(SIGLOST,trb_handle); 
  signal(SIGUSR1,trb_handle);
  signal(SIGUSR2,trb_handle);
#endif
} /* end of trb_signal */

/****************************************************************/
/*	trb_signalinit						*/
/*	initiate trapping of all signals			*/
/****************************************************************/
void trb_signalinit(argc,argv)
int argc;
char *argv[];
{
  FILE *fp;
/*---------------------------------------*/
/* find the executable file */
  trb_exefind(argc,argv);
/* remove files CRASH, STACKDUMP, & FRAMEDUMP */
  unlink("./CRASH");
  unlink("./STACKDUMP");
  unlink("./FRAMEDUMP");
  fpcrash= 0;
  fpstackdump= 0;  
  fpframedump= 0;  
/* set up our signal handler */
  trb_signal();
} /* end of ita_signalinit */


/**************************************************************/
/*	str_getdelimited                                      */
/*	returns substring bounded by 2 characters	      */
/**************************************************************/
static void str_getdelimited(intext,bounds,outtext)
char *intext,*bounds,*outtext;
{
  int ll;
  char start, end;
  char *ptr, *ptr2;
/*------------------------------------------------------*/
  outtext[0]=CNULL;
  start= bounds[0];
  end= bounds[1];  
  ptr=strchr(intext,start);
  if(ptr==NULL)return;
  ptr++;
  ptr2=strchr(ptr,end);
  if(ptr2==NULL)return;
  ll=ptr2-ptr;
  strncpy(outtext,ptr,ll);
  outtext[ll]=CNULL;
}

/********************************************************/
/*	str_whiteout					*/
/*	routine to change certain characters to blanks 	*/
/********************************************************/
static void str_whiteout(string,chars)
char *string,*chars;
{
/*... locals */
  int i,j,ls,lc;
  char cc;
/*-----------------------------*/
  ls=strlen(string);
  if(ls<1)return;
  lc=strlen(chars);
  if(lc<1)return;
  for(i=0;i<ls;i++)
    {cc=string[i];
     for(j=0;j<lc;j++)if(cc==chars[j])cc=' ';
     string[i]=cc;
    }
} /* end of str_whiteout */
  
/*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

  Alan Dunham          |     /\    /\     |   Calgary ... 
  adunham@ita.lgc.com  |    /  \  /  \    |       home of Big Rock beer
  (403) 269 4669       |   /    \/    \   |      
  Calgary, Alberta     |  /     /      \  |  
Newsgroups: comp.unix.bsd