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