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