1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 23*0Sstevel@tonic-gate /* All Rights Reserved */ 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate 26*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate /* 29*0Sstevel@tonic-gate * File: symintLoad.c 30*0Sstevel@tonic-gate * Date: 12/15/88 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * This file provides code to build the profiling symbol array 33*0Sstevel@tonic-gate * (array of PROF_SYMBOL). This array contains all of the 34*0Sstevel@tonic-gate * symbol table information plus selected debug information for 35*0Sstevel@tonic-gate * each file and each function that has a coverage array. 36*0Sstevel@tonic-gate * 37*0Sstevel@tonic-gate * The symbol table contains entries for every file, every 38*0Sstevel@tonic-gate * function, and every coverage array. The debug information 39*0Sstevel@tonic-gate * has corresponding entries except that there are no entries 40*0Sstevel@tonic-gate * for the coverage arrays. (This may change later.) 41*0Sstevel@tonic-gate * 42*0Sstevel@tonic-gate * The algorithm for building the profiling symbol array 43*0Sstevel@tonic-gate * consists of scanning the symbol table for file, function, 44*0Sstevel@tonic-gate * and coverage array entries and building an entry for each. 45*0Sstevel@tonic-gate * The construction of an entry is constrained by the 46*0Sstevel@tonic-gate * following factors: 47*0Sstevel@tonic-gate * 48*0Sstevel@tonic-gate * - An entry is built for every file. 49*0Sstevel@tonic-gate * 50*0Sstevel@tonic-gate * - An entry is built for a function only if there 51*0Sstevel@tonic-gate * is a corresponding coverage array for the function. 52*0Sstevel@tonic-gate * 53*0Sstevel@tonic-gate * - Entries must be ordered in the sense that each 54*0Sstevel@tonic-gate * non-file entry points to its owner file and each 55*0Sstevel@tonic-gate * file entry points to the next file (or null). 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * - The assembler specification (see C Issue 5 3B2 58*0Sstevel@tonic-gate * Assembler System Test Specification by Howe, p. 28) 59*0Sstevel@tonic-gate * states that all local symbols follow their file 60*0Sstevel@tonic-gate * symbol in the symbol table. This allows us to relate 61*0Sstevel@tonic-gate * a function and its coverage array to the file that 62*0Sstevel@tonic-gate * contains it. 63*0Sstevel@tonic-gate * 64*0Sstevel@tonic-gate * - For each symbol included in the profiling symbol 65*0Sstevel@tonic-gate * array, all corresponding symbol table information must 66*0Sstevel@tonic-gate * be present together with selected debug information. 67*0Sstevel@tonic-gate * Therefore, the correspondence between a symbol table 68*0Sstevel@tonic-gate * entry and a debug entry must be established. 69*0Sstevel@tonic-gate * 70*0Sstevel@tonic-gate * - Although duplicate (static) function names may appear, 71*0Sstevel@tonic-gate * the names are unique within a given file. Also, the 72*0Sstevel@tonic-gate * value (address) of each function is included in both 73*0Sstevel@tonic-gate * the symbol table information and the debug information. 74*0Sstevel@tonic-gate * This provides a verifable correspondence between these 75*0Sstevel@tonic-gate * information sets. 76*0Sstevel@tonic-gate * 77*0Sstevel@tonic-gate * The algorithm used in this file is as follows: 78*0Sstevel@tonic-gate */ 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* 83*0Sstevel@tonic-gate * This is a discussion of the problem of multiple files with a single 84*0Sstevel@tonic-gate * name. (See also, the _err_exit call in the routine "add_function".) 85*0Sstevel@tonic-gate * 86*0Sstevel@tonic-gate * Currently, when the executable contains more than one file with 87*0Sstevel@tonic-gate * a common name, we sometimes mix a set of functions with the wrong 88*0Sstevel@tonic-gate * file. Because the addresses don't match, add_profsymbol tends to 89*0Sstevel@tonic-gate * fail (with _err_exit). The problem is to consistently choose the 90*0Sstevel@tonic-gate * correct file for the set of functions that are about to be processed. 91*0Sstevel@tonic-gate * This aspect of the problem has been addressed by the code below, 92*0Sstevel@tonic-gate * but there is another part to the story. 93*0Sstevel@tonic-gate * 94*0Sstevel@tonic-gate * In order to match the symbol table with the debug information, we 95*0Sstevel@tonic-gate * have to strip the path (if any) off of the file name; that is, 96*0Sstevel@tonic-gate * the function _CAleaf is used to find the name of the file. This 97*0Sstevel@tonic-gate * means that even if we make the match, we may still have trouble 98*0Sstevel@tonic-gate * finding the file. One solution might be to retain a pointer to 99*0Sstevel@tonic-gate * the full name for use at the proper point (when lprof is trying 100*0Sstevel@tonic-gate * to find the source file). I have not traced this down completely; 101*0Sstevel@tonic-gate * it may or may not work depending upon whether the full path is 102*0Sstevel@tonic-gate * always included in the debug information. If it is not possible 103*0Sstevel@tonic-gate * to depend on the complete path, then there may be no way to completely 104*0Sstevel@tonic-gate * solve the problem. (Consider talking to the debugger people about 105*0Sstevel@tonic-gate * this problem; they have to deal with it also.) 106*0Sstevel@tonic-gate * 107*0Sstevel@tonic-gate * Below I have included the code I used to solve the first part of 108*0Sstevel@tonic-gate * the problem. I have also included an explanation of what each part 109*0Sstevel@tonic-gate * of the code does. When the code is implemented this way, it does 110*0Sstevel@tonic-gate * work for some cases, but I'm not sure that the assumptions it makes 111*0Sstevel@tonic-gate * are valid. In particular, it makes implicit assumptions about the 112*0Sstevel@tonic-gate * ordering of names and pointers; you should check that these assumptions 113*0Sstevel@tonic-gate * do not include that the values returned from malloc are monotone 114*0Sstevel@tonic-gate * increasing (which I think they do). 115*0Sstevel@tonic-gate * 116*0Sstevel@tonic-gate * With the following change, add_profsymbol will scan to the first 117*0Sstevel@tonic-gate * file entry of the given name that has not yet been processed. It 118*0Sstevel@tonic-gate * detects that a file has been processed by noting that sn_value_p 119*0Sstevel@tonic-gate * has been set to zero; it accepts the first one whose value is not 120*0Sstevel@tonic-gate * zero and calls dbfill_tag to "refill" the tag. Warning: setting 121*0Sstevel@tonic-gate * sn_value_p to zero is dangerous; in particular, you must avoid 122*0Sstevel@tonic-gate * trying to use this value when it is zero. Some cpus will produce 123*0Sstevel@tonic-gate * a segmentation violation, but the 3b2 does not. 124*0Sstevel@tonic-gate * 125*0Sstevel@tonic-gate * add_profsymbol() 126*0Sstevel@tonic-gate * { 127*0Sstevel@tonic-gate * ... 128*0Sstevel@tonic-gate * } else if (stchk_file(prsym_p)) { 129*0Sstevel@tonic-gate * if ( 130*0Sstevel@tonic-gate * (sn_p + 1) < (dblist + dblist_cnt) 131*0Sstevel@tonic-gate * && strcmp(sn_p[0].sn_name_p, sn_p[1].sn_name_p) == 0 132*0Sstevel@tonic-gate * ) { 133*0Sstevel@tonic-gate * _err_warn( 134*0Sstevel@tonic-gate * "File name %s was used more than once.", 135*0Sstevel@tonic-gate * sn_p->sn_name_p 136*0Sstevel@tonic-gate * ); 137*0Sstevel@tonic-gate * while ( 138*0Sstevel@tonic-gate * sn_p->sn_value_p == 0 139*0Sstevel@tonic-gate * && sn_p < (dblist + dblist_cnt) 140*0Sstevel@tonic-gate * ) { 141*0Sstevel@tonic-gate * sn_p++; 142*0Sstevel@tonic-gate * } 143*0Sstevel@tonic-gate * dbfill_tag(sn_p->sn_value_p, &tag); 144*0Sstevel@tonic-gate * } 145*0Sstevel@tonic-gate * sn_p->sn_value_p = 0; 146*0Sstevel@tonic-gate * add_file(&tag); 147*0Sstevel@tonic-gate * } else { 148*0Sstevel@tonic-gate * ... 149*0Sstevel@tonic-gate * } 150*0Sstevel@tonic-gate * 151*0Sstevel@tonic-gate * The change to sn_search is only to prepare for a call to sn_compare 152*0Sstevel@tonic-gate * which has been changed to compare on both the name and the pointer 153*0Sstevel@tonic-gate * value (instead of just the name). (Here, we might be using the 154*0Sstevel@tonic-gate * incorrect assumption that malloc is monotone increasing; this scheme 155*0Sstevel@tonic-gate * should be carefully thought out.) The change consists of setting 156*0Sstevel@tonic-gate * the sn_value_p in the local tnode to zero; this allows sn_compare 157*0Sstevel@tonic-gate * to ignore the value and compare only the name. 158*0Sstevel@tonic-gate * 159*0Sstevel@tonic-gate * sn_search() 160*0Sstevel@tonic-gate * { 161*0Sstevel@tonic-gate * ... 162*0Sstevel@tonic-gate * tnode.sn_name_p = name_p; 163*0Sstevel@tonic-gate * tnode.sn_value_p = 0; 164*0Sstevel@tonic-gate * ... 165*0Sstevel@tonic-gate * } 166*0Sstevel@tonic-gate * 167*0Sstevel@tonic-gate * This routine used to compare only the name; now it compares both 168*0Sstevel@tonic-gate * the name and the sn_value_p pointer (see note above sn_search). 169*0Sstevel@tonic-gate * When the value pointer is zero, there is no use in comparing 170*0Sstevel@tonic-gate * that part of the item. 171*0Sstevel@tonic-gate * 172*0Sstevel@tonic-gate * sn_compare() 173*0Sstevel@tonic-gate * { 174*0Sstevel@tonic-gate * register int i; 175*0Sstevel@tonic-gate * 176*0Sstevel@tonic-gate * if (i = strcmp(a_p->sn_name_p, b_p->sn_name_p)) { 177*0Sstevel@tonic-gate * return(i); 178*0Sstevel@tonic-gate * } else if (a_p->sn_value_p == 0 || b_p->sn_value_p == 0) { 179*0Sstevel@tonic-gate * return(i); 180*0Sstevel@tonic-gate * } else if (a_p->sn_value_p < b_p->sn_value_p) { 181*0Sstevel@tonic-gate * return(-1); 182*0Sstevel@tonic-gate * } else { 183*0Sstevel@tonic-gate * return(1); 184*0Sstevel@tonic-gate * } 185*0Sstevel@tonic-gate * } 186*0Sstevel@tonic-gate */ 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate #include "string.h" 190*0Sstevel@tonic-gate #include "symint.h" 191*0Sstevel@tonic-gate #include "debug.h" 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate /* search node */ 194*0Sstevel@tonic-gate typedef struct { 195*0Sstevel@tonic-gate char *sn_name_p; 196*0Sstevel@tonic-gate char *sn_value_p; 197*0Sstevel@tonic-gate } SEARCH_NODE; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate PROF_SYMBOL * _symintLoad(); 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate #if isLPROF 203*0Sstevel@tonic-gate static int addcovset(); 204*0Sstevel@tonic-gate static SEARCH_NODE *build_stlist(); 205*0Sstevel@tonic-gate static int stscan(); 206*0Sstevel@tonic-gate static int stchk_focov(); 207*0Sstevel@tonic-gate static int stchk_filowog(); 208*0Sstevel@tonic-gate static int stchk_gowf(); 209*0Sstevel@tonic-gate static int stchk_func(); 210*0Sstevel@tonic-gate static int stchk_file(); 211*0Sstevel@tonic-gate static int stchk_cov(); 212*0Sstevel@tonic-gate static int stchk_match(); 213*0Sstevel@tonic-gate static void init_dblist(); 214*0Sstevel@tonic-gate static int dbscan_tag(); 215*0Sstevel@tonic-gate static void dbfill_tag(); 216*0Sstevel@tonic-gate static char * dbseek_att(); 217*0Sstevel@tonic-gate static int dbchk_stmnts(); 218*0Sstevel@tonic-gate static int dbchk_lowpc(); 219*0Sstevel@tonic-gate static int dbchk_highpc(); 220*0Sstevel@tonic-gate static int dbchk_filosub(); 221*0Sstevel@tonic-gate static PROF_SYMBOL * add_profsymbol(); 222*0Sstevel@tonic-gate static int add_function(); 223*0Sstevel@tonic-gate static void add_file(); 224*0Sstevel@tonic-gate static void check_capacity(); 225*0Sstevel@tonic-gate static char * debName(); 226*0Sstevel@tonic-gate static LEN4 bytesFor(); 227*0Sstevel@tonic-gate static SEARCH_NODE * sn_search(); 228*0Sstevel@tonic-gate static int sn_compare(); 229*0Sstevel@tonic-gate #ifdef DEBUG 230*0Sstevel@tonic-gate static void sn_dump(); 231*0Sstevel@tonic-gate static void profsym_dump(); 232*0Sstevel@tonic-gate #endif 233*0Sstevel@tonic-gate static LEN2 alignval2(); 234*0Sstevel@tonic-gate static LEN4 alignval4(); 235*0Sstevel@tonic-gate static void verify_match(); 236*0Sstevel@tonic-gate #endif 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate /* debug tag */ 240*0Sstevel@tonic-gate typedef struct { 241*0Sstevel@tonic-gate LEN4 tg_length; 242*0Sstevel@tonic-gate LEN2 tg_value; 243*0Sstevel@tonic-gate char *tg_att_p; 244*0Sstevel@tonic-gate int tg_attlen; 245*0Sstevel@tonic-gate } DB_TAG; 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate /* 248*0Sstevel@tonic-gate * Debug list used to connect a symbol table entry to a debug entry. 249*0Sstevel@tonic-gate */ 250*0Sstevel@tonic-gate static SEARCH_NODE *dblist; /* array */ 251*0Sstevel@tonic-gate static int dblist_cnt; /* number of elements in array */ 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * Global symbol table list used to connect coverage array entries 255*0Sstevel@tonic-gate * with their (global) owner functions. This list contains all 256*0Sstevel@tonic-gate * global and weak functions. 257*0Sstevel@tonic-gate */ 258*0Sstevel@tonic-gate static SEARCH_NODE *gstlist; /* array */ 259*0Sstevel@tonic-gate static int gstlist_cnt; /* number of elements in array */ 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate static PROF_FILE *profPtr; 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate #define ST_NAME(a) &profPtr->pf_symstr_p[(a)->st_name] 264*0Sstevel@tonic-gate #define PS_NAME(a) &profPtr->pf_symstr_p[(a)->ps_sym.st_name] 265*0Sstevel@tonic-gate #define DB_NAME(a) (a)->ps_dbg.pd_name 266*0Sstevel@tonic-gate #define DB_TAGLEN(ap) alignval4(ap) 267*0Sstevel@tonic-gate #define DB_STMNTOS(ap) alignval4((ap) + sizeof(LEN2)) 268*0Sstevel@tonic-gate #define DB_PCVALUE(ap) alignval4((ap) + sizeof(LEN2)) 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * NOTE: When you change MATCH_STR, also change pcrt1.s. 272*0Sstevel@tonic-gate * (See notes on "verify_match" below.) 273*0Sstevel@tonic-gate */ 274*0Sstevel@tonic-gate #ifdef __STDC__ 275*0Sstevel@tonic-gate #define MATCH_NAME _edata 276*0Sstevel@tonic-gate #define MATCH_STR "_edata" 277*0Sstevel@tonic-gate #else 278*0Sstevel@tonic-gate #define MATCH_NAME edata 279*0Sstevel@tonic-gate #define MATCH_STR "edata" 280*0Sstevel@tonic-gate #endif 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate static PROF_SYMBOL *prsym_list_p = 0; /* the list to return. */ 283*0Sstevel@tonic-gate static int prsym_cnt = 0; /* #entries in the list */ 284*0Sstevel@tonic-gate static int prsym_cap = 0; /* #entries capacity allocated */ 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate static int prstsym_size; /* size of a symbol table symbol */ 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate static int add_profsym_search_fail; /* see add_profsymbol() */ 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate #if isLPROF 291*0Sstevel@tonic-gate static int prsym_size; /* size of a PROF_SYMBOL */ 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate /* * * * * * 295*0Sstevel@tonic-gate * addr of line information, and of the PROF_DEBUGE, 296*0Sstevel@tonic-gate * associated with the last file (symbol) seen. 297*0Sstevel@tonic-gate * 298*0Sstevel@tonic-gate * also, the DEBUGE for the file in effect Before the current one! 299*0Sstevel@tonic-gate */ 300*0Sstevel@tonic-gate #define DBG_LINE_SIZE (sizeof(LEN4) + sizeof(LEN2) + sizeof(LEN4)) 301*0Sstevel@tonic-gate static char *curf_lp; 302*0Sstevel@tonic-gate static LEN4 curf_lncnt; 303*0Sstevel@tonic-gate static LEN4 curf_base; 304*0Sstevel@tonic-gate static PROF_LINE *curf_lns_p; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate static PROF_DEBUGE *curf_dbp; 307*0Sstevel@tonic-gate static PROF_DEBUGE *priorFile_dbp; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate #endif 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate /* * * * * * 312*0Sstevel@tonic-gate * _symintLoad(proffilePtr) 313*0Sstevel@tonic-gate * proffilePtr - PROF_FILE pointer returned by _symintOpen(). 314*0Sstevel@tonic-gate * 315*0Sstevel@tonic-gate * returns PROF_SYMBOL * - pointer to the malloc-ed array of 316*0Sstevel@tonic-gate * symbol information entries, or 317*0Sstevel@tonic-gate * NULL if fails. 318*0Sstevel@tonic-gate * 319*0Sstevel@tonic-gate * 320*0Sstevel@tonic-gate * This routine builds the interface data structure from the data 321*0Sstevel@tonic-gate * already loaded during _symintOpen(). 322*0Sstevel@tonic-gate * 323*0Sstevel@tonic-gate * There are two different incarnations of this routine: 324*0Sstevel@tonic-gate * one for Prof, and one for Lprof. 325*0Sstevel@tonic-gate * 326*0Sstevel@tonic-gate * Lprof: 327*0Sstevel@tonic-gate * 328*0Sstevel@tonic-gate * 1. Pass through the symbol table and 329*0Sstevel@tonic-gate * populate an extended PROF_SYMBOL array. 330*0Sstevel@tonic-gate * 331*0Sstevel@tonic-gate * 2. Include only certain symbols (see intro). 332*0Sstevel@tonic-gate * 333*0Sstevel@tonic-gate * 3. Find and include the debug information 334*0Sstevel@tonic-gate * for each included symbol. 335*0Sstevel@tonic-gate * 336*0Sstevel@tonic-gate * Prof: 337*0Sstevel@tonic-gate * 338*0Sstevel@tonic-gate * 1. Allocate a duplicate copy of the symbol table 339*0Sstevel@tonic-gate * data. (For Prof, a PROF_SYMBOL is just 340*0Sstevel@tonic-gate * a structure containing an Elf32_Sym!) 341*0Sstevel@tonic-gate * 342*0Sstevel@tonic-gate * 2. Set internal parameters to reflect this. 343*0Sstevel@tonic-gate * 344*0Sstevel@tonic-gate * 345*0Sstevel@tonic-gate * Problems are dealt with by issuing an _err_exit(). 346*0Sstevel@tonic-gate * 347*0Sstevel@tonic-gate */ 348*0Sstevel@tonic-gate PROF_SYMBOL * 349*0Sstevel@tonic-gate _symintLoad(proffilePtr) 350*0Sstevel@tonic-gate PROF_FILE *proffilePtr; 351*0Sstevel@tonic-gate { 352*0Sstevel@tonic-gate Elf_Data *symdat_p; 353*0Sstevel@tonic-gate PROF_SYMBOL *ps; 354*0Sstevel@tonic-gate int symcount = 0; 355*0Sstevel@tonic-gate #if isLPROF 356*0Sstevel@tonic-gate Elf32_Sym *sym_p; 357*0Sstevel@tonic-gate Elf32_Sym *sym_lim_p; 358*0Sstevel@tonic-gate Elf32_Sym *next_p; 359*0Sstevel@tonic-gate Elf32_Sym *tsym_p; 360*0Sstevel@tonic-gate #endif 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate DEBUG_LOC("_symintLoad: top"); 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate profPtr = proffilePtr; 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate /* * * * * * 367*0Sstevel@tonic-gate * sanity checks. 368*0Sstevel@tonic-gate */ 369*0Sstevel@tonic-gate DEBUG_EXP(printf("profPtr = %x\n", profPtr)); 370*0Sstevel@tonic-gate DEBUG_EXP(printf("profPtr->pf_symdat_p = %x\n", profPtr->pf_symdat_p)); 371*0Sstevel@tonic-gate DEBUG_EXP(printf("profPtr->pf_nstsyms = %x\n", profPtr->pf_nstsyms)); 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate assert( profPtr != 0 ); 374*0Sstevel@tonic-gate assert( profPtr->pf_symdat_p != 0 ); 375*0Sstevel@tonic-gate assert( profPtr->pf_nstsyms != 0 ); 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate symdat_p = profPtr->pf_symdat_p; 378*0Sstevel@tonic-gate DEBUG_EXP(printf("symdat_p->d_size = %x\n", symdat_p->d_size)); 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate prstsym_size = (symdat_p->d_size / profPtr->pf_nstsyms); 381*0Sstevel@tonic-gate DEBUG_EXP(printf("_symintLoad: prstsym_size = %d\n",prstsym_size)); 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate #if isLPROF 384*0Sstevel@tonic-gate prsym_size = prstsym_size + sizeof(PROF_DEBUGE); 385*0Sstevel@tonic-gate DEBUG_EXP(printf("_symintLoad: prsym_size = %d\n",prsym_size)); 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate /* * * * * * 388*0Sstevel@tonic-gate * Initialize structure parameters. Updated by add_profsymbol(). 389*0Sstevel@tonic-gate */ 390*0Sstevel@tonic-gate prsym_cnt = prsym_cap = 0; 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate init_dblist(); 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate sym_lim_p = (Elf32_Sym *) 395*0Sstevel@tonic-gate (((char *) (symdat_p->d_buf)) + symdat_p->d_size); 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate tsym_p = NULL; 398*0Sstevel@tonic-gate gstlist = build_stlist(tsym_p, sym_lim_p, stchk_gowf, &gstlist_cnt); 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate verify_match(); 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate next_p = NULL; 403*0Sstevel@tonic-gate (void) stscan(&next_p, sym_lim_p, stchk_file); 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate priorFile_dbp = 0; 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate sym_p = next_p; 408*0Sstevel@tonic-gate while (sym_p < sym_lim_p) { 409*0Sstevel@tonic-gate NO_DEBUG(printf("index for sym_p = %d\n",sym_p->st_name)); 410*0Sstevel@tonic-gate NO_DEBUG(printf("name for sym_p = %s\n", ST_NAME(sym_p))); 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate (void) stscan(&next_p, sym_lim_p, stchk_filowog); 413*0Sstevel@tonic-gate tsym_p = sym_p; 414*0Sstevel@tonic-gate if (stscan(&tsym_p, next_p, stchk_cov)) { 415*0Sstevel@tonic-gate symcount += addcovset(sym_p, next_p, tsym_p); 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate if (!stchk_file(next_p)) { 418*0Sstevel@tonic-gate (void) stscan(&next_p, sym_lim_p, stchk_file); 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate sym_p = next_p; 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate free(gstlist); 424*0Sstevel@tonic-gate profPtr->pf_nsyms = symcount; 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate DEBUG_EXP(printf("number of symbols constructed = %d\n", symcount)); 427*0Sstevel@tonic-gate #ifdef DEBUG 428*0Sstevel@tonic-gate printf("before profsym_dump\n"); 429*0Sstevel@tonic-gate profsym_dump(prsym_list_p, symcount); 430*0Sstevel@tonic-gate printf("after profsym_dump\n"); 431*0Sstevel@tonic-gate #endif 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate #else /* isPROF */ 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate /* * * * * * 436*0Sstevel@tonic-gate * alloc a new copy of the array, and 437*0Sstevel@tonic-gate * do a bit-wise copy since the structures 438*0Sstevel@tonic-gate * ARE THE SAME SIZE & (effectively) HAVE THE SAME FIELDS! 439*0Sstevel@tonic-gate * Set the descriptive `parameters' accordingly. 440*0Sstevel@tonic-gate * 441*0Sstevel@tonic-gate * (We'll take a copy, to simplify the 'Drop' 442*0Sstevel@tonic-gate * logic.) 443*0Sstevel@tonic-gate */ 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate { 446*0Sstevel@tonic-gate int st_size; /* size of symbol table data */ 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate st_size = symdat_p->d_size; 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate NO_DEBUG_LOC("_symintLoad: before malloc for symbol list (PROF)"); 451*0Sstevel@tonic-gate prsym_list_p = (PROF_SYMBOL *) _Malloc(st_size, 1); 452*0Sstevel@tonic-gate NO_DEBUG_LOC("_symintLoad: after malloc for symbol list (PROF)"); 453*0Sstevel@tonic-gate prsym_cap = prsym_cnt = profPtr->pf_nstsyms; 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate NO_DEBUG_LOC("_symintLoad: before memcpy for symbol list (PROF)"); 456*0Sstevel@tonic-gate memcpy((char *) &(prsym_list_p->ps_sym), symdat_p->d_buf, st_size); 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate profPtr->pf_nsyms = profPtr->pf_nstsyms; 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate #endif 462*0Sstevel@tonic-gate DEBUG_LOC("_symintLoad: bottom"); 463*0Sstevel@tonic-gate return( prsym_list_p ); 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate #ifdef isLPROF 468*0Sstevel@tonic-gate /* 469*0Sstevel@tonic-gate * addcovset: Add coverage array set to PROF_SYMBOL array. 470*0Sstevel@tonic-gate * 471*0Sstevel@tonic-gate * The (local) symbols between the given file symbol and the 472*0Sstevel@tonic-gate * end contain at least one coverage array. Sort all function 473*0Sstevel@tonic-gate * and coverage array symbols (by name) within the given bounds 474*0Sstevel@tonic-gate * and process each of the coverage array symbols by finding 475*0Sstevel@tonic-gate * its corresponding (local or global) function and adding entries 476*0Sstevel@tonic-gate * for both the coverage array and the function to the profile 477*0Sstevel@tonic-gate * symbol array. Note that the file is also added to the profile 478*0Sstevel@tonic-gate * symbol array and that pointers are managed accordingly (the file 479*0Sstevel@tonic-gate * entries are linked and each of the non-file entries points 480*0Sstevel@tonic-gate * to its owner file). 481*0Sstevel@tonic-gate * 482*0Sstevel@tonic-gate * - Add the file to the PROF_SYMBOL array. If the file is not 483*0Sstevel@tonic-gate * found (i.e., the filename in the debug information does not 484*0Sstevel@tonic-gate * match the filename in the symbol table), then fail. 485*0Sstevel@tonic-gate * - Build (allocate) a sorted list of all function and coverage 486*0Sstevel@tonic-gate * array symbols within the given limits. 487*0Sstevel@tonic-gate * - Find the top of the coverage array subset of the pointer list. 488*0Sstevel@tonic-gate * - For each coverage array pointer: 489*0Sstevel@tonic-gate * - Find its function (look in local list, then global list). 490*0Sstevel@tonic-gate * - Add function and assoc coverage array to PROF_SYMBOL array. 491*0Sstevel@tonic-gate * - Free the sorted list. 492*0Sstevel@tonic-gate * 493*0Sstevel@tonic-gate * Note: "k" is used to avoid having "cov_p" increment beyond 494*0Sstevel@tonic-gate * the last allocated search node and thereby (possibly) cause 495*0Sstevel@tonic-gate * a segmentation violation. 496*0Sstevel@tonic-gate */ 497*0Sstevel@tonic-gate static int 498*0Sstevel@tonic-gate addcovset(filsym_p, end_p, cov_p) 499*0Sstevel@tonic-gate Elf32_Sym *filsym_p; 500*0Sstevel@tonic-gate Elf32_Sym *end_p; 501*0Sstevel@tonic-gate Elf32_Sym *cov_p; 502*0Sstevel@tonic-gate { 503*0Sstevel@tonic-gate SEARCH_NODE *stl_p; 504*0Sstevel@tonic-gate SEARCH_NODE *sncov_p; 505*0Sstevel@tonic-gate SEARCH_NODE *snfunc_p; 506*0Sstevel@tonic-gate PROF_SYMBOL *ps_p; 507*0Sstevel@tonic-gate int k, stlcount; 508*0Sstevel@tonic-gate char *fname_p; 509*0Sstevel@tonic-gate int symcount = 0; 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate DEBUG_LOC("addcovset: top"); 512*0Sstevel@tonic-gate ps_p = add_profsymbol(filsym_p); 513*0Sstevel@tonic-gate if (add_profsym_search_fail) { 514*0Sstevel@tonic-gate _err_exit("Unable to locate file %s in debug information.\n", 515*0Sstevel@tonic-gate ST_NAME(filsym_p) 516*0Sstevel@tonic-gate ); 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate ps_p->ps_dbg.pd_file_p = 0; 519*0Sstevel@tonic-gate symcount++; 520*0Sstevel@tonic-gate DEBUG_EXP(printf("debug name for ps_p = %s\n", DB_NAME(ps_p))); 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate curf_dbp = &(ps_p->ps_dbg); 523*0Sstevel@tonic-gate if (priorFile_dbp) { 524*0Sstevel@tonic-gate priorFile_dbp->pd_file_p = curf_dbp; 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate priorFile_dbp = curf_dbp; 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate stl_p = build_stlist(filsym_p, end_p, stchk_focov, &stlcount); 529*0Sstevel@tonic-gate sncov_p = sn_search(ST_NAME(cov_p), stl_p, stlcount); 530*0Sstevel@tonic-gate while ( 531*0Sstevel@tonic-gate (sncov_p-1) >= stl_p 532*0Sstevel@tonic-gate && strncmp( 533*0Sstevel@tonic-gate (sncov_p-1)->sn_name_p, 534*0Sstevel@tonic-gate COV_PREFIX, 535*0Sstevel@tonic-gate sizeof(COV_PREFIX)-1 536*0Sstevel@tonic-gate ) == 0 537*0Sstevel@tonic-gate ) { 538*0Sstevel@tonic-gate sncov_p--; 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate k = stlcount; 542*0Sstevel@tonic-gate while (k-- > 0 && stchk_cov((Elf32_Sym *) (sncov_p->sn_value_p))) { 543*0Sstevel@tonic-gate fname_p = (char *) &(sncov_p->sn_name_p[sizeof(COV_PREFIX)-1]); 544*0Sstevel@tonic-gate if ( 545*0Sstevel@tonic-gate (snfunc_p = sn_search(fname_p, stl_p, stlcount)) 546*0Sstevel@tonic-gate || (snfunc_p = sn_search(fname_p, gstlist, gstlist_cnt)) 547*0Sstevel@tonic-gate ) { 548*0Sstevel@tonic-gate ps_p = add_profsymbol(snfunc_p->sn_value_p); 549*0Sstevel@tonic-gate ps_p->ps_dbg.pd_file_p = curf_dbp; 550*0Sstevel@tonic-gate symcount++; 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate ps_p = add_profsymbol(sncov_p->sn_value_p); 553*0Sstevel@tonic-gate ps_p->ps_dbg.pd_file_p = curf_dbp; 554*0Sstevel@tonic-gate symcount++; 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate sncov_p++; 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate free(stl_p); 560*0Sstevel@tonic-gate DEBUG_LOC("addcovset: bottom"); 561*0Sstevel@tonic-gate return(symcount); 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * build_stlist: Build a tailored list of symbol table entries. 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate static SEARCH_NODE * 569*0Sstevel@tonic-gate build_stlist(begin_p, end_p, filter_p, count_p) 570*0Sstevel@tonic-gate Elf32_Sym *begin_p; 571*0Sstevel@tonic-gate Elf32_Sym *end_p; 572*0Sstevel@tonic-gate int (*filter_p)(); 573*0Sstevel@tonic-gate int *count_p; 574*0Sstevel@tonic-gate { 575*0Sstevel@tonic-gate Elf32_Sym *tsym_p; 576*0Sstevel@tonic-gate SEARCH_NODE *list_p; 577*0Sstevel@tonic-gate int i, count; 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate DEBUG_LOC("build_stlist: top"); 580*0Sstevel@tonic-gate DEBUG_EXP(printf("begin_p = 0x%lx, end_p = 0x%lx\n", begin_p, end_p)); 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate count = 0; 583*0Sstevel@tonic-gate tsym_p = begin_p; 584*0Sstevel@tonic-gate while (stscan(&tsym_p, end_p, filter_p)) { 585*0Sstevel@tonic-gate count++; 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate DEBUG_EXP(printf("count = %d\n",count)); 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate list_p = (SEARCH_NODE *) _Malloc(count, sizeof(*list_p)); 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate i = 0; 592*0Sstevel@tonic-gate tsym_p = begin_p; 593*0Sstevel@tonic-gate while (stscan(&tsym_p, end_p, filter_p)) { 594*0Sstevel@tonic-gate list_p[i].sn_name_p = ST_NAME(tsym_p); 595*0Sstevel@tonic-gate list_p[i].sn_value_p = (char *) tsym_p; 596*0Sstevel@tonic-gate i++; 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate DEBUG_EXP(sn_dump("symbol table (pre sort)", list_p, count)); 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate qsort(list_p, count, sizeof(*list_p), sn_compare); 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate DEBUG_EXP(sn_dump("symbol table (post sort)", list_p, count)); 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate DEBUG_LOC("build_stlist: bottom"); 605*0Sstevel@tonic-gate *count_p = count; 606*0Sstevel@tonic-gate return(list_p); 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate /* 611*0Sstevel@tonic-gate * stscan - symbol table scan 612*0Sstevel@tonic-gate * 613*0Sstevel@tonic-gate * Scan the symbol table until the given limit is reached or 614*0Sstevel@tonic-gate * the filter function returns true. Neither the starting 615*0Sstevel@tonic-gate * symbol (**sym_pp) nor the limit symbol (*lim_p) are legal 616*0Sstevel@tonic-gate * return values. Instead, if the starting pointer is NULL, 617*0Sstevel@tonic-gate * then the first item in the table is a valid return value. 618*0Sstevel@tonic-gate * This allows the routine to be used as a generator by 619*0Sstevel@tonic-gate * starting from where the last call stopped. 620*0Sstevel@tonic-gate */ 621*0Sstevel@tonic-gate static int 622*0Sstevel@tonic-gate stscan(sym_pp, lim_p, filter_p) 623*0Sstevel@tonic-gate Elf32_Sym **sym_pp; 624*0Sstevel@tonic-gate Elf32_Sym *lim_p; 625*0Sstevel@tonic-gate int (*filter_p)(); 626*0Sstevel@tonic-gate { 627*0Sstevel@tonic-gate if (*sym_pp == NULL) { 628*0Sstevel@tonic-gate *sym_pp = (Elf32_Sym *) (profPtr->pf_symdat_p->d_buf); 629*0Sstevel@tonic-gate } else { 630*0Sstevel@tonic-gate *sym_pp = (Elf32_Sym *) ((char *) (*sym_pp) + prstsym_size); 631*0Sstevel@tonic-gate } 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate while (*sym_pp < lim_p) { 634*0Sstevel@tonic-gate if ((*filter_p)(*sym_pp)) { 635*0Sstevel@tonic-gate return(1); 636*0Sstevel@tonic-gate } 637*0Sstevel@tonic-gate *sym_pp = (Elf32_Sym *) ((char *) (*sym_pp) + prstsym_size); 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate return(0); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate /* 644*0Sstevel@tonic-gate * These routines check the type of a symbol table entry. 645*0Sstevel@tonic-gate */ 646*0Sstevel@tonic-gate static int 647*0Sstevel@tonic-gate stchk_focov(sym_p) /* symbol is function or coverage array */ 648*0Sstevel@tonic-gate Elf32_Sym *sym_p; { 649*0Sstevel@tonic-gate return(stchk_func(sym_p) || stchk_cov(sym_p)); 650*0Sstevel@tonic-gate } 651*0Sstevel@tonic-gate static int 652*0Sstevel@tonic-gate stchk_filowog(sym_p) /* symbol is a file, a weak, or a global */ 653*0Sstevel@tonic-gate Elf32_Sym *sym_p; { 654*0Sstevel@tonic-gate return( 655*0Sstevel@tonic-gate stchk_file(sym_p) 656*0Sstevel@tonic-gate || ELF32_ST_BIND(sym_p->st_info) == STB_GLOBAL 657*0Sstevel@tonic-gate || ELF32_ST_BIND(sym_p->st_info) == STB_WEAK 658*0Sstevel@tonic-gate ); 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate static int 661*0Sstevel@tonic-gate stchk_gowf(sym_p) /* symbol is global or weak function */ 662*0Sstevel@tonic-gate Elf32_Sym *sym_p; { 663*0Sstevel@tonic-gate return( 664*0Sstevel@tonic-gate (stchk_func(sym_p) || stchk_match(sym_p)) 665*0Sstevel@tonic-gate && ( 666*0Sstevel@tonic-gate ELF32_ST_BIND(sym_p->st_info) == STB_GLOBAL 667*0Sstevel@tonic-gate || ELF32_ST_BIND(sym_p->st_info) == STB_WEAK 668*0Sstevel@tonic-gate ) 669*0Sstevel@tonic-gate ); 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate static int 672*0Sstevel@tonic-gate stchk_func(sym_p) /* symbol is a function */ 673*0Sstevel@tonic-gate Elf32_Sym *sym_p; { 674*0Sstevel@tonic-gate return(ELF32_ST_TYPE(sym_p->st_info) == STT_FUNC); 675*0Sstevel@tonic-gate } 676*0Sstevel@tonic-gate static int 677*0Sstevel@tonic-gate stchk_file(sym_p) /* symbol is a file */ 678*0Sstevel@tonic-gate Elf32_Sym *sym_p; { 679*0Sstevel@tonic-gate return(ELF32_ST_TYPE(sym_p->st_info) == STT_FILE); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate static int 682*0Sstevel@tonic-gate stchk_cov(sym_p) /* symbol is a coverage array */ 683*0Sstevel@tonic-gate Elf32_Sym *sym_p; { 684*0Sstevel@tonic-gate return( 685*0Sstevel@tonic-gate strncmp(ST_NAME(sym_p), COV_PREFIX, sizeof(COV_PREFIX)-1) == 0 686*0Sstevel@tonic-gate ); 687*0Sstevel@tonic-gate } 688*0Sstevel@tonic-gate static int 689*0Sstevel@tonic-gate stchk_match(sym_p) /* symbol is the match symbol */ 690*0Sstevel@tonic-gate Elf32_Sym *sym_p; { 691*0Sstevel@tonic-gate return( 692*0Sstevel@tonic-gate strncmp(ST_NAME(sym_p), MATCH_STR, sizeof(MATCH_STR)-1) == 0 693*0Sstevel@tonic-gate ); 694*0Sstevel@tonic-gate } 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate /* 698*0Sstevel@tonic-gate * Initialize debug array (dblist). 699*0Sstevel@tonic-gate * 700*0Sstevel@tonic-gate * This routine prepares the debug array for searching (see 701*0Sstevel@tonic-gate * also fillout_sym_dbinfo). 702*0Sstevel@tonic-gate * 703*0Sstevel@tonic-gate * Initialization proceeds as follows: 704*0Sstevel@tonic-gate * 705*0Sstevel@tonic-gate * - Count the debug entries that we care about. 706*0Sstevel@tonic-gate * - _Malloc space to contain the pointers. 707*0Sstevel@tonic-gate * - Extract pointers and fill in array. 708*0Sstevel@tonic-gate * - Sort entries alphabetically by name. 709*0Sstevel@tonic-gate */ 710*0Sstevel@tonic-gate static void 711*0Sstevel@tonic-gate init_dblist() 712*0Sstevel@tonic-gate { 713*0Sstevel@tonic-gate DB_TAG tag; 714*0Sstevel@tonic-gate char *cur_p; 715*0Sstevel@tonic-gate char *lim_p; 716*0Sstevel@tonic-gate Elf_Data *dat_p; 717*0Sstevel@tonic-gate int k; 718*0Sstevel@tonic-gate extern char *_CAleaf(); 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate DEBUG_LOC("init_dblist: top"); 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate dat_p = profPtr->pf_debugdat_p; 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate DEBUG_EXP(printf("dat_p = 0x%lx, d_buf = 0x%x, d_size = %d\n", 725*0Sstevel@tonic-gate dat_p, dat_p->d_buf, dat_p->d_size 726*0Sstevel@tonic-gate )); 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate lim_p = (char *) (dat_p->d_buf) + dat_p->d_size; 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate dblist_cnt = 0; 731*0Sstevel@tonic-gate cur_p = NULL; 732*0Sstevel@tonic-gate while (dbscan_tag(&cur_p, lim_p, &tag, dbchk_filosub)) { 733*0Sstevel@tonic-gate dblist_cnt++; 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate dblist = (SEARCH_NODE *) _Malloc(dblist_cnt, sizeof(*dblist)); 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate DEBUG_EXP(printf("dblist_cnt = %d\n",dblist_cnt)); 739*0Sstevel@tonic-gate DEBUG_EXP(printf("dblist = 0x%lx\n", dblist)); 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate k = 0; 742*0Sstevel@tonic-gate cur_p = NULL; 743*0Sstevel@tonic-gate while (dbscan_tag(&cur_p, lim_p, &tag, dbchk_filosub)) { 744*0Sstevel@tonic-gate dblist[k].sn_name_p = 745*0Sstevel@tonic-gate _CAleaf(debName(tag.tg_att_p, tag.tg_attlen)); 746*0Sstevel@tonic-gate dblist[k].sn_value_p = cur_p; 747*0Sstevel@tonic-gate k++; 748*0Sstevel@tonic-gate } 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate DEBUG_EXP(sn_dump("debug info (pre sort)", dblist, dblist_cnt)); 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate qsort(dblist, dblist_cnt, sizeof(*dblist), sn_compare); 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate DEBUG_EXP(sn_dump("debug info (post sort)", dblist, dblist_cnt)); 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate DEBUG_LOC("init_dblist: bottom"); 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate /* 761*0Sstevel@tonic-gate * Search for a given tag from the given starting point in 762*0Sstevel@tonic-gate * the debug information. If found, fill in the tag at the 763*0Sstevel@tonic-gate * given pointer and return 1. Otherwise, return 0. 764*0Sstevel@tonic-gate */ 765*0Sstevel@tonic-gate static int 766*0Sstevel@tonic-gate dbscan_tag(dbpos_pp, dblim_p, tag_p, filter_p) 767*0Sstevel@tonic-gate char **dbpos_pp; 768*0Sstevel@tonic-gate char *dblim_p; 769*0Sstevel@tonic-gate DB_TAG *tag_p; 770*0Sstevel@tonic-gate int (*filter_p)(); 771*0Sstevel@tonic-gate { 772*0Sstevel@tonic-gate NO_DEBUG_LOC("dbscan_tag: top"); 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate if (*dbpos_pp == NULL) { 775*0Sstevel@tonic-gate *dbpos_pp = profPtr->pf_debugdat_p->d_buf; 776*0Sstevel@tonic-gate } else { 777*0Sstevel@tonic-gate *dbpos_pp += DB_TAGLEN(*dbpos_pp); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate while (*dbpos_pp < dblim_p) { 781*0Sstevel@tonic-gate dbfill_tag(*dbpos_pp, tag_p); 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate if ((*filter_p)(tag_p->tg_value)) { 784*0Sstevel@tonic-gate goto success; 785*0Sstevel@tonic-gate } 786*0Sstevel@tonic-gate *dbpos_pp += tag_p->tg_length; 787*0Sstevel@tonic-gate } 788*0Sstevel@tonic-gate return(0); 789*0Sstevel@tonic-gate success:; 790*0Sstevel@tonic-gate return(1); 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate static void 794*0Sstevel@tonic-gate dbfill_tag(dbpos_p, tag_p) 795*0Sstevel@tonic-gate char *dbpos_p; 796*0Sstevel@tonic-gate DB_TAG *tag_p; 797*0Sstevel@tonic-gate { 798*0Sstevel@tonic-gate tag_p->tg_length = DB_TAGLEN(dbpos_p); 799*0Sstevel@tonic-gate tag_p->tg_value = alignval2(dbpos_p + sizeof(LEN4)); 800*0Sstevel@tonic-gate tag_p->tg_att_p = dbpos_p + sizeof(LEN4) + sizeof(LEN2); 801*0Sstevel@tonic-gate tag_p->tg_attlen = tag_p->tg_length - sizeof(LEN4) - sizeof(LEN2); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate /* 806*0Sstevel@tonic-gate * Search the given tag for the given attribute(s). 807*0Sstevel@tonic-gate * Return a pointer to the attribute or NULL if not found. 808*0Sstevel@tonic-gate */ 809*0Sstevel@tonic-gate static char * 810*0Sstevel@tonic-gate dbseek_att(tag_p, filter_p) 811*0Sstevel@tonic-gate DB_TAG *tag_p; 812*0Sstevel@tonic-gate int (*filter_p)(); 813*0Sstevel@tonic-gate { 814*0Sstevel@tonic-gate int size; 815*0Sstevel@tonic-gate char *att_p; 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate NO_DEBUG_LOC("dbseek_att: top"); 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate size = tag_p->tg_attlen; 820*0Sstevel@tonic-gate att_p = tag_p->tg_att_p; 821*0Sstevel@tonic-gate NO_DEBUG(printf("attribute size = %d\n",size)); 822*0Sstevel@tonic-gate while (size > 0) { 823*0Sstevel@tonic-gate LEN4 length; 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate if ((*filter_p)(alignval2(att_p))) { 826*0Sstevel@tonic-gate return(att_p); 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate length = bytesFor(att_p); 830*0Sstevel@tonic-gate NO_DEBUG(printf("bytesFor returns length = %d\n",length)); 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate size -= sizeof(LEN2) + length; 833*0Sstevel@tonic-gate att_p += sizeof(LEN2) + length; 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate return((char *) 0); 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate /* 840*0Sstevel@tonic-gate * dbchk...: Routines that check debug tags and attributes. 841*0Sstevel@tonic-gate */ 842*0Sstevel@tonic-gate static int 843*0Sstevel@tonic-gate dbchk_stmnts(value) /* statement list (line section) */ 844*0Sstevel@tonic-gate LEN2 value; 845*0Sstevel@tonic-gate { 846*0Sstevel@tonic-gate return(value == AT_stmt_list); 847*0Sstevel@tonic-gate } 848*0Sstevel@tonic-gate static int 849*0Sstevel@tonic-gate dbchk_lowpc(value) /* statement list (line section) */ 850*0Sstevel@tonic-gate LEN2 value; 851*0Sstevel@tonic-gate { 852*0Sstevel@tonic-gate return(value == AT_low_pc); 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate static int 855*0Sstevel@tonic-gate dbchk_highpc(value) /* statement list (line section) */ 856*0Sstevel@tonic-gate LEN2 value; 857*0Sstevel@tonic-gate { 858*0Sstevel@tonic-gate return(value == AT_high_pc); 859*0Sstevel@tonic-gate } 860*0Sstevel@tonic-gate static int 861*0Sstevel@tonic-gate dbchk_filosub(value) /* file or subroutine */ 862*0Sstevel@tonic-gate LEN2 value; 863*0Sstevel@tonic-gate { 864*0Sstevel@tonic-gate switch(value) { 865*0Sstevel@tonic-gate case TAG_source_file: 866*0Sstevel@tonic-gate case TAG_subroutine: 867*0Sstevel@tonic-gate case TAG_global_subroutine: 868*0Sstevel@tonic-gate case TAG_inline_subroutine: 869*0Sstevel@tonic-gate return(1); 870*0Sstevel@tonic-gate default: 871*0Sstevel@tonic-gate return(0); 872*0Sstevel@tonic-gate } 873*0Sstevel@tonic-gate } 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate #define PS_BLKFACTOR (64) /* handle this many symbols at a time */ 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate /* 880*0Sstevel@tonic-gate * add_profsymbol: Add a new entry to the profsymbol array. 881*0Sstevel@tonic-gate * 882*0Sstevel@tonic-gate * This routine allocates the space required (as needed) for 883*0Sstevel@tonic-gate * the PROF_SYMBOL array, extracts the required information 884*0Sstevel@tonic-gate * from the symbol table and from the debug information, if 885*0Sstevel@tonic-gate * available (none is recorded for the coverage structures). 886*0Sstevel@tonic-gate * 887*0Sstevel@tonic-gate * - Check current capacity, assuming one new symbol is to be added. 888*0Sstevel@tonic-gate * - Copy all of the symbol table information. 889*0Sstevel@tonic-gate * - Search for the symbol in the debug list. If this search fails, 890*0Sstevel@tonic-gate * then flag this failure with "add_profsym_search_fail". This is used 891*0Sstevel@tonic-gate * by "addcovset()" for an error exit when a file is not found in the 892*0Sstevel@tonic-gate * debug information. This applies only to files - other symbols 893*0Sstevel@tonic-gate * which are not found may still be valid. 894*0Sstevel@tonic-gate * - If the symbol is a function, it may be either global or local 895*0Sstevel@tonic-gate * and local functions are not unique. Therefore we must compare the 896*0Sstevel@tonic-gate * address (value) in the symbol table with the address (low_pc) 897*0Sstevel@tonic-gate * given in the debug information to verify the match. 898*0Sstevel@tonic-gate * - If the symbol is a file, no verification is needed, but we 899*0Sstevel@tonic-gate * must change to a new statement list. 900*0Sstevel@tonic-gate * - If the symbol is a coverage structure, then we are finished with it. 901*0Sstevel@tonic-gate */ 902*0Sstevel@tonic-gate static PROF_SYMBOL * 903*0Sstevel@tonic-gate add_profsymbol(prsym_p) 904*0Sstevel@tonic-gate Elf32_Sym *prsym_p; 905*0Sstevel@tonic-gate { 906*0Sstevel@tonic-gate DB_TAG tag; 907*0Sstevel@tonic-gate PROF_SYMBOL *ps_p; 908*0Sstevel@tonic-gate char *att_p; 909*0Sstevel@tonic-gate SEARCH_NODE *sn_p; 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate DEBUG_LOC("add_profsymbol: top"); 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate check_capacity(); 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate ps_p = prsym_list_p + prsym_cnt - 1; 916*0Sstevel@tonic-gate memcpy((char *) &(ps_p->ps_sym), (char *) prsym_p, prstsym_size); 917*0Sstevel@tonic-gate memset((char *) &(ps_p->ps_dbg), '\0', sizeof(PROF_DEBUGE)); 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate DEBUG_EXP(printf("symbol name = %s\n", ST_NAME(prsym_p))); 920*0Sstevel@tonic-gate ps_p->ps_dbg.pd_name = ST_NAME(prsym_p); 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate add_profsym_search_fail = 0; 923*0Sstevel@tonic-gate if (!(sn_p = sn_search(ST_NAME(prsym_p), dblist, dblist_cnt))) { 924*0Sstevel@tonic-gate add_profsym_search_fail = 1; 925*0Sstevel@tonic-gate goto theend; 926*0Sstevel@tonic-gate } 927*0Sstevel@tonic-gate DEBUG_EXP(printf("Post search: sn_p->sn_name_p = %s\n",sn_p->sn_name_p)); 928*0Sstevel@tonic-gate dbfill_tag(sn_p->sn_value_p, &tag); 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate if (stchk_func(prsym_p)) { 931*0Sstevel@tonic-gate while (strcmp(ST_NAME(prsym_p), sn_p->sn_name_p) == 0) { 932*0Sstevel@tonic-gate if (add_function(ps_p, &tag)) { 933*0Sstevel@tonic-gate break; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate sn_p++; 936*0Sstevel@tonic-gate dbfill_tag(sn_p->sn_value_p, &tag); 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate } else if (stchk_file(prsym_p)) { 939*0Sstevel@tonic-gate if ( 940*0Sstevel@tonic-gate (sn_p + 1) < (dblist + dblist_cnt) 941*0Sstevel@tonic-gate && strcmp(sn_p[0].sn_name_p, sn_p[1].sn_name_p) == 0 942*0Sstevel@tonic-gate ) { 943*0Sstevel@tonic-gate _err_warn( 944*0Sstevel@tonic-gate "File name %s was used more than once.", 945*0Sstevel@tonic-gate sn_p->sn_name_p 946*0Sstevel@tonic-gate ); 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate add_file(&tag); 949*0Sstevel@tonic-gate } else { 950*0Sstevel@tonic-gate goto theend; 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate ps_p->ps_dbg.pd_symtag = tag.tg_value; 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate theend:; 956*0Sstevel@tonic-gate DEBUG_LOC("add_profsymbol: bottom"); 957*0Sstevel@tonic-gate return(ps_p); 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate static void 962*0Sstevel@tonic-gate add_file(tag_p) 963*0Sstevel@tonic-gate DB_TAG *tag_p; 964*0Sstevel@tonic-gate { 965*0Sstevel@tonic-gate int i; 966*0Sstevel@tonic-gate char *tp; 967*0Sstevel@tonic-gate PROF_LINE *lnp; 968*0Sstevel@tonic-gate char *att_p; 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate att_p = dbseek_att(tag_p, dbchk_stmnts); 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate curf_lp = ((char *) profPtr->pf_linedat_p->d_buf) + DB_STMNTOS(att_p); 973*0Sstevel@tonic-gate curf_lncnt = (alignval4(curf_lp) - 2*sizeof(LEN4)) / DBG_LINE_SIZE; 974*0Sstevel@tonic-gate curf_base = alignval4(curf_lp + sizeof(LEN4)); 975*0Sstevel@tonic-gate curf_lp += sizeof(LEN4) + sizeof(LEN4); 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate curf_lns_p = (PROF_LINE *) _Malloc(curf_lncnt, sizeof(*curf_lns_p)); 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate i = 0; 980*0Sstevel@tonic-gate tp = curf_lp; 981*0Sstevel@tonic-gate lnp = curf_lns_p; 982*0Sstevel@tonic-gate while (i++ < curf_lncnt) { 983*0Sstevel@tonic-gate *lnp++ = alignval4(tp); 984*0Sstevel@tonic-gate tp += DBG_LINE_SIZE; 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate 987*0Sstevel@tonic-gate #ifdef DEBUG 988*0Sstevel@tonic-gate printf("File Debug Line Information\n"); 989*0Sstevel@tonic-gate printf(" DBG_LINE_SIZE = %d\n", DBG_LINE_SIZE); 990*0Sstevel@tonic-gate printf(" curf_lp = 0x%x\n", curf_lp); 991*0Sstevel@tonic-gate printf(" curf_lncnt = %d\n", curf_lncnt); 992*0Sstevel@tonic-gate printf(" curf_base = 0x%x\n", curf_base); 993*0Sstevel@tonic-gate printf(" curf_lns_p = 0x%x\n", curf_lns_p); 994*0Sstevel@tonic-gate printf("Dump of line numbers\n"); 995*0Sstevel@tonic-gate for (i = 0, lnp = curf_lns_p; i < curf_lncnt; i++) { 996*0Sstevel@tonic-gate printf(" line %d = %d\n", i, lnp[i]); 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate #endif 999*0Sstevel@tonic-gate } 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate /* 1004*0Sstevel@tonic-gate * add_function -- add to function's PROF_DEBUGE, line# pointer info. 1005*0Sstevel@tonic-gate * 1006*0Sstevel@tonic-gate * Warning: Because we are reading directly from memory, we 1007*0Sstevel@tonic-gate * cannot depend upon the form of the structures we are reading 1008*0Sstevel@tonic-gate * (e.g., pl_delta in PROF_LINE). Thus, line_p is a "char *" 1009*0Sstevel@tonic-gate * and NOT a "PROF_LINE *". 1010*0Sstevel@tonic-gate * 1011*0Sstevel@tonic-gate * 1012*0Sstevel@tonic-gate * Note from below(***): 1013*0Sstevel@tonic-gate * 1014*0Sstevel@tonic-gate * Note that this routine finds the range of .line section 1015*0Sstevel@tonic-gate * entries that should be associated with this function, from 1016*0Sstevel@tonic-gate * those which belong to this file. 1017*0Sstevel@tonic-gate * 1018*0Sstevel@tonic-gate * The FIRST line entry for a fcn is selected because 1019*0Sstevel@tonic-gate * it is the first with a ``delta,'' or memory offset 1020*0Sstevel@tonic-gate * from the file ``base address (curf_base),'' 1021*0Sstevel@tonic-gate * whose value is GREATER OR EQUAL to the effective offset 1022*0Sstevel@tonic-gate * associated with this function (lo_delta). 1023*0Sstevel@tonic-gate * 1024*0Sstevel@tonic-gate * The LAST line entry is selected because it is 1025*0Sstevel@tonic-gate * the LAST with a ``delta'' whose value is LESS THAN 1026*0Sstevel@tonic-gate * the effective offset of the END of this function (hi_delta) 1027*0Sstevel@tonic-gate * - i.e. it is the last line number associated with 1028*0Sstevel@tonic-gate * code that is wholly included in this function! 1029*0Sstevel@tonic-gate * 1030*0Sstevel@tonic-gate * If no line number is found with a delta value that 1031*0Sstevel@tonic-gate * exceeds hi_delta (i.e. is part of the next function), 1032*0Sstevel@tonic-gate * then it is assumed that the last line number entry seen 1033*0Sstevel@tonic-gate * should simply be accepted as part of this function's set 1034*0Sstevel@tonic-gate * of line numbers; it simply has no ``bounding line entry.'' 1035*0Sstevel@tonic-gate * 1036*0Sstevel@tonic-gate */ 1037*0Sstevel@tonic-gate 1038*0Sstevel@tonic-gate static int 1039*0Sstevel@tonic-gate add_function(ps_p, tag_p) 1040*0Sstevel@tonic-gate PROF_SYMBOL *ps_p; 1041*0Sstevel@tonic-gate DB_TAG *tag_p; 1042*0Sstevel@tonic-gate { 1043*0Sstevel@tonic-gate char *att_p; 1044*0Sstevel@tonic-gate LEN4 high_pc, hi_delta; 1045*0Sstevel@tonic-gate LEN4 low_pc, lo_delta; 1046*0Sstevel@tonic-gate char *line_p; 1047*0Sstevel@tonic-gate int first_found = 0; 1048*0Sstevel@tonic-gate PROF_LINE *pl_p; 1049*0Sstevel@tonic-gate int i; 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate DEBUG_LOC("add_function: top"); 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate att_p = dbseek_att(tag_p, dbchk_lowpc); 1054*0Sstevel@tonic-gate low_pc = DB_PCVALUE(att_p); 1055*0Sstevel@tonic-gate if (ps_p->ps_sym.st_value != low_pc) { 1056*0Sstevel@tonic-gate DEBUG_LOC("add_function: returning - failed"); 1057*0Sstevel@tonic-gate return(0); 1058*0Sstevel@tonic-gate } 1059*0Sstevel@tonic-gate att_p = dbseek_att(tag_p, dbchk_highpc); 1060*0Sstevel@tonic-gate high_pc = DB_PCVALUE(att_p); 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate hi_delta = high_pc - curf_base; 1063*0Sstevel@tonic-gate lo_delta = low_pc - curf_base; 1064*0Sstevel@tonic-gate DEBUG_EXP(printf("lo_delta = 0x%x\n", lo_delta)); 1065*0Sstevel@tonic-gate DEBUG_EXP(printf("hi_delta = 0x%x\n", hi_delta)); 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate line_p = curf_lp; 1068*0Sstevel@tonic-gate pl_p = curf_lns_p - 1; 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate DEBUG_EXP(printf("Building symbol: %s\n",SYMBOL_NAME(ps_p))); 1071*0Sstevel@tonic-gate i = 0; 1072*0Sstevel@tonic-gate while (i++ < curf_lncnt) { 1073*0Sstevel@tonic-gate LEN4 delad; 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate pl_p++; 1076*0Sstevel@tonic-gate delad = alignval4(line_p + sizeof(LEN4) + sizeof(LEN2)); 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate NO_DEBUG(printf("delad = 0x%x\n", delad)); 1079*0Sstevel@tonic-gate NO_DEBUG(printf("line_p = 0x%x\n", line_p)); 1080*0Sstevel@tonic-gate 1081*0Sstevel@tonic-gate if (!first_found && (delad >= lo_delta)) { 1082*0Sstevel@tonic-gate DEBUG_LOC("found first line"); 1083*0Sstevel@tonic-gate first_found = 1; 1084*0Sstevel@tonic-gate ps_p->ps_dbg.pd_line_p = pl_p; 1085*0Sstevel@tonic-gate } else if (delad >= hi_delta) { 1086*0Sstevel@tonic-gate DEBUG_LOC("found last line"); 1087*0Sstevel@tonic-gate ps_p->ps_dbg.pd_lali_p = pl_p-1; 1088*0Sstevel@tonic-gate break; 1089*0Sstevel@tonic-gate } 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate line_p += DBG_LINE_SIZE; 1092*0Sstevel@tonic-gate } 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate /* 1095*0Sstevel@tonic-gate * If the first line is not found, then we have failed 1096*0Sstevel@tonic-gate * and must return zero. It is possible (e.g., sometimes 1097*0Sstevel@tonic-gate * when the function is the last one in the file) for the 1098*0Sstevel@tonic-gate * first line to be found, but the last not. In this case, 1099*0Sstevel@tonic-gate * we assume it simply the last possible line. 1100*0Sstevel@tonic-gate */ 1101*0Sstevel@tonic-gate if (ps_p->ps_dbg.pd_line_p == NULL) { 1102*0Sstevel@tonic-gate _err_exit( 1103*0Sstevel@tonic-gate "Unable to locate line information for function %s.", 1104*0Sstevel@tonic-gate SYMBOL_NAME(ps_p) 1105*0Sstevel@tonic-gate ); 1106*0Sstevel@tonic-gate } 1107*0Sstevel@tonic-gate if (ps_p->ps_dbg.pd_lali_p == NULL) { 1108*0Sstevel@tonic-gate DEBUG_LOC("found last line (by default)"); 1109*0Sstevel@tonic-gate ps_p->ps_dbg.pd_lali_p = pl_p; 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate DEBUG_EXP(printf("first line (pd_line_p) = 0x%x\n",ps_p->ps_dbg.pd_line_p)); 1112*0Sstevel@tonic-gate DEBUG_EXP(printf("last line (pd_lali_p) = 0x%x\n",ps_p->ps_dbg.pd_lali_p)); 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate DEBUG_LOC("add_function: bottom"); 1115*0Sstevel@tonic-gate return(1); 1116*0Sstevel@tonic-gate } 1117*0Sstevel@tonic-gate 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate /* * * * * * 1120*0Sstevel@tonic-gate * If capacity will be exceeded with a new symbol, then 1121*0Sstevel@tonic-gate * increase the capacity. 1122*0Sstevel@tonic-gate */ 1123*0Sstevel@tonic-gate static void 1124*0Sstevel@tonic-gate check_capacity() 1125*0Sstevel@tonic-gate { 1126*0Sstevel@tonic-gate if ( ++prsym_cnt > prsym_cap ) { 1127*0Sstevel@tonic-gate if ( prsym_cap == 0 ) { 1128*0Sstevel@tonic-gate prsym_cap = PS_BLKFACTOR; 1129*0Sstevel@tonic-gate prsym_list_p = (PROF_SYMBOL *) 1130*0Sstevel@tonic-gate _Malloc( prsym_size, prsym_cap ); 1131*0Sstevel@tonic-gate } else { 1132*0Sstevel@tonic-gate prsym_cap += PS_BLKFACTOR; 1133*0Sstevel@tonic-gate prsym_list_p = (PROF_SYMBOL *) 1134*0Sstevel@tonic-gate _Realloc( (char *) prsym_list_p, 1135*0Sstevel@tonic-gate prsym_size * prsym_cap ); 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate } 1138*0Sstevel@tonic-gate } 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate /* * * * * * 1143*0Sstevel@tonic-gate * debName -- return ptr to name value for name attr type:attr value pair. 1144*0Sstevel@tonic-gate * 1145*0Sstevel@tonic-gate * this routine is called by fillout_sym_dbinfo, to scan 1146*0Sstevel@tonic-gate * through a list of debug attributes and return a ptr 1147*0Sstevel@tonic-gate * to the name attrib value, when that type/value pair is found. 1148*0Sstevel@tonic-gate */ 1149*0Sstevel@tonic-gate 1150*0Sstevel@tonic-gate static 1151*0Sstevel@tonic-gate char * 1152*0Sstevel@tonic-gate debName( att_p, att_size ) 1153*0Sstevel@tonic-gate char *att_p; /* ptr to list of (attr_type,attr_value) pairs */ 1154*0Sstevel@tonic-gate int att_size; /* byte length attribute list */ 1155*0Sstevel@tonic-gate { 1156*0Sstevel@tonic-gate char *name_p = ""; 1157*0Sstevel@tonic-gate /* * * * * * 1158*0Sstevel@tonic-gate * loop through the entries. when you find a name, 1159*0Sstevel@tonic-gate * return the addr of the related data (a char string). 1160*0Sstevel@tonic-gate */ 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate NO_DEBUG_LOC("debName: top"); 1163*0Sstevel@tonic-gate while ( att_size>0 ) { 1164*0Sstevel@tonic-gate LEN2 typea_one; 1165*0Sstevel@tonic-gate LEN4 lena_one; 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate NO_DEBUG(printf("att_size = %d\n",att_size)); 1168*0Sstevel@tonic-gate typea_one = alignval2(att_p) ; 1169*0Sstevel@tonic-gate NO_DEBUG(printf("typea_one = 0x%x\n",typea_one)); 1170*0Sstevel@tonic-gate lena_one = bytesFor(att_p) ; 1171*0Sstevel@tonic-gate NO_DEBUG(printf("lena_one = %d\n",lena_one)); 1172*0Sstevel@tonic-gate NO_DEBUG(printf("att_p = 0x%x\n",att_p)); 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate if( typea_one == AT_name ) { 1175*0Sstevel@tonic-gate name_p = att_p + sizeof(LEN2); 1176*0Sstevel@tonic-gate break; 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate att_size -= sizeof(LEN2) + lena_one; 1179*0Sstevel@tonic-gate att_p += sizeof(LEN2) + lena_one; 1180*0Sstevel@tonic-gate } 1181*0Sstevel@tonic-gate NO_DEBUG(printf("name = %s\n",name_p)); 1182*0Sstevel@tonic-gate NO_DEBUG_LOC("debName: bottom"); 1183*0Sstevel@tonic-gate return( name_p ); 1184*0Sstevel@tonic-gate } 1185*0Sstevel@tonic-gate 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate /* * * * * * 1188*0Sstevel@tonic-gate * bytesFor - indicate the number of bytes of attribute data 1189*0Sstevel@tonic-gate * expected to be defined for an attribute type, 1190*0Sstevel@tonic-gate * given a ptr to the attribute type:value pair. 1191*0Sstevel@tonic-gate * 1192*0Sstevel@tonic-gate * we don't particularly care about the specific attribute; 1193*0Sstevel@tonic-gate * more, we are interested in the 'form' of the value 1194*0Sstevel@tonic-gate * associated with this attribute type; hence the 'bit un-masking'. 1195*0Sstevel@tonic-gate * 1196*0Sstevel@tonic-gate * used by fillout1(). 1197*0Sstevel@tonic-gate */ 1198*0Sstevel@tonic-gate static LEN4 1199*0Sstevel@tonic-gate bytesFor(attr_p) 1200*0Sstevel@tonic-gate char *attr_p; 1201*0Sstevel@tonic-gate { 1202*0Sstevel@tonic-gate LEN4 len; 1203*0Sstevel@tonic-gate LEN2 form, type; 1204*0Sstevel@tonic-gate char *data_p = attr_p + sizeof(LEN2); /* beginning of attr data */ 1205*0Sstevel@tonic-gate 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate NO_DEBUG_LOC("bytesFor: top"); 1208*0Sstevel@tonic-gate 1209*0Sstevel@tonic-gate type = alignval2(attr_p); 1210*0Sstevel@tonic-gate form = type & FORM_MASK ; 1211*0Sstevel@tonic-gate NO_DEBUG(printf("attribute: type = 0x%x",type)); 1212*0Sstevel@tonic-gate NO_DEBUG(printf(", form = 0x%x\n",form)); 1213*0Sstevel@tonic-gate switch( form ) 1214*0Sstevel@tonic-gate { 1215*0Sstevel@tonic-gate case FORM_STRING: /* NUL-terminated string */ 1216*0Sstevel@tonic-gate /* * * * * * 1217*0Sstevel@tonic-gate * len of string is #chars plus one for NULL. 1218*0Sstevel@tonic-gate */ 1219*0Sstevel@tonic-gate len = strlen(data_p) + 1; 1220*0Sstevel@tonic-gate break; 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate case FORM_DATA2: /* 2 bytes */ 1223*0Sstevel@tonic-gate len = 2; 1224*0Sstevel@tonic-gate break; 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate case FORM_ADDR: /* relocated address */ 1227*0Sstevel@tonic-gate case FORM_REF: /* reference to another .debug entry */ 1228*0Sstevel@tonic-gate case FORM_DATA4: /* 4 bytes */ 1229*0Sstevel@tonic-gate len = 4; 1230*0Sstevel@tonic-gate break; 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate case FORM_DATA8: /* 8 bytes (two 4-byte values) */ 1233*0Sstevel@tonic-gate len = 8; 1234*0Sstevel@tonic-gate break; 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate case FORM_BLOCK2: /* block with 2-byte length, then data */ 1237*0Sstevel@tonic-gate len = alignval2(data_p) + 2 ; /* + 2 -> len of length */ 1238*0Sstevel@tonic-gate break; 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate case FORM_BLOCK4: /* block with 4-byte length, then data */ 1241*0Sstevel@tonic-gate len = alignval4(data_p) + 4 ; /* + 4 -> len of length */ 1242*0Sstevel@tonic-gate break; 1243*0Sstevel@tonic-gate 1244*0Sstevel@tonic-gate case FORM_NONE: /* error */ 1245*0Sstevel@tonic-gate default: 1246*0Sstevel@tonic-gate len = 0; 1247*0Sstevel@tonic-gate break; 1248*0Sstevel@tonic-gate } 1249*0Sstevel@tonic-gate 1250*0Sstevel@tonic-gate if (len==0) 1251*0Sstevel@tonic-gate _err_exit("Invalid FORM_value %#x for attribute type %#x\n", 1252*0Sstevel@tonic-gate form , type); 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate NO_DEBUG_LOC("bytesFor: bottom"); 1255*0Sstevel@tonic-gate return(len); 1256*0Sstevel@tonic-gate } 1257*0Sstevel@tonic-gate 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate /* 1260*0Sstevel@tonic-gate * sn_search: Search sorted list of SEARCH_NODE for given name. 1261*0Sstevel@tonic-gate * 1262*0Sstevel@tonic-gate * Search the list for the entry with the given name. If there 1263*0Sstevel@tonic-gate * is no such entry, return 0. Otherwise return a pointer to 1264*0Sstevel@tonic-gate * the *first* entry in the list that matches. 1265*0Sstevel@tonic-gate */ 1266*0Sstevel@tonic-gate static SEARCH_NODE * 1267*0Sstevel@tonic-gate sn_search(name_p, list_p, count) 1268*0Sstevel@tonic-gate char *name_p; 1269*0Sstevel@tonic-gate SEARCH_NODE *list_p; 1270*0Sstevel@tonic-gate int count; 1271*0Sstevel@tonic-gate { 1272*0Sstevel@tonic-gate SEARCH_NODE tnode; 1273*0Sstevel@tonic-gate SEARCH_NODE *sn_p; 1274*0Sstevel@tonic-gate int index; 1275*0Sstevel@tonic-gate 1276*0Sstevel@tonic-gate tnode.sn_name_p = name_p; 1277*0Sstevel@tonic-gate 1278*0Sstevel@tonic-gate sn_p = (SEARCH_NODE *) bsearch( 1279*0Sstevel@tonic-gate (char *) &tnode, 1280*0Sstevel@tonic-gate (char *) list_p, 1281*0Sstevel@tonic-gate count, 1282*0Sstevel@tonic-gate sizeof(*list_p), 1283*0Sstevel@tonic-gate sn_compare 1284*0Sstevel@tonic-gate ); 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate if (sn_p == NULL) { 1287*0Sstevel@tonic-gate return(NULL); 1288*0Sstevel@tonic-gate } 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate index = sn_p - list_p; 1291*0Sstevel@tonic-gate while ((index > 0) && (sn_compare(&list_p[index-1], &tnode) == 0)) 1292*0Sstevel@tonic-gate index--; 1293*0Sstevel@tonic-gate 1294*0Sstevel@tonic-gate return(&list_p[index]); 1295*0Sstevel@tonic-gate } 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate static int 1298*0Sstevel@tonic-gate sn_compare(a_p, b_p) 1299*0Sstevel@tonic-gate SEARCH_NODE *a_p; 1300*0Sstevel@tonic-gate SEARCH_NODE *b_p; 1301*0Sstevel@tonic-gate { 1302*0Sstevel@tonic-gate return(strcmp(a_p->sn_name_p, b_p->sn_name_p)); 1303*0Sstevel@tonic-gate } 1304*0Sstevel@tonic-gate 1305*0Sstevel@tonic-gate #ifdef DEBUG 1306*0Sstevel@tonic-gate static void 1307*0Sstevel@tonic-gate sn_dump(title_p, snlist_p, sncount) 1308*0Sstevel@tonic-gate char *title_p; 1309*0Sstevel@tonic-gate SEARCH_NODE *snlist_p; 1310*0Sstevel@tonic-gate int sncount; 1311*0Sstevel@tonic-gate { 1312*0Sstevel@tonic-gate int i; 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate printf("search list for %s: count = %d\n", title_p, sncount); 1315*0Sstevel@tonic-gate for (i = 0; i < sncount; i++) { 1316*0Sstevel@tonic-gate printf( 1317*0Sstevel@tonic-gate " name = %s, pointer = 0x%lx\n" 1318*0Sstevel@tonic-gate , snlist_p[i].sn_name_p 1319*0Sstevel@tonic-gate , snlist_p[i].sn_value_p 1320*0Sstevel@tonic-gate ); 1321*0Sstevel@tonic-gate } 1322*0Sstevel@tonic-gate } 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate static void 1325*0Sstevel@tonic-gate profsym_dump(list_p, count) 1326*0Sstevel@tonic-gate PROF_SYMBOL *list_p; 1327*0Sstevel@tonic-gate int count; 1328*0Sstevel@tonic-gate { 1329*0Sstevel@tonic-gate int i; 1330*0Sstevel@tonic-gate PROF_LINE *p; 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate printf("Dump of %d prof symbols found.\n", count); 1333*0Sstevel@tonic-gate for (i = 0; i < count; i++, list_p++) { 1334*0Sstevel@tonic-gate printf("%d: location 0x%x\n", i, list_p); 1335*0Sstevel@tonic-gate printf("\tSymbol %s\n", ST_NAME(&(list_p->ps_sym))); 1336*0Sstevel@tonic-gate printf("\t st_size = %d\n", list_p->ps_sym.st_size); 1337*0Sstevel@tonic-gate printf("\t st_info = 0x%lx\n", list_p->ps_sym.st_info); 1338*0Sstevel@tonic-gate printf("\tDebug Information\n"); 1339*0Sstevel@tonic-gate printf("\t pd_name = %s\n", list_p->ps_dbg.pd_name); 1340*0Sstevel@tonic-gate printf("\t pd_symtag = 0x%lx\n", list_p->ps_dbg.pd_symtag); 1341*0Sstevel@tonic-gate p = list_p->ps_dbg.pd_line_p; 1342*0Sstevel@tonic-gate printf("\t *pd_line_p = %d\n", (p ? *p : 0)); 1343*0Sstevel@tonic-gate p = list_p->ps_dbg.pd_lali_p; 1344*0Sstevel@tonic-gate printf("\t *pd_lali_p = %d\n", (p ? *p : 0)); 1345*0Sstevel@tonic-gate printf("\t pd_file_p = 0x%lx\n", list_p->ps_dbg.pd_file_p); 1346*0Sstevel@tonic-gate } 1347*0Sstevel@tonic-gate } 1348*0Sstevel@tonic-gate #endif 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate 1351*0Sstevel@tonic-gate /* 1352*0Sstevel@tonic-gate * alignment routines 1353*0Sstevel@tonic-gate * 1354*0Sstevel@tonic-gate * These routines are used to avoid the EMT trap that occurs 1355*0Sstevel@tonic-gate * when moving a unit of data (of 2 or more bytes) across a 1356*0Sstevel@tonic-gate * word boundry. 1357*0Sstevel@tonic-gate */ 1358*0Sstevel@tonic-gate static LEN2 1359*0Sstevel@tonic-gate alignval2(p) 1360*0Sstevel@tonic-gate char *p; 1361*0Sstevel@tonic-gate { 1362*0Sstevel@tonic-gate LEN2 tmp; char *tp = (char *) &tmp; 1363*0Sstevel@tonic-gate 1364*0Sstevel@tonic-gate tp[0] = p[0]; tp[1] = p[1]; 1365*0Sstevel@tonic-gate return(tmp); 1366*0Sstevel@tonic-gate } 1367*0Sstevel@tonic-gate 1368*0Sstevel@tonic-gate static LEN4 1369*0Sstevel@tonic-gate alignval4(p) 1370*0Sstevel@tonic-gate char *p; 1371*0Sstevel@tonic-gate { 1372*0Sstevel@tonic-gate LEN4 tmp; char *tp = (char *) &tmp; 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate tp[0] = p[0]; tp[1] = p[1]; tp[2] = p[2]; tp[3] = p[3]; 1375*0Sstevel@tonic-gate return(tmp); 1376*0Sstevel@tonic-gate } 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate /* 1379*0Sstevel@tonic-gate * Disscussion of the argv[0] problem and solution. 1380*0Sstevel@tonic-gate * 1381*0Sstevel@tonic-gate * If a process is run with a misleading first argument (argv[0]), 1382*0Sstevel@tonic-gate * the profiler will be confused when trying to read the file and 1383*0Sstevel@tonic-gate * match the information against that in memory. As a confidence 1384*0Sstevel@tonic-gate * check, we compare the address of MATCH_STR as seen in the symbol 1385*0Sstevel@tonic-gate * table to the address of MATCH_STR as seen while running the code. 1386*0Sstevel@tonic-gate * If these are the same, it is *very* unlikely that the file 1387*0Sstevel@tonic-gate * does not correspond to the code in memory. 1388*0Sstevel@tonic-gate * 1389*0Sstevel@tonic-gate * Because this code may be run from a shared object, we must 1390*0Sstevel@tonic-gate * insure that our reference to MATCH_STR is that of the main routine. 1391*0Sstevel@tonic-gate * We are depending on MATCH_NAME to not be defined by any shared object 1392*0Sstevel@tonic-gate * (including this one - libprof.so - when so built). 1393*0Sstevel@tonic-gate * 1394*0Sstevel@tonic-gate * The search for MATCH_STR in the symbol table is done in _symintLoad 1395*0Sstevel@tonic-gate * because SymintLoad has an ordered version of selected entries from the 1396*0Sstevel@tonic-gate * symbol table which makes searching very efficient (O(log n)). 1397*0Sstevel@tonic-gate * 1398*0Sstevel@tonic-gate * See also soqueue.c. 1399*0Sstevel@tonic-gate */ 1400*0Sstevel@tonic-gate 1401*0Sstevel@tonic-gate int _prof_check_match; 1402*0Sstevel@tonic-gate 1403*0Sstevel@tonic-gate static void 1404*0Sstevel@tonic-gate verify_match() 1405*0Sstevel@tonic-gate { 1406*0Sstevel@tonic-gate SEARCH_NODE *sn_p; 1407*0Sstevel@tonic-gate Elf32_Sym *sym_p; 1408*0Sstevel@tonic-gate extern char MATCH_NAME; 1409*0Sstevel@tonic-gate 1410*0Sstevel@tonic-gate if (_prof_check_match) { 1411*0Sstevel@tonic-gate if (!(sn_p = sn_search(MATCH_STR, gstlist, gstlist_cnt))) { 1412*0Sstevel@tonic-gate _err_exit("Cannot find match name."); 1413*0Sstevel@tonic-gate } 1414*0Sstevel@tonic-gate sym_p = (Elf32_Sym *) sn_p->sn_value_p; 1415*0Sstevel@tonic-gate if (sym_p->st_value != (Elf32_Addr) &MATCH_NAME) { 1416*0Sstevel@tonic-gate _err_exit("Location of file for this process unknown."); 1417*0Sstevel@tonic-gate } 1418*0Sstevel@tonic-gate } 1419*0Sstevel@tonic-gate } 1420*0Sstevel@tonic-gate #endif 1421*0Sstevel@tonic-gate 1422