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