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