xref: /titanic_50/usr/src/cmd/sgs/prof/common/profv.c (revision b9bd317cda1afb3a01f4812de73e8cec888cbbd7)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*b9bd317cSab196087  * Common Development and Distribution License (the "License").
6*b9bd317cSab196087  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2192ed1782Smike_s 
227c478bd9Sstevel@tonic-gate /*
23*b9bd317cSab196087  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2492ed1782Smike_s  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
2692ed1782Smike_s 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * All routines in this file are for processing new-style, *versioned*
317c478bd9Sstevel@tonic-gate  * mon.out format. Together with rdelf.c, lookup.c and profv.h, these
327c478bd9Sstevel@tonic-gate  * form the complete set of files to profile new-style mon.out files.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
3592ed1782Smike_s #include <stdlib.h>
3692ed1782Smike_s #include <string.h>
37*b9bd317cSab196087 #include "conv.h"
387c478bd9Sstevel@tonic-gate #include "profv.h"
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate bool		time_in_ticks = FALSE;
417c478bd9Sstevel@tonic-gate size_t		n_pcsamples, n_accounted_ticks, n_zeros, total_funcs;
427c478bd9Sstevel@tonic-gate unsigned char	sort_flag;
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate mod_info_t	modules;
457c478bd9Sstevel@tonic-gate size_t		n_modules = 1;	/* always include the aout object */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate struct stat	aout_stat, monout_stat;
487c478bd9Sstevel@tonic-gate profrec_t	*profsym;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate int
cmp_by_name(const void * arg1,const void * arg2)5192ed1782Smike_s cmp_by_name(const void *arg1, const void *arg2)
527c478bd9Sstevel@tonic-gate {
5392ed1782Smike_s 	profrec_t *a = (profrec_t *)arg1;
5492ed1782Smike_s 	profrec_t *b = (profrec_t *)arg2;
5592ed1782Smike_s 
567c478bd9Sstevel@tonic-gate 	return (strcmp(a->demangled_name, b->demangled_name));
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static void
setup_demangled_names(void)6092ed1782Smike_s setup_demangled_names(void)
617c478bd9Sstevel@tonic-gate {
62*b9bd317cSab196087 	const char	*p;
63*b9bd317cSab196087 	char	*nbp, *nbe, *namebuf;
647c478bd9Sstevel@tonic-gate 	size_t	cur_len = 0, namebuf_sz = BUCKET_SZ;
6592ed1782Smike_s 	size_t	i, namelen;
667c478bd9Sstevel@tonic-gate 
6792ed1782Smike_s 	if ((namebuf = malloc(namebuf_sz)) == NULL) {
6892ed1782Smike_s 		(void) fprintf(stderr, "%s: can't allocate %d bytes\n",
697c478bd9Sstevel@tonic-gate 		    cmdname, namebuf_sz);
707c478bd9Sstevel@tonic-gate 		exit(ERR_MEMORY);
717c478bd9Sstevel@tonic-gate 	}
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	nbp = namebuf;
747c478bd9Sstevel@tonic-gate 	nbe = namebuf + namebuf_sz;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	for (i = 0; i < total_funcs; i++) {
77*b9bd317cSab196087 		if ((p = conv_demangle_name(profsym[i].name)) == NULL)
787c478bd9Sstevel@tonic-gate 			continue;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 		namelen = strlen(p);
817c478bd9Sstevel@tonic-gate 		if ((nbp + namelen + 1) > nbe) {
827c478bd9Sstevel@tonic-gate 			namebuf_sz += BUCKET_SZ;
8392ed1782Smike_s 			namebuf = realloc(namebuf, namebuf_sz);
847c478bd9Sstevel@tonic-gate 			if (namebuf == NULL) {
8592ed1782Smike_s 				(void) fprintf(stderr,
8692ed1782Smike_s 				    "%s: can't alloc %d bytes\n",
877c478bd9Sstevel@tonic-gate 				    cmdname, BUCKET_SZ);
887c478bd9Sstevel@tonic-gate 				exit(ERR_MEMORY);
897c478bd9Sstevel@tonic-gate 			}
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 			nbp = namebuf + cur_len;
927c478bd9Sstevel@tonic-gate 			nbe = namebuf + namebuf_sz;
937c478bd9Sstevel@tonic-gate 		}
947c478bd9Sstevel@tonic-gate 
9592ed1782Smike_s 		(void) strcpy(nbp, p);
967c478bd9Sstevel@tonic-gate 		profsym[i].demangled_name = nbp;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 		nbp += namelen + 1;
997c478bd9Sstevel@tonic-gate 		cur_len += namelen + 1;
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate int
cmp_by_time(const void * arg1,const void * arg2)10492ed1782Smike_s cmp_by_time(const void *arg1, const void *arg2)
1057c478bd9Sstevel@tonic-gate {
10692ed1782Smike_s 	profrec_t *a = (profrec_t *)arg1;
10792ed1782Smike_s 	profrec_t *b = (profrec_t *)arg2;
10892ed1782Smike_s 
1097c478bd9Sstevel@tonic-gate 	if (a->percent_time > b->percent_time)
1107c478bd9Sstevel@tonic-gate 		return (-1);
1117c478bd9Sstevel@tonic-gate 	else if (a->percent_time < b->percent_time)
1127c478bd9Sstevel@tonic-gate 		return (1);
1137c478bd9Sstevel@tonic-gate 	else
1147c478bd9Sstevel@tonic-gate 		return (0);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate int
cmp_by_ncalls(const void * arg1,const void * arg2)11892ed1782Smike_s cmp_by_ncalls(const void *arg1, const void *arg2)
1197c478bd9Sstevel@tonic-gate {
12092ed1782Smike_s 	profrec_t *a = (profrec_t *)arg1;
12192ed1782Smike_s 	profrec_t *b = (profrec_t *)arg2;
12292ed1782Smike_s 
1237c478bd9Sstevel@tonic-gate 	if (a->ncalls > b->ncalls)
1247c478bd9Sstevel@tonic-gate 		return (-1);
1257c478bd9Sstevel@tonic-gate 	else if (a->ncalls < b->ncalls)
1267c478bd9Sstevel@tonic-gate 		return (1);
1277c478bd9Sstevel@tonic-gate 	else
1287c478bd9Sstevel@tonic-gate 		return (0);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static void
print_profile_data(void)13392ed1782Smike_s print_profile_data(void)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate 	int		i;
13692ed1782Smike_s 	int		(*sort_func)(const void *, const void *);
1377c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
1387c478bd9Sstevel@tonic-gate 	double		cumsecs = 0;
1397c478bd9Sstevel@tonic-gate 	char		filler[20];
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	/*
1427c478bd9Sstevel@tonic-gate 	 * Sort the compiled data; the sort flags are mutually exclusive.
1437c478bd9Sstevel@tonic-gate 	 */
1447c478bd9Sstevel@tonic-gate 	switch (sort_flag) {
1457c478bd9Sstevel@tonic-gate 		case BY_NCALLS:
1467c478bd9Sstevel@tonic-gate 			sort_func = cmp_by_ncalls;
1477c478bd9Sstevel@tonic-gate 			break;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 		case BY_NAME:
1507c478bd9Sstevel@tonic-gate 			if (Cflag)
1517c478bd9Sstevel@tonic-gate 				setup_demangled_names();
1527c478bd9Sstevel@tonic-gate 			sort_func = cmp_by_name;
1537c478bd9Sstevel@tonic-gate 			break;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 		case BY_ADDRESS:
1567c478bd9Sstevel@tonic-gate 			sort_flag |= BY_ADDRESS;
1577c478bd9Sstevel@tonic-gate 			sort_func = NULL;	/* already sorted by addr */
1587c478bd9Sstevel@tonic-gate 			break;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 		case BY_TIME:		/* default is to sort by time */
1617c478bd9Sstevel@tonic-gate 		default:
1627c478bd9Sstevel@tonic-gate 			sort_func = cmp_by_time;
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (sort_func) {
16792ed1782Smike_s 		qsort(profsym, total_funcs, sizeof (profrec_t), sort_func);
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/*
1717c478bd9Sstevel@tonic-gate 	 * If we're sorting by name, and if it is a verbose print, we wouldn't
1727c478bd9Sstevel@tonic-gate 	 * have set up the print_mid fields yet.
1737c478bd9Sstevel@tonic-gate 	 */
1747c478bd9Sstevel@tonic-gate 	if ((flags & F_VERBOSE) && (sort_flag == BY_NAME)) {
1757c478bd9Sstevel@tonic-gate 		for (i = 0; i < total_funcs; i++) {
1767c478bd9Sstevel@tonic-gate 			/*
1777c478bd9Sstevel@tonic-gate 			 * same as previous or next (if there's one) ?
1787c478bd9Sstevel@tonic-gate 			 */
1797c478bd9Sstevel@tonic-gate 			if (i && (strcmp(profsym[i].demangled_name,
1807c478bd9Sstevel@tonic-gate 			    profsym[i-1].demangled_name) == 0)) {
1817c478bd9Sstevel@tonic-gate 				profsym[i].print_mid = TRUE;
1827c478bd9Sstevel@tonic-gate 			} else if ((i < (total_funcs - 1)) &&
1837c478bd9Sstevel@tonic-gate 			    (strcmp(profsym[i].demangled_name,
1847c478bd9Sstevel@tonic-gate 			    profsym[i+1].demangled_name) == 0)) {
1857c478bd9Sstevel@tonic-gate 				profsym[i].print_mid = TRUE;
1867c478bd9Sstevel@tonic-gate 			}
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	/*
1917c478bd9Sstevel@tonic-gate 	 * The actual printing part.
1927c478bd9Sstevel@tonic-gate 	 */
1937c478bd9Sstevel@tonic-gate 	if (!(flags & F_NHEAD)) {
1947c478bd9Sstevel@tonic-gate 		if (flags & F_PADDR)
19592ed1782Smike_s 			(void) printf("        %s", atitle);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		if (time_in_ticks)
19892ed1782Smike_s 			(void) puts(
19992ed1782Smike_s 			    " %Time   Tiks  Cumtiks  #Calls   tiks/call  Name");
2007c478bd9Sstevel@tonic-gate 		else
20192ed1782Smike_s 			(void) puts(
20292ed1782Smike_s 			    " %Time Seconds Cumsecs  #Calls   msec/call  Name");
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	mi = NULL;
2067c478bd9Sstevel@tonic-gate 	for (i = 0; i < total_funcs; i++) {
2077c478bd9Sstevel@tonic-gate 		/*
2087c478bd9Sstevel@tonic-gate 		 * Since the same value may denote different symbols in
2097c478bd9Sstevel@tonic-gate 		 * different shared objects, it is debatable if it is
2107c478bd9Sstevel@tonic-gate 		 * meaningful to print addresses at all. Especially so
2117c478bd9Sstevel@tonic-gate 		 * if we were asked to sort by symbol addresses.
2127c478bd9Sstevel@tonic-gate 		 *
2137c478bd9Sstevel@tonic-gate 		 * If we've to sort by address, I think it is better to sort
2147c478bd9Sstevel@tonic-gate 		 * it on a per-module basis and if verbose mode is on too,
2157c478bd9Sstevel@tonic-gate 		 * print a newline to separate out modules.
2167c478bd9Sstevel@tonic-gate 		 */
2177c478bd9Sstevel@tonic-gate 		if ((flags & F_VERBOSE) && (sort_flag == BY_ADDRESS)) {
2187c478bd9Sstevel@tonic-gate 			if (mi != profsym[i].module) {
21992ed1782Smike_s 				(void) printf("\n");
2207c478bd9Sstevel@tonic-gate 				mi = profsym[i].module;
2217c478bd9Sstevel@tonic-gate 			}
2227c478bd9Sstevel@tonic-gate 		}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 		if (flags & F_PADDR) {
2257c478bd9Sstevel@tonic-gate 			if (aformat[2] == 'x')
22692ed1782Smike_s 				(void) printf("%16llx ", profsym[i].addr);
2277c478bd9Sstevel@tonic-gate 			else
22892ed1782Smike_s 				(void) printf("%16llo ", profsym[i].addr);
2297c478bd9Sstevel@tonic-gate 		}
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		cumsecs += profsym[i].seconds;
23292ed1782Smike_s 		(void) printf("%6.1f%8.2f%8.2f", profsym[i].percent_time,
2337c478bd9Sstevel@tonic-gate 		    profsym[i].seconds, cumsecs);
2347c478bd9Sstevel@tonic-gate 
23592ed1782Smike_s 		(void) printf("%8d%12.4f  ",
2367c478bd9Sstevel@tonic-gate 		    profsym[i].ncalls, profsym[i].msecs_per_call);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 		if (profsym[i].print_mid)
23992ed1782Smike_s 			(void) printf("%d:", (profsym[i].module)->id);
2407c478bd9Sstevel@tonic-gate 
24192ed1782Smike_s 		(void) printf("%s\n", profsym[i].demangled_name);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (flags & F_PADDR)
24592ed1782Smike_s 		(void) sprintf(filler, "%16s", "");
2467c478bd9Sstevel@tonic-gate 	else
2477c478bd9Sstevel@tonic-gate 		filler[0] = 0;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (flags & F_VERBOSE) {
25092ed1782Smike_s 		(void) puts("\n");
25192ed1782Smike_s 		(void) printf("%s   Total Object Modules     %7d\n",
2527c478bd9Sstevel@tonic-gate 		    filler, n_modules);
25392ed1782Smike_s 		(void) printf("%s   Qualified Symbols        %7d\n",
2547c478bd9Sstevel@tonic-gate 		    filler, total_funcs);
25592ed1782Smike_s 		(void) printf("%s   Symbols with zero usage  %7d\n",
2567c478bd9Sstevel@tonic-gate 		    filler, n_zeros);
25792ed1782Smike_s 		(void) printf("%s   Total pc-hits            %7d\n",
2587c478bd9Sstevel@tonic-gate 		    filler, n_pcsamples);
25992ed1782Smike_s 		(void) printf("%s   Accounted pc-hits        %7d\n",
2607c478bd9Sstevel@tonic-gate 		    filler, n_accounted_ticks);
2617c478bd9Sstevel@tonic-gate 		if ((!gflag) && (n_pcsamples - n_accounted_ticks)) {
26292ed1782Smike_s 			(void) printf("%s   Missed pc-hits (try -g)  %7d\n\n",
2637c478bd9Sstevel@tonic-gate 			    filler, n_pcsamples - n_accounted_ticks);
2647c478bd9Sstevel@tonic-gate 		} else {
26592ed1782Smike_s 			(void) printf("%s   Missed pc-hits           %7d\n\n",
2667c478bd9Sstevel@tonic-gate 			    filler, n_pcsamples - n_accounted_ticks);
2677c478bd9Sstevel@tonic-gate 		}
26892ed1782Smike_s 		(void) printf("%s   Module info\n", filler);
2697c478bd9Sstevel@tonic-gate 		for (mi = &modules; mi; mi = mi->next)
27092ed1782Smike_s 			(void) printf("%s      %d: `%s'\n", filler,
27192ed1782Smike_s 			    mi->id, mi->path);
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate int
name_cmp(const void * arg1,const void * arg2)27692ed1782Smike_s name_cmp(const void *arg1, const void *arg2)
2777c478bd9Sstevel@tonic-gate {
27892ed1782Smike_s 	profnames_t *a = (profnames_t *)arg1;
27992ed1782Smike_s 	profnames_t *b = (profnames_t *)arg2;
28092ed1782Smike_s 
2817c478bd9Sstevel@tonic-gate 	return (strcmp(a->name, b->name));
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate static void
check_dupnames(void)28592ed1782Smike_s check_dupnames(void)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	int		i;
2887c478bd9Sstevel@tonic-gate 	profnames_t	*pn;
2897c478bd9Sstevel@tonic-gate 
29092ed1782Smike_s 	pn = calloc(total_funcs, sizeof (profnames_t));
2917c478bd9Sstevel@tonic-gate 	if (pn == NULL) {
29292ed1782Smike_s 		(void) fprintf(stderr, "%s: no room for %d bytes\n",
29392ed1782Smike_s 		    cmdname, total_funcs * sizeof (profnames_t));
2947c478bd9Sstevel@tonic-gate 		exit(ERR_MEMORY);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	for (i = 0; i < total_funcs; i++) {
2987c478bd9Sstevel@tonic-gate 		pn[i].name = profsym[i].demangled_name;
2997c478bd9Sstevel@tonic-gate 		pn[i].pfrec = &profsym[i];
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
30292ed1782Smike_s 	qsort(pn, total_funcs, sizeof (profnames_t), name_cmp);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	for (i = 0; i < total_funcs; i++) {
3057c478bd9Sstevel@tonic-gate 		/*
3067c478bd9Sstevel@tonic-gate 		 * same as previous or next (if there's one) ?
3077c478bd9Sstevel@tonic-gate 		 */
3087c478bd9Sstevel@tonic-gate 		if (i && (strcmp(pn[i].name, pn[i-1].name) == 0))
3097c478bd9Sstevel@tonic-gate 			(pn[i].pfrec)->print_mid = TRUE;
3107c478bd9Sstevel@tonic-gate 		else if ((i < (total_funcs - 1)) &&
3117c478bd9Sstevel@tonic-gate 		    (strcmp(pn[i].name, pn[i+1].name) == 0)) {
3127c478bd9Sstevel@tonic-gate 			(pn[i].pfrec)->print_mid = TRUE;
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	free(pn);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate static void
compute_times(nltype * nl,profrec_t * psym)3207c478bd9Sstevel@tonic-gate compute_times(nltype *nl, profrec_t *psym)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	static int	first_time = TRUE;
3237c478bd9Sstevel@tonic-gate 	static long	hz;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	if (first_time) {
3267c478bd9Sstevel@tonic-gate 		if ((hz = sysconf(_SC_CLK_TCK)) == -1)
3277c478bd9Sstevel@tonic-gate 			time_in_ticks = TRUE;
3287c478bd9Sstevel@tonic-gate 		first_time = FALSE;
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	if (time_in_ticks) {
3327c478bd9Sstevel@tonic-gate 		psym->seconds = (double)nl->nticks;
3337c478bd9Sstevel@tonic-gate 		if (nl->ncalls) {
3347c478bd9Sstevel@tonic-gate 			psym->msecs_per_call = (double)nl->nticks /
3357c478bd9Sstevel@tonic-gate 			    (double)nl->ncalls;
3367c478bd9Sstevel@tonic-gate 		} else
3377c478bd9Sstevel@tonic-gate 			psym->msecs_per_call = (double)0.0;
3387c478bd9Sstevel@tonic-gate 	} else {
3397c478bd9Sstevel@tonic-gate 		psym->seconds = (double)nl->nticks / (double)hz;
3407c478bd9Sstevel@tonic-gate 		if (nl->ncalls) {
34192ed1782Smike_s 			psym->msecs_per_call =
34292ed1782Smike_s 			    ((double)psym->seconds * 1000.0) /
34392ed1782Smike_s 			    (double)nl->ncalls;
3447c478bd9Sstevel@tonic-gate 		} else
3457c478bd9Sstevel@tonic-gate 			psym->msecs_per_call = (double)0.0;
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	if (n_pcsamples) {
34992ed1782Smike_s 		psym->percent_time =
35092ed1782Smike_s 		    ((double)nl->nticks / (double)n_pcsamples) * 100;
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate static void
collect_profsyms(void)35592ed1782Smike_s collect_profsyms(void)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
3587c478bd9Sstevel@tonic-gate 	nltype		*nl;
3597c478bd9Sstevel@tonic-gate 	size_t		i, ndx;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next)
3637c478bd9Sstevel@tonic-gate 		total_funcs += mi->nfuncs;
3647c478bd9Sstevel@tonic-gate 
36592ed1782Smike_s 	profsym = calloc(total_funcs, sizeof (profrec_t));
3667c478bd9Sstevel@tonic-gate 	if (profsym == NULL) {
36792ed1782Smike_s 		(void) fprintf(stderr, "%s: no room for %d bytes\n",
36892ed1782Smike_s 		    cmdname, total_funcs * sizeof (profrec_t));
3697c478bd9Sstevel@tonic-gate 		exit(ERR_MEMORY);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	ndx = 0;
3737c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
3747c478bd9Sstevel@tonic-gate 		nl = mi->nl;
3757c478bd9Sstevel@tonic-gate 		for (i = 0; i < mi->nfuncs; i++) {
3767c478bd9Sstevel@tonic-gate 			/*
3777c478bd9Sstevel@tonic-gate 			 * I think F_ZSYMS doesn't make sense for the new
3787c478bd9Sstevel@tonic-gate 			 * mon.out format, since we don't have a profiling
3797c478bd9Sstevel@tonic-gate 			 * *range*, per se. But the man page demands it,
3807c478bd9Sstevel@tonic-gate 			 * so...
3817c478bd9Sstevel@tonic-gate 			 */
3827c478bd9Sstevel@tonic-gate 			if ((nl[i].ncalls == 0) && (nl[i].nticks == 0)) {
3837c478bd9Sstevel@tonic-gate 				n_zeros++;
3847c478bd9Sstevel@tonic-gate 				if (!(flags & F_ZSYMS))
3857c478bd9Sstevel@tonic-gate 					continue;
3867c478bd9Sstevel@tonic-gate 			}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 			/*
3897c478bd9Sstevel@tonic-gate 			 * Initially, we set demangled_name to be
3907c478bd9Sstevel@tonic-gate 			 * the same as name. If Cflag is set, we later
3917c478bd9Sstevel@tonic-gate 			 * change this to be the demangled name ptr.
3927c478bd9Sstevel@tonic-gate 			 */
3937c478bd9Sstevel@tonic-gate 			profsym[ndx].addr = nl[i].value;
3947c478bd9Sstevel@tonic-gate 			profsym[ndx].ncalls = nl[i].ncalls;
3957c478bd9Sstevel@tonic-gate 			profsym[ndx].name = nl[i].name;
3967c478bd9Sstevel@tonic-gate 			profsym[ndx].demangled_name = nl[i].name;
3977c478bd9Sstevel@tonic-gate 			profsym[ndx].module = mi;
3987c478bd9Sstevel@tonic-gate 			profsym[ndx].print_mid = FALSE;
3997c478bd9Sstevel@tonic-gate 			compute_times(&nl[i], &profsym[ndx]);
4007c478bd9Sstevel@tonic-gate 			ndx++;
4017c478bd9Sstevel@tonic-gate 		}
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	/*
4057c478bd9Sstevel@tonic-gate 	 * Adjust total_funcs to actual printable funcs
4067c478bd9Sstevel@tonic-gate 	 */
4077c478bd9Sstevel@tonic-gate 	total_funcs = ndx;
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate static void
assign_pcsamples(mod_info_t * module,Address * pcsmpl,size_t n_samples)41192ed1782Smike_s assign_pcsamples(mod_info_t *module, Address *pcsmpl,
41292ed1782Smike_s     size_t n_samples)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	Address		*pcptr, *pcse = pcsmpl + n_samples;
4157c478bd9Sstevel@tonic-gate 	Address		nxt_func;
4167c478bd9Sstevel@tonic-gate 	nltype		*nl;
4177c478bd9Sstevel@tonic-gate 	size_t		nticks;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	/* Locate the first pc-hit for this module */
4207c478bd9Sstevel@tonic-gate 	if ((pcptr = locate(pcsmpl, n_samples, module->load_base)) == NULL)
4217c478bd9Sstevel@tonic-gate 		return;			/* no pc-hits in this module */
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/* Assign all pc-hits in this module to appropriate functions */
4247c478bd9Sstevel@tonic-gate 	while ((pcptr < pcse) && (*pcptr < module->load_end)) {
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		/* Update the corresponding function's time */
4277c478bd9Sstevel@tonic-gate 		if (nl = nllookup(module, *pcptr, &nxt_func)) {
4287c478bd9Sstevel@tonic-gate 			/*
4297c478bd9Sstevel@tonic-gate 			 * Collect all pc-hits in this function. Each
4307c478bd9Sstevel@tonic-gate 			 * pc-hit counts as 1 tick.
4317c478bd9Sstevel@tonic-gate 			 */
4327c478bd9Sstevel@tonic-gate 			nticks = 0;
4337c478bd9Sstevel@tonic-gate 			while ((pcptr < pcse) && (*pcptr < nxt_func)) {
4347c478bd9Sstevel@tonic-gate 				nticks++;
4357c478bd9Sstevel@tonic-gate 				pcptr++;
4367c478bd9Sstevel@tonic-gate 			}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 			nl->nticks += nticks;
4397c478bd9Sstevel@tonic-gate 			n_accounted_ticks += nticks;
4407c478bd9Sstevel@tonic-gate 		} else {
4417c478bd9Sstevel@tonic-gate 			/*
4427c478bd9Sstevel@tonic-gate 			 * pc sample could not be assigned to function;
4437c478bd9Sstevel@tonic-gate 			 * probably in a PLT
4447c478bd9Sstevel@tonic-gate 			 */
4457c478bd9Sstevel@tonic-gate 			pcptr++;
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
45092ed1782Smike_s static int
pc_cmp(const void * arg1,const void * arg2)45192ed1782Smike_s pc_cmp(const void *arg1, const void *arg2)
4527c478bd9Sstevel@tonic-gate {
45392ed1782Smike_s 	Address *pc1 = (Address *)arg1;
45492ed1782Smike_s 	Address *pc2 = (Address *)arg2;
45592ed1782Smike_s 
4567c478bd9Sstevel@tonic-gate 	if (*pc1 > *pc2)
4577c478bd9Sstevel@tonic-gate 		return (1);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (*pc1 < *pc2)
4607c478bd9Sstevel@tonic-gate 		return (-1);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	return (0);
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate static void
process_pcsamples(ProfBuffer * bufp)46692ed1782Smike_s process_pcsamples(ProfBuffer *bufp)
4677c478bd9Sstevel@tonic-gate {
4687c478bd9Sstevel@tonic-gate 	Address		*pc_samples;
4697c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
4707c478bd9Sstevel@tonic-gate 	size_t		nelem = bufp->bufsize;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/* buffer with no pc samples ? */
4737c478bd9Sstevel@tonic-gate 	if (nelem == 0)
4747c478bd9Sstevel@tonic-gate 		return;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	/* Allocate for the pcsample chunk */
4777c478bd9Sstevel@tonic-gate 	pc_samples = (Address *) calloc(nelem, sizeof (Address));
4787c478bd9Sstevel@tonic-gate 	if (pc_samples == NULL) {
47992ed1782Smike_s 		(void) fprintf(stderr, "%s: no room for %d sample pc's\n",
4807c478bd9Sstevel@tonic-gate 		    cmdname, nelem);
4817c478bd9Sstevel@tonic-gate 		exit(ERR_MEMORY);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 
48492ed1782Smike_s 	(void) memcpy(pc_samples, (caddr_t)bufp + bufp->buffer,
4857c478bd9Sstevel@tonic-gate 	    nelem * sizeof (Address));
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/* Sort the pc samples */
48892ed1782Smike_s 	qsort(pc_samples, nelem, sizeof (Address), pc_cmp);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	/*
4917c478bd9Sstevel@tonic-gate 	 * Assign pcsamples to functions in the currently active
4927c478bd9Sstevel@tonic-gate 	 * module list
4937c478bd9Sstevel@tonic-gate 	 */
4947c478bd9Sstevel@tonic-gate 	for (mi = &modules; mi; mi = mi->next) {
4957c478bd9Sstevel@tonic-gate 		if (mi->active == FALSE)
4967c478bd9Sstevel@tonic-gate 			continue;
4977c478bd9Sstevel@tonic-gate 		assign_pcsamples(mi, pc_samples, nelem);
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	free(pc_samples);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/* Update total number of pcsamples read so far */
5037c478bd9Sstevel@tonic-gate 	n_pcsamples += nelem;
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate static void
process_cgraph(ProfCallGraph * cgp)50792ed1782Smike_s process_cgraph(ProfCallGraph *cgp)
5087c478bd9Sstevel@tonic-gate {
5097c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
5107c478bd9Sstevel@tonic-gate 	Address		f_end;
5117c478bd9Sstevel@tonic-gate 	Index		callee_off;
5127c478bd9Sstevel@tonic-gate 	ProfFunction	*calleep;
5137c478bd9Sstevel@tonic-gate 	nltype		*nl;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	for (callee_off = cgp->functions; callee_off;
5167c478bd9Sstevel@tonic-gate 	    callee_off = calleep->next_to) {
5177c478bd9Sstevel@tonic-gate 
51892ed1782Smike_s 		/* LINTED: pointer cast */
5197c478bd9Sstevel@tonic-gate 		calleep = (ProfFunction *)((char *)cgp + callee_off);
5207c478bd9Sstevel@tonic-gate 		if (calleep->count == 0)
5217c478bd9Sstevel@tonic-gate 			continue;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 		/*
5247c478bd9Sstevel@tonic-gate 		 * If we cannot identify a callee with a module, we
5257c478bd9Sstevel@tonic-gate 		 * cannot get to its namelist, just skip it.
5267c478bd9Sstevel@tonic-gate 		 */
5277c478bd9Sstevel@tonic-gate 		for (mi = &modules; mi; mi = mi->next) {
5287c478bd9Sstevel@tonic-gate 			if (mi->active == FALSE)
5297c478bd9Sstevel@tonic-gate 				continue;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 			if (calleep->topc >= mi->load_base &&
5327c478bd9Sstevel@tonic-gate 			    calleep->topc < mi->load_end) {
5337c478bd9Sstevel@tonic-gate 				/*
5347c478bd9Sstevel@tonic-gate 				 * nllookup() returns the next lower entry
5357c478bd9Sstevel@tonic-gate 				 * point on a miss. So just make sure the
5367c478bd9Sstevel@tonic-gate 				 * callee's pc is not outside this function
5377c478bd9Sstevel@tonic-gate 				 */
5387c478bd9Sstevel@tonic-gate 				if (nl = nllookup(mi, calleep->topc, 0)) {
5397c478bd9Sstevel@tonic-gate 					f_end = mi->load_base + (nl->value -
5407c478bd9Sstevel@tonic-gate 					    mi->txt_origin) + nl->size;
5417c478bd9Sstevel@tonic-gate 					if (calleep->topc < f_end)
5427c478bd9Sstevel@tonic-gate 						nl->ncalls += calleep->count;
5437c478bd9Sstevel@tonic-gate 				}
5447c478bd9Sstevel@tonic-gate 			}
5457c478bd9Sstevel@tonic-gate 		}
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate static mod_info_t *
get_shobj_syms(char * pathname,GElf_Addr ld_base,GElf_Addr ld_end)5507c478bd9Sstevel@tonic-gate get_shobj_syms(char *pathname, GElf_Addr ld_base, GElf_Addr ld_end)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate 	mod_info_t	*mi;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	/* Create a new module element */
55592ed1782Smike_s 	if ((mi = malloc(sizeof (mod_info_t))) == NULL) {
55692ed1782Smike_s 		(void) fprintf(stderr, "%s: no room for %d bytes\n",
5577c478bd9Sstevel@tonic-gate 		    cmdname, sizeof (mod_info_t));
5587c478bd9Sstevel@tonic-gate 		exit(ERR_MEMORY);
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 
56192ed1782Smike_s 	mi->path = malloc(strlen(pathname) + 1);
5627c478bd9Sstevel@tonic-gate 	if (mi->path == NULL) {
56392ed1782Smike_s 		(void) fprintf(stderr, "%s: can't allocate %d bytes\n",
56492ed1782Smike_s 		    cmdname, strlen(pathname) + 1);
5657c478bd9Sstevel@tonic-gate 		exit(ERR_MEMORY);
5667c478bd9Sstevel@tonic-gate 	}
56792ed1782Smike_s 	(void) strcpy(mi->path, pathname);
5687c478bd9Sstevel@tonic-gate 	mi->next = NULL;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	get_syms(pathname, mi);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	/* and fill in info... */
5737c478bd9Sstevel@tonic-gate 	mi->id = n_modules + 1;
5747c478bd9Sstevel@tonic-gate 	mi->load_base = ld_base;
5757c478bd9Sstevel@tonic-gate 	mi->load_end = ld_end;
5767c478bd9Sstevel@tonic-gate 	mi->active = TRUE;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	n_modules++;
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	return (mi);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate /*
5847c478bd9Sstevel@tonic-gate  * Two modules overlap each other if they don't lie completely *outside*
5857c478bd9Sstevel@tonic-gate  * each other.
5867c478bd9Sstevel@tonic-gate  */
5877c478bd9Sstevel@tonic-gate static bool
does_overlap(ProfModule * new,mod_info_t * old)58892ed1782Smike_s does_overlap(ProfModule *new, mod_info_t *old)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	/* case 1: new module lies completely *before* the old one */
5917c478bd9Sstevel@tonic-gate 	if (new->startaddr < old->load_base && new->endaddr <= old->load_base)
5927c478bd9Sstevel@tonic-gate 		return (FALSE);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	/* case 2: new module lies completely *after* the old one */
5957c478bd9Sstevel@tonic-gate 	if (new->startaddr >= old->load_end && new->endaddr >= old->load_end)
5967c478bd9Sstevel@tonic-gate 		return (FALSE);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	/* probably a dlopen: the modules overlap each other */
5997c478bd9Sstevel@tonic-gate 	return (TRUE);
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate static bool
is_same_as_aout(char * modpath,struct stat * buf)60392ed1782Smike_s is_same_as_aout(char *modpath, struct stat *buf)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	if (stat(modpath, buf) == -1) {
6067c478bd9Sstevel@tonic-gate 		perror(modpath);
6077c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	if ((buf->st_dev == aout_stat.st_dev) &&
6117c478bd9Sstevel@tonic-gate 	    (buf->st_ino == aout_stat.st_ino)) {
6127c478bd9Sstevel@tonic-gate 		return (TRUE);
6137c478bd9Sstevel@tonic-gate 	} else
6147c478bd9Sstevel@tonic-gate 		return (FALSE);
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate static void
process_modules(ProfModuleList * modlp)61892ed1782Smike_s process_modules(ProfModuleList *modlp)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate 	ProfModule	*newmodp;
6217c478bd9Sstevel@tonic-gate 	mod_info_t	*mi, *last, *new_module;
6227c478bd9Sstevel@tonic-gate 	char		*so_path;
6237c478bd9Sstevel@tonic-gate 	bool		more_modules = TRUE;
6247c478bd9Sstevel@tonic-gate 	struct stat	so_statbuf;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	/* Check version of module type object */
6277c478bd9Sstevel@tonic-gate 	if (modlp->version > PROF_MODULES_VER) {
62892ed1782Smike_s 		(void) fprintf(stderr,
62992ed1782Smike_s 		    "%s: unsupported version %d for modules\n",
6307c478bd9Sstevel@tonic-gate 		    cmdname, modlp->version);
6317c478bd9Sstevel@tonic-gate 		exit(ERR_INPUT);
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	/*
6367c478bd9Sstevel@tonic-gate 	 * Scan the PROF_MODULES_T list and add modules to current list
6377c478bd9Sstevel@tonic-gate 	 * of modules, if they're not present already
6387c478bd9Sstevel@tonic-gate 	 */
63992ed1782Smike_s 	/* LINTED: pointer cast */
6407c478bd9Sstevel@tonic-gate 	newmodp = (ProfModule *)((caddr_t)modlp + modlp->modules);
6417c478bd9Sstevel@tonic-gate 	do {
6427c478bd9Sstevel@tonic-gate 		/*
6437c478bd9Sstevel@tonic-gate 		 * Since the aout could've been renamed after its run, we
6447c478bd9Sstevel@tonic-gate 		 * should see if current module overlaps aout. If it does, it
6457c478bd9Sstevel@tonic-gate 		 * is probably the renamed aout. We should also skip any other
6467c478bd9Sstevel@tonic-gate 		 * non-sharedobj's that we see (or should we report an error ?)
6477c478bd9Sstevel@tonic-gate 		 */
6487c478bd9Sstevel@tonic-gate 		so_path = (caddr_t)modlp + newmodp->path;
6497c478bd9Sstevel@tonic-gate 		if (does_overlap(newmodp, &modules) ||
6507c478bd9Sstevel@tonic-gate 		    is_same_as_aout(so_path, &so_statbuf) ||
6517c478bd9Sstevel@tonic-gate 		    (!is_shared_obj(so_path))) {
6527c478bd9Sstevel@tonic-gate 			if (!newmodp->next)
6537c478bd9Sstevel@tonic-gate 				more_modules = FALSE;
6547c478bd9Sstevel@tonic-gate 
65592ed1782Smike_s 			/* LINTED: pointer cast */
6567c478bd9Sstevel@tonic-gate 			newmodp = (ProfModule *)
6577c478bd9Sstevel@tonic-gate 			    ((caddr_t)modlp + newmodp->next);
6587c478bd9Sstevel@tonic-gate 			continue;
6597c478bd9Sstevel@tonic-gate 		}
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		/*
6627c478bd9Sstevel@tonic-gate 		 * Check all modules (leave the first one, 'cos that
6637c478bd9Sstevel@tonic-gate 		 * is the program executable info). If this module is already
6647c478bd9Sstevel@tonic-gate 		 * there in the list, skip it.
6657c478bd9Sstevel@tonic-gate 		 */
6667c478bd9Sstevel@tonic-gate 		last = &modules;
66792ed1782Smike_s 		while ((mi = last->next) != NULL) {
6687c478bd9Sstevel@tonic-gate 			/*
6697c478bd9Sstevel@tonic-gate 			 * We expect the full pathname for all shared objects
6707c478bd9Sstevel@tonic-gate 			 * needed by the program executable. In this case, we
6717c478bd9Sstevel@tonic-gate 			 * simply need to compare the paths to see if they are
6727c478bd9Sstevel@tonic-gate 			 * the same file.
6737c478bd9Sstevel@tonic-gate 			 */
6747c478bd9Sstevel@tonic-gate 			if (strcmp(mi->path, so_path) == 0)
6757c478bd9Sstevel@tonic-gate 				break;
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 			/*
6787c478bd9Sstevel@tonic-gate 			 * Check if this new shared object will overlap any
6797c478bd9Sstevel@tonic-gate 			 * existing module. If yes, deactivate the old one.
6807c478bd9Sstevel@tonic-gate 			 */
6817c478bd9Sstevel@tonic-gate 			if (does_overlap(newmodp, mi))
6827c478bd9Sstevel@tonic-gate 				mi->active = FALSE;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 			last = mi;
6857c478bd9Sstevel@tonic-gate 		}
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 		/* Module already there, skip it */
6887c478bd9Sstevel@tonic-gate 		if (mi != NULL) {
6897c478bd9Sstevel@tonic-gate 			mi->load_base = newmodp->startaddr;
6907c478bd9Sstevel@tonic-gate 			mi->load_end = newmodp->endaddr;
6917c478bd9Sstevel@tonic-gate 			mi->active = TRUE;
6927c478bd9Sstevel@tonic-gate 			if (!newmodp->next)
6937c478bd9Sstevel@tonic-gate 				more_modules = FALSE;
6947c478bd9Sstevel@tonic-gate 
69592ed1782Smike_s 			/* LINTED: pointer cast */
6967c478bd9Sstevel@tonic-gate 			newmodp = (ProfModule *)
6977c478bd9Sstevel@tonic-gate 			    ((caddr_t)modlp + newmodp->next);
6987c478bd9Sstevel@tonic-gate 			continue;
6997c478bd9Sstevel@tonic-gate 		}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 		/*
7027c478bd9Sstevel@tonic-gate 		 * Check if mon.out is outdated with respect to the new
7037c478bd9Sstevel@tonic-gate 		 * module we want to add
7047c478bd9Sstevel@tonic-gate 		 */
7057c478bd9Sstevel@tonic-gate 		if (monout_stat.st_mtime < so_statbuf.st_mtime) {
70692ed1782Smike_s 			(void) fprintf(stderr,
70792ed1782Smike_s 			    "%s: newer shared obj %s outdates profile info\n",
70892ed1782Smike_s 			    cmdname, so_path);
7097c478bd9Sstevel@tonic-gate 			exit(ERR_INPUT);
7107c478bd9Sstevel@tonic-gate 		}
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 		/* Create this module's nameslist */
7137c478bd9Sstevel@tonic-gate 		new_module = get_shobj_syms(so_path,
7147c478bd9Sstevel@tonic-gate 		    newmodp->startaddr, newmodp->endaddr);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		/* Add it to the tail of active module list */
7177c478bd9Sstevel@tonic-gate 		last->next = new_module;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 		/*
7207c478bd9Sstevel@tonic-gate 		 * Move to the next module in the PROF_MODULES_T list
7217c478bd9Sstevel@tonic-gate 		 * (if present)
7227c478bd9Sstevel@tonic-gate 		 */
7237c478bd9Sstevel@tonic-gate 		if (!newmodp->next)
7247c478bd9Sstevel@tonic-gate 			more_modules = FALSE;
7257c478bd9Sstevel@tonic-gate 
72692ed1782Smike_s 		/* LINTED: pointer cast */
7277c478bd9Sstevel@tonic-gate 		newmodp = (ProfModule *)((caddr_t)modlp + newmodp->next);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	} while (more_modules);
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate static void
process_mon_out(caddr_t memp,size_t fsz)7337c478bd9Sstevel@tonic-gate process_mon_out(caddr_t memp, size_t fsz)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	ProfObject	*objp;
7367c478bd9Sstevel@tonic-gate 	caddr_t		file_end;
7377c478bd9Sstevel@tonic-gate 	bool		found_pcsamples = FALSE, found_cgraph = FALSE;
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	/*
7407c478bd9Sstevel@tonic-gate 	 * Save file end pointer and start after header
7417c478bd9Sstevel@tonic-gate 	 */
7427c478bd9Sstevel@tonic-gate 	file_end = memp + fsz;
74392ed1782Smike_s 	/* LINTED: pointer cast */
7447c478bd9Sstevel@tonic-gate 	objp = (ProfObject *)(memp + ((ProfHeader *)memp)->size);
7457c478bd9Sstevel@tonic-gate 	while ((caddr_t)objp < file_end) {
7467c478bd9Sstevel@tonic-gate 		switch (objp->type) {
7477c478bd9Sstevel@tonic-gate 			case PROF_MODULES_T :
7487c478bd9Sstevel@tonic-gate 				process_modules((ProfModuleList *)objp);
7497c478bd9Sstevel@tonic-gate 				break;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 			case PROF_CALLGRAPH_T :
7527c478bd9Sstevel@tonic-gate 				process_cgraph((ProfCallGraph *)objp);
7537c478bd9Sstevel@tonic-gate 				found_cgraph = TRUE;
7547c478bd9Sstevel@tonic-gate 				break;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 			case PROF_BUFFER_T :
7577c478bd9Sstevel@tonic-gate 				process_pcsamples((ProfBuffer *)objp);
7587c478bd9Sstevel@tonic-gate 				found_pcsamples = TRUE;
7597c478bd9Sstevel@tonic-gate 				break;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 			default :
76292ed1782Smike_s 				(void) fprintf(stderr,
7637c478bd9Sstevel@tonic-gate 				    "%s: unknown prof object type=%d\n",
7647c478bd9Sstevel@tonic-gate 				    cmdname, objp->type);
7657c478bd9Sstevel@tonic-gate 				exit(ERR_INPUT);
7667c478bd9Sstevel@tonic-gate 		}
76792ed1782Smike_s 		/* LINTED: pointer cast */
7687c478bd9Sstevel@tonic-gate 		objp = (ProfObject *)((caddr_t)objp + objp->size);
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	if (!found_cgraph || !found_pcsamples) {
77292ed1782Smike_s 		(void) fprintf(stderr,
77392ed1782Smike_s 		    "%s: missing callgraph/pcsamples in `%s'\n",
7747c478bd9Sstevel@tonic-gate 		    cmdname, mon_fn);
7757c478bd9Sstevel@tonic-gate 		exit(ERR_INPUT);
7767c478bd9Sstevel@tonic-gate 	}
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	if ((caddr_t)objp > file_end) {
77992ed1782Smike_s 		(void) fprintf(stderr, "%s: malformed file `%s'\n",
78092ed1782Smike_s 		    cmdname, mon_fn);
7817c478bd9Sstevel@tonic-gate 		exit(ERR_INPUT);
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate static void
get_aout_syms(char * pathname,mod_info_t * mi)7867c478bd9Sstevel@tonic-gate get_aout_syms(char *pathname, mod_info_t *mi)
7877c478bd9Sstevel@tonic-gate {
78892ed1782Smike_s 	mi->path = malloc(strlen(pathname) + 1);
7897c478bd9Sstevel@tonic-gate 	if (mi->path == NULL) {
79092ed1782Smike_s 		(void) fprintf(stderr, "%s: can't allocate %d bytes\n",
79192ed1782Smike_s 		    cmdname, strlen(pathname) + 1);
7927c478bd9Sstevel@tonic-gate 		exit(ERR_MEMORY);
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 
79592ed1782Smike_s 	(void) strcpy(mi->path, pathname);
7967c478bd9Sstevel@tonic-gate 	mi->next = NULL;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	get_syms(pathname, mi);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	mi->id = 1;
8017c478bd9Sstevel@tonic-gate 	mi->load_base = mi->txt_origin;
8027c478bd9Sstevel@tonic-gate 	mi->load_end = mi->data_end;
8037c478bd9Sstevel@tonic-gate 	mi->active = TRUE;
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate void
profver(void)80792ed1782Smike_s profver(void)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate 	int		fd;
8107c478bd9Sstevel@tonic-gate 	unsigned int	magic_num;
8117c478bd9Sstevel@tonic-gate 	bool		invalid_version;
8127c478bd9Sstevel@tonic-gate 	caddr_t		fmem;
8137c478bd9Sstevel@tonic-gate 	ProfHeader	prof_hdr;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	/*
8167c478bd9Sstevel@tonic-gate 	 * Check the magic and see if this is versioned or *old-style*
8177c478bd9Sstevel@tonic-gate 	 * mon.out.
8187c478bd9Sstevel@tonic-gate 	 */
8197c478bd9Sstevel@tonic-gate 	if ((fd = open(mon_fn, O_RDONLY)) == -1) {
8207c478bd9Sstevel@tonic-gate 		perror(mon_fn);
8217c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
8227c478bd9Sstevel@tonic-gate 	}
8237c478bd9Sstevel@tonic-gate 	if (read(fd, (char *)&magic_num, sizeof (unsigned int)) == -1) {
8247c478bd9Sstevel@tonic-gate 		perror("read");
8257c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
8267c478bd9Sstevel@tonic-gate 	}
8277c478bd9Sstevel@tonic-gate 	if (magic_num != (unsigned int) PROF_MAGIC) {
82892ed1782Smike_s 		(void) close(fd);
8297c478bd9Sstevel@tonic-gate 		return;
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	/*
8357c478bd9Sstevel@tonic-gate 	 * Check versioning info. For now, let's say we provide
8367c478bd9Sstevel@tonic-gate 	 * backward compatibility, so we accept all older versions.
8377c478bd9Sstevel@tonic-gate 	 */
83892ed1782Smike_s 	(void) lseek(fd, 0L, SEEK_SET);
8397c478bd9Sstevel@tonic-gate 	if (read(fd, (char *)&prof_hdr, sizeof (ProfHeader)) == -1) {
8407c478bd9Sstevel@tonic-gate 		perror("read");
8417c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 	invalid_version = FALSE;
8447c478bd9Sstevel@tonic-gate 	if (prof_hdr.h_major_ver > PROF_MAJOR_VERSION)
8457c478bd9Sstevel@tonic-gate 		invalid_version = TRUE;
8467c478bd9Sstevel@tonic-gate 	else if (prof_hdr.h_major_ver == PROF_MAJOR_VERSION) {
8477c478bd9Sstevel@tonic-gate 		if (prof_hdr.h_minor_ver > PROF_MINOR_VERSION)
8487c478bd9Sstevel@tonic-gate 		invalid_version = FALSE;
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 	if (invalid_version) {
85192ed1782Smike_s 		(void) fprintf(stderr,
85292ed1782Smike_s 		    "%s: mon.out version %d.%d not supported\n",
8537c478bd9Sstevel@tonic-gate 		    cmdname, prof_hdr.h_major_ver, prof_hdr.h_minor_ver);
8547c478bd9Sstevel@tonic-gate 		exit(ERR_INPUT);
8557c478bd9Sstevel@tonic-gate 	}
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	/*
8607c478bd9Sstevel@tonic-gate 	 * Map mon.out onto memory.
8617c478bd9Sstevel@tonic-gate 	 */
8627c478bd9Sstevel@tonic-gate 	if (stat(mon_fn, &monout_stat) == -1) {
8637c478bd9Sstevel@tonic-gate 		perror(mon_fn);
8647c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 	if ((fmem = mmap(0, monout_stat.st_size,
8677c478bd9Sstevel@tonic-gate 	    PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
8687c478bd9Sstevel@tonic-gate 		perror("mmap");
8697c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
8707c478bd9Sstevel@tonic-gate 	}
87192ed1782Smike_s 	(void) close(fd);
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	/*
8757c478bd9Sstevel@tonic-gate 	 * Now, read program executable's symbol table. Also save it's
8767c478bd9Sstevel@tonic-gate 	 * stat in aout_stat for use while processing mon.out
8777c478bd9Sstevel@tonic-gate 	 */
8787c478bd9Sstevel@tonic-gate 	if (stat(sym_fn, &aout_stat) == -1) {
8797c478bd9Sstevel@tonic-gate 		perror(sym_fn);
8807c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
8817c478bd9Sstevel@tonic-gate 	}
8827c478bd9Sstevel@tonic-gate 	get_aout_syms(sym_fn, &modules);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	/*
8857c478bd9Sstevel@tonic-gate 	 * Process the mon.out, all shared objects it references
8867c478bd9Sstevel@tonic-gate 	 * and collect statistics on ticks spent in each function,
8877c478bd9Sstevel@tonic-gate 	 * number of calls, etc.
8887c478bd9Sstevel@tonic-gate 	 */
8897c478bd9Sstevel@tonic-gate 	process_mon_out(fmem, monout_stat.st_size);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	/*
8927c478bd9Sstevel@tonic-gate 	 * Based on the flags and the statistics we've got, create
8937c478bd9Sstevel@tonic-gate 	 * a list of relevant symbols whose profiling details should
8947c478bd9Sstevel@tonic-gate 	 * be printed
8957c478bd9Sstevel@tonic-gate 	 */
8967c478bd9Sstevel@tonic-gate 	collect_profsyms();
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	/*
8997c478bd9Sstevel@tonic-gate 	 * Check for duplicate names in output. We need to print the
9007c478bd9Sstevel@tonic-gate 	 * module id's if verbose. Also, if we are sorting by name anyway,
9017c478bd9Sstevel@tonic-gate 	 * we don't need to check for duplicates here. We'll do that later.
9027c478bd9Sstevel@tonic-gate 	 */
9037c478bd9Sstevel@tonic-gate 	if ((flags & F_VERBOSE) && (sort_flag != BY_NAME))
9047c478bd9Sstevel@tonic-gate 		check_dupnames();
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	/*
9077c478bd9Sstevel@tonic-gate 	 * Print output
9087c478bd9Sstevel@tonic-gate 	 */
9097c478bd9Sstevel@tonic-gate 	print_profile_data();
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 
91292ed1782Smike_s 	(void) munmap(fmem, monout_stat.st_size);
9137c478bd9Sstevel@tonic-gate 	exit(0);
9147c478bd9Sstevel@tonic-gate }
915