home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / gnu / djgpp / src / binutils.2 / gprof / gprof.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-25  |  17.7 KB  |  725 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. char copyright[] =
  22. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  23.  All rights reserved.\n";
  24. #endif /* not lint */
  25.  
  26. #ifndef lint
  27. static char sccsid[] = "@(#)gprof.c    5.6 (Berkeley) 6/1/90";
  28. #endif /* not lint */
  29.  
  30. #include "gprof.h"
  31.  
  32. bfd    *abfd;
  33.  
  34. char    *whoami = "gprof";
  35.  
  36.     /*
  37.      *    things which get -E excluded by default.
  38.      */
  39. char    *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
  40.  
  41. int discard_underscores = 1; /* Should we discard initial underscores? */
  42. int bsd_style_output = 0; /* As opposed to FSF style output */
  43.  
  44. main(argc, argv)
  45.     int argc;
  46.     char **argv;
  47. {
  48.     char    **sp;
  49.     nltype    **timesortnlp;
  50.  
  51.     --argc;
  52.     argv++;
  53.     debug = 0;
  54.     bflag = TRUE;
  55.     while ( *argv != 0 && **argv == '-' ) {
  56.     (*argv)++;
  57.     switch ( **argv ) {
  58.     case 'a':
  59.         aflag = TRUE;
  60.         break;
  61.     case 'b':
  62.         bflag = FALSE;
  63.         break;
  64.     case 'c':
  65.         cflag = TRUE;
  66.         break;
  67.     case 'd':
  68.         dflag = TRUE;
  69.         (*argv)++;
  70.         debug |= atoi( *argv );
  71.         debug |= ANYDEBUG;
  72. #        ifdef DEBUG
  73.         printf("[main] debug = %d\n", debug);
  74. #        else not DEBUG
  75.         printf("%s: -d ignored\n", whoami);
  76. #        endif DEBUG
  77.         break;
  78.     case 'E':
  79.         ++argv;
  80.         addlist( Elist , *argv );
  81.         Eflag = TRUE;
  82.         addlist( elist , *argv );
  83.         eflag = TRUE;
  84.         break;
  85.     case 'e':
  86.         addlist( elist , *++argv );
  87.         eflag = TRUE;
  88.         break;
  89.     case 'F':
  90.         ++argv;
  91.         addlist( Flist , *argv );
  92.         Fflag = TRUE;
  93.         addlist( flist , *argv );
  94.         fflag = TRUE;
  95.         break;
  96.     case 'f':
  97.         addlist( flist , *++argv );
  98.         fflag = TRUE;
  99.         break;
  100.     case 'k':
  101.         addlist( kfromlist , *++argv );
  102.         addlist( ktolist , *++argv );
  103.         kflag = TRUE;
  104.         break;
  105.     case 's':
  106.         sflag = TRUE;
  107.         break;
  108.     case 'T': /* "Traditional" output format */
  109.         bsd_style_output = 1;
  110.         break;
  111.     case 'z':
  112.         zflag = TRUE;
  113.         break;
  114.     default:
  115.         fprintf (stderr, "usage:  gprof [-a] [-b] [-c] [-d[num]] \
  116. [-E function-name] [-e function-name] \
  117. [-F function-name] [-f function-name] \
  118. [-k from to] [-s] [-T] [-z] [image-file] \
  119. [profile file(s)]\n");
  120.         exit (1);
  121.     }
  122.     argv++;
  123.     }
  124.     if ( *argv != 0 ) {
  125.     a_outname  = *argv;
  126.     argv++;
  127.     } else {
  128.     a_outname  = A_OUTNAME;
  129.     }
  130.     if ( *argv != 0 ) {
  131.     gmonname = *argv;
  132.     argv++;
  133.     } else {
  134.     gmonname = GMONNAME;
  135.     }
  136.     /*
  137.      *    turn off default functions
  138.      */
  139.     for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
  140.     Eflag = TRUE;
  141.     addlist( Elist , *sp );
  142.     eflag = TRUE;
  143.     addlist( elist , *sp );
  144.     }
  145.     /*
  146.      *    how many ticks per second?
  147.      *    if we can't tell, report time in ticks.
  148.      */
  149.     hz = hertz();
  150.     if (hz == 0) {
  151.     hz = 1;
  152.     fprintf(stderr, "time is in ticks, not seconds\n");
  153.     }
  154.     /*
  155.      *    get information about a.out file.
  156.      */
  157.     getnfile();
  158.     /*
  159.      *    get information about mon.out file(s).
  160.      */
  161.     do    {
  162.     getpfile( gmonname );
  163.     if ( *argv != 0 ) {
  164.         gmonname = *argv;
  165.     }
  166.     } while ( *argv++ != 0 );
  167.     /*
  168.      *    dump out a gmon.sum file if requested
  169.      */
  170.     if ( sflag ) {
  171.     dumpsum( GMONSUM );
  172.     }
  173.     /*
  174.      *    assign samples to procedures
  175.      */
  176.     asgnsamples();
  177.     /*
  178.      *    assemble the dynamic profile
  179.      */
  180.     timesortnlp = doarcs();
  181.     
  182.     if (bsd_style_output) {
  183.     printgprof( timesortnlp );    /* print the dynamic profile */
  184.     printprof();  /* print the flat profile */
  185.     } else {
  186.     printprof();  /* print the flat profile */
  187.     printgprof( timesortnlp );    /* print the dynamic profile */
  188.     }
  189.     /*
  190.      *    print the index
  191.      */
  192.     printindex();    
  193.     done();
  194. }
  195.  
  196.     /*
  197.      * Set up string and symbol tables from a.out.
  198.      *    and optionally the text space.
  199.      * On return symbol table is sorted by value.
  200.      */
  201. getnfile()
  202. {
  203.   int        valcmp();
  204.  
  205.   abfd = bfd_openr (a_outname, NULL);
  206.  
  207.   if (abfd == NULL) {
  208.     perror (a_outname);
  209.     done();
  210.   }
  211.  
  212.   if (!bfd_check_format (abfd, bfd_object)) {
  213.     fprintf (stderr, "%s: %s: bad format\n", whoami, a_outname);
  214.     done();
  215.   }
  216.  
  217. /*  getstrtab(nfile); */
  218.   getsymtab(abfd);
  219.   gettextspace( abfd );
  220.   qsort(nl, nname, sizeof(nltype), valcmp);
  221.  
  222. #   ifdef DEBUG
  223.   if ( debug & AOUTDEBUG ) {
  224.     register int j;
  225.     
  226.     for (j = 0; j < nname; j++){
  227.       printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
  228.     }
  229.   }
  230. #   endif DEBUG
  231. }
  232.  
  233. /*
  234.  * Read in symbol table
  235.  */
  236. getsymtab(abfd)
  237. bfd    *abfd;
  238. {
  239.     register long    i;
  240.     int            askfor;
  241.     int            nosyms;
  242.     asymbol        **syms;
  243.     i = get_symtab_upper_bound (abfd);    /* This will probably give us more
  244.                      * than we need, but that's ok.
  245.                      */
  246.     syms = (asymbol**)xmalloc (i);
  247.     nosyms = bfd_canonicalize_symtab (abfd, syms);
  248.  
  249.     nname = 0;
  250.     for (i = 0; i < nosyms; i++) {
  251.       if (!funcsymbol (syms[i]))
  252.     continue;
  253.       nname++;
  254.     }
  255.  
  256.     if (nname == 0) {
  257.       fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
  258.       done();
  259.     }
  260.     askfor = nname + 1;
  261.     nl = (nltype *) calloc( askfor , sizeof(nltype) );
  262.     if (nl == 0) {
  263.     fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
  264.         whoami, askfor * sizeof(nltype) );
  265.     done();
  266.     }
  267.  
  268.     /* pass2 - read symbols */
  269.     npe = nl;
  270.     nname = 0;
  271.     for (i = 0; i < nosyms; i++) {
  272.       if (!funcsymbol (syms[i])) {
  273. #        ifdef DEBUG
  274.     if ( debug & AOUTDEBUG ) {
  275.       printf( "[getsymtab] rejecting: 0x%x %s\n" ,
  276.          syms[i]->value, syms[i]->name);
  277.     }
  278. #        endif DEBUG
  279.     continue;
  280.       }
  281.       /* Symbol offsets are always section-relative. */
  282.       npe->value = syms[i]->value + syms[i]->section->vma;
  283.       npe->name = syms[i]->name;
  284.  
  285.       /* If we see "main" without an initial '_', we assume
  286.      names are *not* prefixed by '_'. */
  287.       if (npe->name[0] == 'm' && discard_underscores
  288.       && strcmp(npe->name, "main") == 0)
  289.       discard_underscores = 0;
  290.  
  291. #    ifdef DEBUG
  292.       if ( debug & AOUTDEBUG ) {
  293.     printf( "[getsymtab] %d %s 0x%08x\n" ,
  294.            nname , npe -> name , npe -> value );
  295.       }
  296. #    endif DEBUG
  297.       npe++;
  298.       nname++;
  299.     }
  300.     npe->value = -1;
  301. }
  302.  
  303. /*
  304.  *    read in the text space of an a.out file
  305.  */
  306. gettextspace( abfd )
  307.      bfd    *abfd;
  308. {
  309.   asection    *texsec;
  310.     
  311.   if ( cflag == 0 ) {
  312.     return;
  313.   }
  314.  
  315.   texsec = bfd_get_section_by_name (abfd, ".text");
  316.   if (texsec == NULL) {
  317.     return;
  318.   }
  319.  
  320.   textspace = (u_char *) malloc( texsec->_cooked_size );
  321.  
  322.   if ( textspace == 0 ) {
  323.     fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
  324.         whoami , texsec->_cooked_size);
  325.     fprintf( stderr , "can't do -c\n" );
  326.     return;
  327.   }
  328.   bfd_get_section_contents (abfd, texsec, textspace, texsec->filepos, 
  329.                 texsec->_cooked_size);
  330. }
  331. /*
  332.  *    information from a gmon.out file is in two parts:
  333.  *    an array of sampling hits within pc ranges,
  334.  *    and the arcs.
  335.  */
  336. getpfile(filename)
  337.     char *filename;
  338. {
  339.     FILE        *pfile;
  340.     FILE        *openpfile();
  341.     struct rawarc    arc;
  342.  
  343.     pfile = openpfile(filename);
  344.     readsamples(pfile);
  345.     /*
  346.      *    the rest of the file consists of
  347.      *    a bunch of <from,self,count> tuples.
  348.      */
  349.     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
  350.       arc.raw_frompc = bfd_get_32 (abfd, (bfd_byte *) &arc.raw_frompc);
  351.       arc.raw_selfpc = bfd_get_32 (abfd, (bfd_byte *) &arc.raw_selfpc);
  352.       arc.raw_count  = bfd_get_32 (abfd, (bfd_byte *) &arc.raw_count);
  353. #    ifdef DEBUG
  354.         if ( debug & SAMPLEDEBUG ) {
  355.         printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
  356.             arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
  357.         }
  358. #    endif DEBUG
  359.         /*
  360.          *    add this arc
  361.          */
  362.     tally( &arc );
  363.     }
  364.     fclose(pfile);
  365. }
  366.  
  367. FILE *
  368. openpfile(filename)
  369.     char *filename;
  370. {
  371.     struct hdr    tmp;
  372.     FILE    *pfile;
  373.  
  374.     if((pfile = fopen(filename, "rb")) == NULL) {
  375.     perror(filename);
  376.     done();
  377.     }
  378.     fread(&tmp, sizeof(struct hdr), 1, pfile);
  379.     tmp.lowpc  = (UNIT *)bfd_get_32 (abfd, (bfd_byte *) &tmp.lowpc);
  380.     tmp.highpc = (UNIT *)bfd_get_32 (abfd, (bfd_byte *) &tmp.highpc);
  381.     tmp.ncnt   =         bfd_get_32 (abfd, (bfd_byte *) &tmp.ncnt);
  382.  
  383.     if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
  384.      tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
  385.     fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
  386.     done();
  387.     }
  388.     h = tmp;
  389.     s_lowpc = (unsigned long) h.lowpc;
  390.     s_highpc = (unsigned long) h.highpc;
  391.     lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
  392.     highpc = (unsigned long)h.highpc / sizeof(UNIT);
  393.     sampbytes = h.ncnt - sizeof(struct hdr);
  394.     nsamples = sampbytes / sizeof (UNIT);
  395. #   ifdef DEBUG
  396.     if ( debug & SAMPLEDEBUG ) {
  397.         printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
  398.         h.lowpc , h.highpc , h.ncnt );
  399.         printf( "[openpfile]   s_lowpc 0x%x   s_highpc 0x%x\n" ,
  400.         s_lowpc , s_highpc );
  401.         printf( "[openpfile]     lowpc 0x%x     highpc 0x%x\n" ,
  402.         lowpc , highpc );
  403.         printf( "[openpfile] sampbytes %d nsamples %d\n" ,
  404.         sampbytes , nsamples );
  405.     }
  406. #   endif DEBUG
  407.     return(pfile);
  408. }
  409.  
  410. tally( rawp )
  411.     struct rawarc    *rawp;
  412. {
  413.     nltype        *parentp;
  414.     nltype        *childp;
  415.  
  416.     parentp = nllookup( rawp -> raw_frompc );
  417.     childp = nllookup( rawp -> raw_selfpc );
  418.     if ( kflag
  419.      && onlist( kfromlist , parentp -> name )
  420.      && onlist( ktolist , childp -> name ) ) {
  421.     return;
  422.     }
  423.     childp -> ncall += rawp -> raw_count;
  424. #   ifdef DEBUG
  425.     if ( debug & TALLYDEBUG ) {
  426.         printf( "[tally] arc from %s to %s traversed %d times\n" ,
  427.             parentp -> name , childp -> name , rawp -> raw_count );
  428.     }
  429. #   endif DEBUG
  430.     addarc( parentp , childp , rawp -> raw_count );
  431. }
  432.  
  433. /*
  434.  * dump out the gmon.sum file
  435.  */
  436. dumpsum( sumfile )
  437.     char *sumfile;
  438. {
  439.     register nltype *nlp;
  440.     register arctype *arcp;
  441.     struct rawarc arc;
  442.     FILE *sfile;
  443.  
  444.     if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
  445.     perror( sumfile );
  446.     done();
  447.     }
  448.     /*
  449.      * dump the header; use the last header read in
  450.      */
  451.     if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
  452.     perror( sumfile );
  453.     done();
  454.     }
  455.     /*
  456.      * dump the samples
  457.      */
  458.     if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) {
  459.     perror( sumfile );
  460.     done();
  461.     }
  462.     /*
  463.      * dump the normalized raw arc information
  464.      */
  465.     for ( nlp = nl ; nlp < npe ; nlp++ ) {
  466.     for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
  467.         arc.raw_frompc = arcp -> arc_parentp -> value;
  468.         arc.raw_selfpc = arcp -> arc_childp -> value;
  469.         arc.raw_count = arcp -> arc_count;
  470.         if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
  471.         perror( sumfile );
  472.         done();
  473.         }
  474. #        ifdef DEBUG
  475.         if ( debug & SAMPLEDEBUG ) {
  476.             printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
  477.                 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
  478.         }
  479. #        endif DEBUG
  480.     }
  481.     }
  482.     fclose( sfile );
  483. }
  484.  
  485. valcmp(p1, p2)
  486.     nltype *p1, *p2;
  487. {
  488.     if ( p1 -> value < p2 -> value ) {
  489.     return LESSTHAN;
  490.     }
  491.     if ( p1 -> value > p2 -> value ) {
  492.     return GREATERTHAN;
  493.     }
  494.     return EQUALTO;
  495. }
  496.  
  497. readsamples(pfile)
  498.     FILE    *pfile;
  499. {
  500.     register i;
  501.     UNIT    sample;
  502.     
  503.     if (samples == 0) {
  504.     samples = (UNIT *) malloc (sampbytes * sizeof(UNIT));
  505.     if (samples == 0) {
  506.         fprintf( stderr , "%s: No room for %d sample pc's\n", 
  507.         whoami , sampbytes / sizeof (UNIT));
  508.         done();
  509.     }
  510.       memset (samples, 0, sampbytes * sizeof(UNIT));
  511.     }
  512.     for (i = 0; i < nsamples; i++) {
  513.     fread(&sample, sizeof (UNIT), 1, pfile);
  514.     sample = bfd_get_16 (abfd, (bfd_byte *) &sample);
  515.     if (feof(pfile))
  516.         break;
  517.     samples[i] += sample;
  518.     }
  519.     if (i != nsamples) {
  520.     fprintf(stderr,
  521.         "%s: unexpected EOF after reading %d/%d samples\n",
  522.         whoami , --i , nsamples );
  523.     done();
  524.     }
  525. }
  526.  
  527. /*
  528.  *    Assign samples to the procedures to which they belong.
  529.  *
  530.  *    There are three cases as to where pcl and pch can be
  531.  *    with respect to the routine entry addresses svalue0 and svalue1
  532.  *    as shown in the following diagram.  overlap computes the
  533.  *    distance between the arrows, the fraction of the sample
  534.  *    that is to be credited to the routine which starts at svalue0.
  535.  *
  536.  *        svalue0                                         svalue1
  537.  *           |                                               |
  538.  *           v                                               v
  539.  *
  540.  *           +-----------------------------------------------+
  541.  *           |                           |
  542.  *      |  ->|    |<-        ->|         |<-        ->|    |<-  |
  543.  *      |         |          |         |          |         |
  544.  *      +---------+          +---------+          +---------+
  545.  *
  546.  *      ^         ^          ^         ^          ^         ^
  547.  *      |         |          |         |          |         |
  548.  *     pcl       pch         pcl       pch         pcl       pch
  549.  *
  550.  *    For the vax we assert that samples will never fall in the first
  551.  *    two bytes of any routine, since that is the entry mask,
  552.  *    thus we give call alignentries() to adjust the entry points if
  553.  *    the entry mask falls in one bucket but the code for the routine
  554.  *    doesn't start until the next bucket.  In conjunction with the
  555.  *    alignment of routine addresses, this should allow us to have
  556.  *    only one sample for every four bytes of text space and never
  557.  *    have any overlap (the two end cases, above).
  558.  */
  559. asgnsamples()
  560. {
  561.     register int    j;
  562.     UNIT        ccnt;
  563.     double        time;
  564.     unsigned long    pcl, pch;
  565.     register int    i;
  566.     unsigned long    overlap;
  567.     unsigned long    svalue0, svalue1;
  568.  
  569.     /* read samples and assign to namelist symbols */
  570.     scale = highpc - lowpc;
  571.     scale /= nsamples;
  572.     alignentries();
  573.     for (i = 0, j = 1; i < nsamples; i++) {
  574.     ccnt = samples[i];
  575.     if (ccnt == 0)
  576.         continue;
  577.     pcl = lowpc + scale * i;
  578.     pch = lowpc + scale * (i + 1);
  579.     time = ccnt;
  580. #    ifdef DEBUG
  581.         if ( debug & SAMPLEDEBUG ) {
  582.         printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
  583.             pcl , pch , ccnt );
  584.         }
  585. #    endif DEBUG
  586.     totime += time;
  587.     for (j = j - 1; j < nname; j++) {
  588.         svalue0 = nl[j].svalue;
  589.         svalue1 = nl[j+1].svalue;
  590.         /*
  591.          *    if high end of tick is below entry address, 
  592.          *    go for next tick.
  593.          */
  594.         if (pch < svalue0)
  595.             break;
  596.         /*
  597.          *    if low end of tick into next routine,
  598.          *    go for next routine.
  599.          */
  600.         if (pcl >= svalue1)
  601.             continue;
  602.         overlap = min(pch, svalue1) - max(pcl, svalue0);
  603.         if (overlap > 0) {
  604. #        ifdef DEBUG
  605.             if (debug & SAMPLEDEBUG) {
  606.             printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
  607.                 nl[j].value/sizeof(UNIT), svalue0, svalue1,
  608.                 nl[j].name, 
  609.                 overlap * time / scale, overlap);
  610.             }
  611. #        endif DEBUG
  612.         nl[j].time += overlap * time / scale;
  613.         }
  614.     }
  615.     }
  616. #   ifdef DEBUG
  617.     if (debug & SAMPLEDEBUG) {
  618.         printf("[asgnsamples] totime %f\n", totime);
  619.     }
  620. #   endif DEBUG
  621. }
  622.  
  623.  
  624. unsigned long
  625. min(a, b)
  626.     unsigned long a,b;
  627. {
  628.     if (a<b)
  629.     return(a);
  630.     return(b);
  631. }
  632.  
  633. unsigned long
  634. max(a, b)
  635.     unsigned long a,b;
  636. {
  637.     if (a>b)
  638.     return(a);
  639.     return(b);
  640. }
  641.  
  642.     /*
  643.      *    calculate scaled entry point addresses (to save time in asgnsamples),
  644.      *    and possibly push the scaled entry points over the entry mask,
  645.      *    if it turns out that the entry point is in one bucket and the code
  646.      *    for a routine is in the next bucket.
  647.      */
  648. alignentries()
  649. {
  650.     register struct nl    *nlp;
  651.     unsigned long    bucket_of_entry;
  652.     unsigned long    bucket_of_code;
  653.  
  654.     for (nlp = nl; nlp < npe; nlp++) {
  655.     nlp -> svalue = nlp -> value / sizeof(UNIT);
  656.     bucket_of_entry = (nlp->svalue - lowpc) / scale;
  657.     bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
  658.     if (bucket_of_entry < bucket_of_code) {
  659. #        ifdef DEBUG
  660.         if (debug & SAMPLEDEBUG) {
  661.             printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
  662.                 nlp->svalue, nlp->svalue + UNITS_TO_CODE);
  663.         }
  664. #        endif DEBUG
  665.         nlp->svalue += UNITS_TO_CODE;
  666.     }
  667.     }
  668. }
  669.  
  670. bool
  671. funcsymbol( symp )
  672.      asymbol *symp;
  673. {
  674.   extern char    *strtab;    /* string table from a.out */
  675.   extern int    aflag;        /* if static functions aren't desired */
  676.   CONST char    *name;
  677.   int i;
  678.  
  679.   /*
  680.    *    must be a text symbol,
  681.    *    and static text symbols don't qualify if aflag set.
  682.    */
  683.   
  684.  
  685.   if (!symp->section)
  686.     return FALSE;
  687.  
  688.   if (aflag && (symp->flags&BSF_LOCAL)) {
  689. #if defined(DEBUG)
  690.     fprintf (stderr, "%s(%d):  %s:  not a function\n", __FILE__, __LINE__, symp->name);
  691. #endif
  692.     return FALSE;
  693.   }
  694.   /*
  695.    *    can't have any `funny' characters in name,
  696.    *    where `funny' includes    `.', .o file names
  697.    *            and    `$', pascal labels.
  698.    */
  699.   if (!symp->name)
  700.     return FALSE;
  701.  
  702.   for (name = symp->name; *name; name++) {
  703.     if ( *name == '.' || *name == '$' ) {
  704.       return FALSE;
  705.     }
  706.   }
  707.   
  708.   if (strncmp(symp->name, "___gnu_compiled", 15) == 0)
  709.     return FALSE;
  710.  
  711.   i = bfd_decode_symclass (symp);
  712. #if defined(DEBUG) && 0
  713.   if (i != 'T' && i != 't')
  714.     fprintf (stderr, "%s(%d):  %s is of class %c\n", __FILE__, __LINE__, symp->name, i);
  715. #endif
  716.  
  717.   return (i == 'T' || i == 't');
  718. }
  719.  
  720. done()
  721. {
  722.  
  723.     exit(0);
  724. }
  725.