Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include	<stdio.h>
     28 #include	<dlfcn.h>
     29 #include	<libelf.h>
     30 #include	<link.h>
     31 #include	<debug.h>
     32 #include	"msg.h"
     33 #include	"_libld.h"
     34 
     35 /*
     36  * Table which defines the default functions to be called by the library
     37  * SUPPORT (-S <libname>).  These functions can be redefined by the
     38  * ld_support_loadso() routine.
     39  */
     40 static Support_list support[LDS_NUM] = {
     41 	{MSG_ORIG(MSG_SUP_VERSION),	NULL},	/* LDS_VERSION */
     42 	{MSG_ORIG(MSG_SUP_INPUT_DONE),	NULL},	/* LDS_INPUT_DONE */
     43 #if	defined(_ELF64)
     44 	{MSG_ORIG(MSG_SUP_START_64),	NULL},	/* LDS_START */
     45 	{MSG_ORIG(MSG_SUP_ATEXIT_64),	NULL},	/* LDS_ATEXIT */
     46 	{MSG_ORIG(MSG_SUP_OPEN_64),	NULL},	/* LDS_OPEN */
     47 	{MSG_ORIG(MSG_SUP_FILE_64),	NULL},	/* LDS_FILE */
     48 	{MSG_ORIG(MSG_SUP_INSEC_64),	NULL},	/* LDS_INSEC */
     49 	{MSG_ORIG(MSG_SUP_SEC_64),	NULL}	/* LDS_SEC */
     50 #else	/* Elf32 */
     51 	{MSG_ORIG(MSG_SUP_START),	NULL},	/* LDS_START */
     52 	{MSG_ORIG(MSG_SUP_ATEXIT),	NULL},	/* LDS_ATEXIT */
     53 	{MSG_ORIG(MSG_SUP_OPEN),	NULL},	/* LDS_OPEN */
     54 	{MSG_ORIG(MSG_SUP_FILE),	NULL},	/* LDS_FILE */
     55 	{MSG_ORIG(MSG_SUP_INSEC),	NULL},	/* LDS_INSEC */
     56 	{MSG_ORIG(MSG_SUP_SEC),		NULL}	/* LDS_SEC */
     57 #endif
     58 };
     59 
     60 /*
     61  * Loads in a support shared object specified using the SGS_SUPPORT environment
     62  * variable or the -S ld option, and determines which interface functions are
     63  * provided by that object.
     64  */
     65 uintptr_t
     66 ld_sup_loadso(Ofl_desc *ofl, const char *obj)
     67 {
     68 	void	*handle, (*fptr)();
     69 	uint_t	interface, version = LD_SUP_VERSION1;
     70 
     71 	/*
     72 	 * Load the required support library.  If we are unable to load it fail
     73 	 * with a fatal error.
     74 	 */
     75 	if ((handle = dlopen(obj, (RTLD_LAZY | RTLD_FIRST))) == NULL) {
     76 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SUP_NOLOAD),
     77 		    obj, dlerror());
     78 		return (S_ERROR);
     79 	}
     80 
     81 	for (interface = 0; interface < LDS_NUM; interface++) {
     82 		Func_list	fl;
     83 
     84 		if ((fptr = (void (*)())dlsym(handle,
     85 		    support[interface].sup_name)) == NULL)
     86 			continue;
     87 
     88 		DBG_CALL(Dbg_support_load(ofl->ofl_lml, obj,
     89 		    support[interface].sup_name));
     90 
     91 		if (interface == LDS_VERSION) {
     92 			DBG_CALL(Dbg_support_action(ofl->ofl_lml, obj,
     93 			    support[LDS_VERSION].sup_name, LDS_VERSION, 0));
     94 
     95 			version = ((uint_t(*)())fptr)(LD_SUP_VCURRENT);
     96 
     97 			/*
     98 			 * If version is LD_SUP_VNONE, unload the support
     99 			 * library and act as if it was never requested.
    100 			 * This provides the support library with a mechanism
    101 			 * for opting out of the process.
    102 			 *
    103 			 * Note that this depends on LDS_VERSION being the
    104 			 * first item in support[]. If this were not true,
    105 			 * then other functions from the library might be
    106 			 * entered into the function lists, and unloading
    107 			 * the object would cause corruption.
    108 			 */
    109 			assert(LDS_VERSION == 0);
    110 			if (version == LD_SUP_VNONE) {
    111 				DBG_CALL(Dbg_support_vnone(ofl->ofl_lml,
    112 				    obj));
    113 				(void) dlclose(handle);
    114 				return (1);
    115 			}
    116 
    117 			/*
    118 			 * If the support library has a version higher
    119 			 * than we support, we are unable to accept it.
    120 			 */
    121 			if (version > LD_SUP_VCURRENT) {
    122 				eprintf(ofl->ofl_lml, ERR_FATAL,
    123 				    MSG_INTL(MSG_SUP_BADVERSION), obj,
    124 				    LD_SUP_VCURRENT, version);
    125 				(void) dlclose(handle);
    126 				return (S_ERROR);
    127 			}
    128 		}
    129 
    130 		fl.fl_obj = obj;
    131 		fl.fl_fptr = fptr;
    132 		fl.fl_version = version;
    133 		if (alist_append(&support[interface].sup_funcs, &fl,
    134 		    sizeof (Func_list), AL_CNT_SUPPORT) == NULL)
    135 			return (S_ERROR);
    136 	}
    137 	return (1);
    138 }
    139 
    140 /*
    141  * Wrapper routines for the ld support library calls.
    142  */
    143 void
    144 ld_sup_start(Ofl_desc *ofl, const Half etype, const char *caller)
    145 {
    146 	Func_list	*flp;
    147 	Aliste		idx;
    148 
    149 	for (ALIST_TRAVERSE(support[LDS_START].sup_funcs, idx, flp)) {
    150 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
    151 		    support[LDS_START].sup_name, LDS_START, ofl->ofl_name));
    152 		(*flp->fl_fptr)(ofl->ofl_name, etype, caller);
    153 	}
    154 }
    155 
    156 void
    157 ld_sup_atexit(Ofl_desc *ofl, int ecode)
    158 {
    159 	Func_list	*flp;
    160 	Aliste		idx;
    161 
    162 	for (ALIST_TRAVERSE(support[LDS_ATEXIT].sup_funcs, idx, flp)) {
    163 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
    164 		    support[LDS_ATEXIT].sup_name, LDS_ATEXIT, 0));
    165 		(*flp->fl_fptr)(ecode);
    166 	}
    167 }
    168 
    169 void
    170 ld_sup_open(Ofl_desc *ofl, const char **opath, const char **ofile, int *ofd,
    171     int flags, Elf **oelf, Elf *ref, size_t off, const Elf_Kind ekind)
    172 {
    173 	Func_list	*flp;
    174 	Aliste		idx;
    175 
    176 	for (ALIST_TRAVERSE(support[LDS_OPEN].sup_funcs, idx, flp)) {
    177 		const char	*npath = *opath;
    178 		const char	*nfile = *ofile;
    179 		Elf		*nelf = *oelf;
    180 		int		nfd = *ofd;
    181 		int		_flags = 0;
    182 
    183 		/*
    184 		 * This interface was introduced in VERSION3.  Only call this
    185 		 * function for libraries reporting support for version 3 or
    186 		 * above.
    187 		 */
    188 		if (flp->fl_version < LD_SUP_VERSION3)
    189 			continue;
    190 
    191 		if (!(flags & FLG_IF_CMDLINE))
    192 			_flags |= LD_SUP_DERIVED;
    193 		if (!(flags & FLG_IF_NEEDED))
    194 			_flags |= LD_SUP_INHERITED;
    195 		if (flags & FLG_IF_EXTRACT)
    196 			_flags |= LD_SUP_EXTRACTED;
    197 
    198 		/*
    199 		 * If the present object is an extracted archive member, make
    200 		 * sure the archive offset is reset so that the caller can
    201 		 * obtain an ELF descriptor to the same member (an elf_begin()
    202 		 * moves the offset to the next member).
    203 		 */
    204 		if (flags & FLG_IF_EXTRACT)
    205 			(void) elf_rand(ref, off);
    206 
    207 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
    208 		    support[LDS_OPEN].sup_name, LDS_OPEN, *opath));
    209 		(*flp->fl_fptr)(&npath, &nfile, &nfd, _flags, &nelf, ref, off,
    210 		    ekind);
    211 
    212 		/*
    213 		 * If the file descriptor, ELF descriptor, or file names have
    214 		 * been modified, then diagnose the differences and return the
    215 		 * new data.  As a basic test, make sure the support library
    216 		 * hasn't nulled out data ld(1) will try and dereference.
    217 		 */
    218 		if ((npath != *opath) || (nfd != *ofd) || (nelf != *oelf)) {
    219 			Dbg_file_modified(ofl->ofl_lml, flp->fl_obj, *opath,
    220 			    npath, *ofd, nfd, *oelf, nelf);
    221 			if (npath)
    222 				*opath = npath;
    223 			if (nfile)
    224 				*ofile = nfile;
    225 			*ofd = nfd;
    226 			*oelf = nelf;
    227 		}
    228 	}
    229 }
    230 
    231 void
    232 ld_sup_file(Ofl_desc *ofl, const char *ifile, const Elf_Kind ekind, int flags,
    233     Elf *elf)
    234 {
    235 	Func_list	*flp;
    236 	Aliste		idx;
    237 
    238 	for (ALIST_TRAVERSE(support[LDS_FILE].sup_funcs, idx, flp)) {
    239 		int	_flags = 0;
    240 
    241 		if (!(flags & FLG_IF_CMDLINE))
    242 			_flags |= LD_SUP_DERIVED;
    243 		if (!(flags & FLG_IF_NEEDED))
    244 			_flags |= LD_SUP_INHERITED;
    245 		if (flags & FLG_IF_EXTRACT)
    246 			_flags |= LD_SUP_EXTRACTED;
    247 
    248 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
    249 		    support[LDS_FILE].sup_name, LDS_FILE, ifile));
    250 		(*flp->fl_fptr)(ifile, ekind, _flags, elf);
    251 	}
    252 }
    253 
    254 uintptr_t
    255 ld_sup_input_section(Ofl_desc *ofl, Ifl_desc *ifl, const char *sname,
    256     Shdr **oshdr, Word ndx, Elf_Scn *scn, Elf *elf)
    257 {
    258 	Func_list	*flp;
    259 	Aliste		idx;
    260 	uint_t		flags = 0;
    261 	Elf_Data	*data = NULL;
    262 
    263 	for (ALIST_TRAVERSE(support[LDS_INSEC].sup_funcs, idx, flp)) {
    264 		Shdr	*nshdr = *oshdr;
    265 
    266 		/*
    267 		 * This interface was introduced in VERSION2.  Only call this
    268 		 * function for libraries reporting support for version 2 or
    269 		 * above.
    270 		 */
    271 		if (flp->fl_version < LD_SUP_VERSION2)
    272 			continue;
    273 
    274 		if ((data == NULL) &&
    275 		    ((data = elf_getdata(scn, NULL)) == NULL)) {
    276 			eprintf(ofl->ofl_lml, ERR_ELF,
    277 			    MSG_INTL(MSG_ELF_GETDATA), ifl->ifl_name);
    278 			ofl->ofl_flags |= FLG_OF_FATAL;
    279 			return (S_ERROR);
    280 		}
    281 
    282 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
    283 		    support[LDS_INSEC].sup_name, LDS_INSEC, sname));
    284 		(*flp->fl_fptr)(sname, &nshdr, ndx, data, elf, &flags);
    285 
    286 		/*
    287 		 * If the section header has been re-allocated (known to occur
    288 		 * with libCCexcept.so), then diagnose the section header
    289 		 * difference and return the new section header.
    290 		 */
    291 		if (nshdr != *oshdr) {
    292 			Dbg_shdr_modified(ofl->ofl_lml, flp->fl_obj,
    293 			    ifl->ifl_ehdr->e_ident[EI_OSABI],
    294 			    ifl->ifl_ehdr->e_machine, ndx, *oshdr, nshdr,
    295 			    sname);
    296 			*oshdr = nshdr;
    297 		}
    298 	}
    299 	return (0);
    300 }
    301 
    302 void
    303 ld_sup_section(Ofl_desc *ofl, const char *scn, Shdr *shdr, Word ndx,
    304     Elf_Data *data, Elf *elf)
    305 {
    306 	Func_list	*flp;
    307 	Aliste		idx;
    308 
    309 	for (ALIST_TRAVERSE(support[LDS_SEC].sup_funcs, idx, flp)) {
    310 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
    311 		    support[LDS_SEC].sup_name, LDS_SEC, scn));
    312 		(*flp->fl_fptr)(scn, shdr, ndx, data, elf);
    313 	}
    314 }
    315 
    316 void
    317 ld_sup_input_done(Ofl_desc *ofl)
    318 {
    319 	Func_list	*flp;
    320 	Aliste		idx;
    321 	uint_t		flags = 0;
    322 
    323 	for (ALIST_TRAVERSE(support[LDS_INPUT_DONE].sup_funcs, idx, flp)) {
    324 		/*
    325 		 * This interface was introduced in VERSION2.  Only call this
    326 		 * function for libraries reporting support for version 2 or
    327 		 * above.
    328 		 */
    329 		if (flp->fl_version < LD_SUP_VERSION2)
    330 			continue;
    331 
    332 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
    333 		    support[LDS_INPUT_DONE].sup_name, LDS_INPUT_DONE, 0));
    334 		(*flp->fl_fptr)(&flags);
    335 	}
    336 }
    337