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