dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / abi / apptrace / common / apptrace.c
blobb40d9d860f578caf8ac015f670df5d2cebca3375
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
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"
51 #include <libproc.h>
52 #include <libctf.h>
54 #define NUM_ARGS 40
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);
59 static struct ps_prochandle *proc_hdl = NULL;
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;
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)
78 static Liblist *intlib_listend;
81 * These globals are sought and used by interceptlib.c
82 * which goes into all interceptor objects.
84 FILE *ABISTREAM;
85 sigset_t abisigset;
88 * Strings are printed with "%.*s", abi_strpsz, string
90 int abi_strpsz = 20;
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).
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.
106 * The interceptors also need to examine errno which also needs to be
107 * extracted from the base link map.
109 * All of these pointers are initialized in la_preinit().
112 thread_t (*abi_thr_self)(void);
113 int (*abi_thr_main)(void);
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);
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
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";
145 * The list of functions below are functions for which
146 * apptrace.so will not perform any tracing.
148 * The user visible failure of tracing these functions
149 * is a core dump of the application under observation.
151 * This list was originally discovered during sotruss
152 * development. Attempts lacking sufficient determination
153 * to shrink this list have failed.
155 * There are a number of different kinds of issues here.
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.
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.
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.
170 * The leaf functions *getsp can probably be removed given the
171 * presence of an interceptor but that experiment has not been
172 * conducted.
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.
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
205 uint_t
206 la_version(uint_t version)
208 char *str;
209 FILE *fp;
211 ABISTREAM = stderr;
213 if (version > LAV_CURRENT)
214 (void) fprintf(stderr,
215 dgettext(TEXT_DOMAIN,
216 "apptrace: unexpected version: %u\n"),
217 version);
219 build_env_list(&bindto_list, "APPTRACE_BINDTO");
220 build_env_list(&bindto_excl, "APPTRACE_BINDTO_EXCLUDE");
222 build_env_list(&bindfrom_list, "APPTRACE_BINDFROM");
223 build_env_list(&bindfrom_excl, "APPTRACE_BINDFROM_EXCLUDE");
225 if (checkenv("APPTRACE_PID") != NULL) {
226 pidout = 1;
227 } else {
228 char *str = "LD_AUDIT=";
229 char *str2 = "LD_AUDIT64=";
231 * This disables apptrace output in subsequent exec'ed
232 * processes.
234 (void) putenv(str);
235 (void) putenv(str2);
238 if ((str = checkenv("APPTRACE_OUTPUT")) != NULL) {
239 int fd, newfd, targetfd, lowerlimit;
240 struct rlimit rl;
242 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
243 (void) fprintf(stderr,
244 dgettext(TEXT_DOMAIN,
245 "apptrace: getrlimit: %s\n"),
246 strerror(errno));
247 exit(EXIT_FAILURE);
250 fd = open(str, O_WRONLY|O_CREAT|O_TRUNC, 0666);
251 if (fd == -1) {
252 (void) fprintf(stderr,
253 dgettext(TEXT_DOMAIN,
254 "apptrace: %s: %s\n"),
255 str,
256 strerror(errno));
257 exit(EXIT_FAILURE);
261 * Those fans of dup2 should note that dup2 cannot
262 * be used below because dup2 closes the target file
263 * descriptor. Thus, if we're apptracing say, ksh
264 * we'd have closed the fd it uses for the history
265 * file (63 on my box).
267 * fcntl with F_DUPFD returns first available >= arg3
268 * so we iterate from the top until we find a available
269 * fd.
271 * Not finding an fd after 10 tries is a failure.
273 * Since the _file member of the FILE structure is an
274 * unsigned char, we must clamp our fd request to
275 * UCHAR_MAX
277 lowerlimit = ((rl.rlim_cur >
278 UCHAR_MAX) ? UCHAR_MAX : rl.rlim_cur) - 10;
280 for (targetfd = lowerlimit + 10;
281 targetfd > lowerlimit; targetfd--) {
282 if ((newfd = fcntl(fd, F_DUPFD, targetfd)) != -1)
283 break;
286 if (newfd == -1) {
287 (void) fprintf(stderr,
288 dgettext(TEXT_DOMAIN,
289 "apptrace: F_DUPFD: %s\n"),
290 strerror(errno));
291 exit(EXIT_FAILURE);
293 (void) close(fd);
295 if (fcntl(newfd, F_SETFD, FD_CLOEXEC) == -1) {
296 (void) fprintf(stderr,
297 dgettext(TEXT_DOMAIN,
298 "apptrace: fcntl FD_CLOEXEC: %s\n"),
299 strerror(errno));
300 exit(EXIT_FAILURE);
303 if ((fp = fdopen(newfd, "wF")) != NULL) {
304 ABISTREAM = fp;
305 } else {
306 (void) fprintf(stderr,
307 dgettext(TEXT_DOMAIN,
308 "apptrace: fdopen: %s\n"),
309 strerror(errno));
310 exit(EXIT_FAILURE);
314 #if defined(_LP64)
315 build_env_list1(&intlib_list, &intlib_listend,
316 "APPTRACE_INTERCEPTORS64");
317 #else
318 build_env_list1(&intlib_list, &intlib_listend,
319 "APPTRACE_INTERCEPTORS");
320 #endif
322 /* Set up lists interfaces to trace or ignore */
323 env_to_intlist(&trace_list, "APPTRACE_INTERFACES");
324 env_to_intlist(&trace_excl, "APPTRACE_INTERFACES_EXCLUDE");
325 env_to_intlist(&verbose_list, "APPTRACE_VERBOSE");
326 env_to_intlist(&verbose_excl, "APPTRACE_VERBOSE_EXCLUDE");
328 return (LAV_CURRENT);
331 /* ARGSUSED1 */
332 uint_t
333 la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie)
335 uint_t flags;
336 static int first = 1;
337 int perr;
340 * If this is the first time in, then l_name is the app
341 * and unless the user gave an explict from list
342 * we will trace calls from it.
344 if (first && bindfrom_list == NULL) {
345 flags = LA_FLG_BINDFROM | LA_FLG_BINDTO;
346 first = 0;
347 goto work;
351 * If we have no bindto_list, then we assume that we
352 * bindto everything (apptrace -T \*)
354 * Otherwise we make sure that l_name is on the list.
356 flags = 0;
357 if (bindto_list == NULL) {
358 flags = LA_FLG_BINDTO;
359 } else if (check_list(bindto_list, lmp->l_name) != NULL) {
360 flags |= LA_FLG_BINDTO;
364 * If l_name is on the exclusion list, zero the bit.
366 if ((bindto_excl != NULL) &&
367 check_list(bindto_excl, lmp->l_name) != NULL) {
368 flags &= ~LA_FLG_BINDTO;
372 * If l_name is on the bindfrom list then trace
374 if (check_list(bindfrom_list, lmp->l_name) != NULL) {
375 flags |= LA_FLG_BINDFROM;
379 * If l_name is on the exclusion list, zero the bit
380 * else trace, (this allows "-F !foo" to imply
381 * "-F '*' -F !foo")
383 if (check_list(bindfrom_excl, lmp->l_name) != NULL) {
384 flags &= ~LA_FLG_BINDFROM;
385 } else if (bindfrom_excl != NULL && bindfrom_list == NULL) {
386 flags |= LA_FLG_BINDFROM;
389 work:
390 if (flags) {
391 *cookie = (uintptr_t)abibasename(lmp->l_name);
394 * only call Pgrab() once to get the ps_prochandle
396 if (proc_hdl == NULL)
397 proc_hdl = Pgrab(getpid(), PGRAB_RDONLY, &perr);
400 return (flags);
403 static void
404 apptrace_preinit_fail(void)
406 (void) fprintf(stderr,
407 dgettext(TEXT_DOMAIN, "apptrace: la_preinit: %s\n"),
408 dlerror());
409 exit(EXIT_FAILURE);
412 /* ARGSUSED */
413 void
414 la_preinit(uintptr_t *cookie)
416 void *h = NULL;
418 (void) sigfillset(&abisigset);
420 h = dlmopen(LM_ID_BASE, libcpath, RTLD_LAZY | RTLD_NOLOAD);
421 if (h == NULL)
422 apptrace_preinit_fail();
424 if ((abi_thr_self =
425 (thread_t (*)(void)) dlsym(h, thr_self_sym)) == NULL)
426 apptrace_preinit_fail();
427 if ((abi_thr_main =
428 (int (*)(void)) dlsym(h, thr_main_sym)) == NULL)
429 apptrace_preinit_fail();
431 /* Do printf style pointers */
432 if ((ABI_VFPRINTF =
433 (int (*)(FILE *, char const *, va_list))
434 dlsym(h, vfprintf_sym)) == NULL)
435 apptrace_preinit_fail();
437 if ((ABI_VFWPRINTF =
438 (int (*)(FILE *, const wchar_t *, va_list))
439 dlsym(h, vfwprintf_sym)) == NULL)
440 apptrace_preinit_fail();
442 if ((ABI_VPRINTF =
443 (int (*)(char const *, va_list))
444 dlsym(h, vprintf_sym)) == NULL)
445 apptrace_preinit_fail();
447 if ((ABI_VSNPRINTF =
448 (int (*)(char *, size_t, char const *, va_list))
449 dlsym(h, vsnprintf_sym)) == NULL)
450 apptrace_preinit_fail();
452 if ((ABI_VSPRINTF =
453 (int (*)(char *, char const *, va_list))
454 dlsym(h, vsprintf_sym)) == NULL)
455 apptrace_preinit_fail();
457 if ((ABI_VSWPRINTF =
458 (int (*)(wchar_t *, size_t, const wchar_t *, va_list))
459 dlsym(h, vswprintf_sym)) == NULL)
460 apptrace_preinit_fail();
462 if ((ABI_VWPRINTF =
463 (int (*)(const wchar_t *, va_list))
464 dlsym(h, vwprintf_sym)) == NULL)
465 apptrace_preinit_fail();
467 if ((__abi_real_errno =
468 (int *(*)(void))
469 dlsym(h, errno_sym)) == NULL)
470 apptrace_preinit_fail();
472 (void) dlclose(h);
475 /* ARGSUSED1 */
476 #if defined(_LP64)
477 uintptr_t
478 la_symbind64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcook,
479 uintptr_t *defcook, uint_t *sb_flags, char const *sym_name)
480 #else
481 uintptr_t
482 la_symbind32(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcook,
483 uintptr_t *defcook, uint_t *sb_flags)
484 #endif
486 #if !defined(_LP64)
487 char const *sym_name = (char const *) symp->st_name;
488 #endif
489 int intercept = 0, verbose = 0;
490 uintptr_t ret = symp->st_value;
491 uint_t ndx;
492 char *str;
494 #if defined(_LP64)
495 if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
496 goto end;
497 #else
498 /* If we're not looking at a function, bug out */
499 if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
500 goto end;
501 #endif
503 if (verbose_list != NULL) {
504 /* apptrace ... -v verbose_list ... cmd */
505 if (check_intlist(verbose_list, sym_name))
506 verbose = 1;
508 if (verbose_excl != NULL) {
509 /* apptrace ... -v !verbose_excl ... cmd */
510 if (check_intlist(verbose_excl, sym_name))
511 verbose = 0;
512 else if (verbose_list == NULL && trace_list == NULL &&
513 trace_excl == NULL)
514 /* apptrace -v !verbose_excl cmd */
515 intercept = 1;
517 if (trace_list != NULL) {
518 /* apptrace ... -t trace_list ... cmd */
519 if (check_intlist(trace_list, sym_name))
520 intercept = 1;
521 } else if (verbose_list == NULL && verbose_excl == NULL)
522 /* default (implies -t '*'): apptrace cmd */
523 intercept = 1;
525 if (trace_excl != NULL) {
526 /* apptrace ... -t !trace_excl ... cmd */
527 if (check_intlist(trace_excl, sym_name))
528 intercept = 0;
531 if (verbose == 0 && intercept == 0) {
532 *sb_flags |= (LA_SYMB_NOPLTEXIT | LA_SYMB_NOPLTENTER);
533 goto end;
537 * Check to see if this symbol is one of the 'special' symbols.
538 * If so we disable calls for that symbol.
540 for (ndx = 0; (str = spec_sym[ndx]) != NULL; ndx++) {
541 int cmpval;
542 cmpval = strcmp(sym_name, str);
543 if (cmpval < 0)
544 break;
545 if (cmpval == 0) {
546 intercept = verbose = 0;
547 *sb_flags |= (LA_SYMB_NOPLTEXIT | LA_SYMB_NOPLTENTER);
548 break;
552 end:
553 return (ret);
556 /* ARGSUSED1 */
557 #if defined(__sparcv9)
558 uintptr_t
559 la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
560 uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags,
561 char const *sym_name)
562 #elif defined(__sparc)
563 uintptr_t
564 la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
565 uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags)
566 #elif defined(__amd64)
567 uintptr_t
568 la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
569 uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags,
570 char const *sym_name)
571 #elif defined(__i386)
572 uintptr_t
573 la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
574 uintptr_t *defcookie, La_i86_regs *regset, uint_t *sb_flags)
575 #endif
577 char *defname = (char *)(*defcookie);
578 char *refname = (char *)(*refcookie);
579 sigset_t omask;
580 #if !defined(_LP64)
581 char const *sym_name = (char const *)symp->st_name;
582 #endif
584 char buf[256];
585 GElf_Sym sym;
586 prsyminfo_t si;
587 ctf_file_t *ctfp;
588 ctf_funcinfo_t finfo;
589 int argc;
590 ctf_id_t argt[NUM_ARGS];
591 ulong_t argv[NUM_ARGS];
592 int i;
593 char *sep = "";
594 ctf_id_t type, rtype;
595 int kind;
597 abilock(&omask);
599 if (pidout)
600 (void) fprintf(ABISTREAM, "%7u:", (unsigned int)getpid());
602 if ((ctfp = Pname_to_ctf(proc_hdl, defname)) == NULL)
603 goto fail;
605 if (Pxlookup_by_name(proc_hdl, PR_LMID_EVERY, defname, sym_name,
606 &sym, &si) != 0)
607 goto fail;
609 if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR)
610 goto fail;
612 (void) type_name(ctfp, finfo.ctc_return, buf, sizeof (buf));
613 (void) fprintf(ABISTREAM, "-> %-8s -> %8s:%s %s(",
614 refname, defname, buf, sym_name);
617 * According to bug in la_pltexit(), it can't return
618 * if the type is just a struct/union. So, if the return
619 * type is a struct/union, la_pltexit() should be off.
621 rtype = ctf_type_resolve(ctfp, finfo.ctc_return);
622 type = ctf_type_reference(ctfp, rtype);
623 rtype = ctf_type_resolve(ctfp, type);
624 kind = ctf_type_kind(ctfp, rtype);
625 if ((kind == CTF_K_STRUCT || kind == CTF_K_UNION) &&
626 strpbrk(buf, "*") == NULL)
627 *sb_flags |= LA_SYMB_NOPLTEXIT;
629 argc = MIN(sizeof (argt) / sizeof (argt[0]), finfo.ctc_argc);
630 (void) ctf_func_args(ctfp, si.prs_id, argc, argt);
632 argv[0] = GETARG0(regset);
633 if (argc > 1)
634 argv[1] = GETARG1(regset);
635 if (argc > 2)
636 argv[2] = GETARG2(regset);
637 if (argc > 3)
638 argv[3] = GETARG3(regset);
639 if (argc > 4)
640 argv[4] = GETARG4(regset);
641 if (argc > 5)
642 argv[5] = GETARG5(regset);
643 if (argc > 6) {
644 for (i = 6; i < argc; i++)
645 argv[i] = GETARG_6NUP(i, regset);
648 for (i = 0; i < argc; i++) {
649 (void) type_name(ctfp, argt[i], buf, sizeof (buf));
650 (void) fprintf(ABISTREAM, "%s%s = ", sep, buf);
651 rtype = ctf_type_resolve(ctfp, argt[i]);
652 type = ctf_type_reference(ctfp, rtype);
653 rtype = ctf_type_resolve(ctfp, type);
654 kind = ctf_type_kind(ctfp, rtype);
655 if (kind == CTF_K_STRUCT || kind == CTF_K_UNION)
656 (void) fprintf(ABISTREAM, "0x%p", (void *)argv[i]);
657 else
658 print_value(ctfp, argt[i], argv[i]);
659 sep = ", ";
662 if (finfo.ctc_flags & CTF_FUNC_VARARG)
663 (void) fprintf(ABISTREAM, "%s...", sep);
664 else if (argc == 0)
665 (void) fprintf(ABISTREAM, "void");
667 if ((*sb_flags & LA_SYMB_NOPLTEXIT) != 0)
668 (void) fprintf(ABISTREAM, ") ** ST\n");
669 else
670 (void) fprintf(ABISTREAM, ")\n");
672 if (verbose_list != NULL &&
673 check_intlist(verbose_list, sym_name) != 0) {
674 for (i = 0; i < argc; i++) {
675 (void) type_name(ctfp, argt[i], buf, sizeof (buf));
676 (void) fprintf(ABISTREAM, "\targ%d = (%s) ", i, buf);
677 print_value(ctfp, argt[i], argv[i]);
678 (void) fprintf(ABISTREAM, "\n");
680 if ((*sb_flags & LA_SYMB_NOPLTEXIT) != 0) {
681 if (kind == CTF_K_STRUCT)
682 (void) fprintf(ABISTREAM,
683 "\treturn = (struct), apptrace "
684 "will not trace the return\n");
685 else
686 (void) fprintf(ABISTREAM,
687 "\treturn = (union), apptrace "
688 "will not trace the return\n");
692 (void) fflush(ABISTREAM);
693 abiunlock(&omask);
694 return (symp->st_value);
696 fail:
697 (void) fprintf(ABISTREAM,
698 "-> %-8s -> %8s:%s(0x%lx, 0x%lx, 0x%lx) ** NR\n",
699 refname, defname, sym_name,
700 (ulong_t)GETARG0(regset),
701 (ulong_t)GETARG1(regset),
702 (ulong_t)GETARG2(regset));
704 *sb_flags |= LA_SYMB_NOPLTEXIT;
705 (void) fflush(ABISTREAM);
706 abiunlock(&omask);
707 return (symp->st_value);
710 /* ARGSUSED */
711 #if defined(_LP64)
712 uintptr_t
713 la_pltexit64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
714 uintptr_t *defcookie, uintptr_t retval, const char *sym_name)
715 #else
716 uintptr_t
717 la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
718 uintptr_t *defcookie, uintptr_t retval)
719 #endif
721 #if !defined(_LP64)
722 const char *sym_name = (const char *)symp->st_name;
723 #endif
724 sigset_t omask;
725 char buf[256];
726 GElf_Sym sym;
727 prsyminfo_t si;
728 ctf_file_t *ctfp;
729 ctf_funcinfo_t finfo;
730 char *defname = (char *)(*defcookie);
731 char *refname = (char *)(*refcookie);
733 abilock(&omask);
735 if (pidout)
736 (void) fprintf(ABISTREAM, "%7u:", (unsigned int)getpid());
738 if (retval == 0) {
739 if (verbose_list == NULL) {
740 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()\n",
741 refname, defname, sym_name);
742 (void) fflush(ABISTREAM);
744 abiunlock(&omask);
745 return (retval);
748 if ((ctfp = Pname_to_ctf(proc_hdl, defname)) == NULL)
749 goto fail;
751 if (Pxlookup_by_name(proc_hdl, PR_LMID_EVERY, defname,
752 sym_name, &sym, &si) != 0)
753 goto fail;
755 if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR)
756 goto fail;
758 if (verbose_list != NULL) {
759 if (check_intlist(verbose_list, sym_name) != 0) {
760 (void) type_name(ctfp, finfo.ctc_return, buf,
761 sizeof (buf));
762 (void) fprintf(ABISTREAM, "\treturn = (%s) ", buf);
763 print_value(ctfp, finfo.ctc_return, retval);
764 (void) fprintf(ABISTREAM, "\n");
765 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()",
766 refname, defname, sym_name);
767 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval);
769 } else {
770 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()",
771 refname, defname, sym_name);
772 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval);
775 (void) fflush(ABISTREAM);
776 abiunlock(&omask);
777 return (retval);
779 fail:
780 if (verbose_list != NULL) {
781 if (check_intlist(verbose_list, sym_name) != 0) {
782 (void) fprintf(ABISTREAM,
783 "\treturn = 0x%p\n", (void *)retval);
784 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()",
785 refname, defname, sym_name);
786 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval);
788 } else {
789 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()",
790 refname, defname, sym_name);
791 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval);
794 (void) fflush(ABISTREAM);
795 abiunlock(&omask);
796 return (retval);