xref: /illumos-gate/usr/src/cmd/sgs/gprof/common/gprof.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include	<sysexits.h>
30*7c478bd9Sstevel@tonic-gate #include	<stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include	<unistd.h>
32*7c478bd9Sstevel@tonic-gate #include	"gprof.h"
33*7c478bd9Sstevel@tonic-gate #include	"profile.h"
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate char		*whoami = "gprof";
36*7c478bd9Sstevel@tonic-gate static pctype	lowpc, highpc;		/* range profiled, in UNIT's */
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate /*
39*7c478bd9Sstevel@tonic-gate  *	things which get -E excluded by default.
40*7c478bd9Sstevel@tonic-gate  */
41*7c478bd9Sstevel@tonic-gate static char *defaultEs[] = {
42*7c478bd9Sstevel@tonic-gate 	"mcount",
43*7c478bd9Sstevel@tonic-gate 	"__mcleanup",
44*7c478bd9Sstevel@tonic-gate 	0
45*7c478bd9Sstevel@tonic-gate };
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate static char *objname[] = {
50*7c478bd9Sstevel@tonic-gate 	"<invalid object>",
51*7c478bd9Sstevel@tonic-gate 	"PROF_BUFFER_T",
52*7c478bd9Sstevel@tonic-gate 	"PROF_CALLGRAPH_T",
53*7c478bd9Sstevel@tonic-gate 	"PROF_MODULES_T",
54*7c478bd9Sstevel@tonic-gate 	0
55*7c478bd9Sstevel@tonic-gate };
56*7c478bd9Sstevel@tonic-gate #define	MAX_OBJTYPES	3
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #endif DEBUG
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate void
61*7c478bd9Sstevel@tonic-gate done()
62*7c478bd9Sstevel@tonic-gate {
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	exit(EX_OK);
65*7c478bd9Sstevel@tonic-gate }
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate static pctype
68*7c478bd9Sstevel@tonic-gate max(pctype a, pctype b)
69*7c478bd9Sstevel@tonic-gate {
70*7c478bd9Sstevel@tonic-gate 	if (a > b)
71*7c478bd9Sstevel@tonic-gate 		return (a);
72*7c478bd9Sstevel@tonic-gate 	return (b);
73*7c478bd9Sstevel@tonic-gate }
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate static pctype
76*7c478bd9Sstevel@tonic-gate min(pctype a, pctype b)
77*7c478bd9Sstevel@tonic-gate {
78*7c478bd9Sstevel@tonic-gate 	if (a < b)
79*7c478bd9Sstevel@tonic-gate 		return (a);
80*7c478bd9Sstevel@tonic-gate 	return (b);
81*7c478bd9Sstevel@tonic-gate }
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate /*
84*7c478bd9Sstevel@tonic-gate  *	calculate scaled entry point addresses (to save time in asgnsamples),
85*7c478bd9Sstevel@tonic-gate  *	and possibly push the scaled entry points over the entry mask,
86*7c478bd9Sstevel@tonic-gate  *	if it turns out that the entry point is in one bucket and the code
87*7c478bd9Sstevel@tonic-gate  *	for a routine is in the next bucket.
88*7c478bd9Sstevel@tonic-gate  *
89*7c478bd9Sstevel@tonic-gate  */
90*7c478bd9Sstevel@tonic-gate static void
91*7c478bd9Sstevel@tonic-gate alignentries()
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 	register struct nl *	nlp;
94*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
95*7c478bd9Sstevel@tonic-gate 	pctype			bucket_of_entry;
96*7c478bd9Sstevel@tonic-gate 	pctype			bucket_of_code;
97*7c478bd9Sstevel@tonic-gate #endif DEBUG
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	/* for old-style gmon.out, nameslist is only in modules.nl */
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	for (nlp = modules.nl; nlp < modules.npe; nlp++) {
102*7c478bd9Sstevel@tonic-gate 		nlp->svalue = nlp->value / sizeof (UNIT);
103*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
104*7c478bd9Sstevel@tonic-gate 		bucket_of_entry = (nlp->svalue - lowpc) / scale;
105*7c478bd9Sstevel@tonic-gate 		bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
106*7c478bd9Sstevel@tonic-gate 		if (bucket_of_entry < bucket_of_code) {
107*7c478bd9Sstevel@tonic-gate 			if (debug & SAMPLEDEBUG) {
108*7c478bd9Sstevel@tonic-gate 				printf("[alignentries] pushing svalue 0x%llx "
109*7c478bd9Sstevel@tonic-gate 				"to 0x%llx\n", nlp->svalue,
110*7c478bd9Sstevel@tonic-gate 				nlp->svalue + UNITS_TO_CODE);
111*7c478bd9Sstevel@tonic-gate 			}
112*7c478bd9Sstevel@tonic-gate 		}
113*7c478bd9Sstevel@tonic-gate #endif DEBUG
114*7c478bd9Sstevel@tonic-gate 	}
115*7c478bd9Sstevel@tonic-gate }
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate /*
118*7c478bd9Sstevel@tonic-gate  *	old-style gmon.out
119*7c478bd9Sstevel@tonic-gate  *	------------------
120*7c478bd9Sstevel@tonic-gate  *
121*7c478bd9Sstevel@tonic-gate  *	Assign samples to the procedures to which they belong.
122*7c478bd9Sstevel@tonic-gate  *
123*7c478bd9Sstevel@tonic-gate  *	There are three cases as to where pcl and pch can be
124*7c478bd9Sstevel@tonic-gate  *	with respect to the routine entry addresses svalue0 and svalue1
125*7c478bd9Sstevel@tonic-gate  *	as shown in the following diagram.  overlap computes the
126*7c478bd9Sstevel@tonic-gate  *	distance between the arrows, the fraction of the sample
127*7c478bd9Sstevel@tonic-gate  *	that is to be credited to the routine which starts at svalue0.
128*7c478bd9Sstevel@tonic-gate  *
129*7c478bd9Sstevel@tonic-gate  *	    svalue0                                         svalue1
130*7c478bd9Sstevel@tonic-gate  *	       |                                               |
131*7c478bd9Sstevel@tonic-gate  *	       v                                               v
132*7c478bd9Sstevel@tonic-gate  *
133*7c478bd9Sstevel@tonic-gate  *	       +-----------------------------------------------+
134*7c478bd9Sstevel@tonic-gate  *	       |					       |
135*7c478bd9Sstevel@tonic-gate  *	  |  ->|    |<-		->|         |<-		->|    |<-  |
136*7c478bd9Sstevel@tonic-gate  *	  |         |		  |         |		  |         |
137*7c478bd9Sstevel@tonic-gate  *	  +---------+		  +---------+		  +---------+
138*7c478bd9Sstevel@tonic-gate  *
139*7c478bd9Sstevel@tonic-gate  *	  ^         ^		  ^         ^		  ^         ^
140*7c478bd9Sstevel@tonic-gate  *	  |         |		  |         |		  |         |
141*7c478bd9Sstevel@tonic-gate  *	 pcl       pch		 pcl       pch		 pcl       pch
142*7c478bd9Sstevel@tonic-gate  *
143*7c478bd9Sstevel@tonic-gate  *	For the vax we assert that samples will never fall in the first
144*7c478bd9Sstevel@tonic-gate  *	two bytes of any routine, since that is the entry mask,
145*7c478bd9Sstevel@tonic-gate  *	thus we give call alignentries() to adjust the entry points if
146*7c478bd9Sstevel@tonic-gate  *	the entry mask falls in one bucket but the code for the routine
147*7c478bd9Sstevel@tonic-gate  *	doesn't start until the next bucket.  In conjunction with the
148*7c478bd9Sstevel@tonic-gate  *	alignment of routine addresses, this should allow us to have
149*7c478bd9Sstevel@tonic-gate  *	only one sample for every four bytes of text space and never
150*7c478bd9Sstevel@tonic-gate  *	have any overlap (the two end cases, above).
151*7c478bd9Sstevel@tonic-gate  */
152*7c478bd9Sstevel@tonic-gate static void
153*7c478bd9Sstevel@tonic-gate asgnsamples()
154*7c478bd9Sstevel@tonic-gate {
155*7c478bd9Sstevel@tonic-gate 	sztype		i, j;
156*7c478bd9Sstevel@tonic-gate 	unsigned_UNIT	ccnt;
157*7c478bd9Sstevel@tonic-gate 	double		time;
158*7c478bd9Sstevel@tonic-gate 	pctype		pcl, pch;
159*7c478bd9Sstevel@tonic-gate 	pctype		overlap;
160*7c478bd9Sstevel@tonic-gate 	pctype		svalue0, svalue1;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	extern mod_info_t	modules;
163*7c478bd9Sstevel@tonic-gate 	nltype		*nl = modules.nl;
164*7c478bd9Sstevel@tonic-gate 	sztype		nname = modules.nname;
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	/* read samples and assign to namelist symbols */
167*7c478bd9Sstevel@tonic-gate 	scale = highpc - lowpc;
168*7c478bd9Sstevel@tonic-gate 	scale /= nsamples;
169*7c478bd9Sstevel@tonic-gate 	alignentries();
170*7c478bd9Sstevel@tonic-gate 	for (i = 0, j = 1; i < nsamples; i++) {
171*7c478bd9Sstevel@tonic-gate 		ccnt = samples[i];
172*7c478bd9Sstevel@tonic-gate 		if (ccnt == 0)
173*7c478bd9Sstevel@tonic-gate 			continue;
174*7c478bd9Sstevel@tonic-gate 		pcl = lowpc + scale * i;
175*7c478bd9Sstevel@tonic-gate 		pch = lowpc + scale * (i + 1);
176*7c478bd9Sstevel@tonic-gate 		time = ccnt;
177*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
178*7c478bd9Sstevel@tonic-gate 		if (debug & SAMPLEDEBUG) {
179*7c478bd9Sstevel@tonic-gate 			printf("[asgnsamples] pcl 0x%llx pch 0x%llx ccnt %d\n",
180*7c478bd9Sstevel@tonic-gate 			    pcl, pch, ccnt);
181*7c478bd9Sstevel@tonic-gate 		}
182*7c478bd9Sstevel@tonic-gate #endif DEBUG
183*7c478bd9Sstevel@tonic-gate 		totime += time;
184*7c478bd9Sstevel@tonic-gate 		for (j = (j ? j - 1 : 0); j < nname; j++) {
185*7c478bd9Sstevel@tonic-gate 			svalue0 = nl[j].svalue;
186*7c478bd9Sstevel@tonic-gate 			svalue1 = nl[j+1].svalue;
187*7c478bd9Sstevel@tonic-gate 			/*
188*7c478bd9Sstevel@tonic-gate 			 *	if high end of tick is below entry address,
189*7c478bd9Sstevel@tonic-gate 			 *	go for next tick.
190*7c478bd9Sstevel@tonic-gate 			 */
191*7c478bd9Sstevel@tonic-gate 			if (pch < svalue0)
192*7c478bd9Sstevel@tonic-gate 				break;
193*7c478bd9Sstevel@tonic-gate 			/*
194*7c478bd9Sstevel@tonic-gate 			 *	if low end of tick into next routine,
195*7c478bd9Sstevel@tonic-gate 			 *	go for next routine.
196*7c478bd9Sstevel@tonic-gate 			 */
197*7c478bd9Sstevel@tonic-gate 			if (pcl >= svalue1)
198*7c478bd9Sstevel@tonic-gate 				continue;
199*7c478bd9Sstevel@tonic-gate 			overlap = min(pch, svalue1) - max(pcl, svalue0);
200*7c478bd9Sstevel@tonic-gate 			if (overlap != 0) {
201*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
202*7c478bd9Sstevel@tonic-gate 				if (debug & SAMPLEDEBUG) {
203*7c478bd9Sstevel@tonic-gate 					printf("[asgnsamples] "
204*7c478bd9Sstevel@tonic-gate 					    "(0x%llx->0x%llx-0x%llx) %s gets "
205*7c478bd9Sstevel@tonic-gate 					    "%f ticks %lld overlap\n",
206*7c478bd9Sstevel@tonic-gate 					    nl[j].value/sizeof (UNIT), svalue0,
207*7c478bd9Sstevel@tonic-gate 					    svalue1, nl[j].name,
208*7c478bd9Sstevel@tonic-gate 					    overlap * time / scale, overlap);
209*7c478bd9Sstevel@tonic-gate 				}
210*7c478bd9Sstevel@tonic-gate #endif DEBUG
211*7c478bd9Sstevel@tonic-gate 				nl[j].time += overlap * time / scale;
212*7c478bd9Sstevel@tonic-gate 			}
213*7c478bd9Sstevel@tonic-gate 		}
214*7c478bd9Sstevel@tonic-gate 	}
215*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
216*7c478bd9Sstevel@tonic-gate 	if (debug & SAMPLEDEBUG) {
217*7c478bd9Sstevel@tonic-gate 		printf("[asgnsamples] totime %f\n", totime);
218*7c478bd9Sstevel@tonic-gate 	}
219*7c478bd9Sstevel@tonic-gate #endif DEBUG
220*7c478bd9Sstevel@tonic-gate }
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate static void
224*7c478bd9Sstevel@tonic-gate dump_callgraph(FILE *fp, char *filename,
225*7c478bd9Sstevel@tonic-gate 				unsigned long tarcs, unsigned long ncallees)
226*7c478bd9Sstevel@tonic-gate {
227*7c478bd9Sstevel@tonic-gate 	ProfCallGraph		prof_cgraph;
228*7c478bd9Sstevel@tonic-gate 	ProfFunction		prof_func;
229*7c478bd9Sstevel@tonic-gate 	register arctype	*arcp;
230*7c478bd9Sstevel@tonic-gate 	mod_info_t		*mi;
231*7c478bd9Sstevel@tonic-gate 	nltype			*nlp;
232*7c478bd9Sstevel@tonic-gate 	size_t			cur_offset;
233*7c478bd9Sstevel@tonic-gate 	unsigned long		caller_id = 0, callee_id = 0;
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	/*
236*7c478bd9Sstevel@tonic-gate 	 * Write the callgraph header
237*7c478bd9Sstevel@tonic-gate 	 */
238*7c478bd9Sstevel@tonic-gate 	prof_cgraph.type = PROF_CALLGRAPH_T;
239*7c478bd9Sstevel@tonic-gate 	prof_cgraph.version = PROF_CALLGRAPH_VER;
240*7c478bd9Sstevel@tonic-gate 	prof_cgraph.functions = PROFCGRAPH_SZ;
241*7c478bd9Sstevel@tonic-gate 	prof_cgraph.size = PROFCGRAPH_SZ + tarcs * PROFFUNC_SZ;
242*7c478bd9Sstevel@tonic-gate 	if (fwrite(&prof_cgraph, sizeof (ProfCallGraph), 1, fp) != 1) {
243*7c478bd9Sstevel@tonic-gate 		perror(filename);
244*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 	if (CGRAPH_FILLER)
247*7c478bd9Sstevel@tonic-gate 		fseek(fp, CGRAPH_FILLER, SEEK_CUR);
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	/* Current offset inside the callgraph object */
250*7c478bd9Sstevel@tonic-gate 	cur_offset = prof_cgraph.functions;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
253*7c478bd9Sstevel@tonic-gate 		for (nlp = mi->nl; nlp < mi->npe; nlp++) {
254*7c478bd9Sstevel@tonic-gate 			if (nlp->ncallers == 0)
255*7c478bd9Sstevel@tonic-gate 				continue;
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 			/* If this is the last callee, set next_to to 0 */
258*7c478bd9Sstevel@tonic-gate 			callee_id++;
259*7c478bd9Sstevel@tonic-gate 			if (callee_id == ncallees)
260*7c478bd9Sstevel@tonic-gate 				prof_func.next_to = 0;
261*7c478bd9Sstevel@tonic-gate 			else {
262*7c478bd9Sstevel@tonic-gate 				prof_func.next_to = cur_offset +
263*7c478bd9Sstevel@tonic-gate 						    nlp->ncallers * PROFFUNC_SZ;
264*7c478bd9Sstevel@tonic-gate 			}
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 			/*
267*7c478bd9Sstevel@tonic-gate 			 * Dump this callee's raw arc information with all
268*7c478bd9Sstevel@tonic-gate 			 * its callers
269*7c478bd9Sstevel@tonic-gate 			 */
270*7c478bd9Sstevel@tonic-gate 			caller_id = 1;
271*7c478bd9Sstevel@tonic-gate 			for (arcp = nlp->parents; arcp;
272*7c478bd9Sstevel@tonic-gate 					    arcp = arcp->arc_parentlist) {
273*7c478bd9Sstevel@tonic-gate 				/*
274*7c478bd9Sstevel@tonic-gate 				 * If no more callers for this callee, set
275*7c478bd9Sstevel@tonic-gate 				 * next_from to 0
276*7c478bd9Sstevel@tonic-gate 				 */
277*7c478bd9Sstevel@tonic-gate 				if (caller_id == nlp->ncallers)
278*7c478bd9Sstevel@tonic-gate 					prof_func.next_from = 0;
279*7c478bd9Sstevel@tonic-gate 				else {
280*7c478bd9Sstevel@tonic-gate 					prof_func.next_from = cur_offset +
281*7c478bd9Sstevel@tonic-gate 								PROFFUNC_SZ;
282*7c478bd9Sstevel@tonic-gate 				}
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 				prof_func.frompc =
285*7c478bd9Sstevel@tonic-gate 					arcp->arc_parentp->module->load_base +
286*7c478bd9Sstevel@tonic-gate 					(arcp->arc_parentp->value -
287*7c478bd9Sstevel@tonic-gate 					arcp->arc_parentp->module->txt_origin);
288*7c478bd9Sstevel@tonic-gate 				prof_func.topc =
289*7c478bd9Sstevel@tonic-gate 					mi->load_base +
290*7c478bd9Sstevel@tonic-gate 						(nlp->value - mi->txt_origin);
291*7c478bd9Sstevel@tonic-gate 				prof_func.count = arcp->arc_count;
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 				if (fwrite(&prof_func, sizeof (ProfFunction),
295*7c478bd9Sstevel@tonic-gate 								1, fp) != 1) {
296*7c478bd9Sstevel@tonic-gate 					perror(filename);
297*7c478bd9Sstevel@tonic-gate 					exit(EX_IOERR);
298*7c478bd9Sstevel@tonic-gate 				}
299*7c478bd9Sstevel@tonic-gate 				if (FUNC_FILLER)
300*7c478bd9Sstevel@tonic-gate 					fseek(fp, FUNC_FILLER, SEEK_CUR);
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 				cur_offset += PROFFUNC_SZ;
303*7c478bd9Sstevel@tonic-gate 				caller_id++;
304*7c478bd9Sstevel@tonic-gate 			}
305*7c478bd9Sstevel@tonic-gate 		} /* for nlp... */
306*7c478bd9Sstevel@tonic-gate 	} /* for mi... */
307*7c478bd9Sstevel@tonic-gate }
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate /*
310*7c478bd9Sstevel@tonic-gate  * To save all pc-hits in all the gmon.out's is infeasible, as this
311*7c478bd9Sstevel@tonic-gate  * may become quite huge even with a small number of files to sum.
312*7c478bd9Sstevel@tonic-gate  * Instead, we'll dump *fictitious hits* to correct functions
313*7c478bd9Sstevel@tonic-gate  * by scanning module namelists. Again, since this is summing
314*7c478bd9Sstevel@tonic-gate  * pc-hits, we may have to dump the pcsamples out in chunks if the
315*7c478bd9Sstevel@tonic-gate  * number of pc-hits is high.
316*7c478bd9Sstevel@tonic-gate  */
317*7c478bd9Sstevel@tonic-gate static void
318*7c478bd9Sstevel@tonic-gate dump_hits(FILE *fp, char *filename, nltype *nlp)
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate 	Address		*p, hitpc;
321*7c478bd9Sstevel@tonic-gate 	size_t		i, nelem, ntowrite;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	if ((nelem = nlp->nticks) > PROF_BUFFER_SIZE)
324*7c478bd9Sstevel@tonic-gate 		nelem = PROF_BUFFER_SIZE;
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	if ((p = (Address *) calloc(nelem, sizeof (Address))) == NULL) {
327*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: no room for %ld pcsamples\n",
328*7c478bd9Sstevel@tonic-gate 							    whoami, nelem);
329*7c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
330*7c478bd9Sstevel@tonic-gate 	}
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	/*
333*7c478bd9Sstevel@tonic-gate 	 * Set up *fictitious* hits (to function entry) buffer
334*7c478bd9Sstevel@tonic-gate 	 */
335*7c478bd9Sstevel@tonic-gate 	hitpc = nlp->module->load_base + (nlp->value - nlp->module->txt_origin);
336*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nelem; i++)
337*7c478bd9Sstevel@tonic-gate 		p[i] = hitpc;
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	for (ntowrite = nlp->nticks; ntowrite >= nelem; ntowrite -= nelem) {
340*7c478bd9Sstevel@tonic-gate 		if (fwrite(p, nelem * sizeof (Address), 1, fp) != 1) {
341*7c478bd9Sstevel@tonic-gate 			perror(filename);
342*7c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
343*7c478bd9Sstevel@tonic-gate 		}
344*7c478bd9Sstevel@tonic-gate 	}
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	if (ntowrite) {
347*7c478bd9Sstevel@tonic-gate 		if (fwrite(p, ntowrite * sizeof (Address), 1, fp) != 1) {
348*7c478bd9Sstevel@tonic-gate 			perror(filename);
349*7c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
350*7c478bd9Sstevel@tonic-gate 		}
351*7c478bd9Sstevel@tonic-gate 	}
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	free(p);
354*7c478bd9Sstevel@tonic-gate }
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate static void
357*7c478bd9Sstevel@tonic-gate dump_pcsamples(FILE *fp, char *filename,
358*7c478bd9Sstevel@tonic-gate 				unsigned long *tarcs, unsigned long *ncallees)
359*7c478bd9Sstevel@tonic-gate {
360*7c478bd9Sstevel@tonic-gate 	ProfBuffer		prof_buffer;
361*7c478bd9Sstevel@tonic-gate 	register arctype	*arcp;
362*7c478bd9Sstevel@tonic-gate 	mod_info_t		*mi;
363*7c478bd9Sstevel@tonic-gate 	nltype			*nlp;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	prof_buffer.type = PROF_BUFFER_T;
366*7c478bd9Sstevel@tonic-gate 	prof_buffer.version = PROF_BUFFER_VER;
367*7c478bd9Sstevel@tonic-gate 	prof_buffer.buffer = PROFBUF_SZ;
368*7c478bd9Sstevel@tonic-gate 	prof_buffer.bufsize = n_pcsamples;
369*7c478bd9Sstevel@tonic-gate 	prof_buffer.size = PROFBUF_SZ + n_pcsamples * sizeof (Address);
370*7c478bd9Sstevel@tonic-gate 	if (fwrite(&prof_buffer, sizeof (ProfBuffer), 1, fp) != 1) {
371*7c478bd9Sstevel@tonic-gate 		perror(filename);
372*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
373*7c478bd9Sstevel@tonic-gate 	}
374*7c478bd9Sstevel@tonic-gate 	if (BUF_FILLER)
375*7c478bd9Sstevel@tonic-gate 		fseek(fp, BUF_FILLER, SEEK_CUR);
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	*tarcs = 0;
378*7c478bd9Sstevel@tonic-gate 	*ncallees = 0;
379*7c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
380*7c478bd9Sstevel@tonic-gate 		for (nlp = mi->nl; nlp < mi->npe; nlp++) {
381*7c478bd9Sstevel@tonic-gate 			if (nlp->nticks)
382*7c478bd9Sstevel@tonic-gate 				dump_hits(fp, filename, nlp);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 			nlp->ncallers = 0;
385*7c478bd9Sstevel@tonic-gate 			for (arcp = nlp->parents; arcp;
386*7c478bd9Sstevel@tonic-gate 					    arcp = arcp->arc_parentlist) {
387*7c478bd9Sstevel@tonic-gate 				(nlp->ncallers)++;
388*7c478bd9Sstevel@tonic-gate 			}
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 			if (nlp->ncallers) {
391*7c478bd9Sstevel@tonic-gate 				(*tarcs) += nlp->ncallers;
392*7c478bd9Sstevel@tonic-gate 				(*ncallees)++;
393*7c478bd9Sstevel@tonic-gate 			}
394*7c478bd9Sstevel@tonic-gate 		}
395*7c478bd9Sstevel@tonic-gate 	}
396*7c478bd9Sstevel@tonic-gate }
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate static void
399*7c478bd9Sstevel@tonic-gate dump_modules(FILE *fp, char *filename, size_t pbuf_sz)
400*7c478bd9Sstevel@tonic-gate {
401*7c478bd9Sstevel@tonic-gate 	char		*pbuf, *p;
402*7c478bd9Sstevel@tonic-gate 	size_t		namelen;
403*7c478bd9Sstevel@tonic-gate 	Index		off_nxt, off_path;
404*7c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	ProfModuleList	prof_modlist;
407*7c478bd9Sstevel@tonic-gate 	ProfModule	prof_mod;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	/* Allocate for path strings buffer */
410*7c478bd9Sstevel@tonic-gate 	pbuf_sz = CEIL(pbuf_sz, STRUCT_ALIGN);
411*7c478bd9Sstevel@tonic-gate 	if ((p = pbuf = (char *) calloc(pbuf_sz, sizeof (char))) == NULL) {
412*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: no room for %ld bytes\n",
413*7c478bd9Sstevel@tonic-gate 					    whoami, pbuf_sz * sizeof (char));
414*7c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	/* Dump out PROF_MODULE_T info for all non-aout modules */
418*7c478bd9Sstevel@tonic-gate 	prof_modlist.type = PROF_MODULES_T;
419*7c478bd9Sstevel@tonic-gate 	prof_modlist.version = PROF_MODULES_VER;
420*7c478bd9Sstevel@tonic-gate 	prof_modlist.modules = PROFMODLIST_SZ;
421*7c478bd9Sstevel@tonic-gate 	prof_modlist.size = PROFMODLIST_SZ + (n_modules - 1) * PROFMOD_SZ +
422*7c478bd9Sstevel@tonic-gate 								    pbuf_sz;
423*7c478bd9Sstevel@tonic-gate 	if (fwrite(&prof_modlist, sizeof (ProfModuleList), 1, fp) != 1) {
424*7c478bd9Sstevel@tonic-gate 		perror(filename);
425*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
426*7c478bd9Sstevel@tonic-gate 	}
427*7c478bd9Sstevel@tonic-gate 	if (MODLIST_FILLER)
428*7c478bd9Sstevel@tonic-gate 		fseek(fp, MODLIST_FILLER, SEEK_CUR);
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	/*
431*7c478bd9Sstevel@tonic-gate 	 * Initialize offsets for ProfModule elements.
432*7c478bd9Sstevel@tonic-gate 	 */
433*7c478bd9Sstevel@tonic-gate 	off_nxt = PROFMODLIST_SZ + PROFMOD_SZ;
434*7c478bd9Sstevel@tonic-gate 	off_path = PROFMODLIST_SZ + (n_modules - 1) * PROFMOD_SZ;
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	for (mi = modules.next; mi; mi = mi->next) {
437*7c478bd9Sstevel@tonic-gate 		if (mi->next)
438*7c478bd9Sstevel@tonic-gate 			prof_mod.next = off_nxt;
439*7c478bd9Sstevel@tonic-gate 		else
440*7c478bd9Sstevel@tonic-gate 			prof_mod.next = 0;
441*7c478bd9Sstevel@tonic-gate 		prof_mod.path = off_path;
442*7c478bd9Sstevel@tonic-gate 		prof_mod.startaddr = mi->load_base;
443*7c478bd9Sstevel@tonic-gate 		prof_mod.endaddr = mi->load_end;
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 		if (fwrite(&prof_mod, sizeof (ProfModule), 1, fp) != 1) {
446*7c478bd9Sstevel@tonic-gate 			perror(filename);
447*7c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
448*7c478bd9Sstevel@tonic-gate 		}
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 		if (MOD_FILLER)
451*7c478bd9Sstevel@tonic-gate 			fseek(fp, MOD_FILLER, SEEK_CUR);
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 		strcpy(p, mi->name);
454*7c478bd9Sstevel@tonic-gate 		namelen = strlen(mi->name);
455*7c478bd9Sstevel@tonic-gate 		p += namelen + 1;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 		/* Note that offset to every path str need not be aligned */
458*7c478bd9Sstevel@tonic-gate 		off_nxt += PROFMOD_SZ;
459*7c478bd9Sstevel@tonic-gate 		off_path += namelen + 1;
460*7c478bd9Sstevel@tonic-gate 	}
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	/* Write out the module path strings */
463*7c478bd9Sstevel@tonic-gate 	if (pbuf_sz) {
464*7c478bd9Sstevel@tonic-gate 		if (fwrite(pbuf, pbuf_sz, 1, fp) != 1) {
465*7c478bd9Sstevel@tonic-gate 			perror(filename);
466*7c478bd9Sstevel@tonic-gate 			exit(EX_IOERR);
467*7c478bd9Sstevel@tonic-gate 		}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 		free(pbuf);
470*7c478bd9Sstevel@tonic-gate 	}
471*7c478bd9Sstevel@tonic-gate }
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate /*
474*7c478bd9Sstevel@tonic-gate  * If we have inactive modules, their current load addresses may overlap with
475*7c478bd9Sstevel@tonic-gate  * active ones, and so we've to assign fictitious, non-overlapping addresses
476*7c478bd9Sstevel@tonic-gate  * to all modules before we dump them.
477*7c478bd9Sstevel@tonic-gate  */
478*7c478bd9Sstevel@tonic-gate static void
479*7c478bd9Sstevel@tonic-gate fixup_maps(size_t *pathsz)
480*7c478bd9Sstevel@tonic-gate {
481*7c478bd9Sstevel@tonic-gate 	unsigned int	n_inactive = 0;
482*7c478bd9Sstevel@tonic-gate 	Address		lbase, lend;
483*7c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	/* Pick the lowest load address among modules */
486*7c478bd9Sstevel@tonic-gate 	*pathsz = 0;
487*7c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 		if (mi->active == FALSE)
490*7c478bd9Sstevel@tonic-gate 			n_inactive++;
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 		if (mi == &modules || mi->load_base < lbase)
493*7c478bd9Sstevel@tonic-gate 			lbase = mi->load_base;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 		/*
496*7c478bd9Sstevel@tonic-gate 		 * Return total path size of non-aout modules only
497*7c478bd9Sstevel@tonic-gate 		 */
498*7c478bd9Sstevel@tonic-gate 		if (mi != &modules)
499*7c478bd9Sstevel@tonic-gate 			*pathsz = (*pathsz) + strlen(mi->name) + 1;
500*7c478bd9Sstevel@tonic-gate 	}
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	/*
503*7c478bd9Sstevel@tonic-gate 	 * All module info is in fine shape already if there are no
504*7c478bd9Sstevel@tonic-gate 	 * inactive modules
505*7c478bd9Sstevel@tonic-gate 	 */
506*7c478bd9Sstevel@tonic-gate 	if (n_inactive == 0)
507*7c478bd9Sstevel@tonic-gate 		return;
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	/*
510*7c478bd9Sstevel@tonic-gate 	 * Assign fictitious load addresses to all (non-aout) modules so
511*7c478bd9Sstevel@tonic-gate 	 * that sum info can be dumped out.
512*7c478bd9Sstevel@tonic-gate 	 */
513*7c478bd9Sstevel@tonic-gate 	for (mi = modules.next; mi; mi = mi->next) {
514*7c478bd9Sstevel@tonic-gate 		lend = lbase + (mi->data_end - mi->txt_origin);
515*7c478bd9Sstevel@tonic-gate 		if ((lbase < modules.load_base && lend < modules.load_base) ||
516*7c478bd9Sstevel@tonic-gate 		    (lbase > modules.load_end && lend > modules.load_end)) {
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 			mi->load_base = lbase;
519*7c478bd9Sstevel@tonic-gate 			mi->load_end = lend;
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 			/* just to give an appearance of reality */
522*7c478bd9Sstevel@tonic-gate 			lbase = CEIL(lend + PGSZ, PGSZ);
523*7c478bd9Sstevel@tonic-gate 		} else {
524*7c478bd9Sstevel@tonic-gate 			/*
525*7c478bd9Sstevel@tonic-gate 			 * can't use this lbase & lend pair, as it
526*7c478bd9Sstevel@tonic-gate 			 * overlaps with aout's addresses
527*7c478bd9Sstevel@tonic-gate 			 */
528*7c478bd9Sstevel@tonic-gate 			mi->load_base = CEIL(modules.load_end + PGSZ, PGSZ);
529*7c478bd9Sstevel@tonic-gate 			mi->load_end = mi->load_base + (lend - lbase);
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 			lbase = CEIL(mi->load_end + PGSZ, PGSZ);
532*7c478bd9Sstevel@tonic-gate 		}
533*7c478bd9Sstevel@tonic-gate 	}
534*7c478bd9Sstevel@tonic-gate }
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate static void
537*7c478bd9Sstevel@tonic-gate dump_gprofhdr(FILE *fp, char *filename)
538*7c478bd9Sstevel@tonic-gate {
539*7c478bd9Sstevel@tonic-gate 	ProfHeader	prof_hdr;
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 	prof_hdr.h_magic = PROF_MAGIC;
542*7c478bd9Sstevel@tonic-gate 	prof_hdr.h_major_ver = PROF_MAJOR_VERSION;
543*7c478bd9Sstevel@tonic-gate 	prof_hdr.h_minor_ver = PROF_MINOR_VERSION;
544*7c478bd9Sstevel@tonic-gate 	prof_hdr.size = PROFHDR_SZ;
545*7c478bd9Sstevel@tonic-gate 	if (fwrite(&prof_hdr, sizeof (prof_hdr), 1, fp) != 1) {
546*7c478bd9Sstevel@tonic-gate 		perror(filename);
547*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	if (HDR_FILLER)
551*7c478bd9Sstevel@tonic-gate 		fseek(fp, HDR_FILLER, SEEK_CUR);
552*7c478bd9Sstevel@tonic-gate }
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate static void
555*7c478bd9Sstevel@tonic-gate dumpsum_ostyle(char *sumfile)
556*7c478bd9Sstevel@tonic-gate {
557*7c478bd9Sstevel@tonic-gate 	register nltype *nlp;
558*7c478bd9Sstevel@tonic-gate 	register arctype *arcp;
559*7c478bd9Sstevel@tonic-gate 	struct rawarc arc;
560*7c478bd9Sstevel@tonic-gate 	struct rawarc32 arc32;
561*7c478bd9Sstevel@tonic-gate 	FILE *sfile;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	if ((sfile = fopen(sumfile, "w")) == NULL) {
564*7c478bd9Sstevel@tonic-gate 		perror(sumfile);
565*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
566*7c478bd9Sstevel@tonic-gate 	}
567*7c478bd9Sstevel@tonic-gate 	/*
568*7c478bd9Sstevel@tonic-gate 	 * dump the header; use the last header read in
569*7c478bd9Sstevel@tonic-gate 	 */
570*7c478bd9Sstevel@tonic-gate 	if (Bflag) {
571*7c478bd9Sstevel@tonic-gate 	    if (fwrite(&h, sizeof (h), 1, sfile) != 1) {
572*7c478bd9Sstevel@tonic-gate 		perror(sumfile);
573*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
574*7c478bd9Sstevel@tonic-gate 	    }
575*7c478bd9Sstevel@tonic-gate 	} else {
576*7c478bd9Sstevel@tonic-gate 	    struct hdr32 hdr;
577*7c478bd9Sstevel@tonic-gate 	    hdr.lowpc  = (pctype32)h.lowpc;
578*7c478bd9Sstevel@tonic-gate 	    hdr.highpc = (pctype32)h.highpc;
579*7c478bd9Sstevel@tonic-gate 	    hdr.ncnt   = (pctype32)h.ncnt;
580*7c478bd9Sstevel@tonic-gate 	    if (fwrite(&hdr, sizeof (hdr), 1, sfile) != 1) {
581*7c478bd9Sstevel@tonic-gate 		perror(sumfile);
582*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
583*7c478bd9Sstevel@tonic-gate 	    }
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 	/*
586*7c478bd9Sstevel@tonic-gate 	 * dump the samples
587*7c478bd9Sstevel@tonic-gate 	 */
588*7c478bd9Sstevel@tonic-gate 	if (fwrite(samples, sizeof (unsigned_UNIT), nsamples, sfile) !=
589*7c478bd9Sstevel@tonic-gate 	    nsamples) {
590*7c478bd9Sstevel@tonic-gate 		perror(sumfile);
591*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
592*7c478bd9Sstevel@tonic-gate 	}
593*7c478bd9Sstevel@tonic-gate 	/*
594*7c478bd9Sstevel@tonic-gate 	 * dump the normalized raw arc information. For old-style dumping,
595*7c478bd9Sstevel@tonic-gate 	 * the only namelist is in modules.nl
596*7c478bd9Sstevel@tonic-gate 	 */
597*7c478bd9Sstevel@tonic-gate 	for (nlp = modules.nl; nlp < modules.npe; nlp++) {
598*7c478bd9Sstevel@tonic-gate 		for (arcp = nlp->children; arcp;
599*7c478bd9Sstevel@tonic-gate 		    arcp = arcp->arc_childlist) {
600*7c478bd9Sstevel@tonic-gate 			if (Bflag) {
601*7c478bd9Sstevel@tonic-gate 			    arc.raw_frompc = arcp->arc_parentp->value;
602*7c478bd9Sstevel@tonic-gate 			    arc.raw_selfpc = arcp->arc_childp->value;
603*7c478bd9Sstevel@tonic-gate 			    arc.raw_count = arcp->arc_count;
604*7c478bd9Sstevel@tonic-gate 			    if (fwrite(&arc, sizeof (arc), 1, sfile) != 1) {
605*7c478bd9Sstevel@tonic-gate 				    perror(sumfile);
606*7c478bd9Sstevel@tonic-gate 				    exit(EX_IOERR);
607*7c478bd9Sstevel@tonic-gate 			    }
608*7c478bd9Sstevel@tonic-gate 			} else {
609*7c478bd9Sstevel@tonic-gate 			    arc32.raw_frompc =
610*7c478bd9Sstevel@tonic-gate 				(pctype32)arcp->arc_parentp->value;
611*7c478bd9Sstevel@tonic-gate 			    arc32.raw_selfpc =
612*7c478bd9Sstevel@tonic-gate 				(pctype32)arcp->arc_childp->value;
613*7c478bd9Sstevel@tonic-gate 			    arc32.raw_count = (actype32)arcp->arc_count;
614*7c478bd9Sstevel@tonic-gate 			    if (fwrite(&arc32, sizeof (arc32), 1, sfile) != 1) {
615*7c478bd9Sstevel@tonic-gate 				    perror(sumfile);
616*7c478bd9Sstevel@tonic-gate 				    exit(EX_IOERR);
617*7c478bd9Sstevel@tonic-gate 			    }
618*7c478bd9Sstevel@tonic-gate 			}
619*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
620*7c478bd9Sstevel@tonic-gate 			if (debug & SAMPLEDEBUG) {
621*7c478bd9Sstevel@tonic-gate 				printf("[dumpsum_ostyle] frompc 0x%llx selfpc "
622*7c478bd9Sstevel@tonic-gate 				    "0x%llx count %lld\n", arc.raw_frompc,
623*7c478bd9Sstevel@tonic-gate 				    arc.raw_selfpc, arc.raw_count);
624*7c478bd9Sstevel@tonic-gate 			}
625*7c478bd9Sstevel@tonic-gate #endif DEBUG
626*7c478bd9Sstevel@tonic-gate 		}
627*7c478bd9Sstevel@tonic-gate 	}
628*7c478bd9Sstevel@tonic-gate 	fclose(sfile);
629*7c478bd9Sstevel@tonic-gate }
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate /*
632*7c478bd9Sstevel@tonic-gate  * dump out the gmon.sum file
633*7c478bd9Sstevel@tonic-gate  */
634*7c478bd9Sstevel@tonic-gate static void
635*7c478bd9Sstevel@tonic-gate dumpsum(char *sumfile)
636*7c478bd9Sstevel@tonic-gate {
637*7c478bd9Sstevel@tonic-gate 	FILE		*sfile;
638*7c478bd9Sstevel@tonic-gate 	size_t		pathbuf_sz;
639*7c478bd9Sstevel@tonic-gate 	unsigned long	total_arcs;	/* total number of arcs in all */
640*7c478bd9Sstevel@tonic-gate 	unsigned long	ncallees;	/* no. of callees with parents */
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	if (old_style) {
643*7c478bd9Sstevel@tonic-gate 		dumpsum_ostyle(sumfile);
644*7c478bd9Sstevel@tonic-gate 		return;
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	if ((sfile = fopen(sumfile, "w")) == NULL) {
648*7c478bd9Sstevel@tonic-gate 		perror(sumfile);
649*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
650*7c478bd9Sstevel@tonic-gate 	}
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	/*
653*7c478bd9Sstevel@tonic-gate 	 * Dump the new-style gprof header. Even if one of the original
654*7c478bd9Sstevel@tonic-gate 	 * profiled-files was of a older version, the summed file is of
655*7c478bd9Sstevel@tonic-gate 	 * current version only.
656*7c478bd9Sstevel@tonic-gate 	 */
657*7c478bd9Sstevel@tonic-gate 	dump_gprofhdr(sfile, sumfile);
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 	/*
660*7c478bd9Sstevel@tonic-gate 	 * Fix up load-maps and dump out modules info
661*7c478bd9Sstevel@tonic-gate 	 *
662*7c478bd9Sstevel@tonic-gate 	 * Fix up module load maps so inactive modules get *some* address
663*7c478bd9Sstevel@tonic-gate 	 * (and btw, could you get the total size of non-aout module path
664*7c478bd9Sstevel@tonic-gate 	 * strings please ?)
665*7c478bd9Sstevel@tonic-gate 	 */
666*7c478bd9Sstevel@tonic-gate 	fixup_maps(&pathbuf_sz);
667*7c478bd9Sstevel@tonic-gate 	dump_modules(sfile, sumfile, pathbuf_sz);
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	/*
671*7c478bd9Sstevel@tonic-gate 	 * Dump out the summ'd pcsamples
672*7c478bd9Sstevel@tonic-gate 	 *
673*7c478bd9Sstevel@tonic-gate 	 * For dumping call graph information later, we need certain
674*7c478bd9Sstevel@tonic-gate 	 * statistics (like total arcs, number of callers for each node);
675*7c478bd9Sstevel@tonic-gate 	 * collect these also while we are at it.
676*7c478bd9Sstevel@tonic-gate 	 */
677*7c478bd9Sstevel@tonic-gate 	dump_pcsamples(sfile, sumfile, &total_arcs, &ncallees);
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	/*
680*7c478bd9Sstevel@tonic-gate 	 * Dump out the summ'd call graph information
681*7c478bd9Sstevel@tonic-gate 	 */
682*7c478bd9Sstevel@tonic-gate 	dump_callgraph(sfile, sumfile, total_arcs, ncallees);
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	fclose(sfile);
686*7c478bd9Sstevel@tonic-gate }
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate static void
689*7c478bd9Sstevel@tonic-gate tally(mod_info_t *caller_mod, mod_info_t *callee_mod, struct rawarc *rawp)
690*7c478bd9Sstevel@tonic-gate {
691*7c478bd9Sstevel@tonic-gate 	nltype		*parentp;
692*7c478bd9Sstevel@tonic-gate 	nltype		*childp;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	/*
695*7c478bd9Sstevel@tonic-gate 	 * if count == 0 this is a null arc and
696*7c478bd9Sstevel@tonic-gate 	 * we don't need to tally it.
697*7c478bd9Sstevel@tonic-gate 	 */
698*7c478bd9Sstevel@tonic-gate 	if (rawp->raw_count == 0)
699*7c478bd9Sstevel@tonic-gate 		return;
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	/*
702*7c478bd9Sstevel@tonic-gate 	 * Lookup the caller and callee pcs in namelists of
703*7c478bd9Sstevel@tonic-gate 	 * appropriate modules
704*7c478bd9Sstevel@tonic-gate 	 */
705*7c478bd9Sstevel@tonic-gate 	parentp = nllookup(caller_mod, rawp->raw_frompc, NULL);
706*7c478bd9Sstevel@tonic-gate 	childp = nllookup(callee_mod, rawp->raw_selfpc, NULL);
707*7c478bd9Sstevel@tonic-gate 	if (childp && parentp) {
708*7c478bd9Sstevel@tonic-gate 		if (!Dflag)
709*7c478bd9Sstevel@tonic-gate 			childp->ncall += rawp->raw_count;
710*7c478bd9Sstevel@tonic-gate 		else {
711*7c478bd9Sstevel@tonic-gate 			if (first_file)
712*7c478bd9Sstevel@tonic-gate 				childp->ncall += rawp->raw_count;
713*7c478bd9Sstevel@tonic-gate 			else {
714*7c478bd9Sstevel@tonic-gate 				childp->ncall -= rawp->raw_count;
715*7c478bd9Sstevel@tonic-gate 				if (childp->ncall < 0)
716*7c478bd9Sstevel@tonic-gate 					childp->ncall = 0;
717*7c478bd9Sstevel@tonic-gate 			}
718*7c478bd9Sstevel@tonic-gate 		}
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
721*7c478bd9Sstevel@tonic-gate 		if (debug & TALLYDEBUG) {
722*7c478bd9Sstevel@tonic-gate 			printf("[tally] arc from %s to %s traversed "
723*7c478bd9Sstevel@tonic-gate 			    "%lld times\n", parentp->name,
724*7c478bd9Sstevel@tonic-gate 			    childp->name, rawp->raw_count);
725*7c478bd9Sstevel@tonic-gate 		}
726*7c478bd9Sstevel@tonic-gate #endif DEBUG
727*7c478bd9Sstevel@tonic-gate 		addarc(parentp, childp, rawp->raw_count);
728*7c478bd9Sstevel@tonic-gate 	}
729*7c478bd9Sstevel@tonic-gate }
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate /*
732*7c478bd9Sstevel@tonic-gate  * Look up a module's base address in a sorted list of pc-hits. Unlike
733*7c478bd9Sstevel@tonic-gate  * nllookup(), this deals with misses by mapping them to the next *higher*
734*7c478bd9Sstevel@tonic-gate  * pc-hit. This is so that we get into the module's first pc-hit rightaway,
735*7c478bd9Sstevel@tonic-gate  * even if the module's entry-point (load_base) itself is not a hit.
736*7c478bd9Sstevel@tonic-gate  */
737*7c478bd9Sstevel@tonic-gate static Address *
738*7c478bd9Sstevel@tonic-gate locate(Address	*pclist, size_t nelem, Address keypc)
739*7c478bd9Sstevel@tonic-gate {
740*7c478bd9Sstevel@tonic-gate 	size_t	low = 0, middle, high = nelem - 1;
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	if (keypc <= pclist[low])
743*7c478bd9Sstevel@tonic-gate 		return (pclist);
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	if (keypc > pclist[high])
746*7c478bd9Sstevel@tonic-gate 		return (NULL);
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	while (low != high) {
749*7c478bd9Sstevel@tonic-gate 		middle = (high + low) >> 1;
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 		if ((pclist[middle] < keypc) && (pclist[middle + 1] >= keypc))
752*7c478bd9Sstevel@tonic-gate 			return (&pclist[middle + 1]);
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 		if (pclist[middle] >= keypc)
755*7c478bd9Sstevel@tonic-gate 			high = middle;
756*7c478bd9Sstevel@tonic-gate 		else
757*7c478bd9Sstevel@tonic-gate 			low = middle + 1;
758*7c478bd9Sstevel@tonic-gate 	}
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	/* must never reach here! */
761*7c478bd9Sstevel@tonic-gate 	return (NULL);
762*7c478bd9Sstevel@tonic-gate }
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate static void
765*7c478bd9Sstevel@tonic-gate assign_pcsamples(module, pcsmpl, n_samples)
766*7c478bd9Sstevel@tonic-gate mod_info_t	*module;
767*7c478bd9Sstevel@tonic-gate Address		*pcsmpl;
768*7c478bd9Sstevel@tonic-gate size_t		n_samples;
769*7c478bd9Sstevel@tonic-gate {
770*7c478bd9Sstevel@tonic-gate 	Address		*pcptr, *pcse = pcsmpl + n_samples;
771*7c478bd9Sstevel@tonic-gate 	pctype		nxt_func;
772*7c478bd9Sstevel@tonic-gate 	nltype		*fnl;
773*7c478bd9Sstevel@tonic-gate 	size_t		func_nticks;
774*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
775*7c478bd9Sstevel@tonic-gate 	size_t		n_hits_in_module = 0;
776*7c478bd9Sstevel@tonic-gate #endif DEBUG
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	/* Locate the first pc-hit for this module */
779*7c478bd9Sstevel@tonic-gate 	if ((pcptr = locate(pcsmpl, n_samples, module->load_base)) == NULL) {
780*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
781*7c478bd9Sstevel@tonic-gate 		if (debug & PCSMPLDEBUG) {
782*7c478bd9Sstevel@tonic-gate 			printf("[assign_pcsamples] no pc-hits in\n");
783*7c478bd9Sstevel@tonic-gate 			printf("                   `%s'\n", module->name);
784*7c478bd9Sstevel@tonic-gate 		}
785*7c478bd9Sstevel@tonic-gate #endif DEBUG
786*7c478bd9Sstevel@tonic-gate 		return;			/* no pc-hits in this module */
787*7c478bd9Sstevel@tonic-gate 	}
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	/* Assign all pc-hits in this module to appropriate functions */
790*7c478bd9Sstevel@tonic-gate 	while ((pcptr < pcse) && (*pcptr < module->load_end)) {
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 		/* Update the corresponding function's time */
793*7c478bd9Sstevel@tonic-gate 		if (fnl = nllookup(module, (pctype) *pcptr, &nxt_func)) {
794*7c478bd9Sstevel@tonic-gate 			/*
795*7c478bd9Sstevel@tonic-gate 			 * Collect all pc-hits in this function. Each
796*7c478bd9Sstevel@tonic-gate 			 * pc-hit counts as 1 tick.
797*7c478bd9Sstevel@tonic-gate 			 */
798*7c478bd9Sstevel@tonic-gate 			func_nticks = 0;
799*7c478bd9Sstevel@tonic-gate 			while ((pcptr < pcse) && (*pcptr < nxt_func)) {
800*7c478bd9Sstevel@tonic-gate 				func_nticks++;
801*7c478bd9Sstevel@tonic-gate 				pcptr++;
802*7c478bd9Sstevel@tonic-gate 			}
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 			if (func_nticks == 0)
805*7c478bd9Sstevel@tonic-gate 				pcptr++;
806*7c478bd9Sstevel@tonic-gate 			else {
807*7c478bd9Sstevel@tonic-gate 				fnl->nticks += func_nticks;
808*7c478bd9Sstevel@tonic-gate 				fnl->time += func_nticks;
809*7c478bd9Sstevel@tonic-gate 				totime += func_nticks;
810*7c478bd9Sstevel@tonic-gate 			}
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
813*7c478bd9Sstevel@tonic-gate 			n_hits_in_module += func_nticks;
814*7c478bd9Sstevel@tonic-gate #endif DEBUG
815*7c478bd9Sstevel@tonic-gate 		} else {
816*7c478bd9Sstevel@tonic-gate 			/*
817*7c478bd9Sstevel@tonic-gate 			 * pc sample could not be assigned to function;
818*7c478bd9Sstevel@tonic-gate 			 * probably in a PLT
819*7c478bd9Sstevel@tonic-gate 			 */
820*7c478bd9Sstevel@tonic-gate 			pcptr++;
821*7c478bd9Sstevel@tonic-gate 		}
822*7c478bd9Sstevel@tonic-gate 	}
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
825*7c478bd9Sstevel@tonic-gate 	if (debug & PCSMPLDEBUG) {
826*7c478bd9Sstevel@tonic-gate 		printf("[assign_pcsamples] %ld hits in\n", n_hits_in_module);
827*7c478bd9Sstevel@tonic-gate 		printf("                   `%s'\n", module->name);
828*7c478bd9Sstevel@tonic-gate 	}
829*7c478bd9Sstevel@tonic-gate #endif DEBUG
830*7c478bd9Sstevel@tonic-gate }
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate int
833*7c478bd9Sstevel@tonic-gate pc_cmp(Address *pc1, Address *pc2)
834*7c478bd9Sstevel@tonic-gate {
835*7c478bd9Sstevel@tonic-gate 	if (*pc1 > *pc2)
836*7c478bd9Sstevel@tonic-gate 		return (1);
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	if (*pc1 < *pc2)
839*7c478bd9Sstevel@tonic-gate 		return (-1);
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 	return (0);
842*7c478bd9Sstevel@tonic-gate }
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate static void
845*7c478bd9Sstevel@tonic-gate process_pcsamples(bufp)
846*7c478bd9Sstevel@tonic-gate ProfBuffer	*bufp;
847*7c478bd9Sstevel@tonic-gate {
848*7c478bd9Sstevel@tonic-gate 	Address		*pc_samples;
849*7c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
850*7c478bd9Sstevel@tonic-gate 	caddr_t		p;
851*7c478bd9Sstevel@tonic-gate 	size_t		chunk_size, nelem_read, nelem_to_read;
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
854*7c478bd9Sstevel@tonic-gate 	if (debug & PCSMPLDEBUG) {
855*7c478bd9Sstevel@tonic-gate 		printf("[process_pcsamples] number of pcsamples = %lld\n",
856*7c478bd9Sstevel@tonic-gate 							    bufp->bufsize);
857*7c478bd9Sstevel@tonic-gate 	}
858*7c478bd9Sstevel@tonic-gate #endif DEBUG
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	/* buffer with no pc samples ? */
861*7c478bd9Sstevel@tonic-gate 	if (bufp->bufsize == 0)
862*7c478bd9Sstevel@tonic-gate 		return;
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	/*
865*7c478bd9Sstevel@tonic-gate 	 * If we're processing pcsamples of a profile sum, we could have
866*7c478bd9Sstevel@tonic-gate 	 * more than PROF_BUFFER_SIZE number of samples. In such a case,
867*7c478bd9Sstevel@tonic-gate 	 * we must read the pcsamples in chunks.
868*7c478bd9Sstevel@tonic-gate 	 */
869*7c478bd9Sstevel@tonic-gate 	if ((chunk_size = bufp->bufsize) > PROF_BUFFER_SIZE)
870*7c478bd9Sstevel@tonic-gate 		chunk_size = PROF_BUFFER_SIZE;
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 	/* Allocate for the pcsample chunk */
873*7c478bd9Sstevel@tonic-gate 	pc_samples = (Address *) calloc(chunk_size, sizeof (Address));
874*7c478bd9Sstevel@tonic-gate 	if (pc_samples == NULL) {
875*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: no room for %ld sample pc's\n",
876*7c478bd9Sstevel@tonic-gate 							whoami, chunk_size);
877*7c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
878*7c478bd9Sstevel@tonic-gate 	}
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	/* Copy the current set of pcsamples */
881*7c478bd9Sstevel@tonic-gate 	nelem_read = 0;
882*7c478bd9Sstevel@tonic-gate 	nelem_to_read = bufp->bufsize;
883*7c478bd9Sstevel@tonic-gate 	p = (char *) bufp + bufp->buffer;
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	while (nelem_read < nelem_to_read) {
886*7c478bd9Sstevel@tonic-gate 		memcpy((void *) pc_samples, p, chunk_size * sizeof (Address));
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 		/* Sort the pc samples */
889*7c478bd9Sstevel@tonic-gate 		qsort(pc_samples, chunk_size, sizeof (Address),
890*7c478bd9Sstevel@tonic-gate 				(int (*)(const void *, const void *)) pc_cmp);
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 		/*
893*7c478bd9Sstevel@tonic-gate 		 * Assign pcsamples to functions in the currently active
894*7c478bd9Sstevel@tonic-gate 		 * module list
895*7c478bd9Sstevel@tonic-gate 		 */
896*7c478bd9Sstevel@tonic-gate 		for (mi = &modules; mi; mi = mi->next) {
897*7c478bd9Sstevel@tonic-gate 			if (mi->active == FALSE)
898*7c478bd9Sstevel@tonic-gate 				continue;
899*7c478bd9Sstevel@tonic-gate 			assign_pcsamples(mi, pc_samples, chunk_size);
900*7c478bd9Sstevel@tonic-gate 		}
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 		p += (chunk_size * sizeof (Address));
903*7c478bd9Sstevel@tonic-gate 		nelem_read += chunk_size;
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 		if ((nelem_to_read - nelem_read) < chunk_size)
906*7c478bd9Sstevel@tonic-gate 			chunk_size = nelem_to_read - nelem_read;
907*7c478bd9Sstevel@tonic-gate 	}
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 	free(pc_samples);
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 	/* Update total number of pcsamples read so far */
912*7c478bd9Sstevel@tonic-gate 	n_pcsamples += bufp->bufsize;
913*7c478bd9Sstevel@tonic-gate }
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate static mod_info_t *
916*7c478bd9Sstevel@tonic-gate find_module(Address addr)
917*7c478bd9Sstevel@tonic-gate {
918*7c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
921*7c478bd9Sstevel@tonic-gate 		if (mi->active == FALSE)
922*7c478bd9Sstevel@tonic-gate 			continue;
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 		if (addr >= mi->load_base && addr < mi->load_end)
925*7c478bd9Sstevel@tonic-gate 			return (mi);
926*7c478bd9Sstevel@tonic-gate 	}
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	return (NULL);
929*7c478bd9Sstevel@tonic-gate }
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate static void
932*7c478bd9Sstevel@tonic-gate process_cgraph(cgp)
933*7c478bd9Sstevel@tonic-gate ProfCallGraph	*cgp;
934*7c478bd9Sstevel@tonic-gate {
935*7c478bd9Sstevel@tonic-gate 	struct rawarc	arc;
936*7c478bd9Sstevel@tonic-gate 	mod_info_t	*callee_mi, *caller_mi;
937*7c478bd9Sstevel@tonic-gate 	ProfFunction	*calleep, *callerp;
938*7c478bd9Sstevel@tonic-gate 	Index		caller_off, callee_off;
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	/*
941*7c478bd9Sstevel@tonic-gate 	 * Note that *callee_off* increment in the for loop below
942*7c478bd9Sstevel@tonic-gate 	 * uses *calleep* and *calleep* doesn't get set until the for loop
943*7c478bd9Sstevel@tonic-gate 	 * is entered. We don't expect the increment to be executed before
944*7c478bd9Sstevel@tonic-gate 	 * the loop body is executed atleast once, so this should be ok.
945*7c478bd9Sstevel@tonic-gate 	 */
946*7c478bd9Sstevel@tonic-gate 	for (callee_off = cgp->functions; callee_off;
947*7c478bd9Sstevel@tonic-gate 					    callee_off = calleep->next_to) {
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 		calleep = (ProfFunction *) ((char *) cgp + callee_off);
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 		/*
952*7c478bd9Sstevel@tonic-gate 		 * We could choose either to sort the {caller, callee}
953*7c478bd9Sstevel@tonic-gate 		 * list twice and assign callee/caller to modules or inspect
954*7c478bd9Sstevel@tonic-gate 		 * each callee/caller in the active modules list. Since
955*7c478bd9Sstevel@tonic-gate 		 * the modules list is usually very small, we'l choose the
956*7c478bd9Sstevel@tonic-gate 		 * latter.
957*7c478bd9Sstevel@tonic-gate 		 */
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate 		/*
960*7c478bd9Sstevel@tonic-gate 		 * If we cannot identify a callee with a module, there's
961*7c478bd9Sstevel@tonic-gate 		 * no use worrying about who called it.
962*7c478bd9Sstevel@tonic-gate 		 */
963*7c478bd9Sstevel@tonic-gate 		if ((callee_mi = find_module(calleep->topc)) == NULL) {
964*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
965*7c478bd9Sstevel@tonic-gate 			if (debug & CGRAPHDEBUG) {
966*7c478bd9Sstevel@tonic-gate 				printf("[process_cgraph] callee %#llx missed\n",
967*7c478bd9Sstevel@tonic-gate 							    calleep->topc);
968*7c478bd9Sstevel@tonic-gate 			}
969*7c478bd9Sstevel@tonic-gate #endif DEBUG
970*7c478bd9Sstevel@tonic-gate 			continue;
971*7c478bd9Sstevel@tonic-gate 		} else
972*7c478bd9Sstevel@tonic-gate 			arc.raw_selfpc = calleep->topc;
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 		for (caller_off = callee_off; caller_off;
975*7c478bd9Sstevel@tonic-gate 					caller_off = callerp->next_from)  {
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 			callerp = (ProfFunction *) ((char *) cgp + caller_off);
978*7c478bd9Sstevel@tonic-gate 			if ((caller_mi = find_module(callerp->frompc)) ==
979*7c478bd9Sstevel@tonic-gate 									NULL) {
980*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
981*7c478bd9Sstevel@tonic-gate 				if (debug & CGRAPHDEBUG) {
982*7c478bd9Sstevel@tonic-gate 					printf("[process_cgraph] caller %#llx "
983*7c478bd9Sstevel@tonic-gate 						"missed\n", callerp->frompc);
984*7c478bd9Sstevel@tonic-gate 				}
985*7c478bd9Sstevel@tonic-gate #endif DEBUG
986*7c478bd9Sstevel@tonic-gate 				continue;
987*7c478bd9Sstevel@tonic-gate 			}
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 			arc.raw_frompc = callerp->frompc;
990*7c478bd9Sstevel@tonic-gate 			arc.raw_count = callerp->count;
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
993*7c478bd9Sstevel@tonic-gate 			if (debug & CGRAPHDEBUG) {
994*7c478bd9Sstevel@tonic-gate 				printf("[process_cgraph] arc <%#llx, %#llx, "
995*7c478bd9Sstevel@tonic-gate 						"%lld>\n", arc.raw_frompc,
996*7c478bd9Sstevel@tonic-gate 						arc.raw_selfpc, arc.raw_count);
997*7c478bd9Sstevel@tonic-gate 			}
998*7c478bd9Sstevel@tonic-gate #endif DEBUG
999*7c478bd9Sstevel@tonic-gate 			tally(caller_mi, callee_mi, &arc);
1000*7c478bd9Sstevel@tonic-gate 		}
1001*7c478bd9Sstevel@tonic-gate 	}
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1004*7c478bd9Sstevel@tonic-gate 	puts("\n");
1005*7c478bd9Sstevel@tonic-gate #endif DEBUG
1006*7c478bd9Sstevel@tonic-gate }
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate /*
1009*7c478bd9Sstevel@tonic-gate  * Two modules overlap each other if they don't lie completely *outside*
1010*7c478bd9Sstevel@tonic-gate  * each other.
1011*7c478bd9Sstevel@tonic-gate  */
1012*7c478bd9Sstevel@tonic-gate static bool
1013*7c478bd9Sstevel@tonic-gate does_overlap(ProfModule *new, mod_info_t *old)
1014*7c478bd9Sstevel@tonic-gate {
1015*7c478bd9Sstevel@tonic-gate 	/* case 1: new module lies completely *before* the old one */
1016*7c478bd9Sstevel@tonic-gate 	if (new->startaddr < old->load_base && new->endaddr <= old->load_base)
1017*7c478bd9Sstevel@tonic-gate 		return (FALSE);
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate 	/* case 2: new module lies completely *after* the old one */
1020*7c478bd9Sstevel@tonic-gate 	if (new->startaddr >= old->load_end && new->endaddr >= old->load_end)
1021*7c478bd9Sstevel@tonic-gate 		return (FALSE);
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	/* probably a dlopen: the modules overlap each other */
1024*7c478bd9Sstevel@tonic-gate 	return (TRUE);
1025*7c478bd9Sstevel@tonic-gate }
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate static bool
1028*7c478bd9Sstevel@tonic-gate is_same_as_aout(char *modpath, struct stat *buf)
1029*7c478bd9Sstevel@tonic-gate {
1030*7c478bd9Sstevel@tonic-gate 	if (stat(modpath, buf) == -1) {
1031*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: can't get info on `%s'\n",
1032*7c478bd9Sstevel@tonic-gate 							whoami, modpath);
1033*7c478bd9Sstevel@tonic-gate 		exit(EX_NOINPUT);
1034*7c478bd9Sstevel@tonic-gate 	}
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 	if ((buf->st_dev == aout_info.dev) && (buf->st_ino == aout_info.ino))
1037*7c478bd9Sstevel@tonic-gate 		return (TRUE);
1038*7c478bd9Sstevel@tonic-gate 	else
1039*7c478bd9Sstevel@tonic-gate 		return (FALSE);
1040*7c478bd9Sstevel@tonic-gate }
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate static void
1043*7c478bd9Sstevel@tonic-gate process_modules(modlp)
1044*7c478bd9Sstevel@tonic-gate ProfModuleList	*modlp;
1045*7c478bd9Sstevel@tonic-gate {
1046*7c478bd9Sstevel@tonic-gate 	ProfModule	*newmodp;
1047*7c478bd9Sstevel@tonic-gate 	mod_info_t	*mi, *last, *new_module;
1048*7c478bd9Sstevel@tonic-gate 	char		*so_path, *name;
1049*7c478bd9Sstevel@tonic-gate 	bool		more_modules = TRUE;
1050*7c478bd9Sstevel@tonic-gate 	struct stat	so_statbuf;
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1053*7c478bd9Sstevel@tonic-gate 	if (debug & MODULEDEBUG) {
1054*7c478bd9Sstevel@tonic-gate 		printf("[process_modules] module obj version %u\n",
1055*7c478bd9Sstevel@tonic-gate 							    modlp->version);
1056*7c478bd9Sstevel@tonic-gate 	}
1057*7c478bd9Sstevel@tonic-gate #endif DEBUG
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 	/* Check version of module type object */
1060*7c478bd9Sstevel@tonic-gate 	if (modlp->version > PROF_MODULES_VER) {
1061*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: version %d for module type objects"
1062*7c478bd9Sstevel@tonic-gate 				"is not supported\n", whoami, modlp->version);
1063*7c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
1064*7c478bd9Sstevel@tonic-gate 	}
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	/*
1068*7c478bd9Sstevel@tonic-gate 	 * Scan the PROF_MODULES_T list and add modules to current list
1069*7c478bd9Sstevel@tonic-gate 	 * of modules, if they're not present already
1070*7c478bd9Sstevel@tonic-gate 	 */
1071*7c478bd9Sstevel@tonic-gate 	newmodp = (ProfModule *) ((char *) modlp + modlp->modules);
1072*7c478bd9Sstevel@tonic-gate 	do {
1073*7c478bd9Sstevel@tonic-gate 		/*
1074*7c478bd9Sstevel@tonic-gate 		 * Since the prog could've been renamed after its run, we
1075*7c478bd9Sstevel@tonic-gate 		 * should see if this overlaps a.out. If it does, it is
1076*7c478bd9Sstevel@tonic-gate 		 * probably the renamed aout. We should also skip any other
1077*7c478bd9Sstevel@tonic-gate 		 * non-sharedobj's that we see (or should we report an error ?)
1078*7c478bd9Sstevel@tonic-gate 		 */
1079*7c478bd9Sstevel@tonic-gate 		so_path = (caddr_t) modlp + newmodp->path;
1080*7c478bd9Sstevel@tonic-gate 		if (does_overlap(newmodp, &modules) ||
1081*7c478bd9Sstevel@tonic-gate 				    is_same_as_aout(so_path, &so_statbuf) ||
1082*7c478bd9Sstevel@tonic-gate 						(!is_shared_obj(so_path))) {
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 			if (!newmodp->next)
1085*7c478bd9Sstevel@tonic-gate 				more_modules = FALSE;
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 			newmodp = (ProfModule *)
1088*7c478bd9Sstevel@tonic-gate 					((caddr_t) modlp + newmodp->next);
1089*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1090*7c478bd9Sstevel@tonic-gate 			if (debug & MODULEDEBUG) {
1091*7c478bd9Sstevel@tonic-gate 				printf("[process_modules] `%s'\n", so_path);
1092*7c478bd9Sstevel@tonic-gate 				printf("                  skipped\n");
1093*7c478bd9Sstevel@tonic-gate 			}
1094*7c478bd9Sstevel@tonic-gate #endif DEBUG
1095*7c478bd9Sstevel@tonic-gate 			continue;
1096*7c478bd9Sstevel@tonic-gate 		}
1097*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1098*7c478bd9Sstevel@tonic-gate 		if (debug & MODULEDEBUG)
1099*7c478bd9Sstevel@tonic-gate 			printf("[process_modules] `%s'...\n", so_path);
1100*7c478bd9Sstevel@tonic-gate #endif DEBUG
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 		/*
1103*7c478bd9Sstevel@tonic-gate 		 * Check all modules (leave the first one, 'cos that
1104*7c478bd9Sstevel@tonic-gate 		 * is the program executable info). If this module is already
1105*7c478bd9Sstevel@tonic-gate 		 * there in the list, update the load addresses and proceed.
1106*7c478bd9Sstevel@tonic-gate 		 */
1107*7c478bd9Sstevel@tonic-gate 		last = &modules;
1108*7c478bd9Sstevel@tonic-gate 		while (mi = last->next) {
1109*7c478bd9Sstevel@tonic-gate 			/*
1110*7c478bd9Sstevel@tonic-gate 			 * We expect the full pathname for all shared objects
1111*7c478bd9Sstevel@tonic-gate 			 * needed by the program executable. In this case, we
1112*7c478bd9Sstevel@tonic-gate 			 * simply need to compare the paths to see if they are
1113*7c478bd9Sstevel@tonic-gate 			 * the same file.
1114*7c478bd9Sstevel@tonic-gate 			 */
1115*7c478bd9Sstevel@tonic-gate 			if (strcmp(mi->name, so_path) == 0)
1116*7c478bd9Sstevel@tonic-gate 				break;
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 			/*
1119*7c478bd9Sstevel@tonic-gate 			 * Check if this new shared object will overlap
1120*7c478bd9Sstevel@tonic-gate 			 * any existing module. If yes, remove the old one
1121*7c478bd9Sstevel@tonic-gate 			 * from the linked list (but don't free it, 'cos
1122*7c478bd9Sstevel@tonic-gate 			 * there may be symbols referring to this module
1123*7c478bd9Sstevel@tonic-gate 			 * still)
1124*7c478bd9Sstevel@tonic-gate 			 */
1125*7c478bd9Sstevel@tonic-gate 			if (does_overlap(newmodp, mi)) {
1126*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1127*7c478bd9Sstevel@tonic-gate 				if (debug & MODULEDEBUG) {
1128*7c478bd9Sstevel@tonic-gate 					printf("[process_modules] `%s'\n",
1129*7c478bd9Sstevel@tonic-gate 								    so_path);
1130*7c478bd9Sstevel@tonic-gate 					printf("                  overlaps\n");
1131*7c478bd9Sstevel@tonic-gate 					printf("                  `%s'\n",
1132*7c478bd9Sstevel@tonic-gate 								    mi->name);
1133*7c478bd9Sstevel@tonic-gate 				}
1134*7c478bd9Sstevel@tonic-gate #endif DEBUG
1135*7c478bd9Sstevel@tonic-gate 				mi->active = FALSE;
1136*7c478bd9Sstevel@tonic-gate 			}
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate 			last = mi;
1139*7c478bd9Sstevel@tonic-gate 		}
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate 		/* Module already there, skip it */
1142*7c478bd9Sstevel@tonic-gate 		if (mi != NULL) {
1143*7c478bd9Sstevel@tonic-gate 			mi->load_base = newmodp->startaddr;
1144*7c478bd9Sstevel@tonic-gate 			mi->load_end = newmodp->endaddr;
1145*7c478bd9Sstevel@tonic-gate 			mi->active = TRUE;
1146*7c478bd9Sstevel@tonic-gate 			if (!newmodp->next)
1147*7c478bd9Sstevel@tonic-gate 				more_modules = FALSE;
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 			newmodp = (ProfModule *)
1150*7c478bd9Sstevel@tonic-gate 					((caddr_t) modlp + newmodp->next);
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1153*7c478bd9Sstevel@tonic-gate 			if (debug & MODULEDEBUG) {
1154*7c478bd9Sstevel@tonic-gate 				printf("[process_modules] base=%#llx, "
1155*7c478bd9Sstevel@tonic-gate 						"end=%#llx\n", mi->load_base,
1156*7c478bd9Sstevel@tonic-gate 						mi->load_end);
1157*7c478bd9Sstevel@tonic-gate 			}
1158*7c478bd9Sstevel@tonic-gate #endif DEBUG
1159*7c478bd9Sstevel@tonic-gate 			continue;
1160*7c478bd9Sstevel@tonic-gate 		}
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 		/*
1163*7c478bd9Sstevel@tonic-gate 		 * Check if gmon.out is outdated with respect to the new
1164*7c478bd9Sstevel@tonic-gate 		 * module we want to add
1165*7c478bd9Sstevel@tonic-gate 		 */
1166*7c478bd9Sstevel@tonic-gate 		if (gmonout_info.mtime < so_statbuf.st_mtime) {
1167*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: shared obj outdates prof info\n",
1168*7c478bd9Sstevel@tonic-gate 								    whoami);
1169*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "\t(newer %s)\n", so_path);
1170*7c478bd9Sstevel@tonic-gate 			exit(EX_NOINPUT);
1171*7c478bd9Sstevel@tonic-gate 		}
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 		/* Create a new module element */
1174*7c478bd9Sstevel@tonic-gate 		new_module = (mod_info_t *) malloc(sizeof (mod_info_t));
1175*7c478bd9Sstevel@tonic-gate 		if (new_module == NULL) {
1176*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: no room for %ld bytes\n",
1177*7c478bd9Sstevel@tonic-gate 						whoami, sizeof (mod_info_t));
1178*7c478bd9Sstevel@tonic-gate 			exit(EX_OSERR);
1179*7c478bd9Sstevel@tonic-gate 		}
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 		/* and fill in info... */
1182*7c478bd9Sstevel@tonic-gate 		new_module->id = n_modules + 1;
1183*7c478bd9Sstevel@tonic-gate 		new_module->load_base = newmodp->startaddr;
1184*7c478bd9Sstevel@tonic-gate 		new_module->load_end = newmodp->endaddr;
1185*7c478bd9Sstevel@tonic-gate 		new_module->name = (char *) malloc(strlen(so_path) + 1);
1186*7c478bd9Sstevel@tonic-gate 		if (new_module->name == NULL) {
1187*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: no room for %ld bytes\n",
1188*7c478bd9Sstevel@tonic-gate 						whoami, strlen(so_path) + 1);
1189*7c478bd9Sstevel@tonic-gate 			exit(EX_OSERR);
1190*7c478bd9Sstevel@tonic-gate 		}
1191*7c478bd9Sstevel@tonic-gate 		strcpy(new_module->name, so_path);
1192*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1193*7c478bd9Sstevel@tonic-gate 		if (debug & MODULEDEBUG) {
1194*7c478bd9Sstevel@tonic-gate 			printf("[process_modules] base=%#llx, end=%#llx\n",
1195*7c478bd9Sstevel@tonic-gate 				new_module->load_base, new_module->load_end);
1196*7c478bd9Sstevel@tonic-gate 		}
1197*7c478bd9Sstevel@tonic-gate #endif DEBUG
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 		/* Create this module's nameslist */
1200*7c478bd9Sstevel@tonic-gate 		process_namelist(new_module);
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 		/* Add it to the tail of active module list */
1203*7c478bd9Sstevel@tonic-gate 		last->next = new_module;
1204*7c478bd9Sstevel@tonic-gate 		n_modules++;
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1207*7c478bd9Sstevel@tonic-gate 		if (debug & MODULEDEBUG) {
1208*7c478bd9Sstevel@tonic-gate 			printf("[process_modules] total shared objects = %ld\n",
1209*7c478bd9Sstevel@tonic-gate 							    n_modules - 1);
1210*7c478bd9Sstevel@tonic-gate 		}
1211*7c478bd9Sstevel@tonic-gate #endif DEBUG
1212*7c478bd9Sstevel@tonic-gate 		/*
1213*7c478bd9Sstevel@tonic-gate 		 * Move to the next module in the PROF_MODULES_T list
1214*7c478bd9Sstevel@tonic-gate 		 * (if present)
1215*7c478bd9Sstevel@tonic-gate 		 */
1216*7c478bd9Sstevel@tonic-gate 		if (!newmodp->next)
1217*7c478bd9Sstevel@tonic-gate 			more_modules = FALSE;
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 		newmodp = (ProfModule *) ((caddr_t) modlp + newmodp->next);
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 	} while (more_modules);
1222*7c478bd9Sstevel@tonic-gate }
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate static void
1225*7c478bd9Sstevel@tonic-gate reset_active_modules()
1226*7c478bd9Sstevel@tonic-gate {
1227*7c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate 	/* Except the executable, no other module should remain active */
1230*7c478bd9Sstevel@tonic-gate 	for (mi = modules.next; mi; mi = mi->next)
1231*7c478bd9Sstevel@tonic-gate 		mi->active = FALSE;
1232*7c478bd9Sstevel@tonic-gate }
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate static void
1235*7c478bd9Sstevel@tonic-gate getpfiledata(memp, fsz)
1236*7c478bd9Sstevel@tonic-gate caddr_t	memp;
1237*7c478bd9Sstevel@tonic-gate size_t	fsz;
1238*7c478bd9Sstevel@tonic-gate {
1239*7c478bd9Sstevel@tonic-gate 	ProfObject	*objp;
1240*7c478bd9Sstevel@tonic-gate 	caddr_t		file_end;
1241*7c478bd9Sstevel@tonic-gate 	bool		found_pcsamples = FALSE, found_cgraph = FALSE;
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	/*
1244*7c478bd9Sstevel@tonic-gate 	 * Before processing a new gmon.out, all modules except the
1245*7c478bd9Sstevel@tonic-gate 	 * program executable must be made inactive, so that symbols
1246*7c478bd9Sstevel@tonic-gate 	 * are searched only in the program executable, if we don't
1247*7c478bd9Sstevel@tonic-gate 	 * find a MODULES_T object. Don't do it *after* we read a gmon.out,
1248*7c478bd9Sstevel@tonic-gate 	 * because we need the active module data after we're done with
1249*7c478bd9Sstevel@tonic-gate 	 * the last gmon.out, if we're doing summing.
1250*7c478bd9Sstevel@tonic-gate 	 */
1251*7c478bd9Sstevel@tonic-gate 	reset_active_modules();
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 	file_end = memp + fsz;
1254*7c478bd9Sstevel@tonic-gate 	objp = (ProfObject *) (memp + ((ProfHeader *) memp)->size);
1255*7c478bd9Sstevel@tonic-gate 	while ((caddr_t) objp < file_end) {
1256*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1257*7c478bd9Sstevel@tonic-gate 		{
1258*7c478bd9Sstevel@tonic-gate 			unsigned int	type = 0;
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 			if (debug & MONOUTDEBUG) {
1261*7c478bd9Sstevel@tonic-gate 				if (objp->type <= MAX_OBJTYPES)
1262*7c478bd9Sstevel@tonic-gate 					type = objp->type;
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 				printf("\n[getpfiledata] object %s [%#lx]\n",
1265*7c478bd9Sstevel@tonic-gate 						objname[type], objp->type);
1266*7c478bd9Sstevel@tonic-gate 			}
1267*7c478bd9Sstevel@tonic-gate 		}
1268*7c478bd9Sstevel@tonic-gate #endif DEBUG
1269*7c478bd9Sstevel@tonic-gate 		switch (objp->type) {
1270*7c478bd9Sstevel@tonic-gate 			case PROF_MODULES_T :
1271*7c478bd9Sstevel@tonic-gate 				process_modules((ProfModuleList *) objp);
1272*7c478bd9Sstevel@tonic-gate 				break;
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 			case PROF_CALLGRAPH_T :
1275*7c478bd9Sstevel@tonic-gate 				process_cgraph((ProfCallGraph *) objp);
1276*7c478bd9Sstevel@tonic-gate 				found_cgraph = TRUE;
1277*7c478bd9Sstevel@tonic-gate 				break;
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 			case PROF_BUFFER_T :
1280*7c478bd9Sstevel@tonic-gate 				process_pcsamples((ProfBuffer *) objp);
1281*7c478bd9Sstevel@tonic-gate 				found_pcsamples = TRUE;
1282*7c478bd9Sstevel@tonic-gate 				break;
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate 			default :
1285*7c478bd9Sstevel@tonic-gate 				fprintf(stderr,
1286*7c478bd9Sstevel@tonic-gate 					"%s: unknown prof object type=%d\n",
1287*7c478bd9Sstevel@tonic-gate 							whoami, objp->type);
1288*7c478bd9Sstevel@tonic-gate 				exit(EX_SOFTWARE);
1289*7c478bd9Sstevel@tonic-gate 		}
1290*7c478bd9Sstevel@tonic-gate 		objp = (ProfObject *) ((caddr_t) objp + objp->size);
1291*7c478bd9Sstevel@tonic-gate 	}
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate 	if (!found_cgraph || !found_pcsamples) {
1294*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
1295*7c478bd9Sstevel@tonic-gate 			"%s: missing callgraph/pcsamples object\n", whoami);
1296*7c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
1297*7c478bd9Sstevel@tonic-gate 	}
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 	if ((caddr_t) objp > file_end) {
1300*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: malformed profile file.\n", whoami);
1301*7c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
1302*7c478bd9Sstevel@tonic-gate 	}
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate 	if (first_file)
1305*7c478bd9Sstevel@tonic-gate 		first_file = FALSE;
1306*7c478bd9Sstevel@tonic-gate }
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate static void
1309*7c478bd9Sstevel@tonic-gate readarcs(pfile)
1310*7c478bd9Sstevel@tonic-gate FILE	*pfile;
1311*7c478bd9Sstevel@tonic-gate {
1312*7c478bd9Sstevel@tonic-gate 	/*
1313*7c478bd9Sstevel@tonic-gate 	 *	the rest of the file consists of
1314*7c478bd9Sstevel@tonic-gate 	 *	a bunch of <from,self,count> tuples.
1315*7c478bd9Sstevel@tonic-gate 	 */
1316*7c478bd9Sstevel@tonic-gate 	/* CONSTCOND */
1317*7c478bd9Sstevel@tonic-gate 	while (1) {
1318*7c478bd9Sstevel@tonic-gate 		struct rawarc	arc;
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate 		if (rflag) {
1321*7c478bd9Sstevel@tonic-gate 			if (Bflag) {
1322*7c478bd9Sstevel@tonic-gate 				L_cgarc64		rtld_arc64;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 				/*
1325*7c478bd9Sstevel@tonic-gate 				 * If rflag is set then this is an profiled
1326*7c478bd9Sstevel@tonic-gate 				 * image generated by rtld.  It needs to be
1327*7c478bd9Sstevel@tonic-gate 				 * 'converted' to the standard data format.
1328*7c478bd9Sstevel@tonic-gate 				 */
1329*7c478bd9Sstevel@tonic-gate 				if (fread(&rtld_arc64,
1330*7c478bd9Sstevel@tonic-gate 					    sizeof (L_cgarc64), 1, pfile) != 1)
1331*7c478bd9Sstevel@tonic-gate 					break;
1332*7c478bd9Sstevel@tonic-gate 
1333*7c478bd9Sstevel@tonic-gate 				if (rtld_arc64.cg_from == PRF_OUTADDR64)
1334*7c478bd9Sstevel@tonic-gate 					arc.raw_frompc = s_highpc + 0x10;
1335*7c478bd9Sstevel@tonic-gate 				else
1336*7c478bd9Sstevel@tonic-gate 					arc.raw_frompc =
1337*7c478bd9Sstevel@tonic-gate 					    (pctype)rtld_arc64.cg_from;
1338*7c478bd9Sstevel@tonic-gate 				arc.raw_selfpc = (pctype)rtld_arc64.cg_to;
1339*7c478bd9Sstevel@tonic-gate 				arc.raw_count = (actype)rtld_arc64.cg_count;
1340*7c478bd9Sstevel@tonic-gate 			} else {
1341*7c478bd9Sstevel@tonic-gate 				L_cgarc		rtld_arc;
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate 				/*
1344*7c478bd9Sstevel@tonic-gate 				 * If rflag is set then this is an profiled
1345*7c478bd9Sstevel@tonic-gate 				 * image generated by rtld.  It needs to be
1346*7c478bd9Sstevel@tonic-gate 				 * 'converted' to the standard data format.
1347*7c478bd9Sstevel@tonic-gate 				 */
1348*7c478bd9Sstevel@tonic-gate 				if (fread(&rtld_arc,
1349*7c478bd9Sstevel@tonic-gate 					    sizeof (L_cgarc), 1, pfile) != 1)
1350*7c478bd9Sstevel@tonic-gate 					break;
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate 				if (rtld_arc.cg_from == PRF_OUTADDR)
1353*7c478bd9Sstevel@tonic-gate 					arc.raw_frompc = s_highpc + 0x10;
1354*7c478bd9Sstevel@tonic-gate 				else
1355*7c478bd9Sstevel@tonic-gate 					arc.raw_frompc = (pctype)
1356*7c478bd9Sstevel@tonic-gate 					    (uintptr_t)rtld_arc.cg_from;
1357*7c478bd9Sstevel@tonic-gate 				arc.raw_selfpc = (pctype)
1358*7c478bd9Sstevel@tonic-gate 				    (uintptr_t)rtld_arc.cg_to;
1359*7c478bd9Sstevel@tonic-gate 				arc.raw_count = (actype)rtld_arc.cg_count;
1360*7c478bd9Sstevel@tonic-gate 			}
1361*7c478bd9Sstevel@tonic-gate 		} else {
1362*7c478bd9Sstevel@tonic-gate 			if (Bflag) {
1363*7c478bd9Sstevel@tonic-gate 				if (fread(&arc, sizeof (struct rawarc), 1,
1364*7c478bd9Sstevel@tonic-gate 				    pfile) != 1) {
1365*7c478bd9Sstevel@tonic-gate 					break;
1366*7c478bd9Sstevel@tonic-gate 				}
1367*7c478bd9Sstevel@tonic-gate 			} else {
1368*7c478bd9Sstevel@tonic-gate 				/*
1369*7c478bd9Sstevel@tonic-gate 				 * If these aren't big %pc's, we need to read
1370*7c478bd9Sstevel@tonic-gate 				 * into the 32-bit raw arc structure, and
1371*7c478bd9Sstevel@tonic-gate 				 * assign the members into the actual arc.
1372*7c478bd9Sstevel@tonic-gate 				 */
1373*7c478bd9Sstevel@tonic-gate 				struct rawarc32 arc32;
1374*7c478bd9Sstevel@tonic-gate 				if (fread(&arc32, sizeof (struct rawarc32),
1375*7c478bd9Sstevel@tonic-gate 				    1, pfile) != 1)
1376*7c478bd9Sstevel@tonic-gate 					break;
1377*7c478bd9Sstevel@tonic-gate 				arc.raw_frompc = (pctype)arc32.raw_frompc;
1378*7c478bd9Sstevel@tonic-gate 				arc.raw_selfpc = (pctype)arc32.raw_selfpc;
1379*7c478bd9Sstevel@tonic-gate 				arc.raw_count  = (actype)arc32.raw_count;
1380*7c478bd9Sstevel@tonic-gate 			}
1381*7c478bd9Sstevel@tonic-gate 		}
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1384*7c478bd9Sstevel@tonic-gate 		if (debug & SAMPLEDEBUG) {
1385*7c478bd9Sstevel@tonic-gate 			printf("[getpfile] frompc 0x%llx selfpc "
1386*7c478bd9Sstevel@tonic-gate 			    "0x%llx count %lld\n", arc.raw_frompc,
1387*7c478bd9Sstevel@tonic-gate 			    arc.raw_selfpc, arc.raw_count);
1388*7c478bd9Sstevel@tonic-gate 		}
1389*7c478bd9Sstevel@tonic-gate #endif DEBUG
1390*7c478bd9Sstevel@tonic-gate 		/*
1391*7c478bd9Sstevel@tonic-gate 		 *	add this arc
1392*7c478bd9Sstevel@tonic-gate 		 */
1393*7c478bd9Sstevel@tonic-gate 		tally(&modules, &modules, &arc);
1394*7c478bd9Sstevel@tonic-gate 	}
1395*7c478bd9Sstevel@tonic-gate 	if (first_file)
1396*7c478bd9Sstevel@tonic-gate 		first_file = FALSE;
1397*7c478bd9Sstevel@tonic-gate }
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate static void
1400*7c478bd9Sstevel@tonic-gate readsamples(FILE *pfile)
1401*7c478bd9Sstevel@tonic-gate {
1402*7c478bd9Sstevel@tonic-gate 	sztype		i;
1403*7c478bd9Sstevel@tonic-gate 	unsigned_UNIT	sample;
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate 	if (samples == 0) {
1406*7c478bd9Sstevel@tonic-gate 		samples = (unsigned_UNIT *) calloc(nsamples,
1407*7c478bd9Sstevel@tonic-gate 		    sizeof (unsigned_UNIT));
1408*7c478bd9Sstevel@tonic-gate 		if (samples == 0) {
1409*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: No room for %ld sample pc's\n",
1410*7c478bd9Sstevel@tonic-gate 			    whoami, sampbytes / sizeof (unsigned_UNIT));
1411*7c478bd9Sstevel@tonic-gate 			exit(EX_OSERR);
1412*7c478bd9Sstevel@tonic-gate 		}
1413*7c478bd9Sstevel@tonic-gate 	}
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nsamples; i++) {
1416*7c478bd9Sstevel@tonic-gate 		fread(&sample, sizeof (unsigned_UNIT), 1, pfile);
1417*7c478bd9Sstevel@tonic-gate 		if (feof(pfile))
1418*7c478bd9Sstevel@tonic-gate 			break;
1419*7c478bd9Sstevel@tonic-gate 		samples[i] += sample;
1420*7c478bd9Sstevel@tonic-gate 	}
1421*7c478bd9Sstevel@tonic-gate 	if (i != nsamples) {
1422*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
1423*7c478bd9Sstevel@tonic-gate 		    "%s: unexpected EOF after reading %ld/%ld samples\n",
1424*7c478bd9Sstevel@tonic-gate 		    whoami, --i, nsamples);
1425*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
1426*7c478bd9Sstevel@tonic-gate 	}
1427*7c478bd9Sstevel@tonic-gate }
1428*7c478bd9Sstevel@tonic-gate 
1429*7c478bd9Sstevel@tonic-gate static void *
1430*7c478bd9Sstevel@tonic-gate handle_versioned(FILE *pfile, char *filename, size_t *fsz)
1431*7c478bd9Sstevel@tonic-gate {
1432*7c478bd9Sstevel@tonic-gate 	int		fd;
1433*7c478bd9Sstevel@tonic-gate 	bool		invalid_version;
1434*7c478bd9Sstevel@tonic-gate 	caddr_t		fmem;
1435*7c478bd9Sstevel@tonic-gate 	struct stat	buf;
1436*7c478bd9Sstevel@tonic-gate 	ProfHeader	prof_hdr;
1437*7c478bd9Sstevel@tonic-gate 
1438*7c478bd9Sstevel@tonic-gate 	/*
1439*7c478bd9Sstevel@tonic-gate 	 * Check versioning info. For now, let's say we provide
1440*7c478bd9Sstevel@tonic-gate 	 * backward compatibility, so we accept all older versions.
1441*7c478bd9Sstevel@tonic-gate 	 */
1442*7c478bd9Sstevel@tonic-gate 	if (fread(&prof_hdr, sizeof (ProfHeader), 1, pfile) == 0) {
1443*7c478bd9Sstevel@tonic-gate 		perror("fread()");
1444*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
1445*7c478bd9Sstevel@tonic-gate 	}
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	invalid_version = FALSE;
1448*7c478bd9Sstevel@tonic-gate 	if (prof_hdr.h_major_ver > PROF_MAJOR_VERSION)
1449*7c478bd9Sstevel@tonic-gate 		invalid_version = TRUE;
1450*7c478bd9Sstevel@tonic-gate 	else if (prof_hdr.h_major_ver == PROF_MAJOR_VERSION) {
1451*7c478bd9Sstevel@tonic-gate 		if (prof_hdr.h_minor_ver > PROF_MINOR_VERSION)
1452*7c478bd9Sstevel@tonic-gate 			invalid_version = FALSE;
1453*7c478bd9Sstevel@tonic-gate 	}
1454*7c478bd9Sstevel@tonic-gate 
1455*7c478bd9Sstevel@tonic-gate 	if (invalid_version) {
1456*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: version %d.%d not supported\n",
1457*7c478bd9Sstevel@tonic-gate 			whoami, prof_hdr.h_major_ver, prof_hdr.h_minor_ver);
1458*7c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
1459*7c478bd9Sstevel@tonic-gate 	}
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 	/*
1462*7c478bd9Sstevel@tonic-gate 	 * Map gmon.out onto memory.
1463*7c478bd9Sstevel@tonic-gate 	 */
1464*7c478bd9Sstevel@tonic-gate 	fclose(pfile);
1465*7c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1) {
1466*7c478bd9Sstevel@tonic-gate 		perror(filename);
1467*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
1468*7c478bd9Sstevel@tonic-gate 	}
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate 	if ((*fsz = lseek(fd, 0, SEEK_END)) == -1) {
1471*7c478bd9Sstevel@tonic-gate 		perror(filename);
1472*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
1473*7c478bd9Sstevel@tonic-gate 	}
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate 	fmem = mmap(0, *fsz, PROT_READ, MAP_PRIVATE, fd, 0);
1476*7c478bd9Sstevel@tonic-gate 	if (fmem == MAP_FAILED) {
1477*7c478bd9Sstevel@tonic-gate 	    fprintf(stderr, "%s: can't map %s\n", whoami, filename);
1478*7c478bd9Sstevel@tonic-gate 	    exit(EX_IOERR);
1479*7c478bd9Sstevel@tonic-gate 	}
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate 	/*
1482*7c478bd9Sstevel@tonic-gate 	 * Before we close this fd, save this gmon.out's info to later verify
1483*7c478bd9Sstevel@tonic-gate 	 * if the shared objects it references have changed since the time
1484*7c478bd9Sstevel@tonic-gate 	 * they were used to generate this gmon.out
1485*7c478bd9Sstevel@tonic-gate 	 */
1486*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &buf) == -1) {
1487*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: can't get info on `%s'\n",
1488*7c478bd9Sstevel@tonic-gate 							whoami, filename);
1489*7c478bd9Sstevel@tonic-gate 		exit(EX_NOINPUT);
1490*7c478bd9Sstevel@tonic-gate 	}
1491*7c478bd9Sstevel@tonic-gate 	gmonout_info.dev = buf.st_dev;
1492*7c478bd9Sstevel@tonic-gate 	gmonout_info.ino = buf.st_ino;
1493*7c478bd9Sstevel@tonic-gate 	gmonout_info.mtime = buf.st_mtime;
1494*7c478bd9Sstevel@tonic-gate 	gmonout_info.size = buf.st_size;
1495*7c478bd9Sstevel@tonic-gate 
1496*7c478bd9Sstevel@tonic-gate 	close(fd);
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 	return ((void *) fmem);
1499*7c478bd9Sstevel@tonic-gate }
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate static void *
1502*7c478bd9Sstevel@tonic-gate openpfile(filename, fsz)
1503*7c478bd9Sstevel@tonic-gate char	*filename;
1504*7c478bd9Sstevel@tonic-gate size_t	*fsz;
1505*7c478bd9Sstevel@tonic-gate {
1506*7c478bd9Sstevel@tonic-gate 	struct hdr	tmp;
1507*7c478bd9Sstevel@tonic-gate 	FILE *		pfile;
1508*7c478bd9Sstevel@tonic-gate 	unsigned long	magic_num;
1509*7c478bd9Sstevel@tonic-gate 	size_t		hdrsize = sizeof (struct hdr);
1510*7c478bd9Sstevel@tonic-gate 	static bool	first_time = TRUE;
1511*7c478bd9Sstevel@tonic-gate 	extern bool	old_style;
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate 	if ((pfile = fopen(filename, "r")) == NULL) {
1514*7c478bd9Sstevel@tonic-gate 		perror(filename);
1515*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
1516*7c478bd9Sstevel@tonic-gate 	}
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 	/*
1519*7c478bd9Sstevel@tonic-gate 	 * Read in the magic. Note that we changed the cast "unsigned long"
1520*7c478bd9Sstevel@tonic-gate 	 * to "unsigned int" because that's how h_magic is defined in the
1521*7c478bd9Sstevel@tonic-gate 	 * new format ProfHeader.
1522*7c478bd9Sstevel@tonic-gate 	 */
1523*7c478bd9Sstevel@tonic-gate 	if (fread(&magic_num, sizeof (unsigned int), 1, pfile) == 0) {
1524*7c478bd9Sstevel@tonic-gate 		perror("fread()");
1525*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
1526*7c478bd9Sstevel@tonic-gate 	}
1527*7c478bd9Sstevel@tonic-gate 
1528*7c478bd9Sstevel@tonic-gate 	rewind(pfile);
1529*7c478bd9Sstevel@tonic-gate 
1530*7c478bd9Sstevel@tonic-gate 	/*
1531*7c478bd9Sstevel@tonic-gate 	 * First check if this is versioned or *old-style* gmon.out
1532*7c478bd9Sstevel@tonic-gate 	 */
1533*7c478bd9Sstevel@tonic-gate 	if (magic_num == (unsigned int)PROF_MAGIC) {
1534*7c478bd9Sstevel@tonic-gate 		if ((!first_time) && (old_style == TRUE)) {
1535*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: can't mix old & new format "
1536*7c478bd9Sstevel@tonic-gate 						"profiled files\n", whoami);
1537*7c478bd9Sstevel@tonic-gate 			exit(EX_SOFTWARE);
1538*7c478bd9Sstevel@tonic-gate 		}
1539*7c478bd9Sstevel@tonic-gate 		first_time = FALSE;
1540*7c478bd9Sstevel@tonic-gate 		old_style = FALSE;
1541*7c478bd9Sstevel@tonic-gate 		return (handle_versioned(pfile, filename, fsz));
1542*7c478bd9Sstevel@tonic-gate 	}
1543*7c478bd9Sstevel@tonic-gate 
1544*7c478bd9Sstevel@tonic-gate 	if ((!first_time) && (old_style == FALSE)) {
1545*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: can't mix old & new format "
1546*7c478bd9Sstevel@tonic-gate 						"profiled files\n", whoami);
1547*7c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
1548*7c478bd9Sstevel@tonic-gate 	}
1549*7c478bd9Sstevel@tonic-gate 
1550*7c478bd9Sstevel@tonic-gate 	first_time = FALSE;
1551*7c478bd9Sstevel@tonic-gate 	old_style = TRUE;
1552*7c478bd9Sstevel@tonic-gate 	fsz = 0;
1553*7c478bd9Sstevel@tonic-gate 
1554*7c478bd9Sstevel@tonic-gate 	/*
1555*7c478bd9Sstevel@tonic-gate 	 * Now, we need to determine if this is a run-time linker
1556*7c478bd9Sstevel@tonic-gate 	 * profiled file or if it is a standard gmon.out.
1557*7c478bd9Sstevel@tonic-gate 	 *
1558*7c478bd9Sstevel@tonic-gate 	 * We do this by checking if magic matches PRF_MAGIC. If it
1559*7c478bd9Sstevel@tonic-gate 	 * does, then this is a run-time linker profiled file, if it
1560*7c478bd9Sstevel@tonic-gate 	 * doesn't, it must be a gmon.out file.
1561*7c478bd9Sstevel@tonic-gate 	 */
1562*7c478bd9Sstevel@tonic-gate 	if (magic_num == (unsigned long)PRF_MAGIC)
1563*7c478bd9Sstevel@tonic-gate 		rflag = TRUE;
1564*7c478bd9Sstevel@tonic-gate 	else
1565*7c478bd9Sstevel@tonic-gate 		rflag = FALSE;
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate 	if (rflag) {
1568*7c478bd9Sstevel@tonic-gate 		if (Bflag) {
1569*7c478bd9Sstevel@tonic-gate 			L_hdr64		l_hdr64;
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate 			/*
1572*7c478bd9Sstevel@tonic-gate 			 * If the rflag is set then the input file is
1573*7c478bd9Sstevel@tonic-gate 			 * rtld profiled data, we'll read it in and convert
1574*7c478bd9Sstevel@tonic-gate 			 * it to the standard format (ie: make it look like
1575*7c478bd9Sstevel@tonic-gate 			 * a gmon.out file).
1576*7c478bd9Sstevel@tonic-gate 			 */
1577*7c478bd9Sstevel@tonic-gate 			if (fread(&l_hdr64, sizeof (L_hdr64), 1, pfile) == 0) {
1578*7c478bd9Sstevel@tonic-gate 				perror("fread()");
1579*7c478bd9Sstevel@tonic-gate 				exit(EX_IOERR);
1580*7c478bd9Sstevel@tonic-gate 			}
1581*7c478bd9Sstevel@tonic-gate 			if (l_hdr64.hd_version != PRF_VERSION_64) {
1582*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "%s: expected version %d, "
1583*7c478bd9Sstevel@tonic-gate 				    "got version %d when processing 64-bit "
1584*7c478bd9Sstevel@tonic-gate 				    "run-time linker profiled file.\n",
1585*7c478bd9Sstevel@tonic-gate 				    whoami, PRF_VERSION_64, l_hdr64.hd_version);
1586*7c478bd9Sstevel@tonic-gate 				exit(EX_SOFTWARE);
1587*7c478bd9Sstevel@tonic-gate 			}
1588*7c478bd9Sstevel@tonic-gate 			tmp.lowpc = 0;
1589*7c478bd9Sstevel@tonic-gate 			tmp.highpc = (pctype)l_hdr64.hd_hpc;
1590*7c478bd9Sstevel@tonic-gate 			tmp.ncnt = sizeof (M_hdr64) + l_hdr64.hd_psize;
1591*7c478bd9Sstevel@tonic-gate 		} else {
1592*7c478bd9Sstevel@tonic-gate 			L_hdr		l_hdr;
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 			/*
1595*7c478bd9Sstevel@tonic-gate 			 * If the rflag is set then the input file is
1596*7c478bd9Sstevel@tonic-gate 			 * rtld profiled data, we'll read it in and convert
1597*7c478bd9Sstevel@tonic-gate 			 * it to the standard format (ie: make it look like
1598*7c478bd9Sstevel@tonic-gate 			 * a gmon.out file).
1599*7c478bd9Sstevel@tonic-gate 			 */
1600*7c478bd9Sstevel@tonic-gate 			if (fread(&l_hdr, sizeof (L_hdr), 1, pfile) == 0) {
1601*7c478bd9Sstevel@tonic-gate 				perror("fread()");
1602*7c478bd9Sstevel@tonic-gate 				exit(EX_IOERR);
1603*7c478bd9Sstevel@tonic-gate 			}
1604*7c478bd9Sstevel@tonic-gate 			if (l_hdr.hd_version != PRF_VERSION) {
1605*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "%s: expected version %d, "
1606*7c478bd9Sstevel@tonic-gate 				    "got version %d when processing "
1607*7c478bd9Sstevel@tonic-gate 				    "run-time linker profiled file.\n",
1608*7c478bd9Sstevel@tonic-gate 				    whoami, PRF_VERSION, l_hdr.hd_version);
1609*7c478bd9Sstevel@tonic-gate 				exit(EX_SOFTWARE);
1610*7c478bd9Sstevel@tonic-gate 			}
1611*7c478bd9Sstevel@tonic-gate 			tmp.lowpc = 0;
1612*7c478bd9Sstevel@tonic-gate 			tmp.highpc = (pctype)(uintptr_t)l_hdr.hd_hpc;
1613*7c478bd9Sstevel@tonic-gate 			tmp.ncnt = sizeof (M_hdr) + l_hdr.hd_psize;
1614*7c478bd9Sstevel@tonic-gate 			hdrsize = sizeof (M_hdr);
1615*7c478bd9Sstevel@tonic-gate 		}
1616*7c478bd9Sstevel@tonic-gate 	} else {
1617*7c478bd9Sstevel@tonic-gate 		if (Bflag) {
1618*7c478bd9Sstevel@tonic-gate 			if (fread(&tmp, sizeof (struct hdr), 1, pfile) == 0) {
1619*7c478bd9Sstevel@tonic-gate 				perror("fread()");
1620*7c478bd9Sstevel@tonic-gate 				exit(EX_IOERR);
1621*7c478bd9Sstevel@tonic-gate 			}
1622*7c478bd9Sstevel@tonic-gate 		} else {
1623*7c478bd9Sstevel@tonic-gate 			/*
1624*7c478bd9Sstevel@tonic-gate 			 * If we're not reading big %pc's, we need to read
1625*7c478bd9Sstevel@tonic-gate 			 * the 32-bit header, and assign the members to
1626*7c478bd9Sstevel@tonic-gate 			 * the actual header.
1627*7c478bd9Sstevel@tonic-gate 			 */
1628*7c478bd9Sstevel@tonic-gate 			struct hdr32 hdr32;
1629*7c478bd9Sstevel@tonic-gate 			if (fread(&hdr32, sizeof (hdr32), 1, pfile) == 0) {
1630*7c478bd9Sstevel@tonic-gate 				perror("fread()");
1631*7c478bd9Sstevel@tonic-gate 				exit(EX_IOERR);
1632*7c478bd9Sstevel@tonic-gate 			}
1633*7c478bd9Sstevel@tonic-gate 			tmp.lowpc = hdr32.lowpc;
1634*7c478bd9Sstevel@tonic-gate 			tmp.highpc = hdr32.highpc;
1635*7c478bd9Sstevel@tonic-gate 			tmp.ncnt = hdr32.ncnt;
1636*7c478bd9Sstevel@tonic-gate 			hdrsize = sizeof (struct hdr32);
1637*7c478bd9Sstevel@tonic-gate 		}
1638*7c478bd9Sstevel@tonic-gate 	}
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate 	/*
1641*7c478bd9Sstevel@tonic-gate 	 * perform sanity check on profiled file we've opened.
1642*7c478bd9Sstevel@tonic-gate 	 */
1643*7c478bd9Sstevel@tonic-gate 	if (tmp.lowpc >= tmp.highpc) {
1644*7c478bd9Sstevel@tonic-gate 		if (rflag)
1645*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: badly formed profiled data.\n",
1646*7c478bd9Sstevel@tonic-gate 			    filename);
1647*7c478bd9Sstevel@tonic-gate 		else
1648*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: badly formed gmon.out file.\n",
1649*7c478bd9Sstevel@tonic-gate 			    filename);
1650*7c478bd9Sstevel@tonic-gate 		exit(EX_SOFTWARE);
1651*7c478bd9Sstevel@tonic-gate 	}
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate 	if (s_highpc != 0 && (tmp.lowpc != h.lowpc ||
1654*7c478bd9Sstevel@tonic-gate 	    tmp.highpc != h.highpc || tmp.ncnt != h.ncnt)) {
1655*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
1656*7c478bd9Sstevel@tonic-gate 		    "%s: incompatible with first gmon file\n",
1657*7c478bd9Sstevel@tonic-gate 		    filename);
1658*7c478bd9Sstevel@tonic-gate 		exit(EX_IOERR);
1659*7c478bd9Sstevel@tonic-gate 	}
1660*7c478bd9Sstevel@tonic-gate 	h = tmp;
1661*7c478bd9Sstevel@tonic-gate 	s_lowpc = h.lowpc;
1662*7c478bd9Sstevel@tonic-gate 	s_highpc = h.highpc;
1663*7c478bd9Sstevel@tonic-gate 	lowpc = h.lowpc / sizeof (UNIT);
1664*7c478bd9Sstevel@tonic-gate 	highpc = h.highpc / sizeof (UNIT);
1665*7c478bd9Sstevel@tonic-gate 	sampbytes = h.ncnt > hdrsize ? h.ncnt - hdrsize : 0;
1666*7c478bd9Sstevel@tonic-gate 	nsamples = sampbytes / sizeof (unsigned_UNIT);
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1669*7c478bd9Sstevel@tonic-gate 	if (debug & SAMPLEDEBUG) {
1670*7c478bd9Sstevel@tonic-gate 		printf("[openpfile] hdr.lowpc 0x%llx hdr.highpc "
1671*7c478bd9Sstevel@tonic-gate 		    "0x%llx hdr.ncnt %lld\n",
1672*7c478bd9Sstevel@tonic-gate 		    h.lowpc, h.highpc, h.ncnt);
1673*7c478bd9Sstevel@tonic-gate 		printf("[openpfile]   s_lowpc 0x%llx   s_highpc 0x%llx\n",
1674*7c478bd9Sstevel@tonic-gate 		    s_lowpc, s_highpc);
1675*7c478bd9Sstevel@tonic-gate 		printf("[openpfile]     lowpc 0x%llx     highpc 0x%llx\n",
1676*7c478bd9Sstevel@tonic-gate 		    lowpc, highpc);
1677*7c478bd9Sstevel@tonic-gate 		printf("[openpfile] sampbytes %d nsamples %d\n",
1678*7c478bd9Sstevel@tonic-gate 		    sampbytes, nsamples);
1679*7c478bd9Sstevel@tonic-gate 	}
1680*7c478bd9Sstevel@tonic-gate #endif DEBUG
1681*7c478bd9Sstevel@tonic-gate 
1682*7c478bd9Sstevel@tonic-gate 	return ((void *) pfile);
1683*7c478bd9Sstevel@tonic-gate }
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate /*
1686*7c478bd9Sstevel@tonic-gate  * Information from a gmon.out file depends on whether it's versioned
1687*7c478bd9Sstevel@tonic-gate  * or non-versioned, *old style* gmon.out. If old-style, it is in two
1688*7c478bd9Sstevel@tonic-gate  * parts : an array of sampling hits within pc ranges, and the arcs. If
1689*7c478bd9Sstevel@tonic-gate  * versioned, it contains a header, followed by any number of
1690*7c478bd9Sstevel@tonic-gate  * modules/callgraph/pcsample_buffer objects.
1691*7c478bd9Sstevel@tonic-gate  */
1692*7c478bd9Sstevel@tonic-gate static void
1693*7c478bd9Sstevel@tonic-gate getpfile(char *filename)
1694*7c478bd9Sstevel@tonic-gate {
1695*7c478bd9Sstevel@tonic-gate 	void		*handle;
1696*7c478bd9Sstevel@tonic-gate 	size_t		fsz;
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 	handle = openpfile(filename, &fsz);
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 	if (old_style) {
1701*7c478bd9Sstevel@tonic-gate 		readsamples((FILE *) handle);
1702*7c478bd9Sstevel@tonic-gate 		readarcs((FILE *) handle);
1703*7c478bd9Sstevel@tonic-gate 		fclose((FILE *) handle);
1704*7c478bd9Sstevel@tonic-gate 		return;
1705*7c478bd9Sstevel@tonic-gate 	}
1706*7c478bd9Sstevel@tonic-gate 
1707*7c478bd9Sstevel@tonic-gate 	getpfiledata((caddr_t) handle, fsz);
1708*7c478bd9Sstevel@tonic-gate 	munmap(handle, fsz);
1709*7c478bd9Sstevel@tonic-gate }
1710*7c478bd9Sstevel@tonic-gate 
1711*7c478bd9Sstevel@tonic-gate main(int argc, char ** argv)
1712*7c478bd9Sstevel@tonic-gate {
1713*7c478bd9Sstevel@tonic-gate 	char	**sp;
1714*7c478bd9Sstevel@tonic-gate 	nltype	**timesortnlp;
1715*7c478bd9Sstevel@tonic-gate 	int		c;
1716*7c478bd9Sstevel@tonic-gate 	int		errflg;
1717*7c478bd9Sstevel@tonic-gate 	extern char	*optarg;
1718*7c478bd9Sstevel@tonic-gate 	extern int	optind;
1719*7c478bd9Sstevel@tonic-gate 
1720*7c478bd9Sstevel@tonic-gate 	prog_name = *argv;  /* preserve program name */
1721*7c478bd9Sstevel@tonic-gate 	debug = 0;
1722*7c478bd9Sstevel@tonic-gate 	nflag = FALSE;
1723*7c478bd9Sstevel@tonic-gate 	bflag = TRUE;
1724*7c478bd9Sstevel@tonic-gate 	lflag = FALSE;
1725*7c478bd9Sstevel@tonic-gate 	Cflag = FALSE;
1726*7c478bd9Sstevel@tonic-gate 	first_file = TRUE;
1727*7c478bd9Sstevel@tonic-gate 	rflag = FALSE;
1728*7c478bd9Sstevel@tonic-gate 	Bflag = FALSE;
1729*7c478bd9Sstevel@tonic-gate 	errflg = FALSE;
1730*7c478bd9Sstevel@tonic-gate 
1731*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "abd:CcDE:e:F:f:ln:sz")) != EOF)
1732*7c478bd9Sstevel@tonic-gate 		switch (c) {
1733*7c478bd9Sstevel@tonic-gate 		case 'a':
1734*7c478bd9Sstevel@tonic-gate 			aflag = TRUE;
1735*7c478bd9Sstevel@tonic-gate 			break;
1736*7c478bd9Sstevel@tonic-gate 		case 'b':
1737*7c478bd9Sstevel@tonic-gate 			bflag = FALSE;
1738*7c478bd9Sstevel@tonic-gate 			break;
1739*7c478bd9Sstevel@tonic-gate 		case 'c':
1740*7c478bd9Sstevel@tonic-gate 			cflag = TRUE;
1741*7c478bd9Sstevel@tonic-gate 			break;
1742*7c478bd9Sstevel@tonic-gate 		case 'C':
1743*7c478bd9Sstevel@tonic-gate 			Cflag = TRUE;
1744*7c478bd9Sstevel@tonic-gate 			break;
1745*7c478bd9Sstevel@tonic-gate 		case 'd':
1746*7c478bd9Sstevel@tonic-gate 			dflag = TRUE;
1747*7c478bd9Sstevel@tonic-gate 			debug |= atoi(optarg);
1748*7c478bd9Sstevel@tonic-gate 			printf("[main] debug = 0x%x\n", debug);
1749*7c478bd9Sstevel@tonic-gate 			break;
1750*7c478bd9Sstevel@tonic-gate 		case 'D':
1751*7c478bd9Sstevel@tonic-gate 			Dflag = TRUE;
1752*7c478bd9Sstevel@tonic-gate 			break;
1753*7c478bd9Sstevel@tonic-gate 		case 'E':
1754*7c478bd9Sstevel@tonic-gate 			addlist(Elist, optarg);
1755*7c478bd9Sstevel@tonic-gate 			Eflag = TRUE;
1756*7c478bd9Sstevel@tonic-gate 			addlist(elist, optarg);
1757*7c478bd9Sstevel@tonic-gate 			eflag = TRUE;
1758*7c478bd9Sstevel@tonic-gate 			break;
1759*7c478bd9Sstevel@tonic-gate 		case 'e':
1760*7c478bd9Sstevel@tonic-gate 			addlist(elist, optarg);
1761*7c478bd9Sstevel@tonic-gate 			eflag = TRUE;
1762*7c478bd9Sstevel@tonic-gate 			break;
1763*7c478bd9Sstevel@tonic-gate 		case 'F':
1764*7c478bd9Sstevel@tonic-gate 			addlist(Flist, optarg);
1765*7c478bd9Sstevel@tonic-gate 			Fflag = TRUE;
1766*7c478bd9Sstevel@tonic-gate 			addlist(flist, optarg);
1767*7c478bd9Sstevel@tonic-gate 			fflag = TRUE;
1768*7c478bd9Sstevel@tonic-gate 			break;
1769*7c478bd9Sstevel@tonic-gate 		case 'f':
1770*7c478bd9Sstevel@tonic-gate 			addlist(flist, optarg);
1771*7c478bd9Sstevel@tonic-gate 			fflag = TRUE;
1772*7c478bd9Sstevel@tonic-gate 			break;
1773*7c478bd9Sstevel@tonic-gate 		case 'l':
1774*7c478bd9Sstevel@tonic-gate 			lflag = TRUE;
1775*7c478bd9Sstevel@tonic-gate 			break;
1776*7c478bd9Sstevel@tonic-gate 		case 'n':
1777*7c478bd9Sstevel@tonic-gate 			nflag = TRUE;
1778*7c478bd9Sstevel@tonic-gate 			number_funcs_toprint = atoi(optarg);
1779*7c478bd9Sstevel@tonic-gate 			break;
1780*7c478bd9Sstevel@tonic-gate 		case 's':
1781*7c478bd9Sstevel@tonic-gate 			sflag = TRUE;
1782*7c478bd9Sstevel@tonic-gate 			break;
1783*7c478bd9Sstevel@tonic-gate 		case 'z':
1784*7c478bd9Sstevel@tonic-gate 			zflag = TRUE;
1785*7c478bd9Sstevel@tonic-gate 			break;
1786*7c478bd9Sstevel@tonic-gate 		case '?':
1787*7c478bd9Sstevel@tonic-gate 			errflg++;
1788*7c478bd9Sstevel@tonic-gate 
1789*7c478bd9Sstevel@tonic-gate 		}
1790*7c478bd9Sstevel@tonic-gate 
1791*7c478bd9Sstevel@tonic-gate 	if (errflg) {
1792*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1793*7c478bd9Sstevel@tonic-gate 		    "usage: gprof [ -abcCDlsz ] [ -e function-name ] "
1794*7c478bd9Sstevel@tonic-gate 		    "[ -E function-name ]\n\t[ -f function-name ] "
1795*7c478bd9Sstevel@tonic-gate 		    "[ -F function-name  ]\n\t[  image-file  "
1796*7c478bd9Sstevel@tonic-gate 		    "[ profile-file ... ] ]\n");
1797*7c478bd9Sstevel@tonic-gate 		exit(EX_USAGE);
1798*7c478bd9Sstevel@tonic-gate 	}
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate 	if (optind < argc) {
1801*7c478bd9Sstevel@tonic-gate 		a_outname  = argv[optind++];
1802*7c478bd9Sstevel@tonic-gate 	} else {
1803*7c478bd9Sstevel@tonic-gate 		a_outname  = A_OUTNAME;
1804*7c478bd9Sstevel@tonic-gate 	}
1805*7c478bd9Sstevel@tonic-gate 	if (optind < argc) {
1806*7c478bd9Sstevel@tonic-gate 		gmonname = argv[optind++];
1807*7c478bd9Sstevel@tonic-gate 	} else {
1808*7c478bd9Sstevel@tonic-gate 		gmonname = GMONNAME;
1809*7c478bd9Sstevel@tonic-gate 	}
1810*7c478bd9Sstevel@tonic-gate 	/*
1811*7c478bd9Sstevel@tonic-gate 	 *	turn off default functions
1812*7c478bd9Sstevel@tonic-gate 	 */
1813*7c478bd9Sstevel@tonic-gate 	for (sp = &defaultEs[0]; *sp; sp++) {
1814*7c478bd9Sstevel@tonic-gate 		Eflag = TRUE;
1815*7c478bd9Sstevel@tonic-gate 		addlist(Elist, *sp);
1816*7c478bd9Sstevel@tonic-gate 		eflag = TRUE;
1817*7c478bd9Sstevel@tonic-gate 		addlist(elist, *sp);
1818*7c478bd9Sstevel@tonic-gate 	}
1819*7c478bd9Sstevel@tonic-gate 	/*
1820*7c478bd9Sstevel@tonic-gate 	 *	how many ticks per second?
1821*7c478bd9Sstevel@tonic-gate 	 *	if we can't tell, report time in ticks.
1822*7c478bd9Sstevel@tonic-gate 	 */
1823*7c478bd9Sstevel@tonic-gate 	hz = sysconf(_SC_CLK_TCK);
1824*7c478bd9Sstevel@tonic-gate 	if (hz == -1) {
1825*7c478bd9Sstevel@tonic-gate 		hz = 1;
1826*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "time is in ticks, not seconds\n");
1827*7c478bd9Sstevel@tonic-gate 	}
1828*7c478bd9Sstevel@tonic-gate 
1829*7c478bd9Sstevel@tonic-gate 	getnfile(a_outname);
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	/*
1832*7c478bd9Sstevel@tonic-gate 	 *	get information about mon.out file(s).
1833*7c478bd9Sstevel@tonic-gate 	 */
1834*7c478bd9Sstevel@tonic-gate 	do {
1835*7c478bd9Sstevel@tonic-gate 		getpfile(gmonname);
1836*7c478bd9Sstevel@tonic-gate 		if (optind < argc)
1837*7c478bd9Sstevel@tonic-gate 			gmonname = argv[optind++];
1838*7c478bd9Sstevel@tonic-gate 		else
1839*7c478bd9Sstevel@tonic-gate 			optind++;
1840*7c478bd9Sstevel@tonic-gate 	} while (optind <= argc);
1841*7c478bd9Sstevel@tonic-gate 	/*
1842*7c478bd9Sstevel@tonic-gate 	 *	dump out a gmon.sum file if requested
1843*7c478bd9Sstevel@tonic-gate 	 */
1844*7c478bd9Sstevel@tonic-gate 	if (sflag || Dflag)
1845*7c478bd9Sstevel@tonic-gate 		dumpsum(GMONSUM);
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 	if (old_style) {
1848*7c478bd9Sstevel@tonic-gate 		/*
1849*7c478bd9Sstevel@tonic-gate 		 *	assign samples to procedures
1850*7c478bd9Sstevel@tonic-gate 		 */
1851*7c478bd9Sstevel@tonic-gate 		asgnsamples();
1852*7c478bd9Sstevel@tonic-gate 	}
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate 	/*
1855*7c478bd9Sstevel@tonic-gate 	 *	assemble the dynamic profile
1856*7c478bd9Sstevel@tonic-gate 	 */
1857*7c478bd9Sstevel@tonic-gate 	timesortnlp = doarcs();
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 	/*
1860*7c478bd9Sstevel@tonic-gate 	 *	print the dynamic profile
1861*7c478bd9Sstevel@tonic-gate 	 */
1862*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1863*7c478bd9Sstevel@tonic-gate 	if (debug & ANYDEBUG) {
1864*7c478bd9Sstevel@tonic-gate 		/* raw output of all symbols in all their glory */
1865*7c478bd9Sstevel@tonic-gate 		int i;
1866*7c478bd9Sstevel@tonic-gate 		printf(" Name, pc_entry_pt, svalue, tix_in_routine, "
1867*7c478bd9Sstevel@tonic-gate 		    "#calls, selfcalls, index \n");
1868*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < modules.nname; i++) { 	/* Print each symbol */
1869*7c478bd9Sstevel@tonic-gate 			if (timesortnlp[i]->name)
1870*7c478bd9Sstevel@tonic-gate 				printf(" %s ", timesortnlp[i]->name);
1871*7c478bd9Sstevel@tonic-gate 			else
1872*7c478bd9Sstevel@tonic-gate 				printf(" <cycle> ");
1873*7c478bd9Sstevel@tonic-gate 			printf(" %lld ", timesortnlp[i]->value);
1874*7c478bd9Sstevel@tonic-gate 			printf(" %lld ", timesortnlp[i]->svalue);
1875*7c478bd9Sstevel@tonic-gate 			printf(" %f ", timesortnlp[i]->time);
1876*7c478bd9Sstevel@tonic-gate 			printf(" %lld ", timesortnlp[i]->ncall);
1877*7c478bd9Sstevel@tonic-gate 			printf(" %lld ", timesortnlp[i]->selfcalls);
1878*7c478bd9Sstevel@tonic-gate 			printf(" %d ", timesortnlp[i]->index);
1879*7c478bd9Sstevel@tonic-gate 			printf(" \n");
1880*7c478bd9Sstevel@tonic-gate 		}
1881*7c478bd9Sstevel@tonic-gate 	}
1882*7c478bd9Sstevel@tonic-gate #endif DEBUG
1883*7c478bd9Sstevel@tonic-gate 
1884*7c478bd9Sstevel@tonic-gate 	printgprof(timesortnlp);
1885*7c478bd9Sstevel@tonic-gate 	/*
1886*7c478bd9Sstevel@tonic-gate 	 *	print the flat profile
1887*7c478bd9Sstevel@tonic-gate 	 */
1888*7c478bd9Sstevel@tonic-gate 	printprof();
1889*7c478bd9Sstevel@tonic-gate 	/*
1890*7c478bd9Sstevel@tonic-gate 	 *	print the index
1891*7c478bd9Sstevel@tonic-gate 	 */
1892*7c478bd9Sstevel@tonic-gate 	printindex();
1893*7c478bd9Sstevel@tonic-gate 
1894*7c478bd9Sstevel@tonic-gate 	/*
1895*7c478bd9Sstevel@tonic-gate 	 * print the modules
1896*7c478bd9Sstevel@tonic-gate 	 */
1897*7c478bd9Sstevel@tonic-gate 	printmodules();
1898*7c478bd9Sstevel@tonic-gate 
1899*7c478bd9Sstevel@tonic-gate 	done();
1900*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1901*7c478bd9Sstevel@tonic-gate 	return (0);
1902*7c478bd9Sstevel@tonic-gate }
1903