gprof.c revision 5190
116359Sasami/* 216359Sasami * Copyright (c) 1983, 1993 316359Sasami * The Regents of the University of California. All rights reserved. 416359Sasami * 516359Sasami * Redistribution and use in source and binary forms, with or without 631890Skato * modification, are permitted provided that the following conditions 716359Sasami * are met: 816359Sasami * 1. Redistributions of source code must retain the above copyright 916359Sasami * notice, this list of conditions and the following disclaimer. 1016359Sasami * 2. Redistributions in binary form must reproduce the above copyright 1116359Sasami * notice, this list of conditions and the following disclaimer in the 1216359Sasami * documentation and/or other materials provided with the distribution. 1316359Sasami * 3. All advertising materials mentioning features or use of this software 1416359Sasami * must display the following acknowledgement: 1516359Sasami * This product includes software developed by the University of 1616359Sasami * California, Berkeley and its contributors. 1716359Sasami * 4. Neither the name of the University nor the names of its contributors 1816359Sasami * may be used to endorse or promote products derived from this software 1916359Sasami * without specific prior written permission. 2016359Sasami * 2130665Skato * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2230990Skato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2330665Skato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2425088Skato * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2525571Skato * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2625088Skato * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2725088Skato * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2827690Skato * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2927690Skato * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3016359Sasami * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3116359Sasami * SUCH DAMAGE. 3216359Sasami */ 3316359Sasami 3416359Sasami#ifndef lint 3516359Sasamistatic char copyright[] = 3616359Sasami"@(#) Copyright (c) 1983, 1993\n\ 3716359Sasami The Regents of the University of California. All rights reserved.\n"; 3816359Sasami#endif /* not lint */ 3918846Sasami 4016359Sasami#ifndef lint 4116359Sasamistatic char sccsid[] = "@(#)gprof.c 8.1 (Berkeley) 6/6/93"; 4216359Sasami#endif /* not lint */ 4316359Sasami 4416359Sasami#include "gprof.h" 4516359Sasami 4625256Skatochar *whoami = "gprof"; 4716359Sasami 4816359Sasami /* 4927101Skato * things which get -E excluded by default. 5020494Skato */ 5127101Skatochar *defaultEs[] = { "mcount" , "__mcleanup" , 0 }; 5220494Skato 5320494Skatostatic struct gmonhdr gmonhdr; 5420494Skatostatic bool uflag; 5520494Skatostatic int lflag; 5620494Skatostatic int Lflag; 5716359Sasami 5816359Sasamimain(argc, argv) 5916359Sasami int argc; 6016359Sasami char **argv; 6116359Sasami{ 6216359Sasami char **sp; 6316359Sasami nltype **timesortnlp; 6416359Sasami 6516359Sasami --argc; 6616359Sasami argv++; 6726058Skato debug = 0; 6826058Skato bflag = TRUE; 6926058Skato while ( *argv != 0 && **argv == '-' ) { 7026058Skato (*argv)++; 7126058Skato switch ( **argv ) { 7224112Skato case 'a': 7316359Sasami aflag = TRUE; 7416359Sasami break; 7516359Sasami case 'b': 7616359Sasami bflag = FALSE; 7725088Skato break; 7825088Skato case 'C': 7926058Skato Cflag = TRUE; 8025088Skato cyclethreshold = atoi( *++argv ); 8116359Sasami break; 8216359Sasami case 'c': 8316359Sasami#if defined(vax) || defined(tahoe) 8425088Skato cflag = TRUE; 8525571Skato#else 8626058Skato fprintf(stderr, "gprof: -c isn't supported on this architecture yet\n"); 8725571Skato exit(1); 8825571Skato#endif 8925571Skato break; 9025571Skato case 'd': 9125571Skato dflag = TRUE; 9225088Skato setlinebuf(stdout); 9326058Skato debug |= atoi( *++argv ); 9426058Skato debug |= ANYDEBUG; 9526058Skato# ifdef DEBUG 9626058Skato printf("[main] debug = %d\n", debug); 9725088Skato# else not DEBUG 9825088Skato printf("%s: -d ignored\n", whoami); 9916359Sasami# endif DEBUG 10016359Sasami break; 10116359Sasami case 'E': 10216359Sasami ++argv; 10316359Sasami addlist( Elist , *argv ); 10416359Sasami Eflag = TRUE; 10516359Sasami addlist( elist , *argv ); 10616359Sasami eflag = TRUE; 10716359Sasami break; 10816359Sasami case 'e': 10916359Sasami addlist( elist , *++argv ); 11016359Sasami eflag = TRUE; 11116359Sasami break; 11216359Sasami case 'F': 11326058Skato ++argv; 11426058Skato addlist( Flist , *argv ); 11516359Sasami Fflag = TRUE; 11616359Sasami addlist( flist , *argv ); 11716359Sasami fflag = TRUE; 11816359Sasami break; 11924112Skato case 'f': 12016359Sasami addlist( flist , *++argv ); 12116359Sasami fflag = TRUE; 12216359Sasami break; 12316359Sasami case 'k': 12416359Sasami addlist( kfromlist , *++argv ); 12516359Sasami addlist( ktolist , *++argv ); 12616359Sasami kflag = TRUE; 12716359Sasami break; 12816359Sasami case 'l': 12916359Sasami lflag = 1; 13016359Sasami Lflag = 0; 13124112Skato break; 13216359Sasami case 'L': 13316359Sasami Lflag = 1; 13426058Skato lflag = 0; 13525088Skato break; 13625088Skato case 's': 13726058Skato sflag = TRUE; 13825088Skato break; 13925088Skato case 'u': 14026058Skato uflag = TRUE; 14126058Skato break; 14226058Skato case 'z': 14326058Skato zflag = TRUE; 14426058Skato break; 14526058Skato } 14626058Skato argv++; 14726058Skato } 14826058Skato if ( *argv != 0 ) { 14916359Sasami a_outname = *argv; 15016359Sasami argv++; 15116359Sasami } else { 15216359Sasami a_outname = A_OUTNAME; 15316359Sasami } 15416359Sasami if ( *argv != 0 ) { 15516359Sasami gmonname = *argv; 15616359Sasami argv++; 15716359Sasami } else { 15816359Sasami gmonname = GMONNAME; 15916359Sasami } 16016359Sasami /* 16116359Sasami * turn off default functions 16216359Sasami */ 16316359Sasami for ( sp = &defaultEs[0] ; *sp ; sp++ ) { 16416359Sasami Eflag = TRUE; 16516359Sasami addlist( Elist , *sp ); 16616359Sasami eflag = TRUE; 16716359Sasami addlist( elist , *sp ); 16816359Sasami } 16916359Sasami /* 17016359Sasami * get information about a.out file. 17130330Skato */ 17216359Sasami getnfile(); 17316359Sasami /* 17416359Sasami * get information about mon.out file(s). 17516359Sasami */ 17619551Sasami do { 17716359Sasami getpfile( gmonname ); 17825256Skato if ( *argv != 0 ) { 17925256Skato gmonname = *argv; 18016359Sasami } 18116359Sasami } while ( *argv++ != 0 ); 18216359Sasami /* 18316359Sasami * how many ticks per second? 18416359Sasami * if we can't tell, report time in ticks. 18525088Skato */ 18616359Sasami if (hz == 0) { 18716359Sasami hz = 1; 18816359Sasami fprintf(stderr, "time is in ticks, not seconds\n"); 18916359Sasami } 19016359Sasami /* 19116359Sasami * dump out a gmon.sum file if requested 19216359Sasami */ 19316359Sasami if ( sflag ) { 19416359Sasami dumpsum( GMONSUM ); 19516359Sasami } 19616359Sasami /* 19716359Sasami * assign samples to procedures 19816359Sasami */ 19916359Sasami asgnsamples(); 20016359Sasami /* 20116359Sasami * assemble the dynamic profile 20216359Sasami */ 20316359Sasami timesortnlp = doarcs(); 20416359Sasami /* 20516359Sasami * print the dynamic profile 20616359Sasami */ 20716359Sasami if(!lflag) { 20831890Skato printgprof( timesortnlp ); 20931890Skato } 21031890Skato /* 21130933Skato * print the flat profile 21230933Skato */ 21330933Skato if(!Lflag) { 21416359Sasami printprof(); 21516359Sasami } 21616359Sasami /* 21716359Sasami * print the index 21818095Sasami */ 21916359Sasami printindex(); 22016359Sasami done(); 22116359Sasami} 22216359Sasami 22316359Sasami /* 22416359Sasami * Set up string and symbol tables from a.out. 22516359Sasami * and optionally the text space. 22616359Sasami * On return symbol table is sorted by value. 22716359Sasami */ 22816359Sasamigetnfile() 22916359Sasami{ 23016359Sasami FILE *nfile; 23116359Sasami int valcmp(); 23216359Sasami 23316359Sasami nfile = fopen( a_outname ,"r"); 23416359Sasami if (nfile == NULL) { 23516359Sasami perror( a_outname ); 23616359Sasami done(); 23719122Sasami } 23819122Sasami fread(&xbuf, 1, sizeof(xbuf), nfile); 23916359Sasami if (N_BADMAG(xbuf)) { 24016359Sasami fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); 24116359Sasami done(); 242 } 243 getstrtab(nfile); 244 getsymtab(nfile); 245 gettextspace( nfile ); 246 qsort(nl, nname, sizeof(nltype), valcmp); 247 fclose(nfile); 248# ifdef DEBUG 249 if ( debug & AOUTDEBUG ) { 250 register int j; 251 252 for (j = 0; j < nname; j++){ 253 printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 254 } 255 } 256# endif DEBUG 257} 258 259getstrtab(nfile) 260 FILE *nfile; 261{ 262 263 fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 264 if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 265 fprintf(stderr, "%s: %s: no string table (old format?)\n" , 266 whoami , a_outname ); 267 done(); 268 } 269 strtab = calloc(ssiz, 1); 270 if (strtab == NULL) { 271 fprintf(stderr, "%s: %s: no room for %d bytes of string table\n", 272 whoami , a_outname , ssiz); 273 done(); 274 } 275 if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 276 fprintf(stderr, "%s: %s: error reading string table\n", 277 whoami , a_outname ); 278 done(); 279 } 280} 281 282 /* 283 * Read in symbol table 284 */ 285getsymtab(nfile) 286 FILE *nfile; 287{ 288 register long i; 289 int askfor; 290 struct nlist nbuf; 291 292 /* pass1 - count symbols */ 293 fseek(nfile, (long)N_SYMOFF(xbuf), 0); 294 nname = 0; 295 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 296 fread(&nbuf, sizeof(nbuf), 1, nfile); 297 if ( ! funcsymbol( &nbuf ) ) { 298 continue; 299 } 300 nname++; 301 } 302 if (nname == 0) { 303 fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); 304 done(); 305 } 306 askfor = nname + 1; 307 nl = (nltype *) calloc( askfor , sizeof(nltype) ); 308 if (nl == 0) { 309 fprintf(stderr, "%s: No room for %d bytes of symbol table\n", 310 whoami, askfor * sizeof(nltype) ); 311 done(); 312 } 313 314 /* pass2 - read symbols */ 315 fseek(nfile, (long)N_SYMOFF(xbuf), 0); 316 npe = nl; 317 nname = 0; 318 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 319 fread(&nbuf, sizeof(nbuf), 1, nfile); 320 if ( ! funcsymbol( &nbuf ) ) { 321# ifdef DEBUG 322 if ( debug & AOUTDEBUG ) { 323 printf( "[getsymtab] rejecting: 0x%x %s\n" , 324 nbuf.n_type , strtab + nbuf.n_un.n_strx ); 325 } 326# endif DEBUG 327 continue; 328 } 329 npe->value = nbuf.n_value; 330 npe->name = strtab+nbuf.n_un.n_strx; 331# ifdef DEBUG 332 if ( debug & AOUTDEBUG ) { 333 printf( "[getsymtab] %d %s 0x%08x\n" , 334 nname , npe -> name , npe -> value ); 335 } 336# endif DEBUG 337 npe++; 338 nname++; 339 } 340 npe->value = -1; 341} 342 343 /* 344 * read in the text space of an a.out file 345 */ 346gettextspace( nfile ) 347 FILE *nfile; 348{ 349 350 if ( cflag == 0 ) { 351 return; 352 } 353 textspace = (u_char *) malloc( xbuf.a_text ); 354 if ( textspace == 0 ) { 355 fprintf( stderr , "%s: ran out room for %d bytes of text space: " , 356 whoami , xbuf.a_text ); 357 fprintf( stderr , "can't do -c\n" ); 358 return; 359 } 360 (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 361 if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 362 fprintf( stderr , "%s: couldn't read text space: " , whoami ); 363 fprintf( stderr , "can't do -c\n" ); 364 free( textspace ); 365 textspace = 0; 366 return; 367 } 368} 369 /* 370 * information from a gmon.out file is in two parts: 371 * an array of sampling hits within pc ranges, 372 * and the arcs. 373 */ 374getpfile(filename) 375 char *filename; 376{ 377 FILE *pfile; 378 FILE *openpfile(); 379 struct rawarc arc; 380 381 pfile = openpfile(filename); 382 readsamples(pfile); 383 /* 384 * the rest of the file consists of 385 * a bunch of <from,self,count> tuples. 386 */ 387 while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 388# ifdef DEBUG 389 if ( debug & SAMPLEDEBUG ) { 390 printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 391 arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 392 } 393# endif DEBUG 394 /* 395 * add this arc 396 */ 397 tally( &arc ); 398 } 399 fclose(pfile); 400} 401 402FILE * 403openpfile(filename) 404 char *filename; 405{ 406 struct gmonhdr tmp; 407 FILE *pfile; 408 int size; 409 int rate; 410 411 if((pfile = fopen(filename, "r")) == NULL) { 412 perror(filename); 413 done(); 414 } 415 fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 416 if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 417 tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { 418 fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 419 done(); 420 } 421 gmonhdr = tmp; 422 if ( gmonhdr.version == GMONVERSION ) { 423 rate = gmonhdr.profrate; 424 size = sizeof(struct gmonhdr); 425 } else { 426 fseek(pfile, sizeof(struct ophdr), SEEK_SET); 427 size = sizeof(struct ophdr); 428 gmonhdr.profrate = rate = hertz(); 429 gmonhdr.version = GMONVERSION; 430 } 431 if (hz == 0) { 432 hz = rate; 433 } else if (hz != rate) { 434 fprintf(stderr, 435 "%s: profile clock rate (%d) %s (%d) in first gmon file\n", 436 filename, rate, "incompatible with clock rate", hz); 437 done(); 438 } 439 s_lowpc = (unsigned long) gmonhdr.lpc; 440 s_highpc = (unsigned long) gmonhdr.hpc; 441 lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT); 442 highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT); 443 sampbytes = gmonhdr.ncnt - size; 444 nsamples = sampbytes / sizeof (UNIT); 445# ifdef DEBUG 446 if ( debug & SAMPLEDEBUG ) { 447 printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n", 448 gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 449 printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , 450 s_lowpc , s_highpc ); 451 printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , 452 lowpc , highpc ); 453 printf( "[openpfile] sampbytes %d nsamples %d\n" , 454 sampbytes , nsamples ); 455 printf( "[openpfile] sample rate %d\n" , hz ); 456 } 457# endif DEBUG 458 return(pfile); 459} 460 461tally( rawp ) 462 struct rawarc *rawp; 463{ 464 nltype *parentp; 465 nltype *childp; 466 467 parentp = nllookup( rawp -> raw_frompc ); 468 childp = nllookup( rawp -> raw_selfpc ); 469 if ( parentp == 0 || childp == 0 ) 470 return; 471 if ( kflag 472 && onlist( kfromlist , parentp -> name ) 473 && onlist( ktolist , childp -> name ) ) { 474 return; 475 } 476 childp -> ncall += rawp -> raw_count; 477# ifdef DEBUG 478 if ( debug & TALLYDEBUG ) { 479 printf( "[tally] arc from %s to %s traversed %d times\n" , 480 parentp -> name , childp -> name , rawp -> raw_count ); 481 } 482# endif DEBUG 483 addarc( parentp , childp , rawp -> raw_count ); 484} 485 486/* 487 * dump out the gmon.sum file 488 */ 489dumpsum( sumfile ) 490 char *sumfile; 491{ 492 register nltype *nlp; 493 register arctype *arcp; 494 struct rawarc arc; 495 FILE *sfile; 496 497 if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 498 perror( sumfile ); 499 done(); 500 } 501 /* 502 * dump the header; use the last header read in 503 */ 504 if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { 505 perror( sumfile ); 506 done(); 507 } 508 /* 509 * dump the samples 510 */ 511 if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) { 512 perror( sumfile ); 513 done(); 514 } 515 /* 516 * dump the normalized raw arc information 517 */ 518 for ( nlp = nl ; nlp < npe ; nlp++ ) { 519 for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 520 arc.raw_frompc = arcp -> arc_parentp -> value; 521 arc.raw_selfpc = arcp -> arc_childp -> value; 522 arc.raw_count = arcp -> arc_count; 523 if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 524 perror( sumfile ); 525 done(); 526 } 527# ifdef DEBUG 528 if ( debug & SAMPLEDEBUG ) { 529 printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 530 arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 531 } 532# endif DEBUG 533 } 534 } 535 fclose( sfile ); 536} 537 538valcmp(p1, p2) 539 nltype *p1, *p2; 540{ 541 if ( p1 -> value < p2 -> value ) { 542 return LESSTHAN; 543 } 544 if ( p1 -> value > p2 -> value ) { 545 return GREATERTHAN; 546 } 547 return EQUALTO; 548} 549 550readsamples(pfile) 551 FILE *pfile; 552{ 553 register i; 554 UNIT sample; 555 556 if (samples == 0) { 557 samples = (UNIT *) calloc(sampbytes, sizeof (UNIT)); 558 if (samples == 0) { 559 fprintf( stderr , "%s: No room for %d sample pc's\n", 560 whoami , sampbytes / sizeof (UNIT)); 561 done(); 562 } 563 } 564 for (i = 0; i < nsamples; i++) { 565 fread(&sample, sizeof (UNIT), 1, pfile); 566 if (feof(pfile)) 567 break; 568 samples[i] += sample; 569 } 570 if (i != nsamples) { 571 fprintf(stderr, 572 "%s: unexpected EOF after reading %d/%d samples\n", 573 whoami , --i , nsamples ); 574 done(); 575 } 576} 577 578/* 579 * Assign samples to the procedures to which they belong. 580 * 581 * There are three cases as to where pcl and pch can be 582 * with respect to the routine entry addresses svalue0 and svalue1 583 * as shown in the following diagram. overlap computes the 584 * distance between the arrows, the fraction of the sample 585 * that is to be credited to the routine which starts at svalue0. 586 * 587 * svalue0 svalue1 588 * | | 589 * v v 590 * 591 * +-----------------------------------------------+ 592 * | | 593 * | ->| |<- ->| |<- ->| |<- | 594 * | | | | | | 595 * +---------+ +---------+ +---------+ 596 * 597 * ^ ^ ^ ^ ^ ^ 598 * | | | | | | 599 * pcl pch pcl pch pcl pch 600 * 601 * For the vax we assert that samples will never fall in the first 602 * two bytes of any routine, since that is the entry mask, 603 * thus we give call alignentries() to adjust the entry points if 604 * the entry mask falls in one bucket but the code for the routine 605 * doesn't start until the next bucket. In conjunction with the 606 * alignment of routine addresses, this should allow us to have 607 * only one sample for every four bytes of text space and never 608 * have any overlap (the two end cases, above). 609 */ 610asgnsamples() 611{ 612 register int j; 613 UNIT ccnt; 614 double time; 615 unsigned long pcl, pch; 616 register int i; 617 unsigned long overlap; 618 unsigned long svalue0, svalue1; 619 620 /* read samples and assign to namelist symbols */ 621 scale = highpc - lowpc; 622 scale /= nsamples; 623 alignentries(); 624 for (i = 0, j = 1; i < nsamples; i++) { 625 ccnt = samples[i]; 626 if (ccnt == 0) 627 continue; 628 pcl = lowpc + scale * i; 629 pch = lowpc + scale * (i + 1); 630 time = ccnt; 631# ifdef DEBUG 632 if ( debug & SAMPLEDEBUG ) { 633 printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 634 pcl , pch , ccnt ); 635 } 636# endif DEBUG 637 totime += time; 638 for (j = j - 1; j < nname; j++) { 639 svalue0 = nl[j].svalue; 640 svalue1 = nl[j+1].svalue; 641 /* 642 * if high end of tick is below entry address, 643 * go for next tick. 644 */ 645 if (pch < svalue0) 646 break; 647 /* 648 * if low end of tick into next routine, 649 * go for next routine. 650 */ 651 if (pcl >= svalue1) 652 continue; 653 overlap = min(pch, svalue1) - max(pcl, svalue0); 654 if (overlap > 0) { 655# ifdef DEBUG 656 if (debug & SAMPLEDEBUG) { 657 printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n", 658 nl[j].value/sizeof(UNIT), svalue0, svalue1, 659 nl[j].name, 660 overlap * time / scale, overlap); 661 } 662# endif DEBUG 663 nl[j].time += overlap * time / scale; 664 } 665 } 666 } 667# ifdef DEBUG 668 if (debug & SAMPLEDEBUG) { 669 printf("[asgnsamples] totime %f\n", totime); 670 } 671# endif DEBUG 672} 673 674 675unsigned long 676min(a, b) 677 unsigned long a,b; 678{ 679 if (a<b) 680 return(a); 681 return(b); 682} 683 684unsigned long 685max(a, b) 686 unsigned long a,b; 687{ 688 if (a>b) 689 return(a); 690 return(b); 691} 692 693 /* 694 * calculate scaled entry point addresses (to save time in asgnsamples), 695 * and possibly push the scaled entry points over the entry mask, 696 * if it turns out that the entry point is in one bucket and the code 697 * for a routine is in the next bucket. 698 */ 699alignentries() 700{ 701 register struct nl *nlp; 702 unsigned long bucket_of_entry; 703 unsigned long bucket_of_code; 704 705 for (nlp = nl; nlp < npe; nlp++) { 706 nlp -> svalue = nlp -> value / sizeof(UNIT); 707 bucket_of_entry = (nlp->svalue - lowpc) / scale; 708 bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; 709 if (bucket_of_entry < bucket_of_code) { 710# ifdef DEBUG 711 if (debug & SAMPLEDEBUG) { 712 printf("[alignentries] pushing svalue 0x%x to 0x%x\n", 713 nlp->svalue, nlp->svalue + UNITS_TO_CODE); 714 } 715# endif DEBUG 716 nlp->svalue += UNITS_TO_CODE; 717 } 718 } 719} 720 721bool 722funcsymbol( nlistp ) 723 struct nlist *nlistp; 724{ 725 char *name, c; 726 727 /* 728 * must be a text symbol, 729 * and static text symbols don't qualify if aflag set. 730 */ 731 if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 732 || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 733 return FALSE; 734 } 735 /* 736 * name must start with an underscore if uflag is set. 737 * can't have any `funny' characters in name, 738 * where `funny' includes `.', .o file names 739 * and `$', pascal labels. 740 * need to make an exception for sparc .mul & co. 741 * perhaps we should just drop this code entirely... 742 */ 743 name = strtab + nlistp -> n_un.n_strx; 744 if ( uflag && *name != '_' ) 745 return FALSE; 746#ifdef sparc 747 if ( *name == '.' ) { 748 char *p = name + 1; 749 if ( *p == 'u' ) 750 p++; 751 if ( strcmp ( p, "mul" ) == 0 || strcmp ( p, "div" ) == 0 || 752 strcmp ( p, "rem" ) == 0 ) 753 return TRUE; 754 } 755#endif 756 while ( c = *name++ ) { 757 if ( c == '.' || c == '$' ) { 758 return FALSE; 759 } 760 } 761 return TRUE; 762} 763 764done() 765{ 766 767 exit(0); 768} 769