home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / STKTRACE.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  7KB  |  261 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.  * (adopted for 911229 based code by Johan, WG7J)
  8.  */
  9.   
  10. #include <dos.h>
  11. #include <time.h>
  12. #include "global.h"
  13. #ifdef STKTRACE
  14. #include "proc.h"
  15.   
  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)(),FILE *fp));
  29.   
  30. static unsigned short Codeseg;
  31. extern unsigned char _osmajor;
  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;
  46.     char *cp;
  47.     FILE *fp;
  48.     time_t t;
  49.   
  50.     /* output to file */
  51.     if((fp = fopen("stktrace.out","at")) == NULLFILE)
  52.         return; /* Give up */
  53.   
  54.     time(&t);
  55.     fprintf(fp,"stktrace from proc %s at %s",Curproc->name,ctime(&t));
  56.     Codeseg = _psp + 0x10;
  57. #ifdef  notdef
  58.     fprintf(fp,"Code base segment: %x\n",Codeseg);
  59. #endif
  60.     /* Construct name of map file */
  61.     mapname = malloc(strlen(_argv[0]) + 5);
  62. /*
  63.  * Dos's less than 3.0 do not pass the progname in via argv[0] we fake it, and
  64.  * the mapfile must be 'nos.map'
  65.  */
  66.     if(_osmajor<3)
  67.         strcpy(mapname,"nos");
  68.     else
  69.         strcpy(mapname,_argv[0]);
  70.     if((cp = strrchr(mapname,'.')) != NULLCHAR)
  71.         *cp = '\0';
  72.     strcat(mapname,".map");
  73.   
  74.     /* Read the symbol table in another process to avoid overstressing
  75.      * the stack in this one
  76.      */
  77.     rdproc = newproc("rdsymtab",512,rdsymtab,1,mapname,NULL,0);
  78.     pwait(rdproc);
  79.     free(mapname);
  80.   
  81.     context = MK_FP(_SS,_BP);
  82.     pc = stktrace;
  83.   
  84.     for(i=0;i<20;i++){
  85.         paddr(pc,fp);
  86.         sp = findsym(pc);
  87.         if(sp != NULL)
  88.             fprintf(fp," %s+%x",sp->name,FP_OFF(pc) - sp->offs);
  89.   
  90.         if(FP_OFF(context) == 0){
  91.             /* No context left, we're done */
  92.             fputc('\n',fp);
  93.             break;
  94.         }
  95.         cnext = MK_FP(FP_SEG(context),*context);
  96.         /* Compute number of args to display */
  97.         if(FP_OFF(cnext) != 0){
  98.             nargs = (int)(cnext - context - (1 + (sizeof(pc) >> 1)));
  99.             if(nargs > 20)
  100.                 nargs = 20; /* limit to reasonable number */
  101.         } else {
  102.             /* No higher level context, so just print an
  103.              * arbitrary fixed number of args
  104.              */
  105.             nargs = 6;
  106.         }
  107.         /* Args start after saved BP and return address */
  108.         ctmp = context + 1 + (sizeof(pc) >> 1);
  109.         fputc('(',fp);
  110.         for(j=0;j<nargs;j++){
  111.             fprintf(fp,"%x",*ctmp);
  112.             if(j < nargs-1)
  113.                 fputc(' ',fp);
  114.             else
  115.                 break;
  116.             ctmp++;
  117.         }
  118.         fprintf(fp,")\n");
  119. #ifdef  notdef
  120.         if(strcmp(cp,"_main") == 0)
  121.             break;
  122. #endif
  123.   
  124. #ifdef  LARGECODE
  125.         pc = MK_FP(context[2],context[1]);
  126. #else
  127.         pc = (void (*)())MK_FP(FP_SEG(pc),context[1]);
  128. #endif
  129.         context = cnext;
  130.     }
  131.     clrsymtab();
  132.     fclose(fp);
  133. }
  134. static struct symtab *
  135. findsym(pc)
  136. void (*pc)();
  137. {
  138.     struct symtab *sp,*spprev;
  139.     unsigned short seg,offs;
  140.   
  141. #ifdef  LARGECODE
  142.     seg = FP_SEG(pc) - Codeseg;
  143. #else
  144.     seg = 0;    /* Small code, no segment */
  145. #endif
  146.     offs = FP_OFF(pc);
  147.     spprev = NULL;
  148.     for(sp = Symtab;sp != NULL;spprev = sp,sp = sp->next){
  149.         if(sp->seg > seg || (sp->seg == seg && sp->offs > offs)){
  150.             break;
  151.         }
  152.     }
  153.     return spprev;
  154. }
  155. static void
  156. clrsymtab()
  157. {
  158.     struct symtab *sp,*spnext;
  159.   
  160.     for(sp = Symtab;sp != NULL;sp = spnext){
  161.         spnext = sp->next;
  162.         free(sp->name);
  163.         free(sp);
  164.     }
  165.     Symtab = NULL;
  166. }
  167. static void
  168. rdsymtab(unused,name,p)
  169. int unused;
  170. void *name;
  171. void *p;
  172. {
  173.     char *buf;
  174.     FILE *fp;
  175.     unsigned short seg;
  176.     unsigned short offs;
  177.     struct symtab *sp;
  178.     struct symtab **spp;
  179.     int size = 0;
  180.     int i;
  181.   
  182.     if((fp = fopen(name,"rt")) == NULL){
  183.         printf("Stktrace: can't read %s\n",name);
  184.         return;
  185.     }
  186.     buf = (char *)malloc(128);
  187.     while(fgets(buf,128,fp),!feof(fp)){
  188.         rip(buf);
  189.         if(strcmp(buf,"  Address         Publics by Value") == 0)
  190.             break;
  191.     }
  192.     if(feof(fp)){
  193.         printf("Stktrace: Can't find header line in %s\n",name);
  194.         free(buf);
  195.         return;
  196.     }
  197.     Symtab = NULL;
  198.     while(fgets(buf,128,fp),!feof(fp)){
  199.         rip(buf);
  200.         if(sscanf(buf,"%x:%x",&seg,&offs) != 2)
  201.             continue;
  202.         sp = (struct symtab *)malloc(sizeof(struct symtab));
  203.         sp->offs = offs;
  204.         sp->seg = seg;
  205.         sp->name = strdup(buf+17);
  206.         sp->next = Symtab;
  207.         Symtab = sp;
  208.         size++;
  209.     }
  210.     fclose(fp);
  211.     free(buf);
  212. #ifdef  notdef
  213.     printf("Stktrace: Symbols read: %d\n",size);
  214. #endif
  215.     /* Sort the symbols using the quicksort library function */
  216.     spp = malloc(size*sizeof(struct symtab *));
  217.     for(i=0,sp = Symtab;sp != NULL;i++,sp = sp->next)
  218.         spp[i] = sp;
  219.     qsort(spp,size,sizeof(struct symtab *),scompare);
  220.     /* Now put them back in the linked list */
  221.     Symtab = NULL;
  222.     for(i=size-1;i >= 0;i--){
  223.         sp = spp[i];
  224.         sp->next = Symtab;
  225.         Symtab = sp;
  226.     }
  227.     free(spp);
  228. #ifdef  notdef
  229.     for(sp = Symtab;sp != NULL;sp = sp->next)
  230.         printf("Stktrace: %x:%x   %s\n",sp->seg,sp->offs,sp->name);
  231. #endif
  232. }
  233. static int
  234. scompare(a,b)
  235. struct symtab **a,**b;
  236. {
  237.     if((*a)->seg > (*b)->seg)
  238.         return 1;
  239.     if((*a)->seg < (*b)->seg)
  240.         return -1;
  241.     if((*a)->offs > (*b)->offs)
  242.         return 1;
  243.     if((*a)->offs < (*b)->offs)
  244.         return -1;
  245.     return 0;
  246. }
  247. /* Print a code address according to the memory model */
  248. static void
  249. paddr(pc,fp)
  250. void (*pc)();
  251. FILE *fp;
  252. {
  253. #ifdef  LARGECODE
  254.     fprintf(fp,"%04x:%04x",FP_SEG(pc) - Codeseg,FP_OFF(pc));
  255. #else
  256.     fprintf(fp,"%04x",FP_OFF(pc));
  257. #endif
  258. }
  259.   
  260. #endif /* STKTRACE */
  261.