1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <dlfcn.h>
35*7c478bd9Sstevel@tonic-gate #include <errno.h>
36*7c478bd9Sstevel@tonic-gate #include <fnmatch.h>
37*7c478bd9Sstevel@tonic-gate #include <apptrace.h>
38*7c478bd9Sstevel@tonic-gate #include <libintl.h>
39*7c478bd9Sstevel@tonic-gate #include "abienv.h"
40*7c478bd9Sstevel@tonic-gate
41*7c478bd9Sstevel@tonic-gate static char const *strdup_sym = "strdup";
42*7c478bd9Sstevel@tonic-gate static char const *malloc_sym = "malloc";
43*7c478bd9Sstevel@tonic-gate static char const *comma = ",";
44*7c478bd9Sstevel@tonic-gate
45*7c478bd9Sstevel@tonic-gate static void
bugout(char const * call)46*7c478bd9Sstevel@tonic-gate bugout(char const *call)
47*7c478bd9Sstevel@tonic-gate {
48*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
49*7c478bd9Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "apptrace: %s failed\n"),
50*7c478bd9Sstevel@tonic-gate call);
51*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
52*7c478bd9Sstevel@tonic-gate }
53*7c478bd9Sstevel@tonic-gate
54*7c478bd9Sstevel@tonic-gate void
build_env_list(Liblist ** list,char const * env)55*7c478bd9Sstevel@tonic-gate build_env_list(Liblist **list, char const *env)
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate char *envstr;
58*7c478bd9Sstevel@tonic-gate char *tok;
59*7c478bd9Sstevel@tonic-gate
60*7c478bd9Sstevel@tonic-gate if ((envstr = getenv(env)) == NULL)
61*7c478bd9Sstevel@tonic-gate return;
62*7c478bd9Sstevel@tonic-gate
63*7c478bd9Sstevel@tonic-gate if ((envstr = strdup(envstr)) == NULL)
64*7c478bd9Sstevel@tonic-gate bugout(strdup_sym);
65*7c478bd9Sstevel@tonic-gate
66*7c478bd9Sstevel@tonic-gate tok = strtok(envstr, comma);
67*7c478bd9Sstevel@tonic-gate while (tok != NULL) {
68*7c478bd9Sstevel@tonic-gate Liblist *lp;
69*7c478bd9Sstevel@tonic-gate
70*7c478bd9Sstevel@tonic-gate if ((lp = malloc(sizeof (Liblist))) == NULL)
71*7c478bd9Sstevel@tonic-gate bugout(malloc_sym);
72*7c478bd9Sstevel@tonic-gate
73*7c478bd9Sstevel@tonic-gate lp->l_libname = tok;
74*7c478bd9Sstevel@tonic-gate lp->l_next = *list;
75*7c478bd9Sstevel@tonic-gate *list = lp;
76*7c478bd9Sstevel@tonic-gate tok = strtok(NULL, comma);
77*7c478bd9Sstevel@tonic-gate }
78*7c478bd9Sstevel@tonic-gate }
79*7c478bd9Sstevel@tonic-gate
80*7c478bd9Sstevel@tonic-gate void
build_env_list1(Liblist ** list,Liblist ** listend,const char * env)81*7c478bd9Sstevel@tonic-gate build_env_list1(Liblist **list, Liblist **listend, const char *env)
82*7c478bd9Sstevel@tonic-gate {
83*7c478bd9Sstevel@tonic-gate char *envstr;
84*7c478bd9Sstevel@tonic-gate char *tok;
85*7c478bd9Sstevel@tonic-gate
86*7c478bd9Sstevel@tonic-gate if ((envstr = getenv(env)) == NULL)
87*7c478bd9Sstevel@tonic-gate return;
88*7c478bd9Sstevel@tonic-gate
89*7c478bd9Sstevel@tonic-gate /*
90*7c478bd9Sstevel@tonic-gate * It is possible that we have a single file name,
91*7c478bd9Sstevel@tonic-gate * in which case the subseqent loop will do nothing
92*7c478bd9Sstevel@tonic-gate */
93*7c478bd9Sstevel@tonic-gate if (strchr(envstr, ',') == NULL) {
94*7c478bd9Sstevel@tonic-gate appendlist(list, listend, envstr, 1);
95*7c478bd9Sstevel@tonic-gate return;
96*7c478bd9Sstevel@tonic-gate }
97*7c478bd9Sstevel@tonic-gate
98*7c478bd9Sstevel@tonic-gate if ((envstr = strdup(envstr)) == NULL)
99*7c478bd9Sstevel@tonic-gate bugout(strdup_sym);
100*7c478bd9Sstevel@tonic-gate
101*7c478bd9Sstevel@tonic-gate tok = strtok(envstr, comma);
102*7c478bd9Sstevel@tonic-gate while (tok != NULL) {
103*7c478bd9Sstevel@tonic-gate appendlist(list, listend, tok, 1);
104*7c478bd9Sstevel@tonic-gate tok = strtok(NULL, comma);
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate free(envstr);
107*7c478bd9Sstevel@tonic-gate }
108*7c478bd9Sstevel@tonic-gate
109*7c478bd9Sstevel@tonic-gate void
env_to_intlist(Intlist ** list,char const * env)110*7c478bd9Sstevel@tonic-gate env_to_intlist(Intlist **list, char const *env)
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate char *envstr;
113*7c478bd9Sstevel@tonic-gate char *tok;
114*7c478bd9Sstevel@tonic-gate
115*7c478bd9Sstevel@tonic-gate if ((envstr = getenv(env)) == NULL)
116*7c478bd9Sstevel@tonic-gate return;
117*7c478bd9Sstevel@tonic-gate
118*7c478bd9Sstevel@tonic-gate if ((envstr = strdup(envstr)) == NULL)
119*7c478bd9Sstevel@tonic-gate bugout(strdup_sym);
120*7c478bd9Sstevel@tonic-gate
121*7c478bd9Sstevel@tonic-gate for (tok = strtok(envstr, comma);
122*7c478bd9Sstevel@tonic-gate tok != NULL;
123*7c478bd9Sstevel@tonic-gate tok = strtok(NULL, comma)) {
124*7c478bd9Sstevel@tonic-gate
125*7c478bd9Sstevel@tonic-gate Intlist *ip;
126*7c478bd9Sstevel@tonic-gate
127*7c478bd9Sstevel@tonic-gate if ((ip = malloc(sizeof (Intlist))) == NULL)
128*7c478bd9Sstevel@tonic-gate bugout(malloc_sym);
129*7c478bd9Sstevel@tonic-gate
130*7c478bd9Sstevel@tonic-gate if ((ip->i_name = strdup(tok)) == NULL)
131*7c478bd9Sstevel@tonic-gate bugout(strdup_sym);
132*7c478bd9Sstevel@tonic-gate
133*7c478bd9Sstevel@tonic-gate ip->i_next = *list;
134*7c478bd9Sstevel@tonic-gate *list = ip;
135*7c478bd9Sstevel@tonic-gate }
136*7c478bd9Sstevel@tonic-gate free(envstr);
137*7c478bd9Sstevel@tonic-gate }
138*7c478bd9Sstevel@tonic-gate
139*7c478bd9Sstevel@tonic-gate void
appendlist(Liblist ** list,Liblist ** listend,const char * name,int fatal)140*7c478bd9Sstevel@tonic-gate appendlist(Liblist **list, Liblist **listend, const char *name, int fatal)
141*7c478bd9Sstevel@tonic-gate {
142*7c478bd9Sstevel@tonic-gate Liblist *lp;
143*7c478bd9Sstevel@tonic-gate void *handle;
144*7c478bd9Sstevel@tonic-gate
145*7c478bd9Sstevel@tonic-gate if (access(name, R_OK)) {
146*7c478bd9Sstevel@tonic-gate if (fatal) {
147*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
148*7c478bd9Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
149*7c478bd9Sstevel@tonic-gate "apptrace: %s: %s\n"),
150*7c478bd9Sstevel@tonic-gate name,
151*7c478bd9Sstevel@tonic-gate strerror(errno));
152*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
153*7c478bd9Sstevel@tonic-gate }
154*7c478bd9Sstevel@tonic-gate return;
155*7c478bd9Sstevel@tonic-gate }
156*7c478bd9Sstevel@tonic-gate
157*7c478bd9Sstevel@tonic-gate if ((handle = dlopen(name, RTLD_LAZY)) == NULL) {
158*7c478bd9Sstevel@tonic-gate if (fatal) {
159*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
160*7c478bd9Sstevel@tonic-gate dgettext(TEXT_DOMAIN,
161*7c478bd9Sstevel@tonic-gate "apptrace: dlopen on %s failed: %s\n"),
162*7c478bd9Sstevel@tonic-gate name,
163*7c478bd9Sstevel@tonic-gate dlerror());
164*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
165*7c478bd9Sstevel@tonic-gate }
166*7c478bd9Sstevel@tonic-gate return;
167*7c478bd9Sstevel@tonic-gate }
168*7c478bd9Sstevel@tonic-gate
169*7c478bd9Sstevel@tonic-gate /* OK, so now add it to the end of the list */
170*7c478bd9Sstevel@tonic-gate if ((lp = malloc(sizeof (Liblist))) == NULL)
171*7c478bd9Sstevel@tonic-gate bugout(malloc_sym);
172*7c478bd9Sstevel@tonic-gate
173*7c478bd9Sstevel@tonic-gate if ((lp->l_libname = strdup(name)) == NULL)
174*7c478bd9Sstevel@tonic-gate bugout(strdup_sym);
175*7c478bd9Sstevel@tonic-gate lp->l_handle = handle;
176*7c478bd9Sstevel@tonic-gate lp->l_next = NULL;
177*7c478bd9Sstevel@tonic-gate if (*listend)
178*7c478bd9Sstevel@tonic-gate (*listend)->l_next = lp;
179*7c478bd9Sstevel@tonic-gate if (*list == NULL)
180*7c478bd9Sstevel@tonic-gate *list = lp;
181*7c478bd9Sstevel@tonic-gate *listend = lp;
182*7c478bd9Sstevel@tonic-gate }
183*7c478bd9Sstevel@tonic-gate
184*7c478bd9Sstevel@tonic-gate /*
185*7c478bd9Sstevel@tonic-gate * Called abibasename() to avoid clash with basename(3C)
186*7c478bd9Sstevel@tonic-gate * Incidentally, basename(3C) is destructive which is why
187*7c478bd9Sstevel@tonic-gate * we are not using it instead.
188*7c478bd9Sstevel@tonic-gate */
189*7c478bd9Sstevel@tonic-gate char *
abibasename(const char * str)190*7c478bd9Sstevel@tonic-gate abibasename(const char *str)
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate char *p;
193*7c478bd9Sstevel@tonic-gate
194*7c478bd9Sstevel@tonic-gate if ((p = strrchr(str, '/')) != NULL)
195*7c478bd9Sstevel@tonic-gate return (p + 1);
196*7c478bd9Sstevel@tonic-gate else
197*7c478bd9Sstevel@tonic-gate return ((char *)str);
198*7c478bd9Sstevel@tonic-gate }
199*7c478bd9Sstevel@tonic-gate
200*7c478bd9Sstevel@tonic-gate Liblist *
check_list(Liblist * list,char const * str)201*7c478bd9Sstevel@tonic-gate check_list(Liblist *list, char const *str)
202*7c478bd9Sstevel@tonic-gate {
203*7c478bd9Sstevel@tonic-gate char *basename1, *basename2, *p1, *p2;
204*7c478bd9Sstevel@tonic-gate Liblist *ret = NULL;
205*7c478bd9Sstevel@tonic-gate
206*7c478bd9Sstevel@tonic-gate if (list == NULL)
207*7c478bd9Sstevel@tonic-gate return (NULL);
208*7c478bd9Sstevel@tonic-gate
209*7c478bd9Sstevel@tonic-gate if ((basename2 = strdup(abibasename(str))) == NULL)
210*7c478bd9Sstevel@tonic-gate bugout(strdup_sym);
211*7c478bd9Sstevel@tonic-gate if ((p2 = strchr(basename2, '.')) != NULL)
212*7c478bd9Sstevel@tonic-gate *p2 = '\0';
213*7c478bd9Sstevel@tonic-gate
214*7c478bd9Sstevel@tonic-gate for (; list; list = list->l_next) {
215*7c478bd9Sstevel@tonic-gate /* Lose the dirname */
216*7c478bd9Sstevel@tonic-gate if ((basename1 = strdup(abibasename(list->l_libname))) == NULL)
217*7c478bd9Sstevel@tonic-gate bugout(strdup_sym);
218*7c478bd9Sstevel@tonic-gate /* Lose the suffix */
219*7c478bd9Sstevel@tonic-gate if ((p1 = strchr(basename1, '.')) != NULL)
220*7c478bd9Sstevel@tonic-gate *p1 = '\0';
221*7c478bd9Sstevel@tonic-gate if (fnmatch(basename1, basename2, 0) == 0) {
222*7c478bd9Sstevel@tonic-gate ret = list;
223*7c478bd9Sstevel@tonic-gate free(basename1);
224*7c478bd9Sstevel@tonic-gate break;
225*7c478bd9Sstevel@tonic-gate }
226*7c478bd9Sstevel@tonic-gate free(basename1);
227*7c478bd9Sstevel@tonic-gate }
228*7c478bd9Sstevel@tonic-gate
229*7c478bd9Sstevel@tonic-gate free(basename2);
230*7c478bd9Sstevel@tonic-gate return (ret);
231*7c478bd9Sstevel@tonic-gate }
232*7c478bd9Sstevel@tonic-gate
233*7c478bd9Sstevel@tonic-gate int
check_intlist(Intlist * list,char const * iface)234*7c478bd9Sstevel@tonic-gate check_intlist(Intlist *list, char const *iface)
235*7c478bd9Sstevel@tonic-gate {
236*7c478bd9Sstevel@tonic-gate if (list == NULL)
237*7c478bd9Sstevel@tonic-gate return (0);
238*7c478bd9Sstevel@tonic-gate
239*7c478bd9Sstevel@tonic-gate for (; list != NULL; list = list->i_next) {
240*7c478bd9Sstevel@tonic-gate if (fnmatch(list->i_name, iface, 0) == 0)
241*7c478bd9Sstevel@tonic-gate return (1);
242*7c478bd9Sstevel@tonic-gate }
243*7c478bd9Sstevel@tonic-gate
244*7c478bd9Sstevel@tonic-gate return (0);
245*7c478bd9Sstevel@tonic-gate }
246*7c478bd9Sstevel@tonic-gate
247*7c478bd9Sstevel@tonic-gate char *
checkenv(char const * env)248*7c478bd9Sstevel@tonic-gate checkenv(char const *env)
249*7c478bd9Sstevel@tonic-gate {
250*7c478bd9Sstevel@tonic-gate char *envstr;
251*7c478bd9Sstevel@tonic-gate
252*7c478bd9Sstevel@tonic-gate if ((envstr = getenv(env)) == NULL)
253*7c478bd9Sstevel@tonic-gate return (NULL);
254*7c478bd9Sstevel@tonic-gate while (*envstr == ' ')
255*7c478bd9Sstevel@tonic-gate envstr++;
256*7c478bd9Sstevel@tonic-gate if (*envstr == '\0')
257*7c478bd9Sstevel@tonic-gate return (NULL);
258*7c478bd9Sstevel@tonic-gate return (envstr);
259*7c478bd9Sstevel@tonic-gate }
260*7c478bd9Sstevel@tonic-gate
261*7c478bd9Sstevel@tonic-gate int
build_interceptor_path(char * buf,size_t l,char const * path)262*7c478bd9Sstevel@tonic-gate build_interceptor_path(char *buf, size_t l, char const *path)
263*7c478bd9Sstevel@tonic-gate {
264*7c478bd9Sstevel@tonic-gate char *p, *t, *f;
265*7c478bd9Sstevel@tonic-gate #if defined(_LP64)
266*7c478bd9Sstevel@tonic-gate char *m;
267*7c478bd9Sstevel@tonic-gate #endif
268*7c478bd9Sstevel@tonic-gate int ret;
269*7c478bd9Sstevel@tonic-gate
270*7c478bd9Sstevel@tonic-gate /* Duplicate the path */
271*7c478bd9Sstevel@tonic-gate if ((p = strdup(path)) == NULL)
272*7c478bd9Sstevel@tonic-gate bugout(strdup_sym);
273*7c478bd9Sstevel@tonic-gate
274*7c478bd9Sstevel@tonic-gate /* Find the last slash, if there ain't one bug out */
275*7c478bd9Sstevel@tonic-gate if ((t = strrchr(p, '/')) == NULL) {
276*7c478bd9Sstevel@tonic-gate ret = 0;
277*7c478bd9Sstevel@tonic-gate goto done;
278*7c478bd9Sstevel@tonic-gate }
279*7c478bd9Sstevel@tonic-gate
280*7c478bd9Sstevel@tonic-gate /*
281*7c478bd9Sstevel@tonic-gate * Wack the slash to a null byte.
282*7c478bd9Sstevel@tonic-gate * Thus if we got:
283*7c478bd9Sstevel@tonic-gate * /A/B/C/D.so.1
284*7c478bd9Sstevel@tonic-gate * p now points to /A/B/C
285*7c478bd9Sstevel@tonic-gate * f is set to point to D.so.1
286*7c478bd9Sstevel@tonic-gate */
287*7c478bd9Sstevel@tonic-gate *t = '\0';
288*7c478bd9Sstevel@tonic-gate f = ++t;
289*7c478bd9Sstevel@tonic-gate
290*7c478bd9Sstevel@tonic-gate #if defined(_LP64)
291*7c478bd9Sstevel@tonic-gate /*
292*7c478bd9Sstevel@tonic-gate * As above except that in LP64 (for sparc) we'll get:
293*7c478bd9Sstevel@tonic-gate * /A/B/C/sparcv9/D.so.1
294*7c478bd9Sstevel@tonic-gate * thus p now points to:
295*7c478bd9Sstevel@tonic-gate * /A/B/C/sparcv9
296*7c478bd9Sstevel@tonic-gate * so we repeat the wack so that we get:
297*7c478bd9Sstevel@tonic-gate * /A/B/C
298*7c478bd9Sstevel@tonic-gate * and retain a pointer, m, to the machine dependent portion.
299*7c478bd9Sstevel@tonic-gate */
300*7c478bd9Sstevel@tonic-gate if ((t = strrchr(p, '/')) == NULL) {
301*7c478bd9Sstevel@tonic-gate ret = 0;
302*7c478bd9Sstevel@tonic-gate goto done;
303*7c478bd9Sstevel@tonic-gate }
304*7c478bd9Sstevel@tonic-gate *t = '\0';
305*7c478bd9Sstevel@tonic-gate m = ++t;
306*7c478bd9Sstevel@tonic-gate
307*7c478bd9Sstevel@tonic-gate /*
308*7c478bd9Sstevel@tonic-gate * Now we can build a path name.
309*7c478bd9Sstevel@tonic-gate * This path is only a guess that'll be checked later in appendlist().
310*7c478bd9Sstevel@tonic-gate * Some system libraries, like libc.so.1, reside in /lib while their
311*7c478bd9Sstevel@tonic-gate * corresponding abi_* counterparts reside in /usr/lib. The same is
312*7c478bd9Sstevel@tonic-gate * true for libraries like libc_psr.so.1 that reside in /platform
313*7c478bd9Sstevel@tonic-gate * rather than /usr/platform. To deal with this, we check whether
314*7c478bd9Sstevel@tonic-gate * the file in the direct path name we generate exists, and if not,
315*7c478bd9Sstevel@tonic-gate * we prepend "/usr" to it. This handles all existing cases.
316*7c478bd9Sstevel@tonic-gate */
317*7c478bd9Sstevel@tonic-gate ret = snprintf(buf, l, "%s/abi/%s/abi_%s", p, m, f);
318*7c478bd9Sstevel@tonic-gate if (access(buf, R_OK) != 0 && strncmp(buf, "/usr/", 5) != 0)
319*7c478bd9Sstevel@tonic-gate ret = snprintf(buf, l, "/usr%s/abi/%s/abi_%s", p, m, f);
320*7c478bd9Sstevel@tonic-gate #else
321*7c478bd9Sstevel@tonic-gate ret = snprintf(buf, l, "%s/abi/abi_%s", p, f);
322*7c478bd9Sstevel@tonic-gate if (access(buf, R_OK) != 0 && strncmp(buf, "/usr/", 5) != 0)
323*7c478bd9Sstevel@tonic-gate ret = snprintf(buf, l, "/usr%s/abi/abi_%s", p, f);
324*7c478bd9Sstevel@tonic-gate #endif
325*7c478bd9Sstevel@tonic-gate
326*7c478bd9Sstevel@tonic-gate done:
327*7c478bd9Sstevel@tonic-gate free(p);
328*7c478bd9Sstevel@tonic-gate return (ret);
329*7c478bd9Sstevel@tonic-gate }
330