10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7008Sab196087 * Common Development and Distribution License (the "License").
6*7008Sab196087 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21211Smike_s
220Sstevel@tonic-gate /*
23*7008Sab196087 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24211Smike_s * Use is subject to license terms.
250Sstevel@tonic-gate */
26211Smike_s
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * All routines in this file are for processing new-style, *versioned*
310Sstevel@tonic-gate * mon.out format. Together with rdelf.c, lookup.c and profv.h, these
320Sstevel@tonic-gate * form the complete set of files to profile new-style mon.out files.
330Sstevel@tonic-gate */
340Sstevel@tonic-gate
35211Smike_s #include <stdlib.h>
36211Smike_s #include <string.h>
37*7008Sab196087 #include "conv.h"
380Sstevel@tonic-gate #include "profv.h"
390Sstevel@tonic-gate
400Sstevel@tonic-gate bool time_in_ticks = FALSE;
410Sstevel@tonic-gate size_t n_pcsamples, n_accounted_ticks, n_zeros, total_funcs;
420Sstevel@tonic-gate unsigned char sort_flag;
430Sstevel@tonic-gate
440Sstevel@tonic-gate mod_info_t modules;
450Sstevel@tonic-gate size_t n_modules = 1; /* always include the aout object */
460Sstevel@tonic-gate
470Sstevel@tonic-gate struct stat aout_stat, monout_stat;
480Sstevel@tonic-gate profrec_t *profsym;
490Sstevel@tonic-gate
500Sstevel@tonic-gate int
cmp_by_name(const void * arg1,const void * arg2)51211Smike_s cmp_by_name(const void *arg1, const void *arg2)
520Sstevel@tonic-gate {
53211Smike_s profrec_t *a = (profrec_t *)arg1;
54211Smike_s profrec_t *b = (profrec_t *)arg2;
55211Smike_s
560Sstevel@tonic-gate return (strcmp(a->demangled_name, b->demangled_name));
570Sstevel@tonic-gate }
580Sstevel@tonic-gate
590Sstevel@tonic-gate static void
setup_demangled_names(void)60211Smike_s setup_demangled_names(void)
610Sstevel@tonic-gate {
62*7008Sab196087 const char *p;
63*7008Sab196087 char *nbp, *nbe, *namebuf;
64211Smike_s size_t cur_len = 0, namebuf_sz = BUCKET_SZ;
65211Smike_s size_t i, namelen;
660Sstevel@tonic-gate
67211Smike_s if ((namebuf = malloc(namebuf_sz)) == NULL) {
68211Smike_s (void) fprintf(stderr, "%s: can't allocate %d bytes\n",
69*7008Sab196087 cmdname, namebuf_sz);
700Sstevel@tonic-gate exit(ERR_MEMORY);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate
730Sstevel@tonic-gate nbp = namebuf;
740Sstevel@tonic-gate nbe = namebuf + namebuf_sz;
750Sstevel@tonic-gate
760Sstevel@tonic-gate for (i = 0; i < total_funcs; i++) {
77*7008Sab196087 if ((p = conv_demangle_name(profsym[i].name)) == NULL)
780Sstevel@tonic-gate continue;
790Sstevel@tonic-gate
800Sstevel@tonic-gate namelen = strlen(p);
810Sstevel@tonic-gate if ((nbp + namelen + 1) > nbe) {
820Sstevel@tonic-gate namebuf_sz += BUCKET_SZ;
83211Smike_s namebuf = realloc(namebuf, namebuf_sz);
840Sstevel@tonic-gate if (namebuf == NULL) {
85211Smike_s (void) fprintf(stderr,
86211Smike_s "%s: can't alloc %d bytes\n",
87211Smike_s cmdname, BUCKET_SZ);
880Sstevel@tonic-gate exit(ERR_MEMORY);
890Sstevel@tonic-gate }
900Sstevel@tonic-gate
910Sstevel@tonic-gate nbp = namebuf + cur_len;
920Sstevel@tonic-gate nbe = namebuf + namebuf_sz;
930Sstevel@tonic-gate }
940Sstevel@tonic-gate
95211Smike_s (void) strcpy(nbp, p);
960Sstevel@tonic-gate profsym[i].demangled_name = nbp;
970Sstevel@tonic-gate
980Sstevel@tonic-gate nbp += namelen + 1;
990Sstevel@tonic-gate cur_len += namelen + 1;
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate int
cmp_by_time(const void * arg1,const void * arg2)104211Smike_s cmp_by_time(const void *arg1, const void *arg2)
1050Sstevel@tonic-gate {
106211Smike_s profrec_t *a = (profrec_t *)arg1;
107211Smike_s profrec_t *b = (profrec_t *)arg2;
108211Smike_s
1090Sstevel@tonic-gate if (a->percent_time > b->percent_time)
1100Sstevel@tonic-gate return (-1);
1110Sstevel@tonic-gate else if (a->percent_time < b->percent_time)
1120Sstevel@tonic-gate return (1);
1130Sstevel@tonic-gate else
1140Sstevel@tonic-gate return (0);
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate int
cmp_by_ncalls(const void * arg1,const void * arg2)118211Smike_s cmp_by_ncalls(const void *arg1, const void *arg2)
1190Sstevel@tonic-gate {
120211Smike_s profrec_t *a = (profrec_t *)arg1;
121211Smike_s profrec_t *b = (profrec_t *)arg2;
122211Smike_s
1230Sstevel@tonic-gate if (a->ncalls > b->ncalls)
1240Sstevel@tonic-gate return (-1);
1250Sstevel@tonic-gate else if (a->ncalls < b->ncalls)
1260Sstevel@tonic-gate return (1);
1270Sstevel@tonic-gate else
1280Sstevel@tonic-gate return (0);
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate static void
print_profile_data(void)133211Smike_s print_profile_data(void)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate int i;
136211Smike_s int (*sort_func)(const void *, const void *);
1370Sstevel@tonic-gate mod_info_t *mi;
1380Sstevel@tonic-gate double cumsecs = 0;
1390Sstevel@tonic-gate char filler[20];
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate /*
1420Sstevel@tonic-gate * Sort the compiled data; the sort flags are mutually exclusive.
1430Sstevel@tonic-gate */
1440Sstevel@tonic-gate switch (sort_flag) {
1450Sstevel@tonic-gate case BY_NCALLS:
1460Sstevel@tonic-gate sort_func = cmp_by_ncalls;
1470Sstevel@tonic-gate break;
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate case BY_NAME:
1500Sstevel@tonic-gate if (Cflag)
1510Sstevel@tonic-gate setup_demangled_names();
1520Sstevel@tonic-gate sort_func = cmp_by_name;
1530Sstevel@tonic-gate break;
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate case BY_ADDRESS:
1560Sstevel@tonic-gate sort_flag |= BY_ADDRESS;
1570Sstevel@tonic-gate sort_func = NULL; /* already sorted by addr */
1580Sstevel@tonic-gate break;
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate case BY_TIME: /* default is to sort by time */
1610Sstevel@tonic-gate default:
1620Sstevel@tonic-gate sort_func = cmp_by_time;
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate if (sort_func) {
167211Smike_s qsort(profsym, total_funcs, sizeof (profrec_t), sort_func);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate * If we're sorting by name, and if it is a verbose print, we wouldn't
1720Sstevel@tonic-gate * have set up the print_mid fields yet.
1730Sstevel@tonic-gate */
1740Sstevel@tonic-gate if ((flags & F_VERBOSE) && (sort_flag == BY_NAME)) {
1750Sstevel@tonic-gate for (i = 0; i < total_funcs; i++) {
1760Sstevel@tonic-gate /*
1770Sstevel@tonic-gate * same as previous or next (if there's one) ?
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate if (i && (strcmp(profsym[i].demangled_name,
180*7008Sab196087 profsym[i-1].demangled_name) == 0)) {
1810Sstevel@tonic-gate profsym[i].print_mid = TRUE;
1820Sstevel@tonic-gate } else if ((i < (total_funcs - 1)) &&
183*7008Sab196087 (strcmp(profsym[i].demangled_name,
184*7008Sab196087 profsym[i+1].demangled_name) == 0)) {
1850Sstevel@tonic-gate profsym[i].print_mid = TRUE;
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate * The actual printing part.
1920Sstevel@tonic-gate */
1930Sstevel@tonic-gate if (!(flags & F_NHEAD)) {
1940Sstevel@tonic-gate if (flags & F_PADDR)
195211Smike_s (void) printf(" %s", atitle);
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate if (time_in_ticks)
198211Smike_s (void) puts(
199211Smike_s " %Time Tiks Cumtiks #Calls tiks/call Name");
2000Sstevel@tonic-gate else
201211Smike_s (void) puts(
202211Smike_s " %Time Seconds Cumsecs #Calls msec/call Name");
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate mi = NULL;
2060Sstevel@tonic-gate for (i = 0; i < total_funcs; i++) {
2070Sstevel@tonic-gate /*
2080Sstevel@tonic-gate * Since the same value may denote different symbols in
2090Sstevel@tonic-gate * different shared objects, it is debatable if it is
2100Sstevel@tonic-gate * meaningful to print addresses at all. Especially so
2110Sstevel@tonic-gate * if we were asked to sort by symbol addresses.
2120Sstevel@tonic-gate *
2130Sstevel@tonic-gate * If we've to sort by address, I think it is better to sort
2140Sstevel@tonic-gate * it on a per-module basis and if verbose mode is on too,
2150Sstevel@tonic-gate * print a newline to separate out modules.
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate if ((flags & F_VERBOSE) && (sort_flag == BY_ADDRESS)) {
2180Sstevel@tonic-gate if (mi != profsym[i].module) {
219211Smike_s (void) printf("\n");
2200Sstevel@tonic-gate mi = profsym[i].module;
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate if (flags & F_PADDR) {
2250Sstevel@tonic-gate if (aformat[2] == 'x')
226211Smike_s (void) printf("%16llx ", profsym[i].addr);
2270Sstevel@tonic-gate else
228211Smike_s (void) printf("%16llo ", profsym[i].addr);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate cumsecs += profsym[i].seconds;
232211Smike_s (void) printf("%6.1f%8.2f%8.2f", profsym[i].percent_time,
233*7008Sab196087 profsym[i].seconds, cumsecs);
2340Sstevel@tonic-gate
235211Smike_s (void) printf("%8d%12.4f ",
236*7008Sab196087 profsym[i].ncalls, profsym[i].msecs_per_call);
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate if (profsym[i].print_mid)
239211Smike_s (void) printf("%d:", (profsym[i].module)->id);
2400Sstevel@tonic-gate
241211Smike_s (void) printf("%s\n", profsym[i].demangled_name);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate if (flags & F_PADDR)
245211Smike_s (void) sprintf(filler, "%16s", "");
2460Sstevel@tonic-gate else
2470Sstevel@tonic-gate filler[0] = 0;
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate if (flags & F_VERBOSE) {
250211Smike_s (void) puts("\n");
251211Smike_s (void) printf("%s Total Object Modules %7d\n",
252*7008Sab196087 filler, n_modules);
253211Smike_s (void) printf("%s Qualified Symbols %7d\n",
254*7008Sab196087 filler, total_funcs);
255211Smike_s (void) printf("%s Symbols with zero usage %7d\n",
256*7008Sab196087 filler, n_zeros);
257211Smike_s (void) printf("%s Total pc-hits %7d\n",
258*7008Sab196087 filler, n_pcsamples);
259211Smike_s (void) printf("%s Accounted pc-hits %7d\n",
260*7008Sab196087 filler, n_accounted_ticks);
2610Sstevel@tonic-gate if ((!gflag) && (n_pcsamples - n_accounted_ticks)) {
262211Smike_s (void) printf("%s Missed pc-hits (try -g) %7d\n\n",
263*7008Sab196087 filler, n_pcsamples - n_accounted_ticks);
2640Sstevel@tonic-gate } else {
265211Smike_s (void) printf("%s Missed pc-hits %7d\n\n",
266*7008Sab196087 filler, n_pcsamples - n_accounted_ticks);
2670Sstevel@tonic-gate }
268211Smike_s (void) printf("%s Module info\n", filler);
2690Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next)
270211Smike_s (void) printf("%s %d: `%s'\n", filler,
271211Smike_s mi->id, mi->path);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate int
name_cmp(const void * arg1,const void * arg2)276211Smike_s name_cmp(const void *arg1, const void *arg2)
2770Sstevel@tonic-gate {
278211Smike_s profnames_t *a = (profnames_t *)arg1;
279211Smike_s profnames_t *b = (profnames_t *)arg2;
280211Smike_s
2810Sstevel@tonic-gate return (strcmp(a->name, b->name));
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate static void
check_dupnames(void)285211Smike_s check_dupnames(void)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate int i;
2880Sstevel@tonic-gate profnames_t *pn;
2890Sstevel@tonic-gate
290211Smike_s pn = calloc(total_funcs, sizeof (profnames_t));
2910Sstevel@tonic-gate if (pn == NULL) {
292211Smike_s (void) fprintf(stderr, "%s: no room for %d bytes\n",
293211Smike_s cmdname, total_funcs * sizeof (profnames_t));
2940Sstevel@tonic-gate exit(ERR_MEMORY);
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate for (i = 0; i < total_funcs; i++) {
2980Sstevel@tonic-gate pn[i].name = profsym[i].demangled_name;
2990Sstevel@tonic-gate pn[i].pfrec = &profsym[i];
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate
302211Smike_s qsort(pn, total_funcs, sizeof (profnames_t), name_cmp);
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate for (i = 0; i < total_funcs; i++) {
3050Sstevel@tonic-gate /*
3060Sstevel@tonic-gate * same as previous or next (if there's one) ?
3070Sstevel@tonic-gate */
3080Sstevel@tonic-gate if (i && (strcmp(pn[i].name, pn[i-1].name) == 0))
3090Sstevel@tonic-gate (pn[i].pfrec)->print_mid = TRUE;
3100Sstevel@tonic-gate else if ((i < (total_funcs - 1)) &&
311*7008Sab196087 (strcmp(pn[i].name, pn[i+1].name) == 0)) {
3120Sstevel@tonic-gate (pn[i].pfrec)->print_mid = TRUE;
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate free(pn);
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate static void
compute_times(nltype * nl,profrec_t * psym)3200Sstevel@tonic-gate compute_times(nltype *nl, profrec_t *psym)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate static int first_time = TRUE;
3230Sstevel@tonic-gate static long hz;
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate if (first_time) {
3260Sstevel@tonic-gate if ((hz = sysconf(_SC_CLK_TCK)) == -1)
3270Sstevel@tonic-gate time_in_ticks = TRUE;
3280Sstevel@tonic-gate first_time = FALSE;
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate if (time_in_ticks) {
332211Smike_s psym->seconds = (double)nl->nticks;
3330Sstevel@tonic-gate if (nl->ncalls) {
334*7008Sab196087 psym->msecs_per_call = (double)nl->nticks /
335*7008Sab196087 (double)nl->ncalls;
3360Sstevel@tonic-gate } else
337*7008Sab196087 psym->msecs_per_call = (double)0.0;
3380Sstevel@tonic-gate } else {
339211Smike_s psym->seconds = (double)nl->nticks / (double)hz;
3400Sstevel@tonic-gate if (nl->ncalls) {
341211Smike_s psym->msecs_per_call =
342211Smike_s ((double)psym->seconds * 1000.0) /
343211Smike_s (double)nl->ncalls;
3440Sstevel@tonic-gate } else
345211Smike_s psym->msecs_per_call = (double)0.0;
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate if (n_pcsamples) {
349211Smike_s psym->percent_time =
350211Smike_s ((double)nl->nticks / (double)n_pcsamples) * 100;
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate static void
collect_profsyms(void)355211Smike_s collect_profsyms(void)
3560Sstevel@tonic-gate {
3570Sstevel@tonic-gate mod_info_t *mi;
3580Sstevel@tonic-gate nltype *nl;
3590Sstevel@tonic-gate size_t i, ndx;
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next)
3630Sstevel@tonic-gate total_funcs += mi->nfuncs;
3640Sstevel@tonic-gate
365211Smike_s profsym = calloc(total_funcs, sizeof (profrec_t));
3660Sstevel@tonic-gate if (profsym == NULL) {
367211Smike_s (void) fprintf(stderr, "%s: no room for %d bytes\n",
368211Smike_s cmdname, total_funcs * sizeof (profrec_t));
3690Sstevel@tonic-gate exit(ERR_MEMORY);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate ndx = 0;
3730Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) {
3740Sstevel@tonic-gate nl = mi->nl;
3750Sstevel@tonic-gate for (i = 0; i < mi->nfuncs; i++) {
3760Sstevel@tonic-gate /*
3770Sstevel@tonic-gate * I think F_ZSYMS doesn't make sense for the new
3780Sstevel@tonic-gate * mon.out format, since we don't have a profiling
3790Sstevel@tonic-gate * *range*, per se. But the man page demands it,
3800Sstevel@tonic-gate * so...
3810Sstevel@tonic-gate */
3820Sstevel@tonic-gate if ((nl[i].ncalls == 0) && (nl[i].nticks == 0)) {
3830Sstevel@tonic-gate n_zeros++;
3840Sstevel@tonic-gate if (!(flags & F_ZSYMS))
3850Sstevel@tonic-gate continue;
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate /*
3890Sstevel@tonic-gate * Initially, we set demangled_name to be
3900Sstevel@tonic-gate * the same as name. If Cflag is set, we later
3910Sstevel@tonic-gate * change this to be the demangled name ptr.
3920Sstevel@tonic-gate */
3930Sstevel@tonic-gate profsym[ndx].addr = nl[i].value;
3940Sstevel@tonic-gate profsym[ndx].ncalls = nl[i].ncalls;
3950Sstevel@tonic-gate profsym[ndx].name = nl[i].name;
3960Sstevel@tonic-gate profsym[ndx].demangled_name = nl[i].name;
3970Sstevel@tonic-gate profsym[ndx].module = mi;
3980Sstevel@tonic-gate profsym[ndx].print_mid = FALSE;
3990Sstevel@tonic-gate compute_times(&nl[i], &profsym[ndx]);
4000Sstevel@tonic-gate ndx++;
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate /*
4050Sstevel@tonic-gate * Adjust total_funcs to actual printable funcs
4060Sstevel@tonic-gate */
4070Sstevel@tonic-gate total_funcs = ndx;
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate static void
assign_pcsamples(mod_info_t * module,Address * pcsmpl,size_t n_samples)411211Smike_s assign_pcsamples(mod_info_t *module, Address *pcsmpl,
412211Smike_s size_t n_samples)
4130Sstevel@tonic-gate {
4140Sstevel@tonic-gate Address *pcptr, *pcse = pcsmpl + n_samples;
4150Sstevel@tonic-gate Address nxt_func;
4160Sstevel@tonic-gate nltype *nl;
4170Sstevel@tonic-gate size_t nticks;
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate /* Locate the first pc-hit for this module */
4200Sstevel@tonic-gate if ((pcptr = locate(pcsmpl, n_samples, module->load_base)) == NULL)
4210Sstevel@tonic-gate return; /* no pc-hits in this module */
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate /* Assign all pc-hits in this module to appropriate functions */
4240Sstevel@tonic-gate while ((pcptr < pcse) && (*pcptr < module->load_end)) {
4250Sstevel@tonic-gate
4260Sstevel@tonic-gate /* Update the corresponding function's time */
4270Sstevel@tonic-gate if (nl = nllookup(module, *pcptr, &nxt_func)) {
4280Sstevel@tonic-gate /*
4290Sstevel@tonic-gate * Collect all pc-hits in this function. Each
4300Sstevel@tonic-gate * pc-hit counts as 1 tick.
4310Sstevel@tonic-gate */
4320Sstevel@tonic-gate nticks = 0;
4330Sstevel@tonic-gate while ((pcptr < pcse) && (*pcptr < nxt_func)) {
4340Sstevel@tonic-gate nticks++;
4350Sstevel@tonic-gate pcptr++;
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate
4380Sstevel@tonic-gate nl->nticks += nticks;
4390Sstevel@tonic-gate n_accounted_ticks += nticks;
4400Sstevel@tonic-gate } else {
4410Sstevel@tonic-gate /*
4420Sstevel@tonic-gate * pc sample could not be assigned to function;
4430Sstevel@tonic-gate * probably in a PLT
4440Sstevel@tonic-gate */
4450Sstevel@tonic-gate pcptr++;
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate
450211Smike_s static int
pc_cmp(const void * arg1,const void * arg2)451211Smike_s pc_cmp(const void *arg1, const void *arg2)
4520Sstevel@tonic-gate {
453211Smike_s Address *pc1 = (Address *)arg1;
454211Smike_s Address *pc2 = (Address *)arg2;
455211Smike_s
4560Sstevel@tonic-gate if (*pc1 > *pc2)
4570Sstevel@tonic-gate return (1);
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate if (*pc1 < *pc2)
4600Sstevel@tonic-gate return (-1);
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate return (0);
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate static void
process_pcsamples(ProfBuffer * bufp)466211Smike_s process_pcsamples(ProfBuffer *bufp)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate Address *pc_samples;
4690Sstevel@tonic-gate mod_info_t *mi;
4700Sstevel@tonic-gate size_t nelem = bufp->bufsize;
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate /* buffer with no pc samples ? */
4730Sstevel@tonic-gate if (nelem == 0)
4740Sstevel@tonic-gate return;
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate /* Allocate for the pcsample chunk */
4770Sstevel@tonic-gate pc_samples = (Address *) calloc(nelem, sizeof (Address));
4780Sstevel@tonic-gate if (pc_samples == NULL) {
479211Smike_s (void) fprintf(stderr, "%s: no room for %d sample pc's\n",
480211Smike_s cmdname, nelem);
4810Sstevel@tonic-gate exit(ERR_MEMORY);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate
484211Smike_s (void) memcpy(pc_samples, (caddr_t)bufp + bufp->buffer,
485211Smike_s nelem * sizeof (Address));
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate /* Sort the pc samples */
488211Smike_s qsort(pc_samples, nelem, sizeof (Address), pc_cmp);
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate /*
4910Sstevel@tonic-gate * Assign pcsamples to functions in the currently active
4920Sstevel@tonic-gate * module list
4930Sstevel@tonic-gate */
4940Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) {
4950Sstevel@tonic-gate if (mi->active == FALSE)
4960Sstevel@tonic-gate continue;
4970Sstevel@tonic-gate assign_pcsamples(mi, pc_samples, nelem);
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate free(pc_samples);
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /* Update total number of pcsamples read so far */
5030Sstevel@tonic-gate n_pcsamples += nelem;
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate static void
process_cgraph(ProfCallGraph * cgp)507211Smike_s process_cgraph(ProfCallGraph *cgp)
5080Sstevel@tonic-gate {
5090Sstevel@tonic-gate mod_info_t *mi;
5100Sstevel@tonic-gate Address f_end;
5110Sstevel@tonic-gate Index callee_off;
5120Sstevel@tonic-gate ProfFunction *calleep;
5130Sstevel@tonic-gate nltype *nl;
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate for (callee_off = cgp->functions; callee_off;
516*7008Sab196087 callee_off = calleep->next_to) {
5170Sstevel@tonic-gate
518211Smike_s /* LINTED: pointer cast */
519211Smike_s calleep = (ProfFunction *)((char *)cgp + callee_off);
5200Sstevel@tonic-gate if (calleep->count == 0)
5210Sstevel@tonic-gate continue;
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate * If we cannot identify a callee with a module, we
5250Sstevel@tonic-gate * cannot get to its namelist, just skip it.
5260Sstevel@tonic-gate */
5270Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) {
5280Sstevel@tonic-gate if (mi->active == FALSE)
5290Sstevel@tonic-gate continue;
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate if (calleep->topc >= mi->load_base &&
532*7008Sab196087 calleep->topc < mi->load_end) {
5330Sstevel@tonic-gate /*
5340Sstevel@tonic-gate * nllookup() returns the next lower entry
5350Sstevel@tonic-gate * point on a miss. So just make sure the
5360Sstevel@tonic-gate * callee's pc is not outside this function
5370Sstevel@tonic-gate */
5380Sstevel@tonic-gate if (nl = nllookup(mi, calleep->topc, 0)) {
5390Sstevel@tonic-gate f_end = mi->load_base + (nl->value -
540*7008Sab196087 mi->txt_origin) + nl->size;
5410Sstevel@tonic-gate if (calleep->topc < f_end)
5420Sstevel@tonic-gate nl->ncalls += calleep->count;
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate static mod_info_t *
get_shobj_syms(char * pathname,GElf_Addr ld_base,GElf_Addr ld_end)5500Sstevel@tonic-gate get_shobj_syms(char *pathname, GElf_Addr ld_base, GElf_Addr ld_end)
5510Sstevel@tonic-gate {
5520Sstevel@tonic-gate mod_info_t *mi;
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate /* Create a new module element */
555211Smike_s if ((mi = malloc(sizeof (mod_info_t))) == NULL) {
556211Smike_s (void) fprintf(stderr, "%s: no room for %d bytes\n",
557211Smike_s cmdname, sizeof (mod_info_t));
5580Sstevel@tonic-gate exit(ERR_MEMORY);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate
561211Smike_s mi->path = malloc(strlen(pathname) + 1);
5620Sstevel@tonic-gate if (mi->path == NULL) {
563211Smike_s (void) fprintf(stderr, "%s: can't allocate %d bytes\n",
564211Smike_s cmdname, strlen(pathname) + 1);
5650Sstevel@tonic-gate exit(ERR_MEMORY);
5660Sstevel@tonic-gate }
567211Smike_s (void) strcpy(mi->path, pathname);
5680Sstevel@tonic-gate mi->next = NULL;
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate get_syms(pathname, mi);
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate /* and fill in info... */
5730Sstevel@tonic-gate mi->id = n_modules + 1;
5740Sstevel@tonic-gate mi->load_base = ld_base;
5750Sstevel@tonic-gate mi->load_end = ld_end;
5760Sstevel@tonic-gate mi->active = TRUE;
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate n_modules++;
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate return (mi);
5810Sstevel@tonic-gate }
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate * Two modules overlap each other if they don't lie completely *outside*
5850Sstevel@tonic-gate * each other.
5860Sstevel@tonic-gate */
5870Sstevel@tonic-gate static bool
does_overlap(ProfModule * new,mod_info_t * old)588211Smike_s does_overlap(ProfModule *new, mod_info_t *old)
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate /* case 1: new module lies completely *before* the old one */
5910Sstevel@tonic-gate if (new->startaddr < old->load_base && new->endaddr <= old->load_base)
5920Sstevel@tonic-gate return (FALSE);
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate /* case 2: new module lies completely *after* the old one */
5950Sstevel@tonic-gate if (new->startaddr >= old->load_end && new->endaddr >= old->load_end)
5960Sstevel@tonic-gate return (FALSE);
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate /* probably a dlopen: the modules overlap each other */
5990Sstevel@tonic-gate return (TRUE);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate static bool
is_same_as_aout(char * modpath,struct stat * buf)603211Smike_s is_same_as_aout(char *modpath, struct stat *buf)
6040Sstevel@tonic-gate {
6050Sstevel@tonic-gate if (stat(modpath, buf) == -1) {
6060Sstevel@tonic-gate perror(modpath);
6070Sstevel@tonic-gate exit(ERR_SYSCALL);
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate if ((buf->st_dev == aout_stat.st_dev) &&
611*7008Sab196087 (buf->st_ino == aout_stat.st_ino)) {
6120Sstevel@tonic-gate return (TRUE);
6130Sstevel@tonic-gate } else
6140Sstevel@tonic-gate return (FALSE);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate
6170Sstevel@tonic-gate static void
process_modules(ProfModuleList * modlp)618211Smike_s process_modules(ProfModuleList *modlp)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate ProfModule *newmodp;
6210Sstevel@tonic-gate mod_info_t *mi, *last, *new_module;
6220Sstevel@tonic-gate char *so_path;
6230Sstevel@tonic-gate bool more_modules = TRUE;
6240Sstevel@tonic-gate struct stat so_statbuf;
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate /* Check version of module type object */
6270Sstevel@tonic-gate if (modlp->version > PROF_MODULES_VER) {
628211Smike_s (void) fprintf(stderr,
629211Smike_s "%s: unsupported version %d for modules\n",
630211Smike_s cmdname, modlp->version);
6310Sstevel@tonic-gate exit(ERR_INPUT);
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate /*
6360Sstevel@tonic-gate * Scan the PROF_MODULES_T list and add modules to current list
6370Sstevel@tonic-gate * of modules, if they're not present already
6380Sstevel@tonic-gate */
639211Smike_s /* LINTED: pointer cast */
640211Smike_s newmodp = (ProfModule *)((caddr_t)modlp + modlp->modules);
6410Sstevel@tonic-gate do {
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate * Since the aout could've been renamed after its run, we
6440Sstevel@tonic-gate * should see if current module overlaps aout. If it does, it
6450Sstevel@tonic-gate * is probably the renamed aout. We should also skip any other
6460Sstevel@tonic-gate * non-sharedobj's that we see (or should we report an error ?)
6470Sstevel@tonic-gate */
648211Smike_s so_path = (caddr_t)modlp + newmodp->path;
6490Sstevel@tonic-gate if (does_overlap(newmodp, &modules) ||
650*7008Sab196087 is_same_as_aout(so_path, &so_statbuf) ||
651*7008Sab196087 (!is_shared_obj(so_path))) {
6520Sstevel@tonic-gate if (!newmodp->next)
6530Sstevel@tonic-gate more_modules = FALSE;
6540Sstevel@tonic-gate
655211Smike_s /* LINTED: pointer cast */
6560Sstevel@tonic-gate newmodp = (ProfModule *)
657211Smike_s ((caddr_t)modlp + newmodp->next);
6580Sstevel@tonic-gate continue;
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate /*
6620Sstevel@tonic-gate * Check all modules (leave the first one, 'cos that
6630Sstevel@tonic-gate * is the program executable info). If this module is already
6640Sstevel@tonic-gate * there in the list, skip it.
6650Sstevel@tonic-gate */
6660Sstevel@tonic-gate last = &modules;
667211Smike_s while ((mi = last->next) != NULL) {
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate * We expect the full pathname for all shared objects
6700Sstevel@tonic-gate * needed by the program executable. In this case, we
6710Sstevel@tonic-gate * simply need to compare the paths to see if they are
6720Sstevel@tonic-gate * the same file.
6730Sstevel@tonic-gate */
6740Sstevel@tonic-gate if (strcmp(mi->path, so_path) == 0)
6750Sstevel@tonic-gate break;
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate /*
6780Sstevel@tonic-gate * Check if this new shared object will overlap any
6790Sstevel@tonic-gate * existing module. If yes, deactivate the old one.
6800Sstevel@tonic-gate */
6810Sstevel@tonic-gate if (does_overlap(newmodp, mi))
6820Sstevel@tonic-gate mi->active = FALSE;
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate last = mi;
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate /* Module already there, skip it */
6880Sstevel@tonic-gate if (mi != NULL) {
6890Sstevel@tonic-gate mi->load_base = newmodp->startaddr;
6900Sstevel@tonic-gate mi->load_end = newmodp->endaddr;
6910Sstevel@tonic-gate mi->active = TRUE;
6920Sstevel@tonic-gate if (!newmodp->next)
6930Sstevel@tonic-gate more_modules = FALSE;
6940Sstevel@tonic-gate
695211Smike_s /* LINTED: pointer cast */
6960Sstevel@tonic-gate newmodp = (ProfModule *)
697211Smike_s ((caddr_t)modlp + newmodp->next);
6980Sstevel@tonic-gate continue;
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate /*
7020Sstevel@tonic-gate * Check if mon.out is outdated with respect to the new
7030Sstevel@tonic-gate * module we want to add
7040Sstevel@tonic-gate */
7050Sstevel@tonic-gate if (monout_stat.st_mtime < so_statbuf.st_mtime) {
706211Smike_s (void) fprintf(stderr,
707211Smike_s "%s: newer shared obj %s outdates profile info\n",
708211Smike_s cmdname, so_path);
7090Sstevel@tonic-gate exit(ERR_INPUT);
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate /* Create this module's nameslist */
7130Sstevel@tonic-gate new_module = get_shobj_syms(so_path,
714*7008Sab196087 newmodp->startaddr, newmodp->endaddr);
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate /* Add it to the tail of active module list */
7170Sstevel@tonic-gate last->next = new_module;
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate /*
7200Sstevel@tonic-gate * Move to the next module in the PROF_MODULES_T list
7210Sstevel@tonic-gate * (if present)
7220Sstevel@tonic-gate */
7230Sstevel@tonic-gate if (!newmodp->next)
7240Sstevel@tonic-gate more_modules = FALSE;
7250Sstevel@tonic-gate
726211Smike_s /* LINTED: pointer cast */
727211Smike_s newmodp = (ProfModule *)((caddr_t)modlp + newmodp->next);
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate } while (more_modules);
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate static void
process_mon_out(caddr_t memp,size_t fsz)7330Sstevel@tonic-gate process_mon_out(caddr_t memp, size_t fsz)
7340Sstevel@tonic-gate {
7350Sstevel@tonic-gate ProfObject *objp;
7360Sstevel@tonic-gate caddr_t file_end;
7370Sstevel@tonic-gate bool found_pcsamples = FALSE, found_cgraph = FALSE;
7380Sstevel@tonic-gate
7390Sstevel@tonic-gate /*
7400Sstevel@tonic-gate * Save file end pointer and start after header
7410Sstevel@tonic-gate */
7420Sstevel@tonic-gate file_end = memp + fsz;
743211Smike_s /* LINTED: pointer cast */
744211Smike_s objp = (ProfObject *)(memp + ((ProfHeader *)memp)->size);
745211Smike_s while ((caddr_t)objp < file_end) {
7460Sstevel@tonic-gate switch (objp->type) {
7470Sstevel@tonic-gate case PROF_MODULES_T :
748211Smike_s process_modules((ProfModuleList *)objp);
7490Sstevel@tonic-gate break;
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate case PROF_CALLGRAPH_T :
752211Smike_s process_cgraph((ProfCallGraph *)objp);
7530Sstevel@tonic-gate found_cgraph = TRUE;
7540Sstevel@tonic-gate break;
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate case PROF_BUFFER_T :
757211Smike_s process_pcsamples((ProfBuffer *)objp);
7580Sstevel@tonic-gate found_pcsamples = TRUE;
7590Sstevel@tonic-gate break;
7600Sstevel@tonic-gate
7610Sstevel@tonic-gate default :
762211Smike_s (void) fprintf(stderr,
763*7008Sab196087 "%s: unknown prof object type=%d\n",
764*7008Sab196087 cmdname, objp->type);
7650Sstevel@tonic-gate exit(ERR_INPUT);
7660Sstevel@tonic-gate }
767211Smike_s /* LINTED: pointer cast */
768211Smike_s objp = (ProfObject *)((caddr_t)objp + objp->size);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate
7710Sstevel@tonic-gate if (!found_cgraph || !found_pcsamples) {
772211Smike_s (void) fprintf(stderr,
773211Smike_s "%s: missing callgraph/pcsamples in `%s'\n",
774211Smike_s cmdname, mon_fn);
7750Sstevel@tonic-gate exit(ERR_INPUT);
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate
778211Smike_s if ((caddr_t)objp > file_end) {
779211Smike_s (void) fprintf(stderr, "%s: malformed file `%s'\n",
780211Smike_s cmdname, mon_fn);
7810Sstevel@tonic-gate exit(ERR_INPUT);
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate }
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate static void
get_aout_syms(char * pathname,mod_info_t * mi)7860Sstevel@tonic-gate get_aout_syms(char *pathname, mod_info_t *mi)
7870Sstevel@tonic-gate {
788211Smike_s mi->path = malloc(strlen(pathname) + 1);
7890Sstevel@tonic-gate if (mi->path == NULL) {
790211Smike_s (void) fprintf(stderr, "%s: can't allocate %d bytes\n",
791211Smike_s cmdname, strlen(pathname) + 1);
7920Sstevel@tonic-gate exit(ERR_MEMORY);
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate
795211Smike_s (void) strcpy(mi->path, pathname);
7960Sstevel@tonic-gate mi->next = NULL;
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate get_syms(pathname, mi);
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate mi->id = 1;
8010Sstevel@tonic-gate mi->load_base = mi->txt_origin;
8020Sstevel@tonic-gate mi->load_end = mi->data_end;
8030Sstevel@tonic-gate mi->active = TRUE;
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate void
profver(void)807211Smike_s profver(void)
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate int fd;
8100Sstevel@tonic-gate unsigned int magic_num;
8110Sstevel@tonic-gate bool invalid_version;
8120Sstevel@tonic-gate caddr_t fmem;
8130Sstevel@tonic-gate ProfHeader prof_hdr;
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate /*
8160Sstevel@tonic-gate * Check the magic and see if this is versioned or *old-style*
8170Sstevel@tonic-gate * mon.out.
8180Sstevel@tonic-gate */
8190Sstevel@tonic-gate if ((fd = open(mon_fn, O_RDONLY)) == -1) {
8200Sstevel@tonic-gate perror(mon_fn);
8210Sstevel@tonic-gate exit(ERR_SYSCALL);
8220Sstevel@tonic-gate }
823211Smike_s if (read(fd, (char *)&magic_num, sizeof (unsigned int)) == -1) {
8240Sstevel@tonic-gate perror("read");
8250Sstevel@tonic-gate exit(ERR_SYSCALL);
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate if (magic_num != (unsigned int) PROF_MAGIC) {
828211Smike_s (void) close(fd);
8290Sstevel@tonic-gate return;
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate * Check versioning info. For now, let's say we provide
8360Sstevel@tonic-gate * backward compatibility, so we accept all older versions.
8370Sstevel@tonic-gate */
838211Smike_s (void) lseek(fd, 0L, SEEK_SET);
839211Smike_s if (read(fd, (char *)&prof_hdr, sizeof (ProfHeader)) == -1) {
8400Sstevel@tonic-gate perror("read");
8410Sstevel@tonic-gate exit(ERR_SYSCALL);
8420Sstevel@tonic-gate }
8430Sstevel@tonic-gate invalid_version = FALSE;
8440Sstevel@tonic-gate if (prof_hdr.h_major_ver > PROF_MAJOR_VERSION)
8450Sstevel@tonic-gate invalid_version = TRUE;
8460Sstevel@tonic-gate else if (prof_hdr.h_major_ver == PROF_MAJOR_VERSION) {
8470Sstevel@tonic-gate if (prof_hdr.h_minor_ver > PROF_MINOR_VERSION)
8480Sstevel@tonic-gate invalid_version = FALSE;
8490Sstevel@tonic-gate }
8500Sstevel@tonic-gate if (invalid_version) {
851211Smike_s (void) fprintf(stderr,
852211Smike_s "%s: mon.out version %d.%d not supported\n",
853211Smike_s cmdname, prof_hdr.h_major_ver, prof_hdr.h_minor_ver);
8540Sstevel@tonic-gate exit(ERR_INPUT);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate /*
8600Sstevel@tonic-gate * Map mon.out onto memory.
8610Sstevel@tonic-gate */
8620Sstevel@tonic-gate if (stat(mon_fn, &monout_stat) == -1) {
8630Sstevel@tonic-gate perror(mon_fn);
8640Sstevel@tonic-gate exit(ERR_SYSCALL);
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate if ((fmem = mmap(0, monout_stat.st_size,
867*7008Sab196087 PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
8680Sstevel@tonic-gate perror("mmap");
8690Sstevel@tonic-gate exit(ERR_SYSCALL);
8700Sstevel@tonic-gate }
871211Smike_s (void) close(fd);
8720Sstevel@tonic-gate
8730Sstevel@tonic-gate
8740Sstevel@tonic-gate /*
8750Sstevel@tonic-gate * Now, read program executable's symbol table. Also save it's
8760Sstevel@tonic-gate * stat in aout_stat for use while processing mon.out
8770Sstevel@tonic-gate */
8780Sstevel@tonic-gate if (stat(sym_fn, &aout_stat) == -1) {
8790Sstevel@tonic-gate perror(sym_fn);
8800Sstevel@tonic-gate exit(ERR_SYSCALL);
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate get_aout_syms(sym_fn, &modules);
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate /*
8850Sstevel@tonic-gate * Process the mon.out, all shared objects it references
8860Sstevel@tonic-gate * and collect statistics on ticks spent in each function,
8870Sstevel@tonic-gate * number of calls, etc.
8880Sstevel@tonic-gate */
8890Sstevel@tonic-gate process_mon_out(fmem, monout_stat.st_size);
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate /*
8920Sstevel@tonic-gate * Based on the flags and the statistics we've got, create
8930Sstevel@tonic-gate * a list of relevant symbols whose profiling details should
8940Sstevel@tonic-gate * be printed
8950Sstevel@tonic-gate */
8960Sstevel@tonic-gate collect_profsyms();
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate /*
8990Sstevel@tonic-gate * Check for duplicate names in output. We need to print the
9000Sstevel@tonic-gate * module id's if verbose. Also, if we are sorting by name anyway,
9010Sstevel@tonic-gate * we don't need to check for duplicates here. We'll do that later.
9020Sstevel@tonic-gate */
9030Sstevel@tonic-gate if ((flags & F_VERBOSE) && (sort_flag != BY_NAME))
9040Sstevel@tonic-gate check_dupnames();
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate /*
9070Sstevel@tonic-gate * Print output
9080Sstevel@tonic-gate */
9090Sstevel@tonic-gate print_profile_data();
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate
912211Smike_s (void) munmap(fmem, monout_stat.st_size);
9130Sstevel@tonic-gate exit(0);
9140Sstevel@tonic-gate }
915