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