1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright (c) 1988 AT&T 24*0Sstevel@tonic-gate * All Rights Reserved 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * 27*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28*0Sstevel@tonic-gate * Use is subject to license terms. 29*0Sstevel@tonic-gate */ 30*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate /* 33*0Sstevel@tonic-gate * Utility routines for run-time linker. some are duplicated here from libc 34*0Sstevel@tonic-gate * (with different names) to avoid name space collisions. 35*0Sstevel@tonic-gate */ 36*0Sstevel@tonic-gate #include "_synonyms.h" 37*0Sstevel@tonic-gate #include <stdio.h> 38*0Sstevel@tonic-gate #include <sys/types.h> 39*0Sstevel@tonic-gate #include <sys/mman.h> 40*0Sstevel@tonic-gate #include <sys/lwp.h> 41*0Sstevel@tonic-gate #include <sys/debug.h> 42*0Sstevel@tonic-gate #include <stdarg.h> 43*0Sstevel@tonic-gate #include <fcntl.h> 44*0Sstevel@tonic-gate #include <string.h> 45*0Sstevel@tonic-gate #include <ctype.h> 46*0Sstevel@tonic-gate #include <dlfcn.h> 47*0Sstevel@tonic-gate #include <unistd.h> 48*0Sstevel@tonic-gate #include <stdlib.h> 49*0Sstevel@tonic-gate #include <signal.h> 50*0Sstevel@tonic-gate #include <sys/auxv.h> 51*0Sstevel@tonic-gate #include "_rtld.h" 52*0Sstevel@tonic-gate #include "_audit.h" 53*0Sstevel@tonic-gate #include "conv.h" 54*0Sstevel@tonic-gate #include "msg.h" 55*0Sstevel@tonic-gate #include "debug.h" 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate static int ld_flags_env(const char *, Word *, Word *, uint_t, int); 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate /* 60*0Sstevel@tonic-gate * All error messages go through eprintf(). During process initialization these 61*0Sstevel@tonic-gate * messages should be directed to the standard error, however once control has 62*0Sstevel@tonic-gate * been passed to the applications code these messages should be stored in an 63*0Sstevel@tonic-gate * internal buffer for use with dlerror(). Note, fatal error conditions that 64*0Sstevel@tonic-gate * may occur while running the application will still cause a standard error 65*0Sstevel@tonic-gate * message, see rtldexit() in this file for details. 66*0Sstevel@tonic-gate * The `application' flag serves to indicate the transition between process 67*0Sstevel@tonic-gate * initialization and when the applications code is running. 68*0Sstevel@tonic-gate */ 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate /* 71*0Sstevel@tonic-gate * Null function used as place where a debugger can set a breakpoint. 72*0Sstevel@tonic-gate */ 73*0Sstevel@tonic-gate void 74*0Sstevel@tonic-gate rtld_db_dlactivity(void) 75*0Sstevel@tonic-gate { 76*0Sstevel@tonic-gate DBG_CALL(Dbg_util_dbnotify(r_debug.rtd_rdebug.r_rdevent, 77*0Sstevel@tonic-gate r_debug.rtd_rdebug.r_state)); 78*0Sstevel@tonic-gate } 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate /* 81*0Sstevel@tonic-gate * Null function used as place where debugger can set a pre .init 82*0Sstevel@tonic-gate * processing breakpoint. 83*0Sstevel@tonic-gate */ 84*0Sstevel@tonic-gate void 85*0Sstevel@tonic-gate rtld_db_preinit(void) 86*0Sstevel@tonic-gate { 87*0Sstevel@tonic-gate DBG_CALL(Dbg_util_dbnotify(r_debug.rtd_rdebug.r_rdevent, 88*0Sstevel@tonic-gate r_debug.rtd_rdebug.r_state)); 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate /* 93*0Sstevel@tonic-gate * Null function used as place where debugger can set a post .init 94*0Sstevel@tonic-gate * processing breakpoint. 95*0Sstevel@tonic-gate */ 96*0Sstevel@tonic-gate void 97*0Sstevel@tonic-gate rtld_db_postinit(void) 98*0Sstevel@tonic-gate { 99*0Sstevel@tonic-gate DBG_CALL(Dbg_util_dbnotify(r_debug.rtd_rdebug.r_rdevent, 100*0Sstevel@tonic-gate r_debug.rtd_rdebug.r_state)); 101*0Sstevel@tonic-gate } 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate /* 105*0Sstevel@tonic-gate * Debugger Event Notification 106*0Sstevel@tonic-gate * 107*0Sstevel@tonic-gate * This function centralizes all debugger event notification (ala rtld_db). 108*0Sstevel@tonic-gate * 109*0Sstevel@tonic-gate * There's a simple intent, focused on insuring the primary link-map control 110*0Sstevel@tonic-gate * list (or each link-map list) is consistent, and the indication that objects 111*0Sstevel@tonic-gate * have been added or deleted from this list. Although an RD_ADD and RD_DELETE 112*0Sstevel@tonic-gate * event are posted for each of these, most debuggers don't care, as their 113*0Sstevel@tonic-gate * view is that these events simply convey an "inconsistent" state. 114*0Sstevel@tonic-gate * 115*0Sstevel@tonic-gate * We also don't want to trigger multiple RD_ADD/RD_DELETE events any time we 116*0Sstevel@tonic-gate * enter ld.so.1. 117*0Sstevel@tonic-gate * 118*0Sstevel@tonic-gate * With auditors, we may be in the process of relocating a collection of 119*0Sstevel@tonic-gate * objects, and will leave() ld.so.1 to call the auditor. At this point we 120*0Sstevel@tonic-gate * must indicate an RD_CONSISTENT event, but librtld_db will not report an 121*0Sstevel@tonic-gate * object to the debuggers until relocation processing has been completed on it. 122*0Sstevel@tonic-gate * To allow for the collection of these objects that are pending relocation, an 123*0Sstevel@tonic-gate * RD_ADD event is set after completing a series of relocations on the primary 124*0Sstevel@tonic-gate * link-map control list. 125*0Sstevel@tonic-gate * 126*0Sstevel@tonic-gate * Set an RD_ADD/RD_DELETE event and indicate that an RD_CONSISTENT event is 127*0Sstevel@tonic-gate * required later (LML_FLG_DBNOTIF): 128*0Sstevel@tonic-gate * 129*0Sstevel@tonic-gate * i the first time we add or delete an object to the primary link-map 130*0Sstevel@tonic-gate * control list. 131*0Sstevel@tonic-gate * ii the first time we move a secondary link-map control list to the primary 132*0Sstevel@tonic-gate * link-map control list (effectively, this is like adding a group of 133*0Sstevel@tonic-gate * objects to the primary link-map control list). 134*0Sstevel@tonic-gate * iii the first time we relocate a series of objects on the primary link-map 135*0Sstevel@tonic-gate * control list. 136*0Sstevel@tonic-gate * 137*0Sstevel@tonic-gate * Set an RD_CONSISTENT event when it is required (LML_FLG_DBNOTIF is set) and 138*0Sstevel@tonic-gate * 139*0Sstevel@tonic-gate * i each time we leave the runtime linker. 140*0Sstevel@tonic-gate */ 141*0Sstevel@tonic-gate void 142*0Sstevel@tonic-gate rd_event(Lm_list *lml, rd_event_e event, r_state_e state) 143*0Sstevel@tonic-gate { 144*0Sstevel@tonic-gate void (*fptr)(); 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate switch (event) { 147*0Sstevel@tonic-gate case RD_PREINIT: 148*0Sstevel@tonic-gate fptr = rtld_db_preinit; 149*0Sstevel@tonic-gate break; 150*0Sstevel@tonic-gate case RD_POSTINIT: 151*0Sstevel@tonic-gate fptr = rtld_db_postinit; 152*0Sstevel@tonic-gate break; 153*0Sstevel@tonic-gate case RD_DLACTIVITY: 154*0Sstevel@tonic-gate switch (state) { 155*0Sstevel@tonic-gate case RT_CONSISTENT: 156*0Sstevel@tonic-gate lml->lm_flags &= ~LML_FLG_DBNOTIF; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * Do we need to send a notification? 160*0Sstevel@tonic-gate */ 161*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_DBNOTIF) == 0) 162*0Sstevel@tonic-gate return; 163*0Sstevel@tonic-gate rtld_flags &= ~RT_FL_DBNOTIF; 164*0Sstevel@tonic-gate break; 165*0Sstevel@tonic-gate case RT_ADD: 166*0Sstevel@tonic-gate case RT_DELETE: 167*0Sstevel@tonic-gate lml->lm_flags |= LML_FLG_DBNOTIF; 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * If we are already in an inconsistent state, no 171*0Sstevel@tonic-gate * notification is required. 172*0Sstevel@tonic-gate */ 173*0Sstevel@tonic-gate if (rtld_flags & RT_FL_DBNOTIF) 174*0Sstevel@tonic-gate return; 175*0Sstevel@tonic-gate rtld_flags |= RT_FL_DBNOTIF; 176*0Sstevel@tonic-gate break; 177*0Sstevel@tonic-gate }; 178*0Sstevel@tonic-gate fptr = rtld_db_dlactivity; 179*0Sstevel@tonic-gate break; 180*0Sstevel@tonic-gate default: 181*0Sstevel@tonic-gate /* 182*0Sstevel@tonic-gate * RD_NONE - do nothing 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate break; 185*0Sstevel@tonic-gate }; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate /* 188*0Sstevel@tonic-gate * Set event state and call 'notification' function. 189*0Sstevel@tonic-gate * 190*0Sstevel@tonic-gate * The debugging clients have previously been told about these 191*0Sstevel@tonic-gate * notification functions and have set breakpoints on them if they 192*0Sstevel@tonic-gate * are interested in the notification. 193*0Sstevel@tonic-gate */ 194*0Sstevel@tonic-gate r_debug.rtd_rdebug.r_state = state; 195*0Sstevel@tonic-gate r_debug.rtd_rdebug.r_rdevent = event; 196*0Sstevel@tonic-gate fptr(); 197*0Sstevel@tonic-gate r_debug.rtd_rdebug.r_rdevent = RD_NONE; 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate #if defined(sparc) || defined(i386) || defined(__amd64) 201*0Sstevel@tonic-gate /* 202*0Sstevel@tonic-gate * Stack Cleanup. 203*0Sstevel@tonic-gate * 204*0Sstevel@tonic-gate * This function is invoked to 'remove' arguments that were passed in on the 205*0Sstevel@tonic-gate * stack. This is most likely if ld.so.1 was invoked directly. In that case 206*0Sstevel@tonic-gate * we want to remove ld.so.1 as well as it's arguments from the argv[] array. 207*0Sstevel@tonic-gate * Which means we then need to slide everything above it on the stack down 208*0Sstevel@tonic-gate * accordingly. 209*0Sstevel@tonic-gate * 210*0Sstevel@tonic-gate * While the stack layout is platform specific - it just so happens that x86, 211*0Sstevel@tonic-gate * sparc, & sparcv9 all share the following initial stack layout. 212*0Sstevel@tonic-gate * 213*0Sstevel@tonic-gate * !_______________________! high addresses 214*0Sstevel@tonic-gate * ! ! 215*0Sstevel@tonic-gate * ! Information ! 216*0Sstevel@tonic-gate * ! Block ! 217*0Sstevel@tonic-gate * ! (size varies) ! 218*0Sstevel@tonic-gate * !_______________________! 219*0Sstevel@tonic-gate * ! 0 word ! 220*0Sstevel@tonic-gate * !_______________________! 221*0Sstevel@tonic-gate * ! Auxiliary ! 222*0Sstevel@tonic-gate * ! vector ! 223*0Sstevel@tonic-gate * ! 2 word entries ! 224*0Sstevel@tonic-gate * ! ! 225*0Sstevel@tonic-gate * !_______________________! 226*0Sstevel@tonic-gate * ! 0 word ! 227*0Sstevel@tonic-gate * !_______________________! 228*0Sstevel@tonic-gate * ! Environment ! 229*0Sstevel@tonic-gate * ! pointers ! 230*0Sstevel@tonic-gate * ! ... ! 231*0Sstevel@tonic-gate * ! (one word each) ! 232*0Sstevel@tonic-gate * !_______________________! 233*0Sstevel@tonic-gate * ! 0 word ! 234*0Sstevel@tonic-gate * !_______________________! 235*0Sstevel@tonic-gate * ! Argument ! low addresses 236*0Sstevel@tonic-gate * ! pointers ! 237*0Sstevel@tonic-gate * ! Argc words ! 238*0Sstevel@tonic-gate * !_______________________! 239*0Sstevel@tonic-gate * ! ! 240*0Sstevel@tonic-gate * ! Argc ! 241*0Sstevel@tonic-gate * !_______________________! 242*0Sstevel@tonic-gate * ! ... ! 243*0Sstevel@tonic-gate * 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate static void 246*0Sstevel@tonic-gate stack_cleanup(char **argv, int rmcnt) 247*0Sstevel@tonic-gate { 248*0Sstevel@tonic-gate int i; 249*0Sstevel@tonic-gate long *argc; 250*0Sstevel@tonic-gate char **_argv, **envp, **_envp; 251*0Sstevel@tonic-gate auxv_t *auxv, *_auxv; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * Slide ARGV[] and update argc. 255*0Sstevel@tonic-gate */ 256*0Sstevel@tonic-gate _argv = argv; 257*0Sstevel@tonic-gate argv = &argv[rmcnt]; 258*0Sstevel@tonic-gate for (i = 0; argv[i]; i++) { 259*0Sstevel@tonic-gate _argv[i] = argv[i]; 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate _argv[i] = argv[i]; 262*0Sstevel@tonic-gate argc = (long *)((uintptr_t)_argv - sizeof (long *)); 263*0Sstevel@tonic-gate *argc -= rmcnt; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * Slide ENVP[]. 267*0Sstevel@tonic-gate */ 268*0Sstevel@tonic-gate envp = &argv[i + 1]; 269*0Sstevel@tonic-gate _envp = &_argv[i + 1]; 270*0Sstevel@tonic-gate for (i = 0; envp[i]; i++) { 271*0Sstevel@tonic-gate _envp[i] = envp[i]; 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate _envp[i] = envp[i]; 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate /* 276*0Sstevel@tonic-gate * Slide AUXV[]. 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate auxv = (auxv_t *)&envp[i + 1]; 279*0Sstevel@tonic-gate _auxv = (auxv_t *)&_envp[i + 1]; 280*0Sstevel@tonic-gate for (i = 0; auxv[i].a_type != AT_NULL; i++) { 281*0Sstevel@tonic-gate _auxv[i] = auxv[i]; 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate _auxv[i] = auxv[i]; 284*0Sstevel@tonic-gate } 285*0Sstevel@tonic-gate #else 286*0Sstevel@tonic-gate /* 287*0Sstevel@tonic-gate * Verify that the above routine is appropriate for any new platforms. 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate #error unsupported architecture! 290*0Sstevel@tonic-gate #endif 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate /* 293*0Sstevel@tonic-gate * The only command line argument recognized is -e, followed by an rtld 294*0Sstevel@tonic-gate * environment variable. 295*0Sstevel@tonic-gate */ 296*0Sstevel@tonic-gate int 297*0Sstevel@tonic-gate rtld_getopt(char **argv, Word *lmflags, Word *lmtflags, int aout) 298*0Sstevel@tonic-gate { 299*0Sstevel@tonic-gate int i, errflg = 0; 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate for (i = 1; argv[i]; i++) { 302*0Sstevel@tonic-gate char *str; 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate if (argv[i][0] != '-') 305*0Sstevel@tonic-gate break; 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate if (argv[i][1] == '\0') { 308*0Sstevel@tonic-gate i++; 309*0Sstevel@tonic-gate break; 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if (argv[i][1] != 'e') { 313*0Sstevel@tonic-gate errflg++; 314*0Sstevel@tonic-gate break; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate if (argv[i][2] == '\0') { 318*0Sstevel@tonic-gate i++; 319*0Sstevel@tonic-gate if (argv[i] == NULL) { 320*0Sstevel@tonic-gate errflg++; 321*0Sstevel@tonic-gate break; 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate str = argv[i]; 324*0Sstevel@tonic-gate } else 325*0Sstevel@tonic-gate str = &argv[i][2]; 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate if (ld_flags_env(str, lmflags, lmtflags, 0, aout) == 1) 328*0Sstevel@tonic-gate return (1); 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate if (errflg || (argv[i] == 0)) { 332*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_USG_BADOPT)); 333*0Sstevel@tonic-gate return (1); 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* 337*0Sstevel@tonic-gate * Having gotten the arguments, clean ourselves off of the stack. 338*0Sstevel@tonic-gate */ 339*0Sstevel@tonic-gate stack_cleanup(argv, i); 340*0Sstevel@tonic-gate return (0); 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate /* 345*0Sstevel@tonic-gate * Compare function for FullpathNode AVL tree. 346*0Sstevel@tonic-gate */ 347*0Sstevel@tonic-gate static int 348*0Sstevel@tonic-gate fpavl_compare(const void * n1, const void * n2) 349*0Sstevel@tonic-gate { 350*0Sstevel@tonic-gate uint_t hash1, hash2; 351*0Sstevel@tonic-gate const char *st1, *st2; 352*0Sstevel@tonic-gate int rc; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate hash1 = ((FullpathNode *)n1)->fpn_hash; 355*0Sstevel@tonic-gate hash2 = ((FullpathNode *)n2)->fpn_hash; 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate if (hash1 > hash2) 358*0Sstevel@tonic-gate return (1); 359*0Sstevel@tonic-gate if (hash1 < hash2) 360*0Sstevel@tonic-gate return (-1); 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate st1 = ((FullpathNode *)n1)->fpn_name; 363*0Sstevel@tonic-gate st2 = ((FullpathNode *)n2)->fpn_name; 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate rc = strcmp(st1, st2); 366*0Sstevel@tonic-gate if (rc > 0) 367*0Sstevel@tonic-gate return (1); 368*0Sstevel@tonic-gate if (rc < 0) 369*0Sstevel@tonic-gate return (-1); 370*0Sstevel@tonic-gate return (0); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /* 375*0Sstevel@tonic-gate * Determine if a given pathname is already been loaded in the AVL tree. 376*0Sstevel@tonic-gate * If the pathname does not exist in the AVL tree, the next insertion point 377*0Sstevel@tonic-gate * is deposited in "where". This value can be used by fpavl_insert() to 378*0Sstevel@tonic-gate * expedite the insertion. 379*0Sstevel@tonic-gate */ 380*0Sstevel@tonic-gate Rt_map * 381*0Sstevel@tonic-gate fpavl_loaded(Lm_list *lml, const char *name, avl_index_t *where) 382*0Sstevel@tonic-gate { 383*0Sstevel@tonic-gate FullpathNode fpn, *fpnp; 384*0Sstevel@tonic-gate avl_tree_t *avlt; 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* 387*0Sstevel@tonic-gate * Create the avl tree if required. 388*0Sstevel@tonic-gate */ 389*0Sstevel@tonic-gate if ((avlt = lml->lm_fpavl) == NULL) { 390*0Sstevel@tonic-gate if ((avlt = calloc(sizeof (avl_tree_t), 1)) == 0) 391*0Sstevel@tonic-gate return (0); 392*0Sstevel@tonic-gate avl_create(avlt, fpavl_compare, sizeof (FullpathNode), 393*0Sstevel@tonic-gate SGSOFFSETOF(FullpathNode, fpn_avl)); 394*0Sstevel@tonic-gate lml->lm_fpavl = avlt; 395*0Sstevel@tonic-gate } 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate fpn.fpn_name = name; 398*0Sstevel@tonic-gate fpn.fpn_hash = sgs_str_hash(name); 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate if ((fpnp = avl_find(lml->lm_fpavl, &fpn, where)) == NULL) 401*0Sstevel@tonic-gate return (NULL); 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate return (fpnp->fpn_lmp); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate /* 408*0Sstevel@tonic-gate * Insert a the name into the FullpathNode AVL tree for the link-map list. 409*0Sstevel@tonic-gate * The objects NAME() is the path that would have been searched for, and is 410*0Sstevel@tonic-gate * therefore the name to associate with any "where" value. If the object has 411*0Sstevel@tonic-gate * a different PATHNAME(), perhaps because it has resolved to a different file 412*0Sstevel@tonic-gate * (see fullpath), then this name is recorded also. See load_file(). 413*0Sstevel@tonic-gate */ 414*0Sstevel@tonic-gate int 415*0Sstevel@tonic-gate fpavl_insert(Lm_list *lml, Rt_map *lmp, const char *name, avl_index_t where) 416*0Sstevel@tonic-gate { 417*0Sstevel@tonic-gate FullpathNode *fpnp; 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if (where == 0) { 420*0Sstevel@tonic-gate /* LINTED */ 421*0Sstevel@tonic-gate Rt_map *_lmp = fpavl_loaded(lml, name, &where); 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate /* 424*0Sstevel@tonic-gate * We better not get a hit now, we do not want duplicates in 425*0Sstevel@tonic-gate * the tree. 426*0Sstevel@tonic-gate */ 427*0Sstevel@tonic-gate ASSERT(_lmp == 0); 428*0Sstevel@tonic-gate } 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate /* 431*0Sstevel@tonic-gate * Insert new node in tree 432*0Sstevel@tonic-gate */ 433*0Sstevel@tonic-gate if ((fpnp = calloc(sizeof (FullpathNode), 1)) == 0) 434*0Sstevel@tonic-gate return (0); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate fpnp->fpn_name = name; 437*0Sstevel@tonic-gate fpnp->fpn_hash = sgs_str_hash(name); 438*0Sstevel@tonic-gate fpnp->fpn_lmp = lmp; 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate if (alist_append(&FPNODE(lmp), &fpnp, sizeof (FullpathNode *), 441*0Sstevel@tonic-gate AL_CNT_FPNODE) == 0) { 442*0Sstevel@tonic-gate free(fpnp); 443*0Sstevel@tonic-gate return (0); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate ASSERT(lml->lm_fpavl != NULL); 447*0Sstevel@tonic-gate avl_insert(lml->lm_fpavl, fpnp, where); 448*0Sstevel@tonic-gate return (1); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate /* 452*0Sstevel@tonic-gate * Remove a object from the Fullpath AVL tree. Note, this is called *before* 453*0Sstevel@tonic-gate * the objects link-map is torn down (remove_so), which is where any NAME() and 454*0Sstevel@tonic-gate * PATHNAME() strings will be deallocated. 455*0Sstevel@tonic-gate */ 456*0Sstevel@tonic-gate void 457*0Sstevel@tonic-gate fpavl_remove(Rt_map *lmp) 458*0Sstevel@tonic-gate { 459*0Sstevel@tonic-gate FullpathNode **fpnpp; 460*0Sstevel@tonic-gate Aliste off; 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate for (ALIST_TRAVERSE(FPNODE(lmp), off, fpnpp)) { 463*0Sstevel@tonic-gate FullpathNode *fpnp = *fpnpp; 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate avl_remove(LIST(lmp)->lm_fpavl, fpnp); 466*0Sstevel@tonic-gate free(fpnp); 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate free(FPNODE(lmp)); 469*0Sstevel@tonic-gate FPNODE(lmp) = 0; 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate /* 474*0Sstevel@tonic-gate * Prior to calling an object, either via a .plt or through dlsym(), make sure 475*0Sstevel@tonic-gate * its .init has fired. Through topological sorting, ld.so.1 attempts to fire 476*0Sstevel@tonic-gate * init's in the correct order, however, this order is typically based on needed 477*0Sstevel@tonic-gate * dependencies and non-lazy relocation bindings. Lazy relocations (.plts) can 478*0Sstevel@tonic-gate * still occur and result in bindings that were not captured during topological 479*0Sstevel@tonic-gate * sorting. This routine compensates for this lack of binding information, and 480*0Sstevel@tonic-gate * provides for dynamic .init firing. 481*0Sstevel@tonic-gate */ 482*0Sstevel@tonic-gate void 483*0Sstevel@tonic-gate is_dep_init(Rt_map * dlmp, Rt_map * clmp) 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate Rt_map ** tobj; 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate /* 488*0Sstevel@tonic-gate * If the caller is an auditor, and the destination isn't, then don't 489*0Sstevel@tonic-gate * run any .inits (see comments in load_completion()). 490*0Sstevel@tonic-gate */ 491*0Sstevel@tonic-gate if ((LIST(clmp)->lm_flags & LML_FLG_NOAUDIT) && 492*0Sstevel@tonic-gate (LIST(clmp) != LIST(dlmp))) 493*0Sstevel@tonic-gate return; 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate if ((dlmp == clmp) || (rtld_flags & (RT_FL_BREADTH | RT_FL_INITFIRST))) 496*0Sstevel@tonic-gate return; 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate if ((FLAGS(dlmp) & (FLG_RT_RELOCED | FLG_RT_INITDONE)) == 499*0Sstevel@tonic-gate (FLG_RT_RELOCED | FLG_RT_INITDONE)) 500*0Sstevel@tonic-gate return; 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate if ((FLAGS(dlmp) & (FLG_RT_RELOCED | FLG_RT_INITCALL)) == 503*0Sstevel@tonic-gate (FLG_RT_RELOCED | FLG_RT_INITCALL)) { 504*0Sstevel@tonic-gate DBG_CALL(Dbg_util_no_init(NAME(dlmp))); 505*0Sstevel@tonic-gate return; 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate if ((tobj = calloc(2, sizeof (Rt_map *))) != NULL) { 509*0Sstevel@tonic-gate tobj[0] = dlmp; 510*0Sstevel@tonic-gate call_init(tobj, DBG_INIT_DYN); 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate /* 515*0Sstevel@tonic-gate * In a threaded environment insure the thread responsible for loading an object 516*0Sstevel@tonic-gate * has completed .init processing for that object before any new thread is 517*0Sstevel@tonic-gate * allowed to access the object. This check is only valid with libthread 518*0Sstevel@tonic-gate * TI_VERSION 2, where ld.so.1 implements locking through low level mutexes. 519*0Sstevel@tonic-gate * 520*0Sstevel@tonic-gate * When a new link-map is created, the thread that causes it to be loaded is 521*0Sstevel@tonic-gate * identified by THREADID(dlmp). Compare this with the current thread to 522*0Sstevel@tonic-gate * determine if it must be blocked. 523*0Sstevel@tonic-gate * 524*0Sstevel@tonic-gate * NOTE, there are a number of instances (typically only for .plt processing) 525*0Sstevel@tonic-gate * where we must skip this test: 526*0Sstevel@tonic-gate * 527*0Sstevel@tonic-gate * . any thread id of 0 - threads that call thr_exit() may be in this state 528*0Sstevel@tonic-gate * thus we can't deduce what tid they used to be. Also some of the 529*0Sstevel@tonic-gate * lib/libthread worker threads have this id and must bind (to themselves 530*0Sstevel@tonic-gate * or libc) for libthread to function. 531*0Sstevel@tonic-gate * 532*0Sstevel@tonic-gate * . libthread itself binds to libc, and as libthread is INITFIRST 533*0Sstevel@tonic-gate * libc's .init can't have fired yet. Luckly libc's .init is not required 534*0Sstevel@tonic-gate * by libthreads binding. 535*0Sstevel@tonic-gate * 536*0Sstevel@tonic-gate * . if the caller is an auditor, and the destination isn't, then don't 537*0Sstevel@tonic-gate * block (see comments in load_completion()). 538*0Sstevel@tonic-gate */ 539*0Sstevel@tonic-gate void 540*0Sstevel@tonic-gate is_dep_ready(Rt_map * dlmp, Rt_map * clmp, int what) 541*0Sstevel@tonic-gate { 542*0Sstevel@tonic-gate thread_t tid; 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate if ((LIST(clmp)->lm_flags & LML_FLG_NOAUDIT) && 545*0Sstevel@tonic-gate (LIST(clmp) != LIST(dlmp))) 546*0Sstevel@tonic-gate return; 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_CONCUR) && 549*0Sstevel@tonic-gate ((FLAGS(dlmp) & FLG_RT_INITDONE) == 0) && 550*0Sstevel@tonic-gate ((FLAGS(clmp) & FLG_RT_INITFRST) == 0) && 551*0Sstevel@tonic-gate ((tid = rt_thr_self()) != 0) && (THREADID(dlmp) != tid)) { 552*0Sstevel@tonic-gate while ((FLAGS(dlmp) & FLG_RT_INITDONE) == 0) { 553*0Sstevel@tonic-gate FLAGS1(dlmp) |= FL1_RT_INITWAIT; 554*0Sstevel@tonic-gate DBG_CALL(Dbg_util_wait(what, NAME(clmp), NAME(dlmp))); 555*0Sstevel@tonic-gate (void) rt_cond_wait(CONDVAR(dlmp), &rtldlock); 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate } 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate /* 561*0Sstevel@tonic-gate * Execute .{preinit|init|fini}array sections 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate void 564*0Sstevel@tonic-gate call_array(Addr * array, uint_t arraysz, Rt_map * lmp, uint_t shtype) 565*0Sstevel@tonic-gate { 566*0Sstevel@tonic-gate int start, stop, incr, i; 567*0Sstevel@tonic-gate uint_t arraycnt = (uint_t)(arraysz / sizeof (Addr)); 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate if (array == NULL) 570*0Sstevel@tonic-gate return; 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate /* 573*0Sstevel@tonic-gate * initarray & preinitarray are walked from beginning to end - while 574*0Sstevel@tonic-gate * finiarray is walked from end to beginning. 575*0Sstevel@tonic-gate */ 576*0Sstevel@tonic-gate if (shtype == SHT_FINI_ARRAY) { 577*0Sstevel@tonic-gate start = arraycnt - 1; 578*0Sstevel@tonic-gate stop = incr = -1; 579*0Sstevel@tonic-gate } else { 580*0Sstevel@tonic-gate start = 0; 581*0Sstevel@tonic-gate stop = arraycnt; 582*0Sstevel@tonic-gate incr = 1; 583*0Sstevel@tonic-gate } 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate /* 586*0Sstevel@tonic-gate * Call the .*array[] entries 587*0Sstevel@tonic-gate */ 588*0Sstevel@tonic-gate for (i = start; i != stop; i += incr) { 589*0Sstevel@tonic-gate void (* fptr)(); 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate DBG_CALL(Dbg_util_call_array(NAME(lmp), (void *)array[i], i, 592*0Sstevel@tonic-gate shtype)); 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate fptr = (void(*)())array[i]; 595*0Sstevel@tonic-gate leave(LIST(lmp)); 596*0Sstevel@tonic-gate (*fptr)(); 597*0Sstevel@tonic-gate (void) enter(); 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate /* 603*0Sstevel@tonic-gate * Execute any .init sections. These are passed to us in an lmp array which 604*0Sstevel@tonic-gate * (by default) will have been sorted. 605*0Sstevel@tonic-gate */ 606*0Sstevel@tonic-gate void 607*0Sstevel@tonic-gate call_init(Rt_map ** tobj, int flag) 608*0Sstevel@tonic-gate { 609*0Sstevel@tonic-gate void (* iptr)(); 610*0Sstevel@tonic-gate Rt_map ** _tobj, ** _nobj; 611*0Sstevel@tonic-gate static List pending = { NULL, NULL }; 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate /* 614*0Sstevel@tonic-gate * If we're in the middle of an INITFIRST, this must complete before 615*0Sstevel@tonic-gate * any new init's are fired. In this case add the object list to the 616*0Sstevel@tonic-gate * pending queue and return. We'll pick up the queue after any 617*0Sstevel@tonic-gate * INITFIRST objects have their init's fired. 618*0Sstevel@tonic-gate */ 619*0Sstevel@tonic-gate if (rtld_flags & RT_FL_INITFIRST) { 620*0Sstevel@tonic-gate (void) list_append(&pending, tobj); 621*0Sstevel@tonic-gate return; 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate /* 625*0Sstevel@tonic-gate * If a 'thread initialization' is pending - call it now before any 626*0Sstevel@tonic-gate * .init code is fired. Also clear the thrinit() to mark it as done. 627*0Sstevel@tonic-gate * Note, this is called for each link-map list, which is what libc 628*0Sstevel@tonic-gate * expects. 629*0Sstevel@tonic-gate */ 630*0Sstevel@tonic-gate if (thrinit) { 631*0Sstevel@tonic-gate void (*_thrinit)() = thrinit; 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate thrinit = 0; 634*0Sstevel@tonic-gate leave((Lm_list *)0); 635*0Sstevel@tonic-gate _thrinit(); 636*0Sstevel@tonic-gate (void) enter(); 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate /* 640*0Sstevel@tonic-gate * Traverse the tobj array firing each objects init. 641*0Sstevel@tonic-gate */ 642*0Sstevel@tonic-gate for (_tobj = _nobj = tobj, _nobj++; *_tobj != NULL; _tobj++, _nobj++) { 643*0Sstevel@tonic-gate Rt_map * lmp = *_tobj; 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_INITCALL) 646*0Sstevel@tonic-gate continue; 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_INITCALL; 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate /* 651*0Sstevel@tonic-gate * Establish an initfirst state if necessary - no other inits 652*0Sstevel@tonic-gate * will be fired (because of addition relocation bindings) when 653*0Sstevel@tonic-gate * in this state. 654*0Sstevel@tonic-gate */ 655*0Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_INITFRST) 656*0Sstevel@tonic-gate rtld_flags |= RT_FL_INITFIRST; 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* 659*0Sstevel@tonic-gate * It's the responsibility of MAIN(crt0) to call it's 660*0Sstevel@tonic-gate * _init section. 661*0Sstevel@tonic-gate */ 662*0Sstevel@tonic-gate if ((FLAGS(lmp) & FLG_RT_ISMAIN) == 0) 663*0Sstevel@tonic-gate iptr = INIT(lmp); 664*0Sstevel@tonic-gate else 665*0Sstevel@tonic-gate iptr = 0; 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate if (INITARRAY(lmp) || iptr) { 668*0Sstevel@tonic-gate Aliste off; 669*0Sstevel@tonic-gate Bnd_desc ** bdpp; 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate /* 672*0Sstevel@tonic-gate * Make sure that all dependencies that have been 673*0Sstevel@tonic-gate * relocated to are initialized before this objects 674*0Sstevel@tonic-gate * .init is executed. This insures that a dependency 675*0Sstevel@tonic-gate * on an external item that must first be initialized 676*0Sstevel@tonic-gate * by its associated object is satisfied. 677*0Sstevel@tonic-gate */ 678*0Sstevel@tonic-gate for (ALIST_TRAVERSE(DEPENDS(lmp), off, bdpp)) { 679*0Sstevel@tonic-gate Bnd_desc * bdp = *bdpp; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate if ((bdp->b_flags & BND_REFER) == 0) 682*0Sstevel@tonic-gate continue; 683*0Sstevel@tonic-gate is_dep_ready(bdp->b_depend, lmp, DBG_WAIT_INIT); 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate DBG_CALL(Dbg_util_call_init(NAME(lmp), flag)); 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate if (iptr) { 689*0Sstevel@tonic-gate leave(LIST(lmp)); 690*0Sstevel@tonic-gate (*iptr)(); 691*0Sstevel@tonic-gate (void) enter(); 692*0Sstevel@tonic-gate } 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate call_array(INITARRAY(lmp), INITARRAYSZ(lmp), lmp, 695*0Sstevel@tonic-gate SHT_INIT_ARRAY); 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate if (INITARRAY(lmp) || iptr) 698*0Sstevel@tonic-gate DBG_CALL(Dbg_util_call_init(NAME(lmp), DBG_INIT_DONE)); 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate /* 701*0Sstevel@tonic-gate * Set the initdone flag regardless of whether this object 702*0Sstevel@tonic-gate * actually contains an .init section. This flag prevents us 703*0Sstevel@tonic-gate * from processing this section again for an .init and also 704*0Sstevel@tonic-gate * signifies that a .fini must be called should it exist. 705*0Sstevel@tonic-gate * Clear the sort field for use in later .fini processing. 706*0Sstevel@tonic-gate */ 707*0Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_INITDONE; 708*0Sstevel@tonic-gate SORTVAL(lmp) = 0; 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate /* 711*0Sstevel@tonic-gate * Wake anyone up who might be waiting on this .init. 712*0Sstevel@tonic-gate */ 713*0Sstevel@tonic-gate if (FLAGS1(lmp) & FL1_RT_INITWAIT) { 714*0Sstevel@tonic-gate DBG_CALL(Dbg_util_broadcast(NAME(lmp))); 715*0Sstevel@tonic-gate (void) rt_cond_broadcast(CONDVAR(lmp)); 716*0Sstevel@tonic-gate FLAGS1(lmp) &= ~FL1_RT_INITWAIT; 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate /* 720*0Sstevel@tonic-gate * Set the initdone flag regardless of whether this object 721*0Sstevel@tonic-gate * actually contains an .init section. This flag prevents us 722*0Sstevel@tonic-gate * from processing this section again for an .init and also 723*0Sstevel@tonic-gate * signifies that a .fini must be called should it exist. 724*0Sstevel@tonic-gate * Clear the sort field for use in later .fini processing. 725*0Sstevel@tonic-gate */ 726*0Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_INITDONE; 727*0Sstevel@tonic-gate SORTVAL(lmp) = 0; 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate /* 730*0Sstevel@tonic-gate * If we're firing an INITFIRST object, and other objects must 731*0Sstevel@tonic-gate * be fired which are not INITFIRST, make sure we grab any 732*0Sstevel@tonic-gate * pending objects that might have been delayed as this 733*0Sstevel@tonic-gate * INITFIRST was processed. 734*0Sstevel@tonic-gate */ 735*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_INITFIRST) && 736*0Sstevel@tonic-gate ((*_nobj == NULL) || !(FLAGS(*_nobj) & FLG_RT_INITFRST))) { 737*0Sstevel@tonic-gate Listnode * lnp; 738*0Sstevel@tonic-gate Rt_map ** pobj; 739*0Sstevel@tonic-gate 740*0Sstevel@tonic-gate rtld_flags &= ~RT_FL_INITFIRST; 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate while ((lnp = pending.head) != NULL) { 743*0Sstevel@tonic-gate if ((pending.head = lnp->next) == NULL) 744*0Sstevel@tonic-gate pending.tail = NULL; 745*0Sstevel@tonic-gate pobj = lnp->data; 746*0Sstevel@tonic-gate free(lnp); 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate call_init(pobj, DBG_INIT_PEND); 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate free(tobj); 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate /* 756*0Sstevel@tonic-gate * Function called by atexit(3C). Calls all .fini sections related with the 757*0Sstevel@tonic-gate * mains dependent shared libraries in the order in which the shared libraries 758*0Sstevel@tonic-gate * have been loaded. Skip any .fini defined in the main executable, as this 759*0Sstevel@tonic-gate * will be called by crt0 (main was never marked as initdone). 760*0Sstevel@tonic-gate */ 761*0Sstevel@tonic-gate void 762*0Sstevel@tonic-gate call_fini(Lm_list * lml, Rt_map ** tobj) 763*0Sstevel@tonic-gate { 764*0Sstevel@tonic-gate Rt_map ** _tobj; 765*0Sstevel@tonic-gate void (* fptr)(); 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate for (_tobj = tobj; *_tobj != NULL; _tobj++) { 768*0Sstevel@tonic-gate Rt_map * clmp, * lmp = *_tobj; 769*0Sstevel@tonic-gate Aliste off; 770*0Sstevel@tonic-gate Bnd_desc ** bdpp; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate /* 773*0Sstevel@tonic-gate * If concurrency checking isn't enabled only fire .fini if 774*0Sstevel@tonic-gate * .init has completed. We collect all .fini sections of 775*0Sstevel@tonic-gate * objects that had their .init collected, but that doesn't 776*0Sstevel@tonic-gate * mean at the time that the .init had completed. 777*0Sstevel@tonic-gate */ 778*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_CONCUR) || 779*0Sstevel@tonic-gate (FLAGS(lmp) & FLG_RT_INITDONE)) { 780*0Sstevel@tonic-gate /* 781*0Sstevel@tonic-gate * It's the responsibility of MAIN(crt0) to call it's 782*0Sstevel@tonic-gate * _fini section. 783*0Sstevel@tonic-gate */ 784*0Sstevel@tonic-gate if ((FLAGS(lmp) & FLG_RT_ISMAIN) == 0) 785*0Sstevel@tonic-gate fptr = FINI(lmp); 786*0Sstevel@tonic-gate else 787*0Sstevel@tonic-gate fptr = 0; 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate if (FINIARRAY(lmp) || fptr) { 790*0Sstevel@tonic-gate /* 791*0Sstevel@tonic-gate * If concurrency checking is enabled make sure 792*0Sstevel@tonic-gate * this object's .init is completed before 793*0Sstevel@tonic-gate * calling any .fini. 794*0Sstevel@tonic-gate */ 795*0Sstevel@tonic-gate is_dep_ready(lmp, lmp, DBG_WAIT_FINI); 796*0Sstevel@tonic-gate DBG_CALL(Dbg_util_call_fini(NAME(lmp))); 797*0Sstevel@tonic-gate } 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate call_array(FINIARRAY(lmp), FINIARRAYSZ(lmp), 800*0Sstevel@tonic-gate lmp, SHT_FINI_ARRAY); 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate if (fptr) { 803*0Sstevel@tonic-gate leave(LIST(lmp)); 804*0Sstevel@tonic-gate (*fptr)(); 805*0Sstevel@tonic-gate (void) enter(); 806*0Sstevel@tonic-gate } 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate /* 810*0Sstevel@tonic-gate * Audit `close' operations at this point. The library has 811*0Sstevel@tonic-gate * exercised its last instructions (regardless of whether it 812*0Sstevel@tonic-gate * will be unmapped or not). 813*0Sstevel@tonic-gate * 814*0Sstevel@tonic-gate * First call any global auditing. 815*0Sstevel@tonic-gate */ 816*0Sstevel@tonic-gate if (lml->lm_tflags & LML_TFLG_AUD_OBJCLOSE) 817*0Sstevel@tonic-gate _audit_objclose(&(auditors->ad_list), lmp); 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate /* 820*0Sstevel@tonic-gate * Finally determine whether this object has local auditing 821*0Sstevel@tonic-gate * requirements by inspecting itself and then its dependencies. 822*0Sstevel@tonic-gate */ 823*0Sstevel@tonic-gate if ((lml->lm_flags & LML_FLG_LOCAUDIT) == 0) 824*0Sstevel@tonic-gate continue; 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate if (FLAGS1(lmp) & LML_TFLG_AUD_OBJCLOSE) 827*0Sstevel@tonic-gate _audit_objclose(&(AUDITORS(lmp)->ad_list), lmp); 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate for (ALIST_TRAVERSE(CALLERS(lmp), off, bdpp)) { 830*0Sstevel@tonic-gate Bnd_desc * bdp = *bdpp; 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate clmp = bdp->b_caller; 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate if (FLAGS1(clmp) & LML_TFLG_AUD_OBJCLOSE) { 835*0Sstevel@tonic-gate _audit_objclose(&(AUDITORS(clmp)->ad_list), lmp); 836*0Sstevel@tonic-gate break; 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate } 840*0Sstevel@tonic-gate DBG_CALL(Dbg_bind_plt_summary(M_MACH, pltcnt21d, pltcnt24d, 841*0Sstevel@tonic-gate pltcntu32, pltcntu44, pltcntfull, pltcntfar)); 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate free(tobj); 844*0Sstevel@tonic-gate } 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate void 847*0Sstevel@tonic-gate atexit_fini() 848*0Sstevel@tonic-gate { 849*0Sstevel@tonic-gate Rt_map ** tobj, * lmp; 850*0Sstevel@tonic-gate Lm_list * lml; 851*0Sstevel@tonic-gate Listnode * lnp; 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate (void) enter(); 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate rtld_flags |= RT_FL_ATEXIT; 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate lml = &lml_main; 858*0Sstevel@tonic-gate lmp = (Rt_map *)lml->lm_head; 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate /* 861*0Sstevel@tonic-gate * Display any objects that haven't been referenced so far. 862*0Sstevel@tonic-gate */ 863*0Sstevel@tonic-gate unused(lml); 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate /* 866*0Sstevel@tonic-gate * Reverse topologically sort the main link-map for .fini execution. 867*0Sstevel@tonic-gate */ 868*0Sstevel@tonic-gate if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != 0) && 869*0Sstevel@tonic-gate (tobj != (Rt_map **)S_ERROR)) 870*0Sstevel@tonic-gate call_fini(lml, tobj); 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate /* 873*0Sstevel@tonic-gate * Add an explicit close to main and ld.so.1 (as their fini doesn't get 874*0Sstevel@tonic-gate * processed this auditing will not get caught in call_fini()). This is 875*0Sstevel@tonic-gate * the reverse of the explicit calls to audit_objopen() made in setup(). 876*0Sstevel@tonic-gate */ 877*0Sstevel@tonic-gate if ((lml->lm_tflags | FLAGS1(lmp)) & LML_TFLG_AUD_MASK) { 878*0Sstevel@tonic-gate audit_objclose(lmp, (Rt_map *)lml_rtld.lm_head); 879*0Sstevel@tonic-gate /* 880*0Sstevel@tonic-gate * If the executable has a fini-array, then it was captured 881*0Sstevel@tonic-gate * as part of the call_fini() processing. 882*0Sstevel@tonic-gate */ 883*0Sstevel@tonic-gate if (FINIARRAY(lmp) == 0) 884*0Sstevel@tonic-gate audit_objclose(lmp, lmp); 885*0Sstevel@tonic-gate } 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate /* 888*0Sstevel@tonic-gate * Now that all .fini code has been run, see what unreferenced objects 889*0Sstevel@tonic-gate * remain. Any difference between this and the above unused() would 890*0Sstevel@tonic-gate * indicate an object is only being used for .fini processing, which 891*0Sstevel@tonic-gate * might be fine, but might also indicate an overhead whose removal 892*0Sstevel@tonic-gate * would be worth considering. 893*0Sstevel@tonic-gate */ 894*0Sstevel@tonic-gate unused(lml); 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate /* 897*0Sstevel@tonic-gate * Traverse any alternative link-map lists. 898*0Sstevel@tonic-gate */ 899*0Sstevel@tonic-gate for (LIST_TRAVERSE(&dynlm_list, lnp, lml)) { 900*0Sstevel@tonic-gate if (lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) 901*0Sstevel@tonic-gate continue; 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate if ((lmp = (Rt_map *)lml->lm_head) == 0) 904*0Sstevel@tonic-gate continue; 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate /* 907*0Sstevel@tonic-gate * Reverse topologically sort the link-map for .fini execution. 908*0Sstevel@tonic-gate */ 909*0Sstevel@tonic-gate if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != 0) && 910*0Sstevel@tonic-gate (tobj != (Rt_map **)S_ERROR)) 911*0Sstevel@tonic-gate call_fini(lml, tobj); 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate unused(lml); 914*0Sstevel@tonic-gate } 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate /* 917*0Sstevel@tonic-gate * Finally reverse topologically sort the runtime linkers link-map for 918*0Sstevel@tonic-gate * .fini execution. 919*0Sstevel@tonic-gate */ 920*0Sstevel@tonic-gate lml = &lml_rtld; 921*0Sstevel@tonic-gate lmp = (Rt_map *)lml->lm_head; 922*0Sstevel@tonic-gate 923*0Sstevel@tonic-gate dbg_mask = 0; 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate if (((tobj = tsort(lmp, lml->lm_obj, RT_SORT_FWD)) != 0) && 926*0Sstevel@tonic-gate (tobj != (Rt_map **)S_ERROR)) 927*0Sstevel@tonic-gate call_fini(lml, tobj); 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate leave(&lml_main); 930*0Sstevel@tonic-gate } 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate /* 934*0Sstevel@tonic-gate * This routine is called to complete any runtime linker activity which may have 935*0Sstevel@tonic-gate * resulted in objects being loaded. This is called from all user entry points 936*0Sstevel@tonic-gate * and from any internal dl*() requests. 937*0Sstevel@tonic-gate */ 938*0Sstevel@tonic-gate void 939*0Sstevel@tonic-gate load_completion(Rt_map * nlmp, Rt_map * clmp) 940*0Sstevel@tonic-gate { 941*0Sstevel@tonic-gate Rt_map **tobj = 0; 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate /* 944*0Sstevel@tonic-gate * Establish any .init processing. Note, in a world of lazy loading, 945*0Sstevel@tonic-gate * objects may have been loaded regardless of whether the users request 946*0Sstevel@tonic-gate * was fulfilled (i.e., a dlsym() request may have failed to find a 947*0Sstevel@tonic-gate * symbol but objects might have been loaded during its search). Thus, 948*0Sstevel@tonic-gate * any tsorting starts from the nlmp (new link-maps) pointer and not 949*0Sstevel@tonic-gate * necessarily from the link-map that may have satisfied the request. 950*0Sstevel@tonic-gate * 951*0Sstevel@tonic-gate * Note, if the caller is an auditor, and the destination isn't, then 952*0Sstevel@tonic-gate * don't run any .inits. This scenario is typical of an auditor trying 953*0Sstevel@tonic-gate * to inspect another link-map for symbols. Allow this inspection 954*0Sstevel@tonic-gate * without running any code on the inspected link-map, as running this 955*0Sstevel@tonic-gate * code may reenter the auditor, who has not yet finished their own 956*0Sstevel@tonic-gate * initialization. 957*0Sstevel@tonic-gate */ 958*0Sstevel@tonic-gate if (nlmp && ((clmp == 0) || 959*0Sstevel@tonic-gate ((LIST(clmp)->lm_flags & LML_FLG_NOAUDIT) == 0) || 960*0Sstevel@tonic-gate (LIST(clmp) == LIST(nlmp)))) { 961*0Sstevel@tonic-gate if ((tobj = tsort(nlmp, LIST(nlmp)->lm_init, RT_SORT_REV)) == 962*0Sstevel@tonic-gate (Rt_map **)S_ERROR) 963*0Sstevel@tonic-gate tobj = 0; 964*0Sstevel@tonic-gate } 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate /* 967*0Sstevel@tonic-gate * Indicate the link-map list is consistent. 968*0Sstevel@tonic-gate */ 969*0Sstevel@tonic-gate if (clmp && 970*0Sstevel@tonic-gate ((LIST(clmp)->lm_tflags | FLAGS1(clmp)) & LML_TFLG_AUD_ACTIVITY)) 971*0Sstevel@tonic-gate audit_activity(clmp, LA_ACT_CONSISTENT); 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate /* 974*0Sstevel@tonic-gate * Fire any .init's. 975*0Sstevel@tonic-gate */ 976*0Sstevel@tonic-gate if (tobj) 977*0Sstevel@tonic-gate call_init(tobj, DBG_INIT_SORT); 978*0Sstevel@tonic-gate } 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate /* 981*0Sstevel@tonic-gate * Append an item to the specified list, and return a pointer to the list 982*0Sstevel@tonic-gate * node created. 983*0Sstevel@tonic-gate */ 984*0Sstevel@tonic-gate Listnode * 985*0Sstevel@tonic-gate list_append(List *lst, const void *item) 986*0Sstevel@tonic-gate { 987*0Sstevel@tonic-gate Listnode * _lnp; 988*0Sstevel@tonic-gate 989*0Sstevel@tonic-gate if ((_lnp = malloc(sizeof (Listnode))) == 0) 990*0Sstevel@tonic-gate return (0); 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate _lnp->data = (void *)item; 993*0Sstevel@tonic-gate _lnp->next = NULL; 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate if (lst->head == NULL) 996*0Sstevel@tonic-gate lst->tail = lst->head = _lnp; 997*0Sstevel@tonic-gate else { 998*0Sstevel@tonic-gate lst->tail->next = _lnp; 999*0Sstevel@tonic-gate lst->tail = lst->tail->next; 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate return (_lnp); 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate 1004*0Sstevel@tonic-gate 1005*0Sstevel@tonic-gate /* 1006*0Sstevel@tonic-gate * Add an item after specified listnode, and return a pointer to the list 1007*0Sstevel@tonic-gate * node created. 1008*0Sstevel@tonic-gate */ 1009*0Sstevel@tonic-gate Listnode * 1010*0Sstevel@tonic-gate list_insert(List *lst, const void *item, Listnode *lnp) 1011*0Sstevel@tonic-gate { 1012*0Sstevel@tonic-gate Listnode * _lnp; 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate if ((_lnp = malloc(sizeof (Listnode))) == (Listnode *)0) 1015*0Sstevel@tonic-gate return (0); 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate _lnp->data = (void *)item; 1018*0Sstevel@tonic-gate _lnp->next = lnp->next; 1019*0Sstevel@tonic-gate if (_lnp->next == NULL) 1020*0Sstevel@tonic-gate lst->tail = _lnp; 1021*0Sstevel@tonic-gate lnp->next = _lnp; 1022*0Sstevel@tonic-gate return (_lnp); 1023*0Sstevel@tonic-gate } 1024*0Sstevel@tonic-gate 1025*0Sstevel@tonic-gate /* 1026*0Sstevel@tonic-gate * Prepend an item to the specified list, and return a pointer to the 1027*0Sstevel@tonic-gate * list node created. 1028*0Sstevel@tonic-gate */ 1029*0Sstevel@tonic-gate Listnode * 1030*0Sstevel@tonic-gate list_prepend(List * lst, const void * item) 1031*0Sstevel@tonic-gate { 1032*0Sstevel@tonic-gate Listnode * _lnp; 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate if ((_lnp = malloc(sizeof (Listnode))) == (Listnode *)0) 1035*0Sstevel@tonic-gate return (0); 1036*0Sstevel@tonic-gate 1037*0Sstevel@tonic-gate _lnp->data = (void *)item; 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate if (lst->head == NULL) { 1040*0Sstevel@tonic-gate _lnp->next = NULL; 1041*0Sstevel@tonic-gate lst->tail = lst->head = _lnp; 1042*0Sstevel@tonic-gate } else { 1043*0Sstevel@tonic-gate _lnp->next = lst->head; 1044*0Sstevel@tonic-gate lst->head = _lnp; 1045*0Sstevel@tonic-gate } 1046*0Sstevel@tonic-gate return (_lnp); 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate 1050*0Sstevel@tonic-gate /* 1051*0Sstevel@tonic-gate * Delete a 'listnode' from a list. 1052*0Sstevel@tonic-gate */ 1053*0Sstevel@tonic-gate void 1054*0Sstevel@tonic-gate list_delete(List * lst, void * item) 1055*0Sstevel@tonic-gate { 1056*0Sstevel@tonic-gate Listnode * clnp, * plnp; 1057*0Sstevel@tonic-gate 1058*0Sstevel@tonic-gate for (plnp = NULL, clnp = lst->head; clnp; clnp = clnp->next) { 1059*0Sstevel@tonic-gate if (item == clnp->data) 1060*0Sstevel@tonic-gate break; 1061*0Sstevel@tonic-gate plnp = clnp; 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate if (clnp == 0) 1065*0Sstevel@tonic-gate return; 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate if (lst->head == clnp) 1068*0Sstevel@tonic-gate lst->head = clnp->next; 1069*0Sstevel@tonic-gate if (lst->tail == clnp) 1070*0Sstevel@tonic-gate lst->tail = plnp; 1071*0Sstevel@tonic-gate 1072*0Sstevel@tonic-gate if (plnp) 1073*0Sstevel@tonic-gate plnp->next = clnp->next; 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate free(clnp); 1076*0Sstevel@tonic-gate } 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate /* 1079*0Sstevel@tonic-gate * Append an item to the specified link map control list. 1080*0Sstevel@tonic-gate */ 1081*0Sstevel@tonic-gate void 1082*0Sstevel@tonic-gate lm_append(Lm_list *lml, Aliste lmco, Rt_map *lmp) 1083*0Sstevel@tonic-gate { 1084*0Sstevel@tonic-gate Lm_cntl *lmc; 1085*0Sstevel@tonic-gate int add = 1; 1086*0Sstevel@tonic-gate 1087*0Sstevel@tonic-gate /* 1088*0Sstevel@tonic-gate * Indicate that this link-map list has a new object. 1089*0Sstevel@tonic-gate */ 1090*0Sstevel@tonic-gate (lml->lm_obj)++; 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate /* 1093*0Sstevel@tonic-gate * Alert the debuggers that we are about to mess with the main link-map 1094*0Sstevel@tonic-gate * control list. 1095*0Sstevel@tonic-gate */ 1096*0Sstevel@tonic-gate if ((lmco == ALO_DATA) && ((lml->lm_flags & LML_FLG_DBNOTIF) == 0)) 1097*0Sstevel@tonic-gate rd_event(lml, RD_DLACTIVITY, RT_DELETE); 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate /* LINTED */ 1100*0Sstevel@tonic-gate lmc = (Lm_cntl *)((char *)lml->lm_lists + lmco); 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate /* 1103*0Sstevel@tonic-gate * A link-map list header points to one of more link-map control lists 1104*0Sstevel@tonic-gate * (see include/rtld.h). The initial list, pointed to by lm_cntl, is 1105*0Sstevel@tonic-gate * the list of relocated objects. Other lists maintain objects that 1106*0Sstevel@tonic-gate * are still being analyzed or relocated. This list provides the core 1107*0Sstevel@tonic-gate * link-map list information used by all ld.so.1 routines. 1108*0Sstevel@tonic-gate */ 1109*0Sstevel@tonic-gate if (lmc->lc_head == NULL) { 1110*0Sstevel@tonic-gate /* 1111*0Sstevel@tonic-gate * If this is the first link-map for the given control list, 1112*0Sstevel@tonic-gate * initialize the list. 1113*0Sstevel@tonic-gate */ 1114*0Sstevel@tonic-gate lmc->lc_head = lmc->lc_tail = lmp; 1115*0Sstevel@tonic-gate add = 0; 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate } else if (FLAGS(lmp) & FLG_RT_INTRPOSE) { 1118*0Sstevel@tonic-gate Rt_map *tlmp; 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate /* 1121*0Sstevel@tonic-gate * If this is an interposer then append the link-map following 1122*0Sstevel@tonic-gate * any other interposers (these are objects that have been 1123*0Sstevel@tonic-gate * previously preloaded, or were identified with -z interpose). 1124*0Sstevel@tonic-gate * Interposers can only be inserted on the first link-map 1125*0Sstevel@tonic-gate * control list, as once relocation has started, interposition 1126*0Sstevel@tonic-gate * from new interposers can't be guaranteed. 1127*0Sstevel@tonic-gate * 1128*0Sstevel@tonic-gate * NOTE: We do not interpose on the head of a list. This model 1129*0Sstevel@tonic-gate * evolved because dynamic executables have already been fully 1130*0Sstevel@tonic-gate * relocated within themselves and thus can't be interposed on. 1131*0Sstevel@tonic-gate * Nowadays it's possible to have shared objects at the head of 1132*0Sstevel@tonic-gate * a list, which conceptually means they could be interposed on. 1133*0Sstevel@tonic-gate * But, shared objects can be created via dldump() and may only 1134*0Sstevel@tonic-gate * be partially relocated (just relatives), in which case they 1135*0Sstevel@tonic-gate * are interposable, but are marked as fixed (ET_EXEC). 1136*0Sstevel@tonic-gate * 1137*0Sstevel@tonic-gate * Thus we really don't have a clear method of deciding when the 1138*0Sstevel@tonic-gate * head of a link-map is interposable. So, to be consistent, 1139*0Sstevel@tonic-gate * for now only add interposers after the link-map lists head 1140*0Sstevel@tonic-gate * object. 1141*0Sstevel@tonic-gate */ 1142*0Sstevel@tonic-gate for (tlmp = (Rt_map *)NEXT(lmc->lc_head); tlmp; 1143*0Sstevel@tonic-gate tlmp = (Rt_map *)NEXT(tlmp)) { 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate if (FLAGS(tlmp) & FLG_RT_INTRPOSE) 1146*0Sstevel@tonic-gate continue; 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate /* 1149*0Sstevel@tonic-gate * Insert the new link-map before this non-interposer, 1150*0Sstevel@tonic-gate * and indicate an interposer is found. 1151*0Sstevel@tonic-gate */ 1152*0Sstevel@tonic-gate NEXT((Rt_map *)PREV(tlmp)) = (Link_map *)lmp; 1153*0Sstevel@tonic-gate PREV(lmp) = PREV(tlmp); 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate NEXT(lmp) = (Link_map *)tlmp; 1156*0Sstevel@tonic-gate PREV(tlmp) = (Link_map *)lmp; 1157*0Sstevel@tonic-gate 1158*0Sstevel@tonic-gate lmc->lc_flags |= LMC_FLG_REANALYZE; 1159*0Sstevel@tonic-gate add = 0; 1160*0Sstevel@tonic-gate break; 1161*0Sstevel@tonic-gate } 1162*0Sstevel@tonic-gate } 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate /* 1165*0Sstevel@tonic-gate * Fall through to appending the new link map to the tail of the list. 1166*0Sstevel@tonic-gate * If we're processing the initial objects of this link-map list, add 1167*0Sstevel@tonic-gate * them to the backward compatibility list. 1168*0Sstevel@tonic-gate */ 1169*0Sstevel@tonic-gate if (add) { 1170*0Sstevel@tonic-gate NEXT(lmc->lc_tail) = (Link_map *)lmp; 1171*0Sstevel@tonic-gate PREV(lmp) = (Link_map *)lmc->lc_tail; 1172*0Sstevel@tonic-gate lmc->lc_tail = lmp; 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate /* 1176*0Sstevel@tonic-gate * Having added this link-map to a control list, indicate which control 1177*0Sstevel@tonic-gate * list the link-map belongs to. Note, control list information is 1178*0Sstevel@tonic-gate * always maintained as an offset, as the Alist can be reallocated. 1179*0Sstevel@tonic-gate */ 1180*0Sstevel@tonic-gate CNTL(lmp) = lmco; 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate /* 1183*0Sstevel@tonic-gate * Indicate if an interposer is found. Note that the first object on a 1184*0Sstevel@tonic-gate * link-map can be explicitly defined as an interposer so that it can 1185*0Sstevel@tonic-gate * provide interposition over direct binding requests. 1186*0Sstevel@tonic-gate */ 1187*0Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_INTRPOSE) 1188*0Sstevel@tonic-gate lml->lm_flags |= LML_FLG_INTRPOSE; 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate /* 1191*0Sstevel@tonic-gate * For backward compatibility with debuggers, the link-map list contains 1192*0Sstevel@tonic-gate * pointers to the main control list. 1193*0Sstevel@tonic-gate */ 1194*0Sstevel@tonic-gate if (lmco == ALO_DATA) { 1195*0Sstevel@tonic-gate lml->lm_head = lmc->lc_head; 1196*0Sstevel@tonic-gate lml->lm_tail = lmc->lc_tail; 1197*0Sstevel@tonic-gate } 1198*0Sstevel@tonic-gate } 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate /* 1201*0Sstevel@tonic-gate * Delete an item from the specified link map control list. 1202*0Sstevel@tonic-gate */ 1203*0Sstevel@tonic-gate void 1204*0Sstevel@tonic-gate lm_delete(Lm_list *lml, Rt_map *lmp) 1205*0Sstevel@tonic-gate { 1206*0Sstevel@tonic-gate Lm_cntl *lmc; 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate /* 1209*0Sstevel@tonic-gate * If the control list pointer hasn't been initialized, this object 1210*0Sstevel@tonic-gate * never got added to a link-map list. 1211*0Sstevel@tonic-gate */ 1212*0Sstevel@tonic-gate if (CNTL(lmp) == 0) 1213*0Sstevel@tonic-gate return; 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate /* 1216*0Sstevel@tonic-gate * Alert the debuggers that we are about to mess with the main link-map 1217*0Sstevel@tonic-gate * control list. 1218*0Sstevel@tonic-gate */ 1219*0Sstevel@tonic-gate if ((CNTL(lmp) == ALO_DATA) && ((lml->lm_flags & LML_FLG_DBNOTIF) == 0)) 1220*0Sstevel@tonic-gate rd_event(lml, RD_DLACTIVITY, RT_DELETE); 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate /* LINTED */ 1223*0Sstevel@tonic-gate lmc = (Lm_cntl *)((char *)lml->lm_lists + CNTL(lmp)); 1224*0Sstevel@tonic-gate 1225*0Sstevel@tonic-gate if (lmc->lc_head == lmp) 1226*0Sstevel@tonic-gate lmc->lc_head = (Rt_map *)NEXT(lmp); 1227*0Sstevel@tonic-gate else 1228*0Sstevel@tonic-gate NEXT((Rt_map *)PREV(lmp)) = (void *)NEXT(lmp); 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate if (lmc->lc_tail == lmp) 1231*0Sstevel@tonic-gate lmc->lc_tail = (Rt_map *)PREV(lmp); 1232*0Sstevel@tonic-gate else 1233*0Sstevel@tonic-gate PREV((Rt_map *)NEXT(lmp)) = PREV(lmp); 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate /* 1236*0Sstevel@tonic-gate * For backward compatibility with debuggers, the link-map list contains 1237*0Sstevel@tonic-gate * pointers to the main control list. 1238*0Sstevel@tonic-gate */ 1239*0Sstevel@tonic-gate if (lmc == (Lm_cntl *)&(lml->lm_lists->al_data)) { 1240*0Sstevel@tonic-gate lml->lm_head = lmc->lc_head; 1241*0Sstevel@tonic-gate lml->lm_tail = lmc->lc_tail; 1242*0Sstevel@tonic-gate } 1243*0Sstevel@tonic-gate 1244*0Sstevel@tonic-gate /* 1245*0Sstevel@tonic-gate * Indicate we have one less object on this control list. 1246*0Sstevel@tonic-gate */ 1247*0Sstevel@tonic-gate (lml->lm_obj)--; 1248*0Sstevel@tonic-gate } 1249*0Sstevel@tonic-gate 1250*0Sstevel@tonic-gate /* 1251*0Sstevel@tonic-gate * Move a link-map control list to another. Objects that are being relocated 1252*0Sstevel@tonic-gate * are maintained on secondary control lists. Once their relocation is 1253*0Sstevel@tonic-gate * complete, the entire list is appended to the previous control list, as this 1254*0Sstevel@tonic-gate * list must have been the trigger for generating the new control list. 1255*0Sstevel@tonic-gate */ 1256*0Sstevel@tonic-gate void 1257*0Sstevel@tonic-gate lm_move(Lm_list *lml, Aliste nlmco, Aliste plmco, Lm_cntl *nlmc, Lm_cntl *plmc) 1258*0Sstevel@tonic-gate { 1259*0Sstevel@tonic-gate Rt_map *lmp; 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate DBG_CALL(Dbg_file_cntl(lml, nlmco, plmco)); 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate /* 1264*0Sstevel@tonic-gate * Alert the debuggers that we are about to mess with the main link-map 1265*0Sstevel@tonic-gate * control list. 1266*0Sstevel@tonic-gate */ 1267*0Sstevel@tonic-gate if ((plmco == ALO_DATA) && ((lml->lm_flags & LML_FLG_DBNOTIF) == 0)) 1268*0Sstevel@tonic-gate rd_event(lml, RD_DLACTIVITY, RT_ADD); 1269*0Sstevel@tonic-gate 1270*0Sstevel@tonic-gate /* 1271*0Sstevel@tonic-gate * Indicate each new link-map has been moved to the previous link-map 1272*0Sstevel@tonic-gate * control list. 1273*0Sstevel@tonic-gate */ 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate for (lmp = nlmc->lc_head; lmp; lmp = (Rt_map *)NEXT(lmp)) 1276*0Sstevel@tonic-gate CNTL(lmp) = plmco; 1277*0Sstevel@tonic-gate 1278*0Sstevel@tonic-gate /* 1279*0Sstevel@tonic-gate * Move the new link-map control list, to the callers link-map control 1280*0Sstevel@tonic-gate * list. 1281*0Sstevel@tonic-gate */ 1282*0Sstevel@tonic-gate if (plmc->lc_head == 0) { 1283*0Sstevel@tonic-gate plmc->lc_head = nlmc->lc_head; 1284*0Sstevel@tonic-gate PREV(nlmc->lc_head) = 0; 1285*0Sstevel@tonic-gate } else { 1286*0Sstevel@tonic-gate NEXT(plmc->lc_tail) = (Link_map *)nlmc->lc_head; 1287*0Sstevel@tonic-gate PREV(nlmc->lc_head) = (Link_map *)plmc->lc_tail; 1288*0Sstevel@tonic-gate } 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate plmc->lc_tail = nlmc->lc_tail; 1291*0Sstevel@tonic-gate nlmc->lc_head = nlmc->lc_tail = 0; 1292*0Sstevel@tonic-gate 1293*0Sstevel@tonic-gate /* 1294*0Sstevel@tonic-gate * For backward compatibility with debuggers, the link-map list contains 1295*0Sstevel@tonic-gate * pointers to the main control list. 1296*0Sstevel@tonic-gate */ 1297*0Sstevel@tonic-gate if (plmco == ALO_DATA) { 1298*0Sstevel@tonic-gate lml->lm_head = plmc->lc_head; 1299*0Sstevel@tonic-gate lml->lm_tail = plmc->lc_tail; 1300*0Sstevel@tonic-gate } 1301*0Sstevel@tonic-gate } 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate /* 1304*0Sstevel@tonic-gate * Dlopening a family of objects occurs on a new link-map control list. If the 1305*0Sstevel@tonic-gate * dlopen fails, then its handle is used to tear down the family (dlclose). 1306*0Sstevel@tonic-gate * However, the relocation of this family may have triggered other objects to 1307*0Sstevel@tonic-gate * be loaded, and after their relocation they will have been moved to the 1308*0Sstevel@tonic-gate * dlopen families control list. After a dlopen() failure, see if there are 1309*0Sstevel@tonic-gate * any objects that can be savaged before tearing down this control list. 1310*0Sstevel@tonic-gate */ 1311*0Sstevel@tonic-gate int 1312*0Sstevel@tonic-gate lm_salvage(Lm_list *lml, int test, Aliste nlmco) 1313*0Sstevel@tonic-gate { 1314*0Sstevel@tonic-gate Lm_cntl *nlmc; 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate /* 1317*0Sstevel@tonic-gate * If a dlopen occurred on a new link-map list, then its dlclose may 1318*0Sstevel@tonic-gate * have completely torn down the link-map list. Check that the link-map 1319*0Sstevel@tonic-gate * list still exists before proceeding. 1320*0Sstevel@tonic-gate */ 1321*0Sstevel@tonic-gate if (test) { 1322*0Sstevel@tonic-gate Listnode *lnp; 1323*0Sstevel@tonic-gate Lm_list *tlml; 1324*0Sstevel@tonic-gate int found = 0; 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate for (LIST_TRAVERSE(&dynlm_list, lnp, tlml)) { 1327*0Sstevel@tonic-gate if (tlml == lml) { 1328*0Sstevel@tonic-gate found++; 1329*0Sstevel@tonic-gate break; 1330*0Sstevel@tonic-gate } 1331*0Sstevel@tonic-gate } 1332*0Sstevel@tonic-gate if (found == 0) 1333*0Sstevel@tonic-gate return (0); 1334*0Sstevel@tonic-gate } 1335*0Sstevel@tonic-gate 1336*0Sstevel@tonic-gate /* LINTED */ 1337*0Sstevel@tonic-gate nlmc = (Lm_cntl *)((char *)lml->lm_lists + nlmco); 1338*0Sstevel@tonic-gate 1339*0Sstevel@tonic-gate /* 1340*0Sstevel@tonic-gate * If this link-map control list still contains objects, determine the 1341*0Sstevel@tonic-gate * previous control list and move the objects. 1342*0Sstevel@tonic-gate */ 1343*0Sstevel@tonic-gate if (nlmc->lc_head) { 1344*0Sstevel@tonic-gate Lm_cntl *plmc; 1345*0Sstevel@tonic-gate Aliste plmco; 1346*0Sstevel@tonic-gate 1347*0Sstevel@tonic-gate plmco = nlmco - lml->lm_lists->al_size; 1348*0Sstevel@tonic-gate /* LINTED */ 1349*0Sstevel@tonic-gate plmc = (Lm_cntl *)((char *)lml->lm_lists + plmco); 1350*0Sstevel@tonic-gate 1351*0Sstevel@tonic-gate lm_move(lml, nlmco, plmco, nlmc, plmc); 1352*0Sstevel@tonic-gate } 1353*0Sstevel@tonic-gate return (1); 1354*0Sstevel@tonic-gate } 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate /* 1357*0Sstevel@tonic-gate * Environment variables can have a variety of defined permutations, and thus 1358*0Sstevel@tonic-gate * the following infrastructure exists to allow this variety and to select the 1359*0Sstevel@tonic-gate * required definition. 1360*0Sstevel@tonic-gate * 1361*0Sstevel@tonic-gate * Environment variables can be defined as 32- or 64-bit specific, and if so 1362*0Sstevel@tonic-gate * they will take precedence over any instruction set neutral form. Typically 1363*0Sstevel@tonic-gate * this is only useful when the environment value is an informational string. 1364*0Sstevel@tonic-gate * 1365*0Sstevel@tonic-gate * Environment variables may be obtained from the standard user environment or 1366*0Sstevel@tonic-gate * from a configuration file. The latter provides a fallback if no user 1367*0Sstevel@tonic-gate * environment setting is found, and can take two forms: 1368*0Sstevel@tonic-gate * 1369*0Sstevel@tonic-gate * . a replaceable definition - this will be used if no user environment 1370*0Sstevel@tonic-gate * setting has been seen, or 1371*0Sstevel@tonic-gate * 1372*0Sstevel@tonic-gate * . an permanent definition - this will be used no matter what user 1373*0Sstevel@tonic-gate * environment setting is seen. In the case of list variables it will be 1374*0Sstevel@tonic-gate * appended to any process environment setting seen. 1375*0Sstevel@tonic-gate * 1376*0Sstevel@tonic-gate * Environment variables can be defined without a value (ie. LD_XXXX=) so as to 1377*0Sstevel@tonic-gate * override any replaceable environment variables from a configuration file. 1378*0Sstevel@tonic-gate */ 1379*0Sstevel@tonic-gate static u_longlong_t rplgen; /* replaceable generic */ 1380*0Sstevel@tonic-gate /* variables */ 1381*0Sstevel@tonic-gate static u_longlong_t rplisa; /* replaceable ISA specific */ 1382*0Sstevel@tonic-gate /* variables */ 1383*0Sstevel@tonic-gate static u_longlong_t prmgen; /* permanent generic */ 1384*0Sstevel@tonic-gate /* variables */ 1385*0Sstevel@tonic-gate static u_longlong_t prmisa; /* permanent ISA specific */ 1386*0Sstevel@tonic-gate /* variables */ 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate /* 1389*0Sstevel@tonic-gate * Classify an environment variables type. 1390*0Sstevel@tonic-gate */ 1391*0Sstevel@tonic-gate #define ENV_TYP_IGNORE 0x1 /* ignore - variable is for */ 1392*0Sstevel@tonic-gate /* the wrong ISA */ 1393*0Sstevel@tonic-gate #define ENV_TYP_ISA 0x2 /* variable is ISA specific */ 1394*0Sstevel@tonic-gate #define ENV_TYP_CONFIG 0x4 /* variable obtained from a */ 1395*0Sstevel@tonic-gate /* config file */ 1396*0Sstevel@tonic-gate #define ENV_TYP_PERMANT 0x8 /* variable is permanent */ 1397*0Sstevel@tonic-gate 1398*0Sstevel@tonic-gate /* 1399*0Sstevel@tonic-gate * Identify all environment variables. 1400*0Sstevel@tonic-gate */ 1401*0Sstevel@tonic-gate #define ENV_FLG_AUDIT 0x0000000001ULL 1402*0Sstevel@tonic-gate #define ENV_FLG_AUDIT_ARGS 0x0000000002ULL 1403*0Sstevel@tonic-gate #define ENV_FLG_BIND_NOW 0x0000000004ULL 1404*0Sstevel@tonic-gate #define ENV_FLG_BIND_NOT 0x0000000008ULL 1405*0Sstevel@tonic-gate #define ENV_FLG_BINDINGS 0x0000000010ULL 1406*0Sstevel@tonic-gate #define ENV_FLG_CONCURRENCY 0x0000000020ULL 1407*0Sstevel@tonic-gate #define ENV_FLG_CONFGEN 0x0000000040ULL 1408*0Sstevel@tonic-gate #define ENV_FLG_CONFIG 0x0000000080ULL 1409*0Sstevel@tonic-gate #define ENV_FLG_DEBUG 0x0000000100ULL 1410*0Sstevel@tonic-gate #define ENV_FLG_DEBUG_OUTPUT 0x0000000200ULL 1411*0Sstevel@tonic-gate #define ENV_FLG_DEMANGLE 0x0000000400ULL 1412*0Sstevel@tonic-gate #define ENV_FLG_FLAGS 0x0000000800ULL 1413*0Sstevel@tonic-gate #define ENV_FLG_INIT 0x0000001000ULL 1414*0Sstevel@tonic-gate #define ENV_FLG_LIBPATH 0x0000002000ULL 1415*0Sstevel@tonic-gate #define ENV_FLG_LOADAVAIL 0x0000004000ULL 1416*0Sstevel@tonic-gate #define ENV_FLG_LOADFLTR 0x0000008000ULL 1417*0Sstevel@tonic-gate #define ENV_FLG_NOAUDIT 0x0000010000ULL 1418*0Sstevel@tonic-gate #define ENV_FLG_NOAUXFLTR 0x0000020000ULL 1419*0Sstevel@tonic-gate #define ENV_FLG_NOBAPLT 0x0000040000ULL 1420*0Sstevel@tonic-gate #define ENV_FLG_NOCONFIG 0x0000080000ULL 1421*0Sstevel@tonic-gate #define ENV_FLG_NODIRCONFIG 0x0000100000ULL 1422*0Sstevel@tonic-gate #define ENV_FLG_NODIRECT 0x0000200000ULL 1423*0Sstevel@tonic-gate #define ENV_FLG_NOENVCONFIG 0x0000400000ULL 1424*0Sstevel@tonic-gate #define ENV_FLG_NOLAZY 0x0000800000ULL 1425*0Sstevel@tonic-gate #define ENV_FLG_NOOBJALTER 0x0001000000ULL 1426*0Sstevel@tonic-gate #define ENV_FLG_NOVERSION 0x0002000000ULL 1427*0Sstevel@tonic-gate #define ENV_FLG_PRELOAD 0x0004000000ULL 1428*0Sstevel@tonic-gate #define ENV_FLG_PROFILE 0x0008000000ULL 1429*0Sstevel@tonic-gate #define ENV_FLG_PROFILE_OUTPUT 0x0010000000ULL 1430*0Sstevel@tonic-gate #define ENV_FLG_SIGNAL 0x0020000000ULL 1431*0Sstevel@tonic-gate #define ENV_FLG_TRACE_OBJS 0x0040000000ULL 1432*0Sstevel@tonic-gate #define ENV_FLG_TRACE_PTHS 0x0080000000ULL 1433*0Sstevel@tonic-gate #define ENV_FLG_UNREF 0x0100000000ULL 1434*0Sstevel@tonic-gate #define ENV_FLG_UNUSED 0x0200000000ULL 1435*0Sstevel@tonic-gate #define ENV_FLG_VERBOSE 0x0400000000ULL 1436*0Sstevel@tonic-gate #define ENV_FLG_WARN 0x0800000000ULL 1437*0Sstevel@tonic-gate #define ENV_FLG_NOFLTCONFIG 0x1000000000ULL 1438*0Sstevel@tonic-gate 1439*0Sstevel@tonic-gate #ifdef SIEBEL_DISABLE 1440*0Sstevel@tonic-gate #define ENV_FLG_FIX_1 0x8000000000ULL 1441*0Sstevel@tonic-gate #endif 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate #define SEL_REPLACE 0x0001 1444*0Sstevel@tonic-gate #define SEL_PERMANT 0x0002 1445*0Sstevel@tonic-gate #define SEL_ACT_RT 0x0100 /* setting rtld_flags */ 1446*0Sstevel@tonic-gate #define SEL_ACT_RT2 0x0200 /* setting rtld_flags2 */ 1447*0Sstevel@tonic-gate #define SEL_ACT_STR 0x0400 /* setting string value */ 1448*0Sstevel@tonic-gate #define SEL_ACT_LML 0x0800 /* setting lml_flags */ 1449*0Sstevel@tonic-gate #define SEL_ACT_LMLT 0x1000 /* setting lml_tflags */ 1450*0Sstevel@tonic-gate #define SEL_ACT_SPEC_1 0x2000 /* For FLG_{FLAGS, LIBPATH} */ 1451*0Sstevel@tonic-gate #define SEL_ACT_SPEC_2 0x4000 /* need special handling */ 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate /* 1454*0Sstevel@tonic-gate * Pattern match an LD_XXXX environment variable. s1 points to the XXXX part 1455*0Sstevel@tonic-gate * and len specifies its length (comparing a strings length before the string 1456*0Sstevel@tonic-gate * itself speed things up). s2 points to the token itself which has already 1457*0Sstevel@tonic-gate * had any leading white-space removed. 1458*0Sstevel@tonic-gate */ 1459*0Sstevel@tonic-gate static void 1460*0Sstevel@tonic-gate ld_generic_env(const char *s1, size_t len, const char *s2, Word *lmflags, 1461*0Sstevel@tonic-gate Word *lmtflags, uint_t env_flags, int aout) 1462*0Sstevel@tonic-gate { 1463*0Sstevel@tonic-gate u_longlong_t variable = 0; 1464*0Sstevel@tonic-gate unsigned short select = 0; 1465*0Sstevel@tonic-gate const char **str; 1466*0Sstevel@tonic-gate Word val = 0; 1467*0Sstevel@tonic-gate 1468*0Sstevel@tonic-gate /* 1469*0Sstevel@tonic-gate * Determine whether we're dealing with a replaceable or permanent 1470*0Sstevel@tonic-gate * string. 1471*0Sstevel@tonic-gate */ 1472*0Sstevel@tonic-gate if (env_flags & ENV_TYP_PERMANT) { 1473*0Sstevel@tonic-gate /* 1474*0Sstevel@tonic-gate * If the string is from a configuration file and defined as 1475*0Sstevel@tonic-gate * permanent, assign it as permanent. 1476*0Sstevel@tonic-gate */ 1477*0Sstevel@tonic-gate select |= SEL_PERMANT; 1478*0Sstevel@tonic-gate } else 1479*0Sstevel@tonic-gate select |= SEL_REPLACE; 1480*0Sstevel@tonic-gate 1481*0Sstevel@tonic-gate /* 1482*0Sstevel@tonic-gate * Parse the variable given. 1483*0Sstevel@tonic-gate * 1484*0Sstevel@tonic-gate * The LD_AUDIT family. 1485*0Sstevel@tonic-gate */ 1486*0Sstevel@tonic-gate if (*s1 == 'A') { 1487*0Sstevel@tonic-gate if ((len == MSG_LD_AUDIT_SIZE) && (strncmp(s1, 1488*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_AUDIT), MSG_LD_AUDIT_SIZE) == 0)) { 1489*0Sstevel@tonic-gate /* 1490*0Sstevel@tonic-gate * Replaceable and permanent audit objects can exist. 1491*0Sstevel@tonic-gate */ 1492*0Sstevel@tonic-gate select |= SEL_ACT_STR; 1493*0Sstevel@tonic-gate str = (select & SEL_REPLACE) ? &rpl_audit : &prm_audit; 1494*0Sstevel@tonic-gate variable = ENV_FLG_AUDIT; 1495*0Sstevel@tonic-gate } else if ((len == MSG_LD_AUDIT_ARGS_SIZE) && 1496*0Sstevel@tonic-gate (strncmp(s1, MSG_ORIG(MSG_LD_AUDIT_ARGS), 1497*0Sstevel@tonic-gate MSG_LD_AUDIT_ARGS_SIZE) == 0)) { 1498*0Sstevel@tonic-gate /* 1499*0Sstevel@tonic-gate * A specialized variable for plt_exit() use, not 1500*0Sstevel@tonic-gate * documented for general use. 1501*0Sstevel@tonic-gate */ 1502*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_2; 1503*0Sstevel@tonic-gate variable = ENV_FLG_AUDIT_ARGS; 1504*0Sstevel@tonic-gate } 1505*0Sstevel@tonic-gate } 1506*0Sstevel@tonic-gate /* 1507*0Sstevel@tonic-gate * The LD_BIND family and LD_BREADTH (historic). 1508*0Sstevel@tonic-gate */ 1509*0Sstevel@tonic-gate else if (*s1 == 'B') { 1510*0Sstevel@tonic-gate if ((len == MSG_LD_BIND_NOW_SIZE) && (strncmp(s1, 1511*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_BIND_NOW), MSG_LD_BIND_NOW_SIZE) == 0)) { 1512*0Sstevel@tonic-gate select |= SEL_ACT_RT2; 1513*0Sstevel@tonic-gate val = RT_FL2_BINDNOW; 1514*0Sstevel@tonic-gate variable = ENV_FLG_BIND_NOW; 1515*0Sstevel@tonic-gate } else if ((len == MSG_LD_BIND_NOT_SIZE) && (strncmp(s1, 1516*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_BIND_NOT), MSG_LD_BIND_NOT_SIZE) == 0)) { 1517*0Sstevel@tonic-gate /* 1518*0Sstevel@tonic-gate * Another trick, enabled to help debug AOUT 1519*0Sstevel@tonic-gate * applications under BCP, but not documented for 1520*0Sstevel@tonic-gate * general use. 1521*0Sstevel@tonic-gate */ 1522*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1523*0Sstevel@tonic-gate val = RT_FL_NOBIND; 1524*0Sstevel@tonic-gate variable = ENV_FLG_BIND_NOT; 1525*0Sstevel@tonic-gate } else if ((len == MSG_LD_BINDINGS_SIZE) && (strncmp(s1, 1526*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_BINDINGS), MSG_LD_BINDINGS_SIZE) == 0)) { 1527*0Sstevel@tonic-gate /* 1528*0Sstevel@tonic-gate * This variable is simply for backward compatibility. 1529*0Sstevel@tonic-gate * If this and LD_DEBUG are both specified, only one of 1530*0Sstevel@tonic-gate * the strings is going to get processed. 1531*0Sstevel@tonic-gate */ 1532*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_2; 1533*0Sstevel@tonic-gate variable = ENV_FLG_BINDINGS; 1534*0Sstevel@tonic-gate #ifndef LD_BREADTH_DISABLED 1535*0Sstevel@tonic-gate } else if ((len == MSG_LD_BREADTH_SIZE) && (strncmp(s1, 1536*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_BREADTH), MSG_LD_BREADTH_SIZE) == 0)) { 1537*0Sstevel@tonic-gate /* 1538*0Sstevel@tonic-gate * Besides some old patches this is no longer available. 1539*0Sstevel@tonic-gate */ 1540*0Sstevel@tonic-gate rtld_flags |= RT_FL_BREADTH; 1541*0Sstevel@tonic-gate return; 1542*0Sstevel@tonic-gate #endif 1543*0Sstevel@tonic-gate } 1544*0Sstevel@tonic-gate } 1545*0Sstevel@tonic-gate /* 1546*0Sstevel@tonic-gate * LD_CONCURRENCY and LD_CONFIG family. 1547*0Sstevel@tonic-gate */ 1548*0Sstevel@tonic-gate else if (*s1 == 'C') { 1549*0Sstevel@tonic-gate if ((len == MSG_LD_CONCURRENCY_SIZE) && (strncmp(s1, 1550*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_CONCURRENCY), 1551*0Sstevel@tonic-gate MSG_LD_CONCURRENCY_SIZE) == 0)) { 1552*0Sstevel@tonic-gate /* 1553*0Sstevel@tonic-gate * Waiting in the wings, as concurrency checking isn't 1554*0Sstevel@tonic-gate * yet enabled. 1555*0Sstevel@tonic-gate */ 1556*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_2; 1557*0Sstevel@tonic-gate variable = ENV_FLG_CONCURRENCY; 1558*0Sstevel@tonic-gate } else if ((len == MSG_LD_CONFGEN_SIZE) && (strncmp(s1, 1559*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_CONFGEN), MSG_LD_CONFGEN_SIZE) == 0)) { 1560*0Sstevel@tonic-gate /* 1561*0Sstevel@tonic-gate * Set by crle(1) to indicate it's building a 1562*0Sstevel@tonic-gate * configuration file, not documented for general use. 1563*0Sstevel@tonic-gate */ 1564*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_2; 1565*0Sstevel@tonic-gate variable = ENV_FLG_CONFGEN; 1566*0Sstevel@tonic-gate } else if ((len == MSG_LD_CONFIG_SIZE) && (strncmp(s1, 1567*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_CONFIG), MSG_LD_CONFIG_SIZE) == 0)) { 1568*0Sstevel@tonic-gate /* 1569*0Sstevel@tonic-gate * Secure applications must use a default configuration 1570*0Sstevel@tonic-gate * file. A setting from a configuration file doesn't 1571*0Sstevel@tonic-gate * make sense (given we must be reading a configuration 1572*0Sstevel@tonic-gate * file to have gotten this). 1573*0Sstevel@tonic-gate */ 1574*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_SECURE) || 1575*0Sstevel@tonic-gate (env_flags & ENV_TYP_CONFIG)) 1576*0Sstevel@tonic-gate return; 1577*0Sstevel@tonic-gate select |= SEL_ACT_STR; 1578*0Sstevel@tonic-gate str = &config->c_name; 1579*0Sstevel@tonic-gate variable = ENV_FLG_CONFIG; 1580*0Sstevel@tonic-gate } 1581*0Sstevel@tonic-gate } 1582*0Sstevel@tonic-gate /* 1583*0Sstevel@tonic-gate * The LD_DEBUG family and LD_DEMANGLE. 1584*0Sstevel@tonic-gate */ 1585*0Sstevel@tonic-gate else if (*s1 == 'D') { 1586*0Sstevel@tonic-gate if ((len == MSG_LD_DEBUG_SIZE) && (strncmp(s1, 1587*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_DEBUG), MSG_LD_DEBUG_SIZE) == 0)) { 1588*0Sstevel@tonic-gate select |= SEL_ACT_STR; 1589*0Sstevel@tonic-gate str = (select & SEL_REPLACE) ? &rpl_debug : &prm_debug; 1590*0Sstevel@tonic-gate variable = ENV_FLG_DEBUG; 1591*0Sstevel@tonic-gate } else if ((len == MSG_LD_DEBUG_OUTPUT_SIZE) && (strncmp(s1, 1592*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_DEBUG_OUTPUT), 1593*0Sstevel@tonic-gate MSG_LD_DEBUG_OUTPUT_SIZE) == 0)) { 1594*0Sstevel@tonic-gate select |= SEL_ACT_STR; 1595*0Sstevel@tonic-gate str = &dbg_file; 1596*0Sstevel@tonic-gate variable = ENV_FLG_DEBUG_OUTPUT; 1597*0Sstevel@tonic-gate } else if ((len == MSG_LD_DEMANGLE_SIZE) && (strncmp(s1, 1598*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_DEMANGLE), MSG_LD_DEMANGLE_SIZE) == 0)) { 1599*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1600*0Sstevel@tonic-gate val = RT_FL_DEMANGLE; 1601*0Sstevel@tonic-gate variable = ENV_FLG_DEMANGLE; 1602*0Sstevel@tonic-gate } 1603*0Sstevel@tonic-gate } 1604*0Sstevel@tonic-gate /* 1605*0Sstevel@tonic-gate * LD_FLAGS - collect the best variable definition. On completion of 1606*0Sstevel@tonic-gate * environment variable processing pass the result to ld_flags_env() 1607*0Sstevel@tonic-gate * where they'll be decomposed and passed back to this routine. 1608*0Sstevel@tonic-gate */ 1609*0Sstevel@tonic-gate else if (*s1 == 'F') { 1610*0Sstevel@tonic-gate if ((len == MSG_LD_FLAGS_SIZE) && (strncmp(s1, 1611*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_FLAGS), MSG_LD_FLAGS_SIZE) == 0)) { 1612*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_1; 1613*0Sstevel@tonic-gate str = 1614*0Sstevel@tonic-gate (select & SEL_REPLACE) ? &rpl_ldflags : &prm_ldflags; 1615*0Sstevel@tonic-gate variable = ENV_FLG_FLAGS; 1616*0Sstevel@tonic-gate } 1617*0Sstevel@tonic-gate } 1618*0Sstevel@tonic-gate /* 1619*0Sstevel@tonic-gate * LD_INIT (internal, used by ldd(1)). 1620*0Sstevel@tonic-gate */ 1621*0Sstevel@tonic-gate else if (*s1 == 'I') { 1622*0Sstevel@tonic-gate if ((len == MSG_LD_INIT_SIZE) && (strncmp(s1, 1623*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_INIT), MSG_LD_INIT_SIZE) == 0)) { 1624*0Sstevel@tonic-gate select |= SEL_ACT_LML; 1625*0Sstevel@tonic-gate val = LML_FLG_TRC_INIT; 1626*0Sstevel@tonic-gate variable = ENV_FLG_INIT; 1627*0Sstevel@tonic-gate } 1628*0Sstevel@tonic-gate } 1629*0Sstevel@tonic-gate /* 1630*0Sstevel@tonic-gate * The LD_LIBRARY_PATH and LD_LOAD families. 1631*0Sstevel@tonic-gate */ 1632*0Sstevel@tonic-gate else if (*s1 == 'L') { 1633*0Sstevel@tonic-gate if ((len == MSG_LD_LIBPATH_SIZE) && (strncmp(s1, 1634*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_LIBPATH), MSG_LD_LIBPATH_SIZE) == 0)) { 1635*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_1; 1636*0Sstevel@tonic-gate str = 1637*0Sstevel@tonic-gate (select & SEL_REPLACE) ? &rpl_libpath : &prm_libpath; 1638*0Sstevel@tonic-gate variable = ENV_FLG_LIBPATH; 1639*0Sstevel@tonic-gate } else if ((len == MSG_LD_LOADAVAIL_SIZE) && (strncmp(s1, 1640*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_LOADAVAIL), MSG_LD_LOADAVAIL_SIZE) == 0)) { 1641*0Sstevel@tonic-gate /* 1642*0Sstevel@tonic-gate * Internal use by crle(1), not documented for general 1643*0Sstevel@tonic-gate * use. 1644*0Sstevel@tonic-gate */ 1645*0Sstevel@tonic-gate select |= SEL_ACT_LML; 1646*0Sstevel@tonic-gate val = LML_FLG_LOADAVAIL; 1647*0Sstevel@tonic-gate variable = ENV_FLG_LOADAVAIL; 1648*0Sstevel@tonic-gate } else if ((len == MSG_LD_LOADFLTR_SIZE) && (strncmp(s1, 1649*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_LOADFLTR), MSG_LD_LOADFLTR_SIZE) == 0)) { 1650*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_2; 1651*0Sstevel@tonic-gate variable = ENV_FLG_LOADFLTR; 1652*0Sstevel@tonic-gate } 1653*0Sstevel@tonic-gate } 1654*0Sstevel@tonic-gate /* 1655*0Sstevel@tonic-gate * The LD_NO family. 1656*0Sstevel@tonic-gate */ 1657*0Sstevel@tonic-gate else if (*s1 == 'N') { 1658*0Sstevel@tonic-gate if ((len == MSG_LD_NOAUDIT_SIZE) && (strncmp(s1, 1659*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOAUDIT), MSG_LD_NOAUDIT_SIZE) == 0)) { 1660*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1661*0Sstevel@tonic-gate val = RT_FL_NOAUDIT; 1662*0Sstevel@tonic-gate variable = ENV_FLG_NOAUDIT; 1663*0Sstevel@tonic-gate } else if ((len == MSG_LD_NOAUXFLTR_SIZE) && (strncmp(s1, 1664*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOAUXFLTR), MSG_LD_NOAUXFLTR_SIZE) == 0)) { 1665*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1666*0Sstevel@tonic-gate val = RT_FL_NOAUXFLTR; 1667*0Sstevel@tonic-gate variable = ENV_FLG_NOAUXFLTR; 1668*0Sstevel@tonic-gate } else if ((len == MSG_LD_NOBAPLT_SIZE) && (strncmp(s1, 1669*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOBAPLT), MSG_LD_NOBAPLT_SIZE) == 0)) { 1670*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1671*0Sstevel@tonic-gate val = RT_FL_NOBAPLT; 1672*0Sstevel@tonic-gate variable = ENV_FLG_NOBAPLT; 1673*0Sstevel@tonic-gate } else if ((len == MSG_LD_NOCONFIG_SIZE) && (strncmp(s1, 1674*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOCONFIG), MSG_LD_NOCONFIG_SIZE) == 0)) { 1675*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1676*0Sstevel@tonic-gate val = RT_FL_NOCFG; 1677*0Sstevel@tonic-gate variable = ENV_FLG_NOCONFIG; 1678*0Sstevel@tonic-gate } else if ((len == MSG_LD_NODIRCONFIG_SIZE) && (strncmp(s1, 1679*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NODIRCONFIG), 1680*0Sstevel@tonic-gate MSG_LD_NODIRCONFIG_SIZE) == 0)) { 1681*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1682*0Sstevel@tonic-gate val = RT_FL_NODIRCFG; 1683*0Sstevel@tonic-gate variable = ENV_FLG_NODIRCONFIG; 1684*0Sstevel@tonic-gate } else if ((len == MSG_LD_NODIRECT_SIZE) && (strncmp(s1, 1685*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NODIRECT), MSG_LD_NODIRECT_SIZE) == 0)) { 1686*0Sstevel@tonic-gate select |= SEL_ACT_LMLT; 1687*0Sstevel@tonic-gate val = LML_TFLG_NODIRECT; 1688*0Sstevel@tonic-gate variable = ENV_FLG_NODIRECT; 1689*0Sstevel@tonic-gate } else if ((len == MSG_LD_NOENVCONFIG_SIZE) && (strncmp(s1, 1690*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOENVCONFIG), 1691*0Sstevel@tonic-gate MSG_LD_NOENVCONFIG_SIZE) == 0)) { 1692*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1693*0Sstevel@tonic-gate val = RT_FL_NOENVCFG; 1694*0Sstevel@tonic-gate variable = ENV_FLG_NOENVCONFIG; 1695*0Sstevel@tonic-gate } else if ((len == MSG_LD_NOFLTCONFIG_SIZE) && (strncmp(s1, 1696*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOFLTCONFIG), 1697*0Sstevel@tonic-gate MSG_LD_NOFLTCONFIG_SIZE) == 0)) { 1698*0Sstevel@tonic-gate select |= SEL_ACT_RT2; 1699*0Sstevel@tonic-gate val = RT_FL2_NOFLTCFG; 1700*0Sstevel@tonic-gate variable = ENV_FLG_NOFLTCONFIG; 1701*0Sstevel@tonic-gate } else if ((len == MSG_LD_NOLAZY_SIZE) && (strncmp(s1, 1702*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOLAZY), MSG_LD_NOLAZY_SIZE) == 0)) { 1703*0Sstevel@tonic-gate select |= SEL_ACT_LMLT; 1704*0Sstevel@tonic-gate val = LML_TFLG_NOLAZYLD; 1705*0Sstevel@tonic-gate variable = ENV_FLG_NOLAZY; 1706*0Sstevel@tonic-gate } else if ((len == MSG_LD_NOOBJALTER_SIZE) && (strncmp(s1, 1707*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOOBJALTER), 1708*0Sstevel@tonic-gate MSG_LD_NOOBJALTER_SIZE) == 0)) { 1709*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1710*0Sstevel@tonic-gate val = RT_FL_NOOBJALT; 1711*0Sstevel@tonic-gate variable = ENV_FLG_NOOBJALTER; 1712*0Sstevel@tonic-gate } else if ((len == MSG_LD_NOVERSION_SIZE) && (strncmp(s1, 1713*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_NOVERSION), MSG_LD_NOVERSION_SIZE) == 0)) { 1714*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1715*0Sstevel@tonic-gate val = RT_FL_NOVERSION; 1716*0Sstevel@tonic-gate variable = ENV_FLG_NOVERSION; 1717*0Sstevel@tonic-gate } 1718*0Sstevel@tonic-gate } 1719*0Sstevel@tonic-gate /* 1720*0Sstevel@tonic-gate * LD_ORIGIN. 1721*0Sstevel@tonic-gate */ 1722*0Sstevel@tonic-gate else if (*s1 == 'O') { 1723*0Sstevel@tonic-gate #ifndef EXPAND_RELATIVE 1724*0Sstevel@tonic-gate if ((len == MSG_LD_ORIGIN_SIZE) && (strncmp(s1, 1725*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_ORIGIN), MSG_LD_ORIGIN_SIZE) == 0)) { 1726*0Sstevel@tonic-gate /* 1727*0Sstevel@tonic-gate * Besides some old patches this is no longer required. 1728*0Sstevel@tonic-gate */ 1729*0Sstevel@tonic-gate rtld_flags |= RT_FL_RELATIVE; 1730*0Sstevel@tonic-gate } 1731*0Sstevel@tonic-gate #endif 1732*0Sstevel@tonic-gate return; 1733*0Sstevel@tonic-gate } 1734*0Sstevel@tonic-gate /* 1735*0Sstevel@tonic-gate * LD_PRELOAD and LD_PROFILE family. 1736*0Sstevel@tonic-gate */ 1737*0Sstevel@tonic-gate else if (*s1 == 'P') { 1738*0Sstevel@tonic-gate if ((len == MSG_LD_PRELOAD_SIZE) && (strncmp(s1, 1739*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_PRELOAD), MSG_LD_PRELOAD_SIZE) == 0)) { 1740*0Sstevel@tonic-gate select |= SEL_ACT_STR; 1741*0Sstevel@tonic-gate str = 1742*0Sstevel@tonic-gate (select & SEL_REPLACE) ? &rpl_preload : &prm_preload; 1743*0Sstevel@tonic-gate variable = ENV_FLG_PRELOAD; 1744*0Sstevel@tonic-gate } else if ((len == MSG_LD_PROFILE_SIZE) && (strncmp(s1, 1745*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_PROFILE), MSG_LD_PROFILE_SIZE) == 0)) { 1746*0Sstevel@tonic-gate /* 1747*0Sstevel@tonic-gate * Only one user library can be profiled at a time. 1748*0Sstevel@tonic-gate */ 1749*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_2; 1750*0Sstevel@tonic-gate variable = ENV_FLG_PROFILE; 1751*0Sstevel@tonic-gate } else if ((len == MSG_LD_PROFILE_OUTPUT_SIZE) && (strncmp(s1, 1752*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_PROFILE_OUTPUT), 1753*0Sstevel@tonic-gate MSG_LD_PROFILE_OUTPUT_SIZE) == 0)) { 1754*0Sstevel@tonic-gate /* 1755*0Sstevel@tonic-gate * Only one user library can be profiled at a time. 1756*0Sstevel@tonic-gate */ 1757*0Sstevel@tonic-gate select |= SEL_ACT_STR; 1758*0Sstevel@tonic-gate str = &profile_out; 1759*0Sstevel@tonic-gate variable = ENV_FLG_PROFILE_OUTPUT; 1760*0Sstevel@tonic-gate } 1761*0Sstevel@tonic-gate } 1762*0Sstevel@tonic-gate /* 1763*0Sstevel@tonic-gate * LD_SIGNAL. 1764*0Sstevel@tonic-gate */ 1765*0Sstevel@tonic-gate else if (*s1 == 'S') { 1766*0Sstevel@tonic-gate if (rtld_flags & RT_FL_SECURE) 1767*0Sstevel@tonic-gate return; 1768*0Sstevel@tonic-gate if ((len == MSG_LD_SIGNAL_SIZE) && 1769*0Sstevel@tonic-gate (strncmp(s1, MSG_ORIG(MSG_LD_SIGNAL), 1770*0Sstevel@tonic-gate MSG_LD_SIGNAL_SIZE) == 0)) { 1771*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_2; 1772*0Sstevel@tonic-gate variable = ENV_FLG_SIGNAL; 1773*0Sstevel@tonic-gate } 1774*0Sstevel@tonic-gate } 1775*0Sstevel@tonic-gate /* 1776*0Sstevel@tonic-gate * The LD_TRACE family (internal, used by ldd(1)). 1777*0Sstevel@tonic-gate */ 1778*0Sstevel@tonic-gate else if (*s1 == 'T') { 1779*0Sstevel@tonic-gate if (((len == MSG_LD_TRACE_OBJS_SIZE) && 1780*0Sstevel@tonic-gate (strncmp(s1, MSG_ORIG(MSG_LD_TRACE_OBJS), 1781*0Sstevel@tonic-gate MSG_LD_TRACE_OBJS_SIZE) == 0)) || 1782*0Sstevel@tonic-gate ((len == MSG_LD_TRACE_OBJS_E_SIZE) && 1783*0Sstevel@tonic-gate (((strncmp(s1, MSG_ORIG(MSG_LD_TRACE_OBJS_E), 1784*0Sstevel@tonic-gate MSG_LD_TRACE_OBJS_E_SIZE) == 0) && !aout) || 1785*0Sstevel@tonic-gate ((strncmp(s1, MSG_ORIG(MSG_LD_TRACE_OBJS_A), 1786*0Sstevel@tonic-gate MSG_LD_TRACE_OBJS_A_SIZE) == 0) && aout)))) { 1787*0Sstevel@tonic-gate select |= SEL_ACT_SPEC_2; 1788*0Sstevel@tonic-gate variable = ENV_FLG_TRACE_OBJS; 1789*0Sstevel@tonic-gate } else if ((len == MSG_LD_TRACE_PTHS_SIZE) && (strncmp(s1, 1790*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_TRACE_PTHS), 1791*0Sstevel@tonic-gate MSG_LD_TRACE_PTHS_SIZE) == 0)) { 1792*0Sstevel@tonic-gate select |= SEL_ACT_LML; 1793*0Sstevel@tonic-gate val = LML_FLG_TRC_SEARCH; 1794*0Sstevel@tonic-gate variable = ENV_FLG_TRACE_PTHS; 1795*0Sstevel@tonic-gate } 1796*0Sstevel@tonic-gate } 1797*0Sstevel@tonic-gate /* 1798*0Sstevel@tonic-gate * LD_UNREF and LD_UNUSED (internal, used by ldd(1)). 1799*0Sstevel@tonic-gate */ 1800*0Sstevel@tonic-gate else if (*s1 == 'U') { 1801*0Sstevel@tonic-gate if ((len == MSG_LD_UNREF_SIZE) && (strncmp(s1, 1802*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_UNREF), MSG_LD_UNREF_SIZE) == 0)) { 1803*0Sstevel@tonic-gate select |= SEL_ACT_LML; 1804*0Sstevel@tonic-gate val = LML_FLG_TRC_UNREF; 1805*0Sstevel@tonic-gate variable = ENV_FLG_UNREF; 1806*0Sstevel@tonic-gate } else if ((len == MSG_LD_UNUSED_SIZE) && (strncmp(s1, 1807*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_UNUSED), MSG_LD_UNUSED_SIZE) == 0)) { 1808*0Sstevel@tonic-gate select |= SEL_ACT_LML; 1809*0Sstevel@tonic-gate val = LML_FLG_TRC_UNUSED; 1810*0Sstevel@tonic-gate variable = ENV_FLG_UNUSED; 1811*0Sstevel@tonic-gate } 1812*0Sstevel@tonic-gate } 1813*0Sstevel@tonic-gate /* 1814*0Sstevel@tonic-gate * LD_VERBOSE (internal, used by ldd(1)). 1815*0Sstevel@tonic-gate */ 1816*0Sstevel@tonic-gate else if (*s1 == 'V') { 1817*0Sstevel@tonic-gate if ((len == MSG_LD_VERBOSE_SIZE) && (strncmp(s1, 1818*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_VERBOSE), MSG_LD_VERBOSE_SIZE) == 0)) { 1819*0Sstevel@tonic-gate select |= SEL_ACT_LML; 1820*0Sstevel@tonic-gate val = LML_FLG_TRC_VERBOSE; 1821*0Sstevel@tonic-gate variable = ENV_FLG_VERBOSE; 1822*0Sstevel@tonic-gate } 1823*0Sstevel@tonic-gate } 1824*0Sstevel@tonic-gate /* 1825*0Sstevel@tonic-gate * LD_WARN (internal, used by ldd(1)). 1826*0Sstevel@tonic-gate */ 1827*0Sstevel@tonic-gate else if (*s1 == 'W') { 1828*0Sstevel@tonic-gate if ((len == MSG_LD_WARN_SIZE) && (strncmp(s1, 1829*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_WARN), MSG_LD_WARN_SIZE) == 0)) { 1830*0Sstevel@tonic-gate select |= SEL_ACT_LML; 1831*0Sstevel@tonic-gate val = LML_FLG_TRC_WARN; 1832*0Sstevel@tonic-gate variable = ENV_FLG_WARN; 1833*0Sstevel@tonic-gate } 1834*0Sstevel@tonic-gate #ifdef SIEBEL_DISABLE 1835*0Sstevel@tonic-gate } 1836*0Sstevel@tonic-gate /* 1837*0Sstevel@tonic-gate * LD__FIX__ (undocumented, enable future technology that can't be 1838*0Sstevel@tonic-gate * delivered in a patch release). 1839*0Sstevel@tonic-gate */ 1840*0Sstevel@tonic-gate else if (*s1 == '_') { 1841*0Sstevel@tonic-gate if ((len == MSG_LD_FIX_1_SIZE) && (strncmp(s1, 1842*0Sstevel@tonic-gate MSG_ORIG(MSG_LD_FIX_1), MSG_LD_FIX_1_SIZE) == 0)) { 1843*0Sstevel@tonic-gate select |= SEL_ACT_RT; 1844*0Sstevel@tonic-gate val = RT_FL_DISFIX_1; 1845*0Sstevel@tonic-gate variable = ENV_FLG_FIX_1; 1846*0Sstevel@tonic-gate } 1847*0Sstevel@tonic-gate #endif 1848*0Sstevel@tonic-gate } 1849*0Sstevel@tonic-gate if (variable == 0) 1850*0Sstevel@tonic-gate return; 1851*0Sstevel@tonic-gate 1852*0Sstevel@tonic-gate /* 1853*0Sstevel@tonic-gate * If the variable is already processed with ISA specific variable, 1854*0Sstevel@tonic-gate * no further processing needed. 1855*0Sstevel@tonic-gate */ 1856*0Sstevel@tonic-gate if (((select & SEL_REPLACE) && (rplisa & variable)) || 1857*0Sstevel@tonic-gate ((select & SEL_PERMANT) && (prmisa & variable))) 1858*0Sstevel@tonic-gate return; 1859*0Sstevel@tonic-gate 1860*0Sstevel@tonic-gate /* 1861*0Sstevel@tonic-gate * Now mark the appropriate variables 1862*0Sstevel@tonic-gate */ 1863*0Sstevel@tonic-gate if (env_flags & ENV_TYP_ISA) { 1864*0Sstevel@tonic-gate /* 1865*0Sstevel@tonic-gate * This is ISA setting. We do the setting 1866*0Sstevel@tonic-gate * even if s2 is NULL. 1867*0Sstevel@tonic-gate * If s2 is NULL, we might need to undo 1868*0Sstevel@tonic-gate * the setting. 1869*0Sstevel@tonic-gate */ 1870*0Sstevel@tonic-gate if (select & SEL_REPLACE) { 1871*0Sstevel@tonic-gate rplisa |= variable; 1872*0Sstevel@tonic-gate } else { 1873*0Sstevel@tonic-gate prmisa |= variable; 1874*0Sstevel@tonic-gate } 1875*0Sstevel@tonic-gate } else if (s2) { 1876*0Sstevel@tonic-gate /* 1877*0Sstevel@tonic-gate * This is non0-ISA setting 1878*0Sstevel@tonic-gate */ 1879*0Sstevel@tonic-gate if (select & SEL_REPLACE) { 1880*0Sstevel@tonic-gate rplgen |= variable; 1881*0Sstevel@tonic-gate } else 1882*0Sstevel@tonic-gate prmgen |= variable; 1883*0Sstevel@tonic-gate } else 1884*0Sstevel@tonic-gate /* 1885*0Sstevel@tonic-gate * This is non-ISA setting which 1886*0Sstevel@tonic-gate * can be ignored. 1887*0Sstevel@tonic-gate */ 1888*0Sstevel@tonic-gate return; 1889*0Sstevel@tonic-gate 1890*0Sstevel@tonic-gate /* 1891*0Sstevel@tonic-gate * Now perform the setting. 1892*0Sstevel@tonic-gate */ 1893*0Sstevel@tonic-gate if (select & SEL_ACT_RT) { 1894*0Sstevel@tonic-gate if (s2) 1895*0Sstevel@tonic-gate rtld_flags |= val; 1896*0Sstevel@tonic-gate else 1897*0Sstevel@tonic-gate rtld_flags &= ~val; 1898*0Sstevel@tonic-gate } else if (select & SEL_ACT_RT2) { 1899*0Sstevel@tonic-gate if (s2) 1900*0Sstevel@tonic-gate rtld_flags2 |= val; 1901*0Sstevel@tonic-gate else 1902*0Sstevel@tonic-gate rtld_flags2 &= ~val; 1903*0Sstevel@tonic-gate } else if (select & SEL_ACT_STR) 1904*0Sstevel@tonic-gate *str = s2; 1905*0Sstevel@tonic-gate else if (select & SEL_ACT_LML) { 1906*0Sstevel@tonic-gate if (s2) 1907*0Sstevel@tonic-gate *lmflags |= val; 1908*0Sstevel@tonic-gate else 1909*0Sstevel@tonic-gate *lmflags &= ~val; 1910*0Sstevel@tonic-gate } else if (select & SEL_ACT_LMLT) { 1911*0Sstevel@tonic-gate if (s2) 1912*0Sstevel@tonic-gate *lmtflags |= val; 1913*0Sstevel@tonic-gate else 1914*0Sstevel@tonic-gate *lmtflags &= ~val; 1915*0Sstevel@tonic-gate } else if (select & SEL_ACT_SPEC_1) { 1916*0Sstevel@tonic-gate /* 1917*0Sstevel@tonic-gate * variable is either ENV_FLG_FLAGS or ENV_FLG_LIBPATH 1918*0Sstevel@tonic-gate */ 1919*0Sstevel@tonic-gate *str = s2; 1920*0Sstevel@tonic-gate if ((select & SEL_REPLACE) && (env_flags & ENV_TYP_CONFIG)) { 1921*0Sstevel@tonic-gate if (s2) { 1922*0Sstevel@tonic-gate if (variable == ENV_FLG_FLAGS) 1923*0Sstevel@tonic-gate env_info |= ENV_INF_FLAGCFG; 1924*0Sstevel@tonic-gate else 1925*0Sstevel@tonic-gate env_info |= ENV_INF_PATHCFG; 1926*0Sstevel@tonic-gate } else { 1927*0Sstevel@tonic-gate if (variable == ENV_FLG_FLAGS) 1928*0Sstevel@tonic-gate env_info &= ~ENV_INF_FLAGCFG; 1929*0Sstevel@tonic-gate else 1930*0Sstevel@tonic-gate env_info &= ~ENV_INF_PATHCFG; 1931*0Sstevel@tonic-gate } 1932*0Sstevel@tonic-gate } 1933*0Sstevel@tonic-gate } else if (select & SEL_ACT_SPEC_2) { 1934*0Sstevel@tonic-gate /* 1935*0Sstevel@tonic-gate * variables can be: ENV_FLG_ 1936*0Sstevel@tonic-gate * AUDIT_ARGS, BINDING, CONCURRENCY, CONFGEN, 1937*0Sstevel@tonic-gate * LOADFLTR, PROFILE, SIGNAL, TRACE_OBJS 1938*0Sstevel@tonic-gate */ 1939*0Sstevel@tonic-gate if (variable == ENV_FLG_AUDIT_ARGS) { 1940*0Sstevel@tonic-gate if (s2) { 1941*0Sstevel@tonic-gate audit_argcnt = atoi(s2); 1942*0Sstevel@tonic-gate audit_argcnt += audit_argcnt % 2; 1943*0Sstevel@tonic-gate } else 1944*0Sstevel@tonic-gate audit_argcnt = 0; 1945*0Sstevel@tonic-gate } else if (variable == ENV_FLG_BINDINGS) { 1946*0Sstevel@tonic-gate if (s2) 1947*0Sstevel@tonic-gate rpl_debug = MSG_ORIG(MSG_TKN_BINDINGS); 1948*0Sstevel@tonic-gate else 1949*0Sstevel@tonic-gate rpl_debug = 0; 1950*0Sstevel@tonic-gate } else if (variable == ENV_FLG_CONCURRENCY) { 1951*0Sstevel@tonic-gate if (s2) 1952*0Sstevel@tonic-gate rtld_flags &= ~RT_FL_NOCONCUR; 1953*0Sstevel@tonic-gate else 1954*0Sstevel@tonic-gate rtld_flags |= RT_FL_NOCONCUR; 1955*0Sstevel@tonic-gate } else if (variable == ENV_FLG_CONFGEN) { 1956*0Sstevel@tonic-gate if (s2) { 1957*0Sstevel@tonic-gate rtld_flags |= RT_FL_CONFGEN; 1958*0Sstevel@tonic-gate *lmflags |= LML_FLG_IGNRELERR; 1959*0Sstevel@tonic-gate } else { 1960*0Sstevel@tonic-gate rtld_flags &= ~RT_FL_CONFGEN; 1961*0Sstevel@tonic-gate *lmflags &= ~LML_FLG_IGNRELERR; 1962*0Sstevel@tonic-gate } 1963*0Sstevel@tonic-gate } else if (variable == ENV_FLG_LOADFLTR) { 1964*0Sstevel@tonic-gate if (s2) { 1965*0Sstevel@tonic-gate *lmtflags |= LML_TFLG_LOADFLTR; 1966*0Sstevel@tonic-gate if (*s2 == '2') 1967*0Sstevel@tonic-gate rtld_flags |= RT_FL_WARNFLTR; 1968*0Sstevel@tonic-gate } else { 1969*0Sstevel@tonic-gate *lmtflags &= ~LML_TFLG_LOADFLTR; 1970*0Sstevel@tonic-gate rtld_flags &= ~RT_FL_WARNFLTR; 1971*0Sstevel@tonic-gate } 1972*0Sstevel@tonic-gate } else if (variable == ENV_FLG_PROFILE) { 1973*0Sstevel@tonic-gate profile_name = s2; 1974*0Sstevel@tonic-gate if (s2) { 1975*0Sstevel@tonic-gate if (strcmp(s2, MSG_ORIG(MSG_FIL_RTLD)) == 0) { 1976*0Sstevel@tonic-gate return; 1977*0Sstevel@tonic-gate } 1978*0Sstevel@tonic-gate if (rtld_flags & RT_FL_SECURE) { 1979*0Sstevel@tonic-gate profile_lib = 1980*0Sstevel@tonic-gate #if defined(_ELF64) 1981*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_LDPROFSE_64); 1982*0Sstevel@tonic-gate #else 1983*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_LDPROFSE); 1984*0Sstevel@tonic-gate #endif 1985*0Sstevel@tonic-gate } else { 1986*0Sstevel@tonic-gate profile_lib = 1987*0Sstevel@tonic-gate #if defined(_ELF64) 1988*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_LDPROF_64); 1989*0Sstevel@tonic-gate #else 1990*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_LDPROF); 1991*0Sstevel@tonic-gate #endif 1992*0Sstevel@tonic-gate } 1993*0Sstevel@tonic-gate } else 1994*0Sstevel@tonic-gate profile_lib = 0; 1995*0Sstevel@tonic-gate } else if (variable == ENV_FLG_SIGNAL) { 1996*0Sstevel@tonic-gate killsig = s2 ? atoi(s2) : SIGKILL; 1997*0Sstevel@tonic-gate } else if (variable == ENV_FLG_TRACE_OBJS) { 1998*0Sstevel@tonic-gate if (s2) { 1999*0Sstevel@tonic-gate *lmflags |= LML_FLG_TRC_ENABLE; 2000*0Sstevel@tonic-gate if (*s2 == '2') 2001*0Sstevel@tonic-gate *lmflags |= LML_FLG_TRC_LDDSTUB; 2002*0Sstevel@tonic-gate } else 2003*0Sstevel@tonic-gate *lmflags &= 2004*0Sstevel@tonic-gate ~(LML_FLG_TRC_ENABLE|LML_FLG_TRC_LDDSTUB); 2005*0Sstevel@tonic-gate } 2006*0Sstevel@tonic-gate } 2007*0Sstevel@tonic-gate } 2008*0Sstevel@tonic-gate 2009*0Sstevel@tonic-gate /* 2010*0Sstevel@tonic-gate * Determine whether we have an architecture specific environment variable. 2011*0Sstevel@tonic-gate * If we do, and we're the wrong architecture, it'll just get ignored. 2012*0Sstevel@tonic-gate * Otherwise the variable is processed in it's architecture neutral form. 2013*0Sstevel@tonic-gate */ 2014*0Sstevel@tonic-gate static int 2015*0Sstevel@tonic-gate ld_arch_env(const char *s1, size_t *len) 2016*0Sstevel@tonic-gate { 2017*0Sstevel@tonic-gate size_t _len = *len - 3; 2018*0Sstevel@tonic-gate 2019*0Sstevel@tonic-gate if (s1[_len++] == '_') { 2020*0Sstevel@tonic-gate if ((s1[_len] == '3') && (s1[_len + 1] == '2')) { 2021*0Sstevel@tonic-gate #if defined(_ELF64) 2022*0Sstevel@tonic-gate return (ENV_TYP_IGNORE); 2023*0Sstevel@tonic-gate #else 2024*0Sstevel@tonic-gate *len = *len - 3; 2025*0Sstevel@tonic-gate return (ENV_TYP_ISA); 2026*0Sstevel@tonic-gate #endif 2027*0Sstevel@tonic-gate } 2028*0Sstevel@tonic-gate if ((s1[_len] == '6') && (s1[_len + 1] == '4')) { 2029*0Sstevel@tonic-gate #if defined(_ELF64) 2030*0Sstevel@tonic-gate *len = *len - 3; 2031*0Sstevel@tonic-gate return (ENV_TYP_ISA); 2032*0Sstevel@tonic-gate #else 2033*0Sstevel@tonic-gate return (ENV_TYP_IGNORE); 2034*0Sstevel@tonic-gate #endif 2035*0Sstevel@tonic-gate } 2036*0Sstevel@tonic-gate } 2037*0Sstevel@tonic-gate return (0); 2038*0Sstevel@tonic-gate } 2039*0Sstevel@tonic-gate 2040*0Sstevel@tonic-gate 2041*0Sstevel@tonic-gate /* 2042*0Sstevel@tonic-gate * Process an LD_FLAGS environment variable. The value can be a comma 2043*0Sstevel@tonic-gate * separated set of tokens, which are sent (in upper case) into the generic 2044*0Sstevel@tonic-gate * LD_XXXX environment variable engine. For example: 2045*0Sstevel@tonic-gate * 2046*0Sstevel@tonic-gate * LD_FLAGS=bind_now -> LD_BIND_NOW=1 2047*0Sstevel@tonic-gate * LD_FLAGS=library_path=/foo:. -> LD_LIBRARY_PATH=/foo:. 2048*0Sstevel@tonic-gate * LD_FLAGS=debug=files:detail -> LD_DEBUG=files:detail 2049*0Sstevel@tonic-gate * or 2050*0Sstevel@tonic-gate * LD_FLAGS=bind_now,library_path=/foo:.,debug=files:detail 2051*0Sstevel@tonic-gate */ 2052*0Sstevel@tonic-gate static int 2053*0Sstevel@tonic-gate ld_flags_env(const char *str, Word *lmflags, Word *lmtflags, 2054*0Sstevel@tonic-gate uint_t env_flags, int aout) 2055*0Sstevel@tonic-gate { 2056*0Sstevel@tonic-gate char *nstr, *sstr, *estr = 0; 2057*0Sstevel@tonic-gate size_t nlen, len; 2058*0Sstevel@tonic-gate 2059*0Sstevel@tonic-gate if (str == 0) 2060*0Sstevel@tonic-gate return (0); 2061*0Sstevel@tonic-gate 2062*0Sstevel@tonic-gate /* 2063*0Sstevel@tonic-gate * Create a new string as we're going to transform the token(s) into 2064*0Sstevel@tonic-gate * uppercase and separate tokens with nulls. 2065*0Sstevel@tonic-gate */ 2066*0Sstevel@tonic-gate len = strlen(str); 2067*0Sstevel@tonic-gate if ((nstr = malloc(len + 1)) == 0) 2068*0Sstevel@tonic-gate return (1); 2069*0Sstevel@tonic-gate (void) strcpy(nstr, str); 2070*0Sstevel@tonic-gate 2071*0Sstevel@tonic-gate for (sstr = nstr; sstr; sstr++, len--) { 2072*0Sstevel@tonic-gate int flags; 2073*0Sstevel@tonic-gate 2074*0Sstevel@tonic-gate if ((*sstr != '\0') && (*sstr != ',')) { 2075*0Sstevel@tonic-gate if (estr == 0) { 2076*0Sstevel@tonic-gate if (*sstr == '=') 2077*0Sstevel@tonic-gate estr = sstr; 2078*0Sstevel@tonic-gate else { 2079*0Sstevel@tonic-gate /* 2080*0Sstevel@tonic-gate * Translate token to uppercase. Don't 2081*0Sstevel@tonic-gate * use toupper(3C) as including this 2082*0Sstevel@tonic-gate * code doubles the size of ld.so.1. 2083*0Sstevel@tonic-gate */ 2084*0Sstevel@tonic-gate if ((*sstr >= 'a') && (*sstr <= 'z')) 2085*0Sstevel@tonic-gate *sstr = *sstr - ('a' - 'A'); 2086*0Sstevel@tonic-gate } 2087*0Sstevel@tonic-gate } 2088*0Sstevel@tonic-gate continue; 2089*0Sstevel@tonic-gate } 2090*0Sstevel@tonic-gate 2091*0Sstevel@tonic-gate *sstr = '\0'; 2092*0Sstevel@tonic-gate if (estr) { 2093*0Sstevel@tonic-gate nlen = estr - nstr; 2094*0Sstevel@tonic-gate if ((*++estr == '\0') || (*estr == ',')) 2095*0Sstevel@tonic-gate estr = 0; 2096*0Sstevel@tonic-gate } else 2097*0Sstevel@tonic-gate nlen = sstr - nstr; 2098*0Sstevel@tonic-gate 2099*0Sstevel@tonic-gate /* 2100*0Sstevel@tonic-gate * Fabricate a boolean definition for any unqualified variable. 2101*0Sstevel@tonic-gate * Thus LD_FLAGS=bind_now is represented as BIND_NOW=(null). 2102*0Sstevel@tonic-gate * The value is sufficient to assert any boolean variables, plus 2103*0Sstevel@tonic-gate * the term "(null)" is specifically chosen in case someone 2104*0Sstevel@tonic-gate * mistakenly supplies something like LD_FLAGS=library_path. 2105*0Sstevel@tonic-gate */ 2106*0Sstevel@tonic-gate if (estr == 0) 2107*0Sstevel@tonic-gate estr = (char *)MSG_INTL(MSG_STR_NULL); 2108*0Sstevel@tonic-gate 2109*0Sstevel@tonic-gate /* 2110*0Sstevel@tonic-gate * Determine whether the environment variable is 32- or 64-bit 2111*0Sstevel@tonic-gate * specific. The length, len, will reflect the architecture 2112*0Sstevel@tonic-gate * neutral portion of the string. 2113*0Sstevel@tonic-gate */ 2114*0Sstevel@tonic-gate if ((flags = ld_arch_env(nstr, &nlen)) != ENV_TYP_IGNORE) { 2115*0Sstevel@tonic-gate ld_generic_env(nstr, nlen, estr, lmflags, 2116*0Sstevel@tonic-gate lmtflags, (env_flags | flags), aout); 2117*0Sstevel@tonic-gate } 2118*0Sstevel@tonic-gate if (len == 0) 2119*0Sstevel@tonic-gate return (0); 2120*0Sstevel@tonic-gate 2121*0Sstevel@tonic-gate nstr = sstr + 1; 2122*0Sstevel@tonic-gate estr = 0; 2123*0Sstevel@tonic-gate } 2124*0Sstevel@tonic-gate return (0); 2125*0Sstevel@tonic-gate } 2126*0Sstevel@tonic-gate 2127*0Sstevel@tonic-gate 2128*0Sstevel@tonic-gate /* 2129*0Sstevel@tonic-gate * Process a single environment string. Only strings starting with `LD_' are 2130*0Sstevel@tonic-gate * reserved for our use. By convention, all strings should be of the form 2131*0Sstevel@tonic-gate * `LD_XXXX=', if the string is followed by a non-null value the appropriate 2132*0Sstevel@tonic-gate * functionality is enabled. Also pick off applicable locale variables. 2133*0Sstevel@tonic-gate */ 2134*0Sstevel@tonic-gate #define LOC_LANG 1 2135*0Sstevel@tonic-gate #define LOC_MESG 2 2136*0Sstevel@tonic-gate #define LOC_ALL 3 2137*0Sstevel@tonic-gate 2138*0Sstevel@tonic-gate static void 2139*0Sstevel@tonic-gate ld_str_env(const char *s1, Word *lmflags, Word *lmtflags, uint_t env_flags, 2140*0Sstevel@tonic-gate int aout) 2141*0Sstevel@tonic-gate { 2142*0Sstevel@tonic-gate const char *s2; 2143*0Sstevel@tonic-gate size_t loc = 0; 2144*0Sstevel@tonic-gate 2145*0Sstevel@tonic-gate if (*s1++ != 'L') 2146*0Sstevel@tonic-gate return; 2147*0Sstevel@tonic-gate 2148*0Sstevel@tonic-gate /* 2149*0Sstevel@tonic-gate * See if we have any locale environment settings. These environment 2150*0Sstevel@tonic-gate * variables have a precedence, LC_ALL is higher than LC_MESSAGES which 2151*0Sstevel@tonic-gate * is higher than LANG. 2152*0Sstevel@tonic-gate */ 2153*0Sstevel@tonic-gate s2 = s1; 2154*0Sstevel@tonic-gate if ((*s2++ == 'C') && (*s2++ == '_') && (*s2 != '\0')) { 2155*0Sstevel@tonic-gate if (strncmp(s2, MSG_ORIG(MSG_LC_ALL), MSG_LC_ALL_SIZE) == 0) { 2156*0Sstevel@tonic-gate s2 += MSG_LC_ALL_SIZE; 2157*0Sstevel@tonic-gate if ((*s2 != '\0') && (loc < LOC_ALL)) { 2158*0Sstevel@tonic-gate locale = s2; 2159*0Sstevel@tonic-gate loc = LOC_ALL; 2160*0Sstevel@tonic-gate } 2161*0Sstevel@tonic-gate } else if (strncmp(s2, MSG_ORIG(MSG_LC_MESSAGES), 2162*0Sstevel@tonic-gate MSG_LC_MESSAGES_SIZE) == 0) { 2163*0Sstevel@tonic-gate s2 += MSG_LC_MESSAGES_SIZE; 2164*0Sstevel@tonic-gate if ((*s2 != '\0') && (loc < LOC_MESG)) { 2165*0Sstevel@tonic-gate locale = s2; 2166*0Sstevel@tonic-gate loc = LOC_MESG; 2167*0Sstevel@tonic-gate } 2168*0Sstevel@tonic-gate } 2169*0Sstevel@tonic-gate return; 2170*0Sstevel@tonic-gate } 2171*0Sstevel@tonic-gate 2172*0Sstevel@tonic-gate s2 = s1; 2173*0Sstevel@tonic-gate if ((*s2++ == 'A') && (*s2++ == 'N') && (*s2++ == 'G') && 2174*0Sstevel@tonic-gate (*s2++ == '=') && (*s2 != '\0') && (loc < LOC_LANG)) { 2175*0Sstevel@tonic-gate locale = s2; 2176*0Sstevel@tonic-gate loc = LOC_LANG; 2177*0Sstevel@tonic-gate return; 2178*0Sstevel@tonic-gate } 2179*0Sstevel@tonic-gate 2180*0Sstevel@tonic-gate /* 2181*0Sstevel@tonic-gate * Pick off any LD_XXXX environment variables. 2182*0Sstevel@tonic-gate */ 2183*0Sstevel@tonic-gate if ((*s1++ == 'D') && (*s1++ == '_') && (*s1 != '\0')) { 2184*0Sstevel@tonic-gate size_t len; 2185*0Sstevel@tonic-gate int flags; 2186*0Sstevel@tonic-gate 2187*0Sstevel@tonic-gate /* 2188*0Sstevel@tonic-gate * Environment variables with no value (ie. LD_XXXX=) typically 2189*0Sstevel@tonic-gate * have no impact, however if environment variables are defined 2190*0Sstevel@tonic-gate * within a configuration file, these null user settings can be 2191*0Sstevel@tonic-gate * used to disable any configuration replaceable definitions. 2192*0Sstevel@tonic-gate */ 2193*0Sstevel@tonic-gate if ((s2 = strchr(s1, '=')) == 0) { 2194*0Sstevel@tonic-gate len = strlen(s1); 2195*0Sstevel@tonic-gate s2 = 0; 2196*0Sstevel@tonic-gate } else if (*++s2 == '\0') { 2197*0Sstevel@tonic-gate len = strlen(s1) - 1; 2198*0Sstevel@tonic-gate s2 = 0; 2199*0Sstevel@tonic-gate } else { 2200*0Sstevel@tonic-gate len = s2 - s1 - 1; 2201*0Sstevel@tonic-gate while (isspace(*s2)) 2202*0Sstevel@tonic-gate s2++; 2203*0Sstevel@tonic-gate } 2204*0Sstevel@tonic-gate 2205*0Sstevel@tonic-gate /* 2206*0Sstevel@tonic-gate * Determine whether the environment variable is 32- or 64-bit 2207*0Sstevel@tonic-gate * specific. The length, len, will reflect the architecture 2208*0Sstevel@tonic-gate * neutral portion of the string. 2209*0Sstevel@tonic-gate */ 2210*0Sstevel@tonic-gate if ((flags = ld_arch_env(s1, &len)) == ENV_TYP_IGNORE) 2211*0Sstevel@tonic-gate return; 2212*0Sstevel@tonic-gate env_flags |= flags; 2213*0Sstevel@tonic-gate 2214*0Sstevel@tonic-gate ld_generic_env(s1, len, s2, lmflags, lmtflags, env_flags, aout); 2215*0Sstevel@tonic-gate } 2216*0Sstevel@tonic-gate } 2217*0Sstevel@tonic-gate 2218*0Sstevel@tonic-gate /* 2219*0Sstevel@tonic-gate * Internal getenv routine. Called immediately after ld.so.1 initializes 2220*0Sstevel@tonic-gate * itself. 2221*0Sstevel@tonic-gate */ 2222*0Sstevel@tonic-gate int 2223*0Sstevel@tonic-gate readenv_user(const char ** envp, Word *lmflags, Word *lmtflags, int aout) 2224*0Sstevel@tonic-gate { 2225*0Sstevel@tonic-gate if (envp == (const char **)0) 2226*0Sstevel@tonic-gate return (0); 2227*0Sstevel@tonic-gate 2228*0Sstevel@tonic-gate while (*envp != (const char *)0) 2229*0Sstevel@tonic-gate ld_str_env(*envp++, lmflags, lmtflags, 0, aout); 2230*0Sstevel@tonic-gate 2231*0Sstevel@tonic-gate /* 2232*0Sstevel@tonic-gate * Having collected the best representation of any LD_FLAGS, process 2233*0Sstevel@tonic-gate * these strings. 2234*0Sstevel@tonic-gate */ 2235*0Sstevel@tonic-gate if (ld_flags_env(rpl_ldflags, lmflags, lmtflags, 0, aout) == 1) 2236*0Sstevel@tonic-gate return (1); 2237*0Sstevel@tonic-gate 2238*0Sstevel@tonic-gate /* 2239*0Sstevel@tonic-gate * Don't allow environment controlled auditing when tracing or if 2240*0Sstevel@tonic-gate * explicitly disabled. Trigger all tracing modes from 2241*0Sstevel@tonic-gate * LML_FLG_TRC_ENABLE. 2242*0Sstevel@tonic-gate */ 2243*0Sstevel@tonic-gate if ((*lmflags & LML_FLG_TRC_ENABLE) || (rtld_flags & RT_FL_NOAUDIT)) 2244*0Sstevel@tonic-gate rpl_audit = profile_lib = profile_name = 0; 2245*0Sstevel@tonic-gate if ((*lmflags & LML_FLG_TRC_ENABLE) == 0) 2246*0Sstevel@tonic-gate *lmflags &= ~LML_MSK_TRC; 2247*0Sstevel@tonic-gate 2248*0Sstevel@tonic-gate /* 2249*0Sstevel@tonic-gate * If we have a locale setting make sure its worth processing further. 2250*0Sstevel@tonic-gate * Duplicate the string so that new locale setting can generically 2251*0Sstevel@tonic-gate * cleanup any previous locales. 2252*0Sstevel@tonic-gate */ 2253*0Sstevel@tonic-gate if (locale) { 2254*0Sstevel@tonic-gate if (((*locale == 'C') && (*(locale + 1) == '\0')) || 2255*0Sstevel@tonic-gate (strcmp(locale, MSG_ORIG(MSG_TKN_POSIX)) == 0)) 2256*0Sstevel@tonic-gate locale = 0; 2257*0Sstevel@tonic-gate else 2258*0Sstevel@tonic-gate locale = strdup(locale); 2259*0Sstevel@tonic-gate } 2260*0Sstevel@tonic-gate return (0); 2261*0Sstevel@tonic-gate } 2262*0Sstevel@tonic-gate 2263*0Sstevel@tonic-gate /* 2264*0Sstevel@tonic-gate * Configuration environment processing. Called after the a.out has been 2265*0Sstevel@tonic-gate * processed (as the a.out can specify its own configuration file). 2266*0Sstevel@tonic-gate */ 2267*0Sstevel@tonic-gate int 2268*0Sstevel@tonic-gate readenv_config(Rtc_env * envtbl, Addr addr, int aout) 2269*0Sstevel@tonic-gate { 2270*0Sstevel@tonic-gate Word * lmflags = &(lml_main.lm_flags); 2271*0Sstevel@tonic-gate Word * lmtflags = &(lml_main.lm_tflags); 2272*0Sstevel@tonic-gate 2273*0Sstevel@tonic-gate if (envtbl == (Rtc_env *)0) 2274*0Sstevel@tonic-gate return (0); 2275*0Sstevel@tonic-gate 2276*0Sstevel@tonic-gate while (envtbl->env_str) { 2277*0Sstevel@tonic-gate uint_t env_flags = ENV_TYP_CONFIG; 2278*0Sstevel@tonic-gate 2279*0Sstevel@tonic-gate if (envtbl->env_flags & RTC_ENV_PERMANT) 2280*0Sstevel@tonic-gate env_flags |= ENV_TYP_PERMANT; 2281*0Sstevel@tonic-gate 2282*0Sstevel@tonic-gate ld_str_env((const char *)(envtbl->env_str + addr), 2283*0Sstevel@tonic-gate lmflags, lmtflags, env_flags, 0); 2284*0Sstevel@tonic-gate envtbl++; 2285*0Sstevel@tonic-gate } 2286*0Sstevel@tonic-gate 2287*0Sstevel@tonic-gate /* 2288*0Sstevel@tonic-gate * Having collected the best representation of any LD_FLAGS, process 2289*0Sstevel@tonic-gate * these strings. 2290*0Sstevel@tonic-gate */ 2291*0Sstevel@tonic-gate if (ld_flags_env(rpl_ldflags, lmflags, lmtflags, 0, aout) == 1) 2292*0Sstevel@tonic-gate return (1); 2293*0Sstevel@tonic-gate if (ld_flags_env(prm_ldflags, lmflags, lmtflags, ENV_TYP_CONFIG, 2294*0Sstevel@tonic-gate aout) == 1) 2295*0Sstevel@tonic-gate return (1); 2296*0Sstevel@tonic-gate 2297*0Sstevel@tonic-gate /* 2298*0Sstevel@tonic-gate * Don't allow environment controlled auditing when tracing or if 2299*0Sstevel@tonic-gate * explicitly disabled. Trigger all tracing modes from 2300*0Sstevel@tonic-gate * LML_FLG_TRC_ENABLE. 2301*0Sstevel@tonic-gate */ 2302*0Sstevel@tonic-gate if ((*lmflags & LML_FLG_TRC_ENABLE) || (rtld_flags & RT_FL_NOAUDIT)) 2303*0Sstevel@tonic-gate prm_audit = profile_lib = profile_name = 0; 2304*0Sstevel@tonic-gate if ((*lmflags & LML_FLG_TRC_ENABLE) == 0) 2305*0Sstevel@tonic-gate *lmflags &= ~LML_MSK_TRC; 2306*0Sstevel@tonic-gate 2307*0Sstevel@tonic-gate return (0); 2308*0Sstevel@tonic-gate } 2309*0Sstevel@tonic-gate 2310*0Sstevel@tonic-gate int 2311*0Sstevel@tonic-gate dowrite(Prfbuf * prf) 2312*0Sstevel@tonic-gate { 2313*0Sstevel@tonic-gate /* 2314*0Sstevel@tonic-gate * We do not have a valid file descriptor, so we are unable 2315*0Sstevel@tonic-gate * to flush the buffer. 2316*0Sstevel@tonic-gate */ 2317*0Sstevel@tonic-gate if (prf->pr_fd == -1) 2318*0Sstevel@tonic-gate return (0); 2319*0Sstevel@tonic-gate (void) write(prf->pr_fd, prf->pr_buf, prf->pr_cur - prf->pr_buf); 2320*0Sstevel@tonic-gate prf->pr_cur = prf->pr_buf; 2321*0Sstevel@tonic-gate return (1); 2322*0Sstevel@tonic-gate } 2323*0Sstevel@tonic-gate 2324*0Sstevel@tonic-gate /* 2325*0Sstevel@tonic-gate * Simplified printing. The following conversion specifications are supported: 2326*0Sstevel@tonic-gate * 2327*0Sstevel@tonic-gate * % [#] [-] [min field width] [. precision] s|d|x|c 2328*0Sstevel@tonic-gate * 2329*0Sstevel@tonic-gate * 2330*0Sstevel@tonic-gate * dorprf takes the output buffer in the form of Prfbuf which permits 2331*0Sstevel@tonic-gate * the verification of the output buffer size and the concatenation 2332*0Sstevel@tonic-gate * of data to an already existing output buffer. The Prfbuf 2333*0Sstevel@tonic-gate * structure contains the following: 2334*0Sstevel@tonic-gate * 2335*0Sstevel@tonic-gate * pr_buf pointer to the beginning of the output buffer. 2336*0Sstevel@tonic-gate * pr_cur pointer to the next available byte in the output buffer. By 2337*0Sstevel@tonic-gate * setting pr_cur ahead of pr_buf you can append to an already 2338*0Sstevel@tonic-gate * existing buffer. 2339*0Sstevel@tonic-gate * pr_len the size of the output buffer. By setting pr_len to '0' you 2340*0Sstevel@tonic-gate * disable protection from overflows in the output buffer. 2341*0Sstevel@tonic-gate * pr_fd a pointer to the file-descriptor the buffer will eventually be 2342*0Sstevel@tonic-gate * output to. If pr_fd is set to '-1' then it's assumed there is 2343*0Sstevel@tonic-gate * no output buffer and doprf() will return with an error if the 2344*0Sstevel@tonic-gate * output buffer is overflowed. If pr_fd is > -1 then when the 2345*0Sstevel@tonic-gate * output buffer is filled it will be flushed to pr_fd and then 2346*0Sstevel@tonic-gate * the available for additional data. 2347*0Sstevel@tonic-gate */ 2348*0Sstevel@tonic-gate #define FLG_UT_MINUS 0x0001 /* - */ 2349*0Sstevel@tonic-gate #define FLG_UT_SHARP 0x0002 /* # */ 2350*0Sstevel@tonic-gate #define FLG_UT_DOTSEEN 0x0008 /* dot appeared in format spec */ 2351*0Sstevel@tonic-gate 2352*0Sstevel@tonic-gate /* 2353*0Sstevel@tonic-gate * This macro is for use from within doprf only. it's to be used 2354*0Sstevel@tonic-gate * for checking the output buffer size and placing characters into 2355*0Sstevel@tonic-gate * the buffer. 2356*0Sstevel@tonic-gate */ 2357*0Sstevel@tonic-gate #define PUTC(c) \ 2358*0Sstevel@tonic-gate { \ 2359*0Sstevel@tonic-gate register char tmpc; \ 2360*0Sstevel@tonic-gate \ 2361*0Sstevel@tonic-gate tmpc = (c); \ 2362*0Sstevel@tonic-gate if ((bufsiz) && ((bp + 1) >= bufend)) { \ 2363*0Sstevel@tonic-gate prf->pr_cur = bp; \ 2364*0Sstevel@tonic-gate if (dowrite(prf) == 0) \ 2365*0Sstevel@tonic-gate return (0); \ 2366*0Sstevel@tonic-gate bp = prf->pr_cur; \ 2367*0Sstevel@tonic-gate } \ 2368*0Sstevel@tonic-gate *bp++ = tmpc; \ 2369*0Sstevel@tonic-gate } 2370*0Sstevel@tonic-gate 2371*0Sstevel@tonic-gate size_t 2372*0Sstevel@tonic-gate doprf(const char *format, va_list args, Prfbuf *prf) 2373*0Sstevel@tonic-gate { 2374*0Sstevel@tonic-gate char c; 2375*0Sstevel@tonic-gate char *bp = prf->pr_cur; 2376*0Sstevel@tonic-gate char *bufend = prf->pr_buf + prf->pr_len; 2377*0Sstevel@tonic-gate size_t bufsiz = prf->pr_len; 2378*0Sstevel@tonic-gate 2379*0Sstevel@tonic-gate while ((c = *format++) != '\0') { 2380*0Sstevel@tonic-gate if (c != '%') { 2381*0Sstevel@tonic-gate PUTC(c); 2382*0Sstevel@tonic-gate } else { 2383*0Sstevel@tonic-gate int base = 0, flag = 0, width = 0, prec = 0; 2384*0Sstevel@tonic-gate size_t _i; 2385*0Sstevel@tonic-gate int _c, _n; 2386*0Sstevel@tonic-gate char *_s; 2387*0Sstevel@tonic-gate int ls = 0; 2388*0Sstevel@tonic-gate again: 2389*0Sstevel@tonic-gate c = *format++; 2390*0Sstevel@tonic-gate switch (c) { 2391*0Sstevel@tonic-gate case '-': 2392*0Sstevel@tonic-gate flag |= FLG_UT_MINUS; 2393*0Sstevel@tonic-gate goto again; 2394*0Sstevel@tonic-gate case '#': 2395*0Sstevel@tonic-gate flag |= FLG_UT_SHARP; 2396*0Sstevel@tonic-gate goto again; 2397*0Sstevel@tonic-gate case '.': 2398*0Sstevel@tonic-gate flag |= FLG_UT_DOTSEEN; 2399*0Sstevel@tonic-gate goto again; 2400*0Sstevel@tonic-gate case '0': 2401*0Sstevel@tonic-gate case '1': 2402*0Sstevel@tonic-gate case '2': 2403*0Sstevel@tonic-gate case '3': 2404*0Sstevel@tonic-gate case '4': 2405*0Sstevel@tonic-gate case '5': 2406*0Sstevel@tonic-gate case '6': 2407*0Sstevel@tonic-gate case '7': 2408*0Sstevel@tonic-gate case '8': 2409*0Sstevel@tonic-gate case '9': 2410*0Sstevel@tonic-gate if (flag & FLG_UT_DOTSEEN) 2411*0Sstevel@tonic-gate prec = (prec * 10) + c - '0'; 2412*0Sstevel@tonic-gate else 2413*0Sstevel@tonic-gate width = (width * 10) + c - '0'; 2414*0Sstevel@tonic-gate goto again; 2415*0Sstevel@tonic-gate case 'x': 2416*0Sstevel@tonic-gate case 'X': 2417*0Sstevel@tonic-gate base = 16; 2418*0Sstevel@tonic-gate break; 2419*0Sstevel@tonic-gate case 'd': 2420*0Sstevel@tonic-gate case 'D': 2421*0Sstevel@tonic-gate case 'u': 2422*0Sstevel@tonic-gate base = 10; 2423*0Sstevel@tonic-gate flag &= ~FLG_UT_SHARP; 2424*0Sstevel@tonic-gate break; 2425*0Sstevel@tonic-gate case 'l': 2426*0Sstevel@tonic-gate base = 10; 2427*0Sstevel@tonic-gate ls++; /* number of l's (long or long long) */ 2428*0Sstevel@tonic-gate if ((*format == 'l') || 2429*0Sstevel@tonic-gate (*format == 'd') || (*format == 'D') || 2430*0Sstevel@tonic-gate (*format == 'x') || (*format == 'X') || 2431*0Sstevel@tonic-gate (*format == 'o') || (*format == 'O')) 2432*0Sstevel@tonic-gate goto again; 2433*0Sstevel@tonic-gate break; 2434*0Sstevel@tonic-gate case 'o': 2435*0Sstevel@tonic-gate case 'O': 2436*0Sstevel@tonic-gate base = 8; 2437*0Sstevel@tonic-gate break; 2438*0Sstevel@tonic-gate case 'c': 2439*0Sstevel@tonic-gate _c = va_arg(args, int); 2440*0Sstevel@tonic-gate 2441*0Sstevel@tonic-gate for (_i = 24; _i > 0; _i -= 8) { 2442*0Sstevel@tonic-gate if ((c = ((_c >> _i) & 0x7f)) != 0) { 2443*0Sstevel@tonic-gate PUTC(c); 2444*0Sstevel@tonic-gate } 2445*0Sstevel@tonic-gate } 2446*0Sstevel@tonic-gate if ((c = ((_c >> _i) & 0x7f)) != 0) { 2447*0Sstevel@tonic-gate PUTC(c); 2448*0Sstevel@tonic-gate } 2449*0Sstevel@tonic-gate break; 2450*0Sstevel@tonic-gate case 's': 2451*0Sstevel@tonic-gate _s = va_arg(args, char *); 2452*0Sstevel@tonic-gate _i = strlen(_s); 2453*0Sstevel@tonic-gate /* LINTED */ 2454*0Sstevel@tonic-gate _n = (int)(width - _i); 2455*0Sstevel@tonic-gate if (!prec) 2456*0Sstevel@tonic-gate /* LINTED */ 2457*0Sstevel@tonic-gate prec = (int)_i; 2458*0Sstevel@tonic-gate 2459*0Sstevel@tonic-gate if (width && !(flag & FLG_UT_MINUS)) { 2460*0Sstevel@tonic-gate while (_n-- > 0) 2461*0Sstevel@tonic-gate PUTC(' '); 2462*0Sstevel@tonic-gate } 2463*0Sstevel@tonic-gate while (((c = *_s++) != 0) && prec--) { 2464*0Sstevel@tonic-gate PUTC(c); 2465*0Sstevel@tonic-gate } 2466*0Sstevel@tonic-gate if (width && (flag & FLG_UT_MINUS)) { 2467*0Sstevel@tonic-gate while (_n-- > 0) 2468*0Sstevel@tonic-gate PUTC(' '); 2469*0Sstevel@tonic-gate } 2470*0Sstevel@tonic-gate break; 2471*0Sstevel@tonic-gate case '%': 2472*0Sstevel@tonic-gate PUTC('%'); 2473*0Sstevel@tonic-gate break; 2474*0Sstevel@tonic-gate default: 2475*0Sstevel@tonic-gate break; 2476*0Sstevel@tonic-gate } 2477*0Sstevel@tonic-gate 2478*0Sstevel@tonic-gate /* 2479*0Sstevel@tonic-gate * Numeric processing 2480*0Sstevel@tonic-gate */ 2481*0Sstevel@tonic-gate if (base) { 2482*0Sstevel@tonic-gate char local[20]; 2483*0Sstevel@tonic-gate const char *string = 2484*0Sstevel@tonic-gate MSG_ORIG(MSG_STR_HEXNUM); 2485*0Sstevel@tonic-gate size_t ssize = 0, psize = 0; 2486*0Sstevel@tonic-gate const char *prefix = 2487*0Sstevel@tonic-gate MSG_ORIG(MSG_STR_EMPTY); 2488*0Sstevel@tonic-gate u_longlong_t num; 2489*0Sstevel@tonic-gate 2490*0Sstevel@tonic-gate switch (ls) { 2491*0Sstevel@tonic-gate case 0: /* int */ 2492*0Sstevel@tonic-gate num = (u_longlong_t) 2493*0Sstevel@tonic-gate va_arg(args, uint_t); 2494*0Sstevel@tonic-gate break; 2495*0Sstevel@tonic-gate case 1: /* long */ 2496*0Sstevel@tonic-gate num = (u_longlong_t) 2497*0Sstevel@tonic-gate va_arg(args, ulong_t); 2498*0Sstevel@tonic-gate break; 2499*0Sstevel@tonic-gate case 2: /* long long */ 2500*0Sstevel@tonic-gate num = va_arg(args, u_longlong_t); 2501*0Sstevel@tonic-gate break; 2502*0Sstevel@tonic-gate } 2503*0Sstevel@tonic-gate 2504*0Sstevel@tonic-gate if (flag & FLG_UT_SHARP) { 2505*0Sstevel@tonic-gate if (base == 16) { 2506*0Sstevel@tonic-gate prefix = MSG_ORIG(MSG_STR_HEX); 2507*0Sstevel@tonic-gate psize = 2; 2508*0Sstevel@tonic-gate } else { 2509*0Sstevel@tonic-gate prefix = MSG_ORIG(MSG_STR_ZERO); 2510*0Sstevel@tonic-gate psize = 1; 2511*0Sstevel@tonic-gate } 2512*0Sstevel@tonic-gate } 2513*0Sstevel@tonic-gate if ((base == 10) && (long)num < 0) { 2514*0Sstevel@tonic-gate prefix = MSG_ORIG(MSG_STR_NEGATE); 2515*0Sstevel@tonic-gate psize = MSG_STR_NEGATE_SIZE; 2516*0Sstevel@tonic-gate num = (u_longlong_t)(-(longlong_t)num); 2517*0Sstevel@tonic-gate } 2518*0Sstevel@tonic-gate 2519*0Sstevel@tonic-gate /* 2520*0Sstevel@tonic-gate * Convert the numeric value into a local 2521*0Sstevel@tonic-gate * string (stored in reverse order). 2522*0Sstevel@tonic-gate */ 2523*0Sstevel@tonic-gate _s = local; 2524*0Sstevel@tonic-gate do { 2525*0Sstevel@tonic-gate *_s++ = string[num % base]; 2526*0Sstevel@tonic-gate num /= base; 2527*0Sstevel@tonic-gate ssize++; 2528*0Sstevel@tonic-gate } while (num); 2529*0Sstevel@tonic-gate 2530*0Sstevel@tonic-gate /* 2531*0Sstevel@tonic-gate * Provide any precision or width padding. 2532*0Sstevel@tonic-gate */ 2533*0Sstevel@tonic-gate if (prec) { 2534*0Sstevel@tonic-gate /* LINTED */ 2535*0Sstevel@tonic-gate _n = (int)(prec - ssize); 2536*0Sstevel@tonic-gate while (_n-- > 0) { 2537*0Sstevel@tonic-gate *_s++ = '0'; 2538*0Sstevel@tonic-gate ssize++; 2539*0Sstevel@tonic-gate } 2540*0Sstevel@tonic-gate } 2541*0Sstevel@tonic-gate if (width && !(flag & FLG_UT_MINUS)) { 2542*0Sstevel@tonic-gate /* LINTED */ 2543*0Sstevel@tonic-gate _n = (int)(width - ssize - psize); 2544*0Sstevel@tonic-gate while (_n-- > 0) { 2545*0Sstevel@tonic-gate PUTC(' '); 2546*0Sstevel@tonic-gate } 2547*0Sstevel@tonic-gate } 2548*0Sstevel@tonic-gate 2549*0Sstevel@tonic-gate /* 2550*0Sstevel@tonic-gate * Print any prefix and the numeric string 2551*0Sstevel@tonic-gate */ 2552*0Sstevel@tonic-gate while (*prefix) 2553*0Sstevel@tonic-gate PUTC(*prefix++); 2554*0Sstevel@tonic-gate do { 2555*0Sstevel@tonic-gate PUTC(*--_s); 2556*0Sstevel@tonic-gate } while (_s > local); 2557*0Sstevel@tonic-gate 2558*0Sstevel@tonic-gate /* 2559*0Sstevel@tonic-gate * Provide any width padding. 2560*0Sstevel@tonic-gate */ 2561*0Sstevel@tonic-gate if (width && (flag & FLG_UT_MINUS)) { 2562*0Sstevel@tonic-gate /* LINTED */ 2563*0Sstevel@tonic-gate _n = (int)(width - ssize - psize); 2564*0Sstevel@tonic-gate while (_n-- > 0) 2565*0Sstevel@tonic-gate PUTC(' '); 2566*0Sstevel@tonic-gate } 2567*0Sstevel@tonic-gate } 2568*0Sstevel@tonic-gate } 2569*0Sstevel@tonic-gate } 2570*0Sstevel@tonic-gate PUTC('\0'); 2571*0Sstevel@tonic-gate prf->pr_cur = bp; 2572*0Sstevel@tonic-gate return (1); 2573*0Sstevel@tonic-gate } 2574*0Sstevel@tonic-gate 2575*0Sstevel@tonic-gate static int 2576*0Sstevel@tonic-gate doprintf(const char *format, va_list args, Prfbuf *prf) 2577*0Sstevel@tonic-gate { 2578*0Sstevel@tonic-gate char *ocur = prf->pr_cur; 2579*0Sstevel@tonic-gate 2580*0Sstevel@tonic-gate if (doprf(format, args, prf) == 0) 2581*0Sstevel@tonic-gate return (0); 2582*0Sstevel@tonic-gate /* LINTED */ 2583*0Sstevel@tonic-gate return ((int)(prf->pr_cur - ocur)); 2584*0Sstevel@tonic-gate } 2585*0Sstevel@tonic-gate 2586*0Sstevel@tonic-gate /* VARARGS2 */ 2587*0Sstevel@tonic-gate int 2588*0Sstevel@tonic-gate sprintf(char *buf, const char *format, ...) 2589*0Sstevel@tonic-gate { 2590*0Sstevel@tonic-gate va_list args; 2591*0Sstevel@tonic-gate int len; 2592*0Sstevel@tonic-gate Prfbuf prf; 2593*0Sstevel@tonic-gate 2594*0Sstevel@tonic-gate va_start(args, format); 2595*0Sstevel@tonic-gate prf.pr_buf = prf.pr_cur = buf; 2596*0Sstevel@tonic-gate prf.pr_len = 0; 2597*0Sstevel@tonic-gate prf.pr_fd = -1; 2598*0Sstevel@tonic-gate len = doprintf(format, args, &prf); 2599*0Sstevel@tonic-gate va_end(args); 2600*0Sstevel@tonic-gate 2601*0Sstevel@tonic-gate /* 2602*0Sstevel@tonic-gate * sprintf() return value excludes the terminating null byte. 2603*0Sstevel@tonic-gate */ 2604*0Sstevel@tonic-gate return (len - 1); 2605*0Sstevel@tonic-gate } 2606*0Sstevel@tonic-gate 2607*0Sstevel@tonic-gate /* VARARGS3 */ 2608*0Sstevel@tonic-gate int 2609*0Sstevel@tonic-gate snprintf(char *buf, size_t n, const char *format, ...) 2610*0Sstevel@tonic-gate { 2611*0Sstevel@tonic-gate va_list args; 2612*0Sstevel@tonic-gate int len; 2613*0Sstevel@tonic-gate Prfbuf prf; 2614*0Sstevel@tonic-gate 2615*0Sstevel@tonic-gate va_start(args, format); 2616*0Sstevel@tonic-gate prf.pr_buf = prf.pr_cur = buf; 2617*0Sstevel@tonic-gate prf.pr_len = n; 2618*0Sstevel@tonic-gate prf.pr_fd = -1; 2619*0Sstevel@tonic-gate len = doprintf(format, args, &prf); 2620*0Sstevel@tonic-gate va_end(args); 2621*0Sstevel@tonic-gate 2622*0Sstevel@tonic-gate return (len); 2623*0Sstevel@tonic-gate } 2624*0Sstevel@tonic-gate 2625*0Sstevel@tonic-gate /* VARARGS2 */ 2626*0Sstevel@tonic-gate int 2627*0Sstevel@tonic-gate bufprint(Prfbuf *prf, const char *format, ...) 2628*0Sstevel@tonic-gate { 2629*0Sstevel@tonic-gate va_list args; 2630*0Sstevel@tonic-gate int len; 2631*0Sstevel@tonic-gate 2632*0Sstevel@tonic-gate va_start(args, format); 2633*0Sstevel@tonic-gate len = doprintf(format, args, prf); 2634*0Sstevel@tonic-gate va_end(args); 2635*0Sstevel@tonic-gate 2636*0Sstevel@tonic-gate return (len); 2637*0Sstevel@tonic-gate } 2638*0Sstevel@tonic-gate 2639*0Sstevel@tonic-gate /*PRINTFLIKE1*/ 2640*0Sstevel@tonic-gate int 2641*0Sstevel@tonic-gate printf(const char *format, ...) 2642*0Sstevel@tonic-gate { 2643*0Sstevel@tonic-gate va_list args; 2644*0Sstevel@tonic-gate char buffer[ERRSIZE]; 2645*0Sstevel@tonic-gate Prfbuf prf; 2646*0Sstevel@tonic-gate 2647*0Sstevel@tonic-gate va_start(args, format); 2648*0Sstevel@tonic-gate prf.pr_buf = prf.pr_cur = buffer; 2649*0Sstevel@tonic-gate prf.pr_len = ERRSIZE; 2650*0Sstevel@tonic-gate prf.pr_fd = 1; 2651*0Sstevel@tonic-gate (void) doprf(format, args, &prf); 2652*0Sstevel@tonic-gate va_end(args); 2653*0Sstevel@tonic-gate /* 2654*0Sstevel@tonic-gate * Trim trailing '\0' form buffer 2655*0Sstevel@tonic-gate */ 2656*0Sstevel@tonic-gate prf.pr_cur--; 2657*0Sstevel@tonic-gate return (dowrite(&prf)); 2658*0Sstevel@tonic-gate } 2659*0Sstevel@tonic-gate 2660*0Sstevel@tonic-gate static char errbuf[ERRSIZE], *nextptr = errbuf, *prevptr = 0; 2661*0Sstevel@tonic-gate 2662*0Sstevel@tonic-gate /*PRINTFLIKE2*/ 2663*0Sstevel@tonic-gate void 2664*0Sstevel@tonic-gate eprintf(Error error, const char *format, ...) 2665*0Sstevel@tonic-gate { 2666*0Sstevel@tonic-gate va_list args; 2667*0Sstevel@tonic-gate int overflow = 0; 2668*0Sstevel@tonic-gate static int lock = 0; 2669*0Sstevel@tonic-gate Prfbuf prf; 2670*0Sstevel@tonic-gate 2671*0Sstevel@tonic-gate if (lock || (nextptr == (errbuf + ERRSIZE))) 2672*0Sstevel@tonic-gate return; 2673*0Sstevel@tonic-gate 2674*0Sstevel@tonic-gate /* 2675*0Sstevel@tonic-gate * Note: this lock is here to prevent the same thread from recursively 2676*0Sstevel@tonic-gate * entering itself during a eprintf. ie: during eprintf malloc() fails 2677*0Sstevel@tonic-gate * and we try and call eprintf ... and then malloc() fails .... 2678*0Sstevel@tonic-gate */ 2679*0Sstevel@tonic-gate lock = 1; 2680*0Sstevel@tonic-gate 2681*0Sstevel@tonic-gate /* 2682*0Sstevel@tonic-gate * If we have completed startup initialization, all error messages 2683*0Sstevel@tonic-gate * must be saved. These are reported through dlerror(). If we're 2684*0Sstevel@tonic-gate * still in the initialization stage, output the error directly and 2685*0Sstevel@tonic-gate * add a newline. 2686*0Sstevel@tonic-gate */ 2687*0Sstevel@tonic-gate va_start(args, format); 2688*0Sstevel@tonic-gate 2689*0Sstevel@tonic-gate prf.pr_buf = prf.pr_cur = nextptr; 2690*0Sstevel@tonic-gate prf.pr_len = ERRSIZE - (nextptr - errbuf); 2691*0Sstevel@tonic-gate 2692*0Sstevel@tonic-gate if (!(rtld_flags & RT_FL_APPLIC)) 2693*0Sstevel@tonic-gate prf.pr_fd = 2; 2694*0Sstevel@tonic-gate else 2695*0Sstevel@tonic-gate prf.pr_fd = -1; 2696*0Sstevel@tonic-gate 2697*0Sstevel@tonic-gate if (error > ERR_NONE) { 2698*0Sstevel@tonic-gate if ((error == ERR_FATAL) && (rtld_flags2 & RT_FL2_FTL2WARN)) 2699*0Sstevel@tonic-gate error = ERR_WARNING; 2700*0Sstevel@tonic-gate if (error == ERR_WARNING) { 2701*0Sstevel@tonic-gate if (err_strs[ERR_WARNING] == 0) 2702*0Sstevel@tonic-gate err_strs[ERR_WARNING] = MSG_INTL(MSG_ERR_WARNING); 2703*0Sstevel@tonic-gate } else if (error == ERR_FATAL) { 2704*0Sstevel@tonic-gate if (err_strs[ERR_FATAL] == 0) 2705*0Sstevel@tonic-gate err_strs[ERR_FATAL] = MSG_INTL(MSG_ERR_FATAL); 2706*0Sstevel@tonic-gate } else if (error == ERR_ELF) { 2707*0Sstevel@tonic-gate if (err_strs[ERR_ELF] == 0) 2708*0Sstevel@tonic-gate err_strs[ERR_ELF] = MSG_INTL(MSG_ERR_ELF); 2709*0Sstevel@tonic-gate } 2710*0Sstevel@tonic-gate if (bufprint(&prf, MSG_ORIG(MSG_STR_EMSGFOR1), 2711*0Sstevel@tonic-gate rt_name, pr_name, err_strs[error]) == 0) { 2712*0Sstevel@tonic-gate overflow = 1; 2713*0Sstevel@tonic-gate } else { 2714*0Sstevel@tonic-gate /* 2715*0Sstevel@tonic-gate * Remove the terminating '\0'. 2716*0Sstevel@tonic-gate */ 2717*0Sstevel@tonic-gate prf.pr_cur--; 2718*0Sstevel@tonic-gate } 2719*0Sstevel@tonic-gate } 2720*0Sstevel@tonic-gate 2721*0Sstevel@tonic-gate if ((overflow == 0) && doprf(format, args, &prf) == 0) 2722*0Sstevel@tonic-gate overflow = 1; 2723*0Sstevel@tonic-gate 2724*0Sstevel@tonic-gate /* 2725*0Sstevel@tonic-gate * If this is an ELF error, it will have been generated by a support 2726*0Sstevel@tonic-gate * object that has a dependency on libelf. ld.so.1 doesn't generate any 2727*0Sstevel@tonic-gate * ELF error messages as it doesn't interact with libelf. Determine the 2728*0Sstevel@tonic-gate * ELF error string. 2729*0Sstevel@tonic-gate */ 2730*0Sstevel@tonic-gate if ((overflow == 0) && (error == ERR_ELF)) { 2731*0Sstevel@tonic-gate static int (*elfeno)() = 0; 2732*0Sstevel@tonic-gate static const char *(*elfemg)(); 2733*0Sstevel@tonic-gate const char *emsg; 2734*0Sstevel@tonic-gate Rt_map *dlmp, *lmp = lml_rtld.lm_head; 2735*0Sstevel@tonic-gate 2736*0Sstevel@tonic-gate if (NEXT(lmp) && (elfeno == 0)) { 2737*0Sstevel@tonic-gate if (((elfemg = (const char *(*)())dlsym_intn(RTLD_NEXT, 2738*0Sstevel@tonic-gate MSG_ORIG(MSG_SYM_ELFERRMSG), lmp, &dlmp)) == 0) || 2739*0Sstevel@tonic-gate ((elfeno = (int (*)())dlsym_intn(RTLD_NEXT, 2740*0Sstevel@tonic-gate MSG_ORIG(MSG_SYM_ELFERRNO), lmp, &dlmp)) == 0)) 2741*0Sstevel@tonic-gate elfeno = 0; 2742*0Sstevel@tonic-gate } 2743*0Sstevel@tonic-gate 2744*0Sstevel@tonic-gate /* 2745*0Sstevel@tonic-gate * Lookup the message; equivalent to elf_errmsg(elf_errno()). 2746*0Sstevel@tonic-gate */ 2747*0Sstevel@tonic-gate if (elfeno && ((emsg = (* elfemg)((* elfeno)())) != 0)) { 2748*0Sstevel@tonic-gate prf.pr_cur--; 2749*0Sstevel@tonic-gate if (bufprint(&prf, MSG_ORIG(MSG_STR_EMSGFOR2), 2750*0Sstevel@tonic-gate emsg) == 0) 2751*0Sstevel@tonic-gate overflow = 1; 2752*0Sstevel@tonic-gate } 2753*0Sstevel@tonic-gate } 2754*0Sstevel@tonic-gate 2755*0Sstevel@tonic-gate /* 2756*0Sstevel@tonic-gate * Push out any message that's been built. Note, in the case of an 2757*0Sstevel@tonic-gate * overflow condition, this message may be incomplete, in which case 2758*0Sstevel@tonic-gate * make sure any partial string is null terminated. 2759*0Sstevel@tonic-gate */ 2760*0Sstevel@tonic-gate if (overflow) 2761*0Sstevel@tonic-gate *(prf.pr_cur) = '\0'; 2762*0Sstevel@tonic-gate if ((rtld_flags & (RT_FL_APPLIC | RT_FL_SILENCERR)) == 0) { 2763*0Sstevel@tonic-gate *(prf.pr_cur - 1) = '\n'; 2764*0Sstevel@tonic-gate (void) dowrite(&prf); 2765*0Sstevel@tonic-gate } 2766*0Sstevel@tonic-gate 2767*0Sstevel@tonic-gate DBG_CALL(Dbg_util_str(nextptr)); 2768*0Sstevel@tonic-gate va_end(args); 2769*0Sstevel@tonic-gate 2770*0Sstevel@tonic-gate /* 2771*0Sstevel@tonic-gate * Determine if there was insufficient space left in the buffer to 2772*0Sstevel@tonic-gate * complete the message. If so, we'll have printed out as much as had 2773*0Sstevel@tonic-gate * been processed if we're not yet executing the application. 2774*0Sstevel@tonic-gate * Otherwise, there will be some debugging diagnostic indicating 2775*0Sstevel@tonic-gate * as much of the error message as possible. Write out a final buffer 2776*0Sstevel@tonic-gate * overflow diagnostic - unlocalized, so we don't chance more errors. 2777*0Sstevel@tonic-gate */ 2778*0Sstevel@tonic-gate if (overflow) { 2779*0Sstevel@tonic-gate char *str = (char *)MSG_INTL(MSG_EMG_BUFOVRFLW); 2780*0Sstevel@tonic-gate 2781*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_SILENCERR) == 0) { 2782*0Sstevel@tonic-gate lasterr = str; 2783*0Sstevel@tonic-gate 2784*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_APPLIC) == 0) { 2785*0Sstevel@tonic-gate (void) write(2, str, strlen(str)); 2786*0Sstevel@tonic-gate (void) write(2, MSG_ORIG(MSG_STR_NL), 2787*0Sstevel@tonic-gate MSG_STR_NL_SIZE); 2788*0Sstevel@tonic-gate } 2789*0Sstevel@tonic-gate } 2790*0Sstevel@tonic-gate DBG_CALL(Dbg_util_str(str)); 2791*0Sstevel@tonic-gate 2792*0Sstevel@tonic-gate lock = 0; 2793*0Sstevel@tonic-gate nextptr = errbuf + ERRSIZE; 2794*0Sstevel@tonic-gate return; 2795*0Sstevel@tonic-gate } 2796*0Sstevel@tonic-gate 2797*0Sstevel@tonic-gate /* 2798*0Sstevel@tonic-gate * If the application has started, then error messages are being saved 2799*0Sstevel@tonic-gate * for retrieval by dlerror(), or possible flushing from rtldexit() in 2800*0Sstevel@tonic-gate * the case of a fatal error. In this case, establish the next error 2801*0Sstevel@tonic-gate * pointer. If we haven't started the application, the whole message 2802*0Sstevel@tonic-gate * buffer can be reused. 2803*0Sstevel@tonic-gate */ 2804*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_SILENCERR) == 0) { 2805*0Sstevel@tonic-gate lasterr = nextptr; 2806*0Sstevel@tonic-gate 2807*0Sstevel@tonic-gate /* 2808*0Sstevel@tonic-gate * Note, should we encounter an error such as ENOMEM, there may 2809*0Sstevel@tonic-gate * be a number of the same error messages (ie. an operation 2810*0Sstevel@tonic-gate * fails with ENOMEM, and then the attempts to construct the 2811*0Sstevel@tonic-gate * error message itself, which incurs additional ENOMEM errors). 2812*0Sstevel@tonic-gate * Compare any previous error message with the one we've just 2813*0Sstevel@tonic-gate * created to prevent any duplication clutter. 2814*0Sstevel@tonic-gate */ 2815*0Sstevel@tonic-gate if ((rtld_flags & RT_FL_APPLIC) && 2816*0Sstevel@tonic-gate ((prevptr == 0) || (strcmp(prevptr, nextptr) != 0))) { 2817*0Sstevel@tonic-gate prevptr = nextptr; 2818*0Sstevel@tonic-gate nextptr = prf.pr_cur; 2819*0Sstevel@tonic-gate *nextptr = '\0'; 2820*0Sstevel@tonic-gate } 2821*0Sstevel@tonic-gate } 2822*0Sstevel@tonic-gate lock = 0; 2823*0Sstevel@tonic-gate } 2824*0Sstevel@tonic-gate 2825*0Sstevel@tonic-gate 2826*0Sstevel@tonic-gate #if DEBUG 2827*0Sstevel@tonic-gate /* 2828*0Sstevel@tonic-gate * Provide assfail() for ASSERT() statements, 2829*0Sstevel@tonic-gate * see <sys/debug.h> for further details. 2830*0Sstevel@tonic-gate */ 2831*0Sstevel@tonic-gate int 2832*0Sstevel@tonic-gate assfail(const char *a, const char *f, int l) 2833*0Sstevel@tonic-gate { 2834*0Sstevel@tonic-gate (void) printf("assertion failed: %s, file: %s, line: %d\n", a, f, l); 2835*0Sstevel@tonic-gate (void) _lwp_kill(_lwp_self(), SIGABRT); 2836*0Sstevel@tonic-gate return (0); 2837*0Sstevel@tonic-gate } 2838*0Sstevel@tonic-gate #endif 2839*0Sstevel@tonic-gate 2840*0Sstevel@tonic-gate /* 2841*0Sstevel@tonic-gate * Exit. If we arrive here with a non zero status it's because of a fatal 2842*0Sstevel@tonic-gate * error condition (most commonly a relocation error). If the application has 2843*0Sstevel@tonic-gate * already had control, then the actual fatal error message will have been 2844*0Sstevel@tonic-gate * recorded in the dlerror() message buffer. Print the message before really 2845*0Sstevel@tonic-gate * exiting. 2846*0Sstevel@tonic-gate */ 2847*0Sstevel@tonic-gate void 2848*0Sstevel@tonic-gate rtldexit(Lm_list * lml, int status) 2849*0Sstevel@tonic-gate { 2850*0Sstevel@tonic-gate if (status) { 2851*0Sstevel@tonic-gate if (rtld_flags & RT_FL_APPLIC) { 2852*0Sstevel@tonic-gate /* 2853*0Sstevel@tonic-gate * If the error buffer has been used, write out all 2854*0Sstevel@tonic-gate * pending messages - lasterr is simply a pointer to 2855*0Sstevel@tonic-gate * the last message in this buffer. However, if the 2856*0Sstevel@tonic-gate * buffer couldn't be created at all, lasterr points 2857*0Sstevel@tonic-gate * to a constant error message string. 2858*0Sstevel@tonic-gate */ 2859*0Sstevel@tonic-gate if (*errbuf) { 2860*0Sstevel@tonic-gate char *errptr = errbuf; 2861*0Sstevel@tonic-gate char *errend = errbuf + ERRSIZE; 2862*0Sstevel@tonic-gate 2863*0Sstevel@tonic-gate while ((errptr < errend) && *errptr) { 2864*0Sstevel@tonic-gate size_t size = strlen(errptr); 2865*0Sstevel@tonic-gate (void) write(2, errptr, size); 2866*0Sstevel@tonic-gate (void) write(2, MSG_ORIG(MSG_STR_NL), 2867*0Sstevel@tonic-gate MSG_STR_NL_SIZE); 2868*0Sstevel@tonic-gate errptr += (size + 1); 2869*0Sstevel@tonic-gate } 2870*0Sstevel@tonic-gate } 2871*0Sstevel@tonic-gate if (lasterr && ((lasterr < errbuf) || 2872*0Sstevel@tonic-gate (lasterr > (errbuf + ERRSIZE)))) { 2873*0Sstevel@tonic-gate (void) write(2, lasterr, strlen(lasterr)); 2874*0Sstevel@tonic-gate (void) write(2, MSG_ORIG(MSG_STR_NL), 2875*0Sstevel@tonic-gate MSG_STR_NL_SIZE); 2876*0Sstevel@tonic-gate } 2877*0Sstevel@tonic-gate } 2878*0Sstevel@tonic-gate leave(lml); 2879*0Sstevel@tonic-gate (void) _lwp_kill(_lwp_self(), killsig); 2880*0Sstevel@tonic-gate } 2881*0Sstevel@tonic-gate _exit(status); 2882*0Sstevel@tonic-gate } 2883*0Sstevel@tonic-gate 2884*0Sstevel@tonic-gate /* 2885*0Sstevel@tonic-gate * Routines to co-ordinate the opening of /dev/zero and /proc. 2886*0Sstevel@tonic-gate * dz_fd is exported for possible use by libld.so, and to insure it gets 2887*0Sstevel@tonic-gate * closed on leaving ld.so.1. 2888*0Sstevel@tonic-gate */ 2889*0Sstevel@tonic-gate int dz_fd = FD_UNAVAIL; 2890*0Sstevel@tonic-gate 2891*0Sstevel@tonic-gate void 2892*0Sstevel@tonic-gate dz_init(int fd) 2893*0Sstevel@tonic-gate { 2894*0Sstevel@tonic-gate dz_fd = fd; 2895*0Sstevel@tonic-gate } 2896*0Sstevel@tonic-gate 2897*0Sstevel@tonic-gate 2898*0Sstevel@tonic-gate /* 2899*0Sstevel@tonic-gate * mmap() a page from MAP_ANON 2900*0Sstevel@tonic-gate * 2901*0Sstevel@tonic-gate * Note: MAP_ANON is only on Solaris8++, we use this routine to 2902*0Sstevel@tonic-gate * not only mmap(MAP_ANON) but to also probe if it is available 2903*0Sstevel@tonic-gate * on the current OS. 2904*0Sstevel@tonic-gate */ 2905*0Sstevel@tonic-gate Am_ret 2906*0Sstevel@tonic-gate anon_map(caddr_t *addr, size_t len, int prot, int flags) 2907*0Sstevel@tonic-gate { 2908*0Sstevel@tonic-gate #if defined(MAP_ANON) 2909*0Sstevel@tonic-gate static int noanon = 0; 2910*0Sstevel@tonic-gate caddr_t va; 2911*0Sstevel@tonic-gate 2912*0Sstevel@tonic-gate if (noanon == 0) { 2913*0Sstevel@tonic-gate if ((va = (caddr_t)mmap(*addr, len, prot, 2914*0Sstevel@tonic-gate (flags | MAP_ANON), -1, 0)) != MAP_FAILED) { 2915*0Sstevel@tonic-gate *addr = va; 2916*0Sstevel@tonic-gate return (AM_OK); 2917*0Sstevel@tonic-gate } 2918*0Sstevel@tonic-gate 2919*0Sstevel@tonic-gate if ((errno != EBADF) && (errno != EINVAL)) { 2920*0Sstevel@tonic-gate int err = errno; 2921*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAPANON), 2922*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_DEVZERO), strerror(err)); 2923*0Sstevel@tonic-gate return (AM_ERROR); 2924*0Sstevel@tonic-gate } else 2925*0Sstevel@tonic-gate noanon = 1; 2926*0Sstevel@tonic-gate } 2927*0Sstevel@tonic-gate #endif 2928*0Sstevel@tonic-gate return (AM_NOSUP); 2929*0Sstevel@tonic-gate } 2930*0Sstevel@tonic-gate 2931*0Sstevel@tonic-gate /* 2932*0Sstevel@tonic-gate * Map anonymous memory from /dev/zero, or via MAP_ANON. 2933*0Sstevel@tonic-gate * 2934*0Sstevel@tonic-gate * (MAP_ANON only appears on Solaris 8, so we need fall-back 2935*0Sstevel@tonic-gate * behavior for older systems.) 2936*0Sstevel@tonic-gate */ 2937*0Sstevel@tonic-gate caddr_t 2938*0Sstevel@tonic-gate dz_map(caddr_t addr, size_t len, int prot, int flags) 2939*0Sstevel@tonic-gate { 2940*0Sstevel@tonic-gate caddr_t va; 2941*0Sstevel@tonic-gate int err; 2942*0Sstevel@tonic-gate Am_ret amret; 2943*0Sstevel@tonic-gate 2944*0Sstevel@tonic-gate amret = anon_map(&addr, len, prot, flags); 2945*0Sstevel@tonic-gate 2946*0Sstevel@tonic-gate if (amret == AM_OK) 2947*0Sstevel@tonic-gate return (addr); 2948*0Sstevel@tonic-gate if (amret == AM_ERROR) 2949*0Sstevel@tonic-gate return (MAP_FAILED); 2950*0Sstevel@tonic-gate 2951*0Sstevel@tonic-gate /* amret == AM_NOSUP -> fallback to a devzero mmaping */ 2952*0Sstevel@tonic-gate 2953*0Sstevel@tonic-gate if (dz_fd == FD_UNAVAIL) { 2954*0Sstevel@tonic-gate if ((dz_fd = open(MSG_ORIG(MSG_PTH_DEVZERO), 2955*0Sstevel@tonic-gate O_RDONLY)) == FD_UNAVAIL) { 2956*0Sstevel@tonic-gate err = errno; 2957*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 2958*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_DEVZERO), strerror(err)); 2959*0Sstevel@tonic-gate return (MAP_FAILED); 2960*0Sstevel@tonic-gate } 2961*0Sstevel@tonic-gate } 2962*0Sstevel@tonic-gate 2963*0Sstevel@tonic-gate if ((va = mmap(addr, len, prot, flags, dz_fd, 0)) == MAP_FAILED) { 2964*0Sstevel@tonic-gate err = errno; 2965*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), 2966*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_DEVZERO), strerror(err)); 2967*0Sstevel@tonic-gate } 2968*0Sstevel@tonic-gate return (va); 2969*0Sstevel@tonic-gate } 2970*0Sstevel@tonic-gate 2971*0Sstevel@tonic-gate static int pr_fd = FD_UNAVAIL; 2972*0Sstevel@tonic-gate 2973*0Sstevel@tonic-gate int 2974*0Sstevel@tonic-gate pr_open() 2975*0Sstevel@tonic-gate { 2976*0Sstevel@tonic-gate char proc[16]; 2977*0Sstevel@tonic-gate 2978*0Sstevel@tonic-gate if (pr_fd == FD_UNAVAIL) { 2979*0Sstevel@tonic-gate (void) snprintf(proc, 16, MSG_ORIG(MSG_FMT_PROC), 2980*0Sstevel@tonic-gate (int)getpid()); 2981*0Sstevel@tonic-gate if ((pr_fd = open(proc, O_RDONLY)) == FD_UNAVAIL) { 2982*0Sstevel@tonic-gate int err = errno; 2983*0Sstevel@tonic-gate 2984*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), proc, 2985*0Sstevel@tonic-gate strerror(err)); 2986*0Sstevel@tonic-gate } 2987*0Sstevel@tonic-gate } 2988*0Sstevel@tonic-gate return (pr_fd); 2989*0Sstevel@tonic-gate } 2990*0Sstevel@tonic-gate 2991*0Sstevel@tonic-gate static int nu_fd = FD_UNAVAIL; 2992*0Sstevel@tonic-gate 2993*0Sstevel@tonic-gate caddr_t 2994*0Sstevel@tonic-gate nu_map(caddr_t addr, size_t len, int prot, int flags) 2995*0Sstevel@tonic-gate { 2996*0Sstevel@tonic-gate caddr_t va; 2997*0Sstevel@tonic-gate int err; 2998*0Sstevel@tonic-gate 2999*0Sstevel@tonic-gate if (nu_fd == FD_UNAVAIL) { 3000*0Sstevel@tonic-gate if ((nu_fd = open(MSG_ORIG(MSG_PTH_DEVNULL), 3001*0Sstevel@tonic-gate O_RDONLY)) == FD_UNAVAIL) { 3002*0Sstevel@tonic-gate err = errno; 3003*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 3004*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_DEVNULL), strerror(err)); 3005*0Sstevel@tonic-gate return (MAP_FAILED); 3006*0Sstevel@tonic-gate } 3007*0Sstevel@tonic-gate } 3008*0Sstevel@tonic-gate 3009*0Sstevel@tonic-gate if ((va = (caddr_t)mmap(addr, len, prot, flags, nu_fd, 0)) == 3010*0Sstevel@tonic-gate MAP_FAILED) { 3011*0Sstevel@tonic-gate err = errno; 3012*0Sstevel@tonic-gate eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), 3013*0Sstevel@tonic-gate MSG_ORIG(MSG_PTH_DEVNULL), strerror(err)); 3014*0Sstevel@tonic-gate } 3015*0Sstevel@tonic-gate return (va); 3016*0Sstevel@tonic-gate } 3017*0Sstevel@tonic-gate 3018*0Sstevel@tonic-gate /* 3019*0Sstevel@tonic-gate * Generic entry point from user code - simply grabs a lock. 3020*0Sstevel@tonic-gate */ 3021*0Sstevel@tonic-gate int 3022*0Sstevel@tonic-gate enter(void) 3023*0Sstevel@tonic-gate { 3024*0Sstevel@tonic-gate if (rt_bind_guard(THR_FLG_RTLD)) { 3025*0Sstevel@tonic-gate (void) rt_mutex_lock(&rtldlock); 3026*0Sstevel@tonic-gate return (1); 3027*0Sstevel@tonic-gate } 3028*0Sstevel@tonic-gate return (0); 3029*0Sstevel@tonic-gate } 3030*0Sstevel@tonic-gate 3031*0Sstevel@tonic-gate /* 3032*0Sstevel@tonic-gate * Generate diagnostics as to whether an object has been used. A symbolic 3033*0Sstevel@tonic-gate * reference that gets bound to an object marks it as used. Dependencies that 3034*0Sstevel@tonic-gate * are unused when RTLD_NOW is in effect should be removed from future builds 3035*0Sstevel@tonic-gate * of an object. Dependencies that are unused without RTLD_NOW in effect are 3036*0Sstevel@tonic-gate * candidates for lazy-loading. 3037*0Sstevel@tonic-gate * Unreferenced objects identify objects that are defined as dependencies but 3038*0Sstevel@tonic-gate * are unreferenced by the caller (they may however be referenced by other 3039*0Sstevel@tonic-gate * objects within the process, and therefore don't qualify as completely unused. 3040*0Sstevel@tonic-gate */ 3041*0Sstevel@tonic-gate void 3042*0Sstevel@tonic-gate unused(Lm_list *lml) 3043*0Sstevel@tonic-gate { 3044*0Sstevel@tonic-gate Rt_map *lmp; 3045*0Sstevel@tonic-gate int nl = 0; 3046*0Sstevel@tonic-gate Word tracing; 3047*0Sstevel@tonic-gate 3048*0Sstevel@tonic-gate /* 3049*0Sstevel@tonic-gate * If we're not tracing unused references or dependencies, or debugging 3050*0Sstevel@tonic-gate * there's nothing to do. 3051*0Sstevel@tonic-gate */ 3052*0Sstevel@tonic-gate tracing = lml->lm_flags & (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED); 3053*0Sstevel@tonic-gate 3054*0Sstevel@tonic-gate if ((tracing == 0) && (dbg_mask == 0)) 3055*0Sstevel@tonic-gate return; 3056*0Sstevel@tonic-gate 3057*0Sstevel@tonic-gate /* 3058*0Sstevel@tonic-gate * Traverse the link-maps looking for unreferenced or unused 3059*0Sstevel@tonic-gate * dependencies. Ignore the first object on a link-map list, as this 3060*0Sstevel@tonic-gate * is effectively always used. 3061*0Sstevel@tonic-gate */ 3062*0Sstevel@tonic-gate for (lmp = (Rt_map *)NEXT(lml->lm_head); lmp; 3063*0Sstevel@tonic-gate lmp = (Rt_map *)NEXT(lmp)) { 3064*0Sstevel@tonic-gate /* 3065*0Sstevel@tonic-gate * If tracing unreferenced objects, or under debugging, 3066*0Sstevel@tonic-gate * determine whether any of this objects callers haven't 3067*0Sstevel@tonic-gate * referenced it. 3068*0Sstevel@tonic-gate */ 3069*0Sstevel@tonic-gate if ((tracing & LML_FLG_TRC_UNREF) || dbg_mask) { 3070*0Sstevel@tonic-gate Bnd_desc ** bdpp; 3071*0Sstevel@tonic-gate Aliste off; 3072*0Sstevel@tonic-gate 3073*0Sstevel@tonic-gate for (ALIST_TRAVERSE(CALLERS(lmp), off, bdpp)) { 3074*0Sstevel@tonic-gate Bnd_desc * bdp = *bdpp; 3075*0Sstevel@tonic-gate Rt_map * clmp; 3076*0Sstevel@tonic-gate 3077*0Sstevel@tonic-gate if (bdp->b_flags & BND_REFER) 3078*0Sstevel@tonic-gate continue; 3079*0Sstevel@tonic-gate 3080*0Sstevel@tonic-gate clmp = bdp->b_caller; 3081*0Sstevel@tonic-gate if (FLAGS1(clmp) & FL1_RT_LDDSTUB) 3082*0Sstevel@tonic-gate continue; 3083*0Sstevel@tonic-gate 3084*0Sstevel@tonic-gate if (nl++ == 0) { 3085*0Sstevel@tonic-gate if (tracing & LML_FLG_TRC_UNREF) 3086*0Sstevel@tonic-gate (void) printf(MSG_ORIG(MSG_STR_NL)); 3087*0Sstevel@tonic-gate else 3088*0Sstevel@tonic-gate DBG_CALL(Dbg_util_nl()); 3089*0Sstevel@tonic-gate } 3090*0Sstevel@tonic-gate 3091*0Sstevel@tonic-gate if (tracing & LML_FLG_TRC_UNREF) 3092*0Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_UNREF_FMT), 3093*0Sstevel@tonic-gate NAME(lmp), NAME(clmp)); 3094*0Sstevel@tonic-gate else 3095*0Sstevel@tonic-gate DBG_CALL(Dbg_unused_unref(NAME(lmp), 3096*0Sstevel@tonic-gate NAME(clmp))); 3097*0Sstevel@tonic-gate } 3098*0Sstevel@tonic-gate } 3099*0Sstevel@tonic-gate 3100*0Sstevel@tonic-gate /* 3101*0Sstevel@tonic-gate * If tracing unused objects simply display those objects that 3102*0Sstevel@tonic-gate * haven't been referenced by anyone. 3103*0Sstevel@tonic-gate */ 3104*0Sstevel@tonic-gate if (FLAGS1(lmp) & FL1_RT_USED) 3105*0Sstevel@tonic-gate continue; 3106*0Sstevel@tonic-gate 3107*0Sstevel@tonic-gate if (nl++ == 0) { 3108*0Sstevel@tonic-gate if (tracing) 3109*0Sstevel@tonic-gate (void) printf(MSG_ORIG(MSG_STR_NL)); 3110*0Sstevel@tonic-gate else 3111*0Sstevel@tonic-gate DBG_CALL(Dbg_util_nl()); 3112*0Sstevel@tonic-gate } 3113*0Sstevel@tonic-gate if (CYCGROUP(lmp)) { 3114*0Sstevel@tonic-gate if (tracing) 3115*0Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_UNCYC_FMT), 3116*0Sstevel@tonic-gate NAME(lmp), CYCGROUP(lmp)); 3117*0Sstevel@tonic-gate else 3118*0Sstevel@tonic-gate DBG_CALL(Dbg_unused_file(NAME(lmp), 3119*0Sstevel@tonic-gate CYCGROUP(lmp))); 3120*0Sstevel@tonic-gate } else { 3121*0Sstevel@tonic-gate if (tracing) 3122*0Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_UNUSED_FMT), 3123*0Sstevel@tonic-gate NAME(lmp)); 3124*0Sstevel@tonic-gate else 3125*0Sstevel@tonic-gate DBG_CALL(Dbg_unused_file(NAME(lmp), 0)); 3126*0Sstevel@tonic-gate } 3127*0Sstevel@tonic-gate } 3128*0Sstevel@tonic-gate 3129*0Sstevel@tonic-gate if (dbg_mask) 3130*0Sstevel@tonic-gate DBG_CALL(Dbg_util_nl()); 3131*0Sstevel@tonic-gate } 3132*0Sstevel@tonic-gate 3133*0Sstevel@tonic-gate /* 3134*0Sstevel@tonic-gate * Initialization routine for the Fmap structure. If the fmap structure is 3135*0Sstevel@tonic-gate * already in use, any mapping is released. The structure is then initialized 3136*0Sstevel@tonic-gate * in preparation for further use. 3137*0Sstevel@tonic-gate */ 3138*0Sstevel@tonic-gate void 3139*0Sstevel@tonic-gate fmap_setup() 3140*0Sstevel@tonic-gate { 3141*0Sstevel@tonic-gate #if defined(MAP_ALIGN) 3142*0Sstevel@tonic-gate /* 3143*0Sstevel@tonic-gate * If MAP_ALIGN is set, the fm_addr has been seeded with an alignment 3144*0Sstevel@tonic-gate * value. Otherwise, if fm_addr is non-null it indicates a mapping that 3145*0Sstevel@tonic-gate * should now be freed. 3146*0Sstevel@tonic-gate */ 3147*0Sstevel@tonic-gate if (fmap->fm_maddr && ((fmap->fm_mflags & MAP_ALIGN) == 0)) 3148*0Sstevel@tonic-gate (void) munmap((caddr_t)fmap->fm_maddr, fmap->fm_msize); 3149*0Sstevel@tonic-gate 3150*0Sstevel@tonic-gate /* 3151*0Sstevel@tonic-gate * Providing we haven't determined that this system doesn't support 3152*0Sstevel@tonic-gate * MAP_ALIGN, initialize the mapping address with the default segment 3153*0Sstevel@tonic-gate * alignment. 3154*0Sstevel@tonic-gate */ 3155*0Sstevel@tonic-gate if ((rtld_flags2 & RT_FL2_NOMALIGN) == 0) { 3156*0Sstevel@tonic-gate fmap->fm_maddr = (char *)M_SEGM_ALIGN; 3157*0Sstevel@tonic-gate fmap->fm_mflags = MAP_PRIVATE | MAP_ALIGN; 3158*0Sstevel@tonic-gate } else { 3159*0Sstevel@tonic-gate fmap->fm_maddr = 0; 3160*0Sstevel@tonic-gate fmap->fm_mflags = MAP_PRIVATE; 3161*0Sstevel@tonic-gate } 3162*0Sstevel@tonic-gate #else 3163*0Sstevel@tonic-gate if (fmap->fm_maddr) 3164*0Sstevel@tonic-gate (void) munmap((caddr_t)fmap->fm_maddr, fmap->fm_msize); 3165*0Sstevel@tonic-gate fmap->fm_maddr = 0; 3166*0Sstevel@tonic-gate fmap->fm_mflags = MAP_PRIVATE; 3167*0Sstevel@tonic-gate #endif 3168*0Sstevel@tonic-gate 3169*0Sstevel@tonic-gate fmap->fm_msize = syspagsz; 3170*0Sstevel@tonic-gate fmap->fm_hwptr = 0; 3171*0Sstevel@tonic-gate } 3172*0Sstevel@tonic-gate 3173*0Sstevel@tonic-gate /* 3174*0Sstevel@tonic-gate * Generic cleanup routine called prior to returning control to the user. 3175*0Sstevel@tonic-gate * Insures that any ld.so.1 specific file descriptors or temporary mapping are 3176*0Sstevel@tonic-gate * released, and any locks dropped. 3177*0Sstevel@tonic-gate */ 3178*0Sstevel@tonic-gate void 3179*0Sstevel@tonic-gate leave(Lm_list * lml) 3180*0Sstevel@tonic-gate { 3181*0Sstevel@tonic-gate /* 3182*0Sstevel@tonic-gate * Alert the debuggers that the link-maps are consistent. 3183*0Sstevel@tonic-gate */ 3184*0Sstevel@tonic-gate if (lml) 3185*0Sstevel@tonic-gate rd_event(lml, RD_DLACTIVITY, RT_CONSISTENT); 3186*0Sstevel@tonic-gate 3187*0Sstevel@tonic-gate if (dz_fd != FD_UNAVAIL) { 3188*0Sstevel@tonic-gate (void) close(dz_fd); 3189*0Sstevel@tonic-gate dz_fd = FD_UNAVAIL; 3190*0Sstevel@tonic-gate } 3191*0Sstevel@tonic-gate 3192*0Sstevel@tonic-gate if (pr_fd != FD_UNAVAIL) { 3193*0Sstevel@tonic-gate (void) close(pr_fd); 3194*0Sstevel@tonic-gate pr_fd = FD_UNAVAIL; 3195*0Sstevel@tonic-gate } 3196*0Sstevel@tonic-gate 3197*0Sstevel@tonic-gate if (nu_fd != FD_UNAVAIL) { 3198*0Sstevel@tonic-gate (void) close(nu_fd); 3199*0Sstevel@tonic-gate nu_fd = FD_UNAVAIL; 3200*0Sstevel@tonic-gate } 3201*0Sstevel@tonic-gate 3202*0Sstevel@tonic-gate fmap_setup(); 3203*0Sstevel@tonic-gate 3204*0Sstevel@tonic-gate /* 3205*0Sstevel@tonic-gate * Reinitialize error message pointer, and any overflow indication. 3206*0Sstevel@tonic-gate */ 3207*0Sstevel@tonic-gate nextptr = errbuf; 3208*0Sstevel@tonic-gate prevptr = 0; 3209*0Sstevel@tonic-gate 3210*0Sstevel@tonic-gate /* 3211*0Sstevel@tonic-gate * Don't drop our lock if we are running on our link-map list as 3212*0Sstevel@tonic-gate * there's little point in doing so since we are single-threaded. 3213*0Sstevel@tonic-gate * 3214*0Sstevel@tonic-gate * LML_FLG_HOLDLOCK is set for: 3215*0Sstevel@tonic-gate * *) The ld.so.1's link-map list. 3216*0Sstevel@tonic-gate * *) The auditor's link-map if the environment is 3217*0Sstevel@tonic-gate * libc/libthread un-unified. 3218*0Sstevel@tonic-gate */ 3219*0Sstevel@tonic-gate if (lml && (lml->lm_flags & LML_FLG_HOLDLOCK)) 3220*0Sstevel@tonic-gate return; 3221*0Sstevel@tonic-gate 3222*0Sstevel@tonic-gate if (rt_bind_clear(0) & THR_FLG_RTLD) { 3223*0Sstevel@tonic-gate (void) rt_mutex_unlock(&rtldlock); 3224*0Sstevel@tonic-gate (void) rt_bind_clear(THR_FLG_RTLD); 3225*0Sstevel@tonic-gate } 3226*0Sstevel@tonic-gate } 3227*0Sstevel@tonic-gate 3228*0Sstevel@tonic-gate int 3229*0Sstevel@tonic-gate callable(Rt_map * clmp, Rt_map * dlmp, Grp_hdl * ghp) 3230*0Sstevel@tonic-gate { 3231*0Sstevel@tonic-gate Alist * calp, * dalp; 3232*0Sstevel@tonic-gate Aliste cnt1, cnt2; 3233*0Sstevel@tonic-gate Grp_hdl ** ghpp1, ** ghpp2; 3234*0Sstevel@tonic-gate 3235*0Sstevel@tonic-gate /* 3236*0Sstevel@tonic-gate * An object can always find symbols within itself. 3237*0Sstevel@tonic-gate */ 3238*0Sstevel@tonic-gate if (clmp == dlmp) 3239*0Sstevel@tonic-gate return (1); 3240*0Sstevel@tonic-gate 3241*0Sstevel@tonic-gate /* 3242*0Sstevel@tonic-gate * Don't allow an object to bind to an object that is being deleted 3243*0Sstevel@tonic-gate * unless the binder is also being deleted. 3244*0Sstevel@tonic-gate */ 3245*0Sstevel@tonic-gate if ((FLAGS(dlmp) & FLG_RT_DELETE) && 3246*0Sstevel@tonic-gate ((FLAGS(clmp) & FLG_RT_DELETE) == 0)) 3247*0Sstevel@tonic-gate return (0); 3248*0Sstevel@tonic-gate 3249*0Sstevel@tonic-gate /* 3250*0Sstevel@tonic-gate * An object with world access can always bind to an object with global 3251*0Sstevel@tonic-gate * visibility. 3252*0Sstevel@tonic-gate */ 3253*0Sstevel@tonic-gate if ((MODE(clmp) & RTLD_WORLD) && (MODE(dlmp) & RTLD_GLOBAL)) 3254*0Sstevel@tonic-gate return (1); 3255*0Sstevel@tonic-gate 3256*0Sstevel@tonic-gate /* 3257*0Sstevel@tonic-gate * An object with local access can only bind to an object that is a 3258*0Sstevel@tonic-gate * member of the same group. 3259*0Sstevel@tonic-gate */ 3260*0Sstevel@tonic-gate if (((MODE(clmp) & RTLD_GROUP) == 0) || 3261*0Sstevel@tonic-gate ((calp = GROUPS(clmp)) == 0) || ((dalp = GROUPS(dlmp)) == 0)) 3262*0Sstevel@tonic-gate return (0); 3263*0Sstevel@tonic-gate 3264*0Sstevel@tonic-gate /* 3265*0Sstevel@tonic-gate * Traverse the list of groups the caller is a part of. 3266*0Sstevel@tonic-gate */ 3267*0Sstevel@tonic-gate for (ALIST_TRAVERSE(calp, cnt1, ghpp1)) { 3268*0Sstevel@tonic-gate /* 3269*0Sstevel@tonic-gate * If we're testing for the ability of two objects to bind to 3270*0Sstevel@tonic-gate * each other regardless of a specific group, ignore that group. 3271*0Sstevel@tonic-gate */ 3272*0Sstevel@tonic-gate if (ghp && (*ghpp1 == ghp)) 3273*0Sstevel@tonic-gate continue; 3274*0Sstevel@tonic-gate 3275*0Sstevel@tonic-gate /* 3276*0Sstevel@tonic-gate * Traverse the list of groups the destination is a part of. 3277*0Sstevel@tonic-gate */ 3278*0Sstevel@tonic-gate for (ALIST_TRAVERSE(dalp, cnt2, ghpp2)) { 3279*0Sstevel@tonic-gate if (*ghpp1 == *ghpp2) 3280*0Sstevel@tonic-gate return (1); 3281*0Sstevel@tonic-gate } 3282*0Sstevel@tonic-gate } 3283*0Sstevel@tonic-gate return (0); 3284*0Sstevel@tonic-gate } 3285*0Sstevel@tonic-gate 3286*0Sstevel@tonic-gate /* 3287*0Sstevel@tonic-gate * Initialize the environ symbol. Traditionally this is carried out by the crt 3288*0Sstevel@tonic-gate * code prior to jumping to main. However, init sections get fired before this 3289*0Sstevel@tonic-gate * variable is initialized, so ld.so.1 sets this directly from the AUX vector 3290*0Sstevel@tonic-gate * information. In addition, a process may have multiple link-maps (ld.so.1's 3291*0Sstevel@tonic-gate * debugging and preloading objects), and link auditing, and each may need an 3292*0Sstevel@tonic-gate * environ variable set. 3293*0Sstevel@tonic-gate * 3294*0Sstevel@tonic-gate * This routine is called after a relocation() pass, and thus provides for: 3295*0Sstevel@tonic-gate * 3296*0Sstevel@tonic-gate * o setting environ on the main link-map after the initial application and 3297*0Sstevel@tonic-gate * its dependencies have been established. Typically environ lives in the 3298*0Sstevel@tonic-gate * application (provided by its crt), but in older applications it might 3299*0Sstevel@tonic-gate * be in libc. Who knows what's expected of applications not built on 3300*0Sstevel@tonic-gate * Solaris. 3301*0Sstevel@tonic-gate * 3302*0Sstevel@tonic-gate * o after loading a new shared object. We can add shared objects to various 3303*0Sstevel@tonic-gate * link-maps, and any link-map dependencies requiring getopt() require 3304*0Sstevel@tonic-gate * their own environ. In addition, lazy loading might bring in the 3305*0Sstevel@tonic-gate * supplier of environ (libc) after the link-map has been established and 3306*0Sstevel@tonic-gate * other objects are present. 3307*0Sstevel@tonic-gate * 3308*0Sstevel@tonic-gate * This routine handles all these scenarios, without adding unnecessary overhead 3309*0Sstevel@tonic-gate * to ld.so.1. 3310*0Sstevel@tonic-gate */ 3311*0Sstevel@tonic-gate void 3312*0Sstevel@tonic-gate set_environ(Lm_list *lml) 3313*0Sstevel@tonic-gate { 3314*0Sstevel@tonic-gate Rt_map * dlmp; 3315*0Sstevel@tonic-gate Sym * sym; 3316*0Sstevel@tonic-gate Slookup sl; 3317*0Sstevel@tonic-gate uint_t binfo; 3318*0Sstevel@tonic-gate 3319*0Sstevel@tonic-gate sl.sl_name = MSG_ORIG(MSG_SYM_ENVIRON); 3320*0Sstevel@tonic-gate sl.sl_cmap = lml->lm_head; 3321*0Sstevel@tonic-gate sl.sl_imap = lml->lm_head; 3322*0Sstevel@tonic-gate sl.sl_hash = 0; 3323*0Sstevel@tonic-gate sl.sl_rsymndx = 0; 3324*0Sstevel@tonic-gate sl.sl_flags = LKUP_WEAK; 3325*0Sstevel@tonic-gate 3326*0Sstevel@tonic-gate if (sym = LM_LOOKUP_SYM(lml->lm_head)(&sl, &dlmp, &binfo)) { 3327*0Sstevel@tonic-gate char ** addr = (char **)sym->st_value; 3328*0Sstevel@tonic-gate 3329*0Sstevel@tonic-gate if (!(FLAGS(dlmp) & FLG_RT_FIXED)) 3330*0Sstevel@tonic-gate addr = (char **)((uintptr_t)addr + 3331*0Sstevel@tonic-gate (uintptr_t)ADDR(dlmp)); 3332*0Sstevel@tonic-gate *addr = (char *)environ; 3333*0Sstevel@tonic-gate lml->lm_flags |= LML_FLG_ENVIRON; 3334*0Sstevel@tonic-gate } 3335*0Sstevel@tonic-gate } 3336*0Sstevel@tonic-gate 3337*0Sstevel@tonic-gate /* 3338*0Sstevel@tonic-gate * Determine whether we have a secure executable. Uid and gid information 3339*0Sstevel@tonic-gate * can be passed to us via the aux vector, however if these values are -1 3340*0Sstevel@tonic-gate * then use the appropriate system call to obtain them. 3341*0Sstevel@tonic-gate * 3342*0Sstevel@tonic-gate * o If the user is the root they can do anything 3343*0Sstevel@tonic-gate * 3344*0Sstevel@tonic-gate * o If the real and effective uid's don't match, or the real and 3345*0Sstevel@tonic-gate * effective gid's don't match then this is determined to be a `secure' 3346*0Sstevel@tonic-gate * application. 3347*0Sstevel@tonic-gate * 3348*0Sstevel@tonic-gate * This function is called prior to any dependency processing (see _setup.c). 3349*0Sstevel@tonic-gate * Any secure setting will remain in effect for the life of the process. 3350*0Sstevel@tonic-gate */ 3351*0Sstevel@tonic-gate void 3352*0Sstevel@tonic-gate security(uid_t uid, uid_t euid, gid_t gid, gid_t egid, int auxflags) 3353*0Sstevel@tonic-gate { 3354*0Sstevel@tonic-gate #ifdef AT_SUN_AUXFLAGS 3355*0Sstevel@tonic-gate if (auxflags != -1) { 3356*0Sstevel@tonic-gate if ((auxflags & AF_SUN_SETUGID) != 0) 3357*0Sstevel@tonic-gate rtld_flags |= RT_FL_SECURE; 3358*0Sstevel@tonic-gate return; 3359*0Sstevel@tonic-gate } 3360*0Sstevel@tonic-gate #endif 3361*0Sstevel@tonic-gate if (uid == -1) 3362*0Sstevel@tonic-gate uid = getuid(); 3363*0Sstevel@tonic-gate if (uid) { 3364*0Sstevel@tonic-gate if (euid == -1) 3365*0Sstevel@tonic-gate euid = geteuid(); 3366*0Sstevel@tonic-gate if (uid != euid) 3367*0Sstevel@tonic-gate rtld_flags |= RT_FL_SECURE; 3368*0Sstevel@tonic-gate else { 3369*0Sstevel@tonic-gate if (gid == -1) 3370*0Sstevel@tonic-gate gid = getgid(); 3371*0Sstevel@tonic-gate if (egid == -1) 3372*0Sstevel@tonic-gate egid = getegid(); 3373*0Sstevel@tonic-gate if (gid != egid) 3374*0Sstevel@tonic-gate rtld_flags |= RT_FL_SECURE; 3375*0Sstevel@tonic-gate } 3376*0Sstevel@tonic-gate } 3377*0Sstevel@tonic-gate } 3378*0Sstevel@tonic-gate 3379*0Sstevel@tonic-gate /* 3380*0Sstevel@tonic-gate * _REENTRANT code gets errno redefined to a function so provide for return 3381*0Sstevel@tonic-gate * of the thread errno if applicable. This has no meaning in ld.so.1 which 3382*0Sstevel@tonic-gate * is basically singled threaded. Provide the interface for our dependencies. 3383*0Sstevel@tonic-gate */ 3384*0Sstevel@tonic-gate #undef errno 3385*0Sstevel@tonic-gate #pragma weak _private___errno = ___errno 3386*0Sstevel@tonic-gate int * 3387*0Sstevel@tonic-gate ___errno() 3388*0Sstevel@tonic-gate { 3389*0Sstevel@tonic-gate extern int errno; 3390*0Sstevel@tonic-gate 3391*0Sstevel@tonic-gate return (&errno); 3392*0Sstevel@tonic-gate } 3393*0Sstevel@tonic-gate 3394*0Sstevel@tonic-gate /* 3395*0Sstevel@tonic-gate * The interface with the c library which is supplied through libdl.so.1. 3396*0Sstevel@tonic-gate * A non-null argument allows a function pointer array to be passed to us which 3397*0Sstevel@tonic-gate * is used to re-initialize the linker libc table. 3398*0Sstevel@tonic-gate */ 3399*0Sstevel@tonic-gate void 3400*0Sstevel@tonic-gate _ld_libc(void * ptr) 3401*0Sstevel@tonic-gate { 3402*0Sstevel@tonic-gate get_lcinterface(_caller(caller(), CL_EXECDEF), (Lc_interface *)ptr); 3403*0Sstevel@tonic-gate } 3404*0Sstevel@tonic-gate 3405*0Sstevel@tonic-gate /* 3406*0Sstevel@tonic-gate * Determine whether a symbol name should be demangled. 3407*0Sstevel@tonic-gate */ 3408*0Sstevel@tonic-gate const char * 3409*0Sstevel@tonic-gate demangle(const char *name) 3410*0Sstevel@tonic-gate { 3411*0Sstevel@tonic-gate if (rtld_flags & RT_FL_DEMANGLE) 3412*0Sstevel@tonic-gate return (conv_sym_dem(name)); 3413*0Sstevel@tonic-gate else 3414*0Sstevel@tonic-gate return (name); 3415*0Sstevel@tonic-gate } 3416