xref: /illumos-gate/usr/src/cmd/sgs/gprof/common/printgprof.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1990-1998 by Sun Microsystems, Inc.
24  * All rights reserved.
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 "gprof.h"
34 
35 extern int find_run_directory(char *, char *, char *, char **, char *);
36 void print_demangled_name(int, nltype *);
37 void striped_name(char *, nltype **);
38 
39 
40 extern char *demangle();
41 char *strstr();
42 char *parsename();
43 char name_buffer[512];
44 extern long hz;
45 
46 /*
47  * Symbols that must never be printed, no matter what.
48  */
49 char *splsym[] = {
50 	PRF_ETEXT,
51 	PRF_EXTSYM,
52 	PRF_MEMTERM,
53 	0
54 };
55 
56 char *
57 demangled_name(nltype *selfp)
58 {
59 	char *name;
60 	if (!Cflag)
61 		return (selfp->name);
62 
63 	name = (char *) sgs_demangle(selfp->name);
64 	return (name);
65 }
66 
67 void
68 printprof()
69 {
70 	nltype	*np;
71 	nltype	**sortednlp;
72 	int	i, index;
73 	int 	print_count = number_funcs_toprint;
74 	bool	print_flag = TRUE;
75 	mod_info_t	*mi;
76 
77 	actime = 0.0;
78 	printf("\f\n");
79 	flatprofheader();
80 
81 	/*
82 	 *	Sort the symbol table in by time
83 	 */
84 	sortednlp = (nltype **) calloc(total_names, sizeof (nltype *));
85 	if (sortednlp == (nltype **) 0) {
86 		fprintf(stderr,
87 		    "[printprof] ran out of memory for time sorting\n");
88 	}
89 
90 	index = 0;
91 	for (mi = &modules; mi; mi = mi->next) {
92 		for (i = 0; i < mi->nname; i++)
93 			sortednlp[index++] = &(mi->nl[i]);
94 	}
95 
96 	qsort(sortednlp, total_names, sizeof (nltype *),
97 		(int(*)(const void *, const void *))timecmp);
98 
99 	for (index = 0; (index < total_names) && print_flag; index += 1) {
100 		np = sortednlp[index];
101 		flatprofline(np);
102 		if (nflag) {
103 			if (--print_count == 0)
104 				print_flag = FALSE;
105 		}
106 	}
107 	actime = 0.0;
108 	free(sortednlp);
109 }
110 
111 int
112 timecmp(nltype **npp1, nltype **npp2)
113 {
114 	double	timediff;
115 	long	calldiff;
116 
117 	timediff = (*npp2)->time - (*npp1)->time;
118 
119 	if (timediff > 0.0)
120 		return (1);
121 
122 	if (timediff < 0.0)
123 		return (-1);
124 
125 	calldiff = (*npp2)->ncall - (*npp1)->ncall;
126 
127 	if (calldiff > 0)
128 		return (1);
129 
130 	if (calldiff < 0)
131 		return (-1);
132 
133 	return (strcmp((*npp1)->name, (*npp2)->name));
134 }
135 
136 /*
137  *	header for flatprofline
138  */
139 void
140 flatprofheader()
141 {
142 
143 	if (bflag)
144 		printblurb(FLAT_BLURB);
145 
146 	if (old_style) {
147 		printf("\ngranularity: each sample hit covers %d byte(s)",
148 					    (long)scale * sizeof (UNIT));
149 		if (totime > 0.0) {
150 			printf(" for %.2f%% of %.2f seconds\n\n",
151 			    100.0/totime, totime / hz);
152 		} else {
153 			printf(" no time accumulated\n\n");
154 			/*
155 			 * this doesn't hurt since all the numerators will
156 			 * be zero.
157 			 */
158 			totime = 1.0;
159 		}
160 	}
161 
162 	printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
163 	    "% ", "cumulative", "self ", "", "self ", "total ", "");
164 	printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
165 	    "time", "seconds ", "seconds", "calls",
166 	    "ms/call", "ms/call", "name");
167 }
168 
169 void
170 flatprofline(nltype *np)
171 {
172 	if (zflag == 0 && np->ncall == 0 && np->time == 0)
173 		return;
174 
175 	/*
176 	 * Do not print certain special symbols, like PRF_EXTSYM, etc.
177 	 * even if zflag was on.
178 	 */
179 	if (is_special_sym(np))
180 		return;
181 
182 	actime += np->time;
183 
184 	printf("%5.1f %10.2f %8.2f",
185 	    100 * np->time / totime, actime / hz, np->time / hz);
186 
187 	if (np->ncall != 0) {
188 		printf(" %8lld %8.2f %8.2f  ", np->ncall,
189 		    1000 * np->time / hz / np->ncall,
190 		    1000 * (np->time + np->childtime) / hz / np->ncall);
191 	} else {
192 		if (!Cflag)
193 			printf(" %8.8s %8.8s %8.8s ", "", "", "");
194 		else
195 			printf(" %8.8s %8.8s %8.8s  ", "", "", "");
196 	}
197 
198 	printname(np);
199 
200 	if (Cflag)
201 		print_demangled_name(55, np);
202 
203 	printf("\n");
204 }
205 
206 void
207 gprofheader()
208 {
209 
210 	if (bflag)
211 		printblurb(CALLG_BLURB);
212 
213 	if (old_style) {
214 
215 		printf("\ngranularity: each sample hit covers %d byte(s)",
216 						(long)scale * sizeof (UNIT));
217 
218 		if (printtime > 0.0) {
219 			printf(" for %.2f%% of %.2f seconds\n\n",
220 			    100.0/printtime, printtime / hz);
221 		} else {
222 			printf(" no time propagated\n\n");
223 			/*
224 			 * this doesn't hurt, since all the numerators
225 			 * will be 0.0
226 			 */
227 			printtime = 1.0;
228 		}
229 	} else {
230 		printf("\ngranularity: each pc-hit is considered 1 tick");
231 		if (hz != 1) {
232 			printf(" (@ %4.3f seconds per tick)",
233 							(double) 1.0 / hz);
234 		}
235 		puts("\n\n");
236 	}
237 
238 	printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n",
239 	    "", "", "", "", "called", "total", "parents");
240 	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 	printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n",
244 	    "", "", "", "", "called", "total", "children");
245 	printf("\n");
246 }
247 
248 void
249 gprofline(nltype *np)
250 {
251 	char	kirkbuffer[BUFSIZ];
252 
253 	sprintf(kirkbuffer, "[%d]", np->index);
254 	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 		printf(" %7lld", np->ncall);
260 
261 		if (np->selfcalls != 0)
262 			printf("+%-7lld ", np->selfcalls);
263 		else
264 			printf(" %7.7s ", "");
265 	} else {
266 		printf(" %7.7s %7.7s ", "", "");
267 	}
268 
269 	printname(np);
270 
271 	if (Cflag)
272 		print_demangled_name(50, np);
273 
274 	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 		printf("\n");
335 		printf("-----------------------------------------------\n");
336 		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(nltype **npp1, nltype **npp2)
357 {
358 	nltype	*np1 = *npp1;
359 	nltype	*np2 = *npp2;
360 	double	diff;
361 
362 	diff = (np1->propself + np1->propchild) -
363 	    (np2->propself + np2->propchild);
364 
365 	if (diff < 0.0)
366 		return (1);
367 	if (diff > 0.0)
368 		return (-1);
369 	if (np1->name == 0 && np1->cycleno != 0)
370 		return (-1);
371 	if (np2->name == 0 && np2->cycleno != 0)
372 		return (1);
373 	if (np1->name == 0)
374 		return (-1);
375 	if (np2->name == 0)
376 		return (1);
377 
378 	if (*(np1->name) != '_' && *(np2->name) == '_')
379 		return (-1);
380 	if (*(np1->name) == '_' && *(np2->name) != '_')
381 		return (1);
382 	if (np1->ncall > np2->ncall)
383 		return (-1);
384 	if (np1->ncall < np2->ncall)
385 		return (1);
386 	return (strcmp(np1->name, np2->name));
387 }
388 
389 void
390 printparents(nltype *childp)
391 {
392 	nltype	*parentp;
393 	arctype	*arcp;
394 	nltype	*cycleheadp;
395 
396 	if (childp->cyclehead != 0)
397 		cycleheadp = childp -> cyclehead;
398 	else
399 		cycleheadp = childp;
400 
401 	if (childp->parents == 0) {
402 		printf("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s"
403 		    "     <spontaneous>\n", "", "", "", "", "", "");
404 		return;
405 	}
406 
407 	sortparents(childp);
408 
409 	for (arcp = childp->parents; arcp; arcp = arcp->arc_parentlist) {
410 		parentp = arcp -> arc_parentp;
411 		if (childp == parentp || (childp->cycleno != 0 &&
412 		    parentp->cycleno == childp->cycleno)) {
413 			/*
414 			 *	selfcall or call among siblings
415 			 */
416 			printf("%6.6s %5.5s %7.7s %11.11s %7lld %7.7s     ",
417 			    "", "", "", "", arcp->arc_count, "");
418 			printname(parentp);
419 
420 			if (Cflag)
421 				print_demangled_name(54, parentp);
422 
423 			printf("\n");
424 		} else {
425 			/*
426 			 *	regular parent of child
427 			 */
428 			printf("%6.6s %5.5s %7.2f %11.2f %7lld/%-7lld     ", "",
429 			    "", arcp->arc_time / hz, arcp->arc_childtime / hz,
430 			    arcp->arc_count, cycleheadp->ncall);
431 			printname(parentp);
432 
433 			if (Cflag)
434 				print_demangled_name(54, parentp);
435 
436 			printf("\n");
437 		}
438 	}
439 }
440 
441 void
442 printchildren(nltype *parentp)
443 {
444 	nltype	*childp;
445 	arctype	*arcp;
446 
447 	sortchildren(parentp);
448 
449 	for (arcp = parentp->children; arcp; arcp = arcp->arc_childlist) {
450 		childp = arcp->arc_childp;
451 		if (childp == parentp || (childp->cycleno != 0 &&
452 		    childp->cycleno == parentp->cycleno)) {
453 			/*
454 			 * self call or call to sibling
455 			 */
456 			printf("%6.6s %5.5s %7.7s %11.11s %7lld %7.7s     ",
457 			    "", "", "", "", arcp->arc_count, "");
458 			printname(childp);
459 
460 			if (Cflag)
461 				print_demangled_name(54, childp);
462 
463 			printf("\n");
464 		} else {
465 			/*
466 			 *	regular child of parent
467 			 */
468 			if (childp->cyclehead)
469 				printf("%6.6s %5.5s %7.2f %11.2f "
470 				    "%7lld/%-7lld     ", "", "",
471 				    arcp->arc_time / hz,
472 				    arcp->arc_childtime / hz, arcp->arc_count,
473 				    childp->cyclehead->ncall);
474 			else
475 				printf("%6.6s %5.5s %7.2f %11.2f "
476 				    "%7lld %7.7s    ",
477 				    "", "", arcp->arc_time / hz,
478 				    arcp->arc_childtime / hz, arcp->arc_count,
479 				    "");
480 
481 			printname(childp);
482 
483 			if (Cflag)
484 				print_demangled_name(54, childp);
485 
486 			printf("\n");
487 		}
488 	}
489 }
490 
491 void
492 printname(nltype *selfp)
493 {
494 	char  *c;
495 	c = demangled_name(selfp);
496 
497 	if (selfp->name != 0) {
498 		if (!Cflag)
499 			printf("%s", selfp->name);
500 		else
501 			printf("%s", c);
502 
503 #ifdef DEBUG
504 		if (debug & DFNDEBUG)
505 			printf("{%d} ", selfp->toporder);
506 
507 		if (debug & PROPDEBUG)
508 			printf("%5.2f%% ", selfp->propfraction);
509 #endif DEBUG
510 	}
511 
512 	if (selfp->cycleno != 0)
513 		printf("\t<cycle %d>", selfp->cycleno);
514 
515 	if (selfp->index != 0) {
516 		if (selfp->printflag)
517 			printf(" [%d]", selfp->index);
518 		else
519 			printf(" (%d)", selfp->index);
520 	}
521 }
522 
523 void
524 print_demangled_name(int n, nltype *selfp)
525 {
526 	char *c;
527 	int i;
528 
529 	c = selfp->name;
530 
531 	if (strcmp(c, demangled_name(selfp)) == 0)
532 		return;
533 	else {
534 		printf("\n");
535 		for (i = 1; i < n; i++)
536 			printf(" ");
537 		printf("[%s]", selfp->name);
538 	}
539 }
540 
541 char *exotic();
542 
543 void
544 sortchildren(nltype *parentp)
545 {
546 	arctype	*arcp;
547 	arctype	*detachedp;
548 	arctype	sorted;
549 	arctype	*prevp;
550 
551 	/*
552 	 *	unlink children from parent,
553 	 *	then insertion sort back on to sorted's children.
554 	 *	    *arcp	the arc you have detached and are inserting.
555 	 *	    *detachedp	the rest of the arcs to be sorted.
556 	 *	    sorted	arc list onto which you insertion sort.
557 	 *	    *prevp	arc before the arc you are comparing.
558 	 */
559 	sorted.arc_childlist = 0;
560 
561 	for ((arcp = parentp->children) && (detachedp = arcp->arc_childlist);
562 	    arcp;
563 	    (arcp = detachedp) && (detachedp = detachedp->arc_childlist)) {
564 		/*
565 		 *	consider *arcp as disconnected
566 		 *	insert it into sorted
567 		 */
568 		for (prevp = &sorted; prevp->arc_childlist;
569 		    prevp = prevp->arc_childlist) {
570 			if (arccmp(arcp, prevp->arc_childlist) != LESSTHAN)
571 				break;
572 		}
573 
574 		arcp->arc_childlist = prevp->arc_childlist;
575 		prevp->arc_childlist = arcp;
576 	}
577 
578 	/*
579 	 *	reattach sorted children to parent
580 	 */
581 	parentp->children = sorted.arc_childlist;
582 }
583 
584 void
585 sortparents(nltype *childp)
586 {
587 	arctype	*arcp;
588 	arctype	*detachedp;
589 	arctype	sorted;
590 	arctype	*prevp;
591 
592 	/*
593 	 *	unlink parents from child,
594 	 *	then insertion sort back on to sorted's parents.
595 	 *	    *arcp	the arc you have detached and are inserting.
596 	 *	    *detachedp	the rest of the arcs to be sorted.
597 	 *	    sorted	arc list onto which you insertion sort.
598 	 *	    *prevp	arc before the arc you are comparing.
599 	 */
600 	sorted.arc_parentlist = 0;
601 
602 	for ((arcp = childp->parents) && (detachedp = arcp->arc_parentlist);
603 	    arcp;
604 	    (arcp = detachedp) && (detachedp = detachedp->arc_parentlist)) {
605 		/*
606 		 *	consider *arcp as disconnected
607 		 *	insert it into sorted
608 		 */
609 		for (prevp = &sorted; prevp->arc_parentlist;
610 		    prevp = prevp->arc_parentlist) {
611 			if (arccmp(arcp, prevp->arc_parentlist) != GREATERTHAN)
612 				break;
613 		}
614 		arcp->arc_parentlist = prevp->arc_parentlist;
615 		prevp->arc_parentlist = arcp;
616 	}
617 
618 	/*
619 	 *	reattach sorted arcs to child
620 	 */
621 	childp->parents = sorted.arc_parentlist;
622 }
623 
624 void
625 printcycle(nltype *cyclep)
626 {
627 	char	kirkbuffer[BUFSIZ];
628 
629 	sprintf(kirkbuffer, "[%d]", cyclep->index);
630 	printf("%-6.6s %5.1f %7.2f %11.2f %7lld", kirkbuffer,
631 	    100 * (cyclep->propself + cyclep->propchild) / printtime,
632 	    cyclep -> propself / hz, cyclep -> propchild / hz,
633 	    cyclep -> ncall);
634 
635 	if (cyclep->selfcalls != 0)
636 		printf("+%-7lld", cyclep->selfcalls);
637 	else
638 		printf(" %7.7s", "");
639 
640 	printf(" <cycle %d as a whole>\t[%d]\n", cyclep->cycleno,
641 	    cyclep->index);
642 }
643 
644 /*
645  *	print the members of a cycle
646  */
647 void
648 printmembers(nltype *cyclep)
649 {
650 	nltype	*memberp;
651 
652 	sortmembers(cyclep);
653 
654 	for (memberp = cyclep->cnext; memberp; memberp = memberp->cnext) {
655 		printf("%6.6s %5.5s %7.2f %11.2f %7lld", "", "",
656 		    memberp->propself / hz, memberp->propchild / hz,
657 		    memberp->ncall);
658 
659 		if (memberp->selfcalls != 0)
660 			printf("+%-7lld", memberp->selfcalls);
661 		else
662 			printf(" %7.7s", "");
663 
664 		printf("     ");
665 		printname(memberp);
666 		if (Cflag)
667 			print_demangled_name(54, memberp);
668 		printf("\n");
669 	}
670 }
671 
672 /*
673  * sort members of a cycle
674  */
675 void
676 sortmembers(nltype *cyclep)
677 {
678 	nltype	*todo;
679 	nltype	*doing;
680 	nltype	*prev;
681 
682 	/*
683 	 *	detach cycle members from cyclehead,
684 	 *	and insertion sort them back on.
685 	 */
686 	todo = cyclep->cnext;
687 	cyclep->cnext = 0;
688 
689 	for ((doing = todo) && (todo = doing->cnext);
690 	    doing; (doing = todo) && (todo = doing->cnext)) {
691 		for (prev = cyclep; prev->cnext; prev = prev->cnext) {
692 			if (membercmp(doing, prev->cnext) == GREATERTHAN)
693 				break;
694 		}
695 		doing->cnext = prev->cnext;
696 		prev->cnext = doing;
697 	}
698 }
699 
700 /*
701  *	major sort is on propself + propchild,
702  *	next is sort on ncalls + selfcalls.
703  */
704 int
705 membercmp(nltype *this, nltype *that)
706 {
707 	double	thistime = this->propself + this->propchild;
708 	double	thattime = that->propself + that->propchild;
709 	actype	thiscalls = this->ncall + this->selfcalls;
710 	actype	thatcalls = that->ncall + that->selfcalls;
711 
712 	if (thistime > thattime)
713 		return (GREATERTHAN);
714 
715 	if (thistime < thattime)
716 		return (LESSTHAN);
717 
718 	if (thiscalls > thatcalls)
719 		return (GREATERTHAN);
720 
721 	if (thiscalls < thatcalls)
722 		return (LESSTHAN);
723 
724 	return (EQUALTO);
725 }
726 
727 /*
728  *	compare two arcs to/from the same child/parent.
729  *	- if one arc is a self arc, it's least.
730  *	- if one arc is within a cycle, it's less than.
731  *	- if both arcs are within a cycle, compare arc counts.
732  *	- if neither arc is within a cycle, compare with
733  *		arc_time + arc_childtime as major key
734  *		arc count as minor key
735  */
736 int
737 arccmp(arctype *thisp, arctype *thatp)
738 {
739 	nltype	*thisparentp = thisp->arc_parentp;
740 	nltype	*thischildp = thisp->arc_childp;
741 	nltype	*thatparentp = thatp->arc_parentp;
742 	nltype	*thatchildp = thatp->arc_childp;
743 	double	thistime;
744 	double	thattime;
745 
746 #ifdef DEBUG
747 	if (debug & TIMEDEBUG) {
748 		printf("[arccmp] ");
749 		printname(thisparentp);
750 		printf(" calls ");
751 		printname(thischildp);
752 		printf(" %f + %f %lld/%lld\n", thisp->arc_time,
753 		    thisp->arc_childtime, thisp->arc_count,
754 		    thischildp->ncall);
755 		printf("[arccmp] ");
756 		printname(thatparentp);
757 		printf(" calls ");
758 		printname(thatchildp);
759 		printf(" %f + %f %lld/%lld\n", thatp->arc_time,
760 		    thatp->arc_childtime, thatp->arc_count,
761 		    thatchildp->ncall);
762 		printf("\n");
763 	}
764 #endif DEBUG
765 
766 	if (thisparentp == thischildp) {
767 		/*
768 		 * this is a self call
769 		 */
770 		return (LESSTHAN);
771 	}
772 
773 	if (thatparentp == thatchildp) {
774 		/*
775 		 * that is a self call
776 		 */
777 		return (GREATERTHAN);
778 	}
779 
780 	if (thisparentp->cycleno != 0 && thischildp->cycleno != 0 &&
781 	    thisparentp->cycleno == thischildp->cycleno) {
782 		/*
783 		 * this is a call within a cycle
784 		 */
785 		if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 &&
786 		    thatparentp->cycleno == thatchildp->cycleno) {
787 			/*
788 			 * that is a call within the cycle, too
789 			 */
790 			if (thisp->arc_count < thatp->arc_count)
791 				return (LESSTHAN);
792 
793 			if (thisp->arc_count > thatp->arc_count)
794 				return (GREATERTHAN);
795 
796 			return (EQUALTO);
797 		} else {
798 			/*
799 			 * that isn't a call within the cycle
800 			 */
801 			return (LESSTHAN);
802 		}
803 	} else {
804 		/*
805 		 * this isn't a call within a cycle
806 		 */
807 		if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 &&
808 		    thatparentp->cycleno == thatchildp->cycleno) {
809 			/*
810 			 * that is a call within a cycle
811 			 */
812 			return (GREATERTHAN);
813 		} else {
814 			/*
815 			 * neither is a call within a cycle
816 			 */
817 			thistime = thisp->arc_time + thisp->arc_childtime;
818 			thattime = thatp->arc_time + thatp->arc_childtime;
819 
820 			if (thistime < thattime)
821 				return (LESSTHAN);
822 
823 			if (thistime > thattime)
824 				return (GREATERTHAN);
825 
826 			if (thisp->arc_count < thatp->arc_count)
827 				return (LESSTHAN);
828 
829 			if (thisp->arc_count > thatp->arc_count)
830 				return (GREATERTHAN);
831 
832 			return (EQUALTO);
833 		}
834 	}
835 }
836 
837 void
838 printblurb(char *blurbname)
839 {
840 	FILE	*blurbfile;
841 	int	input;
842 	char	blurb_directory[MAXPATHLEN];
843 	char	cwd[MAXPATHLEN];
844 
845 	cwd[0] = '.';
846 	cwd[1] = '\0';
847 
848 	if (find_run_directory(prog_name, cwd, blurb_directory,
849 	    NULL, getenv("PATH")) != 0) {
850 		(void) fprintf(stderr, "Error in finding run directory.");
851 		return;
852 	} else {
853 		strcat(blurb_directory, blurbname);
854 	}
855 
856 	blurbfile = fopen(blurb_directory, "r");
857 	if (blurbfile == NULL) {
858 		perror(blurb_directory);
859 		return;
860 	}
861 
862 	while ((input = getc(blurbfile)) != EOF)
863 		putchar(input);
864 
865 	fclose(blurbfile);
866 }
867 
868 char *s1, *s2;
869 
870 int
871 namecmp(nltype **npp1, nltype **npp2)
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 
882 void
883 striped_name(char *s, nltype **npp)
884 {
885 	char *d, *c;
886 
887 	c = (char *)s;
888 	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 
899 /*
900  * Checks if the current symbol name is the same as its neighbour and
901  * returns TRUE if it is.
902  */
903 static bool
904 does_clash(nltype **nlp, int ndx, int nnames)
905 {
906 	/*
907 	 * same as previous (if there's one) ?
908 	 */
909 	if (ndx && (strcmp(nlp[ndx]->name, nlp[ndx-1]->name) == 0))
910 		return (TRUE);
911 
912 	/*
913 	 * same as next (if there's one) ?
914 	 */
915 	if ((ndx < (nnames - 1)) &&
916 			    (strcmp(nlp[ndx]->name, nlp[ndx+1]->name) == 0)) {
917 		return (TRUE);
918 	}
919 
920 	return (FALSE);
921 }
922 
923 void
924 printmodules()
925 {
926 	mod_info_t	*mi;
927 
928 	printf("\f\nObject modules\n\n");
929 	for (mi = &modules; mi; mi = mi->next)
930 		printf(" %d: %s\n", mi->id, mi->name);
931 }
932 
933 #define	IDFMT(id)	((id) < 10 ? 1 : 2)
934 #define	NMFMT(id)	((id) < 10 ? 17 : 16)
935 
936 void
937 printindex()
938 {
939 	nltype	**namesortnlp;
940 	nltype	*nlp;
941 	int	index, nnames, todo, i, j;
942 	char	peterbuffer[BUFSIZ];
943 	mod_info_t	*mi;
944 
945 	/*
946 	 *	Now, sort regular function name alphabetically
947 	 *	to create an index.
948 	 */
949 	namesortnlp = calloc(total_names + ncycle, sizeof (nltype *));
950 
951 	if (namesortnlp == NULL)
952 		fprintf(stderr, "%s: ran out of memory for sorting\n", whoami);
953 
954 	nnames = 0;
955 	for (mi = &modules; mi; mi = mi->next) {
956 		for (index = 0; index < mi->nname; index++) {
957 			if (zflag == 0 && (mi->nl[index]).ncall == 0 &&
958 						(mi->nl[index]).time == 0) {
959 				continue;
960 			}
961 
962 			/*
963 			 * Do not print certain special symbols, like
964 			 * PRF_EXTSYM, etc. even if zflag was on.
965 			 */
966 			if (is_special_sym(&(mi->nl[index])))
967 				continue;
968 
969 			namesortnlp[nnames++] = &(mi->nl[index]);
970 		}
971 	}
972 
973 	if (Cflag) {
974 		s1 = malloc(500 * sizeof (char));
975 		s2 = malloc(500 * sizeof (char));
976 	}
977 
978 	qsort(namesortnlp, nnames, sizeof (nltype *),
979 	    (int(*)(const void *, const void *))namecmp);
980 
981 	for (index = 1, todo = nnames; index <= ncycle; index++)
982 		namesortnlp[todo++] = &cyclenl[index];
983 
984 	printf("\f\nIndex by function name\n\n");
985 
986 	if (!Cflag)
987 		index = (todo + 2) / 3;
988 	else
989 		index = todo;
990 
991 	for (i = 0; i < index; i++) {
992 		if (!Cflag) {
993 			for (j = i; j < todo; j += index) {
994 				nlp = namesortnlp[j];
995 
996 				if (nlp->printflag) {
997 					sprintf(peterbuffer,
998 					    "[%d]", nlp->index);
999 				} else {
1000 					sprintf(peterbuffer,
1001 					    "(%d)", nlp->index);
1002 				}
1003 
1004 				if (j < nnames) {
1005 					if (does_clash(namesortnlp,
1006 								j, nnames)) {
1007 						printf("%6.6s %*d:%-*.*s",
1008 							peterbuffer,
1009 							IDFMT(nlp->module->id),
1010 							nlp->module->id,
1011 							NMFMT(nlp->module->id),
1012 							NMFMT(nlp->module->id),
1013 							nlp->name);
1014 					} else {
1015 						printf("%6.6s %-19.19s",
1016 						    peterbuffer, nlp->name);
1017 					}
1018 				} else {
1019 					printf("%6.6s ", peterbuffer);
1020 					sprintf(peterbuffer,
1021 					    "<cycle %d>", nlp->cycleno);
1022 					printf("%-19.19s", peterbuffer);
1023 				}
1024 			}
1025 		} else {
1026 			nlp = namesortnlp[i];
1027 
1028 			if (nlp->printflag)
1029 				sprintf(peterbuffer, "[%d]", nlp->index);
1030 			else
1031 				sprintf(peterbuffer, "(%d)", nlp->index);
1032 
1033 			if (i < nnames) {
1034 				char *d = demangled_name(nlp);
1035 
1036 				if (does_clash(namesortnlp, i, nnames)) {
1037 					printf("%6.6s %d:%s\n", peterbuffer,
1038 							nlp->module->id, d);
1039 				} else
1040 					printf("%6.6s %s\n", peterbuffer, d);
1041 
1042 				if (d != nlp->name)
1043 					printf("%6.6s   [%s]", "", nlp->name);
1044 			} else {
1045 				printf("%6.6s ", peterbuffer);
1046 				sprintf(peterbuffer, "<cycle %d>",
1047 				    nlp->cycleno);
1048 				printf("%-33.33s", peterbuffer);
1049 			}
1050 		}
1051 		printf("\n");
1052 	}
1053 	free(namesortnlp);
1054 }
1055 
1056 
1057 char dname[500];
1058 
1059 char *
1060 exotic(char *s)
1061 {
1062 	char *name;
1063 	int i = 0, j;
1064 	char *p, *s1 = "static constructor function for ";
1065 
1066 	name = malloc(500 * sizeof (char));
1067 
1068 	if (strncmp(s, "__sti__", 7) == 0) {
1069 		i = 0;
1070 		s += 7;
1071 
1072 		if ((p = strstr(s, "_c_")) == NULL) {
1073 			if ((p = strstr(s, "_C_")) == NULL) {
1074 				if ((p = strstr(s, "_cc_")) == NULL) {
1075 					if ((p = strstr(s, "_cxx_")) == NULL) {
1076 						if ((p =
1077 						    strstr(s, "_h_")) == NULL)
1078 							return (NULL);
1079 					}
1080 				}
1081 			}
1082 		} else {
1083 			p += 3;
1084 			*p = '\0';
1085 		}
1086 
1087 		for (i = 0; s1[i] != '\0'; i++)
1088 			dname[i] = s1[i];
1089 		j = i;
1090 
1091 		for (i = 0; s[i] != '\0'; i++)
1092 			dname[j + i] = s[i];
1093 		dname[j + i] = '\0';
1094 
1095 		free(name);
1096 		return (dname);
1097 	}
1098 
1099 	if (strncmp(s, "__std__", 7) == 0) {
1100 		char *s1 = "static destructor function for ";
1101 		i = 0;
1102 		s += 7;
1103 
1104 		if ((p = strstr(s, "_c_")) == NULL) {
1105 			if ((p = strstr(s, "_C_")) == NULL) {
1106 				if ((p = strstr(s, "_cc_")) == NULL) {
1107 					if ((p = strstr(s, "_cxx_")) == NULL) {
1108 						if ((p =
1109 						    strstr(s, "_h_")) == NULL)
1110 							return (NULL);
1111 					}
1112 				}
1113 			}
1114 		} else {
1115 			p += 3;
1116 			*p = '\0';
1117 		}
1118 
1119 		for (i = 0; s1[i] != '\0'; i++)
1120 			dname[i] = s1[i];
1121 		j = i;
1122 
1123 		for (i = 0; s[i] != '\0'; i++)
1124 			dname[j + i] = s[i];
1125 		dname[j + i] = '\0';
1126 
1127 		free(name);
1128 		return (dname);
1129 	}
1130 
1131 	if (strncmp(s, "__vtbl__", 8) == 0) {
1132 		char *s1 = "virtual table for ";
1133 		char *printname, *return_p = dname;
1134 
1135 		s += 8;
1136 		printname = parsename(s);
1137 		return_p = '\0';
1138 		strcat(return_p, s1);
1139 		strcat(return_p, printname);
1140 
1141 		free(name);
1142 		return (dname);
1143 	}
1144 
1145 	if (strncmp(s, "__ptbl__", 8) == 0) {
1146 		char *s1 = "pointer to the virtual table for ";
1147 		char *printname, *return_p = dname;
1148 
1149 		s += 8;
1150 		printname = parsename(s);
1151 		return_p = '\0';
1152 		strcat(return_p, s1);
1153 		strcat(return_p, printname);
1154 
1155 		free(name);
1156 		return (return_p);
1157 	}
1158 
1159 	free(name);
1160 	return (s);
1161 }
1162 
1163 char *
1164 parsename(char *s)
1165 {
1166 	char *d = name_buffer;
1167 	int len;
1168 	char c_init;
1169 	char *len_pointer = s;
1170 
1171 	*d = '\0';
1172 
1173 	strcat(d, "class ");
1174 
1175 	while (isdigit(*s))
1176 		s++;
1177 	c_init = *s;
1178 	*s = '\0';
1179 
1180 	len = atoi(len_pointer);
1181 	*s = c_init;
1182 
1183 	/*
1184 	 * only one class name
1185 	 */
1186 	if (*(s + len) == '\0') {
1187 		strcat(d, s);
1188 		return (d);
1189 	} else {
1190 		/*
1191 		 * two classname  %drootname__%dchildname
1192 		 */
1193 		char *child;
1194 		char *root;
1195 		int child_len;
1196 		char *child_len_p;
1197 		root = s;
1198 		child = s + len + 2;
1199 		child_len_p = child;
1200 
1201 		if (!isdigit(*child)) { /* ptbl file name */
1202 			c_init = *(root + len);
1203 			*(root + len) = '\0';
1204 			strcat(d, root);
1205 			*(root + len) = c_init;
1206 			strcat(d, " in ");
1207 			strcat(d, child);
1208 			return (d);
1209 		}
1210 
1211 		while (isdigit(*child))
1212 			child++;
1213 		c_init = *child;
1214 		*child = '\0';
1215 		child_len = atoi(child_len_p);
1216 		*child = c_init;
1217 		if (*(child + child_len) == '\0') {
1218 			strcat(d, child);
1219 			strcat(d, " derived from ");
1220 			c_init = *(root + len);
1221 			*(root + len) = '\0';
1222 			strcat(d, root);
1223 			*(root + len) = c_init;
1224 			return (d);
1225 		} else { /* %drootname__%dchildname__filename */
1226 			c_init = *(child + child_len);
1227 			*(child + child_len) = '\0';
1228 			strcat(d, child);
1229 			*(child+ child_len) = c_init;
1230 			strcat(d, " derived from ");
1231 			c_init = *(root + len);
1232 			*(root + len) = '\0';
1233 			strcat(d, root);
1234 			*(root + len) = c_init;
1235 			strcat(d, " in ");
1236 			strcat(d, child + child_len + 2);
1237 			return (d);
1238 		}
1239 	}
1240 }
1241