home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / unix / bsd / 4779 < prev    next >
Encoding:
Text File  |  1992-08-27  |  51.1 KB  |  1,662 lines

  1. Newsgroups: comp.unix.bsd
  2. Path: sparky!uunet!sun-barr!cs.utexas.edu!lgc.com!usenet
  3. From: adunham@lgc.com (Alan Dunham)
  4. Subject: Crash Tracebacks in 386BSD
  5. Message-ID: <1992Aug27.212418.19185@lgc.com>
  6. Sender: usenet@lgc.com
  7. Nntp-Posting-Host: sparky.lgc.com
  8. Organization: Landmark Graphics Corp., Houston, Tx
  9. Date: Thu, 27 Aug 1992 21:24:18 GMT
  10. Lines: 1650
  11.  
  12. Howdy:
  13.   I have ported my crash traceback to 386BSD. (see Doctor Dobbs 
  14.   Journal  September 1992 page 80).  This file includes test.c, a
  15.   small test program, and 386bsdcrash.c, the main code file.
  16.   The test program calls trb_signalinit() to set things up.
  17.   This was a quick port and I haven't tested the hell out of it,
  18.   so if you find any bugs, email me at adunham@ita.lgc.com and
  19.   I'll summarize fixes to the net.
  20.  
  21. /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
  22.  
  23. /* test.c  a small program to test the crash traceback */
  24.  
  25. #define DEBUGPRINT        /* we don't want debug info */
  26. #ifdef DEBUGPRINT
  27. # define DBPRINT(s) printf s
  28. #else
  29. # define DBPRINT(s)
  30. #endif
  31.  
  32. void tst_segv(),tst_bus();
  33. void tst_fltdiv(), tst_intdiv(), tst_intoverflow();
  34. void tst_fltoverflow(), tst_fltunderflow();
  35. void tst_lv4(),tst_lv3(),tst_lv2(),tst_lv1();
  36.  
  37. /*----------------------------------------*/
  38. void tst_segv()
  39. {
  40.   char text[16];
  41.   char *ptr;
  42.   int ii, jj, arr[16];
  43.   strcpy(text,"seg fault");
  44.   DBPRINT((" in segv\n"));
  45.   jj= 4096;
  46.   arr[jj] = ii; 
  47. }
  48.  
  49. void tst_fltdiv()
  50. {
  51.   char text[16];
  52.   float e,d,f;
  53. /*-------------------------------*/
  54.   strcpy(text,"fltdiv");
  55.   DBPRINT((" in fltdiv \n"));
  56.   f= 127.0;
  57.   e= 0.0;
  58.   d= 126.0;
  59.   f=d/e;
  60. }
  61.  
  62. void tst_intdiv()
  63. {
  64.   int a,b,c;
  65.   DBPRINT((" in intdiv \n"));
  66.   c=12;
  67.   a=1;
  68.   b=0;
  69.   c=a/b;
  70. }
  71.  
  72. void tst_intoverflow()
  73. {
  74.   int i,aa,bb,cc;
  75.   char text[16];
  76.   strcpy(text,"intoverflow");
  77.   DBPRINT((" in intoverflow \n"));
  78.   aa= 0x0000ffff;
  79.   for(i=0;i<8;i++)
  80.     {aa= aa*16;
  81.      printf("i=%d aa=0x%x \n",i,aa);
  82.     }
  83. }
  84.  
  85. void tst_fltoverflow()
  86. {
  87.   int i;
  88.   float ff;
  89.   char text[16];
  90.   strcpy(text,"fltoverflow");
  91.   DBPRINT((" in fltoverflow \n"));
  92.   ff= 6.023e23;
  93.   for(i=0;i<30;i++)
  94.     {ff= ff* 1.0e2;
  95.      printf("i=%d ff=%10.3e \n",i,ff);
  96.     }
  97. }
  98.  
  99. void tst_fltunderflow()
  100. {
  101.   int i;
  102.   float ff;
  103.   char text[16];
  104.   strcpy(text,"fltunderflow");
  105.   DBPRINT((" in fltunderflow \n"));
  106.   ff= 6.023e-23;
  107.   for(i=0;i<30;i++)
  108.     {ff= ff* 1.0e-2;
  109.      printf("i=%d ff=%10.3e \n",i,ff);
  110.     }
  111. }
  112.  
  113. void tst_lv4(paramtext)
  114. char *paramtext;
  115. {
  116.   long l4;
  117.   char text[16];
  118.   l4= 0xcafefade;
  119.   strcpy(text,"level4");
  120.   tst_bus(); 
  121. }
  122.  
  123. void tst_lv3(paramtext)
  124. char *paramtext;
  125. {
  126.   long l3;
  127.   char text[16];
  128.   l3= 0xdeafdead;
  129.   strcpy(text,"level3");
  130.   tst_lv4("call 4");
  131. }
  132.  
  133. void tst_lv2(paramtext)
  134. char *paramtext;
  135. {
  136.   long l2;
  137.   char text[17];
  138.   l2= 0xfeedface;
  139.   strcpy(text,"level2");
  140.   tst_lv3("call 3");
  141. }
  142.  
  143. void tst_lv1()
  144. {
  145.   long l1, *lptr;
  146.   char text[16];
  147.   l1= 0xdeedfade;
  148.   lptr= &l1;
  149.   strcpy(text,"level1");
  150.   tst_lv2("call 2");
  151. }
  152.  
  153. void tst_bus()
  154. {
  155.   char *ptr;
  156.   unsigned long uu;
  157.   char text[16];
  158.   strcpy(text,"bus error");
  159.   ptr= 0x0;
  160.   *ptr=0;
  161. }
  162.  
  163. void tst_param(ii,ss,ff,dd,cc,uc,us,ul,ui)
  164. int ii;
  165. short ss;
  166. float ff;
  167. double dd;
  168. char cc;
  169. unsigned char uc;
  170. unsigned short us;
  171. unsigned long ul;
  172. unsigned int ui;
  173. {
  174.   tst_bus();
  175. }
  176.  
  177. void tst_param2(ii,ss,ff,dd,cc,uc,us,ul,ui,ptr)
  178. int *ii;
  179. short *ss;
  180. float *ff;
  181. double *dd;
  182. char *cc;
  183. unsigned char *uc;
  184. unsigned short *us;
  185. unsigned long *ul;
  186. unsigned int *ui;
  187. char *ptr;
  188. {
  189.   tst_bus();
  190. }
  191.  
  192. main(argc,argv)
  193. int argc;
  194. char *argv[];
  195. {
  196.   int ii;
  197.   char cc;
  198.   long ll;
  199.   short ss;
  200.   float ff;
  201.   double dd;
  202.   unsigned char uc;
  203.   unsigned short us;
  204.   unsigned long ul;
  205.   unsigned int ui;
  206.   int iarr[12];
  207.   float farr[8];
  208.   char text[21];
  209.   int random;
  210. /*--------------------*/
  211.   
  212.   trb_signalinit(argc,argv);
  213.  
  214.   ll=0xfeeadded;
  215.   strcpy(text,"traceback");
  216.  
  217.   for(ii=0;ii<12;ii++) iarr[ii]=ii;
  218.   for(ii=0,ff=100;ii<8;ii++,ff++) farr[ii]=ff;
  219.  
  220.   ii=12;
  221.   cc='q';
  222.   ss=24;
  223.   ff=256.0;
  224.   dd=512.0;
  225.   uc= 65;
  226.   us= -4;
  227.   ul= -8;
  228.   ui= -16;
  229.  
  230. /* get a random number */
  231.   random= time(0);
  232.   random= random & 7;
  233.   printf("random= %d \n",random);
  234.   switch (random)
  235.     {case 0:    tst_fltoverflow();    /* overflow */
  236.         break;
  237.  
  238.      case 1:    tst_bus();    /* bus error */
  239.         break;
  240.  
  241.      case 2:    tst_segv();    /* segmentation fault */ 
  242.         break;
  243.  
  244.      case 3:    tst_intdiv();            /* integer divide */
  245.         break;
  246.  
  247.      case 4:    tst_fltdiv(ll,ss,ff,dd);    /* float divide */
  248.         break;
  249.  
  250.      case 5:    tst_lv1();        /* several call levels */
  251.         break;
  252.  
  253.      case 6:    tst_param(ii,ss,ff,dd,cc,uc,us,ul,ui);     /* show parameters */
  254.         break;
  255.  
  256.      case 7:    tst_param2(&ii,&ss,&ff,&dd,&cc,&uc,&us,&ul,&ui,text);
  257.         break;
  258.  
  259.      default:    break;
  260.     } /* end of switch */
  261.         
  262.     exit(0);
  263. }
  264.  
  265.  
  266. /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
  267.  
  268. /* 386bsdcrash.c     signal handling & stack traceback */
  269.  
  270. /* 
  271.  * Copyright 1992, Alan Dunham 
  272.  *
  273.  * This code may be copied as long as this copyright notice remains intact 
  274.  * 
  275.  */
  276.  
  277. #include <stdio.h>
  278. #include <signal.h>        /* for signal definitions */
  279. #include <a.out.h>        /* for NSYMOFF etc */
  280. #include <stab.h>        /* for N_SLINE etc */
  281. #include <string.h>        /* for strtok &strstr */
  282. #include <sys/types.h>          /* for ctime */
  283. /*----------------- local defines --------------------*/
  284. #undef PROTOTYPES         /* ignore prototype info */
  285. #undef DEBUGPRINT         /* we want debug info */
  286. #define STACKDUMP 0        /* set to 1 to get 32bit stack dumps */
  287. #define FRAMEDUMP 0        /* set to 1 to dump each stack frame */
  288. #define PARAMDUMP 0        /* set to 1 to get parameter dumps */
  289. #define SYMBOLDUMP 0        /* set to 1 to get local symbol dumps */
  290.  
  291. #define JUMPPC 1        /* how to find next program counter */
  292. #define JUMPSP 0        /* how to find next stack pointer */
  293. #define MAXLEVEL 40        /* maximum number of nested subroutine calls */
  294. #define MAXPARAM 40        /* maximum number of subroutine parameters */
  295. #define DUMPSIZE 256        /* size of stack dump in longwords */
  296. #define NSIGNAL 31              /* #signals to describe in text array */
  297. #define STREQ(a,b)  (strcmp((a),(b))==0)
  298. #define STRNEQ(a,b) (strcmp((a),(b))!=0)
  299. #define CNULL '\0'
  300.  
  301. #ifdef PROTOTYPES
  302. # define P_(s) s
  303. #else
  304. # define P_(s) ()
  305. #endif
  306. #ifdef DEBUGPRINT
  307. # define DBPRINT(s) printf s
  308. #else
  309. # define DBPRINT(s) 
  310. #endif
  311.  
  312. /* defines for data dictionary: basic types */
  313. #define D_INT 1
  314. #define D_CHAR 2
  315. #define D_LONG 3
  316. #define D_UINT 4
  317. #define D_ULONG 5
  318. #define D_SHORT 6
  319. #define D_LONGLONG 7
  320. #define D_USHORT 8
  321. #define D_ULONGLONG 9
  322. #define D_SIGNEDCHAR 10
  323. #define D_UCHAR 11
  324. #define D_FLOAT 12 
  325. #define D_DOUBLE 13
  326. #define D_LONGDOUBLE 14
  327. #define D_VOID 15
  328.  
  329. /*----------------- external functions --------------------*/
  330. char *malloc();
  331. char *getenv();
  332.  
  333. /*----------------- internal functions --------------------*/
  334. static void trb_exefind P_((int argc, char *argv));
  335. static void trb_exeinfo();
  336. static void trb_dictionary P_((int ilevel, FILE fp, FILE fp2));
  337. static void trb_symboldump();
  338. static void trb_stackdump P_((unsigned long start, int nn, FILE **fp));
  339. static void trb_framedump P_((unsigned long sp, unsigned long pc,
  340.                              unsigned long fremeend, FILE **fp));
  341. static void trb_getline P_((int nlevel));
  342. static void trb_params P_((int ilevel, FILE fp, FILE fp2));
  343. static void trb_symbols P_((int ilevel, FILE fp, FILE fp2));
  344. static void trb_traceback P_((int nlevel));
  345. void trb_userinfo P_((FILE fp));
  346. void trb_handle P_((int sig,int code,struct sigcontext *scp));
  347. static void trb_sigtextinit();
  348. static char *trb_codetext P_((int sig, int code));
  349. static void trb_signal();
  350. void trb_signalinit P_((int argc, char *argv[]));
  351. static void str_getdelimited P_((char *inttext, char *bounds,
  352.                  char *outtext));
  353. static void str_whiteout P_((char *string, char *chars));
  354.  
  355. /*----------------- structure definitions -----------------*/
  356. struct levelstr       /* info for each function in traceback */
  357.   {unsigned long stackpointer;    /* start of stack frame */
  358.    unsigned long programcounter;  /* return address */
  359.    unsigned long frameend;        /* end of stack frame (+4) */
  360.    long fileaddr,funcaddr;        /* addresses into string table */
  361.    char funcname[256];            /* name of function */
  362.    char filename[256];            /* name of source file */
  363.    int found;                     /* 0 if function not found */
  364.    int filesymbol;                /* symbol # for start of source file */
  365.    int funcsymbol;                /* symbol # for start of function */
  366.    int line;                      /* line number in source file */
  367.   };
  368.  
  369. struct exestr      /* information about the executable file */
  370.   {int nsym;             /* number of symbols in symbol table */
  371.    unsigned long magic;  /* the magic number of the file */
  372.    long stroffset;       /* offset to the string table */
  373.    long symoffset;       /* offset to the symbol table */
  374.    char name[256];       /* path to the file */
  375.   };
  376.  
  377. struct dictstr     /* a dictionary of defined variable types */
  378.   {char match[8];        /* the defined type  */
  379.    char basetype[8];        /* what it is defined from  */
  380.    int code;            /* our base identifier ie D_INT */
  381.    char fullstring[80];        /* as it was read from COFF */
  382.    int ptr;            /* 1 if it is a pointer */
  383.    int lower,upper;        /* array bounds */
  384.   };
  385.  
  386.   
  387. /*----------------- global variables ----------------------*/
  388. char   sigtext[NSIGNAL+1][64];    /* describe signal values */
  389. struct levelstr level[MAXLEVEL];  /* one per stack frame */
  390. struct exestr exe;
  391. struct dictstr dictionary[200];   /* allow 200 per source file */
  392. int ndict;                        /* number of types per source file */
  393. FILE   *fpcrash,*fpstackdump,*fpframedump;
  394.           /* pointers to files CRASH, STACKDUMP, FRAMEDUMP */
  395. char description[17][20] = {"???","int","char","long","unsigned int",
  396.                  "unsigned long","short","longlong","unsigned short",
  397.                  "unsigned longlong","signed char","unsigned char",
  398.                  "float","double","longdouble","void","???" };
  399.   
  400. /****************************************************************/
  401. /*    trb_exefind                        */
  402. /*    find the path of the file we are executing        */
  403. /****************************************************************/
  404. static void trb_exefind(argc,argv)
  405. int argc;
  406. char *argv[];
  407. {
  408.   FILE *fp;
  409.   int ll;
  410.   char name[256],*path;
  411.   char *ptr,trial[256];
  412. /*---------------------------------*/
  413. /* get name of program */
  414.   strcpy(name,argv[0]);
  415.   
  416. /* 1: if name contains a slash, assume it is the direct path */
  417.   ptr= strchr(name,'/');
  418.   if(ptr!=NULL)
  419.     {strcpy(trial,name);
  420.      fp= fopen(trial,"r");
  421.      if(fp!=NULL)
  422.        {fclose(fp);strcpy(exe.name,trial);return;}
  423.     }
  424.       
  425. /* 2: look in the user's path */
  426.   ptr= getenv("PATH");
  427.   ll= strlen(ptr);
  428.   path= malloc(ll+1);
  429.   strcpy(path,ptr);
  430. /* separate path string into its components */
  431.   ptr= strtok(path,":");
  432.   while(ptr!=NULL)
  433.     {strcpy(trial,ptr);
  434.      strcat(trial,"/");
  435.      strcat(trial,name);
  436.      DBPRINT(("trial exe is %s \n",trial));
  437.      fp= fopen(trial,"r");
  438.      if(fp!=NULL) {fclose(fp);strcpy(exe.name,trial);free(path);return;}
  439.      ptr= strtok(NULL,":");
  440.     }
  441.  
  442. /* 3: try the local directory in case it is not in the path */
  443.   strcpy(trial,"./");
  444.   strcat(trial,name);
  445.   DBPRINT(("trial exe is %s \n",trial));
  446.   fp= fopen(trial,"r");
  447.   if(fp!=NULL){fclose(fp);strcpy(exe.name,trial);return;}
  448.  
  449. } /* end of trb_exefind */
  450.  
  451. /****************************************************************/
  452. /*    trb_exeinfo                        */
  453. /*    get needed info from executable file header        */
  454. /****************************************************************/
  455. static void trb_exeinfo()
  456. {
  457.   int status;
  458.   unsigned long magic;
  459.   FILE *fp;
  460.   struct exec header;    /* exe file header (from a.out.h) */
  461.   struct nlist symbol;    /* symbol table entry */
  462. /*--------------------*/
  463. /* open exe file */
  464.   fp= fopen(exe.name,"r");
  465.   if(fp==NULL)
  466.     {printf("can't open %s\n",exe.name);
  467.      exit(1);}
  468.   
  469. /* read the file header */
  470.   status= fread(&header,sizeof(header),1,fp);
  471.   if(status==0) {printf("could not read header\n"); exit(2);}
  472.  
  473. /* is the magic number okay ? */
  474.   magic= header.a_magic;
  475.   status= N_BADMAG(header);
  476.   if(status!=0)
  477.     {printf("bad magic number = %ld 0x%lx 0%lo \n",magic,magic,magic);
  478.      exit(3);
  479.     }
  480.   exe.magic= magic;
  481.  
  482. /* how big is the symbol table */
  483.   exe.nsym= header.a_syms/sizeof(symbol);
  484.   if(exe.nsym==0) exit(4);
  485.  
  486. /* get file offsets for symbol table & string table */
  487.   exe.symoffset= N_SYMOFF(header);
  488.   exe.stroffset= N_STROFF(header);
  489.  
  490.   fclose(fp);
  491. } /* end of trb_exeinfo */
  492.   
  493. /****************************************************************/
  494. /*    trb_dictionary                        */
  495. /*    make a "data dictionary" for a source file        */
  496. /****************************************************************/
  497. static void trb_dictionary(ilevel,fp,fp2)
  498. int ilevel;
  499. FILE *fp, *fp2;
  500. {
  501.   int i,j,status,type,off;
  502.   int low,high,code,pointer;
  503.   int isym;
  504.   struct nlist symbol;    /* symbol table entry */
  505.   long nseek;
  506.   char *ptr, *ptr2;
  507.   char ttext[1024],tempstring[64];
  508.   char symbolname[32],junk1[8],junk2[8],match[8];
  509. /*--------------------*/
  510.   dictionary[0].code=D_INT;
  511.   dictionary[1].code=D_CHAR;
  512.   dictionary[2].code=D_LONG;
  513.   dictionary[3].code=D_UINT;
  514.   dictionary[4].code=D_ULONG;
  515.   dictionary[5].code=D_SHORT;
  516.   dictionary[6].code=D_LONGLONG;
  517.   dictionary[7].code=D_USHORT;
  518.   dictionary[8].code=D_ULONGLONG;
  519.   dictionary[9].code=D_SIGNEDCHAR;
  520.   dictionary[10].code=D_UCHAR;
  521.   dictionary[11].code=D_FLOAT;
  522.   dictionary[12].code=D_DOUBLE;
  523.   dictionary[13].code=D_LONGDOUBLE;
  524.   dictionary[14].code=D_VOID;
  525.   strcpy(dictionary[0].match,"1");
  526.   strcpy(dictionary[1].match,"2");
  527.   strcpy(dictionary[2].match,"3");
  528.   strcpy(dictionary[3].match,"4");
  529.   strcpy(dictionary[4].match,"5");
  530.   strcpy(dictionary[5].match,"6");
  531.   strcpy(dictionary[6].match,"7");
  532.   strcpy(dictionary[7].match,"8");
  533.   strcpy(dictionary[8].match,"9");
  534.   strcpy(dictionary[9].match,"10");
  535.   strcpy(dictionary[10].match,"11");
  536.   strcpy(dictionary[11].match,"12");
  537.   strcpy(dictionary[12].match,"13");
  538.   strcpy(dictionary[13].match,"14");
  539.   strcpy(dictionary[14].match,"15");
  540.   for(i=0;i<15;i++)
  541.     {dictionary[i].ptr=0;
  542.      dictionary[i].lower=0;
  543.      dictionary[i].upper=0;
  544.      dictionary[i].basetype[0]=CNULL;
  545.     }
  546.  
  547. /* open exe file */
  548.   fp= fopen(exe.name,"r");
  549.   fp2= fopen(exe.name,"r");
  550.   if(fp==NULL)
  551.     {printf("can't open %s\n",exe.name);
  552.      exit(1);}
  553.   ndict=15;
  554.   isym= level[ilevel].filesymbol+1;  /* seek to source files' symbols */
  555.   nseek= exe.symoffset + isym*sizeof(symbol);
  556.   fseek(fp,nseek,0);
  557.   for(i=isym;i<exe.nsym;i++)
  558.     {status= fread(&symbol,sizeof(symbol),1,fp);
  559.      if(status==0) printf("could not read symbol\n");
  560.      type= symbol.n_type;
  561.      if(type==N_SO) return; /* we are at the next source file */
  562.      if(type!=N_LSYM && type!=N_PSYM) continue;  /* local syms & params */
  563.      nseek= exe.stroffset+symbol.n_un.n_strx;
  564.      fseek(fp2,nseek,0);
  565.      ptr= fgets(ttext,sizeof(ttext),fp2);   /* text describing symbol */
  566.      /* ignore structures for now */
  567.      str_getdelimited(ttext,":=",match);
  568.      if(match[0]=='\0') continue; /* new defines are surrounded by := */
  569.      if(match[0]=='t') continue;  /* ignore basic types */
  570.      if(match[0]=='p')   /* remove the p if it is a parameter */
  571.         {strcpy(tempstring,match); strcpy(match,&tempstring[1]);}
  572.      /* extract the symbol name */
  573.      strcpy(tempstring,ttext);
  574.      str_whiteout(tempstring,":=;");
  575.      sscanf(tempstring,"%s",symbolname);
  576.      /* it is a new type, clear some flags */
  577.      dictionary[ndict].ptr= 0;
  578.      dictionary[ndict].code= 0;
  579.      dictionary[ndict].lower= 0;
  580.      dictionary[ndict].upper= 0;
  581.      strcpy(dictionary[ndict].match,match);
  582.      /* is this new type a pointer */       
  583.      ptr2=strstr(ptr,"=*");
  584.      if(ptr2!=NULL)
  585.        {str_getdelimited(ptr2,"*\0",match);
  586.         strcpy(dictionary[ndict].basetype,match);
  587.         dictionary[ndict].ptr= 1;
  588.         for(j=0;j<ndict;j++)
  589.           {if(STREQ(match,dictionary[j].match))
  590.          {code= dictionary[j].code;
  591.               pointer= dictionary[j].ptr+1;
  592.               dictionary[ndict].code= code;
  593.               dictionary[ndict].ptr= pointer;
  594.               break;
  595.              }
  596.           }
  597.         ndict++;
  598.         continue;
  599.        }
  600.      /* is this new type an array */
  601.      ptr2=strstr(ptr,"=ar");
  602.      if(ptr2!=NULL)
  603.        {strcpy(tempstring,ptr);
  604.     str_whiteout(tempstring,":;()");
  605.     sscanf(tempstring,"%s %s %d %d %s",junk1,junk2,&low,&high,match);
  606.       strcpy(dictionary[ndict].basetype,match);
  607.         dictionary[ndict].lower= low;
  608.         dictionary[ndict].upper= high;
  609.         code=0;
  610.     for(j=0;j<ndict;j++)
  611.           {if(STREQ(match,dictionary[j].match))
  612.          {code=dictionary[j].code;
  613.               dictionary[ndict].code=code;
  614.               break;
  615.              }
  616.           }
  617.         ndict++;
  618.         continue;
  619.        }
  620.  
  621.    }  /* end of loop over all symbols */
  622.   printf("ndict extended to %d \n",ndict);
  623. } /* end of trb_dictionary */
  624.   
  625. /****************************************************************/
  626. /*    trb_translate                        */
  627. /*    what kind of variable is a symbol            */
  628. /****************************************************************/
  629. static void trb_translate(ttext,code,pointer,array)
  630. char *ttext;
  631. int *code, *pointer, *array;
  632. {
  633.   int i,j,status,type,off;
  634.   int low,high,size;
  635.   int isym;
  636.   struct nlist symbol;    /* symbol table entry */
  637.   long nseek;
  638.   char *ptr, *ptr2;
  639.   char tempstring[64];
  640.   char symbolname[32],junk1[8],junk2[8],match[8];
  641. /*--------------------*/
  642. /* zero the output flags */
  643.   *code= 0;
  644.   *pointer= 0;
  645.   *array= 0;
  646. /* ignore structures for now */
  647.   str_getdelimited(ttext,":=",match);
  648.   if(match[0]=='\0') str_getdelimited(ttext,":\0",match); /* case of var:17 */
  649.   if(match[0]=='p')    /* remove the p if it is a parameter */
  650.     {strcpy(tempstring,match); strcpy(match,&tempstring[1]);}
  651. /* look in the data dictionary */
  652.     {for(j=0;j<ndict;j++)
  653.        {if(STREQ(match,dictionary[j].match))
  654.           {*code= dictionary[j].code;
  655.            *pointer= dictionary[j].ptr;
  656.            size= dictionary[j].upper-dictionary[j].lower+1;
  657.        if(size>1) *array=size;
  658.            return;
  659.           }
  660.        }
  661.      return;
  662.     }           
  663. } /* end of trb_translate */
  664.  
  665. /****************************************************************/
  666. /*    trb_verbalize                        */
  667. /*    print what kind of variable a symbol is            */
  668. /****************************************************************/
  669. static void trb_verbalize(name,code,pointer,array)
  670. char *name;
  671. int code,pointer,array;
  672. {
  673.   char ttext[80],size[16];
  674. /*------------------------------------------------------*/
  675.   strcpy(ttext,name);           
  676.   if(pointer>0)
  677.     strcat(ttext," is a pointer to type ");
  678.   else if(array>1)
  679.     strcat(ttext," is an array of type ");
  680.   else
  681.     strcat(ttext," is a variable of type ");
  682.   if(pointer==2) strcat(ttext,"*");
  683.   if(pointer==3) strcat(ttext,"*");
  684.   strcat(ttext,description[code]);
  685.  
  686.   if(array>1) {sprintf(size," [%d] ",array); strcat(ttext,size); } 
  687.   printf("%s\n",ttext);  
  688. } /* end of trb_verbalize */
  689.  
  690. /****************************************************************/
  691. /*    trb_symboldump                        */
  692. /*    dump text of local symbols                 */
  693. /****************************************************************/
  694. static void trb_symboldump()
  695. {
  696.   int i,j,ll,status,type,off,line;
  697.   FILE *fp, *fp2, *fpout;
  698.   struct nlist symbol;    /* symbol table entry */
  699.   long nseek;
  700.   char *ptr, *ptr2;
  701.   char ttext[1024];
  702.   long fileaddr,funcaddr;
  703.   unsigned long address;
  704.   char filename[256],funcname[256];
  705. /*--------------------*/
  706. /* open exe file */
  707.   fp= fopen(exe.name,"r");
  708.   fp2= fopen(exe.name,"r");
  709.   if(fp==NULL)
  710.     {printf("can't open %s\n",exe.name);
  711.      exit(1);}
  712. /* open file SYMBOLDUMP */
  713.   fpout= fopen("SYMBOLDUMP","w");
  714.   if(fpout==NULL)
  715.     {printf("can't open file SYMBOLDUMP for output\n");
  716.      exit(1);}
  717.   trb_userinfo(fpout);
  718.   fseek(fp,exe.symoffset,0);
  719.   for(i=0;i<exe.nsym;i++)
  720.     {status= fread(&symbol,sizeof(symbol),1,fp);
  721.      if(status==0) printf("could not read symbol\n");
  722.      type= symbol.n_type;
  723.      if(type==N_SO)    /* source file name: name,,0,0,address */
  724.        {fileaddr= symbol.n_un.n_strx;
  725.         fseek(fp2,exe.stroffset,0);
  726.         fseek(fp2,fileaddr,1);
  727.         ptr= fgets(filename,sizeof(filename),fp2);
  728.         fprintf(fpout,"filename %s \n",filename);
  729.        }
  730.      else if(type==N_FUN)    /* procedure: name,,0,linenumber,address */
  731.        {funcaddr= symbol.n_un.n_strx;
  732.         fseek(fp2,exe.stroffset,0);
  733.         fseek(fp2,funcaddr,1);
  734.         ptr= fgets(ttext,sizeof(ttext),fp2);
  735.         ptr= strtok(ttext,":");
  736.         ll= strlen(ptr);
  737.         if(ll>250){strncpy(funcname,ptr,250); funcname[250]= CNULL;}
  738.         else strcpy(funcname,ptr);
  739.         fprintf(fpout,"procedure %s \n",funcname);
  740.        }
  741.      else if(type==N_SLINE)        /* src line: 0,,0,linenumber,address */
  742.        {line= symbol.n_desc;
  743.         address= symbol.n_value;
  744.     fprintf(fpout,"line=%d address=%x\n",line,address);
  745.        }
  746.      else if(type==N_LSYM)
  747.        {off= symbol.n_value;
  748.         nseek= exe.stroffset+symbol.n_un.n_strx;
  749.         fseek(fp2,nseek,0);
  750.         ptr= fgets(ttext,sizeof(ttext),fp2);
  751.         fprintf(fpout,"frame offset=%d symbol text: >%s< \n",off,ttext);
  752.        }
  753.      else if(type==N_PSYM)    /* parameter: name,,0,type,offset */
  754.        {off= symbol.n_value;
  755.     nseek=exe.stroffset+symbol.n_un.n_strx;
  756.         fseek(fp2,nseek,0);
  757.         ptr= fgets(ttext,sizeof(ttext),fp2);
  758.         fprintf(fpout,"frame offset=%d param text: >%s< \n",off,ttext);
  759.        }
  760.    }  /* end of loop over all symbols */
  761.  
  762.   fclose(fp);
  763.   fclose(fp2);
  764.   fclose(fpout);
  765. } /* end of trb_symboldump */
  766.   
  767. /****************************************************************/
  768. /*    trb_stackdump                        */
  769. /*    dump the stack                        */
  770. /****************************************************************/
  771. static void trb_stackdump(start,nn,fp0)
  772. unsigned long start;
  773. int nn;
  774. FILE **fp0;
  775. {
  776.   int i,j;
  777.   FILE *fp;
  778. /*------------------------------------------------------*/
  779.   fp= *fp0;
  780.   if(fp==0)
  781.     {fp= fopen("STACKDUMP","a"); /* open for append */
  782.      if(fp==NULL) fp= stdout; /* if failure, use standard out */
  783.      *fp0= fp;                /* save it in case we have two crashes */
  784.     }
  785.   trb_userinfo(fp);
  786.   for (i=0; i<nn;i++)
  787.     {fprintf(fp,"%08x ", (long)start);
  788.      fprintf(fp,"%08x ", *(unsigned long *)(start));
  789.      for(j=0;j<4;j++,start++)
  790.        fprintf(fp,"%c",   isprint(*(unsigned char *)(start))
  791.              ? *(unsigned char *)(start) : ' ');
  792.      fprintf(fp,"\n");
  793.     }
  794.   fclose(fp);
  795. } /* end of trb_stackdump */
  796.  
  797. /****************************************************************/
  798. /*    trb_framedump                        */
  799. /*    dump a stack frame                    */
  800. /****************************************************************/
  801. static void trb_framedump(stackpointer,programcounter,frameend,fp0)
  802. unsigned long stackpointer,programcounter,frameend;
  803. FILE **fp0;
  804. {  
  805.   int j;
  806.   unsigned long stackaddress,stackvalue;
  807.   FILE *fp;
  808. /*------------------------------------------------------*/
  809.   fp= *fp0;
  810.   if(fp==0)
  811.     {fp= fopen("FRAMEDUMP","a"); 
  812.      if(fp==NULL) fp= stdout;
  813.      trb_userinfo(fp);
  814.      *fp0= fp;
  815.     }
  816.   fprintf(fp,"-----------------------------------\n");
  817.   fprintf(fp,"sp=%08x pc=%08x\n",stackpointer,programcounter);
  818.   j= 0;
  819.   stackaddress= stackpointer;
  820.   while(stackaddress<frameend)
  821.     {stackvalue= *( (long *)stackaddress);
  822.      fprintf(fp," %8x",stackvalue);
  823.      j++;
  824.      if(j==8) {fprintf(fp,"\n");j= 0;}
  825.      stackaddress= stackaddress+4;
  826.     }
  827.   if(j!=0)fprintf(fp,"\n");
  828.   fprintf(fp,"-----------------------------------\n");
  829. } /* end of trb_framedump */
  830.  
  831. /****************************************************************/
  832. /*    trb_getline                        */
  833. /*    find file lines matching addresses            */
  834. /****************************************************************/
  835. static void trb_getline(nlevel)
  836. int nlevel;
  837. {
  838.   FILE *fp,*fp2;
  839.   struct nlist symbol;    /* symbol table entry */
  840.   unsigned long address,match,lastaddress;
  841.   int type,line,funcsymbol,filesymbol;
  842.   int i,j,ll,status;
  843.   long fileaddr,funcaddr,magic;
  844.   int iff;
  845.   char *ptr,ttext[256];
  846.   char funcname[256],filename[256];
  847. /*----------------------*/
  848. /* initialize */
  849.   address= 0; funcsymbol= 0; filesymbol=0;
  850.   lastaddress= 0xFFFF;
  851.   for(i=0;i<MAXLEVEL;i++)level[i].found= 0;
  852.   DBPRINT(("trb_getline: nlevel=%d pc[0]=%x\n",nlevel,level[0].programcounter));
  853.  
  854. /* use first file pointer to read symbol table */
  855.   fp= fopen(exe.name,"r");
  856.   if(fp==NULL) {printf("can't open %s\n",exe.name);exit(1);}
  857. /* use second file pointer to read the string table */
  858.   fp2= fopen(exe.name,"r");
  859.   
  860. /* read all symbols, look at source lines, file & function names */
  861.   fseek(fp,exe.symoffset,0);
  862.   for(i=0;i<exe.nsym;i++)
  863.     {status= fread(&symbol,sizeof(symbol),1,fp);
  864.      if(status==0) printf("could not read symbol\n");
  865.      type= symbol.n_type;
  866. /* what type of symbol is it */
  867.      if(type==N_SLINE)        /* src line: 0,,0,linenumber,address */
  868.        {line= symbol.n_desc;
  869.         address= symbol.n_value;
  870.     DBPRINT(("line=%d address=%x\n",line,address));
  871.        }
  872.      else if(type==N_FUN)    /* procedure: name,,0,linenumber,address */
  873.        {funcaddr= symbol.n_un.n_strx;
  874.         address= symbol.n_value;
  875.         funcsymbol= i;
  876.         fseek(fp2,exe.stroffset,0);
  877.         fseek(fp2,funcaddr,1);
  878.         ptr= fgets(ttext,sizeof(ttext),fp2);
  879.         ptr= strtok(ttext,":");
  880.         ll= strlen(ptr);
  881.         if(ll>250){strncpy(funcname,ptr,250); funcname[250]= CNULL;}
  882.         else strcpy(funcname,ptr);
  883.         DBPRINT(("procedure %s address=%x\n",funcname,address));
  884.         for(iff=0;iff<nlevel;iff++) /* we matched address, now fill funcname */ 
  885.           if(strcmp(level[iff].funcname,"nextf")==0)
  886.             {strcpy(level[iff].funcname,funcname);
  887.              level[iff].funcsymbol= funcsymbol; /* symbol# of function name */
  888.             }
  889.        }
  890.      else if(type==N_SO)    /* source file name: name,,0,0,address */
  891.        {fileaddr= symbol.n_un.n_strx;
  892.         address= symbol.n_value;
  893.         filesymbol= i;
  894.         fseek(fp2,exe.stroffset,0);
  895.         fseek(fp2,fileaddr,1);
  896.         ptr= fgets(filename,sizeof(filename),fp2);
  897.         DBPRINT(("filename %s address=%x\n",filename,address));
  898.        }
  899.  
  900. /* does this address match one of ours? */
  901.      for(iff=0;iff<nlevel;iff++)
  902.        {if(level[iff].found==0)
  903.          {match= level[iff].programcounter;
  904.           if(address==match)
  905.             {DBPRINT(("exact match of %x found at line %d\n",match,line));
  906.              level[iff].found= 1;
  907.              level[iff].filesymbol= filesymbol;    /* store symbol# of the file */
  908.              strcpy(level[iff].funcname,"nextf");
  909.              strcpy(level[iff].filename,filename);
  910.              level[iff].line= line;
  911.             }
  912.           else if(address>match && lastaddress<match && lastaddress>(match-64))
  913.             {
  914.              DBPRINT(("match of %x before line %d, lastaddress=%x address=%x\n",
  915.              match,line,lastaddress,address));
  916.              level[iff].found= 1;
  917.              level[iff].filesymbol= filesymbol; /* store symbol# of the file */
  918.              strcpy(level[iff].funcname,"nextf");
  919.              strcpy(level[iff].filename,filename);
  920.              level[iff].line= line-1;
  921.             }
  922.          }
  923.        }
  924.     lastaddress= address;
  925.     } /* end of loop over all nsym */
  926.   fclose(fp2);
  927.   fclose(fp);
  928.       
  929. } /* end of trb_getline */
  930.  
  931. /****************************************************************/
  932. /*    trb_params                        */
  933. /*    print one level of parameters                */
  934. /****************************************************************/
  935. static void trb_params(ilevel,fp,fp2)
  936. int ilevel;
  937. FILE *fp, *fp2;
  938. {
  939.   int i,status,type;
  940.   int isym,code,pointer,array;
  941.   int size,middle,sum;
  942.   long addr,off,address,newaddress,stackbase,nseek,contents;
  943.   struct nlist symbol;    /* symbol table entry */
  944.   char *ptr,ttext[1024],symbolname[80],symboltype[80];
  945.   char params[1024],tempstring[1024],outtext[80];
  946.   int ii;
  947.   char cc;
  948.   short ss;
  949.   long ll,l2;
  950.   unsigned char uc;
  951.   unsigned short us;
  952.   unsigned long ul;
  953.   unsigned int ui;
  954.   float ff;
  955.   double dd;
  956.   long vv;
  957. /*------------------------------------*/
  958.   strcpy(params,level[ilevel].funcname);
  959.   strcat(params,"(");
  960.   isym= level[ilevel].funcsymbol+1;
  961.   nseek= exe.symoffset + isym*sizeof(symbol);
  962. /* do a quick loop to get parameter names */
  963.   fseek(fp,nseek,0);
  964.   for(i=isym;i<exe.nsym;i++)
  965.     {status= fread(&symbol,sizeof(symbol),1,fp);
  966.      if(status==0) printf("could not read symbol\n");
  967.      type= symbol.n_type;
  968.      if(type==N_FUN) break;     /* that is all for this function */ 
  969.      else if(type==N_SO) break; /* that is all for this function */
  970.      else if(type==N_PSYM)    /* parameter: name,,0,type,offset */
  971.        {addr= symbol.n_un.n_strx;   /* symbol name in string table */
  972.     fseek(fp2,exe.stroffset,0);
  973.         fseek(fp2,addr,1);
  974.         ptr= fgets(ttext,sizeof(ttext),fp2);
  975.     /* extract the symbol's name */
  976.     strcpy(tempstring,ttext);
  977.     str_whiteout(tempstring,":=;");
  978.     sscanf(tempstring,"%s",symbolname);
  979.     strcat(params,symbolname); strcat(params,",");
  980.        }
  981.     }
  982. /* change the last comma to an )  and print the parameters */
  983.   ll= strlen(params);
  984.   if(params[ll-1]==',') params[ll-1]= ')'; else strcat(params,")");
  985.   fprintf(fpcrash,"%s\n",params);
  986.   
  987.      
  988. /* do a second loop to get values */
  989.   fseek(fp,nseek,0);
  990.   for(i=isym;i<exe.nsym;i++)
  991.     {status= fread(&symbol,sizeof(symbol),1,fp);
  992.      if(status==0) printf("could not read symbol\n");
  993.      type= symbol.n_type;
  994.      if(type==N_FUN) break;     /* that is all for this function */    
  995.      else if(type==N_SO) break; /* that is all for this function */
  996.      else if(type!=N_PSYM)continue;
  997.      addr= symbol.n_un.n_strx;
  998.      off= symbol.n_value;   /* offset from stack frame end */
  999.      fseek(fp2,exe.stroffset,0);
  1000.      fseek(fp2,addr,1);
  1001.      ptr= fgets(ttext,sizeof(ttext),fp2);
  1002.      /* extract the symbol's name */
  1003.      strcpy(tempstring,ttext);
  1004.      str_whiteout(tempstring,":=;");
  1005.      sscanf(tempstring,"%s",symbolname);
  1006.      /* extract text we use to get the symbol's type */
  1007.      ptr= strchr(ttext,':');
  1008.      strcpy(symboltype,ptr);
  1009.      stackbase= level[ilevel].frameend;
  1010.      stackbase= level[ilevel].stackpointer;
  1011.      address= stackbase+off;    /* where the variable's bytes are */
  1012. /* find out what kind of symbol it is */
  1013.      trb_translate(ttext,&code,&pointer,&array);
  1014. #if PARAMDUMP
  1015.      printf("param: >%s< off=%d\n",ttext,off);
  1016.      trb_verbalize(symbolname,code,pointer,array);
  1017. #endif
  1018.  
  1019. /* if it is a pointer, print the address & dereference it */
  1020.      if(pointer==1)
  1021.        {newaddress= *(unsigned long *) address;
  1022.         fprintf(fpcrash,"  %s = 0x%x (pointer to %s) \n",
  1023.           symbolname, newaddress, description[code]);
  1024.         if(newaddress>=0 && newaddress<0x1000) continue;
  1025.         else address= newaddress;
  1026.        }
  1027.      else if(pointer==2)    /* it could be a pointer to a pointer */
  1028.        {newaddress= *(unsigned long *) address;
  1029.         fprintf(fpcrash,"  %s = 0x%x (pointer to *%s) \n",
  1030.           symbolname, newaddress, description[code]);
  1031.         if(newaddress>=0 && newaddress<0x1000) continue;
  1032.         else address= newaddress;
  1033.         newaddress= *(unsigned long *) address;
  1034.         if(newaddress>=0 && newaddress<0x1000) continue;
  1035.         else address= newaddress;
  1036.        }
  1037.  
  1038. /* treat a ptr to char as an array */
  1039.      if(pointer>0 && code==D_CHAR) goto arrays;  /* written by an ex- */
  1040.                          /* fortran programmer */
  1041. /* an array of any type */
  1042.      if(array>1) goto arrays;
  1043.  
  1044. /* int */
  1045.      else if(code==D_INT)
  1046.        {ii= *(int *)address;
  1047.         sprintf(outtext,"%d 0x%x (long)",ii,ii);}
  1048. /* char */
  1049.      else if(code==D_CHAR)
  1050.        {cc= *(char *)address;
  1051.         sprintf(outtext,"\'%c\' 0x%x (char)",cc,cc);}
  1052. /* long */
  1053.      else if(code==D_LONG)
  1054.        {ll= *(long *)address;
  1055.         sprintf(outtext,"%d 0x%x (long)",ll,ll);}
  1056. /* short */
  1057.      else if(code==D_SHORT)
  1058.        {ss= *(short *)address;
  1059.         sprintf(outtext,"%hd 0x%hx (short)",ss,ss);}
  1060. /* unsigned char */
  1061.      else if(code==D_UCHAR)
  1062.        {uc= *(unsigned char *)address;
  1063.         sprintf(outtext,"\'%c\' 0x%x (u char)",uc,uc);}
  1064. /* unsigned short */
  1065.      else if(code==D_USHORT)
  1066.        {us= *(unsigned short *)address;
  1067.         sprintf(outtext,"%hu 0x%hx (u short)",us,us);}
  1068. /* unsigned long */
  1069.      else if(code==D_ULONG)
  1070.        {ul= *(unsigned long *)address;
  1071.         sprintf(outtext,"%u 0x%x (u long)",ul,ul);}
  1072. /* unsigned int */
  1073.      else if(code==D_UINT)
  1074.        {ui= *(unsigned int *)address;
  1075.         sprintf(outtext,"%u 0x%x (u int)",ui,ui);}
  1076. /* float */
  1077.      else if(code==D_FLOAT)
  1078.        {ff= *(float *)address;
  1079.         ll= *(long *)address;
  1080.         sprintf(outtext,"%f 0x%08x (float)",ff,ll);}
  1081. /* double */
  1082.      else if(code==D_DOUBLE)
  1083.        {dd= *(double *)address;
  1084.         ll= *(long *)address;
  1085.         l2= *(long *)(address+sizeof(long));
  1086.         sprintf(outtext,"%f 0x%08x%08x (double)",dd,ll,l2);}
  1087. /* void */
  1088.      else if(code==D_VOID)
  1089.        {vv= *(long *)address;
  1090.         sprintf(outtext,"%d 0x%x (void)",vv,vv);}
  1091. /* ??? */
  1092.      else
  1093.        sprintf(outtext," unknown type ");
  1094.  
  1095.     
  1096.      if(pointer==0)fprintf(fpcrash,"  %s = %s \n",symbolname,outtext);
  1097.      else if(pointer==1)fprintf(fpcrash,"  *%s = %s \n",symbolname,outtext);
  1098.      else if(pointer==2)fprintf(fpcrash,"  **%s = %s \n",symbolname,outtext);
  1099.      continue;
  1100.     
  1101. /*---------*/
  1102. arrays:
  1103. /*---------*/
  1104.      size= array-1;
  1105.      middle= array/2;
  1106. /* int or long array */
  1107.      if(code==D_INT || code==D_LONG)
  1108.        {fprintf(fpcrash,"  %s = an array of type %s \n",
  1109.             symbolname,description[code]);
  1110.         ii= *(int *)address;
  1111.         fprintf(fpcrash,"    %s[0] = %d 0x%x \n", symbolname,ii,ii);
  1112.         ii= *(int *) (address+middle*sizeof(int));
  1113.         fprintf(fpcrash,"    %s[%d] = %d 0x%x \n", symbolname,middle,ii,ii);
  1114.         ii= *(int *) (address+size*sizeof(int));
  1115.         fprintf(fpcrash,"    %s[%d] = %d 0x%x \n", symbolname,size,ii,ii);
  1116.        }
  1117. /* char array */
  1118.      else if(code==D_CHAR)
  1119.        {sum=pointer;
  1120.         if(array>1)sum++;
  1121.         else if(sum==1)
  1122.           fprintf(fpcrash,"  *%s = \"%s\"\n",symbolname,address);
  1123.         else if(sum==2)
  1124.           fprintf(fpcrash,"  *%s = \"%s\"\n",symbolname,address);
  1125.        }
  1126.        
  1127. /* float array */
  1128.      else if(code==D_FLOAT)
  1129.        {fprintf(fpcrash,"  %s = an array of type %s \n",
  1130.             symbolname,description[code]);
  1131.         ff= *(float *)address;
  1132.         fprintf(fpcrash,"    %s[0] = %f 0x%x \n", symbolname,ff,ff);
  1133.         ff= *(float *) (address+middle*sizeof(float));
  1134.         fprintf(fpcrash,"    %s[%d] = %f 0x%x \n", symbolname,middle,ff,ff);
  1135.         ff= *(float *) (address+size*sizeof(float));
  1136.         fprintf(fpcrash,"    %s[%d] = %f 0x%x \n", symbolname,size,ff,ff);
  1137.        }
  1138. /* need to put in other types of arrays */
  1139.  
  1140.     } /* end of loop over all nsym */
  1141.     
  1142. } /* end of trb_params */
  1143.  
  1144. /****************************************************************/
  1145. /*    trb_symbols                        */
  1146. /*    print local symbols in procedure of interest        */
  1147. /****************************************************************/
  1148. static void trb_symbols(ilevel,fp,fp2)
  1149. int ilevel;
  1150. FILE *fp, *fp2;
  1151. {
  1152.   int i,type,status,isym;
  1153.   int code,pointer,array,middle,size;
  1154.   long addr,off,address,newaddress,stackbase;
  1155.   unsigned long value;
  1156.   long nseek;
  1157.   struct nlist symbol;    /* symbol table entry */
  1158.   char *ptr,ttext[1024],tempstring[1024];
  1159.   char symbolname[80],symboltype[80];
  1160.   short int jtemp;  unsigned short jtemp2;
  1161.   char outtext[80];
  1162.   int ii;
  1163.   char cc;
  1164.   short ss;
  1165.   long ll,l2;
  1166.   unsigned char uc;
  1167.   unsigned short us;
  1168.   unsigned long ul;
  1169.   unsigned int ui;
  1170.   float ff;
  1171.   double dd;
  1172.   long vv;
  1173. /*-----------------------------------*/
  1174.   isym= level[ilevel].funcsymbol+1;
  1175.   nseek= exe.symoffset + isym*sizeof(symbol);
  1176.   fseek(fp,nseek,0);
  1177.   stackbase= level[ilevel].stackpointer;
  1178.   for(i=isym;i<exe.nsym;i++)
  1179.     {status= fread(&symbol,sizeof(symbol),1,fp);
  1180.      if(status==0) printf("could not read symbol\n");
  1181.      type= symbol.n_type;
  1182.      if(type==N_FUN) return;            /* new function */
  1183.      else if(type==N_SO) return;        /* new source file */
  1184.      else if(type!=N_LSYM) continue;    /* local sym: name,,0,type,offset */
  1185.      addr= symbol.n_un.n_strx;          /* pointer to string table */
  1186.      off= symbol.n_value;               /* offset from stack frame end */
  1187.      fseek(fp2,exe.stroffset,0);
  1188.      fseek(fp2,addr,1);
  1189.      ptr= fgets(ttext,sizeof(ttext),fp2);
  1190.      /* get the symbol's name */
  1191.      strcpy(tempstring,ttext);
  1192.      str_whiteout(tempstring,":=;");
  1193.      sscanf(tempstring,"%s",symbolname);
  1194.      /* get text used to find type of symbol */
  1195.      ptr= strchr(ttext,':');
  1196.      strcpy(symboltype,ptr);
  1197.      address= stackbase+off;
  1198. /* find out what kind of symbol it is */
  1199.      trb_translate(ttext,&code,&pointer,&array);
  1200. #if SYMBOLDUMP
  1201.      printf("symbol: >%s< off=%d\n",ttext,off);
  1202.      trb_verbalize(symbolname,code,pointer,array);
  1203. #endif
  1204. /* if it is a pointer, print the address & dereference it */
  1205.      if(pointer==1)
  1206.        {newaddress= *(unsigned long *) address;
  1207.         fprintf(fpcrash,"  %s = 0x%x (pointer to %s) \n",
  1208.           symbolname, newaddress, description[code]);
  1209.         if(newaddress>=0 && newaddress<0x1000) continue;
  1210.         else address= newaddress;
  1211.        }
  1212.      else if(pointer==2)   /* could have pointer to pointer */
  1213.        {newaddress= *(unsigned long *) address;
  1214.         fprintf(fpcrash,"  %s = 0x%x (pointer to *%s) \n",
  1215.           symbolname, newaddress, description[code]);
  1216.         if(newaddress>=0 && newaddress<0x1000) continue;
  1217.         else address= newaddress;
  1218.         newaddress= *(unsigned long *) address;
  1219.         if(newaddress>=0 && newaddress<0x1000) continue;
  1220.         else address= newaddress;
  1221.        }
  1222.     
  1223. /* treat a ptr to char as an array */
  1224.      if(pointer>0 && code==D_CHAR) goto arrays;
  1225.  
  1226. /* an array of any type */
  1227.      if(array>1) goto arrays;
  1228.      
  1229. /* int */
  1230.      else if(code==D_INT)
  1231.        {ii= *(int *)address;
  1232.         sprintf(outtext,"%d 0x%x (long)",ii,ii);}
  1233. /* char */
  1234.      else if(code==D_CHAR)
  1235.        {cc= *(char *)address;
  1236.         sprintf(outtext,"\'%c\' 0x%x (char)",cc,cc);}
  1237. /* long */
  1238.      else if(code==D_LONG)
  1239.        {ll= *(long *)address;
  1240.         sprintf(outtext,"%ld 0x%x (long)",ll,ll);}
  1241. /* short */
  1242.      else if(code==D_SHORT)
  1243.        {ss= *(short *)address;
  1244.         sprintf(outtext,"%hd 0x%hx (short)",ss,ss);}
  1245. /* unsigned char */
  1246.      else if(code==D_UCHAR)
  1247.        {uc= *(unsigned char *)address;
  1248.         sprintf(outtext,"\'%c\' 0x%x (u char)",uc,uc);}
  1249. /* unsigned short */
  1250.      else if(code==D_USHORT)
  1251.        {us= *(unsigned short *)address;
  1252.         sprintf(outtext,"%hu 0x%hx (u short)",us,us);}
  1253. /* unsigned long */
  1254.      else if(code==D_ULONG)
  1255.        {ul= *(unsigned long *)address;
  1256.         sprintf(outtext,"%u 0x%x (u long)",ul,ul);}
  1257. /* unsigned int */
  1258.      else if(code==D_UINT)
  1259.        {ui= *(unsigned int *)address;
  1260.         sprintf(outtext,"%u 0x%x (u int)",ui,ui);}
  1261. /* float */
  1262.      else if(code==D_FLOAT)
  1263.        {ff= *(float *)address;
  1264.         ll= *(long *)address;
  1265.         sprintf(outtext,"%f 0x%08x (float)",ff,ll);}
  1266. /* double */
  1267.      else if(code==D_DOUBLE)
  1268.        {dd= *(double *)address;
  1269.         ll= *(long *)address;
  1270.         l2= *(long *)(address+sizeof(long));
  1271.         sprintf(outtext,"%f 0x%08x%08x (double)",dd,ll,l2);}
  1272. /* void */
  1273.      else if(code==D_VOID)
  1274.        {vv= *(long *)address;
  1275.         sprintf(outtext,"%d 0x%x (void)",vv,vv);}
  1276. /* ??? */
  1277.      else
  1278.        sprintf(outtext," unknown type ");
  1279.     
  1280.  
  1281.      if(pointer==0)fprintf(fpcrash,"  %s = %s \n",symbolname,outtext);
  1282.      else if(pointer==1)fprintf(fpcrash,"  *%s = %s \n",symbolname,outtext);
  1283.      continue;
  1284. /*---------*/
  1285. arrays:
  1286. /*---------*/
  1287.      size= array-1;
  1288.      middle= array/2;
  1289. /* int or long array */
  1290.      if(code==D_INT || code==D_LONG)
  1291.        {fprintf(fpcrash,"  %s = an array of type %s \n",
  1292.             symbolname,description[code]);
  1293.         ii= *(int *)address;
  1294.         fprintf(fpcrash,"    %s[0] = %d 0x%x \n", symbolname,ii,ii);
  1295.         ii= *(int *) (address+middle*sizeof(int));
  1296.         fprintf(fpcrash,"    %s[%d] = %d 0x%x \n", symbolname,middle,ii,ii);
  1297.         ii= *(int *) (address+size*sizeof(int));
  1298.         fprintf(fpcrash,"    %s[%d] = %d 0x%x \n", symbolname,size,ii,ii);
  1299.        }
  1300. /* char array */
  1301.      else if(code==D_CHAR)
  1302.        fprintf(fpcrash,"  %s = \"%s\" \n",symbolname,address);
  1303. /* float array */
  1304.      else if(code==D_FLOAT)
  1305.        {fprintf(fpcrash,"  %s = an array of type %s \n",
  1306.             symbolname,description[code]);
  1307.         ff= *(float *)address;
  1308.         ll= *(long *)address;
  1309.         fprintf(fpcrash,"    %s[0] = %f 0x%x \n", symbolname,ff,ll);
  1310.         ff= *(float *) (address+middle*sizeof(float));
  1311.         ll= *(long *) (address+middle*sizeof(float));
  1312.         fprintf(fpcrash,"    %s[%d] = %f 0x%x \n", symbolname,middle,ff,ll);
  1313.         ff= *(float *) (address+size*sizeof(float));
  1314.         ll= *(long *) (address+size*sizeof(float));
  1315.         fprintf(fpcrash,"    %s[%d] = %f 0x%x \n", symbolname,size,ff,ll);
  1316.        }
  1317. /* dump other kinds of arrays */
  1318.  
  1319.     } /* end of loop over all nsym */
  1320.  
  1321. } /* end of trb_symbols */
  1322.  
  1323. /****************************************************************/
  1324. /*    trb_traceback                        */
  1325. /*    print a traceback                     */
  1326. /****************************************************************/
  1327. static void trb_traceback(nlevel)
  1328. int nlevel;
  1329. {
  1330.   int i;
  1331.   FILE *fp,*fp2;
  1332. /*---------------------------*/
  1333.   if(nlevel<1)return;
  1334. /* use first file pointer to read the symbol table */
  1335.   fp= fopen(exe.name,"r");
  1336.   if(fp==NULL) {printf("can't open %s\n",exe.name);exit(1);}
  1337. /* use second file pointer to read the string table */
  1338.   fp2= fopen(exe.name,"r");
  1339.  
  1340. /* print a traceback to the screen */
  1341.   fprintf(fpcrash,"---------- traceback ----------\n");
  1342.   for(i=0;i<nlevel;i++)
  1343.     if(level[i].found!=0)fprintf(fpcrash,"file %s line %d function %s() \n",
  1344.        level[i].filename, level[i].line, level[i].funcname);
  1345.      else
  1346.        fprintf(fpcrash,"address %x \n", level[i].programcounter);
  1347.  
  1348.   for(i=0;i<nlevel;i++)
  1349.     {
  1350.      fprintf(fpcrash,"------------------------------------\n");
  1351.      if(level[i].found!=0)
  1352.        {
  1353.         trb_dictionary(i,fp,fp2);
  1354.         trb_params(i,fp,fp2);
  1355.         fprintf(fpcrash,"  -- local symbols for %s --\n",level[i].funcname);
  1356.         trb_symbols(i,fp,fp2);
  1357.        }
  1358.     }
  1359.   
  1360.   fclose(fp2);
  1361.   fclose(fp);
  1362.        
  1363. } /* end of trb_traceback */
  1364.  
  1365. /****************************************************************/
  1366. /*    trb_userinfo                        */
  1367. /*    put program name, user, etc into a file            */
  1368. /****************************************************************/
  1369. void trb_userinfo(fp)
  1370. FILE *fp;
  1371. {
  1372.   int ll;
  1373.   char *user,host[64],nouser[8];
  1374.   time_t timeofday;
  1375.   char fulltime[26];
  1376. /* get the user's name */
  1377.   user= (char *) getlogin();
  1378.   if(user==NULL)user= (char *)getpwuid(getuid());
  1379.   if(user==NULL){strcpy(nouser,"????"); user=nouser; }
  1380.   
  1381. /* get the time */
  1382.   timeofday=time((time_t *)0);
  1383.   strcpy(fulltime,(char *)ctime(&timeofday));
  1384.   fulltime[24]=CNULL;
  1385. /* get the host */
  1386.   gethostname(host,64);
  1387. /* write to a file */
  1388.   fprintf(fp,"user=%s host=%s date=%s \n", user,host,fulltime);
  1389.   fprintf(fp,"program=%s \n", exe.name);
  1390. } /* end of trb_userinfo */
  1391.  
  1392. /****************************************************************/
  1393. /*    trb_handle                        */
  1394. /*    handle all signals                    */
  1395. /****************************************************************/
  1396. void trb_handle(sig,code,scp)
  1397. int sig, code;
  1398. struct sigcontext *scp;
  1399. {
  1400.   int i,j,exitflag;
  1401.   int nlevel;
  1402.   unsigned long programcounter,stackpointer,frameend;
  1403.   unsigned long instruction;
  1404.   char *ptr;
  1405.   char *startdump;
  1406. /*--------------------*/
  1407. /* write to a file called CRASH */
  1408.   if(fpcrash==0) fpcrash= fopen("CRASH","a");    /* open for append */
  1409.   if(fpcrash==NULL) fpcrash= stdout;     /* if failure, use standard output */
  1410.   fprintf(fpcrash,"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
  1411.   trb_userinfo(fpcrash);
  1412. /* print meaningful message for signal */
  1413.   fprintf(fpcrash,"%s signal=%d(%d) \n",sigtext[sig],sig,code);
  1414.   ptr= trb_codetext(sig,code);
  1415.   if(ptr!=NULL) fprintf(fpcrash,"%s\n",ptr);
  1416. /* get stack pointer & program counter */
  1417.   programcounter= scp->sc_pc;
  1418.   stackpointer= scp->sc_fp;
  1419.   frameend= *( (long *)stackpointer +JUMPSP);
  1420.   DBPRINT((" pc=0x%x sp=0x%x \n", programcounter,stackpointer));
  1421.  
  1422. #if STACKDUMP
  1423.   startdump= (char *)scp->sc_sp;
  1424.   startdump= startdump-128;
  1425.   trb_stackdump(startdump,DUMPSIZE,&fpstackdump);
  1426. #endif
  1427.  
  1428. /* walk the stack, storing stack pointers & program counters */
  1429.   nlevel= 0;
  1430.   while(stackpointer!=0)
  1431.     {level[nlevel].programcounter= programcounter;
  1432.      level[nlevel].frameend= frameend;
  1433.      level[nlevel].stackpointer= stackpointer;
  1434.      if(nlevel<MAXLEVEL)nlevel++;
  1435.      DBPRINT(("sp=%08x pc=%08x\n",stackpointer,programcounter));
  1436. #if FRAMEDUMP
  1437.      trb_framedump(stackpointer,programcounter,frameend,&fpframedump);
  1438. #endif
  1439.      programcounter= *( (long *)stackpointer +JUMPPC);
  1440.      stackpointer= *( (long *)stackpointer +JUMPSP);
  1441.      if(stackpointer!=0) frameend= *( (long *)stackpointer +JUMPSP);
  1442.      if(frameend==0) stackpointer= 0; /* we are at the end */
  1443.     }
  1444.  
  1445.   trb_exeinfo();        /* get info from file header */
  1446.   trb_getline(nlevel);        /* convert addresses to line numbers */
  1447.   trb_traceback(nlevel);    /* print a full traceback */
  1448. #if SYMBOLDUMP
  1449.   trb_symboldump();
  1450. #endif
  1451.  
  1452.   exitflag= 0;
  1453.   switch(sig)
  1454.     {case SIGTRAP:        exitflag= 1;    break;
  1455.      case SIGSEGV:        exitflag= 1;    break; 
  1456.      case SIGABRT:        exitflag= 1;    break;
  1457.      case SIGBUS:        exitflag= 1;    break;
  1458.      case SIGILL:        exitflag= 1;    break;
  1459.      case SIGFPE:               exitflag= 1;    break;
  1460.      default:            
  1461.        printf("signal %d sent to trb_handle \n",sig);
  1462.        break;
  1463.     } /* end of switch on sig */
  1464.   fprintf(fpcrash,"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
  1465. #if FRAMEDUMP
  1466.   fclose(fpframedump);
  1467. #endif
  1468.   if(exitflag) 
  1469.     {if(fpcrash!=stdout) {fclose(fpcrash); system("ls -l CRASH");}
  1470.      exit(sig);
  1471.     }
  1472.   return;
  1473. } /* end of trb_handle */
  1474.  
  1475. /****************************************************************/
  1476. /*    trb_sigtextinit                        */
  1477. /*    initialize signal text messages                */
  1478. /****************************************************************/
  1479. static void trb_sigtextinit()
  1480. {
  1481.   strcpy(sigtext[1],  "SIGHUP:  hangup signal received");
  1482.   strcpy(sigtext[2],  "SIGINT:  interrupt signal received");
  1483.   strcpy(sigtext[3],  "SIGQUIT: quit signal received");
  1484.   strcpy(sigtext[4],  "SIGILL:  illegal instruction (not reset when caught)");
  1485.   strcpy(sigtext[5],  "SIGTRAP: trace trap (not reset when caught)");
  1486.   strcpy(sigtext[6],  "SIGABRT: abort or IOT instruction");
  1487.   strcpy(sigtext[7],  "SIGEMT:  EMT instruction");
  1488.   strcpy(sigtext[8],  "SIGFPE:  floating point exception");
  1489.   strcpy(sigtext[9],  "SIGKILL: kill signal received");
  1490.   strcpy(sigtext[10],  "SIGBUS:  bus error");
  1491.   strcpy(sigtext[11], "SIGSEGV: segmentation violation");
  1492.   strcpy(sigtext[12], "SIGSYS:  bad argument to system call");
  1493.   strcpy(sigtext[13], "SIGPIPE: write on a pipe with no one to read it");
  1494.   strcpy(sigtext[14], "SIGALRM: alarm clock signal received");
  1495.   strcpy(sigtext[15], "SIGTERM: received software termination signal");
  1496.   strcpy(sigtext[16], "SIGURG:  urgent condition on IO channel");
  1497.   strcpy(sigtext[17], "SIGSTOP: sendable stop signal not from tty");
  1498.   strcpy(sigtext[18], "SIGTSTP: received stop signal from tty");
  1499.   strcpy(sigtext[19], "SIGCONT: continue a stopped process");
  1500.   strcpy(sigtext[20], "SIGCHLD: child process has stopped or exited");
  1501.   strcpy(sigtext[21], "SIGTTIN: to readers pgrp upon background tty read");
  1502.   strcpy(sigtext[22], "SIGTTOU: like TTIN for output if (tp->t_local<OSTOP)");
  1503.   strcpy(sigtext[23], "SIGIO:   input/output possible signal");
  1504.   strcpy(sigtext[24], "SIGXCPU: exceeded CPU time limit");
  1505.   strcpy(sigtext[25], "SIGXFSZ: exceeded file size limit");
  1506.   strcpy(sigtext[26], "SIGVTALRM: received virtual time alarm");
  1507.   strcpy(sigtext[27], "SIGPROF: received profiling time alarm");
  1508.   strcpy(sigtext[28], "SIGWINCH: window changed");
  1509.   strcpy(sigtext[29], "SIGLOST: resource lost (eg, record-lock lost)");
  1510.   strcpy(sigtext[30], "SIGUSR1: received user defined signal 1");
  1511.   strcpy(sigtext[31], "SIGUSR2: received user defined signal 2");
  1512. } /* end if trb_sigtextinit */
  1513.  
  1514. /****************************************************************/
  1515. /*    trb_codetext                        */
  1516. /*    return text explanation of signal            */
  1517. /****************************************************************/
  1518. static char *trb_codetext(sig,code)
  1519. int sig,code;
  1520. {
  1521.   if(sig==SIGILL)
  1522.      return("illegal instruction fault");
  1523.     
  1524.   else if(sig==SIGFPE)
  1525.      {if(code==0)return("float divide by zero or overflow");
  1526.       else if(code==2)return("integer divide by zero");
  1527.       else return("misc floating point error");
  1528.      }
  1529.     
  1530.   else if(sig==SIGBUS)
  1531.      return("hardware alignment error");
  1532.     
  1533.   else if(sig==SIGSEGV)
  1534.      return("no mapping at the fault address");
  1535.     
  1536.   else
  1537.     return(NULL);
  1538. } /* end of trb_codetext */
  1539.  
  1540. /****************************************************************/
  1541. /*    trb_signal                        */
  1542. /*    initiate trapping of all signals            */
  1543. /****************************************************************/
  1544. static void trb_signal()
  1545. {
  1546.   int status;
  1547. /*---------------------------------------*/
  1548.   trb_sigtextinit();
  1549. /* trap the important signals */
  1550. /*  signal(SIGILL,trb_handle);  
  1551.   signal(SIGTRAP,trb_handle); */
  1552.   signal(SIGFPE,trb_handle);      /* floating point errors */
  1553.   signal(SIGBUS,trb_handle);      /* bus errors */
  1554.   signal(SIGSEGV,trb_handle);     /* segmentation faults */
  1555.   signal(SIGABRT,trb_handle);      /* to get integer divide */
  1556. /* don't trap the rest */
  1557. #if 0
  1558.   signal(SIGHUP,trb_handle);  
  1559.   signal(SIGINT,trb_handle);  
  1560.   signal(SIGQUIT,trb_handle); 
  1561.   signal(SIGEMT,trb_handle);  
  1562.   signal(SIGKILL,trb_handle);
  1563.   signal(SIGSYS,trb_handle);  
  1564.   signal(SIGPIPE,trb_handle); 
  1565.   signal(SIGALRM,trb_handle); 
  1566.   signal(SIGTERM,trb_handle); 
  1567.   signal(SIGURG,trb_handle);  
  1568.   signal(SIGSTOP,trb_handle); 
  1569.   signal(SIGTSTP,trb_handle); 
  1570.   signal(SIGCONT,trb_handle); 
  1571.   signal(SIGCHLD,trb_handle); 
  1572.   signal(SIGTTIN,trb_handle); 
  1573.   signal(SIGTTOU,trb_handle); 
  1574.   signal(SIGIO,trb_handle);   
  1575.   signal(SIGXCPU,trb_handle); 
  1576.   signal(SIGXFSZ,trb_handle); 
  1577.   signal(SIGVTALRM,trb_handle); 
  1578.   signal(SIGPROF,trb_handle); 
  1579.   signal(SIGWINCH,trb_handle); 
  1580.   signal(SIGLOST,trb_handle); 
  1581.   signal(SIGUSR1,trb_handle);
  1582.   signal(SIGUSR2,trb_handle);
  1583. #endif
  1584. } /* end of trb_signal */
  1585.  
  1586. /****************************************************************/
  1587. /*    trb_signalinit                        */
  1588. /*    initiate trapping of all signals            */
  1589. /****************************************************************/
  1590. void trb_signalinit(argc,argv)
  1591. int argc;
  1592. char *argv[];
  1593. {
  1594.   FILE *fp;
  1595. /*---------------------------------------*/
  1596. /* find the executable file */
  1597.   trb_exefind(argc,argv);
  1598. /* remove files CRASH, STACKDUMP, & FRAMEDUMP */
  1599.   unlink("./CRASH");
  1600.   unlink("./STACKDUMP");
  1601.   unlink("./FRAMEDUMP");
  1602.   fpcrash= 0;
  1603.   fpstackdump= 0;  
  1604.   fpframedump= 0;  
  1605. /* set up our signal handler */
  1606.   trb_signal();
  1607. } /* end of ita_signalinit */
  1608.  
  1609.  
  1610. /**************************************************************/
  1611. /*    str_getdelimited                                      */
  1612. /*    returns substring bounded by 2 characters          */
  1613. /**************************************************************/
  1614. static void str_getdelimited(intext,bounds,outtext)
  1615. char *intext,*bounds,*outtext;
  1616. {
  1617.   int ll;
  1618.   char start, end;
  1619.   char *ptr, *ptr2;
  1620. /*------------------------------------------------------*/
  1621.   outtext[0]=CNULL;
  1622.   start= bounds[0];
  1623.   end= bounds[1];  
  1624.   ptr=strchr(intext,start);
  1625.   if(ptr==NULL)return;
  1626.   ptr++;
  1627.   ptr2=strchr(ptr,end);
  1628.   if(ptr2==NULL)return;
  1629.   ll=ptr2-ptr;
  1630.   strncpy(outtext,ptr,ll);
  1631.   outtext[ll]=CNULL;
  1632. }
  1633.  
  1634. /********************************************************/
  1635. /*    str_whiteout                    */
  1636. /*    routine to change certain characters to blanks     */
  1637. /********************************************************/
  1638. static void str_whiteout(string,chars)
  1639. char *string,*chars;
  1640. {
  1641. /*... locals */
  1642.   int i,j,ls,lc;
  1643.   char cc;
  1644. /*-----------------------------*/
  1645.   ls=strlen(string);
  1646.   if(ls<1)return;
  1647.   lc=strlen(chars);
  1648.   if(lc<1)return;
  1649.   for(i=0;i<ls;i++)
  1650.     {cc=string[i];
  1651.      for(j=0;j<lc;j++)if(cc==chars[j])cc=' ';
  1652.      string[i]=cc;
  1653.     }
  1654. } /* end of str_whiteout */
  1655.   
  1656. /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
  1657.  
  1658.   Alan Dunham          |     /\    /\     |   Calgary ... 
  1659.   adunham@ita.lgc.com  |    /  \  /  \    |       home of Big Rock beer
  1660.   (403) 269 4669       |   /    \/    \   |      
  1661.   Calgary, Alberta     |  /     /      \  |  
  1662.