xref: /titanic_50/usr/src/cmd/sgs/gprof/common/gprof.c (revision 1dd08564e4a3aafe66b00aee6f222b0885346fe8)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*1dd08564Sab196087  * Common Development and Distribution License (the "License").
6*1dd08564Sab196087  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*1dd08564Sab196087  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include	<sysexits.h>
297c478bd9Sstevel@tonic-gate #include	<stdlib.h>
3092ed1782Smike_s #include	<stdio.h>
317c478bd9Sstevel@tonic-gate #include	<unistd.h>
327c478bd9Sstevel@tonic-gate #include	"gprof.h"
337c478bd9Sstevel@tonic-gate #include	"profile.h"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate char		*whoami = "gprof";
367c478bd9Sstevel@tonic-gate static pctype	lowpc, highpc;		/* range profiled, in UNIT's */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  *	things which get -E excluded by default.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate static char *defaultEs[] = {
427c478bd9Sstevel@tonic-gate 	"mcount",
437c478bd9Sstevel@tonic-gate 	"__mcleanup",
4492ed1782Smike_s 	NULL
457c478bd9Sstevel@tonic-gate };
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #ifdef DEBUG
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate static char *objname[] = {
507c478bd9Sstevel@tonic-gate 	"<invalid object>",
517c478bd9Sstevel@tonic-gate 	"PROF_BUFFER_T",
527c478bd9Sstevel@tonic-gate 	"PROF_CALLGRAPH_T",
537c478bd9Sstevel@tonic-gate 	"PROF_MODULES_T",
5492ed1782Smike_s 	NULL
557c478bd9Sstevel@tonic-gate };
567c478bd9Sstevel@tonic-gate #define	MAX_OBJTYPES	3
577c478bd9Sstevel@tonic-gate 
5892ed1782Smike_s #endif /* DEBUG */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate void
done(void)6192ed1782Smike_s done(void)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	exit(EX_OK);
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate static pctype
max(pctype a,pctype b)687c478bd9Sstevel@tonic-gate max(pctype a, pctype b)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate 	if (a > b)
717c478bd9Sstevel@tonic-gate 		return (a);
727c478bd9Sstevel@tonic-gate 	return (b);
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static pctype
min(pctype a,pctype b)767c478bd9Sstevel@tonic-gate min(pctype a, pctype b)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	if (a < b)
797c478bd9Sstevel@tonic-gate 		return (a);
807c478bd9Sstevel@tonic-gate 	return (b);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  *	calculate scaled entry point addresses (to save time in asgnsamples),
857c478bd9Sstevel@tonic-gate  *	and possibly push the scaled entry points over the entry mask,
867c478bd9Sstevel@tonic-gate  *	if it turns out that the entry point is in one bucket and the code
877c478bd9Sstevel@tonic-gate  *	for a routine is in the next bucket.
887c478bd9Sstevel@tonic-gate  *
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate static void
alignentries(void)9192ed1782Smike_s alignentries(void)
927c478bd9Sstevel@tonic-gate {
9392ed1782Smike_s 	struct nl *nlp;
947c478bd9Sstevel@tonic-gate #ifdef DEBUG
957c478bd9Sstevel@tonic-gate 	pctype			bucket_of_entry;
967c478bd9Sstevel@tonic-gate 	pctype			bucket_of_code;
9792ed1782Smike_s #endif /* DEBUG */
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	/* for old-style gmon.out, nameslist is only in modules.nl */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	for (nlp = modules.nl; nlp < modules.npe; nlp++) {
1027c478bd9Sstevel@tonic-gate 		nlp->svalue = nlp->value / sizeof (UNIT);
1037c478bd9Sstevel@tonic-gate #ifdef DEBUG
1047c478bd9Sstevel@tonic-gate 		bucket_of_entry = (nlp->svalue - lowpc) / scale;
1057c478bd9Sstevel@tonic-gate 		bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
1067c478bd9Sstevel@tonic-gate 		if (bucket_of_entry < bucket_of_code) {
1077c478bd9Sstevel@tonic-gate 			if (debug & SAMPLEDEBUG) {
10892ed1782Smike_s 				(void) printf(
10992ed1782Smike_s 				    "[alignentries] pushing svalue 0x%llx "
1107c478bd9Sstevel@tonic-gate 				    "to 0x%llx\n", nlp->svalue,
1117c478bd9Sstevel@tonic-gate 				    nlp->svalue + UNITS_TO_CODE);
1127c478bd9Sstevel@tonic-gate 			}
1137c478bd9Sstevel@tonic-gate 		}
11492ed1782Smike_s #endif /* DEBUG */
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  *	old-style gmon.out
1207c478bd9Sstevel@tonic-gate  *	------------------
1217c478bd9Sstevel@tonic-gate  *
1227c478bd9Sstevel@tonic-gate  *	Assign samples to the procedures to which they belong.
1237c478bd9Sstevel@tonic-gate  *
1247c478bd9Sstevel@tonic-gate  *	There are three cases as to where pcl and pch can be
1257c478bd9Sstevel@tonic-gate  *	with respect to the routine entry addresses svalue0 and svalue1
1267c478bd9Sstevel@tonic-gate  *	as shown in the following diagram.  overlap computes the
1277c478bd9Sstevel@tonic-gate  *	distance between the arrows, the fraction of the sample
1287c478bd9Sstevel@tonic-gate  *	that is to be credited to the routine which starts at svalue0.
1297c478bd9Sstevel@tonic-gate  *
1307c478bd9Sstevel@tonic-gate  *	    svalue0                                         svalue1
1317c478bd9Sstevel@tonic-gate  *	       |                                               |
1327c478bd9Sstevel@tonic-gate  *	       v                                               v
1337c478bd9Sstevel@tonic-gate  *
1347c478bd9Sstevel@tonic-gate  *	       +-----------------------------------------------+
1357c478bd9Sstevel@tonic-gate  *	       |					       |
1367c478bd9Sstevel@tonic-gate  *	  |  ->|    |<-		->|         |<-		->|    |<-  |
1377c478bd9Sstevel@tonic-gate  *	  |         |		  |         |		  |         |
1387c478bd9Sstevel@tonic-gate  *	  +---------+		  +---------+		  +---------+
1397c478bd9Sstevel@tonic-gate  *
1407c478bd9Sstevel@tonic-gate  *	  ^         ^		  ^         ^		  ^         ^
1417c478bd9Sstevel@tonic-gate  *	  |         |		  |         |		  |         |
1427c478bd9Sstevel@tonic-gate  *	 pcl       pch		 pcl       pch		 pcl       pch
1437c478bd9Sstevel@tonic-gate  *
1447c478bd9Sstevel@tonic-gate  *	For the vax we assert that samples will never fall in the first
1457c478bd9Sstevel@tonic-gate  *	two bytes of any routine, since that is the entry mask,
1467c478bd9Sstevel@tonic-gate  *	thus we give call alignentries() to adjust the entry points if
1477c478bd9Sstevel@tonic-gate  *	the entry mask falls in one bucket but the code for the routine
1487c478bd9Sstevel@tonic-gate  *	doesn't start until the next bucket.  In conjunction with the
1497c478bd9Sstevel@tonic-gate  *	alignment of routine addresses, this should allow us to have
1507c478bd9Sstevel@tonic-gate  *	only one sample for every four bytes of text space and never
1517c478bd9Sstevel@tonic-gate  *	have any overlap (the two end cases, above).
1527c478bd9Sstevel@tonic-gate  */
1537c478bd9Sstevel@tonic-gate static void
asgnsamples(void)15492ed1782Smike_s asgnsamples(void)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	sztype		i, j;
1577c478bd9Sstevel@tonic-gate 	unsigned_UNIT	ccnt;
1587c478bd9Sstevel@tonic-gate 	double		time;
1597c478bd9Sstevel@tonic-gate 	pctype		pcl, pch;
1607c478bd9Sstevel@tonic-gate 	pctype		overlap;
1617c478bd9Sstevel@tonic-gate 	pctype		svalue0, svalue1;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	extern mod_info_t	modules;
1647c478bd9Sstevel@tonic-gate 	nltype		*nl = modules.nl;
1657c478bd9Sstevel@tonic-gate 	sztype		nname = modules.nname;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/* read samples and assign to namelist symbols */
1687c478bd9Sstevel@tonic-gate 	scale = highpc - lowpc;
1697c478bd9Sstevel@tonic-gate 	scale /= nsamples;
1707c478bd9Sstevel@tonic-gate 	alignentries();
1717c478bd9Sstevel@tonic-gate 	for (i = 0, j = 1; i < nsamples; i++) {
1727c478bd9Sstevel@tonic-gate 		ccnt = samples[i];
1737c478bd9Sstevel@tonic-gate 		if (ccnt == 0)
1747c478bd9Sstevel@tonic-gate 			continue;
175*1dd08564Sab196087 		/*LINTED: E_ASSIGMENT_CAUSE_LOSS_PREC*/
1767c478bd9Sstevel@tonic-gate 		pcl = lowpc + scale * i;
177*1dd08564Sab196087 		/*LINTED: E_ASSIGMENT_CAUSE_LOSS_PREC*/
1787c478bd9Sstevel@tonic-gate 		pch = lowpc + scale * (i + 1);
1797c478bd9Sstevel@tonic-gate 		time = ccnt;
1807c478bd9Sstevel@tonic-gate #ifdef DEBUG
1817c478bd9Sstevel@tonic-gate 		if (debug & SAMPLEDEBUG) {
18292ed1782Smike_s 			(void) printf(
18392ed1782Smike_s 			    "[asgnsamples] pcl 0x%llx pch 0x%llx ccnt %d\n",
1847c478bd9Sstevel@tonic-gate 			    pcl, pch, ccnt);
1857c478bd9Sstevel@tonic-gate 		}
18692ed1782Smike_s #endif /* DEBUG */
1877c478bd9Sstevel@tonic-gate 		totime += time;
1887c478bd9Sstevel@tonic-gate 		for (j = (j ? j - 1 : 0); j < nname; j++) {
1897c478bd9Sstevel@tonic-gate 			svalue0 = nl[j].svalue;
1907c478bd9Sstevel@tonic-gate 			svalue1 = nl[j+1].svalue;
1917c478bd9Sstevel@tonic-gate 			/*
1927c478bd9Sstevel@tonic-gate 			 *	if high end of tick is below entry address,
1937c478bd9Sstevel@tonic-gate 			 *	go for next tick.
1947c478bd9Sstevel@tonic-gate 			 */
1957c478bd9Sstevel@tonic-gate 			if (pch < svalue0)
1967c478bd9Sstevel@tonic-gate 				break;
1977c478bd9Sstevel@tonic-gate 			/*
1987c478bd9Sstevel@tonic-gate 			 *	if low end of tick into next routine,
1997c478bd9Sstevel@tonic-gate 			 *	go for next routine.
2007c478bd9Sstevel@tonic-gate 			 */
2017c478bd9Sstevel@tonic-gate 			if (pcl >= svalue1)
2027c478bd9Sstevel@tonic-gate 				continue;
2037c478bd9Sstevel@tonic-gate 			overlap = min(pch, svalue1) - max(pcl, svalue0);
2047c478bd9Sstevel@tonic-gate 			if (overlap != 0) {
2057c478bd9Sstevel@tonic-gate #ifdef DEBUG
2067c478bd9Sstevel@tonic-gate 				if (debug & SAMPLEDEBUG) {
20792ed1782Smike_s 					(void) printf("[asgnsamples] "
2087c478bd9Sstevel@tonic-gate 					    "(0x%llx->0x%llx-0x%llx) %s gets "
2097c478bd9Sstevel@tonic-gate 					    "%f ticks %lld overlap\n",
2107c478bd9Sstevel@tonic-gate 					    nl[j].value/sizeof (UNIT), svalue0,
2117c478bd9Sstevel@tonic-gate 					    svalue1, nl[j].name,
2127c478bd9Sstevel@tonic-gate 					    overlap * time / scale, overlap);
2137c478bd9Sstevel@tonic-gate 				}
21492ed1782Smike_s #endif /* DEBUG */
2157c478bd9Sstevel@tonic-gate 				nl[j].time += overlap * time / scale;
2167c478bd9Sstevel@tonic-gate 			}
2177c478bd9Sstevel@tonic-gate 		}
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate #ifdef DEBUG
2207c478bd9Sstevel@tonic-gate 	if (debug & SAMPLEDEBUG) {
22192ed1782Smike_s 		(void) printf("[asgnsamples] totime %f\n", totime);
2227c478bd9Sstevel@tonic-gate 	}
22392ed1782Smike_s #endif /* DEBUG */
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate static void
dump_callgraph(FILE * fp,char * filename,unsigned long tarcs,unsigned long ncallees)22892ed1782Smike_s dump_callgraph(FILE *fp, char *filename, unsigned long tarcs,
22992ed1782Smike_s     unsigned long ncallees)
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate 	ProfCallGraph		prof_cgraph;
2327c478bd9Sstevel@tonic-gate 	ProfFunction		prof_func;
23392ed1782Smike_s 	arctype	*arcp;
2347c478bd9Sstevel@tonic-gate 	mod_info_t		*mi;
2357c478bd9Sstevel@tonic-gate 	nltype			*nlp;
2367c478bd9Sstevel@tonic-gate 	size_t			cur_offset;
2377c478bd9Sstevel@tonic-gate 	unsigned long		caller_id = 0, callee_id = 0;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/*
2407c478bd9Sstevel@tonic-gate 	 * Write the callgraph header
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 	prof_cgraph.type = PROF_CALLGRAPH_T;
2437c478bd9Sstevel@tonic-gate 	prof_cgraph.version = PROF_CALLGRAPH_VER;
2447c478bd9Sstevel@tonic-gate 	prof_cgraph.functions = PROFCGRAPH_SZ;
2457c478bd9Sstevel@tonic-gate 	prof_cgraph.size = PROFCGRAPH_SZ + tarcs * PROFFUNC_SZ;
2467c478bd9Sstevel@tonic-gate 	if (fwrite(&prof_cgraph, sizeof (ProfCallGraph), 1, fp) != 1) {
2477c478bd9Sstevel@tonic-gate 		perror(filename);
2487c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
2497c478bd9Sstevel@tonic-gate 	}
25092ed1782Smike_s 	/* CONSTCOND */
2517c478bd9Sstevel@tonic-gate 	if (CGRAPH_FILLER)
25292ed1782Smike_s 		(void) fseek(fp, CGRAPH_FILLER, SEEK_CUR);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	/* Current offset inside the callgraph object */
2557c478bd9Sstevel@tonic-gate 	cur_offset = prof_cgraph.functions;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
2587c478bd9Sstevel@tonic-gate 		for (nlp = mi->nl; nlp < mi->npe; nlp++) {
2597c478bd9Sstevel@tonic-gate 			if (nlp->ncallers == 0)
2607c478bd9Sstevel@tonic-gate 				continue;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 			/* If this is the last callee, set next_to to 0 */
2637c478bd9Sstevel@tonic-gate 			callee_id++;
2647c478bd9Sstevel@tonic-gate 			if (callee_id == ncallees)
2657c478bd9Sstevel@tonic-gate 				prof_func.next_to = 0;
2667c478bd9Sstevel@tonic-gate 			else {
2677c478bd9Sstevel@tonic-gate 				prof_func.next_to = cur_offset +
2687c478bd9Sstevel@tonic-gate 				    nlp->ncallers * PROFFUNC_SZ;
2697c478bd9Sstevel@tonic-gate 			}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 			/*
2727c478bd9Sstevel@tonic-gate 			 * Dump this callee's raw arc information with all
2737c478bd9Sstevel@tonic-gate 			 * its callers
2747c478bd9Sstevel@tonic-gate 			 */
2757c478bd9Sstevel@tonic-gate 			caller_id = 1;
2767c478bd9Sstevel@tonic-gate 			for (arcp = nlp->parents; arcp;
2777c478bd9Sstevel@tonic-gate 			    arcp = arcp->arc_parentlist) {
2787c478bd9Sstevel@tonic-gate 				/*
2797c478bd9Sstevel@tonic-gate 				 * If no more callers for this callee, set
2807c478bd9Sstevel@tonic-gate 				 * next_from to 0
2817c478bd9Sstevel@tonic-gate 				 */
2827c478bd9Sstevel@tonic-gate 				if (caller_id == nlp->ncallers)
2837c478bd9Sstevel@tonic-gate 					prof_func.next_from = 0;
2847c478bd9Sstevel@tonic-gate 				else {
2857c478bd9Sstevel@tonic-gate 					prof_func.next_from = cur_offset +
2867c478bd9Sstevel@tonic-gate 					    PROFFUNC_SZ;
2877c478bd9Sstevel@tonic-gate 				}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 				prof_func.frompc =
2907c478bd9Sstevel@tonic-gate 				    arcp->arc_parentp->module->load_base +
2917c478bd9Sstevel@tonic-gate 				    (arcp->arc_parentp->value -
2927c478bd9Sstevel@tonic-gate 				    arcp->arc_parentp->module->txt_origin);
293*1dd08564Sab196087 				prof_func.topc = mi->load_base +
2947c478bd9Sstevel@tonic-gate 				    (nlp->value - mi->txt_origin);
2957c478bd9Sstevel@tonic-gate 				prof_func.count = arcp->arc_count;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 				if (fwrite(&prof_func, sizeof (ProfFunction),
2997c478bd9Sstevel@tonic-gate 				    1, fp) != 1) {
3007c478bd9Sstevel@tonic-gate 					perror(filename);
3017c478bd9Sstevel@tonic-gate 					exit(EX_IOERR);
3027c478bd9Sstevel@tonic-gate 				}
30392ed1782Smike_s 				/* CONSTCOND */
3047c478bd9Sstevel@tonic-gate 				if (FUNC_FILLER)
30592ed1782Smike_s 					(void) fseek(fp, FUNC_FILLER, SEEK_CUR);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 				cur_offset += PROFFUNC_SZ;
3087c478bd9Sstevel@tonic-gate 				caller_id++;
3097c478bd9Sstevel@tonic-gate 			}
3107c478bd9Sstevel@tonic-gate 		} /* for nlp... */
3117c478bd9Sstevel@tonic-gate 	} /* for mi... */
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate  * To save all pc-hits in all the gmon.out's is infeasible, as this
3167c478bd9Sstevel@tonic-gate  * may become quite huge even with a small number of files to sum.
3177c478bd9Sstevel@tonic-gate  * Instead, we'll dump *fictitious hits* to correct functions
3187c478bd9Sstevel@tonic-gate  * by scanning module namelists. Again, since this is summing
3197c478bd9Sstevel@tonic-gate  * pc-hits, we may have to dump the pcsamples out in chunks if the
3207c478bd9Sstevel@tonic-gate  * number of pc-hits is high.
3217c478bd9Sstevel@tonic-gate  */
3227c478bd9Sstevel@tonic-gate static void
dump_hits(FILE * fp,char * filename,nltype * nlp)3237c478bd9Sstevel@tonic-gate dump_hits(FILE *fp, char *filename, nltype *nlp)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate 	Address		*p, hitpc;
3267c478bd9Sstevel@tonic-gate 	size_t		i, nelem, ntowrite;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if ((nelem = nlp->nticks) > PROF_BUFFER_SIZE)
3297c478bd9Sstevel@tonic-gate 		nelem = PROF_BUFFER_SIZE;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	if ((p = (Address *) calloc(nelem, sizeof (Address))) == NULL) {
33292ed1782Smike_s 		(void) fprintf(stderr, "%s: no room for %d pcsamples\n",
3337c478bd9Sstevel@tonic-gate 		    whoami, nelem);
3347c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	/*
3387c478bd9Sstevel@tonic-gate 	 * Set up *fictitious* hits (to function entry) buffer
3397c478bd9Sstevel@tonic-gate 	 */
3407c478bd9Sstevel@tonic-gate 	hitpc = nlp->module->load_base + (nlp->value - nlp->module->txt_origin);
3417c478bd9Sstevel@tonic-gate 	for (i = 0; i < nelem; i++)
3427c478bd9Sstevel@tonic-gate 		p[i] = hitpc;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	for (ntowrite = nlp->nticks; ntowrite >= nelem; ntowrite -= nelem) {
3457c478bd9Sstevel@tonic-gate 		if (fwrite(p, nelem * sizeof (Address), 1, fp) != 1) {
3467c478bd9Sstevel@tonic-gate 			perror(filename);
3477c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	if (ntowrite) {
3527c478bd9Sstevel@tonic-gate 		if (fwrite(p, ntowrite * sizeof (Address), 1, fp) != 1) {
3537c478bd9Sstevel@tonic-gate 			perror(filename);
3547c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	free(p);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate static void
dump_pcsamples(FILE * fp,char * filename,unsigned long * tarcs,unsigned long * ncallees)36292ed1782Smike_s dump_pcsamples(FILE *fp, char *filename, unsigned long *tarcs,
36392ed1782Smike_s     unsigned long *ncallees)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	ProfBuffer		prof_buffer;
36692ed1782Smike_s 	arctype	*arcp;
3677c478bd9Sstevel@tonic-gate 	mod_info_t		*mi;
3687c478bd9Sstevel@tonic-gate 	nltype			*nlp;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	prof_buffer.type = PROF_BUFFER_T;
3717c478bd9Sstevel@tonic-gate 	prof_buffer.version = PROF_BUFFER_VER;
3727c478bd9Sstevel@tonic-gate 	prof_buffer.buffer = PROFBUF_SZ;
3737c478bd9Sstevel@tonic-gate 	prof_buffer.bufsize = n_pcsamples;
3747c478bd9Sstevel@tonic-gate 	prof_buffer.size = PROFBUF_SZ + n_pcsamples * sizeof (Address);
3757c478bd9Sstevel@tonic-gate 	if (fwrite(&prof_buffer, sizeof (ProfBuffer), 1, fp) != 1) {
3767c478bd9Sstevel@tonic-gate 		perror(filename);
3777c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
3787c478bd9Sstevel@tonic-gate 	}
37992ed1782Smike_s 	/* CONSTCOND */
3807c478bd9Sstevel@tonic-gate 	if (BUF_FILLER)
38192ed1782Smike_s 		(void) fseek(fp, BUF_FILLER, SEEK_CUR);
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	*tarcs = 0;
3847c478bd9Sstevel@tonic-gate 	*ncallees = 0;
3857c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
3867c478bd9Sstevel@tonic-gate 		for (nlp = mi->nl; nlp < mi->npe; nlp++) {
3877c478bd9Sstevel@tonic-gate 			if (nlp->nticks)
3887c478bd9Sstevel@tonic-gate 				dump_hits(fp, filename, nlp);
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 			nlp->ncallers = 0;
3917c478bd9Sstevel@tonic-gate 			for (arcp = nlp->parents; arcp;
3927c478bd9Sstevel@tonic-gate 			    arcp = arcp->arc_parentlist) {
3937c478bd9Sstevel@tonic-gate 				(nlp->ncallers)++;
3947c478bd9Sstevel@tonic-gate 			}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 			if (nlp->ncallers) {
3977c478bd9Sstevel@tonic-gate 				(*tarcs) += nlp->ncallers;
3987c478bd9Sstevel@tonic-gate 				(*ncallees)++;
3997c478bd9Sstevel@tonic-gate 			}
4007c478bd9Sstevel@tonic-gate 		}
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate static void
dump_modules(FILE * fp,char * filename,size_t pbuf_sz)4057c478bd9Sstevel@tonic-gate dump_modules(FILE *fp, char *filename, size_t pbuf_sz)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	char		*pbuf, *p;
4087c478bd9Sstevel@tonic-gate 	size_t		namelen;
4097c478bd9Sstevel@tonic-gate 	Index		off_nxt, off_path;
4107c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	ProfModuleList	prof_modlist;
4137c478bd9Sstevel@tonic-gate 	ProfModule	prof_mod;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/* Allocate for path strings buffer */
4167c478bd9Sstevel@tonic-gate 	pbuf_sz = CEIL(pbuf_sz, STRUCT_ALIGN);
41792ed1782Smike_s 	if ((p = pbuf = calloc(pbuf_sz, sizeof (char))) == NULL) {
41892ed1782Smike_s 		(void) fprintf(stderr, "%s: no room for %d bytes\n",
4197c478bd9Sstevel@tonic-gate 		    whoami, pbuf_sz * sizeof (char));
4207c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/* Dump out PROF_MODULE_T info for all non-aout modules */
4247c478bd9Sstevel@tonic-gate 	prof_modlist.type = PROF_MODULES_T;
4257c478bd9Sstevel@tonic-gate 	prof_modlist.version = PROF_MODULES_VER;
4267c478bd9Sstevel@tonic-gate 	prof_modlist.modules = PROFMODLIST_SZ;
4277c478bd9Sstevel@tonic-gate 	prof_modlist.size = PROFMODLIST_SZ + (n_modules - 1) * PROFMOD_SZ +
4287c478bd9Sstevel@tonic-gate 	    pbuf_sz;
4297c478bd9Sstevel@tonic-gate 	if (fwrite(&prof_modlist, sizeof (ProfModuleList), 1, fp) != 1) {
4307c478bd9Sstevel@tonic-gate 		perror(filename);
4317c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
4327c478bd9Sstevel@tonic-gate 	}
43392ed1782Smike_s 	/* CONSTCOND */
4347c478bd9Sstevel@tonic-gate 	if (MODLIST_FILLER)
43592ed1782Smike_s 		(void) fseek(fp, MODLIST_FILLER, SEEK_CUR);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	/*
4387c478bd9Sstevel@tonic-gate 	 * Initialize offsets for ProfModule elements.
4397c478bd9Sstevel@tonic-gate 	 */
4407c478bd9Sstevel@tonic-gate 	off_nxt = PROFMODLIST_SZ + PROFMOD_SZ;
4417c478bd9Sstevel@tonic-gate 	off_path = PROFMODLIST_SZ + (n_modules - 1) * PROFMOD_SZ;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	for (mi = modules.next; mi; mi = mi->next) {
4447c478bd9Sstevel@tonic-gate 		if (mi->next)
4457c478bd9Sstevel@tonic-gate 			prof_mod.next = off_nxt;
4467c478bd9Sstevel@tonic-gate 		else
4477c478bd9Sstevel@tonic-gate 			prof_mod.next = 0;
4487c478bd9Sstevel@tonic-gate 		prof_mod.path = off_path;
4497c478bd9Sstevel@tonic-gate 		prof_mod.startaddr = mi->load_base;
4507c478bd9Sstevel@tonic-gate 		prof_mod.endaddr = mi->load_end;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 		if (fwrite(&prof_mod, sizeof (ProfModule), 1, fp) != 1) {
4537c478bd9Sstevel@tonic-gate 			perror(filename);
4547c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
4557c478bd9Sstevel@tonic-gate 		}
4567c478bd9Sstevel@tonic-gate 
45792ed1782Smike_s 		/* CONSTCOND */
4587c478bd9Sstevel@tonic-gate 		if (MOD_FILLER)
45992ed1782Smike_s 			(void) fseek(fp, MOD_FILLER, SEEK_CUR);
4607c478bd9Sstevel@tonic-gate 
46192ed1782Smike_s 		(void) strcpy(p, mi->name);
4627c478bd9Sstevel@tonic-gate 		namelen = strlen(mi->name);
4637c478bd9Sstevel@tonic-gate 		p += namelen + 1;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 		/* Note that offset to every path str need not be aligned */
4667c478bd9Sstevel@tonic-gate 		off_nxt += PROFMOD_SZ;
4677c478bd9Sstevel@tonic-gate 		off_path += namelen + 1;
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	/* Write out the module path strings */
4717c478bd9Sstevel@tonic-gate 	if (pbuf_sz) {
4727c478bd9Sstevel@tonic-gate 		if (fwrite(pbuf, pbuf_sz, 1, fp) != 1) {
4737c478bd9Sstevel@tonic-gate 			perror(filename);
4747c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
4757c478bd9Sstevel@tonic-gate 		}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		free(pbuf);
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate  * If we have inactive modules, their current load addresses may overlap with
4837c478bd9Sstevel@tonic-gate  * active ones, and so we've to assign fictitious, non-overlapping addresses
4847c478bd9Sstevel@tonic-gate  * to all modules before we dump them.
4857c478bd9Sstevel@tonic-gate  */
4867c478bd9Sstevel@tonic-gate static void
fixup_maps(size_t * pathsz)4877c478bd9Sstevel@tonic-gate fixup_maps(size_t *pathsz)
4887c478bd9Sstevel@tonic-gate {
4897c478bd9Sstevel@tonic-gate 	unsigned int	n_inactive = 0;
49092ed1782Smike_s 	Address		lbase = 0, lend;
4917c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	/* Pick the lowest load address among modules */
4947c478bd9Sstevel@tonic-gate 	*pathsz = 0;
4957c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 		if (mi->active == FALSE)
4987c478bd9Sstevel@tonic-gate 			n_inactive++;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		if (mi == &modules || mi->load_base < lbase)
5017c478bd9Sstevel@tonic-gate 			lbase = mi->load_base;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		/*
5047c478bd9Sstevel@tonic-gate 		 * Return total path size of non-aout modules only
5057c478bd9Sstevel@tonic-gate 		 */
5067c478bd9Sstevel@tonic-gate 		if (mi != &modules)
5077c478bd9Sstevel@tonic-gate 			*pathsz = (*pathsz) + strlen(mi->name) + 1;
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	/*
5117c478bd9Sstevel@tonic-gate 	 * All module info is in fine shape already if there are no
5127c478bd9Sstevel@tonic-gate 	 * inactive modules
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 	if (n_inactive == 0)
5157c478bd9Sstevel@tonic-gate 		return;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	/*
5187c478bd9Sstevel@tonic-gate 	 * Assign fictitious load addresses to all (non-aout) modules so
5197c478bd9Sstevel@tonic-gate 	 * that sum info can be dumped out.
5207c478bd9Sstevel@tonic-gate 	 */
5217c478bd9Sstevel@tonic-gate 	for (mi = modules.next; mi; mi = mi->next) {
5227c478bd9Sstevel@tonic-gate 		lend = lbase + (mi->data_end - mi->txt_origin);
5237c478bd9Sstevel@tonic-gate 		if ((lbase < modules.load_base && lend < modules.load_base) ||
5247c478bd9Sstevel@tonic-gate 		    (lbase > modules.load_end && lend > modules.load_end)) {
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 			mi->load_base = lbase;
5277c478bd9Sstevel@tonic-gate 			mi->load_end = lend;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 			/* just to give an appearance of reality */
5307c478bd9Sstevel@tonic-gate 			lbase = CEIL(lend + PGSZ, PGSZ);
5317c478bd9Sstevel@tonic-gate 		} else {
5327c478bd9Sstevel@tonic-gate 			/*
5337c478bd9Sstevel@tonic-gate 			 * can't use this lbase & lend pair, as it
5347c478bd9Sstevel@tonic-gate 			 * overlaps with aout's addresses
5357c478bd9Sstevel@tonic-gate 			 */
5367c478bd9Sstevel@tonic-gate 			mi->load_base = CEIL(modules.load_end + PGSZ, PGSZ);
5377c478bd9Sstevel@tonic-gate 			mi->load_end = mi->load_base + (lend - lbase);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 			lbase = CEIL(mi->load_end + PGSZ, PGSZ);
5407c478bd9Sstevel@tonic-gate 		}
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate static void
dump_gprofhdr(FILE * fp,char * filename)5457c478bd9Sstevel@tonic-gate dump_gprofhdr(FILE *fp, char *filename)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	ProfHeader	prof_hdr;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	prof_hdr.h_magic = PROF_MAGIC;
5507c478bd9Sstevel@tonic-gate 	prof_hdr.h_major_ver = PROF_MAJOR_VERSION;
5517c478bd9Sstevel@tonic-gate 	prof_hdr.h_minor_ver = PROF_MINOR_VERSION;
5527c478bd9Sstevel@tonic-gate 	prof_hdr.size = PROFHDR_SZ;
5537c478bd9Sstevel@tonic-gate 	if (fwrite(&prof_hdr, sizeof (prof_hdr), 1, fp) != 1) {
5547c478bd9Sstevel@tonic-gate 		perror(filename);
5557c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
55892ed1782Smike_s 	/* CONSTCOND */
5597c478bd9Sstevel@tonic-gate 	if (HDR_FILLER)
56092ed1782Smike_s 		(void) fseek(fp, HDR_FILLER, SEEK_CUR);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate static void
dumpsum_ostyle(char * sumfile)5647c478bd9Sstevel@tonic-gate dumpsum_ostyle(char *sumfile)
5657c478bd9Sstevel@tonic-gate {
56692ed1782Smike_s 	nltype *nlp;
56792ed1782Smike_s 	arctype *arcp;
5687c478bd9Sstevel@tonic-gate 	struct rawarc arc;
5697c478bd9Sstevel@tonic-gate 	struct rawarc32 arc32;
5707c478bd9Sstevel@tonic-gate 	FILE *sfile;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	if ((sfile = fopen(sumfile, "w")) == NULL) {
5737c478bd9Sstevel@tonic-gate 		perror(sumfile);
5747c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 	/*
5777c478bd9Sstevel@tonic-gate 	 * dump the header; use the last header read in
5787c478bd9Sstevel@tonic-gate 	 */
5797c478bd9Sstevel@tonic-gate 	if (Bflag) {
5807c478bd9Sstevel@tonic-gate 		if (fwrite(&h, sizeof (h), 1, sfile) != 1) {
5817c478bd9Sstevel@tonic-gate 			perror(sumfile);
5827c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	} else {
5857c478bd9Sstevel@tonic-gate 		struct hdr32 hdr;
5867c478bd9Sstevel@tonic-gate 		hdr.lowpc  = (pctype32)h.lowpc;
5877c478bd9Sstevel@tonic-gate 		hdr.highpc = (pctype32)h.highpc;
5887c478bd9Sstevel@tonic-gate 		hdr.ncnt   = (pctype32)h.ncnt;
5897c478bd9Sstevel@tonic-gate 		if (fwrite(&hdr, sizeof (hdr), 1, sfile) != 1) {
5907c478bd9Sstevel@tonic-gate 			perror(sumfile);
5917c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
5927c478bd9Sstevel@tonic-gate 		}
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 	/*
5957c478bd9Sstevel@tonic-gate 	 * dump the samples
5967c478bd9Sstevel@tonic-gate 	 */
5977c478bd9Sstevel@tonic-gate 	if (fwrite(samples, sizeof (unsigned_UNIT), nsamples, sfile) !=
5987c478bd9Sstevel@tonic-gate 	    nsamples) {
5997c478bd9Sstevel@tonic-gate 		perror(sumfile);
6007c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 	/*
6037c478bd9Sstevel@tonic-gate 	 * dump the normalized raw arc information. For old-style dumping,
6047c478bd9Sstevel@tonic-gate 	 * the only namelist is in modules.nl
6057c478bd9Sstevel@tonic-gate 	 */
6067c478bd9Sstevel@tonic-gate 	for (nlp = modules.nl; nlp < modules.npe; nlp++) {
6077c478bd9Sstevel@tonic-gate 		for (arcp = nlp->children; arcp;
6087c478bd9Sstevel@tonic-gate 		    arcp = arcp->arc_childlist) {
6097c478bd9Sstevel@tonic-gate 			if (Bflag) {
6107c478bd9Sstevel@tonic-gate 				arc.raw_frompc = arcp->arc_parentp->value;
6117c478bd9Sstevel@tonic-gate 				arc.raw_selfpc = arcp->arc_childp->value;
6127c478bd9Sstevel@tonic-gate 				arc.raw_count = arcp->arc_count;
6137c478bd9Sstevel@tonic-gate 				if (fwrite(&arc, sizeof (arc), 1, sfile) != 1) {
6147c478bd9Sstevel@tonic-gate 					perror(sumfile);
6157c478bd9Sstevel@tonic-gate 					exit(EX_IOERR);
6167c478bd9Sstevel@tonic-gate 				}
6177c478bd9Sstevel@tonic-gate 			} else {
6187c478bd9Sstevel@tonic-gate 				arc32.raw_frompc =
6197c478bd9Sstevel@tonic-gate 				    (pctype32)arcp->arc_parentp->value;
6207c478bd9Sstevel@tonic-gate 				arc32.raw_selfpc =
6217c478bd9Sstevel@tonic-gate 				    (pctype32)arcp->arc_childp->value;
6227c478bd9Sstevel@tonic-gate 				arc32.raw_count = (actype32)arcp->arc_count;
623*1dd08564Sab196087 				if (fwrite(&arc32, sizeof (arc32), 1, sfile) !=
624*1dd08564Sab196087 				    1) {
6257c478bd9Sstevel@tonic-gate 					perror(sumfile);
6267c478bd9Sstevel@tonic-gate 					exit(EX_IOERR);
6277c478bd9Sstevel@tonic-gate 				}
6287c478bd9Sstevel@tonic-gate 			}
6297c478bd9Sstevel@tonic-gate #ifdef DEBUG
6307c478bd9Sstevel@tonic-gate 			if (debug & SAMPLEDEBUG) {
63192ed1782Smike_s 				(void) printf(
63292ed1782Smike_s 				    "[dumpsum_ostyle] frompc 0x%llx selfpc "
6337c478bd9Sstevel@tonic-gate 				    "0x%llx count %lld\n", arc.raw_frompc,
6347c478bd9Sstevel@tonic-gate 				    arc.raw_selfpc, arc.raw_count);
6357c478bd9Sstevel@tonic-gate 			}
63692ed1782Smike_s #endif /* DEBUG */
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 	}
63992ed1782Smike_s 	(void) fclose(sfile);
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate  * dump out the gmon.sum file
6447c478bd9Sstevel@tonic-gate  */
6457c478bd9Sstevel@tonic-gate static void
dumpsum(char * sumfile)6467c478bd9Sstevel@tonic-gate dumpsum(char *sumfile)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	FILE		*sfile;
6497c478bd9Sstevel@tonic-gate 	size_t		pathbuf_sz;
6507c478bd9Sstevel@tonic-gate 	unsigned long	total_arcs;	/* total number of arcs in all */
6517c478bd9Sstevel@tonic-gate 	unsigned long	ncallees;	/* no. of callees with parents */
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	if (old_style) {
6547c478bd9Sstevel@tonic-gate 		dumpsum_ostyle(sumfile);
6557c478bd9Sstevel@tonic-gate 		return;
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	if ((sfile = fopen(sumfile, "w")) == NULL) {
6597c478bd9Sstevel@tonic-gate 		perror(sumfile);
6607c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	/*
6647c478bd9Sstevel@tonic-gate 	 * Dump the new-style gprof header. Even if one of the original
6657c478bd9Sstevel@tonic-gate 	 * profiled-files was of a older version, the summed file is of
6667c478bd9Sstevel@tonic-gate 	 * current version only.
6677c478bd9Sstevel@tonic-gate 	 */
6687c478bd9Sstevel@tonic-gate 	dump_gprofhdr(sfile, sumfile);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	/*
6717c478bd9Sstevel@tonic-gate 	 * Fix up load-maps and dump out modules info
6727c478bd9Sstevel@tonic-gate 	 *
6737c478bd9Sstevel@tonic-gate 	 * Fix up module load maps so inactive modules get *some* address
6747c478bd9Sstevel@tonic-gate 	 * (and btw, could you get the total size of non-aout module path
6757c478bd9Sstevel@tonic-gate 	 * strings please ?)
6767c478bd9Sstevel@tonic-gate 	 */
6777c478bd9Sstevel@tonic-gate 	fixup_maps(&pathbuf_sz);
6787c478bd9Sstevel@tonic-gate 	dump_modules(sfile, sumfile, pathbuf_sz);
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	/*
6827c478bd9Sstevel@tonic-gate 	 * Dump out the summ'd pcsamples
6837c478bd9Sstevel@tonic-gate 	 *
6847c478bd9Sstevel@tonic-gate 	 * For dumping call graph information later, we need certain
6857c478bd9Sstevel@tonic-gate 	 * statistics (like total arcs, number of callers for each node);
6867c478bd9Sstevel@tonic-gate 	 * collect these also while we are at it.
6877c478bd9Sstevel@tonic-gate 	 */
6887c478bd9Sstevel@tonic-gate 	dump_pcsamples(sfile, sumfile, &total_arcs, &ncallees);
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	/*
6917c478bd9Sstevel@tonic-gate 	 * Dump out the summ'd call graph information
6927c478bd9Sstevel@tonic-gate 	 */
6937c478bd9Sstevel@tonic-gate 	dump_callgraph(sfile, sumfile, total_arcs, ncallees);
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 
69692ed1782Smike_s 	(void) fclose(sfile);
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate static void
tally(mod_info_t * caller_mod,mod_info_t * callee_mod,struct rawarc * rawp)7007c478bd9Sstevel@tonic-gate tally(mod_info_t *caller_mod, mod_info_t *callee_mod, struct rawarc *rawp)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	nltype		*parentp;
7037c478bd9Sstevel@tonic-gate 	nltype		*childp;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	/*
7067c478bd9Sstevel@tonic-gate 	 * if count == 0 this is a null arc and
7077c478bd9Sstevel@tonic-gate 	 * we don't need to tally it.
7087c478bd9Sstevel@tonic-gate 	 */
7097c478bd9Sstevel@tonic-gate 	if (rawp->raw_count == 0)
7107c478bd9Sstevel@tonic-gate 		return;
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	/*
7137c478bd9Sstevel@tonic-gate 	 * Lookup the caller and callee pcs in namelists of
7147c478bd9Sstevel@tonic-gate 	 * appropriate modules
7157c478bd9Sstevel@tonic-gate 	 */
7167c478bd9Sstevel@tonic-gate 	parentp = nllookup(caller_mod, rawp->raw_frompc, NULL);
7177c478bd9Sstevel@tonic-gate 	childp = nllookup(callee_mod, rawp->raw_selfpc, NULL);
7187c478bd9Sstevel@tonic-gate 	if (childp && parentp) {
7197c478bd9Sstevel@tonic-gate 		if (!Dflag)
7207c478bd9Sstevel@tonic-gate 			childp->ncall += rawp->raw_count;
7217c478bd9Sstevel@tonic-gate 		else {
7227c478bd9Sstevel@tonic-gate 			if (first_file)
7237c478bd9Sstevel@tonic-gate 				childp->ncall += rawp->raw_count;
7247c478bd9Sstevel@tonic-gate 			else {
7257c478bd9Sstevel@tonic-gate 				childp->ncall -= rawp->raw_count;
7267c478bd9Sstevel@tonic-gate 				if (childp->ncall < 0)
7277c478bd9Sstevel@tonic-gate 					childp->ncall = 0;
7287c478bd9Sstevel@tonic-gate 			}
7297c478bd9Sstevel@tonic-gate 		}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate #ifdef DEBUG
7327c478bd9Sstevel@tonic-gate 		if (debug & TALLYDEBUG) {
73392ed1782Smike_s 			(void) printf("[tally] arc from %s to %s traversed "
7347c478bd9Sstevel@tonic-gate 			    "%lld times\n", parentp->name,
7357c478bd9Sstevel@tonic-gate 			    childp->name, rawp->raw_count);
7367c478bd9Sstevel@tonic-gate 		}
73792ed1782Smike_s #endif /* DEBUG */
7387c478bd9Sstevel@tonic-gate 		addarc(parentp, childp, rawp->raw_count);
7397c478bd9Sstevel@tonic-gate 	}
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate /*
7437c478bd9Sstevel@tonic-gate  * Look up a module's base address in a sorted list of pc-hits. Unlike
7447c478bd9Sstevel@tonic-gate  * nllookup(), this deals with misses by mapping them to the next *higher*
7457c478bd9Sstevel@tonic-gate  * pc-hit. This is so that we get into the module's first pc-hit rightaway,
7467c478bd9Sstevel@tonic-gate  * even if the module's entry-point (load_base) itself is not a hit.
7477c478bd9Sstevel@tonic-gate  */
7487c478bd9Sstevel@tonic-gate static Address *
locate(Address * pclist,size_t nelem,Address keypc)7497c478bd9Sstevel@tonic-gate locate(Address	*pclist, size_t nelem, Address keypc)
7507c478bd9Sstevel@tonic-gate {
7517c478bd9Sstevel@tonic-gate 	size_t	low = 0, middle, high = nelem - 1;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	if (keypc <= pclist[low])
7547c478bd9Sstevel@tonic-gate 		return (pclist);
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	if (keypc > pclist[high])
7577c478bd9Sstevel@tonic-gate 		return (NULL);
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	while (low != high) {
7607c478bd9Sstevel@tonic-gate 		middle = (high + low) >> 1;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		if ((pclist[middle] < keypc) && (pclist[middle + 1] >= keypc))
7637c478bd9Sstevel@tonic-gate 			return (&pclist[middle + 1]);
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 		if (pclist[middle] >= keypc)
7667c478bd9Sstevel@tonic-gate 			high = middle;
7677c478bd9Sstevel@tonic-gate 		else
7687c478bd9Sstevel@tonic-gate 			low = middle + 1;
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/* must never reach here! */
7727c478bd9Sstevel@tonic-gate 	return (NULL);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate static void
assign_pcsamples(mod_info_t * module,Address * pcsmpl,size_t n_samples)77692ed1782Smike_s assign_pcsamples(mod_info_t *module, Address *pcsmpl, size_t n_samples)
7777c478bd9Sstevel@tonic-gate {
7787c478bd9Sstevel@tonic-gate 	Address		*pcptr, *pcse = pcsmpl + n_samples;
7797c478bd9Sstevel@tonic-gate 	pctype		nxt_func;
7807c478bd9Sstevel@tonic-gate 	nltype		*fnl;
7817c478bd9Sstevel@tonic-gate 	size_t		func_nticks;
7827c478bd9Sstevel@tonic-gate #ifdef DEBUG
7837c478bd9Sstevel@tonic-gate 	size_t		n_hits_in_module = 0;
78492ed1782Smike_s #endif /* DEBUG */
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	/* Locate the first pc-hit for this module */
7877c478bd9Sstevel@tonic-gate 	if ((pcptr = locate(pcsmpl, n_samples, module->load_base)) == NULL) {
7887c478bd9Sstevel@tonic-gate #ifdef DEBUG
7897c478bd9Sstevel@tonic-gate 		if (debug & PCSMPLDEBUG) {
79092ed1782Smike_s 			(void) printf("[assign_pcsamples] no pc-hits in\n");
79192ed1782Smike_s 			(void) printf(
79292ed1782Smike_s 			    "                   `%s'\n", module->name);
7937c478bd9Sstevel@tonic-gate 		}
79492ed1782Smike_s #endif /* DEBUG */
7957c478bd9Sstevel@tonic-gate 		return;			/* no pc-hits in this module */
7967c478bd9Sstevel@tonic-gate 	}
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	/* Assign all pc-hits in this module to appropriate functions */
7997c478bd9Sstevel@tonic-gate 	while ((pcptr < pcse) && (*pcptr < module->load_end)) {
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 		/* Update the corresponding function's time */
8027c478bd9Sstevel@tonic-gate 		if (fnl = nllookup(module, (pctype) *pcptr, &nxt_func)) {
8037c478bd9Sstevel@tonic-gate 			/*
8047c478bd9Sstevel@tonic-gate 			 * Collect all pc-hits in this function. Each
8057c478bd9Sstevel@tonic-gate 			 * pc-hit counts as 1 tick.
8067c478bd9Sstevel@tonic-gate 			 */
8077c478bd9Sstevel@tonic-gate 			func_nticks = 0;
8087c478bd9Sstevel@tonic-gate 			while ((pcptr < pcse) && (*pcptr < nxt_func)) {
8097c478bd9Sstevel@tonic-gate 				func_nticks++;
8107c478bd9Sstevel@tonic-gate 				pcptr++;
8117c478bd9Sstevel@tonic-gate 			}
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 			if (func_nticks == 0)
8147c478bd9Sstevel@tonic-gate 				pcptr++;
8157c478bd9Sstevel@tonic-gate 			else {
8167c478bd9Sstevel@tonic-gate 				fnl->nticks += func_nticks;
8177c478bd9Sstevel@tonic-gate 				fnl->time += func_nticks;
8187c478bd9Sstevel@tonic-gate 				totime += func_nticks;
8197c478bd9Sstevel@tonic-gate 			}
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate #ifdef DEBUG
8227c478bd9Sstevel@tonic-gate 			n_hits_in_module += func_nticks;
82392ed1782Smike_s #endif /* DEBUG */
8247c478bd9Sstevel@tonic-gate 		} else {
8257c478bd9Sstevel@tonic-gate 			/*
8267c478bd9Sstevel@tonic-gate 			 * pc sample could not be assigned to function;
8277c478bd9Sstevel@tonic-gate 			 * probably in a PLT
8287c478bd9Sstevel@tonic-gate 			 */
8297c478bd9Sstevel@tonic-gate 			pcptr++;
8307c478bd9Sstevel@tonic-gate 		}
8317c478bd9Sstevel@tonic-gate 	}
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate #ifdef DEBUG
8347c478bd9Sstevel@tonic-gate 	if (debug & PCSMPLDEBUG) {
83592ed1782Smike_s 		(void) printf(
83692ed1782Smike_s 		    "[assign_pcsamples] %ld hits in\n", n_hits_in_module);
83792ed1782Smike_s 		(void) printf("                   `%s'\n", module->name);
8387c478bd9Sstevel@tonic-gate 	}
83992ed1782Smike_s #endif /* DEBUG */
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate int
pc_cmp(const void * arg1,const void * arg2)84392ed1782Smike_s pc_cmp(const void *arg1, const void *arg2)
8447c478bd9Sstevel@tonic-gate {
84592ed1782Smike_s 	Address *pc1 = (Address *)arg1;
84692ed1782Smike_s 	Address *pc2 = (Address *)arg2;
84792ed1782Smike_s 
8487c478bd9Sstevel@tonic-gate 	if (*pc1 > *pc2)
8497c478bd9Sstevel@tonic-gate 		return (1);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	if (*pc1 < *pc2)
8527c478bd9Sstevel@tonic-gate 		return (-1);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	return (0);
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate static void
process_pcsamples(ProfBuffer * bufp)85892ed1782Smike_s process_pcsamples(ProfBuffer *bufp)
8597c478bd9Sstevel@tonic-gate {
8607c478bd9Sstevel@tonic-gate 	Address		*pc_samples;
8617c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
8627c478bd9Sstevel@tonic-gate 	caddr_t		p;
8637c478bd9Sstevel@tonic-gate 	size_t		chunk_size, nelem_read, nelem_to_read;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate #ifdef DEBUG
8667c478bd9Sstevel@tonic-gate 	if (debug & PCSMPLDEBUG) {
86792ed1782Smike_s 		(void) printf(
86892ed1782Smike_s 		    "[process_pcsamples] number of pcsamples = %lld\n",
8697c478bd9Sstevel@tonic-gate 		    bufp->bufsize);
8707c478bd9Sstevel@tonic-gate 	}
87192ed1782Smike_s #endif /* DEBUG */
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	/* buffer with no pc samples ? */
8747c478bd9Sstevel@tonic-gate 	if (bufp->bufsize == 0)
8757c478bd9Sstevel@tonic-gate 		return;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	/*
8787c478bd9Sstevel@tonic-gate 	 * If we're processing pcsamples of a profile sum, we could have
8797c478bd9Sstevel@tonic-gate 	 * more than PROF_BUFFER_SIZE number of samples. In such a case,
8807c478bd9Sstevel@tonic-gate 	 * we must read the pcsamples in chunks.
8817c478bd9Sstevel@tonic-gate 	 */
8827c478bd9Sstevel@tonic-gate 	if ((chunk_size = bufp->bufsize) > PROF_BUFFER_SIZE)
8837c478bd9Sstevel@tonic-gate 		chunk_size = PROF_BUFFER_SIZE;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	/* Allocate for the pcsample chunk */
8867c478bd9Sstevel@tonic-gate 	pc_samples = (Address *) calloc(chunk_size, sizeof (Address));
8877c478bd9Sstevel@tonic-gate 	if (pc_samples == NULL) {
88892ed1782Smike_s 		(void) fprintf(stderr, "%s: no room for %d sample pc's\n",
8897c478bd9Sstevel@tonic-gate 		    whoami, chunk_size);
8907c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	/* Copy the current set of pcsamples */
8947c478bd9Sstevel@tonic-gate 	nelem_read = 0;
8957c478bd9Sstevel@tonic-gate 	nelem_to_read = bufp->bufsize;
8967c478bd9Sstevel@tonic-gate 	p = (char *)bufp + bufp->buffer;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	while (nelem_read < nelem_to_read) {
89992ed1782Smike_s 		(void) memcpy((void *) pc_samples, p,
90092ed1782Smike_s 		    chunk_size * sizeof (Address));
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 		/* Sort the pc samples */
90392ed1782Smike_s 		qsort(pc_samples, chunk_size, sizeof (Address), pc_cmp);
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 		/*
9067c478bd9Sstevel@tonic-gate 		 * Assign pcsamples to functions in the currently active
9077c478bd9Sstevel@tonic-gate 		 * module list
9087c478bd9Sstevel@tonic-gate 		 */
9097c478bd9Sstevel@tonic-gate 		for (mi = &modules; mi; mi = mi->next) {
9107c478bd9Sstevel@tonic-gate 			if (mi->active == FALSE)
9117c478bd9Sstevel@tonic-gate 				continue;
9127c478bd9Sstevel@tonic-gate 			assign_pcsamples(mi, pc_samples, chunk_size);
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 		p += (chunk_size * sizeof (Address));
9167c478bd9Sstevel@tonic-gate 		nelem_read += chunk_size;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		if ((nelem_to_read - nelem_read) < chunk_size)
9197c478bd9Sstevel@tonic-gate 			chunk_size = nelem_to_read - nelem_read;
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	free(pc_samples);
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	/* Update total number of pcsamples read so far */
9257c478bd9Sstevel@tonic-gate 	n_pcsamples += bufp->bufsize;
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate static mod_info_t *
find_module(Address addr)9297c478bd9Sstevel@tonic-gate find_module(Address addr)
9307c478bd9Sstevel@tonic-gate {
9317c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
9347c478bd9Sstevel@tonic-gate 		if (mi->active == FALSE)
9357c478bd9Sstevel@tonic-gate 			continue;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 		if (addr >= mi->load_base && addr < mi->load_end)
9387c478bd9Sstevel@tonic-gate 			return (mi);
9397c478bd9Sstevel@tonic-gate 	}
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	return (NULL);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate static void
process_cgraph(ProfCallGraph * cgp)94592ed1782Smike_s process_cgraph(ProfCallGraph *cgp)
9467c478bd9Sstevel@tonic-gate {
9477c478bd9Sstevel@tonic-gate 	struct rawarc	arc;
9487c478bd9Sstevel@tonic-gate 	mod_info_t	*callee_mi, *caller_mi;
9497c478bd9Sstevel@tonic-gate 	ProfFunction	*calleep, *callerp;
9507c478bd9Sstevel@tonic-gate 	Index		caller_off, callee_off;
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	/*
9537c478bd9Sstevel@tonic-gate 	 * Note that *callee_off* increment in the for loop below
9547c478bd9Sstevel@tonic-gate 	 * uses *calleep* and *calleep* doesn't get set until the for loop
9557c478bd9Sstevel@tonic-gate 	 * is entered. We don't expect the increment to be executed before
9567c478bd9Sstevel@tonic-gate 	 * the loop body is executed atleast once, so this should be ok.
9577c478bd9Sstevel@tonic-gate 	 */
9587c478bd9Sstevel@tonic-gate 	for (callee_off = cgp->functions; callee_off;
9597c478bd9Sstevel@tonic-gate 	    callee_off = calleep->next_to) {
9607c478bd9Sstevel@tonic-gate 
96192ed1782Smike_s 		/* LINTED: pointer cast */
9627c478bd9Sstevel@tonic-gate 		calleep = (ProfFunction *)((char *)cgp + callee_off);
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 		/*
9657c478bd9Sstevel@tonic-gate 		 * We could choose either to sort the {caller, callee}
9667c478bd9Sstevel@tonic-gate 		 * list twice and assign callee/caller to modules or inspect
9677c478bd9Sstevel@tonic-gate 		 * each callee/caller in the active modules list. Since
9687c478bd9Sstevel@tonic-gate 		 * the modules list is usually very small, we'l choose the
9697c478bd9Sstevel@tonic-gate 		 * latter.
9707c478bd9Sstevel@tonic-gate 		 */
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 		/*
9737c478bd9Sstevel@tonic-gate 		 * If we cannot identify a callee with a module, there's
9747c478bd9Sstevel@tonic-gate 		 * no use worrying about who called it.
9757c478bd9Sstevel@tonic-gate 		 */
9767c478bd9Sstevel@tonic-gate 		if ((callee_mi = find_module(calleep->topc)) == NULL) {
9777c478bd9Sstevel@tonic-gate #ifdef DEBUG
9787c478bd9Sstevel@tonic-gate 			if (debug & CGRAPHDEBUG) {
97992ed1782Smike_s 				(void) printf(
98092ed1782Smike_s 				    "[process_cgraph] callee %#llx missed\n",
9817c478bd9Sstevel@tonic-gate 				    calleep->topc);
9827c478bd9Sstevel@tonic-gate 			}
98392ed1782Smike_s #endif /* DEBUG */
9847c478bd9Sstevel@tonic-gate 			continue;
9857c478bd9Sstevel@tonic-gate 		} else
9867c478bd9Sstevel@tonic-gate 			arc.raw_selfpc = calleep->topc;
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		for (caller_off = callee_off; caller_off;
9897c478bd9Sstevel@tonic-gate 		    caller_off = callerp->next_from)  {
9907c478bd9Sstevel@tonic-gate 
99192ed1782Smike_s 			/* LINTED: pointer cast */
9927c478bd9Sstevel@tonic-gate 			callerp = (ProfFunction *)((char *)cgp + caller_off);
9937c478bd9Sstevel@tonic-gate 			if ((caller_mi = find_module(callerp->frompc)) ==
9947c478bd9Sstevel@tonic-gate 			    NULL) {
9957c478bd9Sstevel@tonic-gate #ifdef DEBUG
9967c478bd9Sstevel@tonic-gate 				if (debug & CGRAPHDEBUG) {
99792ed1782Smike_s 					(void) printf(
99892ed1782Smike_s 					    "[process_cgraph] caller %#llx "
9997c478bd9Sstevel@tonic-gate 					    "missed\n", callerp->frompc);
10007c478bd9Sstevel@tonic-gate 				}
100192ed1782Smike_s #endif /* DEBUG */
10027c478bd9Sstevel@tonic-gate 				continue;
10037c478bd9Sstevel@tonic-gate 			}
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 			arc.raw_frompc = callerp->frompc;
10067c478bd9Sstevel@tonic-gate 			arc.raw_count = callerp->count;
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate #ifdef DEBUG
10097c478bd9Sstevel@tonic-gate 			if (debug & CGRAPHDEBUG) {
101092ed1782Smike_s 				(void) printf(
101192ed1782Smike_s 				    "[process_cgraph] arc <%#llx, %#llx, "
101292ed1782Smike_s 				    "%lld>\n", arc.raw_frompc, arc.raw_selfpc,
101392ed1782Smike_s 				    arc.raw_count);
10147c478bd9Sstevel@tonic-gate 			}
101592ed1782Smike_s #endif /* DEBUG */
10167c478bd9Sstevel@tonic-gate 			tally(caller_mi, callee_mi, &arc);
10177c478bd9Sstevel@tonic-gate 		}
10187c478bd9Sstevel@tonic-gate 	}
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate #ifdef DEBUG
10217c478bd9Sstevel@tonic-gate 	puts("\n");
102292ed1782Smike_s #endif /* DEBUG */
10237c478bd9Sstevel@tonic-gate }
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate /*
10267c478bd9Sstevel@tonic-gate  * Two modules overlap each other if they don't lie completely *outside*
10277c478bd9Sstevel@tonic-gate  * each other.
10287c478bd9Sstevel@tonic-gate  */
10297c478bd9Sstevel@tonic-gate static bool
does_overlap(ProfModule * new,mod_info_t * old)10307c478bd9Sstevel@tonic-gate does_overlap(ProfModule *new, mod_info_t *old)
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate 	/* case 1: new module lies completely *before* the old one */
10337c478bd9Sstevel@tonic-gate 	if (new->startaddr < old->load_base && new->endaddr <= old->load_base)
10347c478bd9Sstevel@tonic-gate 		return (FALSE);
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	/* case 2: new module lies completely *after* the old one */
10377c478bd9Sstevel@tonic-gate 	if (new->startaddr >= old->load_end && new->endaddr >= old->load_end)
10387c478bd9Sstevel@tonic-gate 		return (FALSE);
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	/* probably a dlopen: the modules overlap each other */
10417c478bd9Sstevel@tonic-gate 	return (TRUE);
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate static bool
is_same_as_aout(char * modpath,struct stat * buf)10457c478bd9Sstevel@tonic-gate is_same_as_aout(char *modpath, struct stat *buf)
10467c478bd9Sstevel@tonic-gate {
10477c478bd9Sstevel@tonic-gate 	if (stat(modpath, buf) == -1) {
104892ed1782Smike_s 		(void) fprintf(stderr, "%s: can't get info on `%s'\n",
10497c478bd9Sstevel@tonic-gate 		    whoami, modpath);
10507c478bd9Sstevel@tonic-gate 		exit(EX_NOINPUT);
10517c478bd9Sstevel@tonic-gate 	}
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	if ((buf->st_dev == aout_info.dev) && (buf->st_ino == aout_info.ino))
10547c478bd9Sstevel@tonic-gate 		return (TRUE);
10557c478bd9Sstevel@tonic-gate 	else
10567c478bd9Sstevel@tonic-gate 		return (FALSE);
10577c478bd9Sstevel@tonic-gate }
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate static void
process_modules(ProfModuleList * modlp)106092ed1782Smike_s process_modules(ProfModuleList *modlp)
10617c478bd9Sstevel@tonic-gate {
10627c478bd9Sstevel@tonic-gate 	ProfModule	*newmodp;
10637c478bd9Sstevel@tonic-gate 	mod_info_t	*mi, *last, *new_module;
106492ed1782Smike_s 	char		*so_path;
10657c478bd9Sstevel@tonic-gate 	bool		more_modules = TRUE;
10667c478bd9Sstevel@tonic-gate 	struct stat	so_statbuf;
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate #ifdef DEBUG
10697c478bd9Sstevel@tonic-gate 	if (debug & MODULEDEBUG) {
107092ed1782Smike_s 		(void) printf("[process_modules] module obj version %u\n",
10717c478bd9Sstevel@tonic-gate 		    modlp->version);
10727c478bd9Sstevel@tonic-gate 	}
107392ed1782Smike_s #endif /* DEBUG */
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	/* Check version of module type object */
10767c478bd9Sstevel@tonic-gate 	if (modlp->version > PROF_MODULES_VER) {
107792ed1782Smike_s 		(void) fprintf(stderr, "%s: version %d for module type objects"
10787c478bd9Sstevel@tonic-gate 		    "is not supported\n", whoami, modlp->version);
10797c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	/*
10847c478bd9Sstevel@tonic-gate 	 * Scan the PROF_MODULES_T list and add modules to current list
10857c478bd9Sstevel@tonic-gate 	 * of modules, if they're not present already
10867c478bd9Sstevel@tonic-gate 	 */
108792ed1782Smike_s 	/* LINTED: pointer cast */
10887c478bd9Sstevel@tonic-gate 	newmodp = (ProfModule *)((char *)modlp + modlp->modules);
10897c478bd9Sstevel@tonic-gate 	do {
10907c478bd9Sstevel@tonic-gate 		/*
10917c478bd9Sstevel@tonic-gate 		 * Since the prog could've been renamed after its run, we
10927c478bd9Sstevel@tonic-gate 		 * should see if this overlaps a.out. If it does, it is
10937c478bd9Sstevel@tonic-gate 		 * probably the renamed aout. We should also skip any other
10947c478bd9Sstevel@tonic-gate 		 * non-sharedobj's that we see (or should we report an error ?)
10957c478bd9Sstevel@tonic-gate 		 */
10967c478bd9Sstevel@tonic-gate 		so_path = (caddr_t)modlp + newmodp->path;
10977c478bd9Sstevel@tonic-gate 		if (does_overlap(newmodp, &modules) ||
10987c478bd9Sstevel@tonic-gate 		    is_same_as_aout(so_path, &so_statbuf) ||
10997c478bd9Sstevel@tonic-gate 		    (!is_shared_obj(so_path))) {
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 			if (!newmodp->next)
11027c478bd9Sstevel@tonic-gate 				more_modules = FALSE;
11037c478bd9Sstevel@tonic-gate 
110492ed1782Smike_s 			/* LINTED: pointer cast */
11057c478bd9Sstevel@tonic-gate 			newmodp = (ProfModule *)
11067c478bd9Sstevel@tonic-gate 			    ((caddr_t)modlp + newmodp->next);
11077c478bd9Sstevel@tonic-gate #ifdef DEBUG
11087c478bd9Sstevel@tonic-gate 			if (debug & MODULEDEBUG) {
110992ed1782Smike_s 				(void) printf(
111092ed1782Smike_s 				    "[process_modules] `%s'\n", so_path);
111192ed1782Smike_s 				(void) printf("                  skipped\n");
11127c478bd9Sstevel@tonic-gate 			}
111392ed1782Smike_s #endif /* DEBUG */
11147c478bd9Sstevel@tonic-gate 			continue;
11157c478bd9Sstevel@tonic-gate 		}
11167c478bd9Sstevel@tonic-gate #ifdef DEBUG
11177c478bd9Sstevel@tonic-gate 		if (debug & MODULEDEBUG)
111892ed1782Smike_s 			(void) printf("[process_modules] `%s'...\n", so_path);
111992ed1782Smike_s #endif /* DEBUG */
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 		/*
11227c478bd9Sstevel@tonic-gate 		 * Check all modules (leave the first one, 'cos that
11237c478bd9Sstevel@tonic-gate 		 * is the program executable info). If this module is already
11247c478bd9Sstevel@tonic-gate 		 * there in the list, update the load addresses and proceed.
11257c478bd9Sstevel@tonic-gate 		 */
11267c478bd9Sstevel@tonic-gate 		last = &modules;
112792ed1782Smike_s 		while ((mi = last->next) != NULL) {
11287c478bd9Sstevel@tonic-gate 			/*
11297c478bd9Sstevel@tonic-gate 			 * We expect the full pathname for all shared objects
11307c478bd9Sstevel@tonic-gate 			 * needed by the program executable. In this case, we
11317c478bd9Sstevel@tonic-gate 			 * simply need to compare the paths to see if they are
11327c478bd9Sstevel@tonic-gate 			 * the same file.
11337c478bd9Sstevel@tonic-gate 			 */
11347c478bd9Sstevel@tonic-gate 			if (strcmp(mi->name, so_path) == 0)
11357c478bd9Sstevel@tonic-gate 				break;
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 			/*
11387c478bd9Sstevel@tonic-gate 			 * Check if this new shared object will overlap
11397c478bd9Sstevel@tonic-gate 			 * any existing module. If yes, remove the old one
11407c478bd9Sstevel@tonic-gate 			 * from the linked list (but don't free it, 'cos
11417c478bd9Sstevel@tonic-gate 			 * there may be symbols referring to this module
11427c478bd9Sstevel@tonic-gate 			 * still)
11437c478bd9Sstevel@tonic-gate 			 */
11447c478bd9Sstevel@tonic-gate 			if (does_overlap(newmodp, mi)) {
11457c478bd9Sstevel@tonic-gate #ifdef DEBUG
11467c478bd9Sstevel@tonic-gate 				if (debug & MODULEDEBUG) {
114792ed1782Smike_s 					(void) printf(
114892ed1782Smike_s 					    "[process_modules] `%s'\n",
11497c478bd9Sstevel@tonic-gate 					    so_path);
115092ed1782Smike_s 					(void) printf(
115192ed1782Smike_s 					    "                  overlaps\n");
115292ed1782Smike_s 					(void) printf(
115392ed1782Smike_s 					    "                  `%s'\n",
11547c478bd9Sstevel@tonic-gate 					    mi->name);
11557c478bd9Sstevel@tonic-gate 				}
115692ed1782Smike_s #endif /* DEBUG */
11577c478bd9Sstevel@tonic-gate 				mi->active = FALSE;
11587c478bd9Sstevel@tonic-gate 			}
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 			last = mi;
11617c478bd9Sstevel@tonic-gate 		}
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 		/* Module already there, skip it */
11647c478bd9Sstevel@tonic-gate 		if (mi != NULL) {
11657c478bd9Sstevel@tonic-gate 			mi->load_base = newmodp->startaddr;
11667c478bd9Sstevel@tonic-gate 			mi->load_end = newmodp->endaddr;
11677c478bd9Sstevel@tonic-gate 			mi->active = TRUE;
11687c478bd9Sstevel@tonic-gate 			if (!newmodp->next)
11697c478bd9Sstevel@tonic-gate 				more_modules = FALSE;
11707c478bd9Sstevel@tonic-gate 
117192ed1782Smike_s 			/* LINTED: pointer cast */
11727c478bd9Sstevel@tonic-gate 			newmodp = (ProfModule *)
11737c478bd9Sstevel@tonic-gate 			    ((caddr_t)modlp + newmodp->next);
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate #ifdef DEBUG
11767c478bd9Sstevel@tonic-gate 			if (debug & MODULEDEBUG) {
117792ed1782Smike_s 				(void) printf("[process_modules] base=%#llx, "
1178*1dd08564Sab196087 				    "end=%#llx\n", mi->load_base, mi->load_end);
11797c478bd9Sstevel@tonic-gate 			}
118092ed1782Smike_s #endif /* DEBUG */
11817c478bd9Sstevel@tonic-gate 			continue;
11827c478bd9Sstevel@tonic-gate 		}
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 		/*
11857c478bd9Sstevel@tonic-gate 		 * Check if gmon.out is outdated with respect to the new
11867c478bd9Sstevel@tonic-gate 		 * module we want to add
11877c478bd9Sstevel@tonic-gate 		 */
11887c478bd9Sstevel@tonic-gate 		if (gmonout_info.mtime < so_statbuf.st_mtime) {
118992ed1782Smike_s 			(void) fprintf(stderr,
119092ed1782Smike_s 			    "%s: shared obj outdates prof info\n", whoami);
119192ed1782Smike_s 			(void) fprintf(stderr, "\t(newer %s)\n", so_path);
11927c478bd9Sstevel@tonic-gate 			exit(EX_NOINPUT);
11937c478bd9Sstevel@tonic-gate 		}
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		/* Create a new module element */
119692ed1782Smike_s 		new_module = malloc(sizeof (mod_info_t));
11977c478bd9Sstevel@tonic-gate 		if (new_module == NULL) {
119892ed1782Smike_s 			(void) fprintf(stderr, "%s: no room for %d bytes\n",
11997c478bd9Sstevel@tonic-gate 			    whoami, sizeof (mod_info_t));
12007c478bd9Sstevel@tonic-gate 			exit(EX_OSERR);
12017c478bd9Sstevel@tonic-gate 		}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 		/* and fill in info... */
12047c478bd9Sstevel@tonic-gate 		new_module->id = n_modules + 1;
12057c478bd9Sstevel@tonic-gate 		new_module->load_base = newmodp->startaddr;
12067c478bd9Sstevel@tonic-gate 		new_module->load_end = newmodp->endaddr;
120792ed1782Smike_s 		new_module->name = malloc(strlen(so_path) + 1);
12087c478bd9Sstevel@tonic-gate 		if (new_module->name == NULL) {
120992ed1782Smike_s 			(void) fprintf(stderr, "%s: no room for %d bytes\n",
12107c478bd9Sstevel@tonic-gate 			    whoami, strlen(so_path) + 1);
12117c478bd9Sstevel@tonic-gate 			exit(EX_OSERR);
12127c478bd9Sstevel@tonic-gate 		}
121392ed1782Smike_s 		(void) strcpy(new_module->name, so_path);
12147c478bd9Sstevel@tonic-gate #ifdef DEBUG
12157c478bd9Sstevel@tonic-gate 		if (debug & MODULEDEBUG) {
121692ed1782Smike_s 			(void) printf(
121792ed1782Smike_s 			    "[process_modules] base=%#llx, end=%#llx\n",
12187c478bd9Sstevel@tonic-gate 			    new_module->load_base, new_module->load_end);
12197c478bd9Sstevel@tonic-gate 		}
122092ed1782Smike_s #endif /* DEBUG */
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 		/* Create this module's nameslist */
12237c478bd9Sstevel@tonic-gate 		process_namelist(new_module);
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 		/* Add it to the tail of active module list */
12267c478bd9Sstevel@tonic-gate 		last->next = new_module;
12277c478bd9Sstevel@tonic-gate 		n_modules++;
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate #ifdef DEBUG
12307c478bd9Sstevel@tonic-gate 		if (debug & MODULEDEBUG) {
123192ed1782Smike_s 			(void) printf(
123292ed1782Smike_s 			    "[process_modules] total shared objects = %ld\n",
12337c478bd9Sstevel@tonic-gate 			    n_modules - 1);
12347c478bd9Sstevel@tonic-gate 		}
123592ed1782Smike_s #endif /* DEBUG */
12367c478bd9Sstevel@tonic-gate 		/*
12377c478bd9Sstevel@tonic-gate 		 * Move to the next module in the PROF_MODULES_T list
12387c478bd9Sstevel@tonic-gate 		 * (if present)
12397c478bd9Sstevel@tonic-gate 		 */
12407c478bd9Sstevel@tonic-gate 		if (!newmodp->next)
12417c478bd9Sstevel@tonic-gate 			more_modules = FALSE;
12427c478bd9Sstevel@tonic-gate 
124392ed1782Smike_s 		/* LINTED: pointer cast */
12447c478bd9Sstevel@tonic-gate 		newmodp = (ProfModule *)((caddr_t)modlp + newmodp->next);
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	} while (more_modules);
12477c478bd9Sstevel@tonic-gate }
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate static void
reset_active_modules(void)125092ed1782Smike_s reset_active_modules(void)
12517c478bd9Sstevel@tonic-gate {
12527c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	/* Except the executable, no other module should remain active */
12557c478bd9Sstevel@tonic-gate 	for (mi = modules.next; mi; mi = mi->next)
12567c478bd9Sstevel@tonic-gate 		mi->active = FALSE;
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate static void
getpfiledata(caddr_t memp,size_t fsz)126092ed1782Smike_s getpfiledata(caddr_t memp, size_t fsz)
12617c478bd9Sstevel@tonic-gate {
12627c478bd9Sstevel@tonic-gate 	ProfObject	*objp;
12637c478bd9Sstevel@tonic-gate 	caddr_t		file_end;
12647c478bd9Sstevel@tonic-gate 	bool		found_pcsamples = FALSE, found_cgraph = FALSE;
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 	/*
12677c478bd9Sstevel@tonic-gate 	 * Before processing a new gmon.out, all modules except the
12687c478bd9Sstevel@tonic-gate 	 * program executable must be made inactive, so that symbols
12697c478bd9Sstevel@tonic-gate 	 * are searched only in the program executable, if we don't
12707c478bd9Sstevel@tonic-gate 	 * find a MODULES_T object. Don't do it *after* we read a gmon.out,
12717c478bd9Sstevel@tonic-gate 	 * because we need the active module data after we're done with
12727c478bd9Sstevel@tonic-gate 	 * the last gmon.out, if we're doing summing.
12737c478bd9Sstevel@tonic-gate 	 */
12747c478bd9Sstevel@tonic-gate 	reset_active_modules();
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	file_end = memp + fsz;
127792ed1782Smike_s 	/* LINTED: pointer cast */
12787c478bd9Sstevel@tonic-gate 	objp = (ProfObject *)(memp + ((ProfHeader *)memp)->size);
12797c478bd9Sstevel@tonic-gate 	while ((caddr_t)objp < file_end) {
12807c478bd9Sstevel@tonic-gate #ifdef DEBUG
12817c478bd9Sstevel@tonic-gate 		{
12827c478bd9Sstevel@tonic-gate 			unsigned int	type = 0;
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 			if (debug & MONOUTDEBUG) {
12857c478bd9Sstevel@tonic-gate 				if (objp->type <= MAX_OBJTYPES)
12867c478bd9Sstevel@tonic-gate 					type = objp->type;
12877c478bd9Sstevel@tonic-gate 
128892ed1782Smike_s 				(void) printf(
128992ed1782Smike_s 				    "\n[getpfiledata] object %s [%#lx]\n",
12907c478bd9Sstevel@tonic-gate 				    objname[type], objp->type);
12917c478bd9Sstevel@tonic-gate 			}
12927c478bd9Sstevel@tonic-gate 		}
129392ed1782Smike_s #endif /* DEBUG */
12947c478bd9Sstevel@tonic-gate 		switch (objp->type) {
12957c478bd9Sstevel@tonic-gate 			case PROF_MODULES_T :
12967c478bd9Sstevel@tonic-gate 				process_modules((ProfModuleList *) objp);
12977c478bd9Sstevel@tonic-gate 				break;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 			case PROF_CALLGRAPH_T :
13007c478bd9Sstevel@tonic-gate 				process_cgraph((ProfCallGraph *) objp);
13017c478bd9Sstevel@tonic-gate 				found_cgraph = TRUE;
13027c478bd9Sstevel@tonic-gate 				break;
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 			case PROF_BUFFER_T :
13057c478bd9Sstevel@tonic-gate 				process_pcsamples((ProfBuffer *) objp);
13067c478bd9Sstevel@tonic-gate 				found_pcsamples = TRUE;
13077c478bd9Sstevel@tonic-gate 				break;
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 			default :
131092ed1782Smike_s 				(void) fprintf(stderr,
13117c478bd9Sstevel@tonic-gate 				    "%s: unknown prof object type=%d\n",
13127c478bd9Sstevel@tonic-gate 				    whoami, objp->type);
13137c478bd9Sstevel@tonic-gate 				exit(EX_SOFTWARE);
13147c478bd9Sstevel@tonic-gate 		}
131592ed1782Smike_s 		/* LINTED: pointer cast */
13167c478bd9Sstevel@tonic-gate 		objp = (ProfObject *)((caddr_t)objp + objp->size);
13177c478bd9Sstevel@tonic-gate 	}
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	if (!found_cgraph || !found_pcsamples) {
132092ed1782Smike_s 		(void) fprintf(stderr,
13217c478bd9Sstevel@tonic-gate 		    "%s: missing callgraph/pcsamples object\n", whoami);
13227c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
13237c478bd9Sstevel@tonic-gate 	}
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	if ((caddr_t)objp > file_end) {
132692ed1782Smike_s 		(void) fprintf(stderr, "%s: malformed profile file.\n", whoami);
13277c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
13287c478bd9Sstevel@tonic-gate 	}
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	if (first_file)
13317c478bd9Sstevel@tonic-gate 		first_file = FALSE;
13327c478bd9Sstevel@tonic-gate }
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate static void
readarcs(FILE * pfile)133592ed1782Smike_s readarcs(FILE *pfile)
13367c478bd9Sstevel@tonic-gate {
13377c478bd9Sstevel@tonic-gate 	/*
13387c478bd9Sstevel@tonic-gate 	 *	the rest of the file consists of
13397c478bd9Sstevel@tonic-gate 	 *	a bunch of <from,self,count> tuples.
13407c478bd9Sstevel@tonic-gate 	 */
13417c478bd9Sstevel@tonic-gate 	/* CONSTCOND */
13427c478bd9Sstevel@tonic-gate 	while (1) {
13437c478bd9Sstevel@tonic-gate 		struct rawarc	arc;
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 		if (rflag) {
13467c478bd9Sstevel@tonic-gate 			if (Bflag) {
13477c478bd9Sstevel@tonic-gate 				L_cgarc64		rtld_arc64;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 				/*
13507c478bd9Sstevel@tonic-gate 				 * If rflag is set then this is an profiled
13517c478bd9Sstevel@tonic-gate 				 * image generated by rtld.  It needs to be
13527c478bd9Sstevel@tonic-gate 				 * 'converted' to the standard data format.
13537c478bd9Sstevel@tonic-gate 				 */
13547c478bd9Sstevel@tonic-gate 				if (fread(&rtld_arc64,
13557c478bd9Sstevel@tonic-gate 				    sizeof (L_cgarc64), 1, pfile) != 1)
13567c478bd9Sstevel@tonic-gate 					break;
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 				if (rtld_arc64.cg_from == PRF_OUTADDR64)
13597c478bd9Sstevel@tonic-gate 					arc.raw_frompc = s_highpc + 0x10;
13607c478bd9Sstevel@tonic-gate 				else
13617c478bd9Sstevel@tonic-gate 					arc.raw_frompc =
13627c478bd9Sstevel@tonic-gate 					    (pctype)rtld_arc64.cg_from;
13637c478bd9Sstevel@tonic-gate 				arc.raw_selfpc = (pctype)rtld_arc64.cg_to;
13647c478bd9Sstevel@tonic-gate 				arc.raw_count = (actype)rtld_arc64.cg_count;
13657c478bd9Sstevel@tonic-gate 			} else {
13667c478bd9Sstevel@tonic-gate 				L_cgarc		rtld_arc;
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 				/*
13697c478bd9Sstevel@tonic-gate 				 * If rflag is set then this is an profiled
13707c478bd9Sstevel@tonic-gate 				 * image generated by rtld.  It needs to be
13717c478bd9Sstevel@tonic-gate 				 * 'converted' to the standard data format.
13727c478bd9Sstevel@tonic-gate 				 */
13737c478bd9Sstevel@tonic-gate 				if (fread(&rtld_arc,
13747c478bd9Sstevel@tonic-gate 				    sizeof (L_cgarc), 1, pfile) != 1)
13757c478bd9Sstevel@tonic-gate 					break;
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 				if (rtld_arc.cg_from == PRF_OUTADDR)
13787c478bd9Sstevel@tonic-gate 					arc.raw_frompc = s_highpc + 0x10;
13797c478bd9Sstevel@tonic-gate 				else
13807c478bd9Sstevel@tonic-gate 					arc.raw_frompc = (pctype)
13817c478bd9Sstevel@tonic-gate 					    (uintptr_t)rtld_arc.cg_from;
13827c478bd9Sstevel@tonic-gate 				arc.raw_selfpc = (pctype)
13837c478bd9Sstevel@tonic-gate 				    (uintptr_t)rtld_arc.cg_to;
13847c478bd9Sstevel@tonic-gate 				arc.raw_count = (actype)rtld_arc.cg_count;
13857c478bd9Sstevel@tonic-gate 			}
13867c478bd9Sstevel@tonic-gate 		} else {
13877c478bd9Sstevel@tonic-gate 			if (Bflag) {
13887c478bd9Sstevel@tonic-gate 				if (fread(&arc, sizeof (struct rawarc), 1,
13897c478bd9Sstevel@tonic-gate 				    pfile) != 1) {
13907c478bd9Sstevel@tonic-gate 					break;
13917c478bd9Sstevel@tonic-gate 				}
13927c478bd9Sstevel@tonic-gate 			} else {
13937c478bd9Sstevel@tonic-gate 				/*
13947c478bd9Sstevel@tonic-gate 				 * If these aren't big %pc's, we need to read
13957c478bd9Sstevel@tonic-gate 				 * into the 32-bit raw arc structure, and
13967c478bd9Sstevel@tonic-gate 				 * assign the members into the actual arc.
13977c478bd9Sstevel@tonic-gate 				 */
13987c478bd9Sstevel@tonic-gate 				struct rawarc32 arc32;
13997c478bd9Sstevel@tonic-gate 				if (fread(&arc32, sizeof (struct rawarc32),
14007c478bd9Sstevel@tonic-gate 				    1, pfile) != 1)
14017c478bd9Sstevel@tonic-gate 					break;
14027c478bd9Sstevel@tonic-gate 				arc.raw_frompc = (pctype)arc32.raw_frompc;
14037c478bd9Sstevel@tonic-gate 				arc.raw_selfpc = (pctype)arc32.raw_selfpc;
14047c478bd9Sstevel@tonic-gate 				arc.raw_count  = (actype)arc32.raw_count;
14057c478bd9Sstevel@tonic-gate 			}
14067c478bd9Sstevel@tonic-gate 		}
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate #ifdef DEBUG
14097c478bd9Sstevel@tonic-gate 		if (debug & SAMPLEDEBUG) {
141092ed1782Smike_s 			(void) printf("[getpfile] frompc 0x%llx selfpc "
14117c478bd9Sstevel@tonic-gate 			    "0x%llx count %lld\n", arc.raw_frompc,
14127c478bd9Sstevel@tonic-gate 			    arc.raw_selfpc, arc.raw_count);
14137c478bd9Sstevel@tonic-gate 		}
141492ed1782Smike_s #endif /* DEBUG */
14157c478bd9Sstevel@tonic-gate 		/*
14167c478bd9Sstevel@tonic-gate 		 *	add this arc
14177c478bd9Sstevel@tonic-gate 		 */
14187c478bd9Sstevel@tonic-gate 		tally(&modules, &modules, &arc);
14197c478bd9Sstevel@tonic-gate 	}
14207c478bd9Sstevel@tonic-gate 	if (first_file)
14217c478bd9Sstevel@tonic-gate 		first_file = FALSE;
14227c478bd9Sstevel@tonic-gate }
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate static void
readsamples(FILE * pfile)14257c478bd9Sstevel@tonic-gate readsamples(FILE *pfile)
14267c478bd9Sstevel@tonic-gate {
14277c478bd9Sstevel@tonic-gate 	sztype		i;
14287c478bd9Sstevel@tonic-gate 	unsigned_UNIT	sample;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	if (samples == 0) {
14317c478bd9Sstevel@tonic-gate 		samples = (unsigned_UNIT *) calloc(nsamples,
14327c478bd9Sstevel@tonic-gate 		    sizeof (unsigned_UNIT));
14337c478bd9Sstevel@tonic-gate 		if (samples == 0) {
143492ed1782Smike_s 			(void) fprintf(stderr,
143592ed1782Smike_s 			    "%s: No room for %d sample pc's\n",
14367c478bd9Sstevel@tonic-gate 			    whoami, sampbytes / sizeof (unsigned_UNIT));
14377c478bd9Sstevel@tonic-gate 			exit(EX_OSERR);
14387c478bd9Sstevel@tonic-gate 		}
14397c478bd9Sstevel@tonic-gate 	}
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	for (i = 0; i < nsamples; i++) {
144292ed1782Smike_s 		(void) fread(&sample, sizeof (unsigned_UNIT), 1, pfile);
14437c478bd9Sstevel@tonic-gate 		if (feof(pfile))
14447c478bd9Sstevel@tonic-gate 			break;
14457c478bd9Sstevel@tonic-gate 		samples[i] += sample;
14467c478bd9Sstevel@tonic-gate 	}
14477c478bd9Sstevel@tonic-gate 	if (i != nsamples) {
144892ed1782Smike_s 		(void) fprintf(stderr,
144992ed1782Smike_s 		    "%s: unexpected EOF after reading %d/%d samples\n",
14507c478bd9Sstevel@tonic-gate 		    whoami, --i, nsamples);
14517c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
14527c478bd9Sstevel@tonic-gate 	}
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate static void *
handle_versioned(FILE * pfile,char * filename,size_t * fsz)14567c478bd9Sstevel@tonic-gate handle_versioned(FILE *pfile, char *filename, size_t *fsz)
14577c478bd9Sstevel@tonic-gate {
14587c478bd9Sstevel@tonic-gate 	int		fd;
14597c478bd9Sstevel@tonic-gate 	bool		invalid_version;
14607c478bd9Sstevel@tonic-gate 	caddr_t		fmem;
14617c478bd9Sstevel@tonic-gate 	struct stat	buf;
14627c478bd9Sstevel@tonic-gate 	ProfHeader	prof_hdr;
146392ed1782Smike_s 	off_t		lret;
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	/*
14667c478bd9Sstevel@tonic-gate 	 * Check versioning info. For now, let's say we provide
14677c478bd9Sstevel@tonic-gate 	 * backward compatibility, so we accept all older versions.
14687c478bd9Sstevel@tonic-gate 	 */
14697c478bd9Sstevel@tonic-gate 	if (fread(&prof_hdr, sizeof (ProfHeader), 1, pfile) == 0) {
14707c478bd9Sstevel@tonic-gate 		perror("fread()");
14717c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
14727c478bd9Sstevel@tonic-gate 	}
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	invalid_version = FALSE;
14757c478bd9Sstevel@tonic-gate 	if (prof_hdr.h_major_ver > PROF_MAJOR_VERSION)
14767c478bd9Sstevel@tonic-gate 		invalid_version = TRUE;
14777c478bd9Sstevel@tonic-gate 	else if (prof_hdr.h_major_ver == PROF_MAJOR_VERSION) {
14787c478bd9Sstevel@tonic-gate 		if (prof_hdr.h_minor_ver > PROF_MINOR_VERSION)
14797c478bd9Sstevel@tonic-gate 			invalid_version = FALSE;
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	if (invalid_version) {
148392ed1782Smike_s 		(void) fprintf(stderr, "%s: version %d.%d not supported\n",
14847c478bd9Sstevel@tonic-gate 		    whoami, prof_hdr.h_major_ver, prof_hdr.h_minor_ver);
14857c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
14867c478bd9Sstevel@tonic-gate 	}
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	/*
14897c478bd9Sstevel@tonic-gate 	 * Map gmon.out onto memory.
14907c478bd9Sstevel@tonic-gate 	 */
149192ed1782Smike_s 	(void) fclose(pfile);
14927c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1) {
14937c478bd9Sstevel@tonic-gate 		perror(filename);
14947c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
14957c478bd9Sstevel@tonic-gate 	}
14967c478bd9Sstevel@tonic-gate 
149792ed1782Smike_s 	if ((lret = lseek(fd, 0, SEEK_END)) == -1) {
14987c478bd9Sstevel@tonic-gate 		perror(filename);
14997c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
15007c478bd9Sstevel@tonic-gate 	}
150192ed1782Smike_s 	*fsz = lret;
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	fmem = mmap(0, *fsz, PROT_READ, MAP_PRIVATE, fd, 0);
15047c478bd9Sstevel@tonic-gate 	if (fmem == MAP_FAILED) {
150592ed1782Smike_s 		(void) fprintf(stderr, "%s: can't map %s\n", whoami, filename);
15067c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
15077c478bd9Sstevel@tonic-gate 	}
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	/*
15107c478bd9Sstevel@tonic-gate 	 * Before we close this fd, save this gmon.out's info to later verify
15117c478bd9Sstevel@tonic-gate 	 * if the shared objects it references have changed since the time
15127c478bd9Sstevel@tonic-gate 	 * they were used to generate this gmon.out
15137c478bd9Sstevel@tonic-gate 	 */
15147c478bd9Sstevel@tonic-gate 	if (fstat(fd, &buf) == -1) {
151592ed1782Smike_s 		(void) fprintf(stderr, "%s: can't get info on `%s'\n",
15167c478bd9Sstevel@tonic-gate 		    whoami, filename);
15177c478bd9Sstevel@tonic-gate 		exit(EX_NOINPUT);
15187c478bd9Sstevel@tonic-gate 	}
15197c478bd9Sstevel@tonic-gate 	gmonout_info.dev = buf.st_dev;
15207c478bd9Sstevel@tonic-gate 	gmonout_info.ino = buf.st_ino;
15217c478bd9Sstevel@tonic-gate 	gmonout_info.mtime = buf.st_mtime;
15227c478bd9Sstevel@tonic-gate 	gmonout_info.size = buf.st_size;
15237c478bd9Sstevel@tonic-gate 
152492ed1782Smike_s 	(void) close(fd);
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	return ((void *) fmem);
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate static void *
openpfile(char * filename,size_t * fsz)153092ed1782Smike_s openpfile(char *filename, size_t *fsz)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate 	struct hdr	tmp;
15337c478bd9Sstevel@tonic-gate 	FILE		*pfile;
15347c478bd9Sstevel@tonic-gate 	unsigned long	magic_num;
1535e0ddff35Sab196087 	size_t		hdrsize;
15367c478bd9Sstevel@tonic-gate 	static bool	first_time = TRUE;
15377c478bd9Sstevel@tonic-gate 	extern bool	old_style;
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	if ((pfile = fopen(filename, "r")) == NULL) {
15407c478bd9Sstevel@tonic-gate 		perror(filename);
15417c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
15427c478bd9Sstevel@tonic-gate 	}
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	/*
15457c478bd9Sstevel@tonic-gate 	 * Read in the magic. Note that we changed the cast "unsigned long"
15467c478bd9Sstevel@tonic-gate 	 * to "unsigned int" because that's how h_magic is defined in the
15477c478bd9Sstevel@tonic-gate 	 * new format ProfHeader.
15487c478bd9Sstevel@tonic-gate 	 */
15497c478bd9Sstevel@tonic-gate 	if (fread(&magic_num, sizeof (unsigned int), 1, pfile) == 0) {
15507c478bd9Sstevel@tonic-gate 		perror("fread()");
15517c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
15527c478bd9Sstevel@tonic-gate 	}
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 	rewind(pfile);
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 	/*
15577c478bd9Sstevel@tonic-gate 	 * First check if this is versioned or *old-style* gmon.out
15587c478bd9Sstevel@tonic-gate 	 */
15597c478bd9Sstevel@tonic-gate 	if (magic_num == (unsigned int)PROF_MAGIC) {
15607c478bd9Sstevel@tonic-gate 		if ((!first_time) && (old_style == TRUE)) {
156192ed1782Smike_s 			(void) fprintf(stderr, "%s: can't mix old & new format "
15627c478bd9Sstevel@tonic-gate 			    "profiled files\n", whoami);
15637c478bd9Sstevel@tonic-gate 			exit(EX_SOFTWARE);
15647c478bd9Sstevel@tonic-gate 		}
15657c478bd9Sstevel@tonic-gate 		first_time = FALSE;
15667c478bd9Sstevel@tonic-gate 		old_style = FALSE;
15677c478bd9Sstevel@tonic-gate 		return (handle_versioned(pfile, filename, fsz));
15687c478bd9Sstevel@tonic-gate 	}
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	if ((!first_time) && (old_style == FALSE)) {
157192ed1782Smike_s 		(void) fprintf(stderr, "%s: can't mix old & new format "
15727c478bd9Sstevel@tonic-gate 		    "profiled files\n", whoami);
15737c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
15747c478bd9Sstevel@tonic-gate 	}
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	first_time = FALSE;
15777c478bd9Sstevel@tonic-gate 	old_style = TRUE;
15787c478bd9Sstevel@tonic-gate 	fsz = 0;
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	/*
15817c478bd9Sstevel@tonic-gate 	 * Now, we need to determine if this is a run-time linker
15827c478bd9Sstevel@tonic-gate 	 * profiled file or if it is a standard gmon.out.
15837c478bd9Sstevel@tonic-gate 	 *
15847c478bd9Sstevel@tonic-gate 	 * We do this by checking if magic matches PRF_MAGIC. If it
15857c478bd9Sstevel@tonic-gate 	 * does, then this is a run-time linker profiled file, if it
15867c478bd9Sstevel@tonic-gate 	 * doesn't, it must be a gmon.out file.
15877c478bd9Sstevel@tonic-gate 	 */
15887c478bd9Sstevel@tonic-gate 	if (magic_num == (unsigned long)PRF_MAGIC)
15897c478bd9Sstevel@tonic-gate 		rflag = TRUE;
15907c478bd9Sstevel@tonic-gate 	else
15917c478bd9Sstevel@tonic-gate 		rflag = FALSE;
15927c478bd9Sstevel@tonic-gate 
1593e0ddff35Sab196087 	hdrsize = Bflag ? sizeof (struct hdr) : sizeof (struct hdr32);
1594e0ddff35Sab196087 
15957c478bd9Sstevel@tonic-gate 	if (rflag) {
15967c478bd9Sstevel@tonic-gate 		if (Bflag) {
15977c478bd9Sstevel@tonic-gate 			L_hdr64		l_hdr64;
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 			/*
16007c478bd9Sstevel@tonic-gate 			 * If the rflag is set then the input file is
16017c478bd9Sstevel@tonic-gate 			 * rtld profiled data, we'll read it in and convert
16027c478bd9Sstevel@tonic-gate 			 * it to the standard format (ie: make it look like
16037c478bd9Sstevel@tonic-gate 			 * a gmon.out file).
16047c478bd9Sstevel@tonic-gate 			 */
16057c478bd9Sstevel@tonic-gate 			if (fread(&l_hdr64, sizeof (L_hdr64), 1, pfile) == 0) {
16067c478bd9Sstevel@tonic-gate 				perror("fread()");
16077c478bd9Sstevel@tonic-gate 				exit(EX_IOERR);
16087c478bd9Sstevel@tonic-gate 			}
16097c478bd9Sstevel@tonic-gate 			if (l_hdr64.hd_version != PRF_VERSION_64) {
161092ed1782Smike_s 				(void) fprintf(stderr,
161192ed1782Smike_s 				    "%s: expected version %d, "
16127c478bd9Sstevel@tonic-gate 				    "got version %d when processing 64-bit "
16137c478bd9Sstevel@tonic-gate 				    "run-time linker profiled file.\n",
16147c478bd9Sstevel@tonic-gate 				    whoami, PRF_VERSION_64, l_hdr64.hd_version);
16157c478bd9Sstevel@tonic-gate 				exit(EX_SOFTWARE);
16167c478bd9Sstevel@tonic-gate 			}
16177c478bd9Sstevel@tonic-gate 			tmp.lowpc = 0;
16187c478bd9Sstevel@tonic-gate 			tmp.highpc = (pctype)l_hdr64.hd_hpc;
1619e0ddff35Sab196087 			tmp.ncnt = hdrsize + l_hdr64.hd_psize;
16207c478bd9Sstevel@tonic-gate 		} else {
16217c478bd9Sstevel@tonic-gate 			L_hdr		l_hdr;
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 			/*
16247c478bd9Sstevel@tonic-gate 			 * If the rflag is set then the input file is
16257c478bd9Sstevel@tonic-gate 			 * rtld profiled data, we'll read it in and convert
16267c478bd9Sstevel@tonic-gate 			 * it to the standard format (ie: make it look like
16277c478bd9Sstevel@tonic-gate 			 * a gmon.out file).
16287c478bd9Sstevel@tonic-gate 			 */
16297c478bd9Sstevel@tonic-gate 			if (fread(&l_hdr, sizeof (L_hdr), 1, pfile) == 0) {
16307c478bd9Sstevel@tonic-gate 				perror("fread()");
16317c478bd9Sstevel@tonic-gate 				exit(EX_IOERR);
16327c478bd9Sstevel@tonic-gate 			}
16337c478bd9Sstevel@tonic-gate 			if (l_hdr.hd_version != PRF_VERSION) {
163492ed1782Smike_s 				(void) fprintf(stderr,
163592ed1782Smike_s 				    "%s: expected version %d, "
16367c478bd9Sstevel@tonic-gate 				    "got version %d when processing "
16377c478bd9Sstevel@tonic-gate 				    "run-time linker profiled file.\n",
16387c478bd9Sstevel@tonic-gate 				    whoami, PRF_VERSION, l_hdr.hd_version);
16397c478bd9Sstevel@tonic-gate 				exit(EX_SOFTWARE);
16407c478bd9Sstevel@tonic-gate 			}
16417c478bd9Sstevel@tonic-gate 			tmp.lowpc = 0;
16427c478bd9Sstevel@tonic-gate 			tmp.highpc = (pctype)(uintptr_t)l_hdr.hd_hpc;
1643e0ddff35Sab196087 			tmp.ncnt = hdrsize + l_hdr.hd_psize;
16447c478bd9Sstevel@tonic-gate 		}
16457c478bd9Sstevel@tonic-gate 	} else {
16467c478bd9Sstevel@tonic-gate 		if (Bflag) {
16477c478bd9Sstevel@tonic-gate 			if (fread(&tmp, sizeof (struct hdr), 1, pfile) == 0) {
16487c478bd9Sstevel@tonic-gate 				perror("fread()");
16497c478bd9Sstevel@tonic-gate 				exit(EX_IOERR);
16507c478bd9Sstevel@tonic-gate 			}
16517c478bd9Sstevel@tonic-gate 		} else {
16527c478bd9Sstevel@tonic-gate 			/*
16537c478bd9Sstevel@tonic-gate 			 * If we're not reading big %pc's, we need to read
16547c478bd9Sstevel@tonic-gate 			 * the 32-bit header, and assign the members to
16557c478bd9Sstevel@tonic-gate 			 * the actual header.
16567c478bd9Sstevel@tonic-gate 			 */
16577c478bd9Sstevel@tonic-gate 			struct hdr32 hdr32;
16587c478bd9Sstevel@tonic-gate 			if (fread(&hdr32, sizeof (hdr32), 1, pfile) == 0) {
16597c478bd9Sstevel@tonic-gate 				perror("fread()");
16607c478bd9Sstevel@tonic-gate 				exit(EX_IOERR);
16617c478bd9Sstevel@tonic-gate 			}
16627c478bd9Sstevel@tonic-gate 			tmp.lowpc = hdr32.lowpc;
16637c478bd9Sstevel@tonic-gate 			tmp.highpc = hdr32.highpc;
16647c478bd9Sstevel@tonic-gate 			tmp.ncnt = hdr32.ncnt;
16657c478bd9Sstevel@tonic-gate 		}
16667c478bd9Sstevel@tonic-gate 	}
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	/*
16697c478bd9Sstevel@tonic-gate 	 * perform sanity check on profiled file we've opened.
16707c478bd9Sstevel@tonic-gate 	 */
16717c478bd9Sstevel@tonic-gate 	if (tmp.lowpc >= tmp.highpc) {
16727c478bd9Sstevel@tonic-gate 		if (rflag)
167392ed1782Smike_s 			(void) fprintf(stderr,
167492ed1782Smike_s 			    "%s: badly formed profiled data.\n",
16757c478bd9Sstevel@tonic-gate 			    filename);
16767c478bd9Sstevel@tonic-gate 		else
167792ed1782Smike_s 			(void) fprintf(stderr,
167892ed1782Smike_s 			    "%s: badly formed gmon.out file.\n",
16797c478bd9Sstevel@tonic-gate 			    filename);
16807c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
16817c478bd9Sstevel@tonic-gate 	}
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	if (s_highpc != 0 && (tmp.lowpc != h.lowpc ||
16847c478bd9Sstevel@tonic-gate 	    tmp.highpc != h.highpc || tmp.ncnt != h.ncnt)) {
168592ed1782Smike_s 		(void) fprintf(stderr,
16867c478bd9Sstevel@tonic-gate 		    "%s: incompatible with first gmon file\n",
16877c478bd9Sstevel@tonic-gate 		    filename);
16887c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
16897c478bd9Sstevel@tonic-gate 	}
16907c478bd9Sstevel@tonic-gate 	h = tmp;
16917c478bd9Sstevel@tonic-gate 	s_lowpc = h.lowpc;
16927c478bd9Sstevel@tonic-gate 	s_highpc = h.highpc;
16937c478bd9Sstevel@tonic-gate 	lowpc = h.lowpc / sizeof (UNIT);
16947c478bd9Sstevel@tonic-gate 	highpc = h.highpc / sizeof (UNIT);
16957c478bd9Sstevel@tonic-gate 	sampbytes = h.ncnt > hdrsize ? h.ncnt - hdrsize : 0;
16967c478bd9Sstevel@tonic-gate 	nsamples = sampbytes / sizeof (unsigned_UNIT);
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate #ifdef DEBUG
16997c478bd9Sstevel@tonic-gate 	if (debug & SAMPLEDEBUG) {
170092ed1782Smike_s 		(void) printf("[openpfile] hdr.lowpc 0x%llx hdr.highpc "
17017c478bd9Sstevel@tonic-gate 		    "0x%llx hdr.ncnt %lld\n",
17027c478bd9Sstevel@tonic-gate 		    h.lowpc, h.highpc, h.ncnt);
170392ed1782Smike_s 		(void) printf(
170492ed1782Smike_s 		    "[openpfile]   s_lowpc 0x%llx   s_highpc 0x%llx\n",
17057c478bd9Sstevel@tonic-gate 		    s_lowpc, s_highpc);
170692ed1782Smike_s 		(void) printf(
170792ed1782Smike_s 		    "[openpfile]     lowpc 0x%llx     highpc 0x%llx\n",
17087c478bd9Sstevel@tonic-gate 		    lowpc, highpc);
170992ed1782Smike_s 		(void) printf("[openpfile] sampbytes %d nsamples %d\n",
17107c478bd9Sstevel@tonic-gate 		    sampbytes, nsamples);
17117c478bd9Sstevel@tonic-gate 	}
171292ed1782Smike_s #endif /* DEBUG */
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	return ((void *) pfile);
17157c478bd9Sstevel@tonic-gate }
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate /*
17187c478bd9Sstevel@tonic-gate  * Information from a gmon.out file depends on whether it's versioned
17197c478bd9Sstevel@tonic-gate  * or non-versioned, *old style* gmon.out. If old-style, it is in two
17207c478bd9Sstevel@tonic-gate  * parts : an array of sampling hits within pc ranges, and the arcs. If
17217c478bd9Sstevel@tonic-gate  * versioned, it contains a header, followed by any number of
17227c478bd9Sstevel@tonic-gate  * modules/callgraph/pcsample_buffer objects.
17237c478bd9Sstevel@tonic-gate  */
17247c478bd9Sstevel@tonic-gate static void
getpfile(char * filename)17257c478bd9Sstevel@tonic-gate getpfile(char *filename)
17267c478bd9Sstevel@tonic-gate {
17277c478bd9Sstevel@tonic-gate 	void		*handle;
17287c478bd9Sstevel@tonic-gate 	size_t		fsz;
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	handle = openpfile(filename, &fsz);
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	if (old_style) {
17337c478bd9Sstevel@tonic-gate 		readsamples((FILE *)handle);
17347c478bd9Sstevel@tonic-gate 		readarcs((FILE *)handle);
173592ed1782Smike_s 		(void) fclose((FILE *)handle);
17367c478bd9Sstevel@tonic-gate 		return;
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	getpfiledata((caddr_t)handle, fsz);
174092ed1782Smike_s 	(void) munmap(handle, fsz);
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate 
174392ed1782Smike_s int
main(int argc,char ** argv)17447c478bd9Sstevel@tonic-gate main(int argc, char **argv)
17457c478bd9Sstevel@tonic-gate {
17467c478bd9Sstevel@tonic-gate 	char	**sp;
17477c478bd9Sstevel@tonic-gate 	nltype	**timesortnlp;
17487c478bd9Sstevel@tonic-gate 	int		c;
17497c478bd9Sstevel@tonic-gate 	int		errflg;
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	prog_name = *argv;  /* preserve program name */
17527c478bd9Sstevel@tonic-gate 	debug = 0;
17537c478bd9Sstevel@tonic-gate 	nflag = FALSE;
17547c478bd9Sstevel@tonic-gate 	bflag = TRUE;
17557c478bd9Sstevel@tonic-gate 	lflag = FALSE;
17567c478bd9Sstevel@tonic-gate 	Cflag = FALSE;
17577c478bd9Sstevel@tonic-gate 	first_file = TRUE;
17587c478bd9Sstevel@tonic-gate 	rflag = FALSE;
17597c478bd9Sstevel@tonic-gate 	Bflag = FALSE;
17607c478bd9Sstevel@tonic-gate 	errflg = FALSE;
17617c478bd9Sstevel@tonic-gate 
17627c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "abd:CcDE:e:F:f:ln:sz")) != EOF)
17637c478bd9Sstevel@tonic-gate 		switch (c) {
17647c478bd9Sstevel@tonic-gate 		case 'a':
17657c478bd9Sstevel@tonic-gate 			aflag = TRUE;
17667c478bd9Sstevel@tonic-gate 			break;
17677c478bd9Sstevel@tonic-gate 		case 'b':
17687c478bd9Sstevel@tonic-gate 			bflag = FALSE;
17697c478bd9Sstevel@tonic-gate 			break;
17707c478bd9Sstevel@tonic-gate 		case 'c':
17717c478bd9Sstevel@tonic-gate 			cflag = TRUE;
17727c478bd9Sstevel@tonic-gate 			break;
17737c478bd9Sstevel@tonic-gate 		case 'C':
17747c478bd9Sstevel@tonic-gate 			Cflag = TRUE;
17757c478bd9Sstevel@tonic-gate 			break;
17767c478bd9Sstevel@tonic-gate 		case 'd':
17777c478bd9Sstevel@tonic-gate 			dflag = TRUE;
17787c478bd9Sstevel@tonic-gate 			debug |= atoi(optarg);
177992ed1782Smike_s 			(void) printf("[main] debug = 0x%x\n", debug);
17807c478bd9Sstevel@tonic-gate 			break;
17817c478bd9Sstevel@tonic-gate 		case 'D':
17827c478bd9Sstevel@tonic-gate 			Dflag = TRUE;
17837c478bd9Sstevel@tonic-gate 			break;
17847c478bd9Sstevel@tonic-gate 		case 'E':
17857c478bd9Sstevel@tonic-gate 			addlist(Elist, optarg);
17867c478bd9Sstevel@tonic-gate 			Eflag = TRUE;
17877c478bd9Sstevel@tonic-gate 			addlist(elist, optarg);
17887c478bd9Sstevel@tonic-gate 			eflag = TRUE;
17897c478bd9Sstevel@tonic-gate 			break;
17907c478bd9Sstevel@tonic-gate 		case 'e':
17917c478bd9Sstevel@tonic-gate 			addlist(elist, optarg);
17927c478bd9Sstevel@tonic-gate 			eflag = TRUE;
17937c478bd9Sstevel@tonic-gate 			break;
17947c478bd9Sstevel@tonic-gate 		case 'F':
17957c478bd9Sstevel@tonic-gate 			addlist(Flist, optarg);
17967c478bd9Sstevel@tonic-gate 			Fflag = TRUE;
17977c478bd9Sstevel@tonic-gate 			addlist(flist, optarg);
17987c478bd9Sstevel@tonic-gate 			fflag = TRUE;
17997c478bd9Sstevel@tonic-gate 			break;
18007c478bd9Sstevel@tonic-gate 		case 'f':
18017c478bd9Sstevel@tonic-gate 			addlist(flist, optarg);
18027c478bd9Sstevel@tonic-gate 			fflag = TRUE;
18037c478bd9Sstevel@tonic-gate 			break;
18047c478bd9Sstevel@tonic-gate 		case 'l':
18057c478bd9Sstevel@tonic-gate 			lflag = TRUE;
18067c478bd9Sstevel@tonic-gate 			break;
18077c478bd9Sstevel@tonic-gate 		case 'n':
18087c478bd9Sstevel@tonic-gate 			nflag = TRUE;
18097c478bd9Sstevel@tonic-gate 			number_funcs_toprint = atoi(optarg);
18107c478bd9Sstevel@tonic-gate 			break;
18117c478bd9Sstevel@tonic-gate 		case 's':
18127c478bd9Sstevel@tonic-gate 			sflag = TRUE;
18137c478bd9Sstevel@tonic-gate 			break;
18147c478bd9Sstevel@tonic-gate 		case 'z':
18157c478bd9Sstevel@tonic-gate 			zflag = TRUE;
18167c478bd9Sstevel@tonic-gate 			break;
18177c478bd9Sstevel@tonic-gate 		case '?':
18187c478bd9Sstevel@tonic-gate 			errflg++;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 		}
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	if (errflg) {
18237c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
18247c478bd9Sstevel@tonic-gate 		    "usage: gprof [ -abcCDlsz ] [ -e function-name ] "
18257c478bd9Sstevel@tonic-gate 		    "[ -E function-name ]\n\t[ -f function-name ] "
18267c478bd9Sstevel@tonic-gate 		    "[ -F function-name  ]\n\t[  image-file  "
18277c478bd9Sstevel@tonic-gate 		    "[ profile-file ... ] ]\n");
18287c478bd9Sstevel@tonic-gate 		exit(EX_USAGE);
18297c478bd9Sstevel@tonic-gate 	}
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	if (optind < argc) {
18327c478bd9Sstevel@tonic-gate 		a_outname  = argv[optind++];
18337c478bd9Sstevel@tonic-gate 	} else {
18347c478bd9Sstevel@tonic-gate 		a_outname  = A_OUTNAME;
18357c478bd9Sstevel@tonic-gate 	}
18367c478bd9Sstevel@tonic-gate 	if (optind < argc) {
18377c478bd9Sstevel@tonic-gate 		gmonname = argv[optind++];
18387c478bd9Sstevel@tonic-gate 	} else {
18397c478bd9Sstevel@tonic-gate 		gmonname = GMONNAME;
18407c478bd9Sstevel@tonic-gate 	}
18417c478bd9Sstevel@tonic-gate 	/*
18427c478bd9Sstevel@tonic-gate 	 *	turn off default functions
18437c478bd9Sstevel@tonic-gate 	 */
18447c478bd9Sstevel@tonic-gate 	for (sp = &defaultEs[0]; *sp; sp++) {
18457c478bd9Sstevel@tonic-gate 		Eflag = TRUE;
18467c478bd9Sstevel@tonic-gate 		addlist(Elist, *sp);
18477c478bd9Sstevel@tonic-gate 		eflag = TRUE;
18487c478bd9Sstevel@tonic-gate 		addlist(elist, *sp);
18497c478bd9Sstevel@tonic-gate 	}
18507c478bd9Sstevel@tonic-gate 	/*
18517c478bd9Sstevel@tonic-gate 	 *	how many ticks per second?
18527c478bd9Sstevel@tonic-gate 	 *	if we can't tell, report time in ticks.
18537c478bd9Sstevel@tonic-gate 	 */
18547c478bd9Sstevel@tonic-gate 	hz = sysconf(_SC_CLK_TCK);
18557c478bd9Sstevel@tonic-gate 	if (hz == -1) {
18567c478bd9Sstevel@tonic-gate 		hz = 1;
185792ed1782Smike_s 		(void) fprintf(stderr, "time is in ticks, not seconds\n");
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	getnfile(a_outname);
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 	/*
18637c478bd9Sstevel@tonic-gate 	 *	get information about mon.out file(s).
18647c478bd9Sstevel@tonic-gate 	 */
18657c478bd9Sstevel@tonic-gate 	do {
18667c478bd9Sstevel@tonic-gate 		getpfile(gmonname);
18677c478bd9Sstevel@tonic-gate 		if (optind < argc)
18687c478bd9Sstevel@tonic-gate 			gmonname = argv[optind++];
18697c478bd9Sstevel@tonic-gate 		else
18707c478bd9Sstevel@tonic-gate 			optind++;
18717c478bd9Sstevel@tonic-gate 	} while (optind <= argc);
18727c478bd9Sstevel@tonic-gate 	/*
18737c478bd9Sstevel@tonic-gate 	 *	dump out a gmon.sum file if requested
18747c478bd9Sstevel@tonic-gate 	 */
18757c478bd9Sstevel@tonic-gate 	if (sflag || Dflag)
18767c478bd9Sstevel@tonic-gate 		dumpsum(GMONSUM);
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 	if (old_style) {
18797c478bd9Sstevel@tonic-gate 		/*
18807c478bd9Sstevel@tonic-gate 		 *	assign samples to procedures
18817c478bd9Sstevel@tonic-gate 		 */
18827c478bd9Sstevel@tonic-gate 		asgnsamples();
18837c478bd9Sstevel@tonic-gate 	}
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	/*
18867c478bd9Sstevel@tonic-gate 	 *	assemble the dynamic profile
18877c478bd9Sstevel@tonic-gate 	 */
18887c478bd9Sstevel@tonic-gate 	timesortnlp = doarcs();
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	/*
18917c478bd9Sstevel@tonic-gate 	 *	print the dynamic profile
18927c478bd9Sstevel@tonic-gate 	 */
18937c478bd9Sstevel@tonic-gate #ifdef DEBUG
18947c478bd9Sstevel@tonic-gate 	if (debug & ANYDEBUG) {
18957c478bd9Sstevel@tonic-gate 		/* raw output of all symbols in all their glory */
18967c478bd9Sstevel@tonic-gate 		int i;
189792ed1782Smike_s 		(void) printf(" Name, pc_entry_pt, svalue, tix_in_routine, "
18987c478bd9Sstevel@tonic-gate 		    "#calls, selfcalls, index \n");
18997c478bd9Sstevel@tonic-gate 		for (i = 0; i < modules.nname; i++) { 	/* Print each symbol */
19007c478bd9Sstevel@tonic-gate 			if (timesortnlp[i]->name)
190192ed1782Smike_s 				(void) printf(" %s ", timesortnlp[i]->name);
19027c478bd9Sstevel@tonic-gate 			else
190392ed1782Smike_s 				(void) printf(" <cycle> ");
190492ed1782Smike_s 			(void) printf(" %lld ", timesortnlp[i]->value);
190592ed1782Smike_s 			(void) printf(" %lld ", timesortnlp[i]->svalue);
190692ed1782Smike_s 			(void) printf(" %f ", timesortnlp[i]->time);
190792ed1782Smike_s 			(void) printf(" %lld ", timesortnlp[i]->ncall);
190892ed1782Smike_s 			(void) printf(" %lld ", timesortnlp[i]->selfcalls);
190992ed1782Smike_s 			(void) printf(" %d ", timesortnlp[i]->index);
191092ed1782Smike_s 			(void) printf(" \n");
19117c478bd9Sstevel@tonic-gate 		}
19127c478bd9Sstevel@tonic-gate 	}
191392ed1782Smike_s #endif /* DEBUG */
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	printgprof(timesortnlp);
19167c478bd9Sstevel@tonic-gate 	/*
19177c478bd9Sstevel@tonic-gate 	 *	print the flat profile
19187c478bd9Sstevel@tonic-gate 	 */
19197c478bd9Sstevel@tonic-gate 	printprof();
19207c478bd9Sstevel@tonic-gate 	/*
19217c478bd9Sstevel@tonic-gate 	 *	print the index
19227c478bd9Sstevel@tonic-gate 	 */
19237c478bd9Sstevel@tonic-gate 	printindex();
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	/*
19267c478bd9Sstevel@tonic-gate 	 * print the modules
19277c478bd9Sstevel@tonic-gate 	 */
19287c478bd9Sstevel@tonic-gate 	printmodules();
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	done();
19317c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
19327c478bd9Sstevel@tonic-gate 	return (0);
19337c478bd9Sstevel@tonic-gate }
1934