1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sysexits.h> 30*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 31*7c478bd9Sstevel@tonic-gate #include <unistd.h> 32*7c478bd9Sstevel@tonic-gate #include "gprof.h" 33*7c478bd9Sstevel@tonic-gate #include "profile.h" 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate char *whoami = "gprof"; 36*7c478bd9Sstevel@tonic-gate static pctype lowpc, highpc; /* range profiled, in UNIT's */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate /* 39*7c478bd9Sstevel@tonic-gate * things which get -E excluded by default. 40*7c478bd9Sstevel@tonic-gate */ 41*7c478bd9Sstevel@tonic-gate static char *defaultEs[] = { 42*7c478bd9Sstevel@tonic-gate "mcount", 43*7c478bd9Sstevel@tonic-gate "__mcleanup", 44*7c478bd9Sstevel@tonic-gate 0 45*7c478bd9Sstevel@tonic-gate }; 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate static char *objname[] = { 50*7c478bd9Sstevel@tonic-gate "<invalid object>", 51*7c478bd9Sstevel@tonic-gate "PROF_BUFFER_T", 52*7c478bd9Sstevel@tonic-gate "PROF_CALLGRAPH_T", 53*7c478bd9Sstevel@tonic-gate "PROF_MODULES_T", 54*7c478bd9Sstevel@tonic-gate 0 55*7c478bd9Sstevel@tonic-gate }; 56*7c478bd9Sstevel@tonic-gate #define MAX_OBJTYPES 3 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #endif DEBUG 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate void 61*7c478bd9Sstevel@tonic-gate done() 62*7c478bd9Sstevel@tonic-gate { 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate exit(EX_OK); 65*7c478bd9Sstevel@tonic-gate } 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate static pctype 68*7c478bd9Sstevel@tonic-gate max(pctype a, pctype b) 69*7c478bd9Sstevel@tonic-gate { 70*7c478bd9Sstevel@tonic-gate if (a > b) 71*7c478bd9Sstevel@tonic-gate return (a); 72*7c478bd9Sstevel@tonic-gate return (b); 73*7c478bd9Sstevel@tonic-gate } 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate static pctype 76*7c478bd9Sstevel@tonic-gate min(pctype a, pctype b) 77*7c478bd9Sstevel@tonic-gate { 78*7c478bd9Sstevel@tonic-gate if (a < b) 79*7c478bd9Sstevel@tonic-gate return (a); 80*7c478bd9Sstevel@tonic-gate return (b); 81*7c478bd9Sstevel@tonic-gate } 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* 84*7c478bd9Sstevel@tonic-gate * calculate scaled entry point addresses (to save time in asgnsamples), 85*7c478bd9Sstevel@tonic-gate * and possibly push the scaled entry points over the entry mask, 86*7c478bd9Sstevel@tonic-gate * if it turns out that the entry point is in one bucket and the code 87*7c478bd9Sstevel@tonic-gate * for a routine is in the next bucket. 88*7c478bd9Sstevel@tonic-gate * 89*7c478bd9Sstevel@tonic-gate */ 90*7c478bd9Sstevel@tonic-gate static void 91*7c478bd9Sstevel@tonic-gate alignentries() 92*7c478bd9Sstevel@tonic-gate { 93*7c478bd9Sstevel@tonic-gate register struct nl * nlp; 94*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 95*7c478bd9Sstevel@tonic-gate pctype bucket_of_entry; 96*7c478bd9Sstevel@tonic-gate pctype bucket_of_code; 97*7c478bd9Sstevel@tonic-gate #endif DEBUG 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* for old-style gmon.out, nameslist is only in modules.nl */ 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate for (nlp = modules.nl; nlp < modules.npe; nlp++) { 102*7c478bd9Sstevel@tonic-gate nlp->svalue = nlp->value / sizeof (UNIT); 103*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 104*7c478bd9Sstevel@tonic-gate bucket_of_entry = (nlp->svalue - lowpc) / scale; 105*7c478bd9Sstevel@tonic-gate bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; 106*7c478bd9Sstevel@tonic-gate if (bucket_of_entry < bucket_of_code) { 107*7c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 108*7c478bd9Sstevel@tonic-gate printf("[alignentries] pushing svalue 0x%llx " 109*7c478bd9Sstevel@tonic-gate "to 0x%llx\n", nlp->svalue, 110*7c478bd9Sstevel@tonic-gate nlp->svalue + UNITS_TO_CODE); 111*7c478bd9Sstevel@tonic-gate } 112*7c478bd9Sstevel@tonic-gate } 113*7c478bd9Sstevel@tonic-gate #endif DEBUG 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * old-style gmon.out 119*7c478bd9Sstevel@tonic-gate * ------------------ 120*7c478bd9Sstevel@tonic-gate * 121*7c478bd9Sstevel@tonic-gate * Assign samples to the procedures to which they belong. 122*7c478bd9Sstevel@tonic-gate * 123*7c478bd9Sstevel@tonic-gate * There are three cases as to where pcl and pch can be 124*7c478bd9Sstevel@tonic-gate * with respect to the routine entry addresses svalue0 and svalue1 125*7c478bd9Sstevel@tonic-gate * as shown in the following diagram. overlap computes the 126*7c478bd9Sstevel@tonic-gate * distance between the arrows, the fraction of the sample 127*7c478bd9Sstevel@tonic-gate * that is to be credited to the routine which starts at svalue0. 128*7c478bd9Sstevel@tonic-gate * 129*7c478bd9Sstevel@tonic-gate * svalue0 svalue1 130*7c478bd9Sstevel@tonic-gate * | | 131*7c478bd9Sstevel@tonic-gate * v v 132*7c478bd9Sstevel@tonic-gate * 133*7c478bd9Sstevel@tonic-gate * +-----------------------------------------------+ 134*7c478bd9Sstevel@tonic-gate * | | 135*7c478bd9Sstevel@tonic-gate * | ->| |<- ->| |<- ->| |<- | 136*7c478bd9Sstevel@tonic-gate * | | | | | | 137*7c478bd9Sstevel@tonic-gate * +---------+ +---------+ +---------+ 138*7c478bd9Sstevel@tonic-gate * 139*7c478bd9Sstevel@tonic-gate * ^ ^ ^ ^ ^ ^ 140*7c478bd9Sstevel@tonic-gate * | | | | | | 141*7c478bd9Sstevel@tonic-gate * pcl pch pcl pch pcl pch 142*7c478bd9Sstevel@tonic-gate * 143*7c478bd9Sstevel@tonic-gate * For the vax we assert that samples will never fall in the first 144*7c478bd9Sstevel@tonic-gate * two bytes of any routine, since that is the entry mask, 145*7c478bd9Sstevel@tonic-gate * thus we give call alignentries() to adjust the entry points if 146*7c478bd9Sstevel@tonic-gate * the entry mask falls in one bucket but the code for the routine 147*7c478bd9Sstevel@tonic-gate * doesn't start until the next bucket. In conjunction with the 148*7c478bd9Sstevel@tonic-gate * alignment of routine addresses, this should allow us to have 149*7c478bd9Sstevel@tonic-gate * only one sample for every four bytes of text space and never 150*7c478bd9Sstevel@tonic-gate * have any overlap (the two end cases, above). 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate static void 153*7c478bd9Sstevel@tonic-gate asgnsamples() 154*7c478bd9Sstevel@tonic-gate { 155*7c478bd9Sstevel@tonic-gate sztype i, j; 156*7c478bd9Sstevel@tonic-gate unsigned_UNIT ccnt; 157*7c478bd9Sstevel@tonic-gate double time; 158*7c478bd9Sstevel@tonic-gate pctype pcl, pch; 159*7c478bd9Sstevel@tonic-gate pctype overlap; 160*7c478bd9Sstevel@tonic-gate pctype svalue0, svalue1; 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate extern mod_info_t modules; 163*7c478bd9Sstevel@tonic-gate nltype *nl = modules.nl; 164*7c478bd9Sstevel@tonic-gate sztype nname = modules.nname; 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate /* read samples and assign to namelist symbols */ 167*7c478bd9Sstevel@tonic-gate scale = highpc - lowpc; 168*7c478bd9Sstevel@tonic-gate scale /= nsamples; 169*7c478bd9Sstevel@tonic-gate alignentries(); 170*7c478bd9Sstevel@tonic-gate for (i = 0, j = 1; i < nsamples; i++) { 171*7c478bd9Sstevel@tonic-gate ccnt = samples[i]; 172*7c478bd9Sstevel@tonic-gate if (ccnt == 0) 173*7c478bd9Sstevel@tonic-gate continue; 174*7c478bd9Sstevel@tonic-gate pcl = lowpc + scale * i; 175*7c478bd9Sstevel@tonic-gate pch = lowpc + scale * (i + 1); 176*7c478bd9Sstevel@tonic-gate time = ccnt; 177*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 178*7c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 179*7c478bd9Sstevel@tonic-gate printf("[asgnsamples] pcl 0x%llx pch 0x%llx ccnt %d\n", 180*7c478bd9Sstevel@tonic-gate pcl, pch, ccnt); 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate #endif DEBUG 183*7c478bd9Sstevel@tonic-gate totime += time; 184*7c478bd9Sstevel@tonic-gate for (j = (j ? j - 1 : 0); j < nname; j++) { 185*7c478bd9Sstevel@tonic-gate svalue0 = nl[j].svalue; 186*7c478bd9Sstevel@tonic-gate svalue1 = nl[j+1].svalue; 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate * if high end of tick is below entry address, 189*7c478bd9Sstevel@tonic-gate * go for next tick. 190*7c478bd9Sstevel@tonic-gate */ 191*7c478bd9Sstevel@tonic-gate if (pch < svalue0) 192*7c478bd9Sstevel@tonic-gate break; 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * if low end of tick into next routine, 195*7c478bd9Sstevel@tonic-gate * go for next routine. 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate if (pcl >= svalue1) 198*7c478bd9Sstevel@tonic-gate continue; 199*7c478bd9Sstevel@tonic-gate overlap = min(pch, svalue1) - max(pcl, svalue0); 200*7c478bd9Sstevel@tonic-gate if (overlap != 0) { 201*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 202*7c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 203*7c478bd9Sstevel@tonic-gate printf("[asgnsamples] " 204*7c478bd9Sstevel@tonic-gate "(0x%llx->0x%llx-0x%llx) %s gets " 205*7c478bd9Sstevel@tonic-gate "%f ticks %lld overlap\n", 206*7c478bd9Sstevel@tonic-gate nl[j].value/sizeof (UNIT), svalue0, 207*7c478bd9Sstevel@tonic-gate svalue1, nl[j].name, 208*7c478bd9Sstevel@tonic-gate overlap * time / scale, overlap); 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate #endif DEBUG 211*7c478bd9Sstevel@tonic-gate nl[j].time += overlap * time / scale; 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 216*7c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 217*7c478bd9Sstevel@tonic-gate printf("[asgnsamples] totime %f\n", totime); 218*7c478bd9Sstevel@tonic-gate } 219*7c478bd9Sstevel@tonic-gate #endif DEBUG 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate static void 224*7c478bd9Sstevel@tonic-gate dump_callgraph(FILE *fp, char *filename, 225*7c478bd9Sstevel@tonic-gate unsigned long tarcs, unsigned long ncallees) 226*7c478bd9Sstevel@tonic-gate { 227*7c478bd9Sstevel@tonic-gate ProfCallGraph prof_cgraph; 228*7c478bd9Sstevel@tonic-gate ProfFunction prof_func; 229*7c478bd9Sstevel@tonic-gate register arctype *arcp; 230*7c478bd9Sstevel@tonic-gate mod_info_t *mi; 231*7c478bd9Sstevel@tonic-gate nltype *nlp; 232*7c478bd9Sstevel@tonic-gate size_t cur_offset; 233*7c478bd9Sstevel@tonic-gate unsigned long caller_id = 0, callee_id = 0; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate /* 236*7c478bd9Sstevel@tonic-gate * Write the callgraph header 237*7c478bd9Sstevel@tonic-gate */ 238*7c478bd9Sstevel@tonic-gate prof_cgraph.type = PROF_CALLGRAPH_T; 239*7c478bd9Sstevel@tonic-gate prof_cgraph.version = PROF_CALLGRAPH_VER; 240*7c478bd9Sstevel@tonic-gate prof_cgraph.functions = PROFCGRAPH_SZ; 241*7c478bd9Sstevel@tonic-gate prof_cgraph.size = PROFCGRAPH_SZ + tarcs * PROFFUNC_SZ; 242*7c478bd9Sstevel@tonic-gate if (fwrite(&prof_cgraph, sizeof (ProfCallGraph), 1, fp) != 1) { 243*7c478bd9Sstevel@tonic-gate perror(filename); 244*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate if (CGRAPH_FILLER) 247*7c478bd9Sstevel@tonic-gate fseek(fp, CGRAPH_FILLER, SEEK_CUR); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* Current offset inside the callgraph object */ 250*7c478bd9Sstevel@tonic-gate cur_offset = prof_cgraph.functions; 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 253*7c478bd9Sstevel@tonic-gate for (nlp = mi->nl; nlp < mi->npe; nlp++) { 254*7c478bd9Sstevel@tonic-gate if (nlp->ncallers == 0) 255*7c478bd9Sstevel@tonic-gate continue; 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate /* If this is the last callee, set next_to to 0 */ 258*7c478bd9Sstevel@tonic-gate callee_id++; 259*7c478bd9Sstevel@tonic-gate if (callee_id == ncallees) 260*7c478bd9Sstevel@tonic-gate prof_func.next_to = 0; 261*7c478bd9Sstevel@tonic-gate else { 262*7c478bd9Sstevel@tonic-gate prof_func.next_to = cur_offset + 263*7c478bd9Sstevel@tonic-gate nlp->ncallers * PROFFUNC_SZ; 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate /* 267*7c478bd9Sstevel@tonic-gate * Dump this callee's raw arc information with all 268*7c478bd9Sstevel@tonic-gate * its callers 269*7c478bd9Sstevel@tonic-gate */ 270*7c478bd9Sstevel@tonic-gate caller_id = 1; 271*7c478bd9Sstevel@tonic-gate for (arcp = nlp->parents; arcp; 272*7c478bd9Sstevel@tonic-gate arcp = arcp->arc_parentlist) { 273*7c478bd9Sstevel@tonic-gate /* 274*7c478bd9Sstevel@tonic-gate * If no more callers for this callee, set 275*7c478bd9Sstevel@tonic-gate * next_from to 0 276*7c478bd9Sstevel@tonic-gate */ 277*7c478bd9Sstevel@tonic-gate if (caller_id == nlp->ncallers) 278*7c478bd9Sstevel@tonic-gate prof_func.next_from = 0; 279*7c478bd9Sstevel@tonic-gate else { 280*7c478bd9Sstevel@tonic-gate prof_func.next_from = cur_offset + 281*7c478bd9Sstevel@tonic-gate PROFFUNC_SZ; 282*7c478bd9Sstevel@tonic-gate } 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate prof_func.frompc = 285*7c478bd9Sstevel@tonic-gate arcp->arc_parentp->module->load_base + 286*7c478bd9Sstevel@tonic-gate (arcp->arc_parentp->value - 287*7c478bd9Sstevel@tonic-gate arcp->arc_parentp->module->txt_origin); 288*7c478bd9Sstevel@tonic-gate prof_func.topc = 289*7c478bd9Sstevel@tonic-gate mi->load_base + 290*7c478bd9Sstevel@tonic-gate (nlp->value - mi->txt_origin); 291*7c478bd9Sstevel@tonic-gate prof_func.count = arcp->arc_count; 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate if (fwrite(&prof_func, sizeof (ProfFunction), 295*7c478bd9Sstevel@tonic-gate 1, fp) != 1) { 296*7c478bd9Sstevel@tonic-gate perror(filename); 297*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate if (FUNC_FILLER) 300*7c478bd9Sstevel@tonic-gate fseek(fp, FUNC_FILLER, SEEK_CUR); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate cur_offset += PROFFUNC_SZ; 303*7c478bd9Sstevel@tonic-gate caller_id++; 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate } /* for nlp... */ 306*7c478bd9Sstevel@tonic-gate } /* for mi... */ 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate /* 310*7c478bd9Sstevel@tonic-gate * To save all pc-hits in all the gmon.out's is infeasible, as this 311*7c478bd9Sstevel@tonic-gate * may become quite huge even with a small number of files to sum. 312*7c478bd9Sstevel@tonic-gate * Instead, we'll dump *fictitious hits* to correct functions 313*7c478bd9Sstevel@tonic-gate * by scanning module namelists. Again, since this is summing 314*7c478bd9Sstevel@tonic-gate * pc-hits, we may have to dump the pcsamples out in chunks if the 315*7c478bd9Sstevel@tonic-gate * number of pc-hits is high. 316*7c478bd9Sstevel@tonic-gate */ 317*7c478bd9Sstevel@tonic-gate static void 318*7c478bd9Sstevel@tonic-gate dump_hits(FILE *fp, char *filename, nltype *nlp) 319*7c478bd9Sstevel@tonic-gate { 320*7c478bd9Sstevel@tonic-gate Address *p, hitpc; 321*7c478bd9Sstevel@tonic-gate size_t i, nelem, ntowrite; 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate if ((nelem = nlp->nticks) > PROF_BUFFER_SIZE) 324*7c478bd9Sstevel@tonic-gate nelem = PROF_BUFFER_SIZE; 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate if ((p = (Address *) calloc(nelem, sizeof (Address))) == NULL) { 327*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: no room for %ld pcsamples\n", 328*7c478bd9Sstevel@tonic-gate whoami, nelem); 329*7c478bd9Sstevel@tonic-gate exit(EX_OSERR); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * Set up *fictitious* hits (to function entry) buffer 334*7c478bd9Sstevel@tonic-gate */ 335*7c478bd9Sstevel@tonic-gate hitpc = nlp->module->load_base + (nlp->value - nlp->module->txt_origin); 336*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) 337*7c478bd9Sstevel@tonic-gate p[i] = hitpc; 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate for (ntowrite = nlp->nticks; ntowrite >= nelem; ntowrite -= nelem) { 340*7c478bd9Sstevel@tonic-gate if (fwrite(p, nelem * sizeof (Address), 1, fp) != 1) { 341*7c478bd9Sstevel@tonic-gate perror(filename); 342*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate if (ntowrite) { 347*7c478bd9Sstevel@tonic-gate if (fwrite(p, ntowrite * sizeof (Address), 1, fp) != 1) { 348*7c478bd9Sstevel@tonic-gate perror(filename); 349*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate free(p); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate static void 357*7c478bd9Sstevel@tonic-gate dump_pcsamples(FILE *fp, char *filename, 358*7c478bd9Sstevel@tonic-gate unsigned long *tarcs, unsigned long *ncallees) 359*7c478bd9Sstevel@tonic-gate { 360*7c478bd9Sstevel@tonic-gate ProfBuffer prof_buffer; 361*7c478bd9Sstevel@tonic-gate register arctype *arcp; 362*7c478bd9Sstevel@tonic-gate mod_info_t *mi; 363*7c478bd9Sstevel@tonic-gate nltype *nlp; 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate prof_buffer.type = PROF_BUFFER_T; 366*7c478bd9Sstevel@tonic-gate prof_buffer.version = PROF_BUFFER_VER; 367*7c478bd9Sstevel@tonic-gate prof_buffer.buffer = PROFBUF_SZ; 368*7c478bd9Sstevel@tonic-gate prof_buffer.bufsize = n_pcsamples; 369*7c478bd9Sstevel@tonic-gate prof_buffer.size = PROFBUF_SZ + n_pcsamples * sizeof (Address); 370*7c478bd9Sstevel@tonic-gate if (fwrite(&prof_buffer, sizeof (ProfBuffer), 1, fp) != 1) { 371*7c478bd9Sstevel@tonic-gate perror(filename); 372*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate if (BUF_FILLER) 375*7c478bd9Sstevel@tonic-gate fseek(fp, BUF_FILLER, SEEK_CUR); 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate *tarcs = 0; 378*7c478bd9Sstevel@tonic-gate *ncallees = 0; 379*7c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 380*7c478bd9Sstevel@tonic-gate for (nlp = mi->nl; nlp < mi->npe; nlp++) { 381*7c478bd9Sstevel@tonic-gate if (nlp->nticks) 382*7c478bd9Sstevel@tonic-gate dump_hits(fp, filename, nlp); 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate nlp->ncallers = 0; 385*7c478bd9Sstevel@tonic-gate for (arcp = nlp->parents; arcp; 386*7c478bd9Sstevel@tonic-gate arcp = arcp->arc_parentlist) { 387*7c478bd9Sstevel@tonic-gate (nlp->ncallers)++; 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate if (nlp->ncallers) { 391*7c478bd9Sstevel@tonic-gate (*tarcs) += nlp->ncallers; 392*7c478bd9Sstevel@tonic-gate (*ncallees)++; 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate static void 399*7c478bd9Sstevel@tonic-gate dump_modules(FILE *fp, char *filename, size_t pbuf_sz) 400*7c478bd9Sstevel@tonic-gate { 401*7c478bd9Sstevel@tonic-gate char *pbuf, *p; 402*7c478bd9Sstevel@tonic-gate size_t namelen; 403*7c478bd9Sstevel@tonic-gate Index off_nxt, off_path; 404*7c478bd9Sstevel@tonic-gate mod_info_t *mi; 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate ProfModuleList prof_modlist; 407*7c478bd9Sstevel@tonic-gate ProfModule prof_mod; 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate /* Allocate for path strings buffer */ 410*7c478bd9Sstevel@tonic-gate pbuf_sz = CEIL(pbuf_sz, STRUCT_ALIGN); 411*7c478bd9Sstevel@tonic-gate if ((p = pbuf = (char *) calloc(pbuf_sz, sizeof (char))) == NULL) { 412*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: no room for %ld bytes\n", 413*7c478bd9Sstevel@tonic-gate whoami, pbuf_sz * sizeof (char)); 414*7c478bd9Sstevel@tonic-gate exit(EX_OSERR); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate /* Dump out PROF_MODULE_T info for all non-aout modules */ 418*7c478bd9Sstevel@tonic-gate prof_modlist.type = PROF_MODULES_T; 419*7c478bd9Sstevel@tonic-gate prof_modlist.version = PROF_MODULES_VER; 420*7c478bd9Sstevel@tonic-gate prof_modlist.modules = PROFMODLIST_SZ; 421*7c478bd9Sstevel@tonic-gate prof_modlist.size = PROFMODLIST_SZ + (n_modules - 1) * PROFMOD_SZ + 422*7c478bd9Sstevel@tonic-gate pbuf_sz; 423*7c478bd9Sstevel@tonic-gate if (fwrite(&prof_modlist, sizeof (ProfModuleList), 1, fp) != 1) { 424*7c478bd9Sstevel@tonic-gate perror(filename); 425*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate if (MODLIST_FILLER) 428*7c478bd9Sstevel@tonic-gate fseek(fp, MODLIST_FILLER, SEEK_CUR); 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate /* 431*7c478bd9Sstevel@tonic-gate * Initialize offsets for ProfModule elements. 432*7c478bd9Sstevel@tonic-gate */ 433*7c478bd9Sstevel@tonic-gate off_nxt = PROFMODLIST_SZ + PROFMOD_SZ; 434*7c478bd9Sstevel@tonic-gate off_path = PROFMODLIST_SZ + (n_modules - 1) * PROFMOD_SZ; 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate for (mi = modules.next; mi; mi = mi->next) { 437*7c478bd9Sstevel@tonic-gate if (mi->next) 438*7c478bd9Sstevel@tonic-gate prof_mod.next = off_nxt; 439*7c478bd9Sstevel@tonic-gate else 440*7c478bd9Sstevel@tonic-gate prof_mod.next = 0; 441*7c478bd9Sstevel@tonic-gate prof_mod.path = off_path; 442*7c478bd9Sstevel@tonic-gate prof_mod.startaddr = mi->load_base; 443*7c478bd9Sstevel@tonic-gate prof_mod.endaddr = mi->load_end; 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate if (fwrite(&prof_mod, sizeof (ProfModule), 1, fp) != 1) { 446*7c478bd9Sstevel@tonic-gate perror(filename); 447*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate if (MOD_FILLER) 451*7c478bd9Sstevel@tonic-gate fseek(fp, MOD_FILLER, SEEK_CUR); 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate strcpy(p, mi->name); 454*7c478bd9Sstevel@tonic-gate namelen = strlen(mi->name); 455*7c478bd9Sstevel@tonic-gate p += namelen + 1; 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* Note that offset to every path str need not be aligned */ 458*7c478bd9Sstevel@tonic-gate off_nxt += PROFMOD_SZ; 459*7c478bd9Sstevel@tonic-gate off_path += namelen + 1; 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate /* Write out the module path strings */ 463*7c478bd9Sstevel@tonic-gate if (pbuf_sz) { 464*7c478bd9Sstevel@tonic-gate if (fwrite(pbuf, pbuf_sz, 1, fp) != 1) { 465*7c478bd9Sstevel@tonic-gate perror(filename); 466*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate free(pbuf); 470*7c478bd9Sstevel@tonic-gate } 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * If we have inactive modules, their current load addresses may overlap with 475*7c478bd9Sstevel@tonic-gate * active ones, and so we've to assign fictitious, non-overlapping addresses 476*7c478bd9Sstevel@tonic-gate * to all modules before we dump them. 477*7c478bd9Sstevel@tonic-gate */ 478*7c478bd9Sstevel@tonic-gate static void 479*7c478bd9Sstevel@tonic-gate fixup_maps(size_t *pathsz) 480*7c478bd9Sstevel@tonic-gate { 481*7c478bd9Sstevel@tonic-gate unsigned int n_inactive = 0; 482*7c478bd9Sstevel@tonic-gate Address lbase, lend; 483*7c478bd9Sstevel@tonic-gate mod_info_t *mi; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate /* Pick the lowest load address among modules */ 486*7c478bd9Sstevel@tonic-gate *pathsz = 0; 487*7c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate if (mi->active == FALSE) 490*7c478bd9Sstevel@tonic-gate n_inactive++; 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate if (mi == &modules || mi->load_base < lbase) 493*7c478bd9Sstevel@tonic-gate lbase = mi->load_base; 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate /* 496*7c478bd9Sstevel@tonic-gate * Return total path size of non-aout modules only 497*7c478bd9Sstevel@tonic-gate */ 498*7c478bd9Sstevel@tonic-gate if (mi != &modules) 499*7c478bd9Sstevel@tonic-gate *pathsz = (*pathsz) + strlen(mi->name) + 1; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate /* 503*7c478bd9Sstevel@tonic-gate * All module info is in fine shape already if there are no 504*7c478bd9Sstevel@tonic-gate * inactive modules 505*7c478bd9Sstevel@tonic-gate */ 506*7c478bd9Sstevel@tonic-gate if (n_inactive == 0) 507*7c478bd9Sstevel@tonic-gate return; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate /* 510*7c478bd9Sstevel@tonic-gate * Assign fictitious load addresses to all (non-aout) modules so 511*7c478bd9Sstevel@tonic-gate * that sum info can be dumped out. 512*7c478bd9Sstevel@tonic-gate */ 513*7c478bd9Sstevel@tonic-gate for (mi = modules.next; mi; mi = mi->next) { 514*7c478bd9Sstevel@tonic-gate lend = lbase + (mi->data_end - mi->txt_origin); 515*7c478bd9Sstevel@tonic-gate if ((lbase < modules.load_base && lend < modules.load_base) || 516*7c478bd9Sstevel@tonic-gate (lbase > modules.load_end && lend > modules.load_end)) { 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate mi->load_base = lbase; 519*7c478bd9Sstevel@tonic-gate mi->load_end = lend; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* just to give an appearance of reality */ 522*7c478bd9Sstevel@tonic-gate lbase = CEIL(lend + PGSZ, PGSZ); 523*7c478bd9Sstevel@tonic-gate } else { 524*7c478bd9Sstevel@tonic-gate /* 525*7c478bd9Sstevel@tonic-gate * can't use this lbase & lend pair, as it 526*7c478bd9Sstevel@tonic-gate * overlaps with aout's addresses 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate mi->load_base = CEIL(modules.load_end + PGSZ, PGSZ); 529*7c478bd9Sstevel@tonic-gate mi->load_end = mi->load_base + (lend - lbase); 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate lbase = CEIL(mi->load_end + PGSZ, PGSZ); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate } 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate static void 537*7c478bd9Sstevel@tonic-gate dump_gprofhdr(FILE *fp, char *filename) 538*7c478bd9Sstevel@tonic-gate { 539*7c478bd9Sstevel@tonic-gate ProfHeader prof_hdr; 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate prof_hdr.h_magic = PROF_MAGIC; 542*7c478bd9Sstevel@tonic-gate prof_hdr.h_major_ver = PROF_MAJOR_VERSION; 543*7c478bd9Sstevel@tonic-gate prof_hdr.h_minor_ver = PROF_MINOR_VERSION; 544*7c478bd9Sstevel@tonic-gate prof_hdr.size = PROFHDR_SZ; 545*7c478bd9Sstevel@tonic-gate if (fwrite(&prof_hdr, sizeof (prof_hdr), 1, fp) != 1) { 546*7c478bd9Sstevel@tonic-gate perror(filename); 547*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate if (HDR_FILLER) 551*7c478bd9Sstevel@tonic-gate fseek(fp, HDR_FILLER, SEEK_CUR); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate static void 555*7c478bd9Sstevel@tonic-gate dumpsum_ostyle(char *sumfile) 556*7c478bd9Sstevel@tonic-gate { 557*7c478bd9Sstevel@tonic-gate register nltype *nlp; 558*7c478bd9Sstevel@tonic-gate register arctype *arcp; 559*7c478bd9Sstevel@tonic-gate struct rawarc arc; 560*7c478bd9Sstevel@tonic-gate struct rawarc32 arc32; 561*7c478bd9Sstevel@tonic-gate FILE *sfile; 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate if ((sfile = fopen(sumfile, "w")) == NULL) { 564*7c478bd9Sstevel@tonic-gate perror(sumfile); 565*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate /* 568*7c478bd9Sstevel@tonic-gate * dump the header; use the last header read in 569*7c478bd9Sstevel@tonic-gate */ 570*7c478bd9Sstevel@tonic-gate if (Bflag) { 571*7c478bd9Sstevel@tonic-gate if (fwrite(&h, sizeof (h), 1, sfile) != 1) { 572*7c478bd9Sstevel@tonic-gate perror(sumfile); 573*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate } else { 576*7c478bd9Sstevel@tonic-gate struct hdr32 hdr; 577*7c478bd9Sstevel@tonic-gate hdr.lowpc = (pctype32)h.lowpc; 578*7c478bd9Sstevel@tonic-gate hdr.highpc = (pctype32)h.highpc; 579*7c478bd9Sstevel@tonic-gate hdr.ncnt = (pctype32)h.ncnt; 580*7c478bd9Sstevel@tonic-gate if (fwrite(&hdr, sizeof (hdr), 1, sfile) != 1) { 581*7c478bd9Sstevel@tonic-gate perror(sumfile); 582*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate /* 586*7c478bd9Sstevel@tonic-gate * dump the samples 587*7c478bd9Sstevel@tonic-gate */ 588*7c478bd9Sstevel@tonic-gate if (fwrite(samples, sizeof (unsigned_UNIT), nsamples, sfile) != 589*7c478bd9Sstevel@tonic-gate nsamples) { 590*7c478bd9Sstevel@tonic-gate perror(sumfile); 591*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate /* 594*7c478bd9Sstevel@tonic-gate * dump the normalized raw arc information. For old-style dumping, 595*7c478bd9Sstevel@tonic-gate * the only namelist is in modules.nl 596*7c478bd9Sstevel@tonic-gate */ 597*7c478bd9Sstevel@tonic-gate for (nlp = modules.nl; nlp < modules.npe; nlp++) { 598*7c478bd9Sstevel@tonic-gate for (arcp = nlp->children; arcp; 599*7c478bd9Sstevel@tonic-gate arcp = arcp->arc_childlist) { 600*7c478bd9Sstevel@tonic-gate if (Bflag) { 601*7c478bd9Sstevel@tonic-gate arc.raw_frompc = arcp->arc_parentp->value; 602*7c478bd9Sstevel@tonic-gate arc.raw_selfpc = arcp->arc_childp->value; 603*7c478bd9Sstevel@tonic-gate arc.raw_count = arcp->arc_count; 604*7c478bd9Sstevel@tonic-gate if (fwrite(&arc, sizeof (arc), 1, sfile) != 1) { 605*7c478bd9Sstevel@tonic-gate perror(sumfile); 606*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate } else { 609*7c478bd9Sstevel@tonic-gate arc32.raw_frompc = 610*7c478bd9Sstevel@tonic-gate (pctype32)arcp->arc_parentp->value; 611*7c478bd9Sstevel@tonic-gate arc32.raw_selfpc = 612*7c478bd9Sstevel@tonic-gate (pctype32)arcp->arc_childp->value; 613*7c478bd9Sstevel@tonic-gate arc32.raw_count = (actype32)arcp->arc_count; 614*7c478bd9Sstevel@tonic-gate if (fwrite(&arc32, sizeof (arc32), 1, sfile) != 1) { 615*7c478bd9Sstevel@tonic-gate perror(sumfile); 616*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 620*7c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 621*7c478bd9Sstevel@tonic-gate printf("[dumpsum_ostyle] frompc 0x%llx selfpc " 622*7c478bd9Sstevel@tonic-gate "0x%llx count %lld\n", arc.raw_frompc, 623*7c478bd9Sstevel@tonic-gate arc.raw_selfpc, arc.raw_count); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate #endif DEBUG 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate fclose(sfile); 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate /* 632*7c478bd9Sstevel@tonic-gate * dump out the gmon.sum file 633*7c478bd9Sstevel@tonic-gate */ 634*7c478bd9Sstevel@tonic-gate static void 635*7c478bd9Sstevel@tonic-gate dumpsum(char *sumfile) 636*7c478bd9Sstevel@tonic-gate { 637*7c478bd9Sstevel@tonic-gate FILE *sfile; 638*7c478bd9Sstevel@tonic-gate size_t pathbuf_sz; 639*7c478bd9Sstevel@tonic-gate unsigned long total_arcs; /* total number of arcs in all */ 640*7c478bd9Sstevel@tonic-gate unsigned long ncallees; /* no. of callees with parents */ 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate if (old_style) { 643*7c478bd9Sstevel@tonic-gate dumpsum_ostyle(sumfile); 644*7c478bd9Sstevel@tonic-gate return; 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate if ((sfile = fopen(sumfile, "w")) == NULL) { 648*7c478bd9Sstevel@tonic-gate perror(sumfile); 649*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate /* 653*7c478bd9Sstevel@tonic-gate * Dump the new-style gprof header. Even if one of the original 654*7c478bd9Sstevel@tonic-gate * profiled-files was of a older version, the summed file is of 655*7c478bd9Sstevel@tonic-gate * current version only. 656*7c478bd9Sstevel@tonic-gate */ 657*7c478bd9Sstevel@tonic-gate dump_gprofhdr(sfile, sumfile); 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate /* 660*7c478bd9Sstevel@tonic-gate * Fix up load-maps and dump out modules info 661*7c478bd9Sstevel@tonic-gate * 662*7c478bd9Sstevel@tonic-gate * Fix up module load maps so inactive modules get *some* address 663*7c478bd9Sstevel@tonic-gate * (and btw, could you get the total size of non-aout module path 664*7c478bd9Sstevel@tonic-gate * strings please ?) 665*7c478bd9Sstevel@tonic-gate */ 666*7c478bd9Sstevel@tonic-gate fixup_maps(&pathbuf_sz); 667*7c478bd9Sstevel@tonic-gate dump_modules(sfile, sumfile, pathbuf_sz); 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* 671*7c478bd9Sstevel@tonic-gate * Dump out the summ'd pcsamples 672*7c478bd9Sstevel@tonic-gate * 673*7c478bd9Sstevel@tonic-gate * For dumping call graph information later, we need certain 674*7c478bd9Sstevel@tonic-gate * statistics (like total arcs, number of callers for each node); 675*7c478bd9Sstevel@tonic-gate * collect these also while we are at it. 676*7c478bd9Sstevel@tonic-gate */ 677*7c478bd9Sstevel@tonic-gate dump_pcsamples(sfile, sumfile, &total_arcs, &ncallees); 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate /* 680*7c478bd9Sstevel@tonic-gate * Dump out the summ'd call graph information 681*7c478bd9Sstevel@tonic-gate */ 682*7c478bd9Sstevel@tonic-gate dump_callgraph(sfile, sumfile, total_arcs, ncallees); 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate fclose(sfile); 686*7c478bd9Sstevel@tonic-gate } 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate static void 689*7c478bd9Sstevel@tonic-gate tally(mod_info_t *caller_mod, mod_info_t *callee_mod, struct rawarc *rawp) 690*7c478bd9Sstevel@tonic-gate { 691*7c478bd9Sstevel@tonic-gate nltype *parentp; 692*7c478bd9Sstevel@tonic-gate nltype *childp; 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate /* 695*7c478bd9Sstevel@tonic-gate * if count == 0 this is a null arc and 696*7c478bd9Sstevel@tonic-gate * we don't need to tally it. 697*7c478bd9Sstevel@tonic-gate */ 698*7c478bd9Sstevel@tonic-gate if (rawp->raw_count == 0) 699*7c478bd9Sstevel@tonic-gate return; 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate /* 702*7c478bd9Sstevel@tonic-gate * Lookup the caller and callee pcs in namelists of 703*7c478bd9Sstevel@tonic-gate * appropriate modules 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate parentp = nllookup(caller_mod, rawp->raw_frompc, NULL); 706*7c478bd9Sstevel@tonic-gate childp = nllookup(callee_mod, rawp->raw_selfpc, NULL); 707*7c478bd9Sstevel@tonic-gate if (childp && parentp) { 708*7c478bd9Sstevel@tonic-gate if (!Dflag) 709*7c478bd9Sstevel@tonic-gate childp->ncall += rawp->raw_count; 710*7c478bd9Sstevel@tonic-gate else { 711*7c478bd9Sstevel@tonic-gate if (first_file) 712*7c478bd9Sstevel@tonic-gate childp->ncall += rawp->raw_count; 713*7c478bd9Sstevel@tonic-gate else { 714*7c478bd9Sstevel@tonic-gate childp->ncall -= rawp->raw_count; 715*7c478bd9Sstevel@tonic-gate if (childp->ncall < 0) 716*7c478bd9Sstevel@tonic-gate childp->ncall = 0; 717*7c478bd9Sstevel@tonic-gate } 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 721*7c478bd9Sstevel@tonic-gate if (debug & TALLYDEBUG) { 722*7c478bd9Sstevel@tonic-gate printf("[tally] arc from %s to %s traversed " 723*7c478bd9Sstevel@tonic-gate "%lld times\n", parentp->name, 724*7c478bd9Sstevel@tonic-gate childp->name, rawp->raw_count); 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate #endif DEBUG 727*7c478bd9Sstevel@tonic-gate addarc(parentp, childp, rawp->raw_count); 728*7c478bd9Sstevel@tonic-gate } 729*7c478bd9Sstevel@tonic-gate } 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate /* 732*7c478bd9Sstevel@tonic-gate * Look up a module's base address in a sorted list of pc-hits. Unlike 733*7c478bd9Sstevel@tonic-gate * nllookup(), this deals with misses by mapping them to the next *higher* 734*7c478bd9Sstevel@tonic-gate * pc-hit. This is so that we get into the module's first pc-hit rightaway, 735*7c478bd9Sstevel@tonic-gate * even if the module's entry-point (load_base) itself is not a hit. 736*7c478bd9Sstevel@tonic-gate */ 737*7c478bd9Sstevel@tonic-gate static Address * 738*7c478bd9Sstevel@tonic-gate locate(Address *pclist, size_t nelem, Address keypc) 739*7c478bd9Sstevel@tonic-gate { 740*7c478bd9Sstevel@tonic-gate size_t low = 0, middle, high = nelem - 1; 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate if (keypc <= pclist[low]) 743*7c478bd9Sstevel@tonic-gate return (pclist); 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate if (keypc > pclist[high]) 746*7c478bd9Sstevel@tonic-gate return (NULL); 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate while (low != high) { 749*7c478bd9Sstevel@tonic-gate middle = (high + low) >> 1; 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate if ((pclist[middle] < keypc) && (pclist[middle + 1] >= keypc)) 752*7c478bd9Sstevel@tonic-gate return (&pclist[middle + 1]); 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate if (pclist[middle] >= keypc) 755*7c478bd9Sstevel@tonic-gate high = middle; 756*7c478bd9Sstevel@tonic-gate else 757*7c478bd9Sstevel@tonic-gate low = middle + 1; 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate /* must never reach here! */ 761*7c478bd9Sstevel@tonic-gate return (NULL); 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate static void 765*7c478bd9Sstevel@tonic-gate assign_pcsamples(module, pcsmpl, n_samples) 766*7c478bd9Sstevel@tonic-gate mod_info_t *module; 767*7c478bd9Sstevel@tonic-gate Address *pcsmpl; 768*7c478bd9Sstevel@tonic-gate size_t n_samples; 769*7c478bd9Sstevel@tonic-gate { 770*7c478bd9Sstevel@tonic-gate Address *pcptr, *pcse = pcsmpl + n_samples; 771*7c478bd9Sstevel@tonic-gate pctype nxt_func; 772*7c478bd9Sstevel@tonic-gate nltype *fnl; 773*7c478bd9Sstevel@tonic-gate size_t func_nticks; 774*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 775*7c478bd9Sstevel@tonic-gate size_t n_hits_in_module = 0; 776*7c478bd9Sstevel@tonic-gate #endif DEBUG 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate /* Locate the first pc-hit for this module */ 779*7c478bd9Sstevel@tonic-gate if ((pcptr = locate(pcsmpl, n_samples, module->load_base)) == NULL) { 780*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 781*7c478bd9Sstevel@tonic-gate if (debug & PCSMPLDEBUG) { 782*7c478bd9Sstevel@tonic-gate printf("[assign_pcsamples] no pc-hits in\n"); 783*7c478bd9Sstevel@tonic-gate printf(" `%s'\n", module->name); 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate #endif DEBUG 786*7c478bd9Sstevel@tonic-gate return; /* no pc-hits in this module */ 787*7c478bd9Sstevel@tonic-gate } 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate /* Assign all pc-hits in this module to appropriate functions */ 790*7c478bd9Sstevel@tonic-gate while ((pcptr < pcse) && (*pcptr < module->load_end)) { 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate /* Update the corresponding function's time */ 793*7c478bd9Sstevel@tonic-gate if (fnl = nllookup(module, (pctype) *pcptr, &nxt_func)) { 794*7c478bd9Sstevel@tonic-gate /* 795*7c478bd9Sstevel@tonic-gate * Collect all pc-hits in this function. Each 796*7c478bd9Sstevel@tonic-gate * pc-hit counts as 1 tick. 797*7c478bd9Sstevel@tonic-gate */ 798*7c478bd9Sstevel@tonic-gate func_nticks = 0; 799*7c478bd9Sstevel@tonic-gate while ((pcptr < pcse) && (*pcptr < nxt_func)) { 800*7c478bd9Sstevel@tonic-gate func_nticks++; 801*7c478bd9Sstevel@tonic-gate pcptr++; 802*7c478bd9Sstevel@tonic-gate } 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate if (func_nticks == 0) 805*7c478bd9Sstevel@tonic-gate pcptr++; 806*7c478bd9Sstevel@tonic-gate else { 807*7c478bd9Sstevel@tonic-gate fnl->nticks += func_nticks; 808*7c478bd9Sstevel@tonic-gate fnl->time += func_nticks; 809*7c478bd9Sstevel@tonic-gate totime += func_nticks; 810*7c478bd9Sstevel@tonic-gate } 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 813*7c478bd9Sstevel@tonic-gate n_hits_in_module += func_nticks; 814*7c478bd9Sstevel@tonic-gate #endif DEBUG 815*7c478bd9Sstevel@tonic-gate } else { 816*7c478bd9Sstevel@tonic-gate /* 817*7c478bd9Sstevel@tonic-gate * pc sample could not be assigned to function; 818*7c478bd9Sstevel@tonic-gate * probably in a PLT 819*7c478bd9Sstevel@tonic-gate */ 820*7c478bd9Sstevel@tonic-gate pcptr++; 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 825*7c478bd9Sstevel@tonic-gate if (debug & PCSMPLDEBUG) { 826*7c478bd9Sstevel@tonic-gate printf("[assign_pcsamples] %ld hits in\n", n_hits_in_module); 827*7c478bd9Sstevel@tonic-gate printf(" `%s'\n", module->name); 828*7c478bd9Sstevel@tonic-gate } 829*7c478bd9Sstevel@tonic-gate #endif DEBUG 830*7c478bd9Sstevel@tonic-gate } 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate int 833*7c478bd9Sstevel@tonic-gate pc_cmp(Address *pc1, Address *pc2) 834*7c478bd9Sstevel@tonic-gate { 835*7c478bd9Sstevel@tonic-gate if (*pc1 > *pc2) 836*7c478bd9Sstevel@tonic-gate return (1); 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate if (*pc1 < *pc2) 839*7c478bd9Sstevel@tonic-gate return (-1); 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate return (0); 842*7c478bd9Sstevel@tonic-gate } 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate static void 845*7c478bd9Sstevel@tonic-gate process_pcsamples(bufp) 846*7c478bd9Sstevel@tonic-gate ProfBuffer *bufp; 847*7c478bd9Sstevel@tonic-gate { 848*7c478bd9Sstevel@tonic-gate Address *pc_samples; 849*7c478bd9Sstevel@tonic-gate mod_info_t *mi; 850*7c478bd9Sstevel@tonic-gate caddr_t p; 851*7c478bd9Sstevel@tonic-gate size_t chunk_size, nelem_read, nelem_to_read; 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 854*7c478bd9Sstevel@tonic-gate if (debug & PCSMPLDEBUG) { 855*7c478bd9Sstevel@tonic-gate printf("[process_pcsamples] number of pcsamples = %lld\n", 856*7c478bd9Sstevel@tonic-gate bufp->bufsize); 857*7c478bd9Sstevel@tonic-gate } 858*7c478bd9Sstevel@tonic-gate #endif DEBUG 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate /* buffer with no pc samples ? */ 861*7c478bd9Sstevel@tonic-gate if (bufp->bufsize == 0) 862*7c478bd9Sstevel@tonic-gate return; 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate /* 865*7c478bd9Sstevel@tonic-gate * If we're processing pcsamples of a profile sum, we could have 866*7c478bd9Sstevel@tonic-gate * more than PROF_BUFFER_SIZE number of samples. In such a case, 867*7c478bd9Sstevel@tonic-gate * we must read the pcsamples in chunks. 868*7c478bd9Sstevel@tonic-gate */ 869*7c478bd9Sstevel@tonic-gate if ((chunk_size = bufp->bufsize) > PROF_BUFFER_SIZE) 870*7c478bd9Sstevel@tonic-gate chunk_size = PROF_BUFFER_SIZE; 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate /* Allocate for the pcsample chunk */ 873*7c478bd9Sstevel@tonic-gate pc_samples = (Address *) calloc(chunk_size, sizeof (Address)); 874*7c478bd9Sstevel@tonic-gate if (pc_samples == NULL) { 875*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: no room for %ld sample pc's\n", 876*7c478bd9Sstevel@tonic-gate whoami, chunk_size); 877*7c478bd9Sstevel@tonic-gate exit(EX_OSERR); 878*7c478bd9Sstevel@tonic-gate } 879*7c478bd9Sstevel@tonic-gate 880*7c478bd9Sstevel@tonic-gate /* Copy the current set of pcsamples */ 881*7c478bd9Sstevel@tonic-gate nelem_read = 0; 882*7c478bd9Sstevel@tonic-gate nelem_to_read = bufp->bufsize; 883*7c478bd9Sstevel@tonic-gate p = (char *) bufp + bufp->buffer; 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate while (nelem_read < nelem_to_read) { 886*7c478bd9Sstevel@tonic-gate memcpy((void *) pc_samples, p, chunk_size * sizeof (Address)); 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate /* Sort the pc samples */ 889*7c478bd9Sstevel@tonic-gate qsort(pc_samples, chunk_size, sizeof (Address), 890*7c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *)) pc_cmp); 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate /* 893*7c478bd9Sstevel@tonic-gate * Assign pcsamples to functions in the currently active 894*7c478bd9Sstevel@tonic-gate * module list 895*7c478bd9Sstevel@tonic-gate */ 896*7c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 897*7c478bd9Sstevel@tonic-gate if (mi->active == FALSE) 898*7c478bd9Sstevel@tonic-gate continue; 899*7c478bd9Sstevel@tonic-gate assign_pcsamples(mi, pc_samples, chunk_size); 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate p += (chunk_size * sizeof (Address)); 903*7c478bd9Sstevel@tonic-gate nelem_read += chunk_size; 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate if ((nelem_to_read - nelem_read) < chunk_size) 906*7c478bd9Sstevel@tonic-gate chunk_size = nelem_to_read - nelem_read; 907*7c478bd9Sstevel@tonic-gate } 908*7c478bd9Sstevel@tonic-gate 909*7c478bd9Sstevel@tonic-gate free(pc_samples); 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate /* Update total number of pcsamples read so far */ 912*7c478bd9Sstevel@tonic-gate n_pcsamples += bufp->bufsize; 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate static mod_info_t * 916*7c478bd9Sstevel@tonic-gate find_module(Address addr) 917*7c478bd9Sstevel@tonic-gate { 918*7c478bd9Sstevel@tonic-gate mod_info_t *mi; 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 921*7c478bd9Sstevel@tonic-gate if (mi->active == FALSE) 922*7c478bd9Sstevel@tonic-gate continue; 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate if (addr >= mi->load_base && addr < mi->load_end) 925*7c478bd9Sstevel@tonic-gate return (mi); 926*7c478bd9Sstevel@tonic-gate } 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate return (NULL); 929*7c478bd9Sstevel@tonic-gate } 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate static void 932*7c478bd9Sstevel@tonic-gate process_cgraph(cgp) 933*7c478bd9Sstevel@tonic-gate ProfCallGraph *cgp; 934*7c478bd9Sstevel@tonic-gate { 935*7c478bd9Sstevel@tonic-gate struct rawarc arc; 936*7c478bd9Sstevel@tonic-gate mod_info_t *callee_mi, *caller_mi; 937*7c478bd9Sstevel@tonic-gate ProfFunction *calleep, *callerp; 938*7c478bd9Sstevel@tonic-gate Index caller_off, callee_off; 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate /* 941*7c478bd9Sstevel@tonic-gate * Note that *callee_off* increment in the for loop below 942*7c478bd9Sstevel@tonic-gate * uses *calleep* and *calleep* doesn't get set until the for loop 943*7c478bd9Sstevel@tonic-gate * is entered. We don't expect the increment to be executed before 944*7c478bd9Sstevel@tonic-gate * the loop body is executed atleast once, so this should be ok. 945*7c478bd9Sstevel@tonic-gate */ 946*7c478bd9Sstevel@tonic-gate for (callee_off = cgp->functions; callee_off; 947*7c478bd9Sstevel@tonic-gate callee_off = calleep->next_to) { 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate calleep = (ProfFunction *) ((char *) cgp + callee_off); 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate /* 952*7c478bd9Sstevel@tonic-gate * We could choose either to sort the {caller, callee} 953*7c478bd9Sstevel@tonic-gate * list twice and assign callee/caller to modules or inspect 954*7c478bd9Sstevel@tonic-gate * each callee/caller in the active modules list. Since 955*7c478bd9Sstevel@tonic-gate * the modules list is usually very small, we'l choose the 956*7c478bd9Sstevel@tonic-gate * latter. 957*7c478bd9Sstevel@tonic-gate */ 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate /* 960*7c478bd9Sstevel@tonic-gate * If we cannot identify a callee with a module, there's 961*7c478bd9Sstevel@tonic-gate * no use worrying about who called it. 962*7c478bd9Sstevel@tonic-gate */ 963*7c478bd9Sstevel@tonic-gate if ((callee_mi = find_module(calleep->topc)) == NULL) { 964*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 965*7c478bd9Sstevel@tonic-gate if (debug & CGRAPHDEBUG) { 966*7c478bd9Sstevel@tonic-gate printf("[process_cgraph] callee %#llx missed\n", 967*7c478bd9Sstevel@tonic-gate calleep->topc); 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate #endif DEBUG 970*7c478bd9Sstevel@tonic-gate continue; 971*7c478bd9Sstevel@tonic-gate } else 972*7c478bd9Sstevel@tonic-gate arc.raw_selfpc = calleep->topc; 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate for (caller_off = callee_off; caller_off; 975*7c478bd9Sstevel@tonic-gate caller_off = callerp->next_from) { 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate callerp = (ProfFunction *) ((char *) cgp + caller_off); 978*7c478bd9Sstevel@tonic-gate if ((caller_mi = find_module(callerp->frompc)) == 979*7c478bd9Sstevel@tonic-gate NULL) { 980*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 981*7c478bd9Sstevel@tonic-gate if (debug & CGRAPHDEBUG) { 982*7c478bd9Sstevel@tonic-gate printf("[process_cgraph] caller %#llx " 983*7c478bd9Sstevel@tonic-gate "missed\n", callerp->frompc); 984*7c478bd9Sstevel@tonic-gate } 985*7c478bd9Sstevel@tonic-gate #endif DEBUG 986*7c478bd9Sstevel@tonic-gate continue; 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate arc.raw_frompc = callerp->frompc; 990*7c478bd9Sstevel@tonic-gate arc.raw_count = callerp->count; 991*7c478bd9Sstevel@tonic-gate 992*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 993*7c478bd9Sstevel@tonic-gate if (debug & CGRAPHDEBUG) { 994*7c478bd9Sstevel@tonic-gate printf("[process_cgraph] arc <%#llx, %#llx, " 995*7c478bd9Sstevel@tonic-gate "%lld>\n", arc.raw_frompc, 996*7c478bd9Sstevel@tonic-gate arc.raw_selfpc, arc.raw_count); 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate #endif DEBUG 999*7c478bd9Sstevel@tonic-gate tally(caller_mi, callee_mi, &arc); 1000*7c478bd9Sstevel@tonic-gate } 1001*7c478bd9Sstevel@tonic-gate } 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1004*7c478bd9Sstevel@tonic-gate puts("\n"); 1005*7c478bd9Sstevel@tonic-gate #endif DEBUG 1006*7c478bd9Sstevel@tonic-gate } 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate /* 1009*7c478bd9Sstevel@tonic-gate * Two modules overlap each other if they don't lie completely *outside* 1010*7c478bd9Sstevel@tonic-gate * each other. 1011*7c478bd9Sstevel@tonic-gate */ 1012*7c478bd9Sstevel@tonic-gate static bool 1013*7c478bd9Sstevel@tonic-gate does_overlap(ProfModule *new, mod_info_t *old) 1014*7c478bd9Sstevel@tonic-gate { 1015*7c478bd9Sstevel@tonic-gate /* case 1: new module lies completely *before* the old one */ 1016*7c478bd9Sstevel@tonic-gate if (new->startaddr < old->load_base && new->endaddr <= old->load_base) 1017*7c478bd9Sstevel@tonic-gate return (FALSE); 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate /* case 2: new module lies completely *after* the old one */ 1020*7c478bd9Sstevel@tonic-gate if (new->startaddr >= old->load_end && new->endaddr >= old->load_end) 1021*7c478bd9Sstevel@tonic-gate return (FALSE); 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate /* probably a dlopen: the modules overlap each other */ 1024*7c478bd9Sstevel@tonic-gate return (TRUE); 1025*7c478bd9Sstevel@tonic-gate } 1026*7c478bd9Sstevel@tonic-gate 1027*7c478bd9Sstevel@tonic-gate static bool 1028*7c478bd9Sstevel@tonic-gate is_same_as_aout(char *modpath, struct stat *buf) 1029*7c478bd9Sstevel@tonic-gate { 1030*7c478bd9Sstevel@tonic-gate if (stat(modpath, buf) == -1) { 1031*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: can't get info on `%s'\n", 1032*7c478bd9Sstevel@tonic-gate whoami, modpath); 1033*7c478bd9Sstevel@tonic-gate exit(EX_NOINPUT); 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate if ((buf->st_dev == aout_info.dev) && (buf->st_ino == aout_info.ino)) 1037*7c478bd9Sstevel@tonic-gate return (TRUE); 1038*7c478bd9Sstevel@tonic-gate else 1039*7c478bd9Sstevel@tonic-gate return (FALSE); 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate static void 1043*7c478bd9Sstevel@tonic-gate process_modules(modlp) 1044*7c478bd9Sstevel@tonic-gate ProfModuleList *modlp; 1045*7c478bd9Sstevel@tonic-gate { 1046*7c478bd9Sstevel@tonic-gate ProfModule *newmodp; 1047*7c478bd9Sstevel@tonic-gate mod_info_t *mi, *last, *new_module; 1048*7c478bd9Sstevel@tonic-gate char *so_path, *name; 1049*7c478bd9Sstevel@tonic-gate bool more_modules = TRUE; 1050*7c478bd9Sstevel@tonic-gate struct stat so_statbuf; 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1053*7c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 1054*7c478bd9Sstevel@tonic-gate printf("[process_modules] module obj version %u\n", 1055*7c478bd9Sstevel@tonic-gate modlp->version); 1056*7c478bd9Sstevel@tonic-gate } 1057*7c478bd9Sstevel@tonic-gate #endif DEBUG 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate /* Check version of module type object */ 1060*7c478bd9Sstevel@tonic-gate if (modlp->version > PROF_MODULES_VER) { 1061*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: version %d for module type objects" 1062*7c478bd9Sstevel@tonic-gate "is not supported\n", whoami, modlp->version); 1063*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1064*7c478bd9Sstevel@tonic-gate } 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate /* 1068*7c478bd9Sstevel@tonic-gate * Scan the PROF_MODULES_T list and add modules to current list 1069*7c478bd9Sstevel@tonic-gate * of modules, if they're not present already 1070*7c478bd9Sstevel@tonic-gate */ 1071*7c478bd9Sstevel@tonic-gate newmodp = (ProfModule *) ((char *) modlp + modlp->modules); 1072*7c478bd9Sstevel@tonic-gate do { 1073*7c478bd9Sstevel@tonic-gate /* 1074*7c478bd9Sstevel@tonic-gate * Since the prog could've been renamed after its run, we 1075*7c478bd9Sstevel@tonic-gate * should see if this overlaps a.out. If it does, it is 1076*7c478bd9Sstevel@tonic-gate * probably the renamed aout. We should also skip any other 1077*7c478bd9Sstevel@tonic-gate * non-sharedobj's that we see (or should we report an error ?) 1078*7c478bd9Sstevel@tonic-gate */ 1079*7c478bd9Sstevel@tonic-gate so_path = (caddr_t) modlp + newmodp->path; 1080*7c478bd9Sstevel@tonic-gate if (does_overlap(newmodp, &modules) || 1081*7c478bd9Sstevel@tonic-gate is_same_as_aout(so_path, &so_statbuf) || 1082*7c478bd9Sstevel@tonic-gate (!is_shared_obj(so_path))) { 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate if (!newmodp->next) 1085*7c478bd9Sstevel@tonic-gate more_modules = FALSE; 1086*7c478bd9Sstevel@tonic-gate 1087*7c478bd9Sstevel@tonic-gate newmodp = (ProfModule *) 1088*7c478bd9Sstevel@tonic-gate ((caddr_t) modlp + newmodp->next); 1089*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1090*7c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 1091*7c478bd9Sstevel@tonic-gate printf("[process_modules] `%s'\n", so_path); 1092*7c478bd9Sstevel@tonic-gate printf(" skipped\n"); 1093*7c478bd9Sstevel@tonic-gate } 1094*7c478bd9Sstevel@tonic-gate #endif DEBUG 1095*7c478bd9Sstevel@tonic-gate continue; 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1098*7c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) 1099*7c478bd9Sstevel@tonic-gate printf("[process_modules] `%s'...\n", so_path); 1100*7c478bd9Sstevel@tonic-gate #endif DEBUG 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate /* 1103*7c478bd9Sstevel@tonic-gate * Check all modules (leave the first one, 'cos that 1104*7c478bd9Sstevel@tonic-gate * is the program executable info). If this module is already 1105*7c478bd9Sstevel@tonic-gate * there in the list, update the load addresses and proceed. 1106*7c478bd9Sstevel@tonic-gate */ 1107*7c478bd9Sstevel@tonic-gate last = &modules; 1108*7c478bd9Sstevel@tonic-gate while (mi = last->next) { 1109*7c478bd9Sstevel@tonic-gate /* 1110*7c478bd9Sstevel@tonic-gate * We expect the full pathname for all shared objects 1111*7c478bd9Sstevel@tonic-gate * needed by the program executable. In this case, we 1112*7c478bd9Sstevel@tonic-gate * simply need to compare the paths to see if they are 1113*7c478bd9Sstevel@tonic-gate * the same file. 1114*7c478bd9Sstevel@tonic-gate */ 1115*7c478bd9Sstevel@tonic-gate if (strcmp(mi->name, so_path) == 0) 1116*7c478bd9Sstevel@tonic-gate break; 1117*7c478bd9Sstevel@tonic-gate 1118*7c478bd9Sstevel@tonic-gate /* 1119*7c478bd9Sstevel@tonic-gate * Check if this new shared object will overlap 1120*7c478bd9Sstevel@tonic-gate * any existing module. If yes, remove the old one 1121*7c478bd9Sstevel@tonic-gate * from the linked list (but don't free it, 'cos 1122*7c478bd9Sstevel@tonic-gate * there may be symbols referring to this module 1123*7c478bd9Sstevel@tonic-gate * still) 1124*7c478bd9Sstevel@tonic-gate */ 1125*7c478bd9Sstevel@tonic-gate if (does_overlap(newmodp, mi)) { 1126*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1127*7c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 1128*7c478bd9Sstevel@tonic-gate printf("[process_modules] `%s'\n", 1129*7c478bd9Sstevel@tonic-gate so_path); 1130*7c478bd9Sstevel@tonic-gate printf(" overlaps\n"); 1131*7c478bd9Sstevel@tonic-gate printf(" `%s'\n", 1132*7c478bd9Sstevel@tonic-gate mi->name); 1133*7c478bd9Sstevel@tonic-gate } 1134*7c478bd9Sstevel@tonic-gate #endif DEBUG 1135*7c478bd9Sstevel@tonic-gate mi->active = FALSE; 1136*7c478bd9Sstevel@tonic-gate } 1137*7c478bd9Sstevel@tonic-gate 1138*7c478bd9Sstevel@tonic-gate last = mi; 1139*7c478bd9Sstevel@tonic-gate } 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate /* Module already there, skip it */ 1142*7c478bd9Sstevel@tonic-gate if (mi != NULL) { 1143*7c478bd9Sstevel@tonic-gate mi->load_base = newmodp->startaddr; 1144*7c478bd9Sstevel@tonic-gate mi->load_end = newmodp->endaddr; 1145*7c478bd9Sstevel@tonic-gate mi->active = TRUE; 1146*7c478bd9Sstevel@tonic-gate if (!newmodp->next) 1147*7c478bd9Sstevel@tonic-gate more_modules = FALSE; 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate newmodp = (ProfModule *) 1150*7c478bd9Sstevel@tonic-gate ((caddr_t) modlp + newmodp->next); 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1153*7c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 1154*7c478bd9Sstevel@tonic-gate printf("[process_modules] base=%#llx, " 1155*7c478bd9Sstevel@tonic-gate "end=%#llx\n", mi->load_base, 1156*7c478bd9Sstevel@tonic-gate mi->load_end); 1157*7c478bd9Sstevel@tonic-gate } 1158*7c478bd9Sstevel@tonic-gate #endif DEBUG 1159*7c478bd9Sstevel@tonic-gate continue; 1160*7c478bd9Sstevel@tonic-gate } 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate /* 1163*7c478bd9Sstevel@tonic-gate * Check if gmon.out is outdated with respect to the new 1164*7c478bd9Sstevel@tonic-gate * module we want to add 1165*7c478bd9Sstevel@tonic-gate */ 1166*7c478bd9Sstevel@tonic-gate if (gmonout_info.mtime < so_statbuf.st_mtime) { 1167*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: shared obj outdates prof info\n", 1168*7c478bd9Sstevel@tonic-gate whoami); 1169*7c478bd9Sstevel@tonic-gate fprintf(stderr, "\t(newer %s)\n", so_path); 1170*7c478bd9Sstevel@tonic-gate exit(EX_NOINPUT); 1171*7c478bd9Sstevel@tonic-gate } 1172*7c478bd9Sstevel@tonic-gate 1173*7c478bd9Sstevel@tonic-gate /* Create a new module element */ 1174*7c478bd9Sstevel@tonic-gate new_module = (mod_info_t *) malloc(sizeof (mod_info_t)); 1175*7c478bd9Sstevel@tonic-gate if (new_module == NULL) { 1176*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: no room for %ld bytes\n", 1177*7c478bd9Sstevel@tonic-gate whoami, sizeof (mod_info_t)); 1178*7c478bd9Sstevel@tonic-gate exit(EX_OSERR); 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate 1181*7c478bd9Sstevel@tonic-gate /* and fill in info... */ 1182*7c478bd9Sstevel@tonic-gate new_module->id = n_modules + 1; 1183*7c478bd9Sstevel@tonic-gate new_module->load_base = newmodp->startaddr; 1184*7c478bd9Sstevel@tonic-gate new_module->load_end = newmodp->endaddr; 1185*7c478bd9Sstevel@tonic-gate new_module->name = (char *) malloc(strlen(so_path) + 1); 1186*7c478bd9Sstevel@tonic-gate if (new_module->name == NULL) { 1187*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: no room for %ld bytes\n", 1188*7c478bd9Sstevel@tonic-gate whoami, strlen(so_path) + 1); 1189*7c478bd9Sstevel@tonic-gate exit(EX_OSERR); 1190*7c478bd9Sstevel@tonic-gate } 1191*7c478bd9Sstevel@tonic-gate strcpy(new_module->name, so_path); 1192*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1193*7c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 1194*7c478bd9Sstevel@tonic-gate printf("[process_modules] base=%#llx, end=%#llx\n", 1195*7c478bd9Sstevel@tonic-gate new_module->load_base, new_module->load_end); 1196*7c478bd9Sstevel@tonic-gate } 1197*7c478bd9Sstevel@tonic-gate #endif DEBUG 1198*7c478bd9Sstevel@tonic-gate 1199*7c478bd9Sstevel@tonic-gate /* Create this module's nameslist */ 1200*7c478bd9Sstevel@tonic-gate process_namelist(new_module); 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate /* Add it to the tail of active module list */ 1203*7c478bd9Sstevel@tonic-gate last->next = new_module; 1204*7c478bd9Sstevel@tonic-gate n_modules++; 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1207*7c478bd9Sstevel@tonic-gate if (debug & MODULEDEBUG) { 1208*7c478bd9Sstevel@tonic-gate printf("[process_modules] total shared objects = %ld\n", 1209*7c478bd9Sstevel@tonic-gate n_modules - 1); 1210*7c478bd9Sstevel@tonic-gate } 1211*7c478bd9Sstevel@tonic-gate #endif DEBUG 1212*7c478bd9Sstevel@tonic-gate /* 1213*7c478bd9Sstevel@tonic-gate * Move to the next module in the PROF_MODULES_T list 1214*7c478bd9Sstevel@tonic-gate * (if present) 1215*7c478bd9Sstevel@tonic-gate */ 1216*7c478bd9Sstevel@tonic-gate if (!newmodp->next) 1217*7c478bd9Sstevel@tonic-gate more_modules = FALSE; 1218*7c478bd9Sstevel@tonic-gate 1219*7c478bd9Sstevel@tonic-gate newmodp = (ProfModule *) ((caddr_t) modlp + newmodp->next); 1220*7c478bd9Sstevel@tonic-gate 1221*7c478bd9Sstevel@tonic-gate } while (more_modules); 1222*7c478bd9Sstevel@tonic-gate } 1223*7c478bd9Sstevel@tonic-gate 1224*7c478bd9Sstevel@tonic-gate static void 1225*7c478bd9Sstevel@tonic-gate reset_active_modules() 1226*7c478bd9Sstevel@tonic-gate { 1227*7c478bd9Sstevel@tonic-gate mod_info_t *mi; 1228*7c478bd9Sstevel@tonic-gate 1229*7c478bd9Sstevel@tonic-gate /* Except the executable, no other module should remain active */ 1230*7c478bd9Sstevel@tonic-gate for (mi = modules.next; mi; mi = mi->next) 1231*7c478bd9Sstevel@tonic-gate mi->active = FALSE; 1232*7c478bd9Sstevel@tonic-gate } 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate static void 1235*7c478bd9Sstevel@tonic-gate getpfiledata(memp, fsz) 1236*7c478bd9Sstevel@tonic-gate caddr_t memp; 1237*7c478bd9Sstevel@tonic-gate size_t fsz; 1238*7c478bd9Sstevel@tonic-gate { 1239*7c478bd9Sstevel@tonic-gate ProfObject *objp; 1240*7c478bd9Sstevel@tonic-gate caddr_t file_end; 1241*7c478bd9Sstevel@tonic-gate bool found_pcsamples = FALSE, found_cgraph = FALSE; 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate /* 1244*7c478bd9Sstevel@tonic-gate * Before processing a new gmon.out, all modules except the 1245*7c478bd9Sstevel@tonic-gate * program executable must be made inactive, so that symbols 1246*7c478bd9Sstevel@tonic-gate * are searched only in the program executable, if we don't 1247*7c478bd9Sstevel@tonic-gate * find a MODULES_T object. Don't do it *after* we read a gmon.out, 1248*7c478bd9Sstevel@tonic-gate * because we need the active module data after we're done with 1249*7c478bd9Sstevel@tonic-gate * the last gmon.out, if we're doing summing. 1250*7c478bd9Sstevel@tonic-gate */ 1251*7c478bd9Sstevel@tonic-gate reset_active_modules(); 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate file_end = memp + fsz; 1254*7c478bd9Sstevel@tonic-gate objp = (ProfObject *) (memp + ((ProfHeader *) memp)->size); 1255*7c478bd9Sstevel@tonic-gate while ((caddr_t) objp < file_end) { 1256*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1257*7c478bd9Sstevel@tonic-gate { 1258*7c478bd9Sstevel@tonic-gate unsigned int type = 0; 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate if (debug & MONOUTDEBUG) { 1261*7c478bd9Sstevel@tonic-gate if (objp->type <= MAX_OBJTYPES) 1262*7c478bd9Sstevel@tonic-gate type = objp->type; 1263*7c478bd9Sstevel@tonic-gate 1264*7c478bd9Sstevel@tonic-gate printf("\n[getpfiledata] object %s [%#lx]\n", 1265*7c478bd9Sstevel@tonic-gate objname[type], objp->type); 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate } 1268*7c478bd9Sstevel@tonic-gate #endif DEBUG 1269*7c478bd9Sstevel@tonic-gate switch (objp->type) { 1270*7c478bd9Sstevel@tonic-gate case PROF_MODULES_T : 1271*7c478bd9Sstevel@tonic-gate process_modules((ProfModuleList *) objp); 1272*7c478bd9Sstevel@tonic-gate break; 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate case PROF_CALLGRAPH_T : 1275*7c478bd9Sstevel@tonic-gate process_cgraph((ProfCallGraph *) objp); 1276*7c478bd9Sstevel@tonic-gate found_cgraph = TRUE; 1277*7c478bd9Sstevel@tonic-gate break; 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate case PROF_BUFFER_T : 1280*7c478bd9Sstevel@tonic-gate process_pcsamples((ProfBuffer *) objp); 1281*7c478bd9Sstevel@tonic-gate found_pcsamples = TRUE; 1282*7c478bd9Sstevel@tonic-gate break; 1283*7c478bd9Sstevel@tonic-gate 1284*7c478bd9Sstevel@tonic-gate default : 1285*7c478bd9Sstevel@tonic-gate fprintf(stderr, 1286*7c478bd9Sstevel@tonic-gate "%s: unknown prof object type=%d\n", 1287*7c478bd9Sstevel@tonic-gate whoami, objp->type); 1288*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1289*7c478bd9Sstevel@tonic-gate } 1290*7c478bd9Sstevel@tonic-gate objp = (ProfObject *) ((caddr_t) objp + objp->size); 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate if (!found_cgraph || !found_pcsamples) { 1294*7c478bd9Sstevel@tonic-gate fprintf(stderr, 1295*7c478bd9Sstevel@tonic-gate "%s: missing callgraph/pcsamples object\n", whoami); 1296*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1297*7c478bd9Sstevel@tonic-gate } 1298*7c478bd9Sstevel@tonic-gate 1299*7c478bd9Sstevel@tonic-gate if ((caddr_t) objp > file_end) { 1300*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: malformed profile file.\n", whoami); 1301*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1302*7c478bd9Sstevel@tonic-gate } 1303*7c478bd9Sstevel@tonic-gate 1304*7c478bd9Sstevel@tonic-gate if (first_file) 1305*7c478bd9Sstevel@tonic-gate first_file = FALSE; 1306*7c478bd9Sstevel@tonic-gate } 1307*7c478bd9Sstevel@tonic-gate 1308*7c478bd9Sstevel@tonic-gate static void 1309*7c478bd9Sstevel@tonic-gate readarcs(pfile) 1310*7c478bd9Sstevel@tonic-gate FILE *pfile; 1311*7c478bd9Sstevel@tonic-gate { 1312*7c478bd9Sstevel@tonic-gate /* 1313*7c478bd9Sstevel@tonic-gate * the rest of the file consists of 1314*7c478bd9Sstevel@tonic-gate * a bunch of <from,self,count> tuples. 1315*7c478bd9Sstevel@tonic-gate */ 1316*7c478bd9Sstevel@tonic-gate /* CONSTCOND */ 1317*7c478bd9Sstevel@tonic-gate while (1) { 1318*7c478bd9Sstevel@tonic-gate struct rawarc arc; 1319*7c478bd9Sstevel@tonic-gate 1320*7c478bd9Sstevel@tonic-gate if (rflag) { 1321*7c478bd9Sstevel@tonic-gate if (Bflag) { 1322*7c478bd9Sstevel@tonic-gate L_cgarc64 rtld_arc64; 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate /* 1325*7c478bd9Sstevel@tonic-gate * If rflag is set then this is an profiled 1326*7c478bd9Sstevel@tonic-gate * image generated by rtld. It needs to be 1327*7c478bd9Sstevel@tonic-gate * 'converted' to the standard data format. 1328*7c478bd9Sstevel@tonic-gate */ 1329*7c478bd9Sstevel@tonic-gate if (fread(&rtld_arc64, 1330*7c478bd9Sstevel@tonic-gate sizeof (L_cgarc64), 1, pfile) != 1) 1331*7c478bd9Sstevel@tonic-gate break; 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate if (rtld_arc64.cg_from == PRF_OUTADDR64) 1334*7c478bd9Sstevel@tonic-gate arc.raw_frompc = s_highpc + 0x10; 1335*7c478bd9Sstevel@tonic-gate else 1336*7c478bd9Sstevel@tonic-gate arc.raw_frompc = 1337*7c478bd9Sstevel@tonic-gate (pctype)rtld_arc64.cg_from; 1338*7c478bd9Sstevel@tonic-gate arc.raw_selfpc = (pctype)rtld_arc64.cg_to; 1339*7c478bd9Sstevel@tonic-gate arc.raw_count = (actype)rtld_arc64.cg_count; 1340*7c478bd9Sstevel@tonic-gate } else { 1341*7c478bd9Sstevel@tonic-gate L_cgarc rtld_arc; 1342*7c478bd9Sstevel@tonic-gate 1343*7c478bd9Sstevel@tonic-gate /* 1344*7c478bd9Sstevel@tonic-gate * If rflag is set then this is an profiled 1345*7c478bd9Sstevel@tonic-gate * image generated by rtld. It needs to be 1346*7c478bd9Sstevel@tonic-gate * 'converted' to the standard data format. 1347*7c478bd9Sstevel@tonic-gate */ 1348*7c478bd9Sstevel@tonic-gate if (fread(&rtld_arc, 1349*7c478bd9Sstevel@tonic-gate sizeof (L_cgarc), 1, pfile) != 1) 1350*7c478bd9Sstevel@tonic-gate break; 1351*7c478bd9Sstevel@tonic-gate 1352*7c478bd9Sstevel@tonic-gate if (rtld_arc.cg_from == PRF_OUTADDR) 1353*7c478bd9Sstevel@tonic-gate arc.raw_frompc = s_highpc + 0x10; 1354*7c478bd9Sstevel@tonic-gate else 1355*7c478bd9Sstevel@tonic-gate arc.raw_frompc = (pctype) 1356*7c478bd9Sstevel@tonic-gate (uintptr_t)rtld_arc.cg_from; 1357*7c478bd9Sstevel@tonic-gate arc.raw_selfpc = (pctype) 1358*7c478bd9Sstevel@tonic-gate (uintptr_t)rtld_arc.cg_to; 1359*7c478bd9Sstevel@tonic-gate arc.raw_count = (actype)rtld_arc.cg_count; 1360*7c478bd9Sstevel@tonic-gate } 1361*7c478bd9Sstevel@tonic-gate } else { 1362*7c478bd9Sstevel@tonic-gate if (Bflag) { 1363*7c478bd9Sstevel@tonic-gate if (fread(&arc, sizeof (struct rawarc), 1, 1364*7c478bd9Sstevel@tonic-gate pfile) != 1) { 1365*7c478bd9Sstevel@tonic-gate break; 1366*7c478bd9Sstevel@tonic-gate } 1367*7c478bd9Sstevel@tonic-gate } else { 1368*7c478bd9Sstevel@tonic-gate /* 1369*7c478bd9Sstevel@tonic-gate * If these aren't big %pc's, we need to read 1370*7c478bd9Sstevel@tonic-gate * into the 32-bit raw arc structure, and 1371*7c478bd9Sstevel@tonic-gate * assign the members into the actual arc. 1372*7c478bd9Sstevel@tonic-gate */ 1373*7c478bd9Sstevel@tonic-gate struct rawarc32 arc32; 1374*7c478bd9Sstevel@tonic-gate if (fread(&arc32, sizeof (struct rawarc32), 1375*7c478bd9Sstevel@tonic-gate 1, pfile) != 1) 1376*7c478bd9Sstevel@tonic-gate break; 1377*7c478bd9Sstevel@tonic-gate arc.raw_frompc = (pctype)arc32.raw_frompc; 1378*7c478bd9Sstevel@tonic-gate arc.raw_selfpc = (pctype)arc32.raw_selfpc; 1379*7c478bd9Sstevel@tonic-gate arc.raw_count = (actype)arc32.raw_count; 1380*7c478bd9Sstevel@tonic-gate } 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1384*7c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 1385*7c478bd9Sstevel@tonic-gate printf("[getpfile] frompc 0x%llx selfpc " 1386*7c478bd9Sstevel@tonic-gate "0x%llx count %lld\n", arc.raw_frompc, 1387*7c478bd9Sstevel@tonic-gate arc.raw_selfpc, arc.raw_count); 1388*7c478bd9Sstevel@tonic-gate } 1389*7c478bd9Sstevel@tonic-gate #endif DEBUG 1390*7c478bd9Sstevel@tonic-gate /* 1391*7c478bd9Sstevel@tonic-gate * add this arc 1392*7c478bd9Sstevel@tonic-gate */ 1393*7c478bd9Sstevel@tonic-gate tally(&modules, &modules, &arc); 1394*7c478bd9Sstevel@tonic-gate } 1395*7c478bd9Sstevel@tonic-gate if (first_file) 1396*7c478bd9Sstevel@tonic-gate first_file = FALSE; 1397*7c478bd9Sstevel@tonic-gate } 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate static void 1400*7c478bd9Sstevel@tonic-gate readsamples(FILE *pfile) 1401*7c478bd9Sstevel@tonic-gate { 1402*7c478bd9Sstevel@tonic-gate sztype i; 1403*7c478bd9Sstevel@tonic-gate unsigned_UNIT sample; 1404*7c478bd9Sstevel@tonic-gate 1405*7c478bd9Sstevel@tonic-gate if (samples == 0) { 1406*7c478bd9Sstevel@tonic-gate samples = (unsigned_UNIT *) calloc(nsamples, 1407*7c478bd9Sstevel@tonic-gate sizeof (unsigned_UNIT)); 1408*7c478bd9Sstevel@tonic-gate if (samples == 0) { 1409*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: No room for %ld sample pc's\n", 1410*7c478bd9Sstevel@tonic-gate whoami, sampbytes / sizeof (unsigned_UNIT)); 1411*7c478bd9Sstevel@tonic-gate exit(EX_OSERR); 1412*7c478bd9Sstevel@tonic-gate } 1413*7c478bd9Sstevel@tonic-gate } 1414*7c478bd9Sstevel@tonic-gate 1415*7c478bd9Sstevel@tonic-gate for (i = 0; i < nsamples; i++) { 1416*7c478bd9Sstevel@tonic-gate fread(&sample, sizeof (unsigned_UNIT), 1, pfile); 1417*7c478bd9Sstevel@tonic-gate if (feof(pfile)) 1418*7c478bd9Sstevel@tonic-gate break; 1419*7c478bd9Sstevel@tonic-gate samples[i] += sample; 1420*7c478bd9Sstevel@tonic-gate } 1421*7c478bd9Sstevel@tonic-gate if (i != nsamples) { 1422*7c478bd9Sstevel@tonic-gate fprintf(stderr, 1423*7c478bd9Sstevel@tonic-gate "%s: unexpected EOF after reading %ld/%ld samples\n", 1424*7c478bd9Sstevel@tonic-gate whoami, --i, nsamples); 1425*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1426*7c478bd9Sstevel@tonic-gate } 1427*7c478bd9Sstevel@tonic-gate } 1428*7c478bd9Sstevel@tonic-gate 1429*7c478bd9Sstevel@tonic-gate static void * 1430*7c478bd9Sstevel@tonic-gate handle_versioned(FILE *pfile, char *filename, size_t *fsz) 1431*7c478bd9Sstevel@tonic-gate { 1432*7c478bd9Sstevel@tonic-gate int fd; 1433*7c478bd9Sstevel@tonic-gate bool invalid_version; 1434*7c478bd9Sstevel@tonic-gate caddr_t fmem; 1435*7c478bd9Sstevel@tonic-gate struct stat buf; 1436*7c478bd9Sstevel@tonic-gate ProfHeader prof_hdr; 1437*7c478bd9Sstevel@tonic-gate 1438*7c478bd9Sstevel@tonic-gate /* 1439*7c478bd9Sstevel@tonic-gate * Check versioning info. For now, let's say we provide 1440*7c478bd9Sstevel@tonic-gate * backward compatibility, so we accept all older versions. 1441*7c478bd9Sstevel@tonic-gate */ 1442*7c478bd9Sstevel@tonic-gate if (fread(&prof_hdr, sizeof (ProfHeader), 1, pfile) == 0) { 1443*7c478bd9Sstevel@tonic-gate perror("fread()"); 1444*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1445*7c478bd9Sstevel@tonic-gate } 1446*7c478bd9Sstevel@tonic-gate 1447*7c478bd9Sstevel@tonic-gate invalid_version = FALSE; 1448*7c478bd9Sstevel@tonic-gate if (prof_hdr.h_major_ver > PROF_MAJOR_VERSION) 1449*7c478bd9Sstevel@tonic-gate invalid_version = TRUE; 1450*7c478bd9Sstevel@tonic-gate else if (prof_hdr.h_major_ver == PROF_MAJOR_VERSION) { 1451*7c478bd9Sstevel@tonic-gate if (prof_hdr.h_minor_ver > PROF_MINOR_VERSION) 1452*7c478bd9Sstevel@tonic-gate invalid_version = FALSE; 1453*7c478bd9Sstevel@tonic-gate } 1454*7c478bd9Sstevel@tonic-gate 1455*7c478bd9Sstevel@tonic-gate if (invalid_version) { 1456*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: version %d.%d not supported\n", 1457*7c478bd9Sstevel@tonic-gate whoami, prof_hdr.h_major_ver, prof_hdr.h_minor_ver); 1458*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1459*7c478bd9Sstevel@tonic-gate } 1460*7c478bd9Sstevel@tonic-gate 1461*7c478bd9Sstevel@tonic-gate /* 1462*7c478bd9Sstevel@tonic-gate * Map gmon.out onto memory. 1463*7c478bd9Sstevel@tonic-gate */ 1464*7c478bd9Sstevel@tonic-gate fclose(pfile); 1465*7c478bd9Sstevel@tonic-gate if ((fd = open(filename, O_RDONLY)) == -1) { 1466*7c478bd9Sstevel@tonic-gate perror(filename); 1467*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1468*7c478bd9Sstevel@tonic-gate } 1469*7c478bd9Sstevel@tonic-gate 1470*7c478bd9Sstevel@tonic-gate if ((*fsz = lseek(fd, 0, SEEK_END)) == -1) { 1471*7c478bd9Sstevel@tonic-gate perror(filename); 1472*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1473*7c478bd9Sstevel@tonic-gate } 1474*7c478bd9Sstevel@tonic-gate 1475*7c478bd9Sstevel@tonic-gate fmem = mmap(0, *fsz, PROT_READ, MAP_PRIVATE, fd, 0); 1476*7c478bd9Sstevel@tonic-gate if (fmem == MAP_FAILED) { 1477*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: can't map %s\n", whoami, filename); 1478*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate /* 1482*7c478bd9Sstevel@tonic-gate * Before we close this fd, save this gmon.out's info to later verify 1483*7c478bd9Sstevel@tonic-gate * if the shared objects it references have changed since the time 1484*7c478bd9Sstevel@tonic-gate * they were used to generate this gmon.out 1485*7c478bd9Sstevel@tonic-gate */ 1486*7c478bd9Sstevel@tonic-gate if (fstat(fd, &buf) == -1) { 1487*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: can't get info on `%s'\n", 1488*7c478bd9Sstevel@tonic-gate whoami, filename); 1489*7c478bd9Sstevel@tonic-gate exit(EX_NOINPUT); 1490*7c478bd9Sstevel@tonic-gate } 1491*7c478bd9Sstevel@tonic-gate gmonout_info.dev = buf.st_dev; 1492*7c478bd9Sstevel@tonic-gate gmonout_info.ino = buf.st_ino; 1493*7c478bd9Sstevel@tonic-gate gmonout_info.mtime = buf.st_mtime; 1494*7c478bd9Sstevel@tonic-gate gmonout_info.size = buf.st_size; 1495*7c478bd9Sstevel@tonic-gate 1496*7c478bd9Sstevel@tonic-gate close(fd); 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate return ((void *) fmem); 1499*7c478bd9Sstevel@tonic-gate } 1500*7c478bd9Sstevel@tonic-gate 1501*7c478bd9Sstevel@tonic-gate static void * 1502*7c478bd9Sstevel@tonic-gate openpfile(filename, fsz) 1503*7c478bd9Sstevel@tonic-gate char *filename; 1504*7c478bd9Sstevel@tonic-gate size_t *fsz; 1505*7c478bd9Sstevel@tonic-gate { 1506*7c478bd9Sstevel@tonic-gate struct hdr tmp; 1507*7c478bd9Sstevel@tonic-gate FILE * pfile; 1508*7c478bd9Sstevel@tonic-gate unsigned long magic_num; 1509*7c478bd9Sstevel@tonic-gate size_t hdrsize = sizeof (struct hdr); 1510*7c478bd9Sstevel@tonic-gate static bool first_time = TRUE; 1511*7c478bd9Sstevel@tonic-gate extern bool old_style; 1512*7c478bd9Sstevel@tonic-gate 1513*7c478bd9Sstevel@tonic-gate if ((pfile = fopen(filename, "r")) == NULL) { 1514*7c478bd9Sstevel@tonic-gate perror(filename); 1515*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1516*7c478bd9Sstevel@tonic-gate } 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate /* 1519*7c478bd9Sstevel@tonic-gate * Read in the magic. Note that we changed the cast "unsigned long" 1520*7c478bd9Sstevel@tonic-gate * to "unsigned int" because that's how h_magic is defined in the 1521*7c478bd9Sstevel@tonic-gate * new format ProfHeader. 1522*7c478bd9Sstevel@tonic-gate */ 1523*7c478bd9Sstevel@tonic-gate if (fread(&magic_num, sizeof (unsigned int), 1, pfile) == 0) { 1524*7c478bd9Sstevel@tonic-gate perror("fread()"); 1525*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1526*7c478bd9Sstevel@tonic-gate } 1527*7c478bd9Sstevel@tonic-gate 1528*7c478bd9Sstevel@tonic-gate rewind(pfile); 1529*7c478bd9Sstevel@tonic-gate 1530*7c478bd9Sstevel@tonic-gate /* 1531*7c478bd9Sstevel@tonic-gate * First check if this is versioned or *old-style* gmon.out 1532*7c478bd9Sstevel@tonic-gate */ 1533*7c478bd9Sstevel@tonic-gate if (magic_num == (unsigned int)PROF_MAGIC) { 1534*7c478bd9Sstevel@tonic-gate if ((!first_time) && (old_style == TRUE)) { 1535*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: can't mix old & new format " 1536*7c478bd9Sstevel@tonic-gate "profiled files\n", whoami); 1537*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1538*7c478bd9Sstevel@tonic-gate } 1539*7c478bd9Sstevel@tonic-gate first_time = FALSE; 1540*7c478bd9Sstevel@tonic-gate old_style = FALSE; 1541*7c478bd9Sstevel@tonic-gate return (handle_versioned(pfile, filename, fsz)); 1542*7c478bd9Sstevel@tonic-gate } 1543*7c478bd9Sstevel@tonic-gate 1544*7c478bd9Sstevel@tonic-gate if ((!first_time) && (old_style == FALSE)) { 1545*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: can't mix old & new format " 1546*7c478bd9Sstevel@tonic-gate "profiled files\n", whoami); 1547*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1548*7c478bd9Sstevel@tonic-gate } 1549*7c478bd9Sstevel@tonic-gate 1550*7c478bd9Sstevel@tonic-gate first_time = FALSE; 1551*7c478bd9Sstevel@tonic-gate old_style = TRUE; 1552*7c478bd9Sstevel@tonic-gate fsz = 0; 1553*7c478bd9Sstevel@tonic-gate 1554*7c478bd9Sstevel@tonic-gate /* 1555*7c478bd9Sstevel@tonic-gate * Now, we need to determine if this is a run-time linker 1556*7c478bd9Sstevel@tonic-gate * profiled file or if it is a standard gmon.out. 1557*7c478bd9Sstevel@tonic-gate * 1558*7c478bd9Sstevel@tonic-gate * We do this by checking if magic matches PRF_MAGIC. If it 1559*7c478bd9Sstevel@tonic-gate * does, then this is a run-time linker profiled file, if it 1560*7c478bd9Sstevel@tonic-gate * doesn't, it must be a gmon.out file. 1561*7c478bd9Sstevel@tonic-gate */ 1562*7c478bd9Sstevel@tonic-gate if (magic_num == (unsigned long)PRF_MAGIC) 1563*7c478bd9Sstevel@tonic-gate rflag = TRUE; 1564*7c478bd9Sstevel@tonic-gate else 1565*7c478bd9Sstevel@tonic-gate rflag = FALSE; 1566*7c478bd9Sstevel@tonic-gate 1567*7c478bd9Sstevel@tonic-gate if (rflag) { 1568*7c478bd9Sstevel@tonic-gate if (Bflag) { 1569*7c478bd9Sstevel@tonic-gate L_hdr64 l_hdr64; 1570*7c478bd9Sstevel@tonic-gate 1571*7c478bd9Sstevel@tonic-gate /* 1572*7c478bd9Sstevel@tonic-gate * If the rflag is set then the input file is 1573*7c478bd9Sstevel@tonic-gate * rtld profiled data, we'll read it in and convert 1574*7c478bd9Sstevel@tonic-gate * it to the standard format (ie: make it look like 1575*7c478bd9Sstevel@tonic-gate * a gmon.out file). 1576*7c478bd9Sstevel@tonic-gate */ 1577*7c478bd9Sstevel@tonic-gate if (fread(&l_hdr64, sizeof (L_hdr64), 1, pfile) == 0) { 1578*7c478bd9Sstevel@tonic-gate perror("fread()"); 1579*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1580*7c478bd9Sstevel@tonic-gate } 1581*7c478bd9Sstevel@tonic-gate if (l_hdr64.hd_version != PRF_VERSION_64) { 1582*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: expected version %d, " 1583*7c478bd9Sstevel@tonic-gate "got version %d when processing 64-bit " 1584*7c478bd9Sstevel@tonic-gate "run-time linker profiled file.\n", 1585*7c478bd9Sstevel@tonic-gate whoami, PRF_VERSION_64, l_hdr64.hd_version); 1586*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1587*7c478bd9Sstevel@tonic-gate } 1588*7c478bd9Sstevel@tonic-gate tmp.lowpc = 0; 1589*7c478bd9Sstevel@tonic-gate tmp.highpc = (pctype)l_hdr64.hd_hpc; 1590*7c478bd9Sstevel@tonic-gate tmp.ncnt = sizeof (M_hdr64) + l_hdr64.hd_psize; 1591*7c478bd9Sstevel@tonic-gate } else { 1592*7c478bd9Sstevel@tonic-gate L_hdr l_hdr; 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate /* 1595*7c478bd9Sstevel@tonic-gate * If the rflag is set then the input file is 1596*7c478bd9Sstevel@tonic-gate * rtld profiled data, we'll read it in and convert 1597*7c478bd9Sstevel@tonic-gate * it to the standard format (ie: make it look like 1598*7c478bd9Sstevel@tonic-gate * a gmon.out file). 1599*7c478bd9Sstevel@tonic-gate */ 1600*7c478bd9Sstevel@tonic-gate if (fread(&l_hdr, sizeof (L_hdr), 1, pfile) == 0) { 1601*7c478bd9Sstevel@tonic-gate perror("fread()"); 1602*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1603*7c478bd9Sstevel@tonic-gate } 1604*7c478bd9Sstevel@tonic-gate if (l_hdr.hd_version != PRF_VERSION) { 1605*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: expected version %d, " 1606*7c478bd9Sstevel@tonic-gate "got version %d when processing " 1607*7c478bd9Sstevel@tonic-gate "run-time linker profiled file.\n", 1608*7c478bd9Sstevel@tonic-gate whoami, PRF_VERSION, l_hdr.hd_version); 1609*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1610*7c478bd9Sstevel@tonic-gate } 1611*7c478bd9Sstevel@tonic-gate tmp.lowpc = 0; 1612*7c478bd9Sstevel@tonic-gate tmp.highpc = (pctype)(uintptr_t)l_hdr.hd_hpc; 1613*7c478bd9Sstevel@tonic-gate tmp.ncnt = sizeof (M_hdr) + l_hdr.hd_psize; 1614*7c478bd9Sstevel@tonic-gate hdrsize = sizeof (M_hdr); 1615*7c478bd9Sstevel@tonic-gate } 1616*7c478bd9Sstevel@tonic-gate } else { 1617*7c478bd9Sstevel@tonic-gate if (Bflag) { 1618*7c478bd9Sstevel@tonic-gate if (fread(&tmp, sizeof (struct hdr), 1, pfile) == 0) { 1619*7c478bd9Sstevel@tonic-gate perror("fread()"); 1620*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1621*7c478bd9Sstevel@tonic-gate } 1622*7c478bd9Sstevel@tonic-gate } else { 1623*7c478bd9Sstevel@tonic-gate /* 1624*7c478bd9Sstevel@tonic-gate * If we're not reading big %pc's, we need to read 1625*7c478bd9Sstevel@tonic-gate * the 32-bit header, and assign the members to 1626*7c478bd9Sstevel@tonic-gate * the actual header. 1627*7c478bd9Sstevel@tonic-gate */ 1628*7c478bd9Sstevel@tonic-gate struct hdr32 hdr32; 1629*7c478bd9Sstevel@tonic-gate if (fread(&hdr32, sizeof (hdr32), 1, pfile) == 0) { 1630*7c478bd9Sstevel@tonic-gate perror("fread()"); 1631*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1632*7c478bd9Sstevel@tonic-gate } 1633*7c478bd9Sstevel@tonic-gate tmp.lowpc = hdr32.lowpc; 1634*7c478bd9Sstevel@tonic-gate tmp.highpc = hdr32.highpc; 1635*7c478bd9Sstevel@tonic-gate tmp.ncnt = hdr32.ncnt; 1636*7c478bd9Sstevel@tonic-gate hdrsize = sizeof (struct hdr32); 1637*7c478bd9Sstevel@tonic-gate } 1638*7c478bd9Sstevel@tonic-gate } 1639*7c478bd9Sstevel@tonic-gate 1640*7c478bd9Sstevel@tonic-gate /* 1641*7c478bd9Sstevel@tonic-gate * perform sanity check on profiled file we've opened. 1642*7c478bd9Sstevel@tonic-gate */ 1643*7c478bd9Sstevel@tonic-gate if (tmp.lowpc >= tmp.highpc) { 1644*7c478bd9Sstevel@tonic-gate if (rflag) 1645*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: badly formed profiled data.\n", 1646*7c478bd9Sstevel@tonic-gate filename); 1647*7c478bd9Sstevel@tonic-gate else 1648*7c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: badly formed gmon.out file.\n", 1649*7c478bd9Sstevel@tonic-gate filename); 1650*7c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE); 1651*7c478bd9Sstevel@tonic-gate } 1652*7c478bd9Sstevel@tonic-gate 1653*7c478bd9Sstevel@tonic-gate if (s_highpc != 0 && (tmp.lowpc != h.lowpc || 1654*7c478bd9Sstevel@tonic-gate tmp.highpc != h.highpc || tmp.ncnt != h.ncnt)) { 1655*7c478bd9Sstevel@tonic-gate fprintf(stderr, 1656*7c478bd9Sstevel@tonic-gate "%s: incompatible with first gmon file\n", 1657*7c478bd9Sstevel@tonic-gate filename); 1658*7c478bd9Sstevel@tonic-gate exit(EX_IOERR); 1659*7c478bd9Sstevel@tonic-gate } 1660*7c478bd9Sstevel@tonic-gate h = tmp; 1661*7c478bd9Sstevel@tonic-gate s_lowpc = h.lowpc; 1662*7c478bd9Sstevel@tonic-gate s_highpc = h.highpc; 1663*7c478bd9Sstevel@tonic-gate lowpc = h.lowpc / sizeof (UNIT); 1664*7c478bd9Sstevel@tonic-gate highpc = h.highpc / sizeof (UNIT); 1665*7c478bd9Sstevel@tonic-gate sampbytes = h.ncnt > hdrsize ? h.ncnt - hdrsize : 0; 1666*7c478bd9Sstevel@tonic-gate nsamples = sampbytes / sizeof (unsigned_UNIT); 1667*7c478bd9Sstevel@tonic-gate 1668*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1669*7c478bd9Sstevel@tonic-gate if (debug & SAMPLEDEBUG) { 1670*7c478bd9Sstevel@tonic-gate printf("[openpfile] hdr.lowpc 0x%llx hdr.highpc " 1671*7c478bd9Sstevel@tonic-gate "0x%llx hdr.ncnt %lld\n", 1672*7c478bd9Sstevel@tonic-gate h.lowpc, h.highpc, h.ncnt); 1673*7c478bd9Sstevel@tonic-gate printf("[openpfile] s_lowpc 0x%llx s_highpc 0x%llx\n", 1674*7c478bd9Sstevel@tonic-gate s_lowpc, s_highpc); 1675*7c478bd9Sstevel@tonic-gate printf("[openpfile] lowpc 0x%llx highpc 0x%llx\n", 1676*7c478bd9Sstevel@tonic-gate lowpc, highpc); 1677*7c478bd9Sstevel@tonic-gate printf("[openpfile] sampbytes %d nsamples %d\n", 1678*7c478bd9Sstevel@tonic-gate sampbytes, nsamples); 1679*7c478bd9Sstevel@tonic-gate } 1680*7c478bd9Sstevel@tonic-gate #endif DEBUG 1681*7c478bd9Sstevel@tonic-gate 1682*7c478bd9Sstevel@tonic-gate return ((void *) pfile); 1683*7c478bd9Sstevel@tonic-gate } 1684*7c478bd9Sstevel@tonic-gate 1685*7c478bd9Sstevel@tonic-gate /* 1686*7c478bd9Sstevel@tonic-gate * Information from a gmon.out file depends on whether it's versioned 1687*7c478bd9Sstevel@tonic-gate * or non-versioned, *old style* gmon.out. If old-style, it is in two 1688*7c478bd9Sstevel@tonic-gate * parts : an array of sampling hits within pc ranges, and the arcs. If 1689*7c478bd9Sstevel@tonic-gate * versioned, it contains a header, followed by any number of 1690*7c478bd9Sstevel@tonic-gate * modules/callgraph/pcsample_buffer objects. 1691*7c478bd9Sstevel@tonic-gate */ 1692*7c478bd9Sstevel@tonic-gate static void 1693*7c478bd9Sstevel@tonic-gate getpfile(char *filename) 1694*7c478bd9Sstevel@tonic-gate { 1695*7c478bd9Sstevel@tonic-gate void *handle; 1696*7c478bd9Sstevel@tonic-gate size_t fsz; 1697*7c478bd9Sstevel@tonic-gate 1698*7c478bd9Sstevel@tonic-gate handle = openpfile(filename, &fsz); 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate if (old_style) { 1701*7c478bd9Sstevel@tonic-gate readsamples((FILE *) handle); 1702*7c478bd9Sstevel@tonic-gate readarcs((FILE *) handle); 1703*7c478bd9Sstevel@tonic-gate fclose((FILE *) handle); 1704*7c478bd9Sstevel@tonic-gate return; 1705*7c478bd9Sstevel@tonic-gate } 1706*7c478bd9Sstevel@tonic-gate 1707*7c478bd9Sstevel@tonic-gate getpfiledata((caddr_t) handle, fsz); 1708*7c478bd9Sstevel@tonic-gate munmap(handle, fsz); 1709*7c478bd9Sstevel@tonic-gate } 1710*7c478bd9Sstevel@tonic-gate 1711*7c478bd9Sstevel@tonic-gate main(int argc, char ** argv) 1712*7c478bd9Sstevel@tonic-gate { 1713*7c478bd9Sstevel@tonic-gate char **sp; 1714*7c478bd9Sstevel@tonic-gate nltype **timesortnlp; 1715*7c478bd9Sstevel@tonic-gate int c; 1716*7c478bd9Sstevel@tonic-gate int errflg; 1717*7c478bd9Sstevel@tonic-gate extern char *optarg; 1718*7c478bd9Sstevel@tonic-gate extern int optind; 1719*7c478bd9Sstevel@tonic-gate 1720*7c478bd9Sstevel@tonic-gate prog_name = *argv; /* preserve program name */ 1721*7c478bd9Sstevel@tonic-gate debug = 0; 1722*7c478bd9Sstevel@tonic-gate nflag = FALSE; 1723*7c478bd9Sstevel@tonic-gate bflag = TRUE; 1724*7c478bd9Sstevel@tonic-gate lflag = FALSE; 1725*7c478bd9Sstevel@tonic-gate Cflag = FALSE; 1726*7c478bd9Sstevel@tonic-gate first_file = TRUE; 1727*7c478bd9Sstevel@tonic-gate rflag = FALSE; 1728*7c478bd9Sstevel@tonic-gate Bflag = FALSE; 1729*7c478bd9Sstevel@tonic-gate errflg = FALSE; 1730*7c478bd9Sstevel@tonic-gate 1731*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "abd:CcDE:e:F:f:ln:sz")) != EOF) 1732*7c478bd9Sstevel@tonic-gate switch (c) { 1733*7c478bd9Sstevel@tonic-gate case 'a': 1734*7c478bd9Sstevel@tonic-gate aflag = TRUE; 1735*7c478bd9Sstevel@tonic-gate break; 1736*7c478bd9Sstevel@tonic-gate case 'b': 1737*7c478bd9Sstevel@tonic-gate bflag = FALSE; 1738*7c478bd9Sstevel@tonic-gate break; 1739*7c478bd9Sstevel@tonic-gate case 'c': 1740*7c478bd9Sstevel@tonic-gate cflag = TRUE; 1741*7c478bd9Sstevel@tonic-gate break; 1742*7c478bd9Sstevel@tonic-gate case 'C': 1743*7c478bd9Sstevel@tonic-gate Cflag = TRUE; 1744*7c478bd9Sstevel@tonic-gate break; 1745*7c478bd9Sstevel@tonic-gate case 'd': 1746*7c478bd9Sstevel@tonic-gate dflag = TRUE; 1747*7c478bd9Sstevel@tonic-gate debug |= atoi(optarg); 1748*7c478bd9Sstevel@tonic-gate printf("[main] debug = 0x%x\n", debug); 1749*7c478bd9Sstevel@tonic-gate break; 1750*7c478bd9Sstevel@tonic-gate case 'D': 1751*7c478bd9Sstevel@tonic-gate Dflag = TRUE; 1752*7c478bd9Sstevel@tonic-gate break; 1753*7c478bd9Sstevel@tonic-gate case 'E': 1754*7c478bd9Sstevel@tonic-gate addlist(Elist, optarg); 1755*7c478bd9Sstevel@tonic-gate Eflag = TRUE; 1756*7c478bd9Sstevel@tonic-gate addlist(elist, optarg); 1757*7c478bd9Sstevel@tonic-gate eflag = TRUE; 1758*7c478bd9Sstevel@tonic-gate break; 1759*7c478bd9Sstevel@tonic-gate case 'e': 1760*7c478bd9Sstevel@tonic-gate addlist(elist, optarg); 1761*7c478bd9Sstevel@tonic-gate eflag = TRUE; 1762*7c478bd9Sstevel@tonic-gate break; 1763*7c478bd9Sstevel@tonic-gate case 'F': 1764*7c478bd9Sstevel@tonic-gate addlist(Flist, optarg); 1765*7c478bd9Sstevel@tonic-gate Fflag = TRUE; 1766*7c478bd9Sstevel@tonic-gate addlist(flist, optarg); 1767*7c478bd9Sstevel@tonic-gate fflag = TRUE; 1768*7c478bd9Sstevel@tonic-gate break; 1769*7c478bd9Sstevel@tonic-gate case 'f': 1770*7c478bd9Sstevel@tonic-gate addlist(flist, optarg); 1771*7c478bd9Sstevel@tonic-gate fflag = TRUE; 1772*7c478bd9Sstevel@tonic-gate break; 1773*7c478bd9Sstevel@tonic-gate case 'l': 1774*7c478bd9Sstevel@tonic-gate lflag = TRUE; 1775*7c478bd9Sstevel@tonic-gate break; 1776*7c478bd9Sstevel@tonic-gate case 'n': 1777*7c478bd9Sstevel@tonic-gate nflag = TRUE; 1778*7c478bd9Sstevel@tonic-gate number_funcs_toprint = atoi(optarg); 1779*7c478bd9Sstevel@tonic-gate break; 1780*7c478bd9Sstevel@tonic-gate case 's': 1781*7c478bd9Sstevel@tonic-gate sflag = TRUE; 1782*7c478bd9Sstevel@tonic-gate break; 1783*7c478bd9Sstevel@tonic-gate case 'z': 1784*7c478bd9Sstevel@tonic-gate zflag = TRUE; 1785*7c478bd9Sstevel@tonic-gate break; 1786*7c478bd9Sstevel@tonic-gate case '?': 1787*7c478bd9Sstevel@tonic-gate errflg++; 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate } 1790*7c478bd9Sstevel@tonic-gate 1791*7c478bd9Sstevel@tonic-gate if (errflg) { 1792*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1793*7c478bd9Sstevel@tonic-gate "usage: gprof [ -abcCDlsz ] [ -e function-name ] " 1794*7c478bd9Sstevel@tonic-gate "[ -E function-name ]\n\t[ -f function-name ] " 1795*7c478bd9Sstevel@tonic-gate "[ -F function-name ]\n\t[ image-file " 1796*7c478bd9Sstevel@tonic-gate "[ profile-file ... ] ]\n"); 1797*7c478bd9Sstevel@tonic-gate exit(EX_USAGE); 1798*7c478bd9Sstevel@tonic-gate } 1799*7c478bd9Sstevel@tonic-gate 1800*7c478bd9Sstevel@tonic-gate if (optind < argc) { 1801*7c478bd9Sstevel@tonic-gate a_outname = argv[optind++]; 1802*7c478bd9Sstevel@tonic-gate } else { 1803*7c478bd9Sstevel@tonic-gate a_outname = A_OUTNAME; 1804*7c478bd9Sstevel@tonic-gate } 1805*7c478bd9Sstevel@tonic-gate if (optind < argc) { 1806*7c478bd9Sstevel@tonic-gate gmonname = argv[optind++]; 1807*7c478bd9Sstevel@tonic-gate } else { 1808*7c478bd9Sstevel@tonic-gate gmonname = GMONNAME; 1809*7c478bd9Sstevel@tonic-gate } 1810*7c478bd9Sstevel@tonic-gate /* 1811*7c478bd9Sstevel@tonic-gate * turn off default functions 1812*7c478bd9Sstevel@tonic-gate */ 1813*7c478bd9Sstevel@tonic-gate for (sp = &defaultEs[0]; *sp; sp++) { 1814*7c478bd9Sstevel@tonic-gate Eflag = TRUE; 1815*7c478bd9Sstevel@tonic-gate addlist(Elist, *sp); 1816*7c478bd9Sstevel@tonic-gate eflag = TRUE; 1817*7c478bd9Sstevel@tonic-gate addlist(elist, *sp); 1818*7c478bd9Sstevel@tonic-gate } 1819*7c478bd9Sstevel@tonic-gate /* 1820*7c478bd9Sstevel@tonic-gate * how many ticks per second? 1821*7c478bd9Sstevel@tonic-gate * if we can't tell, report time in ticks. 1822*7c478bd9Sstevel@tonic-gate */ 1823*7c478bd9Sstevel@tonic-gate hz = sysconf(_SC_CLK_TCK); 1824*7c478bd9Sstevel@tonic-gate if (hz == -1) { 1825*7c478bd9Sstevel@tonic-gate hz = 1; 1826*7c478bd9Sstevel@tonic-gate fprintf(stderr, "time is in ticks, not seconds\n"); 1827*7c478bd9Sstevel@tonic-gate } 1828*7c478bd9Sstevel@tonic-gate 1829*7c478bd9Sstevel@tonic-gate getnfile(a_outname); 1830*7c478bd9Sstevel@tonic-gate 1831*7c478bd9Sstevel@tonic-gate /* 1832*7c478bd9Sstevel@tonic-gate * get information about mon.out file(s). 1833*7c478bd9Sstevel@tonic-gate */ 1834*7c478bd9Sstevel@tonic-gate do { 1835*7c478bd9Sstevel@tonic-gate getpfile(gmonname); 1836*7c478bd9Sstevel@tonic-gate if (optind < argc) 1837*7c478bd9Sstevel@tonic-gate gmonname = argv[optind++]; 1838*7c478bd9Sstevel@tonic-gate else 1839*7c478bd9Sstevel@tonic-gate optind++; 1840*7c478bd9Sstevel@tonic-gate } while (optind <= argc); 1841*7c478bd9Sstevel@tonic-gate /* 1842*7c478bd9Sstevel@tonic-gate * dump out a gmon.sum file if requested 1843*7c478bd9Sstevel@tonic-gate */ 1844*7c478bd9Sstevel@tonic-gate if (sflag || Dflag) 1845*7c478bd9Sstevel@tonic-gate dumpsum(GMONSUM); 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate if (old_style) { 1848*7c478bd9Sstevel@tonic-gate /* 1849*7c478bd9Sstevel@tonic-gate * assign samples to procedures 1850*7c478bd9Sstevel@tonic-gate */ 1851*7c478bd9Sstevel@tonic-gate asgnsamples(); 1852*7c478bd9Sstevel@tonic-gate } 1853*7c478bd9Sstevel@tonic-gate 1854*7c478bd9Sstevel@tonic-gate /* 1855*7c478bd9Sstevel@tonic-gate * assemble the dynamic profile 1856*7c478bd9Sstevel@tonic-gate */ 1857*7c478bd9Sstevel@tonic-gate timesortnlp = doarcs(); 1858*7c478bd9Sstevel@tonic-gate 1859*7c478bd9Sstevel@tonic-gate /* 1860*7c478bd9Sstevel@tonic-gate * print the dynamic profile 1861*7c478bd9Sstevel@tonic-gate */ 1862*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1863*7c478bd9Sstevel@tonic-gate if (debug & ANYDEBUG) { 1864*7c478bd9Sstevel@tonic-gate /* raw output of all symbols in all their glory */ 1865*7c478bd9Sstevel@tonic-gate int i; 1866*7c478bd9Sstevel@tonic-gate printf(" Name, pc_entry_pt, svalue, tix_in_routine, " 1867*7c478bd9Sstevel@tonic-gate "#calls, selfcalls, index \n"); 1868*7c478bd9Sstevel@tonic-gate for (i = 0; i < modules.nname; i++) { /* Print each symbol */ 1869*7c478bd9Sstevel@tonic-gate if (timesortnlp[i]->name) 1870*7c478bd9Sstevel@tonic-gate printf(" %s ", timesortnlp[i]->name); 1871*7c478bd9Sstevel@tonic-gate else 1872*7c478bd9Sstevel@tonic-gate printf(" <cycle> "); 1873*7c478bd9Sstevel@tonic-gate printf(" %lld ", timesortnlp[i]->value); 1874*7c478bd9Sstevel@tonic-gate printf(" %lld ", timesortnlp[i]->svalue); 1875*7c478bd9Sstevel@tonic-gate printf(" %f ", timesortnlp[i]->time); 1876*7c478bd9Sstevel@tonic-gate printf(" %lld ", timesortnlp[i]->ncall); 1877*7c478bd9Sstevel@tonic-gate printf(" %lld ", timesortnlp[i]->selfcalls); 1878*7c478bd9Sstevel@tonic-gate printf(" %d ", timesortnlp[i]->index); 1879*7c478bd9Sstevel@tonic-gate printf(" \n"); 1880*7c478bd9Sstevel@tonic-gate } 1881*7c478bd9Sstevel@tonic-gate } 1882*7c478bd9Sstevel@tonic-gate #endif DEBUG 1883*7c478bd9Sstevel@tonic-gate 1884*7c478bd9Sstevel@tonic-gate printgprof(timesortnlp); 1885*7c478bd9Sstevel@tonic-gate /* 1886*7c478bd9Sstevel@tonic-gate * print the flat profile 1887*7c478bd9Sstevel@tonic-gate */ 1888*7c478bd9Sstevel@tonic-gate printprof(); 1889*7c478bd9Sstevel@tonic-gate /* 1890*7c478bd9Sstevel@tonic-gate * print the index 1891*7c478bd9Sstevel@tonic-gate */ 1892*7c478bd9Sstevel@tonic-gate printindex(); 1893*7c478bd9Sstevel@tonic-gate 1894*7c478bd9Sstevel@tonic-gate /* 1895*7c478bd9Sstevel@tonic-gate * print the modules 1896*7c478bd9Sstevel@tonic-gate */ 1897*7c478bd9Sstevel@tonic-gate printmodules(); 1898*7c478bd9Sstevel@tonic-gate 1899*7c478bd9Sstevel@tonic-gate done(); 1900*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1901*7c478bd9Sstevel@tonic-gate return (0); 1902*7c478bd9Sstevel@tonic-gate } 1903