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