home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / STKTRACE.C < prev    next >
C/C++ Source or Header  |  1992-05-19  |  5KB  |  253 lines

  1. /* This file contains code to print function/arg stack tracebacks
  2.  * at run time, which is extremely useful for finding heap free() errors.
  3.  *
  4.  * This code is highly specific to Borland C and the 80x6 machines.
  5.  *
  6.  * April 10, 1992 P. Karn
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <dos.h>
  12. #include <string.h>
  13. #include <time.h>
  14. #include "global.h"
  15. #include "proc.h"
  16.  
  17. struct symtab {
  18.     struct symtab *next;
  19.     unsigned short seg;
  20.     unsigned short offs;
  21.     char *name;
  22. };
  23. static struct symtab *Symtab;
  24. static void rdsymtab __ARGS((int unused,void *name,void *p));
  25. static void clrsymtab __ARGS((void));
  26. static struct symtab *findsym __ARGS((void (*)()));
  27. static int scompare();
  28. static void paddr __ARGS((void (*pc)()));
  29.  
  30. static unsigned short Codeseg;
  31.  
  32. void
  33. stktrace()
  34. {
  35.     int i,j;
  36.     unsigned short far *context;
  37.     unsigned short far *cnext;
  38.     unsigned short far *ctmp;
  39.     void (*pc)();
  40.     int nargs;
  41.     struct proc *rdproc;
  42.     struct symtab *sp;
  43.     extern char **_argv;
  44.     char *mapname;
  45.     char *cp;
  46.     FILE *fp,*outsave;
  47.     time_t t;
  48.  
  49.     /* Temporarily redirect stdout to file */
  50.     if((fp = fopen("stktrace.out","at")) == NULLFILE)
  51.         return;    /* Give up */
  52.     outsave = Curproc->output;
  53.     Curproc->output = fp;
  54.  
  55.     time(&t);
  56.     printf("stktrace from proc %s at %s",Curproc->name,ctime(&t));
  57.     Codeseg = _psp + 0x10;
  58. #ifdef    notdef
  59.     printf("Code base segment: %x\n",Codeseg);
  60. #endif
  61.     /* Construct name of map file */
  62.     mapname = malloc(strlen(_argv[0]) + 5);
  63.     strcpy(mapname,_argv[0]);
  64.     if((cp = strrchr(mapname,'.')) != NULLCHAR)
  65.         *cp = '\0';
  66.     strcat(mapname,".map");
  67.  
  68.     /* Read the symbol table in another process to avoid overstressing
  69.      * the stack in this one
  70.      */
  71.     rdproc = newproc("rdsymtab",512,rdsymtab,1,mapname,NULL,0);
  72.     pwait(rdproc);
  73.     free(mapname);
  74.  
  75.     context = MK_FP(_SS,_BP);
  76.     pc = stktrace;
  77.  
  78.     for(i=0;i<20;i++){
  79.         paddr(pc);
  80.         sp = findsym(pc);
  81.         if(sp != NULL)
  82.             printf(" %s+%x",sp->name,FP_OFF(pc) - sp->offs);
  83.  
  84.         if(FP_OFF(context) == 0){
  85.             /* No context left, we're done */
  86.             putchar('\n');
  87.             break;
  88.         }
  89.         cnext = MK_FP(FP_SEG(context),*context);
  90.         /* Compute number of args to display */
  91.         if(FP_OFF(cnext) != 0){
  92.             nargs = cnext - context - (1 + sizeof(pc)/2);
  93.             if(nargs > 20)
  94.                 nargs = 20; /* limit to reasonable number */
  95.         } else {
  96.             /* No higher level context, so just print an
  97.              * arbitrary fixed number of args
  98.              */
  99.             nargs = 6;
  100.         }        
  101.         /* Args start after saved BP and return address */
  102.         ctmp = context + 1 + sizeof(pc)/2;
  103.         printf("(");
  104.         for(j=0;j<nargs;j++){
  105.             fprintf(fp,"%x",*ctmp);
  106.             if(j < nargs-1)
  107.                 putchar(' ');
  108.             else
  109.                 break;
  110.             ctmp++;
  111.         }
  112.         printf(")\n");
  113. #ifdef    notdef
  114.         if(strcmp(cp,"_main") == 0)
  115.             break;
  116. #endif
  117.  
  118. #ifdef    LARGECODE
  119.         pc = MK_FP(context[2],context[1]);
  120. #else
  121.         pc = (void (*)())MK_FP(FP_SEG(pc),context[1]);
  122. #endif
  123.         context = cnext;
  124.     }
  125.     clrsymtab();
  126.     fclose(fp);
  127.     Curproc->output = outsave;
  128. }
  129. static struct symtab *
  130. findsym(pc)
  131. void (*pc)();
  132. {
  133.     struct symtab *sp,*spprev;
  134.     unsigned short seg,offs;
  135.     
  136. #ifdef    LARGECODE
  137.     seg = FP_SEG(pc) - Codeseg;
  138. #else
  139.     seg = 0;    /* Small code, no segment */
  140. #endif
  141.     offs = FP_OFF(pc);
  142.     spprev = NULL;
  143.     for(sp = Symtab;sp != NULL;spprev = sp,sp = sp->next){
  144.         if(sp->seg > seg || (sp->seg == seg && sp->offs > offs)){
  145.             break;
  146.         }
  147.     }
  148.     return spprev;
  149. }
  150. static void
  151. clrsymtab()
  152. {
  153.     struct symtab *sp,*spnext;
  154.  
  155.     for(sp = Symtab;sp != NULL;sp = spnext){
  156.         spnext = sp->next;
  157.         free(sp->name);
  158.         free(sp);
  159.     }
  160.     Symtab = NULL;
  161. }
  162. static void
  163. rdsymtab(unused,name,p)
  164. int unused;
  165. void *name;
  166. void *p;
  167. {
  168.     char *buf;
  169.     FILE *fp;
  170.     unsigned short seg;
  171.     unsigned short offs;
  172.     struct symtab *sp;
  173.     struct symtab **spp;
  174.     int size = 0;
  175.     int i;
  176.  
  177.     if((fp = fopen(name,"rt")) == NULL){
  178.         printf("can't read %s\n",name);
  179.         return;
  180.     }
  181.     buf = (char *)malloc(128);
  182.     while(fgets(buf,128,fp),!feof(fp)){
  183.         rip(buf);
  184.         if(strcmp(buf,"  Address         Publics by Value") == 0)
  185.             break;
  186.     }
  187.     if(feof(fp)){
  188.         printf("Can't find header line in %s\n",name);
  189.         free(buf);
  190.         return;
  191.     }
  192.     Symtab = NULL;
  193.     while(fgets(buf,128,fp),!feof(fp)){
  194.         rip(buf);
  195.         if(sscanf(buf,"%x:%x",&seg,&offs) != 2)
  196.             continue;
  197.         sp = (struct symtab *)malloc(sizeof(struct symtab));
  198.         sp->offs = offs;
  199.         sp->seg = seg;
  200.         sp->name = strdup(buf+17);
  201.         sp->next = Symtab;
  202.         Symtab = sp;
  203.         size++;
  204.     }
  205.     fclose(fp);
  206.     free(buf);
  207. #ifdef    notdef
  208.     printf("Symbols read: %d\n",size);
  209. #endif
  210.     /* Sort the symbols using the quicksort library function */
  211.     spp = malloc(size*sizeof(struct symtab *));
  212.     for(i=0,sp = Symtab;sp != NULL;i++,sp = sp->next)
  213.         spp[i] = sp;
  214.     qsort(spp,size,sizeof(struct symtab *),scompare);
  215.     /* Now put them back in the linked list */
  216.     Symtab = NULL;
  217.     for(i=size-1;i >= 0;i--){
  218.         sp = spp[i];
  219.         sp->next = Symtab;
  220.         Symtab = sp;
  221.     }
  222.     free(spp);
  223. #ifdef    notdef
  224.     for(sp = Symtab;sp != NULL;sp = sp->next)
  225.         printf("%x:%x    %s\n",sp->seg,sp->offs,sp->name);
  226. #endif
  227. }
  228. static int
  229. scompare(a,b)
  230. struct symtab **a,**b;
  231. {
  232.     if((*a)->seg > (*b)->seg)
  233.         return 1;
  234.     if((*a)->seg < (*b)->seg)
  235.         return -1;
  236.     if((*a)->offs > (*b)->offs)
  237.         return 1;
  238.     if((*a)->offs < (*b)->offs)
  239.         return -1;
  240.     return 0;
  241. }
  242. /* Print a code address according to the memory model */
  243. static void
  244. paddr(pc)
  245. void (*pc)();
  246. {
  247. #ifdef    LARGECODE
  248.     printf("%04x:%04x",FP_SEG(pc) - Codeseg,FP_OFF(pc));
  249. #else
  250.     printf("%04x",FP_OFF(pc));
  251. #endif    
  252. }
  253.