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 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Routines to provide profiling of shared libraries required by the called 30 * executable. 31 */ 32 #include <stdio.h> 33 #include <fcntl.h> 34 #include <sys/mman.h> 35 #include <unistd.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <synch.h> 41 #include <signal.h> 42 #include <synch.h> 43 #include <link.h> 44 #include <sys/param.h> 45 #include <procfs.h> 46 #include "msg.h" 47 #include "sgs.h" 48 #include "profile.h" 49 #include "_rtld.h" 50 51 52 static char Profile[MAXPATHLEN]; /* Profile buffer pathname */ 53 static char *pname = 0; /* name of object to profile */ 54 static L_hdr *Hptr; /* profile buffer header pointer */ 55 static L_cgarc *Cptr; /* profile buffer call graph pointer */ 56 static caddr_t Hpc, Lpc; /* Range of addresses being monitored */ 57 static size_t Fsize; /* Size of mapped in profile buffer */ 58 uintptr_t profcookie = 0; 59 60 /* 61 * When handling mutex's locally we need to mask signals. The signal 62 * mask is for everything except SIGWAITING. 63 */ 64 static const sigset_t iset = { ~0U, ~0U, ~0U, ~0U }; 65 66 static lwp_mutex_t sharedmutex = SHAREDMUTEX; 67 68 static int 69 prof_mutex_init(lwp_mutex_t *mp) 70 { 71 (void) memcpy(mp, &sharedmutex, sizeof (lwp_mutex_t)); 72 return (0); 73 } 74 75 static int 76 prof_mutex_lock(lwp_mutex_t *mp, sigset_t *oset) 77 { 78 if (oset) 79 (void) sigprocmask(SIG_BLOCK, &iset, oset); 80 (void) _lwp_mutex_lock(mp); 81 return (0); 82 } 83 84 static int 85 prof_mutex_unlock(mutex_t *mp, sigset_t *oset) 86 { 87 (void) _lwp_mutex_unlock(mp); 88 if (oset) 89 (void) sigprocmask(SIG_SETMASK, oset, NULL); 90 return (0); 91 } 92 93 94 extern char *_dgettext(const char *, const char *); 95 96 97 const char * 98 _ldprof_msg(Msg mid) 99 { 100 return (_dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 101 } 102 103 /* 104 * Determine whether a set (of arbitrary size) is in use - used to analyze proc 105 * status information. 106 */ 107 static int 108 setisinuse(uint32_t *sp, uint_t n) 109 { 110 while (n--) 111 if (*sp++) 112 return (1); 113 return (0); 114 } 115 116 #define prisinuse(sp) \ 117 setisinuse((uint32_t *)(sp), \ 118 (uint_t)(sizeof (*(sp)) / sizeof (uint32_t))) 119 120 uint_t 121 la_version(uint_t version) 122 { 123 int fd; 124 ssize_t num; 125 pstatus_t status; 126 127 if (version < LAV_CURRENT) { 128 (void) fprintf(stderr, MSG_INTL(MSG_GEN_AUDITVERSION), 129 LAV_CURRENT, version); 130 return (LAV_CURRENT); 131 } 132 133 /* 134 * To reduce the potential for deadlock conditions that can arise from 135 * being monitored (say by truss(1)) while setting a lock in the profile 136 * buffer, determine if someone is monitoring us. If so silently 137 * disable profiling. 138 */ 139 if ((fd = open(MSG_ORIG(MSG_FMT_PROCSELF), O_RDONLY)) < 0) 140 return (LAV_CURRENT); 141 142 num = read(fd, &status, sizeof (status)); 143 (void) close(fd); 144 145 if ((num != sizeof (status)) || 146 prisinuse(&status.pr_sigtrace) || prisinuse(&status.pr_flttrace) || 147 prisinuse(&status.pr_sysentry) || prisinuse(&status.pr_sysexit)) { 148 return (LAV_CURRENT); 149 } 150 151 /* 152 * We're presently not being monitored (although there's no control of 153 * someone attaching to us later), so retrieve the profile target name. 154 */ 155 if (dlinfo((void *)NULL, RTLD_DI_PROFILENAME, &pname) == -1) 156 (void) fprintf(stderr, MSG_INTL(MSG_GEN_PROFNOTSET)); 157 158 return (LAV_CURRENT); 159 } 160 161 162 int 163 profile_open(const char *fname, Link_map *lmp) 164 { 165 size_t hsize; /* struct hdr size */ 166 size_t psize; /* profile histogram size */ 167 size_t csize; /* call graph array size */ 168 size_t msize; /* size of memory being profiled */ 169 int i, fd, fixed = 0; 170 caddr_t lpc; 171 caddr_t hpc; 172 caddr_t addr; 173 struct stat status; 174 int new_buffer = 0; 175 sigset_t mask; 176 int err; 177 Ehdr * ehdr; /* ELF header for file */ 178 Phdr * phdr; /* program headers for file */ 179 Dyn * dynp = 0; /* Dynamic section */ 180 Word nsym = 0; /* no. of symtab ntries */ 181 182 if (*Profile == '\0') { 183 const char *dir, *suf; 184 char *tmp; 185 186 /* 187 * From the basename of the specified filename generate the 188 * appropriate profile buffer name. The profile file is created 189 * if it does not already exist. 190 */ 191 if (((tmp = strrchr(fname, '/')) != 0) && (*(++tmp))) 192 fname = tmp; 193 194 #if defined(_ELF64) 195 suf = MSG_ORIG(MSG_SUF_PROFILE_64); 196 #else 197 suf = MSG_ORIG(MSG_SUF_PROFILE); 198 #endif 199 if (dlinfo((void *)NULL, RTLD_DI_PROFILEOUT, &dir) == -1) 200 dir = MSG_ORIG(MSG_PTH_VARTMP); 201 202 (void) snprintf(Profile, MAXPATHLEN, MSG_ORIG(MSG_FMT_PROFILE), 203 dir, fname, suf); 204 } 205 206 if ((fd = open(Profile, (O_RDWR | O_CREAT), 0666)) == -1) { 207 err = errno; 208 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), Profile, 209 strerror(err)); 210 return (0); 211 } 212 213 /* 214 * Now we determine the valid pc range for this object. The lpc is easy 215 * (lmp->l_addr), to determine the hpc we must examine the Phdrs. 216 */ 217 lpc = hpc = (caddr_t)lmp->l_addr; 218 /* LINTED */ 219 ehdr = (Ehdr *)lpc; 220 if (ehdr->e_phnum == 0) { 221 (void) close(fd); 222 return (0); 223 } 224 if (ehdr->e_type == ET_EXEC) 225 fixed = 1; 226 /* LINTED */ 227 phdr = (Phdr *)(ehdr->e_phoff + lpc); 228 for (i = 0; i < ehdr->e_phnum; i++, phdr++) { 229 caddr_t _hpc; 230 231 if (phdr->p_type == PT_DYNAMIC) { 232 dynp = (Dyn *)phdr->p_vaddr; 233 if (fixed == 0) { 234 dynp = (Dyn *)((unsigned long)dynp + 235 (unsigned long)lpc); 236 } 237 continue; 238 } 239 240 if (phdr->p_type != PT_LOAD) 241 continue; 242 243 _hpc = (caddr_t)(phdr->p_vaddr + phdr->p_memsz); 244 if (fixed == 0) { 245 _hpc = (caddr_t)((unsigned long)_hpc + 246 (unsigned long)lpc); 247 } 248 if (_hpc > hpc) 249 hpc = _hpc; 250 } 251 if (lpc == hpc) { 252 (void) close(fd); 253 return (0); 254 } 255 256 /* 257 * In order to determine the number of symbols in the object scan the 258 * dynamic section until we find the DT_HASH entry (hash[1] == symcnt). 259 */ 260 if (dynp) { 261 for (; dynp->d_tag != DT_NULL; dynp++) { 262 unsigned int *hashp; 263 264 if (dynp->d_tag != DT_HASH) 265 continue; 266 267 hashp = (unsigned int *)dynp->d_un.d_ptr; 268 if (fixed == 0) { 269 hashp = (unsigned int *)((unsigned long)hashp + 270 (unsigned long)lpc); 271 } 272 nsym = hashp[1]; 273 break; 274 } 275 } 276 277 /* 278 * Determine the (minimum) size of the buffer to allocate 279 */ 280 Lpc = lpc = (caddr_t)PRF_ROUNDWN((long)lpc, sizeof (long)); 281 Hpc = hpc = (caddr_t)PRF_ROUNDUP((long)hpc, sizeof (long)); 282 283 hsize = sizeof (L_hdr); 284 msize = (size_t)(hpc - lpc); 285 psize = (size_t)PRF_ROUNDUP((msize / PRF_BARSIZE), sizeof (long)); 286 csize = (nsym + 1) * PRF_CGINIT * sizeof (L_cgarc); 287 Fsize = (hsize + psize + csize); 288 289 /* 290 * If the file size is zero (ie. we just created it), truncate it 291 * to the minimum size. 292 */ 293 (void) fstat(fd, &status); 294 if (status.st_size == 0) { 295 if (ftruncate(fd, Fsize) == -1) { 296 err = errno; 297 (void) fprintf(stderr, MSG_INTL(MSG_SYS_FTRUNC), 298 Profile, strerror(err)); 299 (void) close(fd); 300 return (0); 301 } 302 new_buffer++; 303 } else 304 Fsize = status.st_size; 305 306 /* 307 * Map the file in. 308 */ 309 if ((addr = (caddr_t)mmap(0, Fsize, (PROT_READ | PROT_WRITE), 310 MAP_SHARED, fd, 0)) == (char *)-1) { 311 err = errno; 312 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP), Profile, 313 strerror(err)); 314 (void) close(fd); 315 return (0); 316 } 317 (void) close(fd); 318 319 /* 320 * Initialize the remaining elements of the header. All pc addresses 321 * that are recorded are relative to zero thus allowing the recorded 322 * entries to be correlated with the symbols in the original file, 323 * and to compensate for any differences in where the file is mapped. 324 * If the high pc address has been initialized from a previous run, 325 * and the new entry is different from the original then a new library 326 * must have been installed. In this case bale out. 327 */ 328 /* LINTED */ 329 Hptr = (L_hdr *)addr; 330 331 if (new_buffer) 332 (void) prof_mutex_init((lwp_mutex_t *)&Hptr->hd_mutex); 333 334 (void) prof_mutex_lock((mutex_t *)&Hptr->hd_mutex, &mask); 335 if (Hptr->hd_hpc) { 336 if (Hptr->hd_hpc != (caddr_t)(hpc - lpc)) { 337 (void) fprintf(stderr, MSG_INTL(MSG_GEN_PROFSZCHG), 338 Profile); 339 (void) prof_mutex_unlock((mutex_t *)&Hptr-> 340 hd_mutex, &mask); 341 (void) munmap((caddr_t)Hptr, Fsize); 342 return (0); 343 } 344 } else { 345 /* 346 * Initialize the header information as we must have just 347 * created the output file. 348 */ 349 Hptr->hd_magic = (unsigned int)PRF_MAGIC; 350 #if defined(_ELF64) 351 Hptr->hd_version = (unsigned int)PRF_VERSION_64; 352 #else 353 Hptr->hd_version = (unsigned int)PRF_VERSION; 354 #endif 355 Hptr->hd_hpc = (caddr_t)(hpc - lpc); 356 /* LINTED */ 357 Hptr->hd_psize = (unsigned int)psize; 358 /* LINTED */ 359 Hptr->hd_fsize = (unsigned int)Fsize; 360 Hptr->hd_ncndx = nsym; 361 Hptr->hd_lcndx = (nsym + 1) * PRF_CGINIT; 362 } 363 364 (void) prof_mutex_unlock((mutex_t *)&Hptr->hd_mutex, &mask); 365 /* LINTED */ 366 Cptr = (L_cgarc *)(addr + hsize + psize); 367 368 /* 369 * Turn on profiling 370 */ 371 /* LINTED */ 372 profil((unsigned short *)(addr + hsize), 373 psize, (unsigned long)lpc, (unsigned int) PRF_SCALE); 374 375 return (1); 376 } 377 378 379 uint_t 380 /* ARGSUSED1 */ 381 la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) 382 { 383 char *objname; 384 385 /* 386 * This would only occur if the getenv() in la_version() failed. 387 * at this point there is nothing for us to do. 388 */ 389 if (pname == 0) 390 return (0); 391 392 /* 393 * Just grab the 'basename' of the object current object for 394 * comparing against the 'profiled object name' 395 */ 396 if (((objname = strrchr(lmp->l_name, '/')) == 0) || 397 (*(++objname) == 0)) 398 objname = lmp->l_name; 399 400 /* 401 * Is this the object we are going to profile. If not 402 * just set the 'BINDFROM' flag for this object. 403 */ 404 if ((strcmp(pname, objname) != 0) && 405 (strcmp(pname, lmp->l_name) != 0)) 406 return (LA_FLG_BINDFROM); 407 408 /* 409 * Don't even try to profile an object that does not have 410 * auditing enabled on it's link-map. This catches 'ld.so.1'. 411 */ 412 if (LIST((Rt_map *)lmp)->lm_flags & LML_FLG_NOAUDIT) 413 return (LA_FLG_BINDFROM); 414 415 if (profile_open(pname, lmp) == 0) 416 return (0); 417 418 profcookie = *cookie; 419 420 return (LA_FLG_BINDFROM | LA_FLG_BINDTO); 421 } 422 423 424 425 uint_t 426 la_objclose(uintptr_t *cookie) 427 { 428 if (*cookie != profcookie) 429 return (0); 430 431 profcookie = 0; 432 /* 433 * Turn profil() off. 434 */ 435 profil(0, 0, 0, 0); 436 (void) munmap((caddr_t)Hptr, Fsize); 437 return (0); 438 } 439 440 441 static int 442 remap_profile(int fd) 443 { 444 caddr_t addr; 445 size_t l_fsize; 446 447 l_fsize = Hptr->hd_fsize; 448 449 if ((addr = (caddr_t)mmap(0, l_fsize, (PROT_READ | PROT_WRITE), 450 MAP_SHARED, fd, 0)) == (char *)-1) { 451 int err = errno; 452 453 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP), Profile, 454 strerror(err)); 455 return (0); 456 } 457 (void) munmap((caddr_t)Hptr, Fsize); 458 459 Fsize = l_fsize; 460 /* LINTED */ 461 Hptr = (L_hdr*) addr; 462 /* LINTED */ 463 Cptr = (L_cgarc *)(addr + sizeof (L_hdr) + Hptr->hd_psize); 464 return (1); 465 } 466 467 468 /* 469 * Update a call graph arc entry. This routine can be called three ways; 470 * o On initialization from one of the bndr() functions. 471 * In this case the `to' address is known, and may be used to 472 * initialize the call graph entry if this function has not 473 * been entered before. 474 * o On initial relocation (ie. LD_BIND_NOW). In this case the `to' 475 * address is known but the `from' isn't. The call graph entry 476 * is initialized to hold this dummy `to' address, but will be 477 * re-initialized later when a function is first called. 478 * o From an initialized plt entry. When profiling, the plt entries 479 * are filled in with the calling functions symbol index and 480 * the plt_cg_elf interface function. This interface function 481 * calls here to determine the `to' functions address, and in so 482 * doing increments the call count. 483 */ 484 uintptr_t 485 plt_cg_interp(uint_t ndx, caddr_t from, caddr_t to) 486 { 487 L_cgarc * cptr, cbucket; 488 sigset_t mask; 489 490 /* 491 * If the from address is outside of the address range being profiled, 492 * simply assign it to the `outside' address. 493 */ 494 if (from != PRF_UNKNOWN) { 495 if ((from > Hpc) || (from < Lpc)) 496 from = PRF_OUTADDR; 497 else 498 from = (caddr_t)(from - Lpc); 499 } 500 501 (void) prof_mutex_lock((mutex_t *)&Hptr->hd_mutex, &mask); 502 /* 503 * Has the buffer grown since last we looked at it (another processes 504 * could have grown it...). 505 */ 506 /* LINTED */ 507 if (Hptr->hd_fsize != (unsigned int)Fsize) { 508 int fd; 509 fd = open(Profile, O_RDWR, 0); 510 if (remap_profile(fd) == 0) { 511 (void) prof_mutex_unlock((mutex_t *)&Hptr->hd_mutex, 512 &mask); 513 exit(1); 514 } 515 (void) close(fd); 516 } 517 518 cptr = &Cptr[ndx]; 519 520 if (cptr->cg_to == 0) { 521 /* 522 * If this is the first time this function has been called we 523 * got here from one of the binders or an initial relocation 524 * (ie. LD_BIND_NOW). In this case the `to' address is 525 * provided. Initialize this functions call graph entry with 526 * the functions address (retained as a relative offset). 527 * If we know where the function call originated from 528 * initialize the count field. 529 */ 530 cptr->cg_to = (caddr_t)(to - Lpc); 531 cptr->cg_from = from; 532 if (from != PRF_UNKNOWN) 533 cptr->cg_count = 1; 534 } else { 535 /* 536 * If a function has been called from a previous run, but we 537 * don't know where we came from (ie. LD_BIND_NOW), then later 538 * calls through the plt will be able to obtain the required 539 * functions address, thus there is no need to proceed further. 540 */ 541 if (from != PRF_UNKNOWN) { 542 /* 543 * If the from addresses match simply bump the count. 544 * If not scan the link list to find a match for this 545 * `from' address. If one doesn't exit create a new 546 * entry and link it in. 547 */ 548 while ((cptr->cg_from != from) && 549 (cptr->cg_from != PRF_UNKNOWN)) { 550 if (cptr->cg_next != 0) 551 cptr = &Cptr[cptr->cg_next]; 552 else { 553 to = cptr->cg_to; 554 cptr->cg_next = Hptr->hd_ncndx++; 555 cptr = &Cptr[cptr->cg_next]; 556 /* 557 * If we've run out of file, extend it. 558 */ 559 if (Hptr->hd_ncndx == Hptr->hd_lcndx) { 560 caddr_t addr; 561 int fd; 562 563 /* LINTED */ 564 Hptr->hd_fsize += (unsigned int) 565 PRF_CGNUMB * 566 sizeof (L_cgarc); 567 fd = open(Profile, O_RDWR, 0); 568 if (ftruncate(fd, 569 Hptr->hd_fsize) == -1) { 570 int err = errno; 571 572 (void) fprintf(stderr, 573 MSG_INTL( 574 MSG_SYS_FTRUNC), 575 Profile, 576 strerror(err)); 577 (void) close(fd); 578 cptr = &cbucket; 579 } 580 /* 581 * Since the buffer will be 582 * remapped, we need to be 583 * prepared to adjust cptr. 584 */ 585 addr = (caddr_t)((Addr)cptr - 586 (Addr)Cptr); 587 if (remap_profile(fd) == 0) { 588 (void) prof_mutex_unlock( 589 (mutex_t *)&Hptr-> 590 hd_mutex, &mask); 591 exit(1); 592 } 593 cptr = (L_cgarc *)((Addr)addr + 594 (Addr)Cptr); 595 (void) close(fd); 596 Hptr->hd_lcndx += PRF_CGNUMB; 597 } 598 cptr->cg_from = from; 599 cptr->cg_to = to; 600 } 601 } 602 /* 603 * If we're updating an entry from an unknown call 604 * address initialize this element, otherwise 605 * increment the call count. 606 */ 607 if (cptr->cg_from == PRF_UNKNOWN) { 608 cptr->cg_from = from; 609 cptr->cg_count = 1; 610 } else 611 cptr->cg_count++; 612 } 613 } 614 /* 615 * Return the real address of the function. 616 */ 617 (void) prof_mutex_unlock((mutex_t *)&Hptr->hd_mutex, &mask); 618 619 return ((uintptr_t)((Addr)cptr->cg_to + (Addr)Lpc)); 620 } 621 622 /* ARGSUSED2 */ 623 #if defined(__sparcv9) 624 uintptr_t 625 la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 626 uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sbflags, 627 const char *sym_name) 628 #elif defined(__sparc) 629 uintptr_t 630 la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, 631 uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sbflags) 632 #elif defined(__amd64) 633 uintptr_t 634 la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 635 uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sbflags, 636 const char *sym_name) 637 #elif defined(__i386) 638 uintptr_t 639 la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, 640 uintptr_t *defcookie, La_i86_regs *regset, uint_t *sbflags) 641 #else 642 #error unexpected architecture! 643 #endif 644 { 645 caddr_t from; 646 647 /* 648 * profiling has been disabled. 649 */ 650 if (profcookie == 0) 651 return (symp->st_value); 652 #if defined(__sparc) || defined(__sparcv9) 653 /* 654 * The callers return address is currently stored in O7 (which 655 * will become I7 when the window shift occurs). 656 */ 657 from = (caddr_t)regset->lr_rego7; 658 #elif defined(__amd64) 659 /* 660 * The callers return address is on the top of the stack for amd64 661 */ 662 from = *(caddr_t *)(regset->lr_rsp); 663 #elif defined(__i386) 664 /* 665 * The callers return address is on the top of the stack for i386 666 */ 667 from = *(caddr_t *)(regset->lr_esp); 668 #else 669 #error unexpected architecture! 670 #endif 671 return (plt_cg_interp(symndx, (caddr_t)from, (caddr_t)symp->st_value)); 672 } 673