17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57a5d89c4Sab196087 * Common Development and Distribution License (the "License"). 67a5d89c4Sab196087 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2192ed1782Smike_s 2292ed1782Smike_s /* 231dd08564Sab196087 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2492ed1782Smike_s * Use is subject to license terms. 2592ed1782Smike_s */ 2692ed1782Smike_s 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate /* 347c478bd9Sstevel@tonic-gate * Program profiling report generator. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * Usage: 377c478bd9Sstevel@tonic-gate * 3892ed1782Smike_s * prof [-ChsVz] [-a | c | n | t] [-o | x] [-g | l] 397c478bd9Sstevel@tonic-gate * [-m mdata] [prog] 407c478bd9Sstevel@tonic-gate * 417c478bd9Sstevel@tonic-gate * Where "prog" is the program that was profiled; "a.out" by default. 427c478bd9Sstevel@tonic-gate * Options are: 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * -n Sort by symbol name. 457c478bd9Sstevel@tonic-gate * -t Sort by decreasing time. 467c478bd9Sstevel@tonic-gate * -c Sort by decreasing number of calls. 477c478bd9Sstevel@tonic-gate * -a Sort by increasing symbol address. 487c478bd9Sstevel@tonic-gate * 497c478bd9Sstevel@tonic-gate * The options that determine the type of sorting are mutually exclusive. 507c478bd9Sstevel@tonic-gate * Additional options are: 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * -o Include symbol addresses in output (in octal). 537c478bd9Sstevel@tonic-gate * -x Include symbol addresses in output (in hexadecimal). 547c478bd9Sstevel@tonic-gate * -g Include non-global T-type symbols in output. 5592ed1782Smike_s * -l Do NOT include local T-type symbols in output (default). 567c478bd9Sstevel@tonic-gate * -z Include all symbols in profiling range, even if zero 577c478bd9Sstevel@tonic-gate * number of calls or time. 587c478bd9Sstevel@tonic-gate * -h Suppress table header. 597c478bd9Sstevel@tonic-gate * -s Follow report with additional statistical information. 607c478bd9Sstevel@tonic-gate * -m mdata Use file "mdata" instead of MON_OUT for profiling data. 617c478bd9Sstevel@tonic-gate * -V print version information for prof (and exit, if only V spec'd) 627c478bd9Sstevel@tonic-gate * -C call C++ demangle routine to demangle names before printing. 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #include <stdio.h> 667c478bd9Sstevel@tonic-gate #include <string.h> 677c478bd9Sstevel@tonic-gate #include <errno.h> 687c478bd9Sstevel@tonic-gate #include <dlfcn.h> 6992ed1782Smike_s #include <ctype.h> 70*b9bd317cSab196087 #include "conv.h" 717c478bd9Sstevel@tonic-gate #include "symint.h" 727c478bd9Sstevel@tonic-gate #include "sys/param.h" /* for HZ */ 737c478bd9Sstevel@tonic-gate #include "mon.h" 747c478bd9Sstevel@tonic-gate #include "sys/stat.h" 757c478bd9Sstevel@tonic-gate #include "debug.h" 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate #define OLD_DEBUG(x) 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #define Print (void) printf 807c478bd9Sstevel@tonic-gate #define Fprint (void) fprintf 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate #if vax 837c478bd9Sstevel@tonic-gate /* Max positive difference between a fnpc and sl_addr for match */ 847c478bd9Sstevel@tonic-gate #define CCADIFF 22 857c478bd9Sstevel@tonic-gate /* Type if n_type field in file symbol table entry. */ 867c478bd9Sstevel@tonic-gate #endif 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate #if (u3b || u3b15 || u3b2 || i386) 897c478bd9Sstevel@tonic-gate /* Max positive difference between a fnpc and sl_addr for match */ 907c478bd9Sstevel@tonic-gate #define CCADIFF 20 /* ?? (16 would probably do) */ 917c478bd9Sstevel@tonic-gate /* For u3b, the "type" is storage class + section number (no type_t) */ 927c478bd9Sstevel@tonic-gate #endif 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate #if (sparc) 957c478bd9Sstevel@tonic-gate #define CCADIFF 24 /* PIC prologue length=20 + 4 */ 967c478bd9Sstevel@tonic-gate #endif 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate #define PROFSEC(ticks) ((double)(ticks)/HZ) /* Convert clock ticks to seconds */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* Title fragment used if symbol addresses in output ("-o" or "-x"). */ 1027c478bd9Sstevel@tonic-gate char *atitle = " Address "; 1037c478bd9Sstevel@tonic-gate /* Format for addresses in output */ 1047c478bd9Sstevel@tonic-gate char *aformat = "%8o "; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate #if !(vax || u3b || u3b15 || u3b2 || i386 || sparc) 1077c478bd9Sstevel@tonic-gate /* Make sure something we are set up for. Else lay egg. */ 1087c478bd9Sstevel@tonic-gate #include "### No code for processor type ###" 1097c478bd9Sstevel@tonic-gate #endif 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* Shorthand to gimme the Precise #of addresses per cells */ 1137c478bd9Sstevel@tonic-gate #define DBL_ADDRPERCELL (((double)bias)/sf) 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* Used for unsigned fixed-point fraction with binary scale at */ 1177c478bd9Sstevel@tonic-gate /* the left of 15'th bit (0 as least significant bit) . */ 1187c478bd9Sstevel@tonic-gate #define BIAS ((long)0200000L) 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * TS1 insures that the symbols section is executable. 1227c478bd9Sstevel@tonic-gate */ 1237c478bd9Sstevel@tonic-gate #define TS1(s) (((s) > 0) && (scnhdrp[(s)-1].sh_flags & SHF_EXECINSTR)) 1247c478bd9Sstevel@tonic-gate /* 1257c478bd9Sstevel@tonic-gate * TS2 insures that the symbol should be reported. We want 1267c478bd9Sstevel@tonic-gate * to report only those symbols that are functions (STT_FUNC) 1277c478bd9Sstevel@tonic-gate * or "notype" (STT_NOTYPE... "printf", for example). Also, 1287c478bd9Sstevel@tonic-gate * unless the gflag is set, the symbol must be global. 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate #define TS2(i) \ 1327c478bd9Sstevel@tonic-gate (((ELF32_ST_TYPE(i) == STT_FUNC) || \ 1337c478bd9Sstevel@tonic-gate (ELF32_ST_TYPE(i) == STT_NOTYPE)) && \ 1347c478bd9Sstevel@tonic-gate ((ELF32_ST_BIND(i) == STB_GLOBAL) || \ 1357c478bd9Sstevel@tonic-gate (gflag && (ELF32_ST_BIND(i) == STB_LOCAL)))) 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate #define TXTSYM(s, i) (TS1(s) && TS2(i)) 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate int gflag = 0; /* replaces gmatch and gmask */ 1407c478bd9Sstevel@tonic-gate int Cflag = 0; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate PROF_FILE *ldptr; /* For program ("a.out") file. */ 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate FILE *mon_iop; /* For profile (MON_OUT) file. */ 1457c478bd9Sstevel@tonic-gate char *sym_fn = "a.out"; /* Default program file name. */ 1467c478bd9Sstevel@tonic-gate char *mon_fn = MON_OUT; /* Default profile file name. */ 1477c478bd9Sstevel@tonic-gate /* May be changed by "-m file". */ 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate long bias; /* adjusted bias */ 1507c478bd9Sstevel@tonic-gate long temp; /* for bias adjust */ 1517c478bd9Sstevel@tonic-gate 15292ed1782Smike_s extern void profver(void); 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* For symbol table entries read from program file. */ 1557c478bd9Sstevel@tonic-gate PROF_SYMBOL nl; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* Compare routines called from qsort() */ 1587c478bd9Sstevel@tonic-gate 15992ed1782Smike_s int c_ccaddr(const void *arg1, const void *arg2); 16092ed1782Smike_s int c_sladdr(const void *arg1, const void *arg2); 16192ed1782Smike_s int c_time(const void *arg1, const void *arg2); 16292ed1782Smike_s int c_ncalls(const void *arg1, const void *arg2); 16392ed1782Smike_s int c_name(const void *arg1, const void *arg2); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* Other stuff. */ 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* Return size of open file (arg is file descriptor) */ 16892ed1782Smike_s static off_t fsize(int fd); 16992ed1782Smike_s 17092ed1782Smike_s static void snh(void); 17192ed1782Smike_s static void Perror(char *s); 17292ed1782Smike_s static void eofon(FILE *iop, char *fn); 17392ed1782Smike_s static void usage(void); 17492ed1782Smike_s static char *getname(PROF_FILE *ldpter, PROF_SYMBOL symbol); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* Memory allocation. Like malloc(), but no return if error. */ 17792ed1782Smike_s static void *_prof_Malloc(int item_count, int item_size); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* Scan past path part (if any) in the ... */ 18092ed1782Smike_s static char *basename(char *s); 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* command name, for error messages. */ 1837c478bd9Sstevel@tonic-gate char *cmdname; 1847c478bd9Sstevel@tonic-gate /* Structure of subroutine call counters (cnt) is defined in mon.h. */ 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* Structure for header of mon.out (hdr) is defined in mon.h. */ 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* Local representation of symbols and call/time information. */ 1897c478bd9Sstevel@tonic-gate struct slist { 1907c478bd9Sstevel@tonic-gate char *sl_name; /* Symbol name. */ 1917c478bd9Sstevel@tonic-gate char *sl_addr; /* Address. */ 1927c478bd9Sstevel@tonic-gate long sl_size; /* size of symbol */ 1937c478bd9Sstevel@tonic-gate long sl_count; /* Count of subroutine calls */ 1947c478bd9Sstevel@tonic-gate float sl_time; /* Count of clock ticks in this routine, */ 1957c478bd9Sstevel@tonic-gate /* converted to secs. */ 1967c478bd9Sstevel@tonic-gate }; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* local structure for tracking synonyms in our symbol list */ 19992ed1782Smike_s struct snymEntry { 2007c478bd9Sstevel@tonic-gate char *sym_addr; /* address which has a synonym */ 2017c478bd9Sstevel@tonic-gate int howMany; /* # of synonyms for this symbol */ 2027c478bd9Sstevel@tonic-gate int snymReported; /* 'was printed in a report line already' */ 2037c478bd9Sstevel@tonic-gate /* flag, */ 2047c478bd9Sstevel@tonic-gate /* > 0 report line printed for these syns. */ 2057c478bd9Sstevel@tonic-gate /* == 0 not printed yet. */ 2067c478bd9Sstevel@tonic-gate long tot_sl_count; /* total subr calls for these snyms */ 2077c478bd9Sstevel@tonic-gate float tot_sl_time; /* total clock ticks (a la sl_time) */ 2087c478bd9Sstevel@tonic-gate }; 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate #define AOUTHSZ (filhdr.f_opthdr) 2127c478bd9Sstevel@tonic-gate PROF_FILE filhdr; /* profile file descriptor */ 2137c478bd9Sstevel@tonic-gate Elf32_Shdr *scnhdrp; /* pointer to first section header */ 2147c478bd9Sstevel@tonic-gate /* (space by _prof_Malloc) */ 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate struct hdr head; /* Profile file (MON_OUT) header. */ 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate int (*sort)() = NULL; /* Compare routine for sorting output */ 2197c478bd9Sstevel@tonic-gate /* symbols. Set by "-[acnt]". */ 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate int flags; /* Various flag bits. */ 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate char *pc_l; /* From head.lpc. */ 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate char *pc_h; /* " head.hpc. */ 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate short VwasSpecified = 0; /* 1 if -V was specified */ 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * Bit macro and flag bit definitions. These need to be identical to the 2317c478bd9Sstevel@tonic-gate * set in profv.h. Any change here should be reflected in profv.c also. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate #define FBIT(pos) (01 << (pos)) /* Returns value with bit pos set. */ 2347c478bd9Sstevel@tonic-gate #define F_SORT FBIT(0) /* Set if "-[acnt]" seen. */ 2357c478bd9Sstevel@tonic-gate #define F_VERBOSE FBIT(1) /* Set if "-s" seen. */ 2367c478bd9Sstevel@tonic-gate #define F_ZSYMS FBIT(2) /* Set if "-z" seen. */ 2377c478bd9Sstevel@tonic-gate #define F_PADDR FBIT(3) /* Set if "-o" or "-x" seen. */ 2387c478bd9Sstevel@tonic-gate #define F_NHEAD FBIT(4) /* Set if "-h" seen. */ 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate struct snymEntry *snymList; /* Pointer to allocated list of */ 2427c478bd9Sstevel@tonic-gate /* synonym entries. */ 2437c478bd9Sstevel@tonic-gate struct snymEntry *snymp; 2447c478bd9Sstevel@tonic-gate /* for scanning entries. */ 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate int snymCapacity; /* #slots in snymList */ 2477c478bd9Sstevel@tonic-gate int n_snyms; /* #used slots in snymList */ 2487c478bd9Sstevel@tonic-gate 24992ed1782Smike_s static int readnl(int symindex); 25092ed1782Smike_s static int fprecision(long count); 25192ed1782Smike_s 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * Sort flags. Mutually exclusive. These need to be identical to the ones 2547c478bd9Sstevel@tonic-gate * defined in profv.h 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate #define BY_ADDRESS 0x1 2577c478bd9Sstevel@tonic-gate #define BY_NCALLS 0x2 2587c478bd9Sstevel@tonic-gate #define BY_NAME 0x4 2597c478bd9Sstevel@tonic-gate #define BY_TIME 0x8 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate extern unsigned char sort_flag; /* what type of sort ? */ 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * printSnymNames - print a comma-seperated list of snym names. 2657c478bd9Sstevel@tonic-gate * This routine hunts down all the synonyms for the given 2667c478bd9Sstevel@tonic-gate * symbol, and prints them as a comma-seperated list. 2677c478bd9Sstevel@tonic-gate * NB we assume that all the synonyms _Follow_ this one, 2687c478bd9Sstevel@tonic-gate * since they are only printed when the First one 2697c478bd9Sstevel@tonic-gate * is seen. 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate void 27292ed1782Smike_s printSnymNames(struct slist *slp, struct snymEntry *snymp) 2737c478bd9Sstevel@tonic-gate { 2747c478bd9Sstevel@tonic-gate /* how many snyms for this addr, total, and their shared address */ 2757c478bd9Sstevel@tonic-gate int i = snymp->howMany; 2767c478bd9Sstevel@tonic-gate char *sharedaddr = snymp->sym_addr; 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* put out first name - it counts as one, so decr count */ 2797c478bd9Sstevel@tonic-gate (void) fputs(slp->sl_name, stdout); 2807c478bd9Sstevel@tonic-gate i--; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* for the others: find each, print each. */ 2837c478bd9Sstevel@tonic-gate while (--i >= 0) { 2841dd08564Sab196087 while ((++slp)->sl_addr != sharedaddr) 2851dd08564Sab196087 ; 2867c478bd9Sstevel@tonic-gate Print(", %s", slp->sl_name); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate /* finally.. the trailing newline */ 28992ed1782Smike_s (void) putchar('\n'); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * getSnymEntry - see if addr was noted as a aliased address 2957c478bd9Sstevel@tonic-gate * (i.e. a synonym symbol) and return the address of the 2967c478bd9Sstevel@tonic-gate * snym entry if it was. 2977c478bd9Sstevel@tonic-gate */ 29892ed1782Smike_s struct snymEntry * 29992ed1782Smike_s getSnymEntry(char *sl_addr) 3007c478bd9Sstevel@tonic-gate { 3017c478bd9Sstevel@tonic-gate struct snymEntry *p; 3027c478bd9Sstevel@tonic-gate int i; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate for (p = snymList, i = n_snyms; --i >= 0; p++) 3057c478bd9Sstevel@tonic-gate if (sl_addr == p->sym_addr) 3067c478bd9Sstevel@tonic-gate return (p); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate return ((struct snymEntry *)0); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate 31292ed1782Smike_s int 31392ed1782Smike_s main(int argc, char **argv) 3147c478bd9Sstevel@tonic-gate { 3157c478bd9Sstevel@tonic-gate char buffer[BUFSIZ]; /* buffer for printf */ 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate WORD *pcounts; /* Pointer to allocated area for */ 3187c478bd9Sstevel@tonic-gate /* pcounts: PC clock hit counts */ 3197c478bd9Sstevel@tonic-gate 32092ed1782Smike_s WORD *pcp; /* For scanning pcounts. */ 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate struct cnt *ccounts; /* Pointer to allocated area for cnt */ 3237c478bd9Sstevel@tonic-gate /* structures: subr PC-call counts. */ 3247c478bd9Sstevel@tonic-gate 32592ed1782Smike_s struct cnt *ccp; /* For scanning ccounts. */ 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate struct slist *slist; /* Pointer to allocated slist structures: */ 3287c478bd9Sstevel@tonic-gate /* symbol name/address/time/call counts */ 3297c478bd9Sstevel@tonic-gate 33092ed1782Smike_s struct slist *slp; /* For scanning slist */ 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate int vn_cc, n_cc; /* Number of cnt structures in profile data */ 3337c478bd9Sstevel@tonic-gate /* file (later # ones used). */ 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate int n_pc; /* Number of pcounts in profile data file. */ 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate int n_syms; /* Number of text symbols (of proper type) */ 3387c478bd9Sstevel@tonic-gate /* that fill in range of profiling. */ 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate int n_nonzero; /* Number of (above symbols) actually printed */ 3417c478bd9Sstevel@tonic-gate /* because nonzero time or # calls. */ 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate int symttl; /* Total # symbols in program file sym-table */ 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate int i; 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate int fdigits = 0; /* # of digits of precision for print msecs/call */ 3487c478bd9Sstevel@tonic-gate 34992ed1782Smike_s int n, symct; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate long sf; /* Scale for index into pcounts: */ 3527c478bd9Sstevel@tonic-gate /* i(pc) = ((pc - pc_l) * sf)/bias. */ 3537c478bd9Sstevel@tonic-gate 35492ed1782Smike_s /* LINTED: set but not used */ 3557c478bd9Sstevel@tonic-gate long s_inv; /* Inverse: i_inv(i) = */ 3567c478bd9Sstevel@tonic-gate /* {pc00, pc00+1, ... pc00+s_inv-1}. */ 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate unsigned pc_m; /* Range of PCs profiled: pc_m = pc_h - pc_l */ 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate float t, t0; 3617c478bd9Sstevel@tonic-gate float t_tot; /* Total time: PROFSEC(sum of all pcounts[i]) */ 3627c478bd9Sstevel@tonic-gate int callTotal = 0; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate DEBUG_LOC("main: top"); 3657c478bd9Sstevel@tonic-gate setbuf(stdout, buffer); 3667c478bd9Sstevel@tonic-gate cmdname = basename(*argv); /* command name. */ 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate while ((n = getopt(argc, argv, "canthsglzoxT:m:VC")) != EOF) { 3697c478bd9Sstevel@tonic-gate switch (n) { 3707c478bd9Sstevel@tonic-gate int (*fcn)(); /* For function to sort results. */ 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate case 'm': /* Specify data file: -m file */ 3737c478bd9Sstevel@tonic-gate mon_fn = optarg; 3747c478bd9Sstevel@tonic-gate break; 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate #ifdef ddt 3777c478bd9Sstevel@tonic-gate case 'T': /* Set trace flags: -T(octnum) */ 3787c478bd9Sstevel@tonic-gate debug_value = (int)strtol(optarg, 0, 8); 3797c478bd9Sstevel@tonic-gate break; 3807c478bd9Sstevel@tonic-gate #endif 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate case 'n': /* Sort by symbol name. */ 3837c478bd9Sstevel@tonic-gate fcn = c_name; 3847c478bd9Sstevel@tonic-gate sort_flag |= BY_NAME; 3857c478bd9Sstevel@tonic-gate goto check; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate case 't': /* Sort by decreasing time. */ 3887c478bd9Sstevel@tonic-gate fcn = c_time; 3897c478bd9Sstevel@tonic-gate sort_flag |= BY_TIME; 3907c478bd9Sstevel@tonic-gate goto check; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate case 'c': /* Sort by decreasing # calls. */ 3937c478bd9Sstevel@tonic-gate fcn = c_ncalls; 3947c478bd9Sstevel@tonic-gate sort_flag |= BY_NCALLS; 3957c478bd9Sstevel@tonic-gate goto check; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate case 'a': /* Sort by increasing symbol address */ 3987c478bd9Sstevel@tonic-gate /* (don't have to -- it will be) */ 3997c478bd9Sstevel@tonic-gate fcn = NULL; 4007c478bd9Sstevel@tonic-gate sort_flag |= BY_ADDRESS; 4017c478bd9Sstevel@tonic-gate check: /* Here to check sort option conflicts. */ 4027c478bd9Sstevel@tonic-gate if (sort != NULL && sort != fcn) { 4037c478bd9Sstevel@tonic-gate Fprint(stderr, "%s: Warning: %c overrides" 4047c478bd9Sstevel@tonic-gate " previous specification\n", cmdname, n); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate sort = fcn; /* Store sort routine */ 4077c478bd9Sstevel@tonic-gate flags |= F_SORT; /* Note have done so */ 4087c478bd9Sstevel@tonic-gate break; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate case 'o': /* Include symbol addresses in output. */ 4117c478bd9Sstevel@tonic-gate case 'x': /* Include symbol addresses in output. */ 4127c478bd9Sstevel@tonic-gate aformat[2] = n; /* 'o' or 'x' in format */ 4137c478bd9Sstevel@tonic-gate flags |= F_PADDR; /* Set flag. */ 4147c478bd9Sstevel@tonic-gate break; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate case 'g': /* Include local T symbols as well as global */ 4177c478bd9Sstevel@tonic-gate gflag = 1; 4187c478bd9Sstevel@tonic-gate break; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate case 'l': /* Do NOT include local T symbols */ 4217c478bd9Sstevel@tonic-gate gflag = 0; 4227c478bd9Sstevel@tonic-gate break; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate case 'z': /* Print all symbols in profiling range, */ 4257c478bd9Sstevel@tonic-gate /* even if no time or # calls. */ 4267c478bd9Sstevel@tonic-gate flags |= F_ZSYMS; /* Set flag. */ 4277c478bd9Sstevel@tonic-gate break; 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate case 'h': /* Suppress table header. */ 4307c478bd9Sstevel@tonic-gate flags |= F_NHEAD; 4317c478bd9Sstevel@tonic-gate break; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate case 's': /* Follow normal output with extra summary. */ 4347c478bd9Sstevel@tonic-gate flags |= F_VERBOSE; /* Set flag (...) */ 4357c478bd9Sstevel@tonic-gate break; 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate case 'V': 4387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "prof: %s %s\n", 4397c478bd9Sstevel@tonic-gate (const char *)SGU_PKG, (const char *)SGU_REL); 4407c478bd9Sstevel@tonic-gate VwasSpecified = 1; 4417c478bd9Sstevel@tonic-gate break; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate case 'C': /* demangle C++ names before printing. */ 4447c478bd9Sstevel@tonic-gate Cflag = 1; 4457c478bd9Sstevel@tonic-gate break; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate case '?': /* But no good. */ 44892ed1782Smike_s usage(); 4497c478bd9Sstevel@tonic-gate } /* End switch (n) */ 4507c478bd9Sstevel@tonic-gate } /* End while (getopt) */ 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate DEBUG_LOC("main: following getopt"); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* if -V the only argument, just exit. */ 4557c478bd9Sstevel@tonic-gate if (VwasSpecified && argc == 2 && !flags) 4567c478bd9Sstevel@tonic-gate exit(0); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate if (optind < argc) 4597c478bd9Sstevel@tonic-gate sym_fn = argv[optind]; /* name other than `a.out' */ 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate if (sort == NULL && !(flags & F_SORT)) 4627c478bd9Sstevel@tonic-gate /* If have not specified sort mode ... */ 4637c478bd9Sstevel@tonic-gate sort = c_time; /* then sort by decreasing time. */ 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * profver() checks to see if the mon.out was "versioned" and if 4677c478bd9Sstevel@tonic-gate * yes, processes it and exits; otherwise, we have an *old-style* 4687c478bd9Sstevel@tonic-gate * mon.out and we process it the old way. 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate profver(); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* Open monitor data file (has counts). */ 4737c478bd9Sstevel@tonic-gate if ((mon_iop = fopen(mon_fn, "r")) == NULL) 4747c478bd9Sstevel@tonic-gate Perror(mon_fn); 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate DEBUG_LOC("main: before _symintOpen"); 4777c478bd9Sstevel@tonic-gate if ((ldptr = _symintOpen(sym_fn)) == NULL) { 4787c478bd9Sstevel@tonic-gate Perror("_symintOpen failed"); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate DEBUG_LOC("main: after _symintOpen"); 4817c478bd9Sstevel@tonic-gate filhdr = *ldptr; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate scnhdrp = ldptr->pf_shdarr_p; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate { 4867c478bd9Sstevel@tonic-gate Elf_Kind k = elf_kind(filhdr.pf_elf_p); 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate DEBUG_EXP(printf("elf_kind = %d\n", k)); 4897c478bd9Sstevel@tonic-gate DEBUG_EXP(printf("elf_type = %d\n", filhdr.pf_elfhd_p->e_type)); 4907c478bd9Sstevel@tonic-gate if ((k != ELF_K_ELF) || (filhdr.pf_elfhd_p->e_type != ET_EXEC)) { 4917c478bd9Sstevel@tonic-gate Fprint(stderr, "%s: %s: improper format\n", cmdname, sym_fn); 4927c478bd9Sstevel@tonic-gate exit(1); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* Compute the file address of symbol table. Machine-dependent. */ 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate DEBUG_EXP(printf("number of symbols (pf_nsyms) = %d\n", 4997c478bd9Sstevel@tonic-gate filhdr.pf_nsyms)); 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* Number of symbols in file symbol table. */ 5027c478bd9Sstevel@tonic-gate symttl = filhdr.pf_nsyms; 5037c478bd9Sstevel@tonic-gate if (symttl == 0) { /* This is possible. */ 5047c478bd9Sstevel@tonic-gate Fprint(stderr, "%s: %s: no symbols\n", cmdname, sym_fn); 5057c478bd9Sstevel@tonic-gate exit(0); /* Note zero exit code. */ 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate /* Get size of file containing profiling data. Read header part. */ 5087c478bd9Sstevel@tonic-gate n = fsize(fileno(mon_iop)); 5097c478bd9Sstevel@tonic-gate if (fread((char *)&head, sizeof (struct hdr), 1, mon_iop) != 1) 5107c478bd9Sstevel@tonic-gate eofon(mon_iop, mon_fn); /* Probably junk file. */ 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* Get # cnt structures (they follow header), */ 5137c478bd9Sstevel@tonic-gate /* and allocate space for them. */ 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate n_cc = head.nfns; 51692ed1782Smike_s ccounts = _prof_Malloc(n_cc, sizeof (struct cnt)); 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* Read the call addr-count pairs. */ 5197c478bd9Sstevel@tonic-gate if (fread((char *)ccounts, sizeof (struct cnt), n_cc, mon_iop) != n_cc) 5207c478bd9Sstevel@tonic-gate eofon(mon_iop, mon_fn); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* 5237c478bd9Sstevel@tonic-gate * Compute # PC counters (pcounts), which occupy whatever is left 5247c478bd9Sstevel@tonic-gate * of the file after the header and call counts. 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate n_pc = (n - sizeof (head) - n_cc * sizeof (struct cnt))/sizeof (WORD); 5287c478bd9Sstevel@tonic-gate ccp = &ccounts[n_cc]; /* Point to last (+1) of call counters ... */ 5297c478bd9Sstevel@tonic-gate do { /* and scan backward until find highest one used. */ 5307c478bd9Sstevel@tonic-gate if ((--ccp)->mcnt) 5317c478bd9Sstevel@tonic-gate break; /* Stop when find nonzero count. */ 5327c478bd9Sstevel@tonic-gate } while (--n_cc > 0); /* Or all are zero. */ 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate if (n_cc > 0) { 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* If less than all cnt entries are used, return unused space. */ 5377c478bd9Sstevel@tonic-gate if (n_cc < head.nfns) { 5387c478bd9Sstevel@tonic-gate if ((ccounts = (struct cnt *)realloc((char *)ccounts, 5397c478bd9Sstevel@tonic-gate (unsigned)n_cc * sizeof (struct cnt))) == NULL) 5407c478bd9Sstevel@tonic-gate snh(); /* Should not fail when reducing size. */ 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* If more than 250 cnt entries used set verbose for warning */ 5447c478bd9Sstevel@tonic-gate if (n_cc > (MPROGS0 * 5)/6) 5457c478bd9Sstevel@tonic-gate flags |= F_VERBOSE; 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate /* Space for PC counts. */ 5487c478bd9Sstevel@tonic-gate pcounts = (WORD *)_prof_Malloc(n_pc, sizeof (WORD)); 5497c478bd9Sstevel@tonic-gate /* Read the PC counts from rest of MON_OUT file. */ 5507c478bd9Sstevel@tonic-gate if (fread((char *)pcounts, sizeof (WORD), n_pc, mon_iop) != n_pc) 5517c478bd9Sstevel@tonic-gate eofon(mon_iop, mon_fn); 5527c478bd9Sstevel@tonic-gate /* 5537c478bd9Sstevel@tonic-gate * 5547c478bd9Sstevel@tonic-gate * Having gotten preliminaries out of the way, get down to business. 5557c478bd9Sstevel@tonic-gate * The range pc_m of addresses over which profiling was done is 5567c478bd9Sstevel@tonic-gate * computed from the low (pc_l) and high (pc_h) addresses, gotten 5577c478bd9Sstevel@tonic-gate * from the MON_OUT header. From this and the number of clock 5587c478bd9Sstevel@tonic-gate * tick counters, n_pc, is computed the so-called "scale", sf, used 5597c478bd9Sstevel@tonic-gate * in the mapping of addresses to indices, as follows: 5607c478bd9Sstevel@tonic-gate * 5617c478bd9Sstevel@tonic-gate * (pc - pc_l) * sf 5627c478bd9Sstevel@tonic-gate * i(pc) = ---------------- 5637c478bd9Sstevel@tonic-gate * 0200000 5647c478bd9Sstevel@tonic-gate * 5657c478bd9Sstevel@tonic-gate * Also, the N-to-one value, s_inv, such that 5667c478bd9Sstevel@tonic-gate * 5677c478bd9Sstevel@tonic-gate * i(pc_l + K * s_inv + d) = K, for 0 <= d < s_inv 5687c478bd9Sstevel@tonic-gate * 5697c478bd9Sstevel@tonic-gate * Following this, the symbol table is scanned, and those symbols 5707c478bd9Sstevel@tonic-gate * that qualify are counted. These are T-type symbols, excluding 5717c478bd9Sstevel@tonic-gate * local (nonglobal) unless the "-g" option was given. Having thus 5727c478bd9Sstevel@tonic-gate * determined the space requirements, space for symbols/times etc. 5737c478bd9Sstevel@tonic-gate * is allocated, and the symbol table re-read, this time keeping 5747c478bd9Sstevel@tonic-gate * qualified symbols. 5757c478bd9Sstevel@tonic-gate * 5767c478bd9Sstevel@tonic-gate * NB s_inv, as actually computed, is not sufficiently accurate 5777c478bd9Sstevel@tonic-gate * (since it is truncated) for many calculations. Since it is 5787c478bd9Sstevel@tonic-gate * logically equivalent to 1/(sf/bias), and the latter is much 5797c478bd9Sstevel@tonic-gate * more accurate, therefore the latter will often appear in 5807c478bd9Sstevel@tonic-gate * the code when 's_inv' is mentioned. dween 5817c478bd9Sstevel@tonic-gate * 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate pc_l = head.lpc; /* Low PC of range that was profiled. */ 5867c478bd9Sstevel@tonic-gate pc_h = head.hpc; /* First address past range of profiling. */ 5877c478bd9Sstevel@tonic-gate pc_m = pc_h - pc_l; /* Range of profiled addresses. */ 5887c478bd9Sstevel@tonic-gate 5891dd08564Sab196087 /* BEGIN CSTYLED */ 5907c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value) Fprint(stderr, 5917c478bd9Sstevel@tonic-gate "low pc = %#o, high pc = %#o, range = %#o = %u\n\ 5927c478bd9Sstevel@tonic-gate call counts: %u, %u used; pc counters: %u\n", 5937c478bd9Sstevel@tonic-gate pc_l, pc_h, pc_m, pc_m, head.nfns, n_cc, n_pc)); 5941dd08564Sab196087 /* END CSTYLED */ 5957c478bd9Sstevel@tonic-gate 5961dd08564Sab196087 /*LINTED: E_ASSIGMENT_CAUSE_LOSS_PREC*/ 5977c478bd9Sstevel@tonic-gate sf = (BIAS * (double)n_pc)/pc_m; 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * Now adjust bias and sf so that there is no overflow 6007c478bd9Sstevel@tonic-gate * when calculating indices. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate bias = BIAS; 6037c478bd9Sstevel@tonic-gate temp = pc_m; 6047c478bd9Sstevel@tonic-gate while ((temp >>= 1) > 0x7fff) { 6057c478bd9Sstevel@tonic-gate sf >>= 1; 6067c478bd9Sstevel@tonic-gate bias >>= 1; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate s_inv = pc_m/n_pc; /* Range of PCs mapped into one index. */ 6097c478bd9Sstevel@tonic-gate 6101dd08564Sab196087 /* BEGIN CSTYLED */ 6117c478bd9Sstevel@tonic-gate OLD_DEBUG( 6127c478bd9Sstevel@tonic-gate if (debug_value) { 6137c478bd9Sstevel@tonic-gate Fprint( 6147c478bd9Sstevel@tonic-gate stderr, 6157c478bd9Sstevel@tonic-gate "sf = %d, s_inv = %d bias = %d\n", 6167c478bd9Sstevel@tonic-gate (long)sf, s_inv, bias); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate ); 6191dd08564Sab196087 /* END CSTYLED */ 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate /* Prepare to read symbols from "a.out" (or whatever). */ 6227c478bd9Sstevel@tonic-gate n_syms = 0; /* Init count of qualified symbols. */ 6237c478bd9Sstevel@tonic-gate n = symttl; /* Total symbols. */ 6247c478bd9Sstevel@tonic-gate while (--n >= 0) /* Scan symbol table. */ 6257c478bd9Sstevel@tonic-gate if (readnl(n)) /* Read and examine symbol, count qualifiers */ 6267c478bd9Sstevel@tonic-gate n_syms++; 6277c478bd9Sstevel@tonic-gate 6281dd08564Sab196087 /* BEGIN CSTYLED */ 6297c478bd9Sstevel@tonic-gate OLD_DEBUG( 6307c478bd9Sstevel@tonic-gate if (debug_value) { 6317c478bd9Sstevel@tonic-gate Fprint(stderr, "%u symbols, %u qualify\n", symttl, n_syms); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate ); 6341dd08564Sab196087 /* END CSTYLED */ 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate /* Allocate space for qualified symbols. */ 6377c478bd9Sstevel@tonic-gate 63892ed1782Smike_s slist = slp = _prof_Malloc(n_syms, sizeof (struct slist)); 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * Allocate space for synonym symbols 6427c478bd9Sstevel@tonic-gate * (i.e. symbols that refer to the same address). 6437c478bd9Sstevel@tonic-gate * NB there can be no more than n_syms/2 addresses 6447c478bd9Sstevel@tonic-gate * with symbols, That Have Aliases, that refer to them! 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate snymCapacity = n_syms/2; 6481dd08564Sab196087 snymList = snymp = 6491dd08564Sab196087 _prof_Malloc(snymCapacity, sizeof (struct snymEntry)); 6507c478bd9Sstevel@tonic-gate n_snyms = 0; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* OLD_DEBUG(debug_value &= ~020); */ 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate /* Loop on number of qualified symbols. */ 6557c478bd9Sstevel@tonic-gate for (n = n_syms, symct = 0; n > 0; symct++) { 6567c478bd9Sstevel@tonic-gate if (readnl(symct)) { /* Get one. Check again. */ 6577c478bd9Sstevel@tonic-gate /* Is qualified. Move name ... */ 6587c478bd9Sstevel@tonic-gate slp->sl_name = getname(ldptr, nl); 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate /* and address into slist structure. */ 6617c478bd9Sstevel@tonic-gate slp->sl_addr = (char *)nl.ps_sym.st_value; 6627c478bd9Sstevel@tonic-gate slp->sl_size = nl.ps_sym.st_size; 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* set other slist fields to zero. */ 6657c478bd9Sstevel@tonic-gate slp->sl_time = 0.0; 6667c478bd9Sstevel@tonic-gate slp->sl_count = 0; 6671dd08564Sab196087 /* BEGIN CSTYLED */ 6687c478bd9Sstevel@tonic-gate OLD_DEBUG( 6697c478bd9Sstevel@tonic-gate if (debug_value & 02) 6707c478bd9Sstevel@tonic-gate Fprint(stderr, "%-8.8s: %#8o\n", slp->sl_name, slp->sl_addr) 6717c478bd9Sstevel@tonic-gate ); 6721dd08564Sab196087 /* END CSTYLED */ 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate slp++; 6757c478bd9Sstevel@tonic-gate --n; 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * 6807c478bd9Sstevel@tonic-gate * Now attempt to match call counts with symbols. To do this, it 6817c478bd9Sstevel@tonic-gate * helps to first sort both the symbols and the call address/count 6827c478bd9Sstevel@tonic-gate * pairs by ascending address, since they are generally not, to 6837c478bd9Sstevel@tonic-gate * begin with. The addresses associated with the counts are not, 6847c478bd9Sstevel@tonic-gate * of course, the subroutine addresses associated with the symbols, 6857c478bd9Sstevel@tonic-gate * but some address slightly past these. Therefore a given count 6867c478bd9Sstevel@tonic-gate * address (in the fnpc field) is matched with the closest symbol 6877c478bd9Sstevel@tonic-gate * address (sl_addr) that is: 6887c478bd9Sstevel@tonic-gate * (1) less than the fnpc value but, 6897c478bd9Sstevel@tonic-gate * (2) not more than the length of the function 6907c478bd9Sstevel@tonic-gate * In other words, unreasonable matchups are avoided. 6917c478bd9Sstevel@tonic-gate * Situations such as this could arise when static procedures are 6927c478bd9Sstevel@tonic-gate * counted but the "-g" option was not given to this program, 6937c478bd9Sstevel@tonic-gate * causing the symbol to fail to qualify. Without this limitation, 6947c478bd9Sstevel@tonic-gate * unmatched counts could be erroneously charged. 6957c478bd9Sstevel@tonic-gate * 6967c478bd9Sstevel@tonic-gate */ 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate ccp = ccounts; /* Point to first call counter. */ 7007c478bd9Sstevel@tonic-gate slp = slist; /* " " " symbol. */ 7017c478bd9Sstevel@tonic-gate /* Sort call counters and ... */ 7027c478bd9Sstevel@tonic-gate qsort((char *)ccp, (unsigned)n_cc, sizeof (struct cnt), c_ccaddr); 7037c478bd9Sstevel@tonic-gate /* symbols by increasing address. */ 7047c478bd9Sstevel@tonic-gate qsort((char *)slp, (unsigned)n_syms, sizeof (struct slist), c_sladdr); 7057c478bd9Sstevel@tonic-gate vn_cc = n_cc; /* save this for verbose option */ 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate /* Loop to match up call counts & symbols. */ 7097c478bd9Sstevel@tonic-gate for (n = n_syms; n > 0 && vn_cc > 0; ) { 7107c478bd9Sstevel@tonic-gate int sz = slp->sl_size; 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate if (sz == 0) 7137c478bd9Sstevel@tonic-gate sz = slp[ 1 ].sl_addr - slp->sl_addr; 7147c478bd9Sstevel@tonic-gate if (slp->sl_addr < ccp->fnpc && 7157c478bd9Sstevel@tonic-gate ccp->fnpc <= slp->sl_addr + sz) { 7167c478bd9Sstevel@tonic-gate /* got a candidate: find Closest. */ 7177c478bd9Sstevel@tonic-gate struct slist *closest_symp; 7187c478bd9Sstevel@tonic-gate do { 7197c478bd9Sstevel@tonic-gate closest_symp = slp; 7207c478bd9Sstevel@tonic-gate slp++; 7217c478bd9Sstevel@tonic-gate --n; 7227c478bd9Sstevel@tonic-gate } while (n > 0 && slp->sl_addr < ccp->fnpc); 7237c478bd9Sstevel@tonic-gate 7241dd08564Sab196087 /* BEGIN CSTYLED */ 7257c478bd9Sstevel@tonic-gate OLD_DEBUG( 7267c478bd9Sstevel@tonic-gate if (debug_value & 04) { 7277c478bd9Sstevel@tonic-gate Fprint(stderr, 7287c478bd9Sstevel@tonic-gate "Routine %-8.8s @ %#8x+%-2d matches count address %#8x\n", 7297c478bd9Sstevel@tonic-gate closest_symp->sl_name, 7307c478bd9Sstevel@tonic-gate closest_symp->sl_addr, 7317c478bd9Sstevel@tonic-gate ccp->fnpc-slp->sl_addr, 7327c478bd9Sstevel@tonic-gate ccp->fnpc); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate ); 7351dd08564Sab196087 /* END CSTYLED */ 7367c478bd9Sstevel@tonic-gate closest_symp->sl_count = ccp->mcnt; /* Copy count. */ 7377c478bd9Sstevel@tonic-gate ++ccp; 7387c478bd9Sstevel@tonic-gate --vn_cc; 7397c478bd9Sstevel@tonic-gate } else if (ccp->fnpc < slp->sl_addr) { 7407c478bd9Sstevel@tonic-gate ++ccp; 7417c478bd9Sstevel@tonic-gate --vn_cc; 7427c478bd9Sstevel@tonic-gate } else { 7437c478bd9Sstevel@tonic-gate ++slp; 7447c478bd9Sstevel@tonic-gate --n; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate /* 7497c478bd9Sstevel@tonic-gate * 7507c478bd9Sstevel@tonic-gate * The distribution of times to addresses is done on a proportional 7517c478bd9Sstevel@tonic-gate * basis as follows: The t counts in pcounts[i] correspond to clock 7527c478bd9Sstevel@tonic-gate * ticks for values of pc in the range pc, pc+1, ..., pc+s_inv-1 7537c478bd9Sstevel@tonic-gate * (odd addresses excluded for PDP11s). Without more detailed info, 7547c478bd9Sstevel@tonic-gate * it must be assumed that there is no greater probability 7557c478bd9Sstevel@tonic-gate * of the clock ticking for any particular pc in this range than for 7567c478bd9Sstevel@tonic-gate * any other. Thus the t counts are considered to be equally 7577c478bd9Sstevel@tonic-gate * distributed over the addresses in the range, and that the time for 7587c478bd9Sstevel@tonic-gate * any given address in the range is pcounts[i]/s_inv. 7597c478bd9Sstevel@tonic-gate * 7607c478bd9Sstevel@tonic-gate * The values of the symbols that qualify, bounded below and above 7617c478bd9Sstevel@tonic-gate * by pc_l and pc_h, respectively, partition the profiling range into 7627c478bd9Sstevel@tonic-gate * regions to which are assigned the total times associated with the 7637c478bd9Sstevel@tonic-gate * addresses they contain in the following way: 7647c478bd9Sstevel@tonic-gate * 7657c478bd9Sstevel@tonic-gate * The sum of all pcounts[i] for which the corresponding addresses are 7667c478bd9Sstevel@tonic-gate * wholly within the partition are charged to the partition (the 7677c478bd9Sstevel@tonic-gate * subroutine whose address is the lower bound of the partition). 7687c478bd9Sstevel@tonic-gate * 7697c478bd9Sstevel@tonic-gate * If the range of addresses corresponding to a given t = pcounts[i] 7707c478bd9Sstevel@tonic-gate * lies astraddle the boundary of a partition, e.g., for some k such 7717c478bd9Sstevel@tonic-gate * that 0 < k < s_inv-1, the addresses pc, pc+1, ..., pc+k-1 are in 7727c478bd9Sstevel@tonic-gate * the lower partition, and the addresses pc+k, pc+k+1, ..., pc+s_inv-1 7737c478bd9Sstevel@tonic-gate * are in the next partition, then k*pcounts[i]/s_inv time is charged 7747c478bd9Sstevel@tonic-gate * to the lower partition, and (s_inv-k) * pcounts[i]/s_inv time to the 7757c478bd9Sstevel@tonic-gate * upper. It is conceivable, in cases of large granularity or small 7767c478bd9Sstevel@tonic-gate * subroutines, for a range corresponding to a given pcounts[i] to 7777c478bd9Sstevel@tonic-gate * overlap three regions, completely containing the (small) middle one. 7787c478bd9Sstevel@tonic-gate * The algorithm is adjusted appropriately in this case. 7797c478bd9Sstevel@tonic-gate * 7807c478bd9Sstevel@tonic-gate */ 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate pcp = pcounts; /* Reset to base. */ 7847c478bd9Sstevel@tonic-gate slp = slist; /* Ditto. */ 7857c478bd9Sstevel@tonic-gate t0 = 0.0; /* Time accumulator. */ 7867c478bd9Sstevel@tonic-gate for (n = 0; n < n_syms; n++) { /* Loop on symbols. */ 7877c478bd9Sstevel@tonic-gate /* Start addr of region, low addr of overlap. */ 7887c478bd9Sstevel@tonic-gate char *pc0, *pc00; 7897c478bd9Sstevel@tonic-gate /* Start addr of next region, low addr of overlap. */ 7907c478bd9Sstevel@tonic-gate char *pc1, *pc10; 7917c478bd9Sstevel@tonic-gate /* First index into pcounts for this region and next region. */ 79292ed1782Smike_s int i0, i1; 7937c478bd9Sstevel@tonic-gate long ticks; 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate /* Address of symbol (subroutine). */ 7967c478bd9Sstevel@tonic-gate pc0 = slp[n].sl_addr; 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /* Address of next symbol, if any or top */ 7997c478bd9Sstevel@tonic-gate /* of profile range, if not */ 8007c478bd9Sstevel@tonic-gate pc1 = (n < n_syms - 1) ? slp[n+1].sl_addr : pc_h; 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate /* Lower bound of indices into pcounts for this range */ 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate i0 = (((unsigned)pc0 - (unsigned)pc_l) * sf)/bias; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* Upper bound (least or least + 1) of indices. */ 8077c478bd9Sstevel@tonic-gate i1 = (((unsigned)pc1 - (unsigned)pc_l) * sf)/bias; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate if (i1 >= n_pc) /* If past top, */ 8107c478bd9Sstevel@tonic-gate i1 = n_pc - 1; /* adjust. */ 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate /* Lowest addr for which count maps to pcounts[i0]; */ 8137c478bd9Sstevel@tonic-gate pc00 = pc_l + (unsigned long)((bias * i0)/sf); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate /* Lowest addr for which count maps to pcounts[i1]. */ 8167c478bd9Sstevel@tonic-gate pc10 = pc_l + (unsigned long)((bias * i1)/sf); 8177c478bd9Sstevel@tonic-gate 8181dd08564Sab196087 /* BEGIN CSTYLED */ 8197c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) Fprint(stderr, 8207c478bd9Sstevel@tonic-gate "%-8.8s\ti0 = %4d, pc00 = %#6o, pc0 = %#6o\n\ 8217c478bd9Sstevel@tonic-gate \t\ti1 = %4d, pc10 = %#6o, pc1 = %#6o\n\t\t", 8227c478bd9Sstevel@tonic-gate slp[n].sl_name, i0, pc00, pc0, i1, pc10, pc1)); 8231dd08564Sab196087 /* END CSTYLED */ 8247c478bd9Sstevel@tonic-gate t = 0; /* Init time for this symbol. */ 8257c478bd9Sstevel@tonic-gate if (i0 == i1) { 8267c478bd9Sstevel@tonic-gate /* Counter overlaps two areas? (unlikely */ 8277c478bd9Sstevel@tonic-gate /* unless large granularity). */ 8287c478bd9Sstevel@tonic-gate ticks = pcp[i0]; /* # Times (clock ticks). */ 8297c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) fprintf(stderr, "ticks = %d\n", ticks)); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* Time less that which overlaps adjacent areas */ 8327c478bd9Sstevel@tonic-gate t += PROFSEC(ticks * ((double)(pc1 - pc0) * sf)/bias); 8337c478bd9Sstevel@tonic-gate 8341dd08564Sab196087 /* BEGIN CSTYLED */ 8357c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) 8367c478bd9Sstevel@tonic-gate Fprint(stderr, "%ld/(%.1f)", (pc1 - pc0) * ticks, DBL_ADDRPERCELL) 8377c478bd9Sstevel@tonic-gate ); 8381dd08564Sab196087 /* END CSTYLED */ 8397c478bd9Sstevel@tonic-gate } else { 8407c478bd9Sstevel@tonic-gate /* Overlap with previous region? */ 8417c478bd9Sstevel@tonic-gate if (pc00 < pc0) { 8427c478bd9Sstevel@tonic-gate ticks = pcp[i0]; 8431dd08564Sab196087 /* BEGIN CSTYLED */ 8447c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) 8457c478bd9Sstevel@tonic-gate fprintf(stderr, "pc00 < pc0 ticks = %d\n", ticks)); 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate /* Get time of overlapping area and */ 8487c478bd9Sstevel@tonic-gate /* subtract proportion for lower region. */ 8497c478bd9Sstevel@tonic-gate t += PROFSEC( 8507c478bd9Sstevel@tonic-gate ticks*(1-((double)(pc0-pc00) *sf)/bias)); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate /* Do not count this time when summing times */ 8537c478bd9Sstevel@tonic-gate /* wholly within the region. */ 8547c478bd9Sstevel@tonic-gate i0++; 8551dd08564Sab196087 /* BEGIN CSTYLED */ 8567c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) 8577c478bd9Sstevel@tonic-gate Fprint(stderr, "%ld/(%.1f) + ", (pc0 - pc00) * ticks, 8587c478bd9Sstevel@tonic-gate DBL_ADDRPERCELL)); 8591dd08564Sab196087 /* END CSTYLED */ 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate /* Init sum of counts for PCs not shared w/other */ 8637c478bd9Sstevel@tonic-gate /* routines. */ 8647c478bd9Sstevel@tonic-gate ticks = 0; 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate /* Stop at first count that overlaps following */ 8677c478bd9Sstevel@tonic-gate /* routine. */ 8687c478bd9Sstevel@tonic-gate for (i = i0; i < i1; i++) 8697c478bd9Sstevel@tonic-gate ticks += pcp[i]; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate t += PROFSEC(ticks); /* Convert to secs, add to total */ 8727c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) Fprint(stderr, "%ld", ticks)); 8737c478bd9Sstevel@tonic-gate /* Some overlap with low addresses of next routine? */ 8747c478bd9Sstevel@tonic-gate if (pc10 < pc1) { 8757c478bd9Sstevel@tonic-gate /* Yes. Get total count ... */ 8767c478bd9Sstevel@tonic-gate ticks = pcp[i1]; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* and accumulate proportion for addresses in */ 8797c478bd9Sstevel@tonic-gate /* range of this routine */ 8807c478bd9Sstevel@tonic-gate t += PROFSEC(((double)ticks * 8817c478bd9Sstevel@tonic-gate (pc1 - pc10)*sf)/bias); 8821dd08564Sab196087 /* BEGIN CSTYLED */ 8837c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) fprintf(stderr, "ticks = %d\n", ticks)); 8847c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) 8857c478bd9Sstevel@tonic-gate Fprint(stderr, " + %ld/(%.1f)", (pc1 - pc10) * ticks, DBL_ADDRPERCELL) 8867c478bd9Sstevel@tonic-gate ); 8871dd08564Sab196087 /* END CSTYLED */ 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate } /* End if (i0 == i1) ... else ... */ 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate slp[n].sl_time = t; /* Store time for this routine. */ 8927c478bd9Sstevel@tonic-gate t0 += t; /* Accumulate total time. */ 8937c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value & 010) Fprint(stderr, " ticks = %.2f msec\n", t)); 8947c478bd9Sstevel@tonic-gate } /* End for (n = 0; n < n_syms; n++) */ 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate /* Final pass to total up time. */ 8977c478bd9Sstevel@tonic-gate /* Sum ticks, then convert to seconds. */ 8987c478bd9Sstevel@tonic-gate 8991dd08564Sab196087 for (n = n_pc, temp = 0; --n >= 0; temp += *(pcp++)) 9001dd08564Sab196087 ; 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate t_tot = PROFSEC(temp); 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * Now, whilst we still have the symbols sorted 9067c478bd9Sstevel@tonic-gate * in address order.. 9077c478bd9Sstevel@tonic-gate * Loop to record duplicates, so we can display 9087c478bd9Sstevel@tonic-gate * synonym symbols correctly. 9097c478bd9Sstevel@tonic-gate * Synonym symbols, or symbols with the same address, 9107c478bd9Sstevel@tonic-gate * are to be displayed by prof on the same line, with 9117c478bd9Sstevel@tonic-gate * one statistics line, as below: 9127c478bd9Sstevel@tonic-gate * ... 255 ldaopen, ldaopen 9137c478bd9Sstevel@tonic-gate * The way this will be implemented, is as follows: 9147c478bd9Sstevel@tonic-gate * 9157c478bd9Sstevel@tonic-gate * Pass 1 - while the symbols are in address order, we 9167c478bd9Sstevel@tonic-gate * do a pre-pass through them, to determine for which 9177c478bd9Sstevel@tonic-gate * addresses there are more than one symbol (i.e. synonyms). 9187c478bd9Sstevel@tonic-gate * During this prepass we collect summary statistics in 9197c478bd9Sstevel@tonic-gate * the synonym entry, for all the synonyms. 9207c478bd9Sstevel@tonic-gate * 9217c478bd9Sstevel@tonic-gate * 'Pass' 2 - while printing a report, for each report line, 9227c478bd9Sstevel@tonic-gate * if the current symbol is a synonym symbol (i.e. in the 9237c478bd9Sstevel@tonic-gate * snymList) then we scan forward and pick up all the names 9247c478bd9Sstevel@tonic-gate * which map to this address, and print them too. 9257c478bd9Sstevel@tonic-gate * If the address' synonyms have already been printed, then 9267c478bd9Sstevel@tonic-gate * we just skip this symbol and go on to process the next. 9277c478bd9Sstevel@tonic-gate * 9287c478bd9Sstevel@tonic-gate */ 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate { 9317c478bd9Sstevel@tonic-gate /* pass 1 */ 9327c478bd9Sstevel@tonic-gate char *thisaddr; 9337c478bd9Sstevel@tonic-gate char *lastaddr = slist->sl_addr; /* use 1st sym as */ 9347c478bd9Sstevel@tonic-gate /* 'last/prior symbol' */ 9357c478bd9Sstevel@tonic-gate int lastWasSnym = 0; /* 1st can't be snym yet-no aliases seen! */ 9367c478bd9Sstevel@tonic-gate int thisIsSnym; 9377c478bd9Sstevel@tonic-gate 9381dd08564Sab196087 /* BEGIN CSTYLED */ 9397c478bd9Sstevel@tonic-gate OLD_DEBUG( 9407c478bd9Sstevel@tonic-gate int totsnyms = 0; int totseries = 0; struct slist *lastslp = slist; 9417c478bd9Sstevel@tonic-gate ); 9421dd08564Sab196087 /* END CSTYLED */ 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* NB loop starts with 2nd symbol, loops over n_syms-1 symbols! */ 9457c478bd9Sstevel@tonic-gate for (n = n_syms-1, slp = slist+1; --n >= 0; slp++) { 9467c478bd9Sstevel@tonic-gate thisaddr = slp->sl_addr; 9477c478bd9Sstevel@tonic-gate thisIsSnym = (thisaddr == lastaddr); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate if (thisIsSnym) { 9507c478bd9Sstevel@tonic-gate /* gotta synonym */ 9517c478bd9Sstevel@tonic-gate if (!lastWasSnym) { 9521dd08564Sab196087 /* BEGIN CSTYLED */ 9537c478bd9Sstevel@tonic-gate OLD_DEBUG( 9547c478bd9Sstevel@tonic-gate if (debug_value) { 9557c478bd9Sstevel@tonic-gate Fprint(stderr, 9567c478bd9Sstevel@tonic-gate "Synonym series:\n1st->\t%s at address %x, ct=%ld, time=%f\n", 9577c478bd9Sstevel@tonic-gate lastslp->sl_name, lastaddr, lastslp->sl_count, 9587c478bd9Sstevel@tonic-gate lastslp->sl_time); 9597c478bd9Sstevel@tonic-gate totseries++; 9607c478bd9Sstevel@tonic-gate totsnyms++; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate ); 9631dd08564Sab196087 /* END CSTYLED */ 9647c478bd9Sstevel@tonic-gate /* this is the Second! of a series */ 9657c478bd9Sstevel@tonic-gate snymp = (n_snyms++ == 0 ? snymList : snymp+1); 9667c478bd9Sstevel@tonic-gate snymp->howMany = 1; /* gotta count 1st one!! */ 9677c478bd9Sstevel@tonic-gate snymp->sym_addr = slp->sl_addr; 9687c478bd9Sstevel@tonic-gate /* zero summary statistics */ 9697c478bd9Sstevel@tonic-gate snymp->tot_sl_count = 0; 9707c478bd9Sstevel@tonic-gate snymp->tot_sl_time = 0.0; 9717c478bd9Sstevel@tonic-gate /* Offen the Reported flag */ 9727c478bd9Sstevel@tonic-gate snymp->snymReported = 0; 9737c478bd9Sstevel@tonic-gate } 9741dd08564Sab196087 /* BEGIN CSTYLED */ 9757c478bd9Sstevel@tonic-gate OLD_DEBUG( 9767c478bd9Sstevel@tonic-gate if (debug_value) { 9777c478bd9Sstevel@tonic-gate Fprint(stderr, 9787c478bd9Sstevel@tonic-gate "\t%s at address %x, ct=%ld, time=%f\n", 9797c478bd9Sstevel@tonic-gate slp->sl_name, 9807c478bd9Sstevel@tonic-gate thisaddr, 9817c478bd9Sstevel@tonic-gate slp->sl_count, 9827c478bd9Sstevel@tonic-gate slp->sl_time); 9837c478bd9Sstevel@tonic-gate totsnyms++; 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate ); 9861dd08564Sab196087 /* END CSTYLED */ 9877c478bd9Sstevel@tonic-gate /* ok - bump count for snym, and note its Finding */ 9887c478bd9Sstevel@tonic-gate snymp->howMany++; 9897c478bd9Sstevel@tonic-gate /* and update the summary statistics */ 9907c478bd9Sstevel@tonic-gate snymp->tot_sl_count += slp->sl_count; 9917c478bd9Sstevel@tonic-gate snymp->tot_sl_time += slp->sl_time; 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate callTotal += slp->sl_count; 9947c478bd9Sstevel@tonic-gate lastaddr = thisaddr; 9957c478bd9Sstevel@tonic-gate lastWasSnym = thisIsSnym; 9961dd08564Sab196087 /* BEGIN CSTYLED */ 9977c478bd9Sstevel@tonic-gate OLD_DEBUG( 9987c478bd9Sstevel@tonic-gate if (debug_value) lastslp = slp; 9997c478bd9Sstevel@tonic-gate ); 10001dd08564Sab196087 /* END CSTYLED */ 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate } 10031dd08564Sab196087 /* BEGIN CSTYLED */ 10047c478bd9Sstevel@tonic-gate OLD_DEBUG( 10057c478bd9Sstevel@tonic-gate if (debug_value) { 10067c478bd9Sstevel@tonic-gate Fprint(stderr, "Total #series %d, #synonyms %d\n", totseries, totsnyms); 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate ); 10091dd08564Sab196087 /* END CSTYLED */ 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate /* 10127c478bd9Sstevel@tonic-gate * Most of the heavy work is done now. Only minor stuff remains. 10137c478bd9Sstevel@tonic-gate * The symbols are currently in address order and must be re-sorted 10147c478bd9Sstevel@tonic-gate * if desired in a different order. Report generating options 10157c478bd9Sstevel@tonic-gate * include "-o" or "-x": Include symbol address, which causes 10167c478bd9Sstevel@tonic-gate * another column 10177c478bd9Sstevel@tonic-gate * in the output; and "-z": Include symbols in report even if zero 10187c478bd9Sstevel@tonic-gate * time and call count. Symbols not in profiling range are excluded 10197c478bd9Sstevel@tonic-gate * in any case. Following the main body of the report, the "-s" 10207c478bd9Sstevel@tonic-gate * option causes certain additional information to be printed. 10217c478bd9Sstevel@tonic-gate */ 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate OLD_DEBUG(if (debug_value) Fprint(stderr, 10247c478bd9Sstevel@tonic-gate "Time unaccounted for: %.7G\n", t_tot - t0)); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate if (sort) /* If comparison routine given then use it. */ 10277c478bd9Sstevel@tonic-gate qsort((char *)slist, (unsigned)n_syms, 10287c478bd9Sstevel@tonic-gate sizeof (struct slist), sort); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate if (!(flags & F_NHEAD)) { 10317c478bd9Sstevel@tonic-gate if (flags & F_PADDR) 103292ed1782Smike_s Print("%s", atitle); /* Title for addresses. */ 10337c478bd9Sstevel@tonic-gate (void) puts(" %Time Seconds Cumsecs #Calls msec/call Name"); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate t = 0.0; /* Init cumulative time. */ 10367c478bd9Sstevel@tonic-gate if (t_tot != 0.0) /* Convert to percent. */ 10377c478bd9Sstevel@tonic-gate t_tot = 100.0/t_tot; /* Prevent divide-by-zero fault */ 10387c478bd9Sstevel@tonic-gate n_nonzero = 0; /* Number of symbols with nonzero time or # calls. */ 10397c478bd9Sstevel@tonic-gate for (n = n_syms, slp = slist; --n >= 0; slp++) { 10407c478bd9Sstevel@tonic-gate long count; /* # Calls. */ 10417c478bd9Sstevel@tonic-gate /* t0, time in seconds. */ 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate /* if a snym symbol, use summarized stats, else use indiv. */ 10447c478bd9Sstevel@tonic-gate if ((snymp = getSnymEntry(slp->sl_addr)) != 0) { 10457c478bd9Sstevel@tonic-gate count = snymp->tot_sl_count; 10467c478bd9Sstevel@tonic-gate t0 = snymp->tot_sl_time; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate } else { 10497c478bd9Sstevel@tonic-gate count = slp->sl_count; 10507c478bd9Sstevel@tonic-gate t0 = slp->sl_time; 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate /* if a snym and already reported, skip this entry */ 10547c478bd9Sstevel@tonic-gate if (snymp && snymp->snymReported) 10557c478bd9Sstevel@tonic-gate continue; 10567c478bd9Sstevel@tonic-gate /* Don't do entries with no action. */ 10577c478bd9Sstevel@tonic-gate if (t0 == 0.0 && count == 0 && !(flags & F_ZSYMS)) 10587c478bd9Sstevel@tonic-gate continue; 10597c478bd9Sstevel@tonic-gate if ((strcmp(slp->sl_name, "_mcount") == 0) || 10607c478bd9Sstevel@tonic-gate (strcmp(slp->sl_name, "mcount") == 0)) { 10617c478bd9Sstevel@tonic-gate count = callTotal; 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate /* count number of entries (i.e. symbols) printed */ 10657c478bd9Sstevel@tonic-gate if (snymp) 10667c478bd9Sstevel@tonic-gate n_nonzero += snymp->howMany; /* add for each snym */ 10677c478bd9Sstevel@tonic-gate else 10687c478bd9Sstevel@tonic-gate n_nonzero++; 10697c478bd9Sstevel@tonic-gate 107092ed1782Smike_s if (flags & F_PADDR) { /* Printing address of symbol? */ 107192ed1782Smike_s /* LINTED: variable format */ 10727c478bd9Sstevel@tonic-gate Print(aformat, slp->sl_addr); 107392ed1782Smike_s } 10747c478bd9Sstevel@tonic-gate t += t0; /* move here; compiler bug !! */ 10757c478bd9Sstevel@tonic-gate Print("%6.1f%8.2f%8.2f", t0 * t_tot, t0, t); 10767c478bd9Sstevel@tonic-gate fdigits = 0; 10777c478bd9Sstevel@tonic-gate if (count) { /* Any calls recorded? */ 10787c478bd9Sstevel@tonic-gate /* Get reasonable number of fractional digits to print. */ 10797c478bd9Sstevel@tonic-gate fdigits = fprecision(count); 10807c478bd9Sstevel@tonic-gate Print("%8ld%#*.*f", count, fdigits+8, fdigits, 10817c478bd9Sstevel@tonic-gate 1000.0*t0/count); 10827c478bd9Sstevel@tonic-gate Print("%*s", 6-fdigits, " "); 10837c478bd9Sstevel@tonic-gate } else { 10847c478bd9Sstevel@tonic-gate Print("%22s", " "); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate /* 10877c478bd9Sstevel@tonic-gate * now print the name (or comma-seperate list of names, 10887c478bd9Sstevel@tonic-gate * for synonym symbols). 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate if (snymp) { 10917c478bd9Sstevel@tonic-gate printSnymNames(slp, snymp); /* print it, then */ 10927c478bd9Sstevel@tonic-gate snymp->snymReported = 1; /* mark it Done */ 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate else 10957c478bd9Sstevel@tonic-gate (void) puts(slp->sl_name); /* print the one name */ 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate if (flags & F_VERBOSE) { /* Extra info? */ 10987c478bd9Sstevel@tonic-gate Fprint(stderr, "%5d/%d call counts used\n", n_cc, head.nfns); 10997c478bd9Sstevel@tonic-gate Fprint(stderr, "%5d/%d symbols qualified", n_syms, symttl); 11007c478bd9Sstevel@tonic-gate if (n_nonzero < n_syms) 11017c478bd9Sstevel@tonic-gate Fprint(stderr, 11027c478bd9Sstevel@tonic-gate ", %d had zero time and zero call-counts\n", 11037c478bd9Sstevel@tonic-gate n_syms - n_nonzero); 11047c478bd9Sstevel@tonic-gate else 11057c478bd9Sstevel@tonic-gate (void) putc('\n', stderr); 110692ed1782Smike_s Fprint(stderr, "%#lx scale factor\n", (long)sf); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate _symintClose(ldptr); 11107c478bd9Sstevel@tonic-gate } else { 11117c478bd9Sstevel@tonic-gate Fprint(stderr, "prof: no call counts captured\n"); 11127c478bd9Sstevel@tonic-gate } 111392ed1782Smike_s return (0); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate /* Return size of file associated with file descriptor fd. */ 11167c478bd9Sstevel@tonic-gate 111792ed1782Smike_s static off_t 111892ed1782Smike_s fsize(int fd) 11197c478bd9Sstevel@tonic-gate { 11207c478bd9Sstevel@tonic-gate struct stat sbuf; 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate if (fstat(fd, &sbuf) < 0) /* Status of open file. */ 11237c478bd9Sstevel@tonic-gate Perror("stat"); 11247c478bd9Sstevel@tonic-gate return (sbuf.st_size); /* This is a long. */ 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate /* Read symbol entry. Return TRUE if satisfies conditions. */ 11287c478bd9Sstevel@tonic-gate 112992ed1782Smike_s static int 113092ed1782Smike_s readnl(int symindex) 11317c478bd9Sstevel@tonic-gate { 11327c478bd9Sstevel@tonic-gate nl = ldptr->pf_symarr_p[symindex]; 11337c478bd9Sstevel@tonic-gate 11341dd08564Sab196087 /* BEGIN CSTYLED */ 11357c478bd9Sstevel@tonic-gate OLD_DEBUG( 11367c478bd9Sstevel@tonic-gate if (debug_value & 020) { 11377c478bd9Sstevel@tonic-gate Fprint(stderr, 11387c478bd9Sstevel@tonic-gate "`%-8.8s'\tst_info=%#4o, value=%#8.6o\n", 11397c478bd9Sstevel@tonic-gate ldptr->pf_symstr_p[nl.ps_sym.st_name], 11407c478bd9Sstevel@tonic-gate (unsigned char) nl.ps_sym.st_info, 11417c478bd9Sstevel@tonic-gate nl.ps_sym.st_value); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate ); 11441dd08564Sab196087 /* END CSTYLED */ 11451dd08564Sab196087 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * TXTSYM accepts global (and local, if "-g" given) T-type symbols. 11487c478bd9Sstevel@tonic-gate * Only those in the profiling range are useful. 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate return (nl.ps_sym.st_shndx < SHN_LORESERVE && 11511dd08564Sab196087 TXTSYM(nl.ps_sym.st_shndx, nl.ps_sym.st_info) && 11527c478bd9Sstevel@tonic-gate (pc_l <= (char *)nl.ps_sym.st_value) && 11537c478bd9Sstevel@tonic-gate ((char *)nl.ps_sym.st_value < pc_h)); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate /* 11567c478bd9Sstevel@tonic-gate * Error-checking memory allocators - 11577c478bd9Sstevel@tonic-gate * Guarantees good return (else none at all). 11587c478bd9Sstevel@tonic-gate */ 11597c478bd9Sstevel@tonic-gate 116092ed1782Smike_s static void * 116192ed1782Smike_s _prof_Malloc(int item_count, int item_size) 11627c478bd9Sstevel@tonic-gate { 116392ed1782Smike_s void *p; 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate if ((p = malloc((unsigned)item_count * (unsigned)item_size)) == NULL) { 11667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: Out of space\n", cmdname); 11677c478bd9Sstevel@tonic-gate exit(1); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate return (p); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate /* 11757c478bd9Sstevel@tonic-gate * Given the quotient Q = N/D, where entier(N) == N and D > 0, an 11767c478bd9Sstevel@tonic-gate * approximation of the "best" number of fractional digits to use 11777c478bd9Sstevel@tonic-gate * in printing Q is f = entier(log10(D)), which is crudely produced 11787c478bd9Sstevel@tonic-gate * by the following routine. 11797c478bd9Sstevel@tonic-gate */ 11807c478bd9Sstevel@tonic-gate 118192ed1782Smike_s static int 118292ed1782Smike_s fprecision(long count) 11837c478bd9Sstevel@tonic-gate { 11847c478bd9Sstevel@tonic-gate return (count < 10 ? 0 : count < 100 ? 1 : count < 1000 ? 2 : 11857c478bd9Sstevel@tonic-gate count < 10000 ? 3 : 4); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * Return pointer to base name(name less path) of string s. 11907c478bd9Sstevel@tonic-gate * Handles case of superfluous trailing '/'s, and unlikely 11917c478bd9Sstevel@tonic-gate * case of s == "/". 11927c478bd9Sstevel@tonic-gate */ 11937c478bd9Sstevel@tonic-gate 119492ed1782Smike_s static char * 119592ed1782Smike_s basename(char *s) 11967c478bd9Sstevel@tonic-gate { 119792ed1782Smike_s char *p; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate p = &s[strlen(s)]; /* End (+1) of string. */ 12007c478bd9Sstevel@tonic-gate while (p > s && *--p == '/') /* Trim trailing '/'s. */ 12017c478bd9Sstevel@tonic-gate *p = '\0'; 12027c478bd9Sstevel@tonic-gate p++; /* New end (+1) of string. */ 12031dd08564Sab196087 while (p > s && *--p != '/') /* Break backward on '/'. */ 12041dd08564Sab196087 ; 12057c478bd9Sstevel@tonic-gate if (*p == '/') /* If found '/', point to 1st following. */ 12067c478bd9Sstevel@tonic-gate p++; 12077c478bd9Sstevel@tonic-gate if (*p == '\0') 12087c478bd9Sstevel@tonic-gate p = "/"; /* If NULL, must be "/". (?) */ 12097c478bd9Sstevel@tonic-gate return (p); 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate /* Here if unexpected read problem. */ 12127c478bd9Sstevel@tonic-gate 121392ed1782Smike_s static void 121492ed1782Smike_s eofon(FILE *iop, char *fn) 12157c478bd9Sstevel@tonic-gate { 12167c478bd9Sstevel@tonic-gate if (ferror(iop)) /* Real error? */ 12177c478bd9Sstevel@tonic-gate Perror(fn); /* Yes. */ 12187c478bd9Sstevel@tonic-gate Fprint(stderr, "%s: %s: Premature EOF\n", cmdname, fn); 12197c478bd9Sstevel@tonic-gate exit(1); 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate /* Version of perror() that prints cmdname first. */ 12237c478bd9Sstevel@tonic-gate 122492ed1782Smike_s static void 122592ed1782Smike_s Perror(char *s) 12267c478bd9Sstevel@tonic-gate { /* Print system error message & exit. */ 122792ed1782Smike_s int err = errno; /* Save current errno in case */ 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate Fprint(stderr, "%s: ", cmdname); 12307c478bd9Sstevel@tonic-gate errno = err; /* Put real error back. */ 12317c478bd9Sstevel@tonic-gate perror(s); /* Print message. */ 12327c478bd9Sstevel@tonic-gate _symintClose(ldptr); /* cleanup symbol information */ 12337c478bd9Sstevel@tonic-gate exit(1); /* Exit w/nonzero status. */ 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate /* Here for things that "Should Never Happen". */ 12377c478bd9Sstevel@tonic-gate 123892ed1782Smike_s static void 123992ed1782Smike_s snh(void) 12407c478bd9Sstevel@tonic-gate { 12417c478bd9Sstevel@tonic-gate Fprint(stderr, "%s: Internal error\n", cmdname); 12427c478bd9Sstevel@tonic-gate (void) abort(); 12437c478bd9Sstevel@tonic-gate } 124492ed1782Smike_s 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * Various comparison routines for qsort. Uses: 12477c478bd9Sstevel@tonic-gate * 12487c478bd9Sstevel@tonic-gate * c_ccaddr - Compare fnpc fields of cnt structs to put 12497c478bd9Sstevel@tonic-gate * call counters in increasing address order. 12507c478bd9Sstevel@tonic-gate * c_sladdr - Sort slist structures on increasing address. 12517c478bd9Sstevel@tonic-gate * c_time - " " " " decreasing time. 12527c478bd9Sstevel@tonic-gate * c_ncalls - " " " " decreasing # calls. 12537c478bd9Sstevel@tonic-gate * c_name - " " " " increasing symbol name 12547c478bd9Sstevel@tonic-gate */ 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate #define CMP2(v1, v2) ((v1) < (v2) ? -1 : (v1) == (v2) ? 0 : 1) 12577c478bd9Sstevel@tonic-gate #define CMP1(v) CMP2(v, 0) 12587c478bd9Sstevel@tonic-gate 125992ed1782Smike_s int 126092ed1782Smike_s c_ccaddr(const void *arg1, const void *arg2) 12617c478bd9Sstevel@tonic-gate { 126292ed1782Smike_s struct cnt *p1 = (struct cnt *)arg1; 126392ed1782Smike_s struct cnt *p2 = (struct cnt *)arg2; 126492ed1782Smike_s 12657c478bd9Sstevel@tonic-gate return (CMP2(p1->fnpc, p2->fnpc)); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate 126892ed1782Smike_s int 126992ed1782Smike_s c_sladdr(const void *arg1, const void *arg2) 12707c478bd9Sstevel@tonic-gate { 127192ed1782Smike_s struct slist *p1 = (struct slist *)arg1; 127292ed1782Smike_s struct slist *p2 = (struct slist *)arg2; 127392ed1782Smike_s 12747c478bd9Sstevel@tonic-gate return (CMP2(p1->sl_addr, p2->sl_addr)); 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate 127792ed1782Smike_s int 127892ed1782Smike_s c_time(const void *arg1, const void *arg2) 12797c478bd9Sstevel@tonic-gate { 128092ed1782Smike_s struct slist *p1 = (struct slist *)arg1; 128192ed1782Smike_s struct slist *p2 = (struct slist *)arg2; 128292ed1782Smike_s float dtime = p2->sl_time - p1->sl_time; /* Decreasing time. */ 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate return (CMP1(dtime)); 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate 128792ed1782Smike_s int 128892ed1782Smike_s c_ncalls(const void *arg1, const void *arg2) 12897c478bd9Sstevel@tonic-gate { 129092ed1782Smike_s struct slist *p1 = (struct slist *)arg1; 129192ed1782Smike_s struct slist *p2 = (struct slist *)arg2; 129292ed1782Smike_s int diff = p2->sl_count - p1->sl_count; 12937c478bd9Sstevel@tonic-gate /* Decreasing # calls. */ 12947c478bd9Sstevel@tonic-gate return (CMP1(diff)); 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate 129792ed1782Smike_s int 129892ed1782Smike_s c_name(const void *arg1, const void *arg2) 12997c478bd9Sstevel@tonic-gate { 130092ed1782Smike_s struct slist *p1 = (struct slist *)arg1; 130192ed1782Smike_s struct slist *p2 = (struct slist *)arg2; 130292ed1782Smike_s int diff; 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* flex names has variable length strings for names */ 13057c478bd9Sstevel@tonic-gate diff = strcmp(p1->sl_name, p2->sl_name); 13067c478bd9Sstevel@tonic-gate return (CMP1(diff)); 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate #define STRSPACE 2400 /* guess at amount of string space */ 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate char *format_buf; 13127c478bd9Sstevel@tonic-gate #define FORMAT_BUF "%s\n\t\t\t\t\t [%s]" 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate static char * 131592ed1782Smike_s demangled_name(char *s) 13167c478bd9Sstevel@tonic-gate { 1317*b9bd317cSab196087 const char *name; 131892ed1782Smike_s size_t len; 13197c478bd9Sstevel@tonic-gate 1320*b9bd317cSab196087 name = conv_demangle_name(s); 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate if (strcmp(name, s) == 0) 13237c478bd9Sstevel@tonic-gate return (s); 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate if (format_buf != NULL) 13267c478bd9Sstevel@tonic-gate free(format_buf); 13277c478bd9Sstevel@tonic-gate 132892ed1782Smike_s len = strlen(name) + strlen(FORMAT_BUF) + strlen(s) + 1; 132992ed1782Smike_s format_buf = malloc(len); 13307c478bd9Sstevel@tonic-gate if (format_buf == NULL) 13317c478bd9Sstevel@tonic-gate return (s); 133292ed1782Smike_s (void) snprintf(format_buf, len, FORMAT_BUF, name, s); 13337c478bd9Sstevel@tonic-gate return (format_buf); 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate /* getname - get the name of a symbol in a permanent fashion */ 133792ed1782Smike_s static char * 133892ed1782Smike_s getname(PROF_FILE *ldpter, PROF_SYMBOL symbol) 13397c478bd9Sstevel@tonic-gate { 13407c478bd9Sstevel@tonic-gate static char *strtable = NULL; /* space for names */ 13417c478bd9Sstevel@tonic-gate static int sp_used = 0; /* space used so far */ 13427c478bd9Sstevel@tonic-gate static int size = 0; /* size of string table */ 134392ed1782Smike_s char *name; /* name to store */ 13447c478bd9Sstevel@tonic-gate int lth; /* space needed for name */ 13457c478bd9Sstevel@tonic-gate int get; /* amount of space to get */ 13467c478bd9Sstevel@tonic-gate 13477a5d89c4Sab196087 name = elf_strptr(ldpter->pf_elf_p, ldpter->pf_symstr_ndx, 13487a5d89c4Sab196087 symbol.ps_sym.st_name); 13497a5d89c4Sab196087 if (name == NULL) 13507c478bd9Sstevel@tonic-gate return ("<<bad symbol name>>"); 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate if (Cflag) 135392ed1782Smike_s name = demangled_name(name); 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate lth = strlen(name) + 1; 13567c478bd9Sstevel@tonic-gate if ((sp_used + lth) > size) { /* if need more space */ 13577c478bd9Sstevel@tonic-gate /* just in case very long name */ 13587c478bd9Sstevel@tonic-gate get = lth > STRSPACE ? lth : STRSPACE; 13597c478bd9Sstevel@tonic-gate strtable = _prof_Malloc(1, get); 13607c478bd9Sstevel@tonic-gate size = get; 13617c478bd9Sstevel@tonic-gate sp_used = 0; 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate (void) strcpy(&(strtable[sp_used]), name); 13647c478bd9Sstevel@tonic-gate name = &(strtable[sp_used]); 13657c478bd9Sstevel@tonic-gate sp_used += lth; 13667c478bd9Sstevel@tonic-gate return (name); 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate 136992ed1782Smike_s static void 137092ed1782Smike_s usage(void) 13717c478bd9Sstevel@tonic-gate { 137292ed1782Smike_s (void) fprintf(stderr, 137392ed1782Smike_s "usage: %s [-ChsVz] [-a | c | n | t] [-o | x] [-g | l]\n" 137492ed1782Smike_s "\t[-m mdata] [prog]\n", 137592ed1782Smike_s cmdname); 137692ed1782Smike_s exit(1); 13777c478bd9Sstevel@tonic-gate } 1378