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 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 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 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 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 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 * 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 * 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 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 * 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 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