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