1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Copyright 2018 Jason King
  27  * Copyright 2018, Joyent, Inc.
  28  */
  29 
  30 #include <ctype.h>
  31 #include <string.h>
  32 #include <sys/param.h>
  33 #include <stdlib.h>
  34 #include "conv.h"
  35 #include "gprof.h"
  36 
  37 void print_demangled_name(int, nltype *);
  38 static void stripped_name(char **, size_t *, nltype **);
  39 
  40 extern long hz;
  41 
  42 /*
  43  * Symbols that must never be printed, no matter what.
  44  */
  45 char *splsym[] = {
  46         PRF_ETEXT,
  47         PRF_EXTSYM,
  48         PRF_MEMTERM,
  49         NULL
  50 };
  51 
  52 static bool is_special_sym(nltype *nlp);
  53 
  54 const char *
  55 demangled_name(nltype *selfp)
  56 {
  57         if (!Cflag)
  58                 return (selfp->name);
  59 
  60         return (conv_demangle_name(selfp->name));
  61 }
  62 
  63 void
  64 printprof(void)
  65 {
  66         nltype  *np;
  67         nltype  **sortednlp;
  68         int     i, index;
  69         int     print_count = number_funcs_toprint;
  70         bool    print_flag = TRUE;
  71         mod_info_t      *mi;
  72 
  73         actime = 0.0;
  74         (void) printf("\f\n");
  75         flatprofheader();
  76 
  77         /*
  78          *      Sort the symbol table in by time
  79          */
  80         sortednlp = (nltype **) calloc(total_names, sizeof (nltype *));
  81         if (sortednlp == (nltype **) 0) {
  82                 (void) fprintf(stderr,
  83                     "[printprof] ran out of memory for time sorting\n");
  84         }
  85 
  86         index = 0;
  87         for (mi = &modules; mi; mi = mi->next) {
  88                 for (i = 0; i < mi->nname; i++)
  89                         sortednlp[index++] = &(mi->nl[i]);
  90         }
  91 
  92         qsort(sortednlp, total_names, sizeof (nltype *), timecmp);
  93 
  94         for (index = 0; (index < total_names) && print_flag; index += 1) {
  95                 np = sortednlp[index];
  96                 flatprofline(np);
  97                 if (nflag) {
  98                         if (--print_count == 0)
  99                                 print_flag = FALSE;
 100                 }
 101         }
 102         actime = 0.0;
 103         free(sortednlp);
 104 }
 105 
 106 int
 107 timecmp(const void *arg1, const void *arg2)
 108 {
 109         nltype **npp1 = (nltype **)arg1;
 110         nltype **npp2 = (nltype **)arg2;
 111         double  timediff;
 112         long    calldiff;
 113 
 114         timediff = (*npp2)->time - (*npp1)->time;
 115 
 116         if (timediff > 0.0)
 117                 return (1);
 118 
 119         if (timediff < 0.0)
 120                 return (-1);
 121 
 122         calldiff = (*npp2)->ncall - (*npp1)->ncall;
 123 
 124         if (calldiff > 0)
 125                 return (1);
 126 
 127         if (calldiff < 0)
 128                 return (-1);
 129 
 130         return (strcmp((*npp1)->name, (*npp2)->name));
 131 }
 132 
 133 /*
 134  *      header for flatprofline
 135  */
 136 void
 137 flatprofheader()
 138 {
 139 
 140         if (bflag)
 141                 printblurb(FLAT_BLURB);
 142 
 143         if (old_style) {
 144                 (void) printf(
 145                     "\ngranularity: each sample hit covers %d byte(s)",
 146                     (long)scale * sizeof (UNIT));
 147                 if (totime > 0.0) {
 148                         (void) printf(" for %.2f%% of %.2f seconds\n\n",
 149                             100.0/totime, totime / hz);
 150                 } else {
 151                         (void) printf(" no time accumulated\n\n");
 152                         /*
 153                          * this doesn't hurt since all the numerators will
 154                          * be zero.
 155                          */
 156                         totime = 1.0;
 157                 }
 158         }
 159 
 160         (void) printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
 161             "% ", "cumulative", "self ", "", "self ", "total ", "");
 162         (void) printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
 163             "time", "seconds ", "seconds", "calls",
 164             "ms/call", "ms/call", "name");
 165 }
 166 
 167 void
 168 flatprofline(nltype *np)
 169 {
 170         if (zflag == 0 && np->ncall == 0 && np->time == 0)
 171                 return;
 172 
 173         /*
 174          * Do not print certain special symbols, like PRF_EXTSYM, etc.
 175          * even if zflag was on.
 176          */
 177         if (is_special_sym(np))
 178                 return;
 179 
 180         actime += np->time;
 181 
 182         (void) printf("%5.1f %10.2f %8.2f",
 183             100 * np->time / totime, actime / hz, np->time / hz);
 184 
 185         if (np->ncall != 0) {
 186                 (void) printf(" %8lld %8.2f %8.2f  ", np->ncall,
 187                     1000 * np->time / hz / np->ncall,
 188                     1000 * (np->time + np->childtime) / hz / np->ncall);
 189         } else {
 190                 if (!Cflag)
 191                         (void) printf(" %8.8s %8.8s %8.8s ", "", "", "");
 192                 else
 193                         (void) printf(" %8.8s %8.8s %8.8s  ", "", "", "");
 194         }
 195 
 196         printname(np);
 197 
 198         if (Cflag)
 199                 print_demangled_name(55, np);
 200 
 201         (void) printf("\n");
 202 }
 203 
 204 void
 205 gprofheader()
 206 {
 207 
 208         if (bflag)
 209                 printblurb(CALLG_BLURB);
 210 
 211         if (old_style) {
 212 
 213                 (void) printf(
 214                     "\ngranularity: each sample hit covers %d byte(s)",
 215                     (long)scale * sizeof (UNIT));
 216 
 217                 if (printtime > 0.0) {
 218                         (void) printf(" for %.2f%% of %.2f seconds\n\n",
 219                             100.0/printtime, printtime / hz);
 220                 } else {
 221                         (void) printf(" no time propagated\n\n");
 222                         /*
 223                          * this doesn't hurt, since all the numerators
 224                          * will be 0.0
 225                          */
 226                         printtime = 1.0;
 227                 }
 228         } else {
 229                 (void) printf(
 230                     "\ngranularity: each pc-hit is considered 1 tick");
 231                 if (hz != 1) {
 232                         (void) printf(" (@ %4.3f seconds per tick)",
 233                             (double)1.0 / hz);
 234                 }
 235                 (void) puts("\n\n");
 236         }
 237 
 238         (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n",
 239             "", "", "", "", "called", "total", "parents");
 240         (void) printf("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n",
 241             "index", "%time", "self", "descendents",
 242             "called", "self", "name", "index");
 243         (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n",
 244             "", "", "", "", "called", "total", "children");
 245         (void) printf("\n");
 246 }
 247 
 248 void
 249 gprofline(nltype *np)
 250 {
 251         char    kirkbuffer[BUFSIZ];
 252 
 253         (void) sprintf(kirkbuffer, "[%d]", np->index);
 254         (void) printf("%-6.6s %5.1f %7.2f %11.2f", kirkbuffer,
 255             100 * (np->propself + np->propchild) / printtime,
 256             np->propself / hz, np->propchild / hz);
 257 
 258         if ((np->ncall + np->selfcalls) != 0) {
 259                 (void) printf(" %7lld", np->ncall);
 260 
 261                 if (np->selfcalls != 0)
 262                         (void) printf("+%-7lld ", np->selfcalls);
 263                 else
 264                         (void) printf(" %7.7s ", "");
 265         } else {
 266                 (void) printf(" %7.7s %7.7s ", "", "");
 267         }
 268 
 269         printname(np);
 270 
 271         if (Cflag)
 272                 print_demangled_name(50, np);
 273 
 274         (void) printf("\n");
 275 }
 276 
 277 static bool
 278 is_special_sym(nltype *nlp)
 279 {
 280         int     i;
 281 
 282         if (nlp->name == NULL)
 283                 return (FALSE);
 284 
 285         for (i = 0;  splsym[i]; i++)
 286                 if (strcmp(splsym[i], nlp->name) == 0)
 287                         return (TRUE);
 288 
 289         return (FALSE);
 290 }
 291 
 292 void
 293 printgprof(nltype **timesortnlp)
 294 {
 295         int     index;
 296         nltype  *parentp;
 297         int     print_count = number_funcs_toprint;
 298         bool    count_flag = TRUE;
 299 
 300         /*
 301          * Print out the structured profiling list
 302          */
 303         gprofheader();
 304 
 305         for (index = 0; index < total_names + ncycle && count_flag; index++) {
 306                 parentp = timesortnlp[index];
 307                 if (zflag == 0 && parentp->ncall == 0 &&
 308                     parentp->selfcalls == 0 && parentp->propself == 0 &&
 309                     parentp -> propchild == 0)
 310                         continue;
 311 
 312                 if (!parentp->printflag)
 313                         continue;
 314 
 315                 /*
 316                  * Do not print certain special symbols, like PRF_EXTSYM, etc.
 317                  * even if zflag was on.
 318                  */
 319                 if (is_special_sym(parentp))
 320                         continue;
 321 
 322                 if (parentp->name == 0 && parentp->cycleno != 0) {
 323                         /*
 324                          *      cycle header
 325                          */
 326                         printcycle(parentp);
 327                         printmembers(parentp);
 328                 } else {
 329                         printparents(parentp);
 330                         gprofline(parentp);
 331                         printchildren(parentp);
 332                 }
 333 
 334                 (void) printf("\n");
 335                 (void) printf(
 336                     "-----------------------------------------------\n");
 337                 (void) printf("\n");
 338 
 339                 if (nflag) {
 340                         --print_count;
 341                         if (print_count == 0)
 342                                 count_flag = FALSE;
 343                 }
 344         }
 345         free(timesortnlp);
 346 }
 347 
 348 /*
 349  *      sort by decreasing propagated time
 350  *      if times are equal, but one is a cycle header,
 351  *              say that's first (e.g. less, i.e. -1).
 352  *      if one's name doesn't have an underscore and the other does,
 353  *              say the one is first.
 354  *      all else being equal, sort by names.
 355  */
 356 int
 357 totalcmp(const void *arg1, const void *arg2)
 358 {
 359         nltype **npp1 = (nltype **)arg1;
 360         nltype **npp2 = (nltype **)arg2;
 361         nltype  *np1 = *npp1;
 362         nltype  *np2 = *npp2;
 363         double  diff;
 364 
 365         diff = (np1->propself + np1->propchild) -
 366             (np2->propself + np2->propchild);
 367 
 368         if (diff < 0.0)
 369                 return (1);
 370         if (diff > 0.0)
 371                 return (-1);
 372         if (np1->name == 0 && np1->cycleno != 0)
 373                 return (-1);
 374         if (np2->name == 0 && np2->cycleno != 0)
 375                 return (1);
 376         if (np1->name == 0)
 377                 return (-1);
 378         if (np2->name == 0)
 379                 return (1);
 380 
 381         if (*(np1->name) != '_' && *(np2->name) == '_')
 382                 return (-1);
 383         if (*(np1->name) == '_' && *(np2->name) != '_')
 384                 return (1);
 385         if (np1->ncall > np2->ncall)
 386                 return (-1);
 387         if (np1->ncall < np2->ncall)
 388                 return (1);
 389         return (strcmp(np1->name, np2->name));
 390 }
 391 
 392 void
 393 printparents(nltype *childp)
 394 {
 395         nltype  *parentp;
 396         arctype *arcp;
 397         nltype  *cycleheadp;
 398 
 399         if (childp->cyclehead != 0)
 400                 cycleheadp = childp -> cyclehead;
 401         else
 402                 cycleheadp = childp;
 403 
 404         if (childp->parents == 0) {
 405                 (void) printf("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s"
 406                     "     <spontaneous>\n", "", "", "", "", "", "");
 407                 return;
 408         }
 409 
 410         sortparents(childp);
 411 
 412         for (arcp = childp->parents; arcp; arcp = arcp->arc_parentlist) {
 413                 parentp = arcp -> arc_parentp;
 414                 if (childp == parentp || (childp->cycleno != 0 &&
 415                     parentp->cycleno == childp->cycleno)) {
 416                         /*
 417                          *      selfcall or call among siblings
 418                          */
 419                         (void) printf(
 420                             "%6.6s %5.5s %7.7s %11.11s %7lld %7.7s     ",
 421                             "", "", "", "", arcp->arc_count, "");
 422                         printname(parentp);
 423 
 424                         if (Cflag)
 425                                 print_demangled_name(54, parentp);
 426 
 427                         (void) printf("\n");
 428                 } else {
 429                         /*
 430                          *      regular parent of child
 431                          */
 432                         (void) printf(
 433                             "%6.6s %5.5s %7.2f %11.2f %7lld/%-7lld     ", "",
 434                             "", arcp->arc_time / hz, arcp->arc_childtime / hz,
 435                             arcp->arc_count, cycleheadp->ncall);
 436                         printname(parentp);
 437 
 438                         if (Cflag)
 439                                 print_demangled_name(54, parentp);
 440 
 441                         (void) printf("\n");
 442                 }
 443         }
 444 }
 445 
 446 void
 447 printchildren(nltype *parentp)
 448 {
 449         nltype  *childp;
 450         arctype *arcp;
 451 
 452         sortchildren(parentp);
 453 
 454         for (arcp = parentp->children; arcp; arcp = arcp->arc_childlist) {
 455                 childp = arcp->arc_childp;
 456                 if (childp == parentp || (childp->cycleno != 0 &&
 457                     childp->cycleno == parentp->cycleno)) {
 458                         /*
 459                          * self call or call to sibling
 460                          */
 461                         (void) printf(
 462                             "%6.6s %5.5s %7.7s %11.11s %7lld %7.7s     ",
 463                             "", "", "", "", arcp->arc_count, "");
 464                         printname(childp);
 465 
 466                         if (Cflag)
 467                                 print_demangled_name(54, childp);
 468 
 469                         (void) printf("\n");
 470                 } else {
 471                         /*
 472                          *      regular child of parent
 473                          */
 474                         if (childp->cyclehead)
 475                                 (void) printf("%6.6s %5.5s %7.2f %11.2f "
 476                                     "%7lld/%-7lld     ", "", "",
 477                                     arcp->arc_time / hz,
 478                                     arcp->arc_childtime / hz, arcp->arc_count,
 479                                     childp->cyclehead->ncall);
 480                         else
 481                                 (void) printf("%6.6s %5.5s %7.2f %11.2f "
 482                                     "%7lld %7.7s    ",
 483                                     "", "", arcp->arc_time / hz,
 484                                     arcp->arc_childtime / hz, arcp->arc_count,
 485                                     "");
 486 
 487                         printname(childp);
 488 
 489                         if (Cflag)
 490                                 print_demangled_name(54, childp);
 491 
 492                         (void) printf("\n");
 493                 }
 494         }
 495 }
 496 
 497 void
 498 printname(nltype *selfp)
 499 {
 500         const char  *c;
 501         c = demangled_name(selfp);
 502 
 503         if (selfp->name != 0) {
 504                 (void) printf("%s", c);
 505 
 506 #ifdef DEBUG
 507                 if (debug & DFNDEBUG)
 508                         (void) printf("{%d} ", selfp->toporder);
 509 
 510                 if (debug & PROPDEBUG)
 511                         (void) printf("%5.2f%% ", selfp->propfraction);
 512 #endif /* DEBUG */
 513         }
 514 
 515         if (selfp->cycleno != 0)
 516                 (void) printf("\t<cycle %d>", selfp->cycleno);
 517 
 518         if (selfp->index != 0) {
 519                 if (selfp->printflag)
 520                         (void) printf(" [%d]", selfp->index);
 521                 else
 522                         (void) printf(" (%d)", selfp->index);
 523         }
 524 
 525         if (c != selfp->name)
 526                 free((void *)c);
 527 }
 528 
 529 void
 530 print_demangled_name(int n, nltype *selfp)
 531 {
 532         char *c = (char *)demangled_name(selfp);
 533         int i;
 534 
 535         if (c == selfp->name)
 536                 return;
 537 
 538         (void) printf("\n");
 539         for (i = 1; i < n; i++)
 540                 (void) printf(" ");
 541         (void) printf("[%s]", selfp->name);
 542 
 543         free(c);
 544 }
 545 
 546 void
 547 sortchildren(nltype *parentp)
 548 {
 549         arctype *arcp;
 550         arctype *detachedp;
 551         arctype sorted;
 552         arctype *prevp;
 553 
 554         /*
 555          *      unlink children from parent,
 556          *      then insertion sort back on to sorted's children.
 557          *          *arcp       the arc you have detached and are inserting.
 558          *          *detachedp  the rest of the arcs to be sorted.
 559          *          sorted      arc list onto which you insertion sort.
 560          *          *prevp      arc before the arc you are comparing.
 561          */
 562         sorted.arc_childlist = 0;
 563 
 564         /* LINTED: warning: assignment operator */
 565         for ((arcp = parentp->children) && (detachedp = arcp->arc_childlist);
 566             arcp;
 567             /* LINTED: warning: assignment operator */
 568             (arcp = detachedp) && (detachedp = detachedp->arc_childlist)) {
 569                 /*
 570                  *      consider *arcp as disconnected
 571                  *      insert it into sorted
 572                  */
 573                 for (prevp = &sorted; prevp->arc_childlist;
 574                     prevp = prevp->arc_childlist) {
 575                         if (arccmp(arcp, prevp->arc_childlist) != LESSTHAN)
 576                                 break;
 577                 }
 578 
 579                 arcp->arc_childlist = prevp->arc_childlist;
 580                 prevp->arc_childlist = arcp;
 581         }
 582 
 583         /*
 584          *      reattach sorted children to parent
 585          */
 586         parentp->children = sorted.arc_childlist;
 587 }
 588 
 589 void
 590 sortparents(nltype *childp)
 591 {
 592         arctype *arcp;
 593         arctype *detachedp;
 594         arctype sorted;
 595         arctype *prevp;
 596 
 597         /*
 598          *      unlink parents from child,
 599          *      then insertion sort back on to sorted's parents.
 600          *          *arcp       the arc you have detached and are inserting.
 601          *          *detachedp  the rest of the arcs to be sorted.
 602          *          sorted      arc list onto which you insertion sort.
 603          *          *prevp      arc before the arc you are comparing.
 604          */
 605         sorted.arc_parentlist = 0;
 606 
 607         /* LINTED: warning: assignment operator */
 608         for ((arcp = childp->parents) && (detachedp = arcp->arc_parentlist);
 609             arcp;
 610             /* LINTED: warning: assignment operator */
 611             (arcp = detachedp) && (detachedp = detachedp->arc_parentlist)) {
 612                 /*
 613                  *      consider *arcp as disconnected
 614                  *      insert it into sorted
 615                  */
 616                 for (prevp = &sorted; prevp->arc_parentlist;
 617                     prevp = prevp->arc_parentlist) {
 618                         if (arccmp(arcp, prevp->arc_parentlist) != GREATERTHAN)
 619                                 break;
 620                 }
 621                 arcp->arc_parentlist = prevp->arc_parentlist;
 622                 prevp->arc_parentlist = arcp;
 623         }
 624 
 625         /*
 626          *      reattach sorted arcs to child
 627          */
 628         childp->parents = sorted.arc_parentlist;
 629 }
 630 
 631 void
 632 printcycle(nltype *cyclep)
 633 {
 634         char    kirkbuffer[BUFSIZ];
 635 
 636         (void) sprintf(kirkbuffer, "[%d]", cyclep->index);
 637         (void) printf("%-6.6s %5.1f %7.2f %11.2f %7lld", kirkbuffer,
 638             100 * (cyclep->propself + cyclep->propchild) / printtime,
 639             cyclep -> propself / hz, cyclep -> propchild / hz,
 640             cyclep -> ncall);
 641 
 642         if (cyclep->selfcalls != 0)
 643                 (void) printf("+%-7lld", cyclep->selfcalls);
 644         else
 645                 (void) printf(" %7.7s", "");
 646 
 647         (void) printf(" <cycle %d as a whole>\t[%d]\n", cyclep->cycleno,
 648             cyclep->index);
 649 }
 650 
 651 /*
 652  *      print the members of a cycle
 653  */
 654 void
 655 printmembers(nltype *cyclep)
 656 {
 657         nltype  *memberp;
 658 
 659         sortmembers(cyclep);
 660 
 661         for (memberp = cyclep->cnext; memberp; memberp = memberp->cnext) {
 662                 (void) printf("%6.6s %5.5s %7.2f %11.2f %7lld", "", "",
 663                     memberp->propself / hz, memberp->propchild / hz,
 664                     memberp->ncall);
 665 
 666                 if (memberp->selfcalls != 0)
 667                         (void) printf("+%-7lld", memberp->selfcalls);
 668                 else
 669                         (void) printf(" %7.7s", "");
 670 
 671                 (void) printf("     ");
 672                 printname(memberp);
 673                 if (Cflag)
 674                         print_demangled_name(54, memberp);
 675                 (void) printf("\n");
 676         }
 677 }
 678 
 679 /*
 680  * sort members of a cycle
 681  */
 682 void
 683 sortmembers(nltype *cyclep)
 684 {
 685         nltype  *todo;
 686         nltype  *doing;
 687         nltype  *prev;
 688 
 689         /*
 690          *      detach cycle members from cyclehead,
 691          *      and insertion sort them back on.
 692          */
 693         todo = cyclep->cnext;
 694         cyclep->cnext = 0;
 695 
 696         /* LINTED: warning: assignment operator */
 697         for ((doing = todo) && (todo = doing->cnext);
 698             doing;
 699             /* LINTED: warning: assignment operator */
 700             (doing = todo) && (todo = doing->cnext)) {
 701                 for (prev = cyclep; prev->cnext; prev = prev->cnext) {
 702                         if (membercmp(doing, prev->cnext) == GREATERTHAN)
 703                                 break;
 704                 }
 705                 doing->cnext = prev->cnext;
 706                 prev->cnext = doing;
 707         }
 708 }
 709 
 710 /*
 711  *      major sort is on propself + propchild,
 712  *      next is sort on ncalls + selfcalls.
 713  */
 714 int
 715 membercmp(nltype *this, nltype *that)
 716 {
 717         double  thistime = this->propself + this->propchild;
 718         double  thattime = that->propself + that->propchild;
 719         actype  thiscalls = this->ncall + this->selfcalls;
 720         actype  thatcalls = that->ncall + that->selfcalls;
 721 
 722         if (thistime > thattime)
 723                 return (GREATERTHAN);
 724 
 725         if (thistime < thattime)
 726                 return (LESSTHAN);
 727 
 728         if (thiscalls > thatcalls)
 729                 return (GREATERTHAN);
 730 
 731         if (thiscalls < thatcalls)
 732                 return (LESSTHAN);
 733 
 734         return (EQUALTO);
 735 }
 736 
 737 /*
 738  *      compare two arcs to/from the same child/parent.
 739  *      - if one arc is a self arc, it's least.
 740  *      - if one arc is within a cycle, it's less than.
 741  *      - if both arcs are within a cycle, compare arc counts.
 742  *      - if neither arc is within a cycle, compare with
 743  *              arc_time + arc_childtime as major key
 744  *              arc count as minor key
 745  */
 746 int
 747 arccmp(arctype *thisp, arctype *thatp)
 748 {
 749         nltype  *thisparentp = thisp->arc_parentp;
 750         nltype  *thischildp = thisp->arc_childp;
 751         nltype  *thatparentp = thatp->arc_parentp;
 752         nltype  *thatchildp = thatp->arc_childp;
 753         double  thistime;
 754         double  thattime;
 755 
 756 #ifdef DEBUG
 757         if (debug & TIMEDEBUG) {
 758                 (void) printf("[arccmp] ");
 759                 printname(thisparentp);
 760                 (void) printf(" calls ");
 761                 printname(thischildp);
 762                 (void) printf(" %f + %f %lld/%lld\n", thisp->arc_time,
 763                     thisp->arc_childtime, thisp->arc_count,
 764                     thischildp->ncall);
 765                 (void) printf("[arccmp] ");
 766                 printname(thatparentp);
 767                 (void) printf(" calls ");
 768                 printname(thatchildp);
 769                 (void) printf(" %f + %f %lld/%lld\n", thatp->arc_time,
 770                     thatp->arc_childtime, thatp->arc_count,
 771                     thatchildp->ncall);
 772                 (void) printf("\n");
 773         }
 774 #endif /* DEBUG */
 775 
 776         if (thisparentp == thischildp) {
 777                 /*
 778                  * this is a self call
 779                  */
 780                 return (LESSTHAN);
 781         }
 782 
 783         if (thatparentp == thatchildp) {
 784                 /*
 785                  * that is a self call
 786                  */
 787                 return (GREATERTHAN);
 788         }
 789 
 790         if (thisparentp->cycleno != 0 && thischildp->cycleno != 0 &&
 791             thisparentp->cycleno == thischildp->cycleno) {
 792                 /*
 793                  * this is a call within a cycle
 794                  */
 795                 if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 &&
 796                     thatparentp->cycleno == thatchildp->cycleno) {
 797                         /*
 798                          * that is a call within the cycle, too
 799                          */
 800                         if (thisp->arc_count < thatp->arc_count)
 801                                 return (LESSTHAN);
 802 
 803                         if (thisp->arc_count > thatp->arc_count)
 804                                 return (GREATERTHAN);
 805 
 806                         return (EQUALTO);
 807                 } else {
 808                         /*
 809                          * that isn't a call within the cycle
 810                          */
 811                         return (LESSTHAN);
 812                 }
 813         } else {
 814                 /*
 815                  * this isn't a call within a cycle
 816                  */
 817                 if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 &&
 818                     thatparentp->cycleno == thatchildp->cycleno) {
 819                         /*
 820                          * that is a call within a cycle
 821                          */
 822                         return (GREATERTHAN);
 823                 } else {
 824                         /*
 825                          * neither is a call within a cycle
 826                          */
 827                         thistime = thisp->arc_time + thisp->arc_childtime;
 828                         thattime = thatp->arc_time + thatp->arc_childtime;
 829 
 830                         if (thistime < thattime)
 831                                 return (LESSTHAN);
 832 
 833                         if (thistime > thattime)
 834                                 return (GREATERTHAN);
 835 
 836                         if (thisp->arc_count < thatp->arc_count)
 837                                 return (LESSTHAN);
 838 
 839                         if (thisp->arc_count > thatp->arc_count)
 840                                 return (GREATERTHAN);
 841 
 842                         return (EQUALTO);
 843                 }
 844         }
 845 }
 846 
 847 void
 848 printblurb(char *blurbname)
 849 {
 850         FILE    *blurbfile;
 851         int     input;
 852 
 853         blurbfile = fopen(blurbname, "r");
 854         if (blurbfile == NULL) {
 855                 perror(blurbname);
 856                 return;
 857         }
 858 
 859         while ((input = getc(blurbfile)) != EOF)
 860                 (void) putchar(input);
 861 
 862         (void) fclose(blurbfile);
 863 }
 864 
 865 static int
 866 namecmp(const void *arg1, const void *arg2)
 867 {
 868         nltype **npp1 = (nltype **)arg1;
 869         nltype **npp2 = (nltype **)arg2;
 870 
 871         if (!Cflag)
 872                 return (strcmp((*npp1)->name, (*npp2)->name));
 873         else {
 874                 static char *s1 = NULL, *s2 = NULL;
 875                 static size_t s1len = 0, s2len = 0;
 876 
 877                 stripped_name(&s1, &s1len, npp1);
 878                 stripped_name(&s2, &s2len, npp2);
 879                 return (strcmp(s1, s2));
 880         }
 881 }
 882 
 883 #define NAME_CHUNK 512
 884 #define ROUNDLEN(x) (((x) + NAME_CHUNK - 1) / NAME_CHUNK * NAME_CHUNK)
 885 static void
 886 adjust_size(char **pp, size_t *lenp, const char *name)
 887 {
 888         void *newp;
 889         size_t nlen = strlen(name);
 890         size_t buflen;
 891 
 892         if (*lenp > nlen) {
 893                 (void) memset(*pp, '\0', *lenp);
 894                 return;
 895         }
 896 
 897         buflen = ROUNDLEN(nlen + 1);
 898         if ((newp = realloc(*pp, buflen)) == NULL) {
 899                 (void) fprintf(stderr,
 900                     "gprof: out of memory comparing names\n");
 901                 exit(EXIT_FAILURE);
 902         }
 903         (void) memset(newp, '\0', buflen);
 904 
 905         *lenp = buflen;
 906         *pp = newp;
 907 }
 908 
 909 static void
 910 stripped_name(char **sp, size_t *slenp, nltype **npp)
 911 {
 912         const char *name, *d;
 913         char *c;
 914 
 915         name = d = demangled_name(*npp);
 916         adjust_size(sp, slenp, name);
 917         c = *sp;
 918 
 919         while ((*d != '(') && (*d != '\0')) {
 920                 if (*d != ':')
 921                         *c++ = *d++;
 922                 else
 923                         d++;
 924         }
 925         *c = '\0';
 926 
 927         if ((*npp)->name != name)
 928                 free((void *)name);
 929 }
 930 
 931 /*
 932  * Checks if the current symbol name is the same as its neighbour and
 933  * returns TRUE if it is.
 934  */
 935 static bool
 936 does_clash(nltype **nlp, int ndx, int nnames)
 937 {
 938         /*
 939          * same as previous (if there's one) ?
 940          */
 941         if (ndx && (strcmp(nlp[ndx]->name, nlp[ndx-1]->name) == 0))
 942                 return (TRUE);
 943 
 944         /*
 945          * same as next (if there's one) ?
 946          */
 947         if ((ndx < (nnames - 1)) &&
 948             (strcmp(nlp[ndx]->name, nlp[ndx+1]->name) == 0)) {
 949                 return (TRUE);
 950         }
 951 
 952         return (FALSE);
 953 }
 954 
 955 void
 956 printmodules()
 957 {
 958         mod_info_t      *mi;
 959 
 960         (void) printf("\f\nObject modules\n\n");
 961         for (mi = &modules; mi; mi = mi->next)
 962                 (void) printf(" %d: %s\n", mi->id, mi->name);
 963 }
 964 
 965 #define IDFMT(id)       ((id) < 10 ? 1 : 2)
 966 #define NMFMT(id)       ((id) < 10 ? 17 : 16)
 967 
 968 void
 969 printindex()
 970 {
 971         nltype  **namesortnlp;
 972         nltype  *nlp;
 973         int     index, nnames, todo, i, j;
 974         char    peterbuffer[BUFSIZ];
 975         mod_info_t      *mi;
 976 
 977         /*
 978          *      Now, sort regular function name alphabetically
 979          *      to create an index.
 980          */
 981         namesortnlp = calloc(total_names + ncycle, sizeof (nltype *));
 982 
 983         if (namesortnlp == NULL)
 984                 (void) fprintf(stderr, "%s: ran out of memory for sorting\n",
 985                     whoami);
 986 
 987         nnames = 0;
 988         for (mi = &modules; mi; mi = mi->next) {
 989                 for (index = 0; index < mi->nname; index++) {
 990                         if (zflag == 0 && (mi->nl[index]).ncall == 0 &&
 991                             (mi->nl[index]).time == 0) {
 992                                 continue;
 993                         }
 994 
 995                         /*
 996                          * Do not print certain special symbols, like
 997                          * PRF_EXTSYM, etc. even if zflag was on.
 998                          */
 999                         if (is_special_sym(&(mi->nl[index])))
1000                                 continue;
1001 
1002                         namesortnlp[nnames++] = &(mi->nl[index]);
1003                 }
1004         }
1005 
1006         qsort(namesortnlp, nnames, sizeof (nltype *), namecmp);
1007 
1008         for (index = 1, todo = nnames; index <= ncycle; index++)
1009                 namesortnlp[todo++] = &cyclenl[index];
1010 
1011         (void) printf("\f\nIndex by function name\n\n");
1012 
1013         if (!Cflag)
1014                 index = (todo + 2) / 3;
1015         else
1016                 index = todo;
1017 
1018         for (i = 0; i < index; i++) {
1019                 if (!Cflag) {
1020                         for (j = i; j < todo; j += index) {
1021                                 nlp = namesortnlp[j];
1022 
1023                                 if (nlp->printflag) {
1024                                         (void) sprintf(peterbuffer,
1025                                             "[%d]", nlp->index);
1026                                 } else {
1027                                         (void) sprintf(peterbuffer,
1028                                             "(%d)", nlp->index);
1029                                 }
1030 
1031                                 if (j < nnames) {
1032                                         if (does_clash(namesortnlp,
1033                                             j, nnames)) {
1034                                                 (void) printf(
1035                                                     "%6.6s %*d:%-*.*s",
1036                                                     peterbuffer,
1037                                                     IDFMT(nlp->module->id),
1038                                                     nlp->module->id,
1039                                                     NMFMT(nlp->module->id),
1040                                                     NMFMT(nlp->module->id),
1041                                                     nlp->name);
1042                                         } else {
1043                                         (void) printf("%6.6s %-19.19s",
1044                                             peterbuffer, nlp->name);
1045                                         }
1046                                 } else {
1047                                         (void) printf("%6.6s ", peterbuffer);
1048                                         (void) sprintf(peterbuffer,
1049                                             "<cycle %d>", nlp->cycleno);
1050                                         (void) printf("%-19.19s", peterbuffer);
1051                                 }
1052                         }
1053                 } else {
1054                         nlp = namesortnlp[i];
1055 
1056                         if (nlp->printflag)
1057                                 (void) sprintf(peterbuffer, "[%d]", nlp->index);
1058                         else
1059                                 (void) sprintf(peterbuffer, "(%d)", nlp->index);
1060 
1061                         if (i < nnames) {
1062                                 const char *d = demangled_name(nlp);
1063 
1064                                 if (does_clash(namesortnlp, i, nnames)) {
1065                                         (void) printf("%6.6s %d:%s\n",
1066                                             peterbuffer, nlp->module->id, d);
1067                                 } else {
1068                                         (void) printf("%6.6s %s\n", peterbuffer,
1069                                             d);
1070                                 }
1071 
1072                                 if (d != nlp->name) {
1073                                         (void) printf("%6.6s   [%s]", "",
1074                                             nlp->name);
1075                                         free((void *)d);
1076                                 }
1077                         } else {
1078                                 (void) printf("%6.6s ", peterbuffer);
1079                                 (void) sprintf(peterbuffer, "<cycle %d>",
1080                                     nlp->cycleno);
1081                                 (void) printf("%-33.33s", peterbuffer);
1082                         }
1083                 }
1084                 (void) printf("\n");
1085         }
1086         free(namesortnlp);
1087 }