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