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