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
la_version(uint_t version)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
la_objopen(Link_map * lmp,Lmid_t lmid,uintptr_t * cookie)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
apptrace_preinit_fail(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
la_preinit(uintptr_t * cookie)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
la_symbind64(Elf64_Sym * symp,uint_t symndx,uintptr_t * refcook,uintptr_t * defcook,uint_t * sb_flags,char const * sym_name)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
la_sparcv9_pltenter(Elf64_Sym * symp,uint_t symndx,uintptr_t * refcookie,uintptr_t * defcookie,La_sparcv9_regs * regset,uint_t * sb_flags,char const * sym_name)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
la_pltexit64(Elf64_Sym * symp,uint_t symndx,uintptr_t * refcookie,uintptr_t * defcookie,uintptr_t retval,const char * sym_name)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