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*1dd08564Sab196087 * Common Development and Distribution License (the "License"). 6*1dd08564Sab196087 * 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 */ 217c478bd9Sstevel@tonic-gate /* 22*1dd08564Sab196087 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sysexits.h> 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 3092ed1782Smike_s #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <unistd.h> 327c478bd9Sstevel@tonic-gate #include "gprof.h" 337c478bd9Sstevel@tonic-gate #include "profile.h" 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate char *whoami = "gprof"; 367c478bd9Sstevel@tonic-gate static pctype lowpc, highpc; /* range profiled, in UNIT's */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate /* 397c478bd9Sstevel@tonic-gate * things which get -E excluded by default. 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate static char *defaultEs[] = { 427c478bd9Sstevel@tonic-gate "mcount", 437c478bd9Sstevel@tonic-gate "__mcleanup", 4492ed1782Smike_s NULL 457c478bd9Sstevel@tonic-gate }; 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #ifdef DEBUG 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate static char *objname[] = { 507c478bd9Sstevel@tonic-gate "<invalid object>", 517c478bd9Sstevel@tonic-gate "PROF_BUFFER_T", 527c478bd9Sstevel@tonic-gate "PROF_CALLGRAPH_T", 537c478bd9Sstevel@tonic-gate "PROF_MODULES_T", 5492ed1782Smike_s NULL 557c478bd9Sstevel@tonic-gate }; 567c478bd9Sstevel@tonic-gate #define MAX_OBJTYPES 3 577c478bd9Sstevel@tonic-gate 5892ed1782Smike_s #endif /* DEBUG */ 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate void 6192ed1782Smike_s done(void) 627c478bd9Sstevel@tonic-gate { 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate exit(EX_OK); 657c478bd9Sstevel@tonic-gate } 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate static pctype 687c478bd9Sstevel@tonic-gate max(pctype a, pctype b) 697c478bd9Sstevel@tonic-gate { 707c478bd9Sstevel@tonic-gate if (a > b) 717c478bd9Sstevel@tonic-gate return (a); 727c478bd9Sstevel@tonic-gate return (b); 737c478bd9Sstevel@tonic-gate } 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate static pctype 767c478bd9Sstevel@tonic-gate min(pctype a, pctype b) 777c478bd9Sstevel@tonic-gate { 787c478bd9Sstevel@tonic-gate if (a < b) 797c478bd9Sstevel@tonic-gate return (a); 807c478bd9Sstevel@tonic-gate return (b); 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * calculate scaled entry point addresses (to save time in asgnsamples), 857c478bd9Sstevel@tonic-gate * and possibly push the scaled entry points over the entry mask, 867c478bd9Sstevel@tonic-gate * if it turns out that the entry point is in one bucket and the code 877c478bd9Sstevel@tonic-gate * for a routine is in the next bucket. 887c478bd9Sstevel@tonic-gate * 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate static void 9192ed1782Smike_s alignentries(void) 927c478bd9Sstevel@tonic-gate { 9392ed1782Smike_s struct nl *nlp; 947c478bd9Sstevel@tonic-gate #ifdef DEBUG 957c478bd9Sstevel@tonic-gate pctype bucket_of_entry; 967c478bd9Sstevel@tonic-gate pctype bucket_of_code; 9792ed1782Smike_s #endif /* DEBUG */ 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* for old-style gmon.out, nameslist is only in modules.nl */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate for (nlp = modules.nl; nlp < modules.npe; nlp++) { 1027c478bd9Sstevel@tonic-gate nlp->svalue = nlp->value / sizeof (UNIT); 1037c478bd9Sstevel@tonic-gate #ifdef DEBUG 1047c478bd9Sstevel@tonic-gate bucket_of_entry = (nlp->svalue - lowpc) / scale; 1057c478bd9Sstevel@tonic-gate bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; 1067c478bd9Sstevel@tonic-gate if (bucket_of_entry < bucket_of_code) { 1077c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 10892ed1782Smike_s (void) printf( 10992ed1782Smike_s "[alignentries] pushing svalue 0x%llx " 1107c478bd9Sstevel@tonic-gate "to 0x%llx\n", nlp->svalue, 1117c478bd9Sstevel@tonic-gate nlp->svalue + UNITS_TO_CODE); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate } 11492ed1782Smike_s #endif /* DEBUG */ 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * old-style gmon.out 1207c478bd9Sstevel@tonic-gate * ------------------ 1217c478bd9Sstevel@tonic-gate * 1227c478bd9Sstevel@tonic-gate * Assign samples to the procedures to which they belong. 1237c478bd9Sstevel@tonic-gate * 1247c478bd9Sstevel@tonic-gate * There are three cases as to where pcl and pch can be 1257c478bd9Sstevel@tonic-gate * with respect to the routine entry addresses svalue0 and svalue1 1267c478bd9Sstevel@tonic-gate * as shown in the following diagram. overlap computes the 1277c478bd9Sstevel@tonic-gate * distance between the arrows, the fraction of the sample 1287c478bd9Sstevel@tonic-gate * that is to be credited to the routine which starts at svalue0. 1297c478bd9Sstevel@tonic-gate * 1307c478bd9Sstevel@tonic-gate * svalue0 svalue1 1317c478bd9Sstevel@tonic-gate * | | 1327c478bd9Sstevel@tonic-gate * v v 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * +-----------------------------------------------+ 1357c478bd9Sstevel@tonic-gate * | | 1367c478bd9Sstevel@tonic-gate * | ->| |<- ->| |<- ->| |<- | 1377c478bd9Sstevel@tonic-gate * | | | | | | 1387c478bd9Sstevel@tonic-gate * +---------+ +---------+ +---------+ 1397c478bd9Sstevel@tonic-gate * 1407c478bd9Sstevel@tonic-gate * ^ ^ ^ ^ ^ ^ 1417c478bd9Sstevel@tonic-gate * | | | | | | 1427c478bd9Sstevel@tonic-gate * pcl pch pcl pch pcl pch 1437c478bd9Sstevel@tonic-gate * 1447c478bd9Sstevel@tonic-gate * For the vax we assert that samples will never fall in the first 1457c478bd9Sstevel@tonic-gate * two bytes of any routine, since that is the entry mask, 1467c478bd9Sstevel@tonic-gate * thus we give call alignentries() to adjust the entry points if 1477c478bd9Sstevel@tonic-gate * the entry mask falls in one bucket but the code for the routine 1487c478bd9Sstevel@tonic-gate * doesn't start until the next bucket. In conjunction with the 1497c478bd9Sstevel@tonic-gate * alignment of routine addresses, this should allow us to have 1507c478bd9Sstevel@tonic-gate * only one sample for every four bytes of text space and never 1517c478bd9Sstevel@tonic-gate * have any overlap (the two end cases, above). 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate static void 15492ed1782Smike_s asgnsamples(void) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate sztype i, j; 1577c478bd9Sstevel@tonic-gate unsigned_UNIT ccnt; 1587c478bd9Sstevel@tonic-gate double time; 1597c478bd9Sstevel@tonic-gate pctype pcl, pch; 1607c478bd9Sstevel@tonic-gate pctype overlap; 1617c478bd9Sstevel@tonic-gate pctype svalue0, svalue1; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate extern mod_info_t modules; 1647c478bd9Sstevel@tonic-gate nltype *nl = modules.nl; 1657c478bd9Sstevel@tonic-gate sztype nname = modules.nname; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* read samples and assign to namelist symbols */ 1687c478bd9Sstevel@tonic-gate scale = highpc - lowpc; 1697c478bd9Sstevel@tonic-gate scale /= nsamples; 1707c478bd9Sstevel@tonic-gate alignentries(); 1717c478bd9Sstevel@tonic-gate for (i = 0, j = 1; i < nsamples; i++) { 1727c478bd9Sstevel@tonic-gate ccnt = samples[i]; 1737c478bd9Sstevel@tonic-gate if (ccnt == 0) 1747c478bd9Sstevel@tonic-gate continue; 175*1dd08564Sab196087 /*LINTED: E_ASSIGMENT_CAUSE_LOSS_PREC*/ 1767c478bd9Sstevel@tonic-gate pcl = lowpc + scale * i; 177*1dd08564Sab196087 /*LINTED: E_ASSIGMENT_CAUSE_LOSS_PREC*/ 1787c478bd9Sstevel@tonic-gate pch = lowpc + scale * (i + 1); 1797c478bd9Sstevel@tonic-gate time = ccnt; 1807c478bd9Sstevel@tonic-gate #ifdef DEBUG 1817c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 18292ed1782Smike_s (void) printf( 18392ed1782Smike_s "[asgnsamples] pcl 0x%llx pch 0x%llx ccnt %d\n", 1847c478bd9Sstevel@tonic-gate pcl, pch, ccnt); 1857c478bd9Sstevel@tonic-gate } 18692ed1782Smike_s #endif /* DEBUG */ 1877c478bd9Sstevel@tonic-gate totime += time; 1887c478bd9Sstevel@tonic-gate for (j = (j ? j - 1 : 0); j < nname; j++) { 1897c478bd9Sstevel@tonic-gate svalue0 = nl[j].svalue; 1907c478bd9Sstevel@tonic-gate svalue1 = nl[j+1].svalue; 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * if high end of tick is below entry address, 1937c478bd9Sstevel@tonic-gate * go for next tick. 1947c478bd9Sstevel@tonic-gate */ 1957c478bd9Sstevel@tonic-gate if (pch < svalue0) 1967c478bd9Sstevel@tonic-gate break; 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * if low end of tick into next routine, 1997c478bd9Sstevel@tonic-gate * go for next routine. 2007c478bd9Sstevel@tonic-gate */ 2017c478bd9Sstevel@tonic-gate if (pcl >= svalue1) 2027c478bd9Sstevel@tonic-gate continue; 2037c478bd9Sstevel@tonic-gate overlap = min(pch, svalue1) - max(pcl, svalue0); 2047c478bd9Sstevel@tonic-gate if (overlap != 0) { 2057c478bd9Sstevel@tonic-gate #ifdef DEBUG 2067c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 20792ed1782Smike_s (void) printf("[asgnsamples] " 2087c478bd9Sstevel@tonic-gate "(0x%llx->0x%llx-0x%llx) %s gets " 2097c478bd9Sstevel@tonic-gate "%f ticks %lld overlap\n", 2107c478bd9Sstevel@tonic-gate nl[j].value/sizeof (UNIT), svalue0, 2117c478bd9Sstevel@tonic-gate svalue1, nl[j].name, 2127c478bd9Sstevel@tonic-gate overlap * time / scale, overlap); 2137c478bd9Sstevel@tonic-gate } 21492ed1782Smike_s #endif /* DEBUG */ 2157c478bd9Sstevel@tonic-gate nl[j].time += overlap * time / scale; 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate #ifdef DEBUG 2207c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 22192ed1782Smike_s (void) printf("[asgnsamples] totime %f\n", totime); 2227c478bd9Sstevel@tonic-gate } 22392ed1782Smike_s #endif /* DEBUG */ 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate static void 22892ed1782Smike_s dump_callgraph(FILE *fp, char *filename, unsigned long tarcs, 22992ed1782Smike_s unsigned long ncallees) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate ProfCallGraph prof_cgraph; 2327c478bd9Sstevel@tonic-gate ProfFunction prof_func; 23392ed1782Smike_s arctype *arcp; 2347c478bd9Sstevel@tonic-gate mod_info_t *mi; 2357c478bd9Sstevel@tonic-gate nltype *nlp; 2367c478bd9Sstevel@tonic-gate size_t cur_offset; 2377c478bd9Sstevel@tonic-gate unsigned long caller_id = 0, callee_id = 0; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Write the callgraph header 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate prof_cgraph.type = PROF_CALLGRAPH_T; 2437c478bd9Sstevel@tonic-gate prof_cgraph.version = PROF_CALLGRAPH_VER; 2447c478bd9Sstevel@tonic-gate prof_cgraph.functions = PROFCGRAPH_SZ; 2457c478bd9Sstevel@tonic-gate prof_cgraph.size = PROFCGRAPH_SZ + tarcs * PROFFUNC_SZ; 2467c478bd9Sstevel@tonic-gate if (fwrite(&prof_cgraph, sizeof (ProfCallGraph), 1, fp) != 1) { 2477c478bd9Sstevel@tonic-gate perror(filename); 2487c478bd9Sstevel@tonic-gate exit(EX_IOERR); 2497c478bd9Sstevel@tonic-gate } 25092ed1782Smike_s /* CONSTCOND */ 2517c478bd9Sstevel@tonic-gate if (CGRAPH_FILLER) 25292ed1782Smike_s (void) fseek(fp, CGRAPH_FILLER, SEEK_CUR); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* Current offset inside the callgraph object */ 2557c478bd9Sstevel@tonic-gate cur_offset = prof_cgraph.functions; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 2587c478bd9Sstevel@tonic-gate for (nlp = mi->nl; nlp < mi->npe; nlp++) { 2597c478bd9Sstevel@tonic-gate if (nlp->ncallers == 0) 2607c478bd9Sstevel@tonic-gate continue; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* If this is the last callee, set next_to to 0 */ 2637c478bd9Sstevel@tonic-gate callee_id++; 2647c478bd9Sstevel@tonic-gate if (callee_id == ncallees) 2657c478bd9Sstevel@tonic-gate prof_func.next_to = 0; 2667c478bd9Sstevel@tonic-gate else { 2677c478bd9Sstevel@tonic-gate prof_func.next_to = cur_offset + 2687c478bd9Sstevel@tonic-gate nlp->ncallers * PROFFUNC_SZ; 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate /* 2727c478bd9Sstevel@tonic-gate * Dump this callee's raw arc information with all 2737c478bd9Sstevel@tonic-gate * its callers 2747c478bd9Sstevel@tonic-gate */ 2757c478bd9Sstevel@tonic-gate caller_id = 1; 2767c478bd9Sstevel@tonic-gate for (arcp = nlp->parents; arcp; 2777c478bd9Sstevel@tonic-gate arcp = arcp->arc_parentlist) { 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * If no more callers for this callee, set 2807c478bd9Sstevel@tonic-gate * next_from to 0 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate if (caller_id == nlp->ncallers) 2837c478bd9Sstevel@tonic-gate prof_func.next_from = 0; 2847c478bd9Sstevel@tonic-gate else { 2857c478bd9Sstevel@tonic-gate prof_func.next_from = cur_offset + 2867c478bd9Sstevel@tonic-gate PROFFUNC_SZ; 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate prof_func.frompc = 2907c478bd9Sstevel@tonic-gate arcp->arc_parentp->module->load_base + 2917c478bd9Sstevel@tonic-gate (arcp->arc_parentp->value - 2927c478bd9Sstevel@tonic-gate arcp->arc_parentp->module->txt_origin); 293*1dd08564Sab196087 prof_func.topc = mi->load_base + 2947c478bd9Sstevel@tonic-gate (nlp->value - mi->txt_origin); 2957c478bd9Sstevel@tonic-gate prof_func.count = arcp->arc_count; 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate if (fwrite(&prof_func, sizeof (ProfFunction), 2997c478bd9Sstevel@tonic-gate 1, fp) != 1) { 3007c478bd9Sstevel@tonic-gate perror(filename); 3017c478bd9Sstevel@tonic-gate exit(EX_IOERR); 3027c478bd9Sstevel@tonic-gate } 30392ed1782Smike_s /* CONSTCOND */ 3047c478bd9Sstevel@tonic-gate if (FUNC_FILLER) 30592ed1782Smike_s (void) fseek(fp, FUNC_FILLER, SEEK_CUR); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate cur_offset += PROFFUNC_SZ; 3087c478bd9Sstevel@tonic-gate caller_id++; 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate } /* for nlp... */ 3117c478bd9Sstevel@tonic-gate } /* for mi... */ 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * To save all pc-hits in all the gmon.out's is infeasible, as this 3167c478bd9Sstevel@tonic-gate * may become quite huge even with a small number of files to sum. 3177c478bd9Sstevel@tonic-gate * Instead, we'll dump *fictitious hits* to correct functions 3187c478bd9Sstevel@tonic-gate * by scanning module namelists. Again, since this is summing 3197c478bd9Sstevel@tonic-gate * pc-hits, we may have to dump the pcsamples out in chunks if the 3207c478bd9Sstevel@tonic-gate * number of pc-hits is high. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate static void 3237c478bd9Sstevel@tonic-gate dump_hits(FILE *fp, char *filename, nltype *nlp) 3247c478bd9Sstevel@tonic-gate { 3257c478bd9Sstevel@tonic-gate Address *p, hitpc; 3267c478bd9Sstevel@tonic-gate size_t i, nelem, ntowrite; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate if ((nelem = nlp->nticks) > PROF_BUFFER_SIZE) 3297c478bd9Sstevel@tonic-gate nelem = PROF_BUFFER_SIZE; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate if ((p = (Address *) calloc(nelem, sizeof (Address))) == NULL) { 33292ed1782Smike_s (void) fprintf(stderr, "%s: no room for %d pcsamples\n", 3337c478bd9Sstevel@tonic-gate whoami, nelem); 3347c478bd9Sstevel@tonic-gate exit(EX_OSERR); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate * Set up *fictitious* hits (to function entry) buffer 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate hitpc = nlp->module->load_base + (nlp->value - nlp->module->txt_origin); 3417c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) 3427c478bd9Sstevel@tonic-gate p[i] = hitpc; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate for (ntowrite = nlp->nticks; ntowrite >= nelem; ntowrite -= nelem) { 3457c478bd9Sstevel@tonic-gate if (fwrite(p, nelem * sizeof (Address), 1, fp) != 1) { 3467c478bd9Sstevel@tonic-gate perror(filename); 3477c478bd9Sstevel@tonic-gate exit(EX_IOERR); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if (ntowrite) { 3527c478bd9Sstevel@tonic-gate if (fwrite(p, ntowrite * sizeof (Address), 1, fp) != 1) { 3537c478bd9Sstevel@tonic-gate perror(filename); 3547c478bd9Sstevel@tonic-gate exit(EX_IOERR); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate free(p); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate static void 36292ed1782Smike_s dump_pcsamples(FILE *fp, char *filename, unsigned long *tarcs, 36392ed1782Smike_s unsigned long *ncallees) 3647c478bd9Sstevel@tonic-gate { 3657c478bd9Sstevel@tonic-gate ProfBuffer prof_buffer; 36692ed1782Smike_s arctype *arcp; 3677c478bd9Sstevel@tonic-gate mod_info_t *mi; 3687c478bd9Sstevel@tonic-gate nltype *nlp; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate prof_buffer.type = PROF_BUFFER_T; 3717c478bd9Sstevel@tonic-gate prof_buffer.version = PROF_BUFFER_VER; 3727c478bd9Sstevel@tonic-gate prof_buffer.buffer = PROFBUF_SZ; 3737c478bd9Sstevel@tonic-gate prof_buffer.bufsize = n_pcsamples; 3747c478bd9Sstevel@tonic-gate prof_buffer.size = PROFBUF_SZ + n_pcsamples * sizeof (Address); 3757c478bd9Sstevel@tonic-gate if (fwrite(&prof_buffer, sizeof (ProfBuffer), 1, fp) != 1) { 3767c478bd9Sstevel@tonic-gate perror(filename); 3777c478bd9Sstevel@tonic-gate exit(EX_IOERR); 3787c478bd9Sstevel@tonic-gate } 37992ed1782Smike_s /* CONSTCOND */ 3807c478bd9Sstevel@tonic-gate if (BUF_FILLER) 38192ed1782Smike_s (void) fseek(fp, BUF_FILLER, SEEK_CUR); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate *tarcs = 0; 3847c478bd9Sstevel@tonic-gate *ncallees = 0; 3857c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 3867c478bd9Sstevel@tonic-gate for (nlp = mi->nl; nlp < mi->npe; nlp++) { 3877c478bd9Sstevel@tonic-gate if (nlp->nticks) 3887c478bd9Sstevel@tonic-gate dump_hits(fp, filename, nlp); 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate nlp->ncallers = 0; 3917c478bd9Sstevel@tonic-gate for (arcp = nlp->parents; arcp; 3927c478bd9Sstevel@tonic-gate arcp = arcp->arc_parentlist) { 3937c478bd9Sstevel@tonic-gate (nlp->ncallers)++; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (nlp->ncallers) { 3977c478bd9Sstevel@tonic-gate (*tarcs) += nlp->ncallers; 3987c478bd9Sstevel@tonic-gate (*ncallees)++; 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate static void 4057c478bd9Sstevel@tonic-gate dump_modules(FILE *fp, char *filename, size_t pbuf_sz) 4067c478bd9Sstevel@tonic-gate { 4077c478bd9Sstevel@tonic-gate char *pbuf, *p; 4087c478bd9Sstevel@tonic-gate size_t namelen; 4097c478bd9Sstevel@tonic-gate Index off_nxt, off_path; 4107c478bd9Sstevel@tonic-gate mod_info_t *mi; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate ProfModuleList prof_modlist; 4137c478bd9Sstevel@tonic-gate ProfModule prof_mod; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* Allocate for path strings buffer */ 4167c478bd9Sstevel@tonic-gate pbuf_sz = CEIL(pbuf_sz, STRUCT_ALIGN); 41792ed1782Smike_s if ((p = pbuf = calloc(pbuf_sz, sizeof (char))) == NULL) { 41892ed1782Smike_s (void) fprintf(stderr, "%s: no room for %d bytes\n", 4197c478bd9Sstevel@tonic-gate whoami, pbuf_sz * sizeof (char)); 4207c478bd9Sstevel@tonic-gate exit(EX_OSERR); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* Dump out PROF_MODULE_T info for all non-aout modules */ 4247c478bd9Sstevel@tonic-gate prof_modlist.type = PROF_MODULES_T; 4257c478bd9Sstevel@tonic-gate prof_modlist.version = PROF_MODULES_VER; 4267c478bd9Sstevel@tonic-gate prof_modlist.modules = PROFMODLIST_SZ; 4277c478bd9Sstevel@tonic-gate prof_modlist.size = PROFMODLIST_SZ + (n_modules - 1) * PROFMOD_SZ + 4287c478bd9Sstevel@tonic-gate pbuf_sz; 4297c478bd9Sstevel@tonic-gate if (fwrite(&prof_modlist, sizeof (ProfModuleList), 1, fp) != 1) { 4307c478bd9Sstevel@tonic-gate perror(filename); 4317c478bd9Sstevel@tonic-gate exit(EX_IOERR); 4327c478bd9Sstevel@tonic-gate } 43392ed1782Smike_s /* CONSTCOND */ 4347c478bd9Sstevel@tonic-gate if (MODLIST_FILLER) 43592ed1782Smike_s (void) fseek(fp, MODLIST_FILLER, SEEK_CUR); 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* 4387c478bd9Sstevel@tonic-gate * Initialize offsets for ProfModule elements. 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate off_nxt = PROFMODLIST_SZ + PROFMOD_SZ; 4417c478bd9Sstevel@tonic-gate off_path = PROFMODLIST_SZ + (n_modules - 1) * PROFMOD_SZ; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate for (mi = modules.next; mi; mi = mi->next) { 4447c478bd9Sstevel@tonic-gate if (mi->next) 4457c478bd9Sstevel@tonic-gate prof_mod.next = off_nxt; 4467c478bd9Sstevel@tonic-gate else 4477c478bd9Sstevel@tonic-gate prof_mod.next = 0; 4487c478bd9Sstevel@tonic-gate prof_mod.path = off_path; 4497c478bd9Sstevel@tonic-gate prof_mod.startaddr = mi->load_base; 4507c478bd9Sstevel@tonic-gate prof_mod.endaddr = mi->load_end; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate if (fwrite(&prof_mod, sizeof (ProfModule), 1, fp) != 1) { 4537c478bd9Sstevel@tonic-gate perror(filename); 4547c478bd9Sstevel@tonic-gate exit(EX_IOERR); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 45792ed1782Smike_s /* CONSTCOND */ 4587c478bd9Sstevel@tonic-gate if (MOD_FILLER) 45992ed1782Smike_s (void) fseek(fp, MOD_FILLER, SEEK_CUR); 4607c478bd9Sstevel@tonic-gate 46192ed1782Smike_s (void) strcpy(p, mi->name); 4627c478bd9Sstevel@tonic-gate namelen = strlen(mi->name); 4637c478bd9Sstevel@tonic-gate p += namelen + 1; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* Note that offset to every path str need not be aligned */ 4667c478bd9Sstevel@tonic-gate off_nxt += PROFMOD_SZ; 4677c478bd9Sstevel@tonic-gate off_path += namelen + 1; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate /* Write out the module path strings */ 4717c478bd9Sstevel@tonic-gate if (pbuf_sz) { 4727c478bd9Sstevel@tonic-gate if (fwrite(pbuf, pbuf_sz, 1, fp) != 1) { 4737c478bd9Sstevel@tonic-gate perror(filename); 4747c478bd9Sstevel@tonic-gate exit(EX_IOERR); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate free(pbuf); 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * If we have inactive modules, their current load addresses may overlap with 4837c478bd9Sstevel@tonic-gate * active ones, and so we've to assign fictitious, non-overlapping addresses 4847c478bd9Sstevel@tonic-gate * to all modules before we dump them. 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate static void 4877c478bd9Sstevel@tonic-gate fixup_maps(size_t *pathsz) 4887c478bd9Sstevel@tonic-gate { 4897c478bd9Sstevel@tonic-gate unsigned int n_inactive = 0; 49092ed1782Smike_s Address lbase = 0, lend; 4917c478bd9Sstevel@tonic-gate mod_info_t *mi; 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* Pick the lowest load address among modules */ 4947c478bd9Sstevel@tonic-gate *pathsz = 0; 4957c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate if (mi->active == FALSE) 4987c478bd9Sstevel@tonic-gate n_inactive++; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate if (mi == &modules || mi->load_base < lbase) 5017c478bd9Sstevel@tonic-gate lbase = mi->load_base; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* 5047c478bd9Sstevel@tonic-gate * Return total path size of non-aout modules only 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate if (mi != &modules) 5077c478bd9Sstevel@tonic-gate *pathsz = (*pathsz) + strlen(mi->name) + 1; 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * All module info is in fine shape already if there are no 5127c478bd9Sstevel@tonic-gate * inactive modules 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate if (n_inactive == 0) 5157c478bd9Sstevel@tonic-gate return; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate /* 5187c478bd9Sstevel@tonic-gate * Assign fictitious load addresses to all (non-aout) modules so 5197c478bd9Sstevel@tonic-gate * that sum info can be dumped out. 5207c478bd9Sstevel@tonic-gate */ 5217c478bd9Sstevel@tonic-gate for (mi = modules.next; mi; mi = mi->next) { 5227c478bd9Sstevel@tonic-gate lend = lbase + (mi->data_end - mi->txt_origin); 5237c478bd9Sstevel@tonic-gate if ((lbase < modules.load_base && lend < modules.load_base) || 5247c478bd9Sstevel@tonic-gate (lbase > modules.load_end && lend > modules.load_end)) { 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate mi->load_base = lbase; 5277c478bd9Sstevel@tonic-gate mi->load_end = lend; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* just to give an appearance of reality */ 5307c478bd9Sstevel@tonic-gate lbase = CEIL(lend + PGSZ, PGSZ); 5317c478bd9Sstevel@tonic-gate } else { 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * can't use this lbase & lend pair, as it 5347c478bd9Sstevel@tonic-gate * overlaps with aout's addresses 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate mi->load_base = CEIL(modules.load_end + PGSZ, PGSZ); 5377c478bd9Sstevel@tonic-gate mi->load_end = mi->load_base + (lend - lbase); 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate lbase = CEIL(mi->load_end + PGSZ, PGSZ); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate static void 5457c478bd9Sstevel@tonic-gate dump_gprofhdr(FILE *fp, char *filename) 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate ProfHeader prof_hdr; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate prof_hdr.h_magic = PROF_MAGIC; 5507c478bd9Sstevel@tonic-gate prof_hdr.h_major_ver = PROF_MAJOR_VERSION; 5517c478bd9Sstevel@tonic-gate prof_hdr.h_minor_ver = PROF_MINOR_VERSION; 5527c478bd9Sstevel@tonic-gate prof_hdr.size = PROFHDR_SZ; 5537c478bd9Sstevel@tonic-gate if (fwrite(&prof_hdr, sizeof (prof_hdr), 1, fp) != 1) { 5547c478bd9Sstevel@tonic-gate perror(filename); 5557c478bd9Sstevel@tonic-gate exit(EX_IOERR); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 55892ed1782Smike_s /* CONSTCOND */ 5597c478bd9Sstevel@tonic-gate if (HDR_FILLER) 56092ed1782Smike_s (void) fseek(fp, HDR_FILLER, SEEK_CUR); 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate static void 5647c478bd9Sstevel@tonic-gate dumpsum_ostyle(char *sumfile) 5657c478bd9Sstevel@tonic-gate { 56692ed1782Smike_s nltype *nlp; 56792ed1782Smike_s arctype *arcp; 5687c478bd9Sstevel@tonic-gate struct rawarc arc; 5697c478bd9Sstevel@tonic-gate struct rawarc32 arc32; 5707c478bd9Sstevel@tonic-gate FILE *sfile; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate if ((sfile = fopen(sumfile, "w")) == NULL) { 5737c478bd9Sstevel@tonic-gate perror(sumfile); 5747c478bd9Sstevel@tonic-gate exit(EX_IOERR); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * dump the header; use the last header read in 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate if (Bflag) { 5807c478bd9Sstevel@tonic-gate if (fwrite(&h, sizeof (h), 1, sfile) != 1) { 5817c478bd9Sstevel@tonic-gate perror(sumfile); 5827c478bd9Sstevel@tonic-gate exit(EX_IOERR); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate } else { 5857c478bd9Sstevel@tonic-gate struct hdr32 hdr; 5867c478bd9Sstevel@tonic-gate hdr.lowpc = (pctype32)h.lowpc; 5877c478bd9Sstevel@tonic-gate hdr.highpc = (pctype32)h.highpc; 5887c478bd9Sstevel@tonic-gate hdr.ncnt = (pctype32)h.ncnt; 5897c478bd9Sstevel@tonic-gate if (fwrite(&hdr, sizeof (hdr), 1, sfile) != 1) { 5907c478bd9Sstevel@tonic-gate perror(sumfile); 5917c478bd9Sstevel@tonic-gate exit(EX_IOERR); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate /* 5957c478bd9Sstevel@tonic-gate * dump the samples 5967c478bd9Sstevel@tonic-gate */ 5977c478bd9Sstevel@tonic-gate if (fwrite(samples, sizeof (unsigned_UNIT), nsamples, sfile) != 5987c478bd9Sstevel@tonic-gate nsamples) { 5997c478bd9Sstevel@tonic-gate perror(sumfile); 6007c478bd9Sstevel@tonic-gate exit(EX_IOERR); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * dump the normalized raw arc information. For old-style dumping, 6047c478bd9Sstevel@tonic-gate * the only namelist is in modules.nl 6057c478bd9Sstevel@tonic-gate */ 6067c478bd9Sstevel@tonic-gate for (nlp = modules.nl; nlp < modules.npe; nlp++) { 6077c478bd9Sstevel@tonic-gate for (arcp = nlp->children; arcp; 6087c478bd9Sstevel@tonic-gate arcp = arcp->arc_childlist) { 6097c478bd9Sstevel@tonic-gate if (Bflag) { 6107c478bd9Sstevel@tonic-gate arc.raw_frompc = arcp->arc_parentp->value; 6117c478bd9Sstevel@tonic-gate arc.raw_selfpc = arcp->arc_childp->value; 6127c478bd9Sstevel@tonic-gate arc.raw_count = arcp->arc_count; 6137c478bd9Sstevel@tonic-gate if (fwrite(&arc, sizeof (arc), 1, sfile) != 1) { 6147c478bd9Sstevel@tonic-gate perror(sumfile); 6157c478bd9Sstevel@tonic-gate exit(EX_IOERR); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate } else { 6187c478bd9Sstevel@tonic-gate arc32.raw_frompc = 6197c478bd9Sstevel@tonic-gate (pctype32)arcp->arc_parentp->value; 6207c478bd9Sstevel@tonic-gate arc32.raw_selfpc = 6217c478bd9Sstevel@tonic-gate (pctype32)arcp->arc_childp->value; 6227c478bd9Sstevel@tonic-gate arc32.raw_count = (actype32)arcp->arc_count; 623*1dd08564Sab196087 if (fwrite(&arc32, sizeof (arc32), 1, sfile) != 624*1dd08564Sab196087 1) { 6257c478bd9Sstevel@tonic-gate perror(sumfile); 6267c478bd9Sstevel@tonic-gate exit(EX_IOERR); 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate #ifdef DEBUG 6307c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 63192ed1782Smike_s (void) printf( 63292ed1782Smike_s "[dumpsum_ostyle] frompc 0x%llx selfpc " 6337c478bd9Sstevel@tonic-gate "0x%llx count %lld\n", arc.raw_frompc, 6347c478bd9Sstevel@tonic-gate arc.raw_selfpc, arc.raw_count); 6357c478bd9Sstevel@tonic-gate } 63692ed1782Smike_s #endif /* DEBUG */ 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate } 63992ed1782Smike_s (void) fclose(sfile); 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * dump out the gmon.sum file 6447c478bd9Sstevel@tonic-gate */ 6457c478bd9Sstevel@tonic-gate static void 6467c478bd9Sstevel@tonic-gate dumpsum(char *sumfile) 6477c478bd9Sstevel@tonic-gate { 6487c478bd9Sstevel@tonic-gate FILE *sfile; 6497c478bd9Sstevel@tonic-gate size_t pathbuf_sz; 6507c478bd9Sstevel@tonic-gate unsigned long total_arcs; /* total number of arcs in all */ 6517c478bd9Sstevel@tonic-gate unsigned long ncallees; /* no. of callees with parents */ 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate if (old_style) { 6547c478bd9Sstevel@tonic-gate dumpsum_ostyle(sumfile); 6557c478bd9Sstevel@tonic-gate return; 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate if ((sfile = fopen(sumfile, "w")) == NULL) { 6597c478bd9Sstevel@tonic-gate perror(sumfile); 6607c478bd9Sstevel@tonic-gate exit(EX_IOERR); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * Dump the new-style gprof header. Even if one of the original 6657c478bd9Sstevel@tonic-gate * profiled-files was of a older version, the summed file is of 6667c478bd9Sstevel@tonic-gate * current version only. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate dump_gprofhdr(sfile, sumfile); 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate /* 6717c478bd9Sstevel@tonic-gate * Fix up load-maps and dump out modules info 6727c478bd9Sstevel@tonic-gate * 6737c478bd9Sstevel@tonic-gate * Fix up module load maps so inactive modules get *some* address 6747c478bd9Sstevel@tonic-gate * (and btw, could you get the total size of non-aout module path 6757c478bd9Sstevel@tonic-gate * strings please ?) 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate fixup_maps(&pathbuf_sz); 6787c478bd9Sstevel@tonic-gate dump_modules(sfile, sumfile, pathbuf_sz); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * Dump out the summ'd pcsamples 6837c478bd9Sstevel@tonic-gate * 6847c478bd9Sstevel@tonic-gate * For dumping call graph information later, we need certain 6857c478bd9Sstevel@tonic-gate * statistics (like total arcs, number of callers for each node); 6867c478bd9Sstevel@tonic-gate * collect these also while we are at it. 6877c478bd9Sstevel@tonic-gate */ 6887c478bd9Sstevel@tonic-gate dump_pcsamples(sfile, sumfile, &total_arcs, &ncallees); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * Dump out the summ'd call graph information 6927c478bd9Sstevel@tonic-gate */ 6937c478bd9Sstevel@tonic-gate dump_callgraph(sfile, sumfile, total_arcs, ncallees); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate 69692ed1782Smike_s (void) fclose(sfile); 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate static void 7007c478bd9Sstevel@tonic-gate tally(mod_info_t *caller_mod, mod_info_t *callee_mod, struct rawarc *rawp) 7017c478bd9Sstevel@tonic-gate { 7027c478bd9Sstevel@tonic-gate nltype *parentp; 7037c478bd9Sstevel@tonic-gate nltype *childp; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* 7067c478bd9Sstevel@tonic-gate * if count == 0 this is a null arc and 7077c478bd9Sstevel@tonic-gate * we don't need to tally it. 7087c478bd9Sstevel@tonic-gate */ 7097c478bd9Sstevel@tonic-gate if (rawp->raw_count == 0) 7107c478bd9Sstevel@tonic-gate return; 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate /* 7137c478bd9Sstevel@tonic-gate * Lookup the caller and callee pcs in namelists of 7147c478bd9Sstevel@tonic-gate * appropriate modules 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate parentp = nllookup(caller_mod, rawp->raw_frompc, NULL); 7177c478bd9Sstevel@tonic-gate childp = nllookup(callee_mod, rawp->raw_selfpc, NULL); 7187c478bd9Sstevel@tonic-gate if (childp && parentp) { 7197c478bd9Sstevel@tonic-gate if (!Dflag) 7207c478bd9Sstevel@tonic-gate childp->ncall += rawp->raw_count; 7217c478bd9Sstevel@tonic-gate else { 7227c478bd9Sstevel@tonic-gate if (first_file) 7237c478bd9Sstevel@tonic-gate childp->ncall += rawp->raw_count; 7247c478bd9Sstevel@tonic-gate else { 7257c478bd9Sstevel@tonic-gate childp->ncall -= rawp->raw_count; 7267c478bd9Sstevel@tonic-gate if (childp->ncall < 0) 7277c478bd9Sstevel@tonic-gate childp->ncall = 0; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate #ifdef DEBUG 7327c478bd9Sstevel@tonic-gate if (debug & TALLYDEBUG) { 73392ed1782Smike_s (void) printf("[tally] arc from %s to %s traversed " 7347c478bd9Sstevel@tonic-gate "%lld times\n", parentp->name, 7357c478bd9Sstevel@tonic-gate childp->name, rawp->raw_count); 7367c478bd9Sstevel@tonic-gate } 73792ed1782Smike_s #endif /* DEBUG */ 7387c478bd9Sstevel@tonic-gate addarc(parentp, childp, rawp->raw_count); 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate /* 7437c478bd9Sstevel@tonic-gate * Look up a module's base address in a sorted list of pc-hits. Unlike 7447c478bd9Sstevel@tonic-gate * nllookup(), this deals with misses by mapping them to the next *higher* 7457c478bd9Sstevel@tonic-gate * pc-hit. This is so that we get into the module's first pc-hit rightaway, 7467c478bd9Sstevel@tonic-gate * even if the module's entry-point (load_base) itself is not a hit. 7477c478bd9Sstevel@tonic-gate */ 7487c478bd9Sstevel@tonic-gate static Address * 7497c478bd9Sstevel@tonic-gate locate(Address *pclist, size_t nelem, Address keypc) 7507c478bd9Sstevel@tonic-gate { 7517c478bd9Sstevel@tonic-gate size_t low = 0, middle, high = nelem - 1; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate if (keypc <= pclist[low]) 7547c478bd9Sstevel@tonic-gate return (pclist); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate if (keypc > pclist[high]) 7577c478bd9Sstevel@tonic-gate return (NULL); 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate while (low != high) { 7607c478bd9Sstevel@tonic-gate middle = (high + low) >> 1; 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate if ((pclist[middle] < keypc) && (pclist[middle + 1] >= keypc)) 7637c478bd9Sstevel@tonic-gate return (&pclist[middle + 1]); 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate if (pclist[middle] >= keypc) 7667c478bd9Sstevel@tonic-gate high = middle; 7677c478bd9Sstevel@tonic-gate else 7687c478bd9Sstevel@tonic-gate low = middle + 1; 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* must never reach here! */ 7727c478bd9Sstevel@tonic-gate return (NULL); 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate static void 77692ed1782Smike_s assign_pcsamples(mod_info_t *module, Address *pcsmpl, size_t n_samples) 7777c478bd9Sstevel@tonic-gate { 7787c478bd9Sstevel@tonic-gate Address *pcptr, *pcse = pcsmpl + n_samples; 7797c478bd9Sstevel@tonic-gate pctype nxt_func; 7807c478bd9Sstevel@tonic-gate nltype *fnl; 7817c478bd9Sstevel@tonic-gate size_t func_nticks; 7827c478bd9Sstevel@tonic-gate #ifdef DEBUG 7837c478bd9Sstevel@tonic-gate size_t n_hits_in_module = 0; 78492ed1782Smike_s #endif /* DEBUG */ 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate /* Locate the first pc-hit for this module */ 7877c478bd9Sstevel@tonic-gate if ((pcptr = locate(pcsmpl, n_samples, module->load_base)) == NULL) { 7887c478bd9Sstevel@tonic-gate #ifdef DEBUG 7897c478bd9Sstevel@tonic-gate if (debug & PCSMPLDEBUG) { 79092ed1782Smike_s (void) printf("[assign_pcsamples] no pc-hits in\n"); 79192ed1782Smike_s (void) printf( 79292ed1782Smike_s " `%s'\n", module->name); 7937c478bd9Sstevel@tonic-gate } 79492ed1782Smike_s #endif /* DEBUG */ 7957c478bd9Sstevel@tonic-gate return; /* no pc-hits in this module */ 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /* Assign all pc-hits in this module to appropriate functions */ 7997c478bd9Sstevel@tonic-gate while ((pcptr < pcse) && (*pcptr < module->load_end)) { 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* Update the corresponding function's time */ 8027c478bd9Sstevel@tonic-gate if (fnl = nllookup(module, (pctype) *pcptr, &nxt_func)) { 8037c478bd9Sstevel@tonic-gate /* 8047c478bd9Sstevel@tonic-gate * Collect all pc-hits in this function. Each 8057c478bd9Sstevel@tonic-gate * pc-hit counts as 1 tick. 8067c478bd9Sstevel@tonic-gate */ 8077c478bd9Sstevel@tonic-gate func_nticks = 0; 8087c478bd9Sstevel@tonic-gate while ((pcptr < pcse) && (*pcptr < nxt_func)) { 8097c478bd9Sstevel@tonic-gate func_nticks++; 8107c478bd9Sstevel@tonic-gate pcptr++; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate if (func_nticks == 0) 8147c478bd9Sstevel@tonic-gate pcptr++; 8157c478bd9Sstevel@tonic-gate else { 8167c478bd9Sstevel@tonic-gate fnl->nticks += func_nticks; 8177c478bd9Sstevel@tonic-gate fnl->time += func_nticks; 8187c478bd9Sstevel@tonic-gate totime += func_nticks; 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate #ifdef DEBUG 8227c478bd9Sstevel@tonic-gate n_hits_in_module += func_nticks; 82392ed1782Smike_s #endif /* DEBUG */ 8247c478bd9Sstevel@tonic-gate } else { 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * pc sample could not be assigned to function; 8277c478bd9Sstevel@tonic-gate * probably in a PLT 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate pcptr++; 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate #ifdef DEBUG 8347c478bd9Sstevel@tonic-gate if (debug & PCSMPLDEBUG) { 83592ed1782Smike_s (void) printf( 83692ed1782Smike_s "[assign_pcsamples] %ld hits in\n", n_hits_in_module); 83792ed1782Smike_s (void) printf(" `%s'\n", module->name); 8387c478bd9Sstevel@tonic-gate } 83992ed1782Smike_s #endif /* DEBUG */ 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate int 84392ed1782Smike_s pc_cmp(const void *arg1, const void *arg2) 8447c478bd9Sstevel@tonic-gate { 84592ed1782Smike_s Address *pc1 = (Address *)arg1; 84692ed1782Smike_s Address *pc2 = (Address *)arg2; 84792ed1782Smike_s 8487c478bd9Sstevel@tonic-gate if (*pc1 > *pc2) 8497c478bd9Sstevel@tonic-gate return (1); 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate if (*pc1 < *pc2) 8527c478bd9Sstevel@tonic-gate return (-1); 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate return (0); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate static void 85892ed1782Smike_s process_pcsamples(ProfBuffer *bufp) 8597c478bd9Sstevel@tonic-gate { 8607c478bd9Sstevel@tonic-gate Address *pc_samples; 8617c478bd9Sstevel@tonic-gate mod_info_t *mi; 8627c478bd9Sstevel@tonic-gate caddr_t p; 8637c478bd9Sstevel@tonic-gate size_t chunk_size, nelem_read, nelem_to_read; 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate #ifdef DEBUG 8667c478bd9Sstevel@tonic-gate if (debug & PCSMPLDEBUG) { 86792ed1782Smike_s (void) printf( 86892ed1782Smike_s "[process_pcsamples] number of pcsamples = %lld\n", 8697c478bd9Sstevel@tonic-gate bufp->bufsize); 8707c478bd9Sstevel@tonic-gate } 87192ed1782Smike_s #endif /* DEBUG */ 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate /* buffer with no pc samples ? */ 8747c478bd9Sstevel@tonic-gate if (bufp->bufsize == 0) 8757c478bd9Sstevel@tonic-gate return; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* 8787c478bd9Sstevel@tonic-gate * If we're processing pcsamples of a profile sum, we could have 8797c478bd9Sstevel@tonic-gate * more than PROF_BUFFER_SIZE number of samples. In such a case, 8807c478bd9Sstevel@tonic-gate * we must read the pcsamples in chunks. 8817c478bd9Sstevel@tonic-gate */ 8827c478bd9Sstevel@tonic-gate if ((chunk_size = bufp->bufsize) > PROF_BUFFER_SIZE) 8837c478bd9Sstevel@tonic-gate chunk_size = PROF_BUFFER_SIZE; 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* Allocate for the pcsample chunk */ 8867c478bd9Sstevel@tonic-gate pc_samples = (Address *) calloc(chunk_size, sizeof (Address)); 8877c478bd9Sstevel@tonic-gate if (pc_samples == NULL) { 88892ed1782Smike_s (void) fprintf(stderr, "%s: no room for %d sample pc's\n", 8897c478bd9Sstevel@tonic-gate whoami, chunk_size); 8907c478bd9Sstevel@tonic-gate exit(EX_OSERR); 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* Copy the current set of pcsamples */ 8947c478bd9Sstevel@tonic-gate nelem_read = 0; 8957c478bd9Sstevel@tonic-gate nelem_to_read = bufp->bufsize; 8967c478bd9Sstevel@tonic-gate p = (char *)bufp + bufp->buffer; 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate while (nelem_read < nelem_to_read) { 89992ed1782Smike_s (void) memcpy((void *) pc_samples, p, 90092ed1782Smike_s chunk_size * sizeof (Address)); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate /* Sort the pc samples */ 90392ed1782Smike_s qsort(pc_samples, chunk_size, sizeof (Address), pc_cmp); 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate /* 9067c478bd9Sstevel@tonic-gate * Assign pcsamples to functions in the currently active 9077c478bd9Sstevel@tonic-gate * module list 9087c478bd9Sstevel@tonic-gate */ 9097c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 9107c478bd9Sstevel@tonic-gate if (mi->active == FALSE) 9117c478bd9Sstevel@tonic-gate continue; 9127c478bd9Sstevel@tonic-gate assign_pcsamples(mi, pc_samples, chunk_size); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate p += (chunk_size * sizeof (Address)); 9167c478bd9Sstevel@tonic-gate nelem_read += chunk_size; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate if ((nelem_to_read - nelem_read) < chunk_size) 9197c478bd9Sstevel@tonic-gate chunk_size = nelem_to_read - nelem_read; 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate free(pc_samples); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* Update total number of pcsamples read so far */ 9257c478bd9Sstevel@tonic-gate n_pcsamples += bufp->bufsize; 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate static mod_info_t * 9297c478bd9Sstevel@tonic-gate find_module(Address addr) 9307c478bd9Sstevel@tonic-gate { 9317c478bd9Sstevel@tonic-gate mod_info_t *mi; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 9347c478bd9Sstevel@tonic-gate if (mi->active == FALSE) 9357c478bd9Sstevel@tonic-gate continue; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate if (addr >= mi->load_base && addr < mi->load_end) 9387c478bd9Sstevel@tonic-gate return (mi); 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate return (NULL); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate static void 94592ed1782Smike_s process_cgraph(ProfCallGraph *cgp) 9467c478bd9Sstevel@tonic-gate { 9477c478bd9Sstevel@tonic-gate struct rawarc arc; 9487c478bd9Sstevel@tonic-gate mod_info_t *callee_mi, *caller_mi; 9497c478bd9Sstevel@tonic-gate ProfFunction *calleep, *callerp; 9507c478bd9Sstevel@tonic-gate Index caller_off, callee_off; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate /* 9537c478bd9Sstevel@tonic-gate * Note that *callee_off* increment in the for loop below 9547c478bd9Sstevel@tonic-gate * uses *calleep* and *calleep* doesn't get set until the for loop 9557c478bd9Sstevel@tonic-gate * is entered. We don't expect the increment to be executed before 9567c478bd9Sstevel@tonic-gate * the loop body is executed atleast once, so this should be ok. 9577c478bd9Sstevel@tonic-gate */ 9587c478bd9Sstevel@tonic-gate for (callee_off = cgp->functions; callee_off; 9597c478bd9Sstevel@tonic-gate callee_off = calleep->next_to) { 9607c478bd9Sstevel@tonic-gate 96192ed1782Smike_s /* LINTED: pointer cast */ 9627c478bd9Sstevel@tonic-gate calleep = (ProfFunction *)((char *)cgp + callee_off); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate /* 9657c478bd9Sstevel@tonic-gate * We could choose either to sort the {caller, callee} 9667c478bd9Sstevel@tonic-gate * list twice and assign callee/caller to modules or inspect 9677c478bd9Sstevel@tonic-gate * each callee/caller in the active modules list. Since 9687c478bd9Sstevel@tonic-gate * the modules list is usually very small, we'l choose the 9697c478bd9Sstevel@tonic-gate * latter. 9707c478bd9Sstevel@tonic-gate */ 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * If we cannot identify a callee with a module, there's 9747c478bd9Sstevel@tonic-gate * no use worrying about who called it. 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate if ((callee_mi = find_module(calleep->topc)) == NULL) { 9777c478bd9Sstevel@tonic-gate #ifdef DEBUG 9787c478bd9Sstevel@tonic-gate if (debug & CGRAPHDEBUG) { 97992ed1782Smike_s (void) printf( 98092ed1782Smike_s "[process_cgraph] callee %#llx missed\n", 9817c478bd9Sstevel@tonic-gate calleep->topc); 9827c478bd9Sstevel@tonic-gate } 98392ed1782Smike_s #endif /* DEBUG */ 9847c478bd9Sstevel@tonic-gate continue; 9857c478bd9Sstevel@tonic-gate } else 9867c478bd9Sstevel@tonic-gate arc.raw_selfpc = calleep->topc; 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate for (caller_off = callee_off; caller_off; 9897c478bd9Sstevel@tonic-gate caller_off = callerp->next_from) { 9907c478bd9Sstevel@tonic-gate 99192ed1782Smike_s /* LINTED: pointer cast */ 9927c478bd9Sstevel@tonic-gate callerp = (ProfFunction *)((char *)cgp + caller_off); 9937c478bd9Sstevel@tonic-gate if ((caller_mi = find_module(callerp->frompc)) == 9947c478bd9Sstevel@tonic-gate NULL) { 9957c478bd9Sstevel@tonic-gate #ifdef DEBUG 9967c478bd9Sstevel@tonic-gate if (debug & CGRAPHDEBUG) { 99792ed1782Smike_s (void) printf( 99892ed1782Smike_s "[process_cgraph] caller %#llx " 9997c478bd9Sstevel@tonic-gate "missed\n", callerp->frompc); 10007c478bd9Sstevel@tonic-gate } 100192ed1782Smike_s #endif /* DEBUG */ 10027c478bd9Sstevel@tonic-gate continue; 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate arc.raw_frompc = callerp->frompc; 10067c478bd9Sstevel@tonic-gate arc.raw_count = callerp->count; 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate #ifdef DEBUG 10097c478bd9Sstevel@tonic-gate if (debug & CGRAPHDEBUG) { 101092ed1782Smike_s (void) printf( 101192ed1782Smike_s "[process_cgraph] arc <%#llx, %#llx, " 101292ed1782Smike_s "%lld>\n", arc.raw_frompc, arc.raw_selfpc, 101392ed1782Smike_s arc.raw_count); 10147c478bd9Sstevel@tonic-gate } 101592ed1782Smike_s #endif /* DEBUG */ 10167c478bd9Sstevel@tonic-gate tally(caller_mi, callee_mi, &arc); 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate #ifdef DEBUG 10217c478bd9Sstevel@tonic-gate puts("\n"); 102292ed1782Smike_s #endif /* DEBUG */ 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate /* 10267c478bd9Sstevel@tonic-gate * Two modules overlap each other if they don't lie completely *outside* 10277c478bd9Sstevel@tonic-gate * each other. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate static bool 10307c478bd9Sstevel@tonic-gate does_overlap(ProfModule *new, mod_info_t *old) 10317c478bd9Sstevel@tonic-gate { 10327c478bd9Sstevel@tonic-gate /* case 1: new module lies completely *before* the old one */ 10337c478bd9Sstevel@tonic-gate if (new->startaddr < old->load_base && new->endaddr <= old->load_base) 10347c478bd9Sstevel@tonic-gate return (FALSE); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* case 2: new module lies completely *after* the old one */ 10377c478bd9Sstevel@tonic-gate if (new->startaddr >= old->load_end && new->endaddr >= old->load_end) 10387c478bd9Sstevel@tonic-gate return (FALSE); 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate /* probably a dlopen: the modules overlap each other */ 10417c478bd9Sstevel@tonic-gate return (TRUE); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate static bool 10457c478bd9Sstevel@tonic-gate is_same_as_aout(char *modpath, struct stat *buf) 10467c478bd9Sstevel@tonic-gate { 10477c478bd9Sstevel@tonic-gate if (stat(modpath, buf) == -1) { 104892ed1782Smike_s (void) fprintf(stderr, "%s: can't get info on `%s'\n", 10497c478bd9Sstevel@tonic-gate whoami, modpath); 10507c478bd9Sstevel@tonic-gate exit(EX_NOINPUT); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate if ((buf->st_dev == aout_info.dev) && (buf->st_ino == aout_info.ino)) 10547c478bd9Sstevel@tonic-gate return (TRUE); 10557c478bd9Sstevel@tonic-gate else 10567c478bd9Sstevel@tonic-gate return (FALSE); 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate static void 106092ed1782Smike_s process_modules(ProfModuleList *modlp) 10617c478bd9Sstevel@tonic-gate { 10627c478bd9Sstevel@tonic-gate ProfModule *newmodp; 10637c478bd9Sstevel@tonic-gate mod_info_t *mi, *last, *new_module; 106492ed1782Smike_s char *so_path; 10657c478bd9Sstevel@tonic-gate bool more_modules = TRUE; 10667c478bd9Sstevel@tonic-gate struct stat so_statbuf; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate #ifdef DEBUG 10697c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 107092ed1782Smike_s (void) printf("[process_modules] module obj version %u\n", 10717c478bd9Sstevel@tonic-gate modlp->version); 10727c478bd9Sstevel@tonic-gate } 107392ed1782Smike_s #endif /* DEBUG */ 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate /* Check version of module type object */ 10767c478bd9Sstevel@tonic-gate if (modlp->version > PROF_MODULES_VER) { 107792ed1782Smike_s (void) fprintf(stderr, "%s: version %d for module type objects" 10787c478bd9Sstevel@tonic-gate "is not supported\n", whoami, modlp->version); 10797c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate /* 10847c478bd9Sstevel@tonic-gate * Scan the PROF_MODULES_T list and add modules to current list 10857c478bd9Sstevel@tonic-gate * of modules, if they're not present already 10867c478bd9Sstevel@tonic-gate */ 108792ed1782Smike_s /* LINTED: pointer cast */ 10887c478bd9Sstevel@tonic-gate newmodp = (ProfModule *)((char *)modlp + modlp->modules); 10897c478bd9Sstevel@tonic-gate do { 10907c478bd9Sstevel@tonic-gate /* 10917c478bd9Sstevel@tonic-gate * Since the prog could've been renamed after its run, we 10927c478bd9Sstevel@tonic-gate * should see if this overlaps a.out. If it does, it is 10937c478bd9Sstevel@tonic-gate * probably the renamed aout. We should also skip any other 10947c478bd9Sstevel@tonic-gate * non-sharedobj's that we see (or should we report an error ?) 10957c478bd9Sstevel@tonic-gate */ 10967c478bd9Sstevel@tonic-gate so_path = (caddr_t)modlp + newmodp->path; 10977c478bd9Sstevel@tonic-gate if (does_overlap(newmodp, &modules) || 10987c478bd9Sstevel@tonic-gate is_same_as_aout(so_path, &so_statbuf) || 10997c478bd9Sstevel@tonic-gate (!is_shared_obj(so_path))) { 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate if (!newmodp->next) 11027c478bd9Sstevel@tonic-gate more_modules = FALSE; 11037c478bd9Sstevel@tonic-gate 110492ed1782Smike_s /* LINTED: pointer cast */ 11057c478bd9Sstevel@tonic-gate newmodp = (ProfModule *) 11067c478bd9Sstevel@tonic-gate ((caddr_t)modlp + newmodp->next); 11077c478bd9Sstevel@tonic-gate #ifdef DEBUG 11087c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 110992ed1782Smike_s (void) printf( 111092ed1782Smike_s "[process_modules] `%s'\n", so_path); 111192ed1782Smike_s (void) printf(" skipped\n"); 11127c478bd9Sstevel@tonic-gate } 111392ed1782Smike_s #endif /* DEBUG */ 11147c478bd9Sstevel@tonic-gate continue; 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate #ifdef DEBUG 11177c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) 111892ed1782Smike_s (void) printf("[process_modules] `%s'...\n", so_path); 111992ed1782Smike_s #endif /* DEBUG */ 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate /* 11227c478bd9Sstevel@tonic-gate * Check all modules (leave the first one, 'cos that 11237c478bd9Sstevel@tonic-gate * is the program executable info). If this module is already 11247c478bd9Sstevel@tonic-gate * there in the list, update the load addresses and proceed. 11257c478bd9Sstevel@tonic-gate */ 11267c478bd9Sstevel@tonic-gate last = &modules; 112792ed1782Smike_s while ((mi = last->next) != NULL) { 11287c478bd9Sstevel@tonic-gate /* 11297c478bd9Sstevel@tonic-gate * We expect the full pathname for all shared objects 11307c478bd9Sstevel@tonic-gate * needed by the program executable. In this case, we 11317c478bd9Sstevel@tonic-gate * simply need to compare the paths to see if they are 11327c478bd9Sstevel@tonic-gate * the same file. 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate if (strcmp(mi->name, so_path) == 0) 11357c478bd9Sstevel@tonic-gate break; 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate /* 11387c478bd9Sstevel@tonic-gate * Check if this new shared object will overlap 11397c478bd9Sstevel@tonic-gate * any existing module. If yes, remove the old one 11407c478bd9Sstevel@tonic-gate * from the linked list (but don't free it, 'cos 11417c478bd9Sstevel@tonic-gate * there may be symbols referring to this module 11427c478bd9Sstevel@tonic-gate * still) 11437c478bd9Sstevel@tonic-gate */ 11447c478bd9Sstevel@tonic-gate if (does_overlap(newmodp, mi)) { 11457c478bd9Sstevel@tonic-gate #ifdef DEBUG 11467c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 114792ed1782Smike_s (void) printf( 114892ed1782Smike_s "[process_modules] `%s'\n", 11497c478bd9Sstevel@tonic-gate so_path); 115092ed1782Smike_s (void) printf( 115192ed1782Smike_s " overlaps\n"); 115292ed1782Smike_s (void) printf( 115392ed1782Smike_s " `%s'\n", 11547c478bd9Sstevel@tonic-gate mi->name); 11557c478bd9Sstevel@tonic-gate } 115692ed1782Smike_s #endif /* DEBUG */ 11577c478bd9Sstevel@tonic-gate mi->active = FALSE; 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate last = mi; 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* Module already there, skip it */ 11647c478bd9Sstevel@tonic-gate if (mi != NULL) { 11657c478bd9Sstevel@tonic-gate mi->load_base = newmodp->startaddr; 11667c478bd9Sstevel@tonic-gate mi->load_end = newmodp->endaddr; 11677c478bd9Sstevel@tonic-gate mi->active = TRUE; 11687c478bd9Sstevel@tonic-gate if (!newmodp->next) 11697c478bd9Sstevel@tonic-gate more_modules = FALSE; 11707c478bd9Sstevel@tonic-gate 117192ed1782Smike_s /* LINTED: pointer cast */ 11727c478bd9Sstevel@tonic-gate newmodp = (ProfModule *) 11737c478bd9Sstevel@tonic-gate ((caddr_t)modlp + newmodp->next); 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate #ifdef DEBUG 11767c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 117792ed1782Smike_s (void) printf("[process_modules] base=%#llx, " 1178*1dd08564Sab196087 "end=%#llx\n", mi->load_base, mi->load_end); 11797c478bd9Sstevel@tonic-gate } 118092ed1782Smike_s #endif /* DEBUG */ 11817c478bd9Sstevel@tonic-gate continue; 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* 11857c478bd9Sstevel@tonic-gate * Check if gmon.out is outdated with respect to the new 11867c478bd9Sstevel@tonic-gate * module we want to add 11877c478bd9Sstevel@tonic-gate */ 11887c478bd9Sstevel@tonic-gate if (gmonout_info.mtime < so_statbuf.st_mtime) { 118992ed1782Smike_s (void) fprintf(stderr, 119092ed1782Smike_s "%s: shared obj outdates prof info\n", whoami); 119192ed1782Smike_s (void) fprintf(stderr, "\t(newer %s)\n", so_path); 11927c478bd9Sstevel@tonic-gate exit(EX_NOINPUT); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate /* Create a new module element */ 119692ed1782Smike_s new_module = malloc(sizeof (mod_info_t)); 11977c478bd9Sstevel@tonic-gate if (new_module == NULL) { 119892ed1782Smike_s (void) fprintf(stderr, "%s: no room for %d bytes\n", 11997c478bd9Sstevel@tonic-gate whoami, sizeof (mod_info_t)); 12007c478bd9Sstevel@tonic-gate exit(EX_OSERR); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate /* and fill in info... */ 12047c478bd9Sstevel@tonic-gate new_module->id = n_modules + 1; 12057c478bd9Sstevel@tonic-gate new_module->load_base = newmodp->startaddr; 12067c478bd9Sstevel@tonic-gate new_module->load_end = newmodp->endaddr; 120792ed1782Smike_s new_module->name = malloc(strlen(so_path) + 1); 12087c478bd9Sstevel@tonic-gate if (new_module->name == NULL) { 120992ed1782Smike_s (void) fprintf(stderr, "%s: no room for %d bytes\n", 12107c478bd9Sstevel@tonic-gate whoami, strlen(so_path) + 1); 12117c478bd9Sstevel@tonic-gate exit(EX_OSERR); 12127c478bd9Sstevel@tonic-gate } 121392ed1782Smike_s (void) strcpy(new_module->name, so_path); 12147c478bd9Sstevel@tonic-gate #ifdef DEBUG 12157c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 121692ed1782Smike_s (void) printf( 121792ed1782Smike_s "[process_modules] base=%#llx, end=%#llx\n", 12187c478bd9Sstevel@tonic-gate new_module->load_base, new_module->load_end); 12197c478bd9Sstevel@tonic-gate } 122092ed1782Smike_s #endif /* DEBUG */ 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate /* Create this module's nameslist */ 12237c478bd9Sstevel@tonic-gate process_namelist(new_module); 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate /* Add it to the tail of active module list */ 12267c478bd9Sstevel@tonic-gate last->next = new_module; 12277c478bd9Sstevel@tonic-gate n_modules++; 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate #ifdef DEBUG 12307c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 123192ed1782Smike_s (void) printf( 123292ed1782Smike_s "[process_modules] total shared objects = %ld\n", 12337c478bd9Sstevel@tonic-gate n_modules - 1); 12347c478bd9Sstevel@tonic-gate } 123592ed1782Smike_s #endif /* DEBUG */ 12367c478bd9Sstevel@tonic-gate /* 12377c478bd9Sstevel@tonic-gate * Move to the next module in the PROF_MODULES_T list 12387c478bd9Sstevel@tonic-gate * (if present) 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate if (!newmodp->next) 12417c478bd9Sstevel@tonic-gate more_modules = FALSE; 12427c478bd9Sstevel@tonic-gate 124392ed1782Smike_s /* LINTED: pointer cast */ 12447c478bd9Sstevel@tonic-gate newmodp = (ProfModule *)((caddr_t)modlp + newmodp->next); 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate } while (more_modules); 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate static void 125092ed1782Smike_s reset_active_modules(void) 12517c478bd9Sstevel@tonic-gate { 12527c478bd9Sstevel@tonic-gate mod_info_t *mi; 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate /* Except the executable, no other module should remain active */ 12557c478bd9Sstevel@tonic-gate for (mi = modules.next; mi; mi = mi->next) 12567c478bd9Sstevel@tonic-gate mi->active = FALSE; 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate static void 126092ed1782Smike_s getpfiledata(caddr_t memp, size_t fsz) 12617c478bd9Sstevel@tonic-gate { 12627c478bd9Sstevel@tonic-gate ProfObject *objp; 12637c478bd9Sstevel@tonic-gate caddr_t file_end; 12647c478bd9Sstevel@tonic-gate bool found_pcsamples = FALSE, found_cgraph = FALSE; 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * Before processing a new gmon.out, all modules except the 12687c478bd9Sstevel@tonic-gate * program executable must be made inactive, so that symbols 12697c478bd9Sstevel@tonic-gate * are searched only in the program executable, if we don't 12707c478bd9Sstevel@tonic-gate * find a MODULES_T object. Don't do it *after* we read a gmon.out, 12717c478bd9Sstevel@tonic-gate * because we need the active module data after we're done with 12727c478bd9Sstevel@tonic-gate * the last gmon.out, if we're doing summing. 12737c478bd9Sstevel@tonic-gate */ 12747c478bd9Sstevel@tonic-gate reset_active_modules(); 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate file_end = memp + fsz; 127792ed1782Smike_s /* LINTED: pointer cast */ 12787c478bd9Sstevel@tonic-gate objp = (ProfObject *)(memp + ((ProfHeader *)memp)->size); 12797c478bd9Sstevel@tonic-gate while ((caddr_t)objp < file_end) { 12807c478bd9Sstevel@tonic-gate #ifdef DEBUG 12817c478bd9Sstevel@tonic-gate { 12827c478bd9Sstevel@tonic-gate unsigned int type = 0; 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate if (debug & MONOUTDEBUG) { 12857c478bd9Sstevel@tonic-gate if (objp->type <= MAX_OBJTYPES) 12867c478bd9Sstevel@tonic-gate type = objp->type; 12877c478bd9Sstevel@tonic-gate 128892ed1782Smike_s (void) printf( 128992ed1782Smike_s "\n[getpfiledata] object %s [%#lx]\n", 12907c478bd9Sstevel@tonic-gate objname[type], objp->type); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate } 129392ed1782Smike_s #endif /* DEBUG */ 12947c478bd9Sstevel@tonic-gate switch (objp->type) { 12957c478bd9Sstevel@tonic-gate case PROF_MODULES_T : 12967c478bd9Sstevel@tonic-gate process_modules((ProfModuleList *) objp); 12977c478bd9Sstevel@tonic-gate break; 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate case PROF_CALLGRAPH_T : 13007c478bd9Sstevel@tonic-gate process_cgraph((ProfCallGraph *) objp); 13017c478bd9Sstevel@tonic-gate found_cgraph = TRUE; 13027c478bd9Sstevel@tonic-gate break; 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate case PROF_BUFFER_T : 13057c478bd9Sstevel@tonic-gate process_pcsamples((ProfBuffer *) objp); 13067c478bd9Sstevel@tonic-gate found_pcsamples = TRUE; 13077c478bd9Sstevel@tonic-gate break; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate default : 131092ed1782Smike_s (void) fprintf(stderr, 13117c478bd9Sstevel@tonic-gate "%s: unknown prof object type=%d\n", 13127c478bd9Sstevel@tonic-gate whoami, objp->type); 13137c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 13147c478bd9Sstevel@tonic-gate } 131592ed1782Smike_s /* LINTED: pointer cast */ 13167c478bd9Sstevel@tonic-gate objp = (ProfObject *)((caddr_t)objp + objp->size); 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate if (!found_cgraph || !found_pcsamples) { 132092ed1782Smike_s (void) fprintf(stderr, 13217c478bd9Sstevel@tonic-gate "%s: missing callgraph/pcsamples object\n", whoami); 13227c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate if ((caddr_t)objp > file_end) { 132692ed1782Smike_s (void) fprintf(stderr, "%s: malformed profile file.\n", whoami); 13277c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate if (first_file) 13317c478bd9Sstevel@tonic-gate first_file = FALSE; 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate static void 133592ed1782Smike_s readarcs(FILE *pfile) 13367c478bd9Sstevel@tonic-gate { 13377c478bd9Sstevel@tonic-gate /* 13387c478bd9Sstevel@tonic-gate * the rest of the file consists of 13397c478bd9Sstevel@tonic-gate * a bunch of <from,self,count> tuples. 13407c478bd9Sstevel@tonic-gate */ 13417c478bd9Sstevel@tonic-gate /* CONSTCOND */ 13427c478bd9Sstevel@tonic-gate while (1) { 13437c478bd9Sstevel@tonic-gate struct rawarc arc; 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate if (rflag) { 13467c478bd9Sstevel@tonic-gate if (Bflag) { 13477c478bd9Sstevel@tonic-gate L_cgarc64 rtld_arc64; 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate /* 13507c478bd9Sstevel@tonic-gate * If rflag is set then this is an profiled 13517c478bd9Sstevel@tonic-gate * image generated by rtld. It needs to be 13527c478bd9Sstevel@tonic-gate * 'converted' to the standard data format. 13537c478bd9Sstevel@tonic-gate */ 13547c478bd9Sstevel@tonic-gate if (fread(&rtld_arc64, 13557c478bd9Sstevel@tonic-gate sizeof (L_cgarc64), 1, pfile) != 1) 13567c478bd9Sstevel@tonic-gate break; 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate if (rtld_arc64.cg_from == PRF_OUTADDR64) 13597c478bd9Sstevel@tonic-gate arc.raw_frompc = s_highpc + 0x10; 13607c478bd9Sstevel@tonic-gate else 13617c478bd9Sstevel@tonic-gate arc.raw_frompc = 13627c478bd9Sstevel@tonic-gate (pctype)rtld_arc64.cg_from; 13637c478bd9Sstevel@tonic-gate arc.raw_selfpc = (pctype)rtld_arc64.cg_to; 13647c478bd9Sstevel@tonic-gate arc.raw_count = (actype)rtld_arc64.cg_count; 13657c478bd9Sstevel@tonic-gate } else { 13667c478bd9Sstevel@tonic-gate L_cgarc rtld_arc; 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate /* 13697c478bd9Sstevel@tonic-gate * If rflag is set then this is an profiled 13707c478bd9Sstevel@tonic-gate * image generated by rtld. It needs to be 13717c478bd9Sstevel@tonic-gate * 'converted' to the standard data format. 13727c478bd9Sstevel@tonic-gate */ 13737c478bd9Sstevel@tonic-gate if (fread(&rtld_arc, 13747c478bd9Sstevel@tonic-gate sizeof (L_cgarc), 1, pfile) != 1) 13757c478bd9Sstevel@tonic-gate break; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate if (rtld_arc.cg_from == PRF_OUTADDR) 13787c478bd9Sstevel@tonic-gate arc.raw_frompc = s_highpc + 0x10; 13797c478bd9Sstevel@tonic-gate else 13807c478bd9Sstevel@tonic-gate arc.raw_frompc = (pctype) 13817c478bd9Sstevel@tonic-gate (uintptr_t)rtld_arc.cg_from; 13827c478bd9Sstevel@tonic-gate arc.raw_selfpc = (pctype) 13837c478bd9Sstevel@tonic-gate (uintptr_t)rtld_arc.cg_to; 13847c478bd9Sstevel@tonic-gate arc.raw_count = (actype)rtld_arc.cg_count; 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate } else { 13877c478bd9Sstevel@tonic-gate if (Bflag) { 13887c478bd9Sstevel@tonic-gate if (fread(&arc, sizeof (struct rawarc), 1, 13897c478bd9Sstevel@tonic-gate pfile) != 1) { 13907c478bd9Sstevel@tonic-gate break; 13917c478bd9Sstevel@tonic-gate } 13927c478bd9Sstevel@tonic-gate } else { 13937c478bd9Sstevel@tonic-gate /* 13947c478bd9Sstevel@tonic-gate * If these aren't big %pc's, we need to read 13957c478bd9Sstevel@tonic-gate * into the 32-bit raw arc structure, and 13967c478bd9Sstevel@tonic-gate * assign the members into the actual arc. 13977c478bd9Sstevel@tonic-gate */ 13987c478bd9Sstevel@tonic-gate struct rawarc32 arc32; 13997c478bd9Sstevel@tonic-gate if (fread(&arc32, sizeof (struct rawarc32), 14007c478bd9Sstevel@tonic-gate 1, pfile) != 1) 14017c478bd9Sstevel@tonic-gate break; 14027c478bd9Sstevel@tonic-gate arc.raw_frompc = (pctype)arc32.raw_frompc; 14037c478bd9Sstevel@tonic-gate arc.raw_selfpc = (pctype)arc32.raw_selfpc; 14047c478bd9Sstevel@tonic-gate arc.raw_count = (actype)arc32.raw_count; 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate #ifdef DEBUG 14097c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 141092ed1782Smike_s (void) printf("[getpfile] frompc 0x%llx selfpc " 14117c478bd9Sstevel@tonic-gate "0x%llx count %lld\n", arc.raw_frompc, 14127c478bd9Sstevel@tonic-gate arc.raw_selfpc, arc.raw_count); 14137c478bd9Sstevel@tonic-gate } 141492ed1782Smike_s #endif /* DEBUG */ 14157c478bd9Sstevel@tonic-gate /* 14167c478bd9Sstevel@tonic-gate * add this arc 14177c478bd9Sstevel@tonic-gate */ 14187c478bd9Sstevel@tonic-gate tally(&modules, &modules, &arc); 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate if (first_file) 14217c478bd9Sstevel@tonic-gate first_file = FALSE; 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate static void 14257c478bd9Sstevel@tonic-gate readsamples(FILE *pfile) 14267c478bd9Sstevel@tonic-gate { 14277c478bd9Sstevel@tonic-gate sztype i; 14287c478bd9Sstevel@tonic-gate unsigned_UNIT sample; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate if (samples == 0) { 14317c478bd9Sstevel@tonic-gate samples = (unsigned_UNIT *) calloc(nsamples, 14327c478bd9Sstevel@tonic-gate sizeof (unsigned_UNIT)); 14337c478bd9Sstevel@tonic-gate if (samples == 0) { 143492ed1782Smike_s (void) fprintf(stderr, 143592ed1782Smike_s "%s: No room for %d sample pc's\n", 14367c478bd9Sstevel@tonic-gate whoami, sampbytes / sizeof (unsigned_UNIT)); 14377c478bd9Sstevel@tonic-gate exit(EX_OSERR); 14387c478bd9Sstevel@tonic-gate } 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate for (i = 0; i < nsamples; i++) { 144292ed1782Smike_s (void) fread(&sample, sizeof (unsigned_UNIT), 1, pfile); 14437c478bd9Sstevel@tonic-gate if (feof(pfile)) 14447c478bd9Sstevel@tonic-gate break; 14457c478bd9Sstevel@tonic-gate samples[i] += sample; 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate if (i != nsamples) { 144892ed1782Smike_s (void) fprintf(stderr, 144992ed1782Smike_s "%s: unexpected EOF after reading %d/%d samples\n", 14507c478bd9Sstevel@tonic-gate whoami, --i, nsamples); 14517c478bd9Sstevel@tonic-gate exit(EX_IOERR); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate static void * 14567c478bd9Sstevel@tonic-gate handle_versioned(FILE *pfile, char *filename, size_t *fsz) 14577c478bd9Sstevel@tonic-gate { 14587c478bd9Sstevel@tonic-gate int fd; 14597c478bd9Sstevel@tonic-gate bool invalid_version; 14607c478bd9Sstevel@tonic-gate caddr_t fmem; 14617c478bd9Sstevel@tonic-gate struct stat buf; 14627c478bd9Sstevel@tonic-gate ProfHeader prof_hdr; 146392ed1782Smike_s off_t lret; 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* 14667c478bd9Sstevel@tonic-gate * Check versioning info. For now, let's say we provide 14677c478bd9Sstevel@tonic-gate * backward compatibility, so we accept all older versions. 14687c478bd9Sstevel@tonic-gate */ 14697c478bd9Sstevel@tonic-gate if (fread(&prof_hdr, sizeof (ProfHeader), 1, pfile) == 0) { 14707c478bd9Sstevel@tonic-gate perror("fread()"); 14717c478bd9Sstevel@tonic-gate exit(EX_IOERR); 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate invalid_version = FALSE; 14757c478bd9Sstevel@tonic-gate if (prof_hdr.h_major_ver > PROF_MAJOR_VERSION) 14767c478bd9Sstevel@tonic-gate invalid_version = TRUE; 14777c478bd9Sstevel@tonic-gate else if (prof_hdr.h_major_ver == PROF_MAJOR_VERSION) { 14787c478bd9Sstevel@tonic-gate if (prof_hdr.h_minor_ver > PROF_MINOR_VERSION) 14797c478bd9Sstevel@tonic-gate invalid_version = FALSE; 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate if (invalid_version) { 148392ed1782Smike_s (void) fprintf(stderr, "%s: version %d.%d not supported\n", 14847c478bd9Sstevel@tonic-gate whoami, prof_hdr.h_major_ver, prof_hdr.h_minor_ver); 14857c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate /* 14897c478bd9Sstevel@tonic-gate * Map gmon.out onto memory. 14907c478bd9Sstevel@tonic-gate */ 149192ed1782Smike_s (void) fclose(pfile); 14927c478bd9Sstevel@tonic-gate if ((fd = open(filename, O_RDONLY)) == -1) { 14937c478bd9Sstevel@tonic-gate perror(filename); 14947c478bd9Sstevel@tonic-gate exit(EX_IOERR); 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate 149792ed1782Smike_s if ((lret = lseek(fd, 0, SEEK_END)) == -1) { 14987c478bd9Sstevel@tonic-gate perror(filename); 14997c478bd9Sstevel@tonic-gate exit(EX_IOERR); 15007c478bd9Sstevel@tonic-gate } 150192ed1782Smike_s *fsz = lret; 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate fmem = mmap(0, *fsz, PROT_READ, MAP_PRIVATE, fd, 0); 15047c478bd9Sstevel@tonic-gate if (fmem == MAP_FAILED) { 150592ed1782Smike_s (void) fprintf(stderr, "%s: can't map %s\n", whoami, filename); 15067c478bd9Sstevel@tonic-gate exit(EX_IOERR); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate /* 15107c478bd9Sstevel@tonic-gate * Before we close this fd, save this gmon.out's info to later verify 15117c478bd9Sstevel@tonic-gate * if the shared objects it references have changed since the time 15127c478bd9Sstevel@tonic-gate * they were used to generate this gmon.out 15137c478bd9Sstevel@tonic-gate */ 15147c478bd9Sstevel@tonic-gate if (fstat(fd, &buf) == -1) { 151592ed1782Smike_s (void) fprintf(stderr, "%s: can't get info on `%s'\n", 15167c478bd9Sstevel@tonic-gate whoami, filename); 15177c478bd9Sstevel@tonic-gate exit(EX_NOINPUT); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate gmonout_info.dev = buf.st_dev; 15207c478bd9Sstevel@tonic-gate gmonout_info.ino = buf.st_ino; 15217c478bd9Sstevel@tonic-gate gmonout_info.mtime = buf.st_mtime; 15227c478bd9Sstevel@tonic-gate gmonout_info.size = buf.st_size; 15237c478bd9Sstevel@tonic-gate 152492ed1782Smike_s (void) close(fd); 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate return ((void *) fmem); 15277c478bd9Sstevel@tonic-gate } 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate static void * 153092ed1782Smike_s openpfile(char *filename, size_t *fsz) 15317c478bd9Sstevel@tonic-gate { 15327c478bd9Sstevel@tonic-gate struct hdr tmp; 15337c478bd9Sstevel@tonic-gate FILE *pfile; 15347c478bd9Sstevel@tonic-gate unsigned long magic_num; 1535e0ddff35Sab196087 size_t hdrsize; 15367c478bd9Sstevel@tonic-gate static bool first_time = TRUE; 15377c478bd9Sstevel@tonic-gate extern bool old_style; 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate if ((pfile = fopen(filename, "r")) == NULL) { 15407c478bd9Sstevel@tonic-gate perror(filename); 15417c478bd9Sstevel@tonic-gate exit(EX_IOERR); 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate /* 15457c478bd9Sstevel@tonic-gate * Read in the magic. Note that we changed the cast "unsigned long" 15467c478bd9Sstevel@tonic-gate * to "unsigned int" because that's how h_magic is defined in the 15477c478bd9Sstevel@tonic-gate * new format ProfHeader. 15487c478bd9Sstevel@tonic-gate */ 15497c478bd9Sstevel@tonic-gate if (fread(&magic_num, sizeof (unsigned int), 1, pfile) == 0) { 15507c478bd9Sstevel@tonic-gate perror("fread()"); 15517c478bd9Sstevel@tonic-gate exit(EX_IOERR); 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate rewind(pfile); 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * First check if this is versioned or *old-style* gmon.out 15587c478bd9Sstevel@tonic-gate */ 15597c478bd9Sstevel@tonic-gate if (magic_num == (unsigned int)PROF_MAGIC) { 15607c478bd9Sstevel@tonic-gate if ((!first_time) && (old_style == TRUE)) { 156192ed1782Smike_s (void) fprintf(stderr, "%s: can't mix old & new format " 15627c478bd9Sstevel@tonic-gate "profiled files\n", whoami); 15637c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate first_time = FALSE; 15667c478bd9Sstevel@tonic-gate old_style = FALSE; 15677c478bd9Sstevel@tonic-gate return (handle_versioned(pfile, filename, fsz)); 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate if ((!first_time) && (old_style == FALSE)) { 157192ed1782Smike_s (void) fprintf(stderr, "%s: can't mix old & new format " 15727c478bd9Sstevel@tonic-gate "profiled files\n", whoami); 15737c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate first_time = FALSE; 15777c478bd9Sstevel@tonic-gate old_style = TRUE; 15787c478bd9Sstevel@tonic-gate fsz = 0; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * Now, we need to determine if this is a run-time linker 15827c478bd9Sstevel@tonic-gate * profiled file or if it is a standard gmon.out. 15837c478bd9Sstevel@tonic-gate * 15847c478bd9Sstevel@tonic-gate * We do this by checking if magic matches PRF_MAGIC. If it 15857c478bd9Sstevel@tonic-gate * does, then this is a run-time linker profiled file, if it 15867c478bd9Sstevel@tonic-gate * doesn't, it must be a gmon.out file. 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate if (magic_num == (unsigned long)PRF_MAGIC) 15897c478bd9Sstevel@tonic-gate rflag = TRUE; 15907c478bd9Sstevel@tonic-gate else 15917c478bd9Sstevel@tonic-gate rflag = FALSE; 15927c478bd9Sstevel@tonic-gate 1593e0ddff35Sab196087 hdrsize = Bflag ? sizeof (struct hdr) : sizeof (struct hdr32); 1594e0ddff35Sab196087 15957c478bd9Sstevel@tonic-gate if (rflag) { 15967c478bd9Sstevel@tonic-gate if (Bflag) { 15977c478bd9Sstevel@tonic-gate L_hdr64 l_hdr64; 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate /* 16007c478bd9Sstevel@tonic-gate * If the rflag is set then the input file is 16017c478bd9Sstevel@tonic-gate * rtld profiled data, we'll read it in and convert 16027c478bd9Sstevel@tonic-gate * it to the standard format (ie: make it look like 16037c478bd9Sstevel@tonic-gate * a gmon.out file). 16047c478bd9Sstevel@tonic-gate */ 16057c478bd9Sstevel@tonic-gate if (fread(&l_hdr64, sizeof (L_hdr64), 1, pfile) == 0) { 16067c478bd9Sstevel@tonic-gate perror("fread()"); 16077c478bd9Sstevel@tonic-gate exit(EX_IOERR); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate if (l_hdr64.hd_version != PRF_VERSION_64) { 161092ed1782Smike_s (void) fprintf(stderr, 161192ed1782Smike_s "%s: expected version %d, " 16127c478bd9Sstevel@tonic-gate "got version %d when processing 64-bit " 16137c478bd9Sstevel@tonic-gate "run-time linker profiled file.\n", 16147c478bd9Sstevel@tonic-gate whoami, PRF_VERSION_64, l_hdr64.hd_version); 16157c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate tmp.lowpc = 0; 16187c478bd9Sstevel@tonic-gate tmp.highpc = (pctype)l_hdr64.hd_hpc; 1619e0ddff35Sab196087 tmp.ncnt = hdrsize + l_hdr64.hd_psize; 16207c478bd9Sstevel@tonic-gate } else { 16217c478bd9Sstevel@tonic-gate L_hdr l_hdr; 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate /* 16247c478bd9Sstevel@tonic-gate * If the rflag is set then the input file is 16257c478bd9Sstevel@tonic-gate * rtld profiled data, we'll read it in and convert 16267c478bd9Sstevel@tonic-gate * it to the standard format (ie: make it look like 16277c478bd9Sstevel@tonic-gate * a gmon.out file). 16287c478bd9Sstevel@tonic-gate */ 16297c478bd9Sstevel@tonic-gate if (fread(&l_hdr, sizeof (L_hdr), 1, pfile) == 0) { 16307c478bd9Sstevel@tonic-gate perror("fread()"); 16317c478bd9Sstevel@tonic-gate exit(EX_IOERR); 16327c478bd9Sstevel@tonic-gate } 16337c478bd9Sstevel@tonic-gate if (l_hdr.hd_version != PRF_VERSION) { 163492ed1782Smike_s (void) fprintf(stderr, 163592ed1782Smike_s "%s: expected version %d, " 16367c478bd9Sstevel@tonic-gate "got version %d when processing " 16377c478bd9Sstevel@tonic-gate "run-time linker profiled file.\n", 16387c478bd9Sstevel@tonic-gate whoami, PRF_VERSION, l_hdr.hd_version); 16397c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate tmp.lowpc = 0; 16427c478bd9Sstevel@tonic-gate tmp.highpc = (pctype)(uintptr_t)l_hdr.hd_hpc; 1643e0ddff35Sab196087 tmp.ncnt = hdrsize + l_hdr.hd_psize; 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate } else { 16467c478bd9Sstevel@tonic-gate if (Bflag) { 16477c478bd9Sstevel@tonic-gate if (fread(&tmp, sizeof (struct hdr), 1, pfile) == 0) { 16487c478bd9Sstevel@tonic-gate perror("fread()"); 16497c478bd9Sstevel@tonic-gate exit(EX_IOERR); 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate } else { 16527c478bd9Sstevel@tonic-gate /* 16537c478bd9Sstevel@tonic-gate * If we're not reading big %pc's, we need to read 16547c478bd9Sstevel@tonic-gate * the 32-bit header, and assign the members to 16557c478bd9Sstevel@tonic-gate * the actual header. 16567c478bd9Sstevel@tonic-gate */ 16577c478bd9Sstevel@tonic-gate struct hdr32 hdr32; 16587c478bd9Sstevel@tonic-gate if (fread(&hdr32, sizeof (hdr32), 1, pfile) == 0) { 16597c478bd9Sstevel@tonic-gate perror("fread()"); 16607c478bd9Sstevel@tonic-gate exit(EX_IOERR); 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate tmp.lowpc = hdr32.lowpc; 16637c478bd9Sstevel@tonic-gate tmp.highpc = hdr32.highpc; 16647c478bd9Sstevel@tonic-gate tmp.ncnt = hdr32.ncnt; 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate * perform sanity check on profiled file we've opened. 16707c478bd9Sstevel@tonic-gate */ 16717c478bd9Sstevel@tonic-gate if (tmp.lowpc >= tmp.highpc) { 16727c478bd9Sstevel@tonic-gate if (rflag) 167392ed1782Smike_s (void) fprintf(stderr, 167492ed1782Smike_s "%s: badly formed profiled data.\n", 16757c478bd9Sstevel@tonic-gate filename); 16767c478bd9Sstevel@tonic-gate else 167792ed1782Smike_s (void) fprintf(stderr, 167892ed1782Smike_s "%s: badly formed gmon.out file.\n", 16797c478bd9Sstevel@tonic-gate filename); 16807c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 16817c478bd9Sstevel@tonic-gate } 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate if (s_highpc != 0 && (tmp.lowpc != h.lowpc || 16847c478bd9Sstevel@tonic-gate tmp.highpc != h.highpc || tmp.ncnt != h.ncnt)) { 168592ed1782Smike_s (void) fprintf(stderr, 16867c478bd9Sstevel@tonic-gate "%s: incompatible with first gmon file\n", 16877c478bd9Sstevel@tonic-gate filename); 16887c478bd9Sstevel@tonic-gate exit(EX_IOERR); 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate h = tmp; 16917c478bd9Sstevel@tonic-gate s_lowpc = h.lowpc; 16927c478bd9Sstevel@tonic-gate s_highpc = h.highpc; 16937c478bd9Sstevel@tonic-gate lowpc = h.lowpc / sizeof (UNIT); 16947c478bd9Sstevel@tonic-gate highpc = h.highpc / sizeof (UNIT); 16957c478bd9Sstevel@tonic-gate sampbytes = h.ncnt > hdrsize ? h.ncnt - hdrsize : 0; 16967c478bd9Sstevel@tonic-gate nsamples = sampbytes / sizeof (unsigned_UNIT); 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate #ifdef DEBUG 16997c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 170092ed1782Smike_s (void) printf("[openpfile] hdr.lowpc 0x%llx hdr.highpc " 17017c478bd9Sstevel@tonic-gate "0x%llx hdr.ncnt %lld\n", 17027c478bd9Sstevel@tonic-gate h.lowpc, h.highpc, h.ncnt); 170392ed1782Smike_s (void) printf( 170492ed1782Smike_s "[openpfile] s_lowpc 0x%llx s_highpc 0x%llx\n", 17057c478bd9Sstevel@tonic-gate s_lowpc, s_highpc); 170692ed1782Smike_s (void) printf( 170792ed1782Smike_s "[openpfile] lowpc 0x%llx highpc 0x%llx\n", 17087c478bd9Sstevel@tonic-gate lowpc, highpc); 170992ed1782Smike_s (void) printf("[openpfile] sampbytes %d nsamples %d\n", 17107c478bd9Sstevel@tonic-gate sampbytes, nsamples); 17117c478bd9Sstevel@tonic-gate } 171292ed1782Smike_s #endif /* DEBUG */ 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate return ((void *) pfile); 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate /* 17187c478bd9Sstevel@tonic-gate * Information from a gmon.out file depends on whether it's versioned 17197c478bd9Sstevel@tonic-gate * or non-versioned, *old style* gmon.out. If old-style, it is in two 17207c478bd9Sstevel@tonic-gate * parts : an array of sampling hits within pc ranges, and the arcs. If 17217c478bd9Sstevel@tonic-gate * versioned, it contains a header, followed by any number of 17227c478bd9Sstevel@tonic-gate * modules/callgraph/pcsample_buffer objects. 17237c478bd9Sstevel@tonic-gate */ 17247c478bd9Sstevel@tonic-gate static void 17257c478bd9Sstevel@tonic-gate getpfile(char *filename) 17267c478bd9Sstevel@tonic-gate { 17277c478bd9Sstevel@tonic-gate void *handle; 17287c478bd9Sstevel@tonic-gate size_t fsz; 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate handle = openpfile(filename, &fsz); 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate if (old_style) { 17337c478bd9Sstevel@tonic-gate readsamples((FILE *)handle); 17347c478bd9Sstevel@tonic-gate readarcs((FILE *)handle); 173592ed1782Smike_s (void) fclose((FILE *)handle); 17367c478bd9Sstevel@tonic-gate return; 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate getpfiledata((caddr_t)handle, fsz); 174092ed1782Smike_s (void) munmap(handle, fsz); 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate 174392ed1782Smike_s int 17447c478bd9Sstevel@tonic-gate main(int argc, char **argv) 17457c478bd9Sstevel@tonic-gate { 17467c478bd9Sstevel@tonic-gate char **sp; 17477c478bd9Sstevel@tonic-gate nltype **timesortnlp; 17487c478bd9Sstevel@tonic-gate int c; 17497c478bd9Sstevel@tonic-gate int errflg; 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate prog_name = *argv; /* preserve program name */ 17527c478bd9Sstevel@tonic-gate debug = 0; 17537c478bd9Sstevel@tonic-gate nflag = FALSE; 17547c478bd9Sstevel@tonic-gate bflag = TRUE; 17557c478bd9Sstevel@tonic-gate lflag = FALSE; 17567c478bd9Sstevel@tonic-gate Cflag = FALSE; 17577c478bd9Sstevel@tonic-gate first_file = TRUE; 17587c478bd9Sstevel@tonic-gate rflag = FALSE; 17597c478bd9Sstevel@tonic-gate Bflag = FALSE; 17607c478bd9Sstevel@tonic-gate errflg = FALSE; 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "abd:CcDE:e:F:f:ln:sz")) != EOF) 17637c478bd9Sstevel@tonic-gate switch (c) { 17647c478bd9Sstevel@tonic-gate case 'a': 17657c478bd9Sstevel@tonic-gate aflag = TRUE; 17667c478bd9Sstevel@tonic-gate break; 17677c478bd9Sstevel@tonic-gate case 'b': 17687c478bd9Sstevel@tonic-gate bflag = FALSE; 17697c478bd9Sstevel@tonic-gate break; 17707c478bd9Sstevel@tonic-gate case 'c': 17717c478bd9Sstevel@tonic-gate cflag = TRUE; 17727c478bd9Sstevel@tonic-gate break; 17737c478bd9Sstevel@tonic-gate case 'C': 17747c478bd9Sstevel@tonic-gate Cflag = TRUE; 17757c478bd9Sstevel@tonic-gate break; 17767c478bd9Sstevel@tonic-gate case 'd': 17777c478bd9Sstevel@tonic-gate dflag = TRUE; 17787c478bd9Sstevel@tonic-gate debug |= atoi(optarg); 177992ed1782Smike_s (void) printf("[main] debug = 0x%x\n", debug); 17807c478bd9Sstevel@tonic-gate break; 17817c478bd9Sstevel@tonic-gate case 'D': 17827c478bd9Sstevel@tonic-gate Dflag = TRUE; 17837c478bd9Sstevel@tonic-gate break; 17847c478bd9Sstevel@tonic-gate case 'E': 17857c478bd9Sstevel@tonic-gate addlist(Elist, optarg); 17867c478bd9Sstevel@tonic-gate Eflag = TRUE; 17877c478bd9Sstevel@tonic-gate addlist(elist, optarg); 17887c478bd9Sstevel@tonic-gate eflag = TRUE; 17897c478bd9Sstevel@tonic-gate break; 17907c478bd9Sstevel@tonic-gate case 'e': 17917c478bd9Sstevel@tonic-gate addlist(elist, optarg); 17927c478bd9Sstevel@tonic-gate eflag = TRUE; 17937c478bd9Sstevel@tonic-gate break; 17947c478bd9Sstevel@tonic-gate case 'F': 17957c478bd9Sstevel@tonic-gate addlist(Flist, optarg); 17967c478bd9Sstevel@tonic-gate Fflag = TRUE; 17977c478bd9Sstevel@tonic-gate addlist(flist, optarg); 17987c478bd9Sstevel@tonic-gate fflag = TRUE; 17997c478bd9Sstevel@tonic-gate break; 18007c478bd9Sstevel@tonic-gate case 'f': 18017c478bd9Sstevel@tonic-gate addlist(flist, optarg); 18027c478bd9Sstevel@tonic-gate fflag = TRUE; 18037c478bd9Sstevel@tonic-gate break; 18047c478bd9Sstevel@tonic-gate case 'l': 18057c478bd9Sstevel@tonic-gate lflag = TRUE; 18067c478bd9Sstevel@tonic-gate break; 18077c478bd9Sstevel@tonic-gate case 'n': 18087c478bd9Sstevel@tonic-gate nflag = TRUE; 18097c478bd9Sstevel@tonic-gate number_funcs_toprint = atoi(optarg); 18107c478bd9Sstevel@tonic-gate break; 18117c478bd9Sstevel@tonic-gate case 's': 18127c478bd9Sstevel@tonic-gate sflag = TRUE; 18137c478bd9Sstevel@tonic-gate break; 18147c478bd9Sstevel@tonic-gate case 'z': 18157c478bd9Sstevel@tonic-gate zflag = TRUE; 18167c478bd9Sstevel@tonic-gate break; 18177c478bd9Sstevel@tonic-gate case '?': 18187c478bd9Sstevel@tonic-gate errflg++; 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate } 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate if (errflg) { 18237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 18247c478bd9Sstevel@tonic-gate "usage: gprof [ -abcCDlsz ] [ -e function-name ] " 18257c478bd9Sstevel@tonic-gate "[ -E function-name ]\n\t[ -f function-name ] " 18267c478bd9Sstevel@tonic-gate "[ -F function-name ]\n\t[ image-file " 18277c478bd9Sstevel@tonic-gate "[ profile-file ... ] ]\n"); 18287c478bd9Sstevel@tonic-gate exit(EX_USAGE); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate if (optind < argc) { 18327c478bd9Sstevel@tonic-gate a_outname = argv[optind++]; 18337c478bd9Sstevel@tonic-gate } else { 18347c478bd9Sstevel@tonic-gate a_outname = A_OUTNAME; 18357c478bd9Sstevel@tonic-gate } 18367c478bd9Sstevel@tonic-gate if (optind < argc) { 18377c478bd9Sstevel@tonic-gate gmonname = argv[optind++]; 18387c478bd9Sstevel@tonic-gate } else { 18397c478bd9Sstevel@tonic-gate gmonname = GMONNAME; 18407c478bd9Sstevel@tonic-gate } 18417c478bd9Sstevel@tonic-gate /* 18427c478bd9Sstevel@tonic-gate * turn off default functions 18437c478bd9Sstevel@tonic-gate */ 18447c478bd9Sstevel@tonic-gate for (sp = &defaultEs[0]; *sp; sp++) { 18457c478bd9Sstevel@tonic-gate Eflag = TRUE; 18467c478bd9Sstevel@tonic-gate addlist(Elist, *sp); 18477c478bd9Sstevel@tonic-gate eflag = TRUE; 18487c478bd9Sstevel@tonic-gate addlist(elist, *sp); 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate /* 18517c478bd9Sstevel@tonic-gate * how many ticks per second? 18527c478bd9Sstevel@tonic-gate * if we can't tell, report time in ticks. 18537c478bd9Sstevel@tonic-gate */ 18547c478bd9Sstevel@tonic-gate hz = sysconf(_SC_CLK_TCK); 18557c478bd9Sstevel@tonic-gate if (hz == -1) { 18567c478bd9Sstevel@tonic-gate hz = 1; 185792ed1782Smike_s (void) fprintf(stderr, "time is in ticks, not seconds\n"); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate getnfile(a_outname); 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate /* 18637c478bd9Sstevel@tonic-gate * get information about mon.out file(s). 18647c478bd9Sstevel@tonic-gate */ 18657c478bd9Sstevel@tonic-gate do { 18667c478bd9Sstevel@tonic-gate getpfile(gmonname); 18677c478bd9Sstevel@tonic-gate if (optind < argc) 18687c478bd9Sstevel@tonic-gate gmonname = argv[optind++]; 18697c478bd9Sstevel@tonic-gate else 18707c478bd9Sstevel@tonic-gate optind++; 18717c478bd9Sstevel@tonic-gate } while (optind <= argc); 18727c478bd9Sstevel@tonic-gate /* 18737c478bd9Sstevel@tonic-gate * dump out a gmon.sum file if requested 18747c478bd9Sstevel@tonic-gate */ 18757c478bd9Sstevel@tonic-gate if (sflag || Dflag) 18767c478bd9Sstevel@tonic-gate dumpsum(GMONSUM); 18777c478bd9Sstevel@tonic-gate 18787c478bd9Sstevel@tonic-gate if (old_style) { 18797c478bd9Sstevel@tonic-gate /* 18807c478bd9Sstevel@tonic-gate * assign samples to procedures 18817c478bd9Sstevel@tonic-gate */ 18827c478bd9Sstevel@tonic-gate asgnsamples(); 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate /* 18867c478bd9Sstevel@tonic-gate * assemble the dynamic profile 18877c478bd9Sstevel@tonic-gate */ 18887c478bd9Sstevel@tonic-gate timesortnlp = doarcs(); 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate /* 18917c478bd9Sstevel@tonic-gate * print the dynamic profile 18927c478bd9Sstevel@tonic-gate */ 18937c478bd9Sstevel@tonic-gate #ifdef DEBUG 18947c478bd9Sstevel@tonic-gate if (debug & ANYDEBUG) { 18957c478bd9Sstevel@tonic-gate /* raw output of all symbols in all their glory */ 18967c478bd9Sstevel@tonic-gate int i; 189792ed1782Smike_s (void) printf(" Name, pc_entry_pt, svalue, tix_in_routine, " 18987c478bd9Sstevel@tonic-gate "#calls, selfcalls, index \n"); 18997c478bd9Sstevel@tonic-gate for (i = 0; i < modules.nname; i++) { /* Print each symbol */ 19007c478bd9Sstevel@tonic-gate if (timesortnlp[i]->name) 190192ed1782Smike_s (void) printf(" %s ", timesortnlp[i]->name); 19027c478bd9Sstevel@tonic-gate else 190392ed1782Smike_s (void) printf(" <cycle> "); 190492ed1782Smike_s (void) printf(" %lld ", timesortnlp[i]->value); 190592ed1782Smike_s (void) printf(" %lld ", timesortnlp[i]->svalue); 190692ed1782Smike_s (void) printf(" %f ", timesortnlp[i]->time); 190792ed1782Smike_s (void) printf(" %lld ", timesortnlp[i]->ncall); 190892ed1782Smike_s (void) printf(" %lld ", timesortnlp[i]->selfcalls); 190992ed1782Smike_s (void) printf(" %d ", timesortnlp[i]->index); 191092ed1782Smike_s (void) printf(" \n"); 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate } 191392ed1782Smike_s #endif /* DEBUG */ 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate printgprof(timesortnlp); 19167c478bd9Sstevel@tonic-gate /* 19177c478bd9Sstevel@tonic-gate * print the flat profile 19187c478bd9Sstevel@tonic-gate */ 19197c478bd9Sstevel@tonic-gate printprof(); 19207c478bd9Sstevel@tonic-gate /* 19217c478bd9Sstevel@tonic-gate * print the index 19227c478bd9Sstevel@tonic-gate */ 19237c478bd9Sstevel@tonic-gate printindex(); 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate /* 19267c478bd9Sstevel@tonic-gate * print the modules 19277c478bd9Sstevel@tonic-gate */ 19287c478bd9Sstevel@tonic-gate printmodules(); 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate done(); 19317c478bd9Sstevel@tonic-gate /* NOTREACHED */ 19327c478bd9Sstevel@tonic-gate return (0); 19337c478bd9Sstevel@tonic-gate } 1934