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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <link.h> 27 #include <dlfcn.h> 28 #include <sys/types.h> 29 #include <sys/param.h> 30 #include <sys/resource.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <regex.h> 37 #include <signal.h> 38 #include <synch.h> 39 #include <fcntl.h> 40 #include <sys/stat.h> 41 #include <apptrace.h> 42 #include <libintl.h> 43 #include <locale.h> 44 #include <limits.h> 45 #include <sys/sysmacros.h> 46 #include "abienv.h" 47 #include "mach.h" 48 49 #include <libproc.h> 50 #include <libctf.h> 51 52 #define NUM_ARGS 40 53 54 extern const char *type_name(ctf_file_t *, ctf_id_t, char *, size_t); 55 extern void print_value(ctf_file_t *, ctf_id_t, ulong_t); 56 57 static struct ps_prochandle *proc_hdl = NULL; 58 59 static Liblist *bindto_list; 60 static Liblist *bindto_excl; 61 static Liblist *bindfrom_list; 62 static Liblist *bindfrom_excl; 63 static Liblist *intlib_list; 64 static uint_t pidout; 65 static Intlist *trace_list; 66 static Intlist *trace_excl; 67 static Intlist *verbose_list; 68 static Intlist *verbose_excl; 69 70 /* 71 * Required for calls to build_env_list1 where 72 * things are added to the end of the list (preserving 73 * search order implied by the setting of env variables 74 * in apptracecmd.c) 75 */ 76 static Liblist *intlib_listend; 77 78 /* 79 * These globals are sought and used by interceptlib.c 80 * which goes into all interceptor objects. 81 */ 82 FILE *ABISTREAM = stderr; 83 sigset_t abisigset; 84 85 /* 86 * Strings are printed with "%.*s", abi_strpsz, string 87 */ 88 int abi_strpsz = 20; 89 90 /* 91 * Special function pointers that'll be set up to point at the 92 * libc/libthread versions in the _application's_ link map (as opposed 93 * to our own). 94 * 95 * Additionally, it is impossible to generalize the programmatic 96 * creation of interceptor functions for variable argument list 97 * functions. However, in the case of the printf family, there is a 98 * vprintf equivalent. The interceptors for the printf family live in 99 * interceptor.c and they call the appropriate vprintf interface 100 * instead of the printf interface that they're intercepting. The 101 * link map issue remains, however, so function pointers for the 102 * vprintf family in the application's link map are set up here. 103 * 104 * The interceptors also need to examine errno which also needs to be 105 * extracted from the base link map. 106 * 107 * All of these pointers are initialized in la_preinit(). 108 */ 109 110 thread_t (*abi_thr_self)(void); 111 int (*abi_thr_main)(void); 112 113 int (*ABI_VFPRINTF)(FILE *, char const *, va_list); 114 int (*ABI_VFWPRINTF)(FILE *, const wchar_t *, va_list); 115 int (*ABI_VPRINTF)(char const *, va_list); 116 int (*ABI_VSNPRINTF)(char *, size_t, char const *, va_list); 117 int (*ABI_VSPRINTF)(char *, char const *, va_list); 118 int (*ABI_VSWPRINTF)(wchar_t *, size_t, const wchar_t *, va_list); 119 int (*ABI_VWPRINTF)(const wchar_t *, va_list); 120 int *(*__abi_real_errno)(void); 121 122 #if defined(__sparcv9) 123 static char const *libcpath = "/lib/sparcv9/libc.so.1"; 124 #elif defined(__amd64) 125 static char const *libcpath = "/lib/amd64/libc.so.1"; 126 #else 127 static char const *libcpath = "/lib/libc.so.1"; 128 #endif 129 130 /* Used as arguments later to dlsym */ 131 static char const *thr_main_sym = "thr_main"; 132 static char const *thr_self_sym = "thr_self"; 133 static char const *vfprintf_sym = "vfprintf"; 134 static char const *vfwprintf_sym = "vfwprintf"; 135 static char const *vprintf_sym = "vprintf"; 136 static char const *vsnprintf_sym = "vsnprintf"; 137 static char const *vsprintf_sym = "vsprintf"; 138 static char const *vswprintf_sym = "vswprintf"; 139 static char const *vwprintf_sym = "vwprintf"; 140 static char const *errno_sym = "___errno"; 141 142 /* 143 * The list of functions below are functions for which 144 * apptrace.so will not perform any tracing. 145 * 146 * The user visible failure of tracing these functions 147 * is a core dump of the application under observation. 148 * 149 * This list was originally discovered during sotruss 150 * development. Attempts lacking sufficient determination 151 * to shrink this list have failed. 152 * 153 * There are a number of different kinds of issues here. 154 * 155 * The .stretX functions have to do with the relationship 156 * that the caller and callee has with functions that 157 * return structures and the altered calling convention 158 * that results. 159 * 160 * We cannot trace *setjmp because the caller of these routines 161 * is not allow to return which is exactly what an interceptor 162 * function is going to do. 163 * 164 * The *context functions are on the list because we cannot trace 165 * netscape without them on the list, but the exact mechanics of the 166 * failure are not known at this time. 167 * 168 * The leaf functions *getsp can probably be removed given the 169 * presence of an interceptor but that experiment has not been 170 * conducted. 171 * 172 * NOTE: this list *must* be maintained in alphabetical order. 173 * if this list ever became too long a faster search mechanism 174 * should be considered. 175 */ 176 static char *spec_sym[] = { 177 #if defined(sparc) 178 ".stret1", 179 ".stret2", 180 ".stret4", 181 ".stret8", 182 #endif 183 "__getcontext", 184 "_getcontext", 185 "_getsp", 186 "_longjmp", 187 "_setcontext", 188 "_setjmp", 189 "_siglongjmp", 190 "_sigsetjmp", 191 "_vfork", 192 "getcontext", 193 "getsp", 194 "longjmp", 195 "setcontext", 196 "setjmp", 197 "siglongjmp", 198 "sigsetjmp", 199 "vfork", 200 NULL 201 }; 202 203 uint_t 204 la_version(uint_t version) 205 { 206 char *str; 207 FILE *fp; 208 209 if (version > LAV_CURRENT) 210 (void) fprintf(stderr, 211 dgettext(TEXT_DOMAIN, 212 "apptrace: unexpected version: %u\n"), 213 version); 214 215 build_env_list(&bindto_list, "APPTRACE_BINDTO"); 216 build_env_list(&bindto_excl, "APPTRACE_BINDTO_EXCLUDE"); 217 218 build_env_list(&bindfrom_list, "APPTRACE_BINDFROM"); 219 build_env_list(&bindfrom_excl, "APPTRACE_BINDFROM_EXCLUDE"); 220 221 if (checkenv("APPTRACE_PID") != NULL) { 222 pidout = 1; 223 } else { 224 char *str = "LD_AUDIT="; 225 char *str2 = "LD_AUDIT64="; 226 /* 227 * This disables apptrace output in subsequent exec'ed 228 * processes. 229 */ 230 (void) putenv(str); 231 (void) putenv(str2); 232 } 233 234 if ((str = checkenv("APPTRACE_OUTPUT")) != NULL) { 235 int fd, newfd, targetfd, lowerlimit; 236 struct rlimit rl; 237 238 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { 239 (void) fprintf(stderr, 240 dgettext(TEXT_DOMAIN, 241 "apptrace: getrlimit: %s\n"), 242 strerror(errno)); 243 exit(EXIT_FAILURE); 244 } 245 246 fd = open(str, O_WRONLY|O_CREAT|O_TRUNC, 0666); 247 if (fd == -1) { 248 (void) fprintf(stderr, 249 dgettext(TEXT_DOMAIN, 250 "apptrace: %s: %s\n"), 251 str, 252 strerror(errno)); 253 exit(EXIT_FAILURE); 254 } 255 256 /* 257 * Those fans of dup2 should note that dup2 cannot 258 * be used below because dup2 closes the target file 259 * descriptor. Thus, if we're apptracing say, ksh 260 * we'd have closed the fd it uses for the history 261 * file (63 on my box). 262 * 263 * fcntl with F_DUPFD returns first available >= arg3 264 * so we iterate from the top until we find a available 265 * fd. 266 * 267 * Not finding an fd after 10 tries is a failure. 268 * 269 * Since the _file member of the FILE structure is an 270 * unsigned char, we must clamp our fd request to 271 * UCHAR_MAX 272 */ 273 lowerlimit = ((rl.rlim_cur > 274 UCHAR_MAX) ? UCHAR_MAX : rl.rlim_cur) - 10; 275 276 for (targetfd = lowerlimit + 10; 277 targetfd > lowerlimit; targetfd--) { 278 if ((newfd = fcntl(fd, F_DUPFD, targetfd)) != -1) 279 break; 280 } 281 282 if (newfd == -1) { 283 (void) fprintf(stderr, 284 dgettext(TEXT_DOMAIN, 285 "apptrace: F_DUPFD: %s\n"), 286 strerror(errno)); 287 exit(EXIT_FAILURE); 288 } 289 (void) close(fd); 290 291 if (fcntl(newfd, F_SETFD, FD_CLOEXEC) == -1) { 292 (void) fprintf(stderr, 293 dgettext(TEXT_DOMAIN, 294 "apptrace: fcntl FD_CLOEXEC: %s\n"), 295 strerror(errno)); 296 exit(EXIT_FAILURE); 297 } 298 299 if ((fp = fdopen(newfd, "wF")) != NULL) { 300 ABISTREAM = fp; 301 } else { 302 (void) fprintf(stderr, 303 dgettext(TEXT_DOMAIN, 304 "apptrace: fdopen: %s\n"), 305 strerror(errno)); 306 exit(EXIT_FAILURE); 307 } 308 } 309 310 #if defined(_LP64) 311 build_env_list1(&intlib_list, &intlib_listend, 312 "APPTRACE_INTERCEPTORS64"); 313 #else 314 build_env_list1(&intlib_list, &intlib_listend, 315 "APPTRACE_INTERCEPTORS"); 316 #endif 317 318 /* Set up lists interfaces to trace or ignore */ 319 env_to_intlist(&trace_list, "APPTRACE_INTERFACES"); 320 env_to_intlist(&trace_excl, "APPTRACE_INTERFACES_EXCLUDE"); 321 env_to_intlist(&verbose_list, "APPTRACE_VERBOSE"); 322 env_to_intlist(&verbose_excl, "APPTRACE_VERBOSE_EXCLUDE"); 323 324 return (LAV_CURRENT); 325 } 326 327 /* ARGSUSED1 */ 328 uint_t 329 la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) 330 { 331 uint_t flags; 332 static int first = 1; 333 int perr; 334 335 /* 336 * If this is the first time in, then l_name is the app 337 * and unless the user gave an explict from list 338 * we will trace calls from it. 339 */ 340 if (first && bindfrom_list == NULL) { 341 flags = LA_FLG_BINDFROM | LA_FLG_BINDTO; 342 first = 0; 343 goto work; 344 } 345 346 /* 347 * If we have no bindto_list, then we assume that we 348 * bindto everything (apptrace -T \*) 349 * 350 * Otherwise we make sure that l_name is on the list. 351 */ 352 flags = 0; 353 if (bindto_list == NULL) { 354 flags = LA_FLG_BINDTO; 355 } else if (check_list(bindto_list, lmp->l_name) != NULL) { 356 flags |= LA_FLG_BINDTO; 357 } 358 359 /* 360 * If l_name is on the exclusion list, zero the bit. 361 */ 362 if ((bindto_excl != NULL) && 363 check_list(bindto_excl, lmp->l_name) != NULL) { 364 flags &= ~LA_FLG_BINDTO; 365 } 366 367 /* 368 * If l_name is on the bindfrom list then trace 369 */ 370 if (check_list(bindfrom_list, lmp->l_name) != NULL) { 371 flags |= LA_FLG_BINDFROM; 372 } 373 374 /* 375 * If l_name is on the exclusion list, zero the bit 376 * else trace, (this allows "-F !foo" to imply 377 * "-F '*' -F !foo") 378 */ 379 if (check_list(bindfrom_excl, lmp->l_name) != NULL) { 380 flags &= ~LA_FLG_BINDFROM; 381 } else if (bindfrom_excl != NULL && bindfrom_list == NULL) { 382 flags |= LA_FLG_BINDFROM; 383 } 384 385 work: 386 if (flags) { 387 *cookie = (uintptr_t)abibasename(lmp->l_name); 388 389 /* 390 * only call Pgrab() once to get the ps_prochandle 391 */ 392 if (proc_hdl == NULL) 393 proc_hdl = Pgrab(getpid(), PGRAB_RDONLY, &perr); 394 } 395 396 return (flags); 397 } 398 399 static void 400 apptrace_preinit_fail(void) 401 { 402 (void) fprintf(stderr, 403 dgettext(TEXT_DOMAIN, "apptrace: la_preinit: %s\n"), 404 dlerror()); 405 exit(EXIT_FAILURE); 406 } 407 408 /* ARGSUSED */ 409 void 410 la_preinit(uintptr_t *cookie) 411 { 412 void *h = NULL; 413 414 (void) sigfillset(&abisigset); 415 416 h = dlmopen(LM_ID_BASE, libcpath, RTLD_LAZY | RTLD_NOLOAD); 417 if (h == NULL) 418 apptrace_preinit_fail(); 419 420 if ((abi_thr_self = 421 (thread_t (*)(void)) dlsym(h, thr_self_sym)) == NULL) 422 apptrace_preinit_fail(); 423 if ((abi_thr_main = 424 (int (*)(void)) dlsym(h, thr_main_sym)) == NULL) 425 apptrace_preinit_fail(); 426 427 /* Do printf style pointers */ 428 if ((ABI_VFPRINTF = 429 (int (*)(FILE *, char const *, va_list)) 430 dlsym(h, vfprintf_sym)) == NULL) 431 apptrace_preinit_fail(); 432 433 if ((ABI_VFWPRINTF = 434 (int (*)(FILE *, const wchar_t *, va_list)) 435 dlsym(h, vfwprintf_sym)) == NULL) 436 apptrace_preinit_fail(); 437 438 if ((ABI_VPRINTF = 439 (int (*)(char const *, va_list)) 440 dlsym(h, vprintf_sym)) == NULL) 441 apptrace_preinit_fail(); 442 443 if ((ABI_VSNPRINTF = 444 (int (*)(char *, size_t, char const *, va_list)) 445 dlsym(h, vsnprintf_sym)) == NULL) 446 apptrace_preinit_fail(); 447 448 if ((ABI_VSPRINTF = 449 (int (*)(char *, char const *, va_list)) 450 dlsym(h, vsprintf_sym)) == NULL) 451 apptrace_preinit_fail(); 452 453 if ((ABI_VSWPRINTF = 454 (int (*)(wchar_t *, size_t, const wchar_t *, va_list)) 455 dlsym(h, vswprintf_sym)) == NULL) 456 apptrace_preinit_fail(); 457 458 if ((ABI_VWPRINTF = 459 (int (*)(const wchar_t *, va_list)) 460 dlsym(h, vwprintf_sym)) == NULL) 461 apptrace_preinit_fail(); 462 463 if ((__abi_real_errno = 464 (int *(*)(void)) 465 dlsym(h, errno_sym)) == NULL) 466 apptrace_preinit_fail(); 467 468 (void) dlclose(h); 469 } 470 471 /* ARGSUSED1 */ 472 #if defined(_LP64) 473 uintptr_t 474 la_symbind64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcook, 475 uintptr_t *defcook, uint_t *sb_flags, char const *sym_name) 476 #else 477 uintptr_t 478 la_symbind32(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcook, 479 uintptr_t *defcook, uint_t *sb_flags) 480 #endif 481 { 482 #if !defined(_LP64) 483 char const *sym_name = (char const *) symp->st_name; 484 #endif 485 int intercept = 0, verbose = 0; 486 uintptr_t ret = symp->st_value; 487 uint_t ndx; 488 char *str; 489 490 #if defined(_LP64) 491 if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC) 492 goto end; 493 #else 494 /* If we're not looking at a function, bug out */ 495 if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC) 496 goto end; 497 #endif 498 499 if (verbose_list != NULL) { 500 /* apptrace ... -v verbose_list ... cmd */ 501 if (check_intlist(verbose_list, sym_name)) 502 verbose = 1; 503 } 504 if (verbose_excl != NULL) { 505 /* apptrace ... -v !verbose_excl ... cmd */ 506 if (check_intlist(verbose_excl, sym_name)) 507 verbose = 0; 508 else if (verbose_list == NULL && trace_list == NULL && 509 trace_excl == NULL) 510 /* apptrace -v !verbose_excl cmd */ 511 intercept = 1; 512 } 513 if (trace_list != NULL) { 514 /* apptrace ... -t trace_list ... cmd */ 515 if (check_intlist(trace_list, sym_name)) 516 intercept = 1; 517 } else if (verbose_list == NULL && verbose_excl == NULL) 518 /* default (implies -t '*'): apptrace cmd */ 519 intercept = 1; 520 521 if (trace_excl != NULL) { 522 /* apptrace ... -t !trace_excl ... cmd */ 523 if (check_intlist(trace_excl, sym_name)) 524 intercept = 0; 525 } 526 527 if (verbose == 0 && intercept == 0) { 528 *sb_flags |= (LA_SYMB_NOPLTEXIT | LA_SYMB_NOPLTENTER); 529 goto end; 530 } 531 532 /* 533 * Check to see if this symbol is one of the 'special' symbols. 534 * If so we disable calls for that symbol. 535 */ 536 for (ndx = 0; (str = spec_sym[ndx]) != NULL; ndx++) { 537 int cmpval; 538 cmpval = strcmp(sym_name, str); 539 if (cmpval < 0) 540 break; 541 if (cmpval == 0) { 542 intercept = verbose = 0; 543 *sb_flags |= (LA_SYMB_NOPLTEXIT | LA_SYMB_NOPLTENTER); 544 break; 545 } 546 } 547 548 end: 549 return (ret); 550 } 551 552 /* ARGSUSED1 */ 553 #if defined(__sparcv9) 554 uintptr_t 555 la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 556 uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags, 557 char const *sym_name) 558 #elif defined(__sparc) 559 uintptr_t 560 la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, 561 uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags) 562 #elif defined(__amd64) 563 uintptr_t 564 la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 565 uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags, 566 char const *sym_name) 567 #elif defined(__i386) 568 uintptr_t 569 la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, 570 uintptr_t *defcookie, La_i86_regs *regset, uint_t *sb_flags) 571 #endif 572 { 573 char *defname = (char *)(*defcookie); 574 char *refname = (char *)(*refcookie); 575 sigset_t omask; 576 #if !defined(_LP64) 577 char const *sym_name = (char const *)symp->st_name; 578 #endif 579 580 char buf[256]; 581 GElf_Sym sym; 582 prsyminfo_t si; 583 ctf_file_t *ctfp; 584 ctf_funcinfo_t finfo; 585 int argc; 586 ctf_id_t argt[NUM_ARGS]; 587 ulong_t argv[NUM_ARGS]; 588 int i; 589 char *sep = ""; 590 ctf_id_t type, rtype; 591 int kind; 592 593 abilock(&omask); 594 595 if (pidout) 596 (void) fprintf(ABISTREAM, "%7u:", (unsigned int)getpid()); 597 598 if ((ctfp = Pname_to_ctf(proc_hdl, defname)) == NULL) 599 goto fail; 600 601 if (Pxlookup_by_name(proc_hdl, PR_LMID_EVERY, defname, sym_name, 602 &sym, &si) != 0) 603 goto fail; 604 605 if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR) 606 goto fail; 607 608 (void) type_name(ctfp, finfo.ctc_return, buf, sizeof (buf)); 609 (void) fprintf(ABISTREAM, "-> %-8s -> %8s:%s %s(", 610 refname, defname, buf, sym_name); 611 612 /* 613 * According to bug in la_pltexit(), it can't return 614 * if the type is just a struct/union. So, if the return 615 * type is a struct/union, la_pltexit() should be off. 616 */ 617 rtype = ctf_type_resolve(ctfp, finfo.ctc_return); 618 type = ctf_type_reference(ctfp, rtype); 619 rtype = ctf_type_resolve(ctfp, type); 620 kind = ctf_type_kind(ctfp, rtype); 621 if ((kind == CTF_K_STRUCT || kind == CTF_K_UNION) && 622 strpbrk(buf, "*") == NULL) 623 *sb_flags |= LA_SYMB_NOPLTEXIT; 624 625 argc = MIN(sizeof (argt) / sizeof (argt[0]), finfo.ctc_argc); 626 (void) ctf_func_args(ctfp, si.prs_id, argc, argt); 627 628 argv[0] = GETARG0(regset); 629 if (argc > 1) 630 argv[1] = GETARG1(regset); 631 if (argc > 2) 632 argv[2] = GETARG2(regset); 633 if (argc > 3) 634 argv[3] = GETARG3(regset); 635 if (argc > 4) 636 argv[4] = GETARG4(regset); 637 if (argc > 5) 638 argv[5] = GETARG5(regset); 639 if (argc > 6) { 640 for (i = 6; i < argc; i++) 641 argv[i] = GETARG_6NUP(i, regset); 642 } 643 644 for (i = 0; i < argc; i++) { 645 (void) type_name(ctfp, argt[i], buf, sizeof (buf)); 646 (void) fprintf(ABISTREAM, "%s%s = ", sep, buf); 647 rtype = ctf_type_resolve(ctfp, argt[i]); 648 type = ctf_type_reference(ctfp, rtype); 649 rtype = ctf_type_resolve(ctfp, type); 650 kind = ctf_type_kind(ctfp, rtype); 651 if (kind == CTF_K_STRUCT || kind == CTF_K_UNION) 652 (void) fprintf(ABISTREAM, "0x%p", (void *)argv[i]); 653 else 654 print_value(ctfp, argt[i], argv[i]); 655 sep = ", "; 656 } 657 658 if (finfo.ctc_flags & CTF_FUNC_VARARG) 659 (void) fprintf(ABISTREAM, "%s...", sep); 660 else if (argc == 0) 661 (void) fprintf(ABISTREAM, "void"); 662 663 if ((*sb_flags & LA_SYMB_NOPLTEXIT) != 0) 664 (void) fprintf(ABISTREAM, ") ** ST\n"); 665 else 666 (void) fprintf(ABISTREAM, ")\n"); 667 668 if (verbose_list != NULL && 669 check_intlist(verbose_list, sym_name) != 0) { 670 for (i = 0; i < argc; i++) { 671 (void) type_name(ctfp, argt[i], buf, sizeof (buf)); 672 (void) fprintf(ABISTREAM, "\targ%d = (%s) ", i, buf); 673 print_value(ctfp, argt[i], argv[i]); 674 (void) fprintf(ABISTREAM, "\n"); 675 } 676 if ((*sb_flags & LA_SYMB_NOPLTEXIT) != 0) { 677 if (kind == CTF_K_STRUCT) 678 (void) fprintf(ABISTREAM, 679 "\treturn = (struct), apptrace " 680 "will not trace the return\n"); 681 else 682 (void) fprintf(ABISTREAM, 683 "\treturn = (union), apptrace " 684 "will not trace the return\n"); 685 } 686 } 687 688 (void) fflush(ABISTREAM); 689 abiunlock(&omask); 690 return (symp->st_value); 691 692 fail: 693 (void) fprintf(ABISTREAM, 694 "-> %-8s -> %8s:%s(0x%lx, 0x%lx, 0x%lx) ** NR\n", 695 refname, defname, sym_name, 696 (ulong_t)GETARG0(regset), 697 (ulong_t)GETARG1(regset), 698 (ulong_t)GETARG2(regset)); 699 700 *sb_flags |= LA_SYMB_NOPLTEXIT; 701 (void) fflush(ABISTREAM); 702 abiunlock(&omask); 703 return (symp->st_value); 704 } 705 706 /* ARGSUSED */ 707 #if defined(_LP64) 708 uintptr_t 709 la_pltexit64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 710 uintptr_t *defcookie, uintptr_t retval, const char *sym_name) 711 #else 712 uintptr_t 713 la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, 714 uintptr_t *defcookie, uintptr_t retval) 715 #endif 716 { 717 #if !defined(_LP64) 718 const char *sym_name = (const char *)symp->st_name; 719 #endif 720 sigset_t omask; 721 char buf[256]; 722 GElf_Sym sym; 723 prsyminfo_t si; 724 ctf_file_t *ctfp; 725 ctf_funcinfo_t finfo; 726 char *defname = (char *)(*defcookie); 727 char *refname = (char *)(*refcookie); 728 729 abilock(&omask); 730 731 if (pidout) 732 (void) fprintf(ABISTREAM, "%7u:", (unsigned int)getpid()); 733 734 if (retval == 0) { 735 if (verbose_list == NULL) { 736 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()\n", 737 refname, defname, sym_name); 738 (void) fflush(ABISTREAM); 739 } 740 abiunlock(&omask); 741 return (retval); 742 } 743 744 if ((ctfp = Pname_to_ctf(proc_hdl, defname)) == NULL) 745 goto fail; 746 747 if (Pxlookup_by_name(proc_hdl, PR_LMID_EVERY, defname, 748 sym_name, &sym, &si) != 0) 749 goto fail; 750 751 if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR) 752 goto fail; 753 754 if (verbose_list != NULL) { 755 if (check_intlist(verbose_list, sym_name) != 0) { 756 (void) type_name(ctfp, finfo.ctc_return, buf, 757 sizeof (buf)); 758 (void) fprintf(ABISTREAM, "\treturn = (%s) ", buf); 759 print_value(ctfp, finfo.ctc_return, retval); 760 (void) fprintf(ABISTREAM, "\n"); 761 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()", 762 refname, defname, sym_name); 763 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval); 764 } 765 } else { 766 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()", 767 refname, defname, sym_name); 768 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval); 769 } 770 771 (void) fflush(ABISTREAM); 772 abiunlock(&omask); 773 return (retval); 774 775 fail: 776 if (verbose_list != NULL) { 777 if (check_intlist(verbose_list, sym_name) != 0) { 778 (void) fprintf(ABISTREAM, 779 "\treturn = 0x%p\n", (void *)retval); 780 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()", 781 refname, defname, sym_name); 782 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval); 783 } 784 } else { 785 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()", 786 refname, defname, sym_name); 787 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval); 788 } 789 790 (void) fflush(ABISTREAM); 791 abiunlock(&omask); 792 return (retval); 793 } 794