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