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