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
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
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
36void print_demangled_name(int, nltype *);
37void striped_name(char *, nltype **);
38
39extern long hz;
40
41/*
42 * Symbols that must never be printed, no matter what.
43 */
44char *splsym[] = {
45	PRF_ETEXT,
46	PRF_EXTSYM,
47	PRF_MEMTERM,
48	NULL
49};
50
51static bool is_special_sym(nltype *nlp);
52
53const char *
54demangled_name(nltype *selfp)
55{
56	if (!Cflag)
57		return (selfp->name);
58
59	return (conv_demangle_name(selfp->name));
60}
61
62void
63printprof(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
105int
106timecmp(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 */
135void
136flatprofheader()
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
166void
167flatprofline(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
203void
204gprofheader()
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
247void
248gprofline(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
276static bool
277is_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
291void
292printgprof(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 */
355int
356totalcmp(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
391void
392printparents(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
445void
446printchildren(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
496void
497printname(nltype *selfp)
498{
499	const char  *c;
500	c = demangled_name(selfp);
501
502	if (selfp->name != 0) {
503		if (!Cflag)
504			(void) printf("%s", selfp->name);
505		else
506			(void) printf("%s", c);
507
508#ifdef DEBUG
509		if (debug & DFNDEBUG)
510			(void) printf("{%d} ", selfp->toporder);
511
512		if (debug & PROPDEBUG)
513			(void) printf("%5.2f%% ", selfp->propfraction);
514#endif /* DEBUG */
515	}
516
517	if (selfp->cycleno != 0)
518		(void) printf("\t<cycle %d>", selfp->cycleno);
519
520	if (selfp->index != 0) {
521		if (selfp->printflag)
522			(void) printf(" [%d]", selfp->index);
523		else
524			(void) printf(" (%d)", selfp->index);
525	}
526}
527
528void
529print_demangled_name(int n, nltype *selfp)
530{
531	char *c;
532	int i;
533
534	c = selfp->name;
535
536	if (strcmp(c, demangled_name(selfp)) == 0)
537		return;
538	else {
539		(void) printf("\n");
540		for (i = 1; i < n; i++)
541			(void) printf(" ");
542		(void) printf("[%s]", selfp->name);
543	}
544}
545
546void
547sortchildren(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
589void
590sortparents(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
631void
632printcycle(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 */
654void
655printmembers(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 */
682void
683sortmembers(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 */
714int
715membercmp(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 */
746int
747arccmp(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
847void
848printblurb(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
865char *s1, *s2;
866
867static int
868namecmp(const void *arg1, const void *arg2)
869{
870	nltype **npp1 = (nltype **)arg1;
871	nltype **npp2 = (nltype **)arg2;
872
873	if (!Cflag)
874		return (strcmp((*npp1)->name, (*npp2)->name));
875	else {
876		striped_name(s1, npp1);
877		striped_name(s2, npp2);
878		return (strcmp(s1, s2));
879	}
880}
881
882void
883striped_name(char *s, nltype **npp)
884{
885	const char *d;
886	char *c;
887
888	c = (char *)s;
889	d = demangled_name(*npp);
890
891	while ((*d != '(') && (*d != '\0')) {
892		if (*d != ':')
893			*c++ = *d++;
894		else
895			d++;
896	}
897	*c = '\0';
898}
899
900/*
901 * Checks if the current symbol name is the same as its neighbour and
902 * returns TRUE if it is.
903 */
904static bool
905does_clash(nltype **nlp, int ndx, int nnames)
906{
907	/*
908	 * same as previous (if there's one) ?
909	 */
910	if (ndx && (strcmp(nlp[ndx]->name, nlp[ndx-1]->name) == 0))
911		return (TRUE);
912
913	/*
914	 * same as next (if there's one) ?
915	 */
916	if ((ndx < (nnames - 1)) &&
917	    (strcmp(nlp[ndx]->name, nlp[ndx+1]->name) == 0)) {
918		return (TRUE);
919	}
920
921	return (FALSE);
922}
923
924void
925printmodules()
926{
927	mod_info_t	*mi;
928
929	(void) printf("\f\nObject modules\n\n");
930	for (mi = &modules; mi; mi = mi->next)
931		(void) printf(" %d: %s\n", mi->id, mi->name);
932}
933
934#define	IDFMT(id)	((id) < 10 ? 1 : 2)
935#define	NMFMT(id)	((id) < 10 ? 17 : 16)
936
937void
938printindex()
939{
940	nltype	**namesortnlp;
941	nltype	*nlp;
942	int	index, nnames, todo, i, j;
943	char	peterbuffer[BUFSIZ];
944	mod_info_t	*mi;
945
946	/*
947	 *	Now, sort regular function name alphabetically
948	 *	to create an index.
949	 */
950	namesortnlp = calloc(total_names + ncycle, sizeof (nltype *));
951
952	if (namesortnlp == NULL)
953		(void) fprintf(stderr, "%s: ran out of memory for sorting\n",
954		    whoami);
955
956	nnames = 0;
957	for (mi = &modules; mi; mi = mi->next) {
958		for (index = 0; index < mi->nname; index++) {
959			if (zflag == 0 && (mi->nl[index]).ncall == 0 &&
960			    (mi->nl[index]).time == 0) {
961				continue;
962			}
963
964			/*
965			 * Do not print certain special symbols, like
966			 * PRF_EXTSYM, etc. even if zflag was on.
967			 */
968			if (is_special_sym(&(mi->nl[index])))
969				continue;
970
971			namesortnlp[nnames++] = &(mi->nl[index]);
972		}
973	}
974
975	if (Cflag) {
976		s1 = malloc(500 * sizeof (char));
977		s2 = malloc(500 * sizeof (char));
978	}
979
980	qsort(namesortnlp, nnames, sizeof (nltype *), namecmp);
981
982	for (index = 1, todo = nnames; index <= ncycle; index++)
983		namesortnlp[todo++] = &cyclenl[index];
984
985	(void) printf("\f\nIndex by function name\n\n");
986
987	if (!Cflag)
988		index = (todo + 2) / 3;
989	else
990		index = todo;
991
992	for (i = 0; i < index; i++) {
993		if (!Cflag) {
994			for (j = i; j < todo; j += index) {
995				nlp = namesortnlp[j];
996
997				if (nlp->printflag) {
998					(void) sprintf(peterbuffer,
999					    "[%d]", nlp->index);
1000				} else {
1001					(void) sprintf(peterbuffer,
1002					    "(%d)", nlp->index);
1003				}
1004
1005				if (j < nnames) {
1006					if (does_clash(namesortnlp,
1007					    j, nnames)) {
1008						(void) printf(
1009						    "%6.6s %*d:%-*.*s",
1010						    peterbuffer,
1011						    IDFMT(nlp->module->id),
1012						    nlp->module->id,
1013						    NMFMT(nlp->module->id),
1014						    NMFMT(nlp->module->id),
1015						    nlp->name);
1016					} else {
1017					(void) printf("%6.6s %-19.19s",
1018					    peterbuffer, nlp->name);
1019					}
1020				} else {
1021					(void) printf("%6.6s ", peterbuffer);
1022					(void) sprintf(peterbuffer,
1023					    "<cycle %d>", nlp->cycleno);
1024					(void) printf("%-19.19s", peterbuffer);
1025				}
1026			}
1027		} else {
1028			nlp = namesortnlp[i];
1029
1030			if (nlp->printflag)
1031				(void) sprintf(peterbuffer, "[%d]", nlp->index);
1032			else
1033				(void) sprintf(peterbuffer, "(%d)", nlp->index);
1034
1035			if (i < nnames) {
1036				const char *d = demangled_name(nlp);
1037
1038				if (does_clash(namesortnlp, i, nnames)) {
1039					(void) printf("%6.6s %d:%s\n",
1040					    peterbuffer, nlp->module->id, d);
1041				} else
1042					(void) printf("%6.6s %s\n", peterbuffer,
1043					    d);
1044
1045				if (d != nlp->name)
1046					(void) printf("%6.6s   [%s]", "",
1047					    nlp->name);
1048			} else {
1049				(void) printf("%6.6s ", peterbuffer);
1050				(void) sprintf(peterbuffer, "<cycle %d>",
1051				    nlp->cycleno);
1052				(void) printf("%-33.33s", peterbuffer);
1053			}
1054		}
1055		(void) printf("\n");
1056	}
1057	free(namesortnlp);
1058}
1059