8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / abi / apptrace / common / apptrace.c
blobd3a970025423b13dd063c6341211e469425b8068
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 = stderr;
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 if (version > LAV_CURRENT)
212 (void) fprintf(stderr,
213 dgettext(TEXT_DOMAIN,
214 "apptrace: unexpected version: %u\n"),
215 version);
217 build_env_list(&bindto_list, "APPTRACE_BINDTO");
218 build_env_list(&bindto_excl, "APPTRACE_BINDTO_EXCLUDE");
220 build_env_list(&bindfrom_list, "APPTRACE_BINDFROM");
221 build_env_list(&bindfrom_excl, "APPTRACE_BINDFROM_EXCLUDE");
223 if (checkenv("APPTRACE_PID") != NULL) {
224 pidout = 1;
225 } else {
226 char *str = "LD_AUDIT=";
227 char *str2 = "LD_AUDIT64=";
229 * This disables apptrace output in subsequent exec'ed
230 * processes.
232 (void) putenv(str);
233 (void) putenv(str2);
236 if ((str = checkenv("APPTRACE_OUTPUT")) != NULL) {
237 int fd, newfd, targetfd, lowerlimit;
238 struct rlimit rl;
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);
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);
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).
265 * fcntl with F_DUPFD returns first available >= arg3
266 * so we iterate from the top until we find a available
267 * fd.
269 * Not finding an fd after 10 tries is a failure.
271 * Since the _file member of the FILE structure is an
272 * unsigned char, we must clamp our fd request to
273 * UCHAR_MAX
275 lowerlimit = ((rl.rlim_cur >
276 UCHAR_MAX) ? UCHAR_MAX : rl.rlim_cur) - 10;
278 for (targetfd = lowerlimit + 10;
279 targetfd > lowerlimit; targetfd--) {
280 if ((newfd = fcntl(fd, F_DUPFD, targetfd)) != -1)
281 break;
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);
291 (void) close(fd);
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);
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);
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
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");
326 return (LAV_CURRENT);
329 /* ARGSUSED1 */
330 uint_t
331 la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie)
333 uint_t flags;
334 static int first = 1;
335 int perr;
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.
342 if (first && bindfrom_list == NULL) {
343 flags = LA_FLG_BINDFROM | LA_FLG_BINDTO;
344 first = 0;
345 goto work;
349 * If we have no bindto_list, then we assume that we
350 * bindto everything (apptrace -T \*)
352 * Otherwise we make sure that l_name is on the list.
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;
362 * If l_name is on the exclusion list, zero the bit.
364 if ((bindto_excl != NULL) &&
365 check_list(bindto_excl, lmp->l_name) != NULL) {
366 flags &= ~LA_FLG_BINDTO;
370 * If l_name is on the bindfrom list then trace
372 if (check_list(bindfrom_list, lmp->l_name) != NULL) {
373 flags |= LA_FLG_BINDFROM;
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")
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;
387 work:
388 if (flags) {
389 *cookie = (uintptr_t)abibasename(lmp->l_name);
392 * only call Pgrab() once to get the ps_prochandle
394 if (proc_hdl == NULL)
395 proc_hdl = Pgrab(getpid(), PGRAB_RDONLY, &perr);
398 return (flags);
401 static void
402 apptrace_preinit_fail(void)
404 (void) fprintf(stderr,
405 dgettext(TEXT_DOMAIN, "apptrace: la_preinit: %s\n"),
406 dlerror());
407 exit(EXIT_FAILURE);
410 /* ARGSUSED */
411 void
412 la_preinit(uintptr_t *cookie)
414 void *h = NULL;
416 (void) sigfillset(&abisigset);
418 h = dlmopen(LM_ID_BASE, libcpath, RTLD_LAZY | RTLD_NOLOAD);
419 if (h == NULL)
420 apptrace_preinit_fail();
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();
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();
435 if ((ABI_VFWPRINTF =
436 (int (*)(FILE *, const wchar_t *, va_list))
437 dlsym(h, vfwprintf_sym)) == NULL)
438 apptrace_preinit_fail();
440 if ((ABI_VPRINTF =
441 (int (*)(char const *, va_list))
442 dlsym(h, vprintf_sym)) == NULL)
443 apptrace_preinit_fail();
445 if ((ABI_VSNPRINTF =
446 (int (*)(char *, size_t, char const *, va_list))
447 dlsym(h, vsnprintf_sym)) == NULL)
448 apptrace_preinit_fail();
450 if ((ABI_VSPRINTF =
451 (int (*)(char *, char const *, va_list))
452 dlsym(h, vsprintf_sym)) == NULL)
453 apptrace_preinit_fail();
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();
460 if ((ABI_VWPRINTF =
461 (int (*)(const wchar_t *, va_list))
462 dlsym(h, vwprintf_sym)) == NULL)
463 apptrace_preinit_fail();
465 if ((__abi_real_errno =
466 (int *(*)(void))
467 dlsym(h, errno_sym)) == NULL)
468 apptrace_preinit_fail();
470 (void) dlclose(h);
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
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;
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
501 if (verbose_list != NULL) {
502 /* apptrace ... -v verbose_list ... cmd */
503 if (check_intlist(verbose_list, sym_name))
504 verbose = 1;
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;
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;
523 if (trace_excl != NULL) {
524 /* apptrace ... -t !trace_excl ... cmd */
525 if (check_intlist(trace_excl, sym_name))
526 intercept = 0;
529 if (verbose == 0 && intercept == 0) {
530 *sb_flags |= (LA_SYMB_NOPLTEXIT | LA_SYMB_NOPLTENTER);
531 goto end;
535 * Check to see if this symbol is one of the 'special' symbols.
536 * If so we disable calls for that symbol.
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;
550 end:
551 return (ret);
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
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
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;
595 abilock(&omask);
597 if (pidout)
598 (void) fprintf(ABISTREAM, "%7u:", (unsigned int)getpid());
600 if ((ctfp = Pname_to_ctf(proc_hdl, defname)) == NULL)
601 goto fail;
603 if (Pxlookup_by_name(proc_hdl, PR_LMID_EVERY, defname, sym_name,
604 &sym, &si) != 0)
605 goto fail;
607 if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR)
608 goto fail;
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);
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.
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;
627 argc = MIN(sizeof (argt) / sizeof (argt[0]), finfo.ctc_argc);
628 (void) ctf_func_args(ctfp, si.prs_id, argc, argt);
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);
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 = ", ";
660 if (finfo.ctc_flags & CTF_FUNC_VARARG)
661 (void) fprintf(ABISTREAM, "%s...", sep);
662 else if (argc == 0)
663 (void) fprintf(ABISTREAM, "void");
665 if ((*sb_flags & LA_SYMB_NOPLTEXIT) != 0)
666 (void) fprintf(ABISTREAM, ") ** ST\n");
667 else
668 (void) fprintf(ABISTREAM, ")\n");
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");
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");
690 (void) fflush(ABISTREAM);
691 abiunlock(&omask);
692 return (symp->st_value);
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));
702 *sb_flags |= LA_SYMB_NOPLTEXIT;
703 (void) fflush(ABISTREAM);
704 abiunlock(&omask);
705 return (symp->st_value);
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
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);
731 abilock(&omask);
733 if (pidout)
734 (void) fprintf(ABISTREAM, "%7u:", (unsigned int)getpid());
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);
742 abiunlock(&omask);
743 return (retval);
746 if ((ctfp = Pname_to_ctf(proc_hdl, defname)) == NULL)
747 goto fail;
749 if (Pxlookup_by_name(proc_hdl, PR_LMID_EVERY, defname,
750 sym_name, &sym, &si) != 0)
751 goto fail;
753 if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR)
754 goto fail;
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);
767 } else {
768 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()",
769 refname, defname, sym_name);
770 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval);
773 (void) fflush(ABISTREAM);
774 abiunlock(&omask);
775 return (retval);
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);
786 } else {
787 (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()",
788 refname, defname, sym_name);
789 (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval);
792 (void) fflush(ABISTREAM);
793 abiunlock(&omask);
794 return (retval);