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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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