xref: /illumos-gate/usr/src/cmd/sgs/libld/common/support.c (revision bb25c06c)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include	<stdio.h>
30 #include	<dlfcn.h>
31 #include	<libelf.h>
32 #include	<link.h>
33 #include	<debug.h>
34 #include	"msg.h"
35 #include	"_libld.h"
36 
37 /*
38  * Table which defines the default functions to be called by the library
39  * SUPPORT (-S <libname>).  These functions can be redefined by the
40  * ld_support_loadso() routine.
41  */
42 static Support_list support[LDS_NUM] = {
43 	{MSG_ORIG(MSG_SUP_VERSION),	{ 0, 0 }},	/* LDS_VERSION */
44 	{MSG_ORIG(MSG_SUP_INPUT_DONE),	{ 0, 0 }},	/* LDS_INPUT_DONE */
45 #if	defined(_ELF64)
46 	{MSG_ORIG(MSG_SUP_START_64),	{ 0, 0 }},	/* LDS_START */
47 	{MSG_ORIG(MSG_SUP_ATEXIT_64),	{ 0, 0 }},	/* LDS_ATEXIT */
48 	{MSG_ORIG(MSG_SUP_OPEN_64),	{ 0, 0 }},	/* LDS_OPEN */
49 	{MSG_ORIG(MSG_SUP_FILE_64),	{ 0, 0 }},	/* LDS_FILE */
50 	{MSG_ORIG(MSG_SUP_INSEC_64),	{ 0, 0 }},	/* LDS_INSEC */
51 	{MSG_ORIG(MSG_SUP_SEC_64),	{ 0, 0 }}	/* LDS_SEC */
52 #else	/* Elf32 */
53 	{MSG_ORIG(MSG_SUP_START),	{ 0, 0 }},	/* LDS_START */
54 	{MSG_ORIG(MSG_SUP_ATEXIT),	{ 0, 0 }},	/* LDS_ATEXIT */
55 	{MSG_ORIG(MSG_SUP_OPEN),	{ 0, 0 }},	/* LDS_OPEN */
56 	{MSG_ORIG(MSG_SUP_FILE),	{ 0, 0 }},	/* LDS_FILE */
57 	{MSG_ORIG(MSG_SUP_INSEC),	{ 0, 0 }},	/* LDS_INSEC */
58 	{MSG_ORIG(MSG_SUP_SEC),		{ 0, 0 }}	/* LDS_SEC */
59 #endif
60 };
61 
62 /*
63  * Loads in a support shared object specified using the SGS_SUPPORT environment
64  * variable or the -S ld option, and determines which interface functions are
65  * provided by that object.
66  */
67 uintptr_t
68 ld_sup_loadso(Ofl_desc *ofl, const char *obj)
69 {
70 	void		*handle, (*fptr)();
71 	Func_list	*flp;
72 	uint_t		interface, version = LD_SUP_VERSION1;
73 
74 	/*
75 	 * Load the required support library.  If we are unable to load it fail
76 	 * with a fatal error.
77 	 */
78 	if ((handle = dlopen(obj, (RTLD_LAZY | RTLD_FIRST))) == NULL) {
79 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SUP_NOLOAD),
80 		    obj, dlerror());
81 		return (S_ERROR);
82 	}
83 
84 	for (interface = 0; interface < LDS_NUM; interface++) {
85 		if ((fptr = (void (*)())dlsym(handle,
86 		    support[interface].sup_name)) == NULL)
87 			continue;
88 
89 		if ((flp = libld_malloc(sizeof (Func_list))) == NULL)
90 			return (S_ERROR);
91 
92 		flp->fl_obj = obj;
93 		flp->fl_fptr = fptr;
94 		DBG_CALL(Dbg_support_load(ofl->ofl_lml, obj,
95 		    support[interface].sup_name));
96 
97 		if (interface == LDS_VERSION) {
98 			DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
99 			    support[LDS_VERSION].sup_name, LDS_VERSION, 0));
100 
101 			version = ((uint_t(*)())flp->fl_fptr)(LD_SUP_VCURRENT);
102 			if ((version == LD_SUP_VNONE) ||
103 			    (version > LD_SUP_VCURRENT)) {
104 				eprintf(ofl->ofl_lml, ERR_FATAL,
105 				    MSG_INTL(MSG_SUP_BADVERSION),
106 				    LD_SUP_VCURRENT, version);
107 				(void) dlclose(handle);
108 				return (S_ERROR);
109 			}
110 		}
111 		flp->fl_version = version;
112 		if (list_appendc(&support[interface].sup_funcs, flp) == 0)
113 			return (S_ERROR);
114 	}
115 	return (1);
116 }
117 
118 /*
119  * Wrapper routines for the ld support library calls.
120  */
121 void
122 ld_sup_start(Ofl_desc *ofl, const Half etype, const char *caller)
123 {
124 	Func_list	*flp;
125 	Listnode	*lnp;
126 
127 	for (LIST_TRAVERSE(&support[LDS_START].sup_funcs, lnp, flp)) {
128 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
129 		    support[LDS_START].sup_name, LDS_START, ofl->ofl_name));
130 		(*flp->fl_fptr)(ofl->ofl_name, etype, caller);
131 	}
132 }
133 
134 void
135 ld_sup_atexit(Ofl_desc *ofl, int ecode)
136 {
137 	Func_list	*flp;
138 	Listnode	*lnp;
139 
140 	for (LIST_TRAVERSE(&support[LDS_ATEXIT].sup_funcs, lnp, flp)) {
141 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
142 		    support[LDS_ATEXIT].sup_name, LDS_ATEXIT, 0));
143 		(*flp->fl_fptr)(ecode);
144 	}
145 }
146 
147 void
148 ld_sup_open(Ofl_desc *ofl, const char **opath, const char **ofile, int *ofd,
149     int flags, Elf **oelf, Elf *ref, size_t off, const Elf_Kind ekind)
150 {
151 	Func_list	*flp;
152 	Listnode	*lnp;
153 	const char	*npath = *opath;
154 	const char	*nfile = *ofile;
155 	Elf		*nelf = *oelf;
156 	int		nfd = *ofd;
157 
158 	for (LIST_TRAVERSE(&support[LDS_OPEN].sup_funcs, lnp, flp)) {
159 		int	_flags = 0;
160 
161 		/*
162 		 * This interface was introduced in VERSION3.  Only call this
163 		 * function for libraries reporting support for version 3 or
164 		 * above.
165 		 */
166 		if (flp->fl_version < LD_SUP_VERSION3)
167 			continue;
168 
169 		if (!(flags & FLG_IF_CMDLINE))
170 			_flags |= LD_SUP_DERIVED;
171 		if (!(flags & FLG_IF_NEEDED))
172 			_flags |= LD_SUP_INHERITED;
173 		if (flags & FLG_IF_EXTRACT)
174 			_flags |= LD_SUP_EXTRACTED;
175 
176 		/*
177 		 * If the present object is an extracted archive member, make
178 		 * sure the archive offset is reset so that the caller can
179 		 * obtain an ELF descriptor to the same member (an elf_begin()
180 		 * moves the offset to the next member).
181 		 */
182 		if (flags & FLG_IF_EXTRACT)
183 			(void) elf_rand(ref, off);
184 
185 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
186 		    support[LDS_OPEN].sup_name, LDS_OPEN, *opath));
187 		(*flp->fl_fptr)(&npath, &nfile, &nfd, _flags, &nelf, ref, off,
188 		    ekind);
189 	}
190 
191 	/*
192 	 * If the file descriptor, ELF descriptor, or file names have been
193 	 * modified, then diagnose the differences and return the new data.
194 	 * As a basic test, make sure the support library hasn't nulled out
195 	 * data ld(1) will try and dereference.
196 	 */
197 	if ((npath != *opath) || (nfd != *ofd) || (nelf != *oelf)) {
198 		Dbg_file_modified(ofl->ofl_lml, flp->fl_obj, *opath, npath,
199 		    *ofd, nfd, *oelf, nelf);
200 		if (npath)
201 			*opath = npath;
202 		if (nfile)
203 			*ofile = nfile;
204 		*ofd = nfd;
205 		*oelf = nelf;
206 	}
207 }
208 
209 void
210 ld_sup_file(Ofl_desc *ofl, const char *ifile, const Elf_Kind ekind, int flags,
211     Elf *elf)
212 {
213 	Func_list	*flp;
214 	Listnode	*lnp;
215 
216 	for (LIST_TRAVERSE(&support[LDS_FILE].sup_funcs, lnp, flp)) {
217 		int	_flags = 0;
218 
219 		if (!(flags & FLG_IF_CMDLINE))
220 			_flags |= LD_SUP_DERIVED;
221 		if (!(flags & FLG_IF_NEEDED))
222 			_flags |= LD_SUP_INHERITED;
223 		if (flags & FLG_IF_EXTRACT)
224 			_flags |= LD_SUP_EXTRACTED;
225 
226 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
227 		    support[LDS_FILE].sup_name, LDS_FILE, ifile));
228 		(*flp->fl_fptr)(ifile, ekind, _flags, elf);
229 	}
230 }
231 
232 uintptr_t
233 ld_sup_input_section(Ofl_desc *ofl, Ifl_desc *ifl, const char *sname,
234     Shdr **oshdr, Word ndx, Elf_Scn *scn, Elf *elf)
235 {
236 	Func_list	*flp;
237 	Listnode	*lnp;
238 	uint_t		flags = 0;
239 	Elf_Data	*data = NULL;
240 	Shdr		*nshdr = *oshdr;
241 
242 	for (LIST_TRAVERSE(&support[LDS_INSEC].sup_funcs, lnp, flp)) {
243 		/*
244 		 * This interface was introduced in VERSION2.  Only call this
245 		 * function for libraries reporting support for version 2 or
246 		 * above.
247 		 */
248 		if (flp->fl_version < LD_SUP_VERSION2)
249 			continue;
250 
251 		if ((data == NULL) &&
252 		    ((data = elf_getdata(scn, NULL)) == NULL)) {
253 			eprintf(ofl->ofl_lml, ERR_ELF,
254 			    MSG_INTL(MSG_ELF_GETDATA), ifl->ifl_name);
255 			ofl->ofl_flags |= FLG_OF_FATAL;
256 			return (S_ERROR);
257 		}
258 
259 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
260 		    support[LDS_INSEC].sup_name, LDS_INSEC, sname));
261 		(*flp->fl_fptr)(sname, &nshdr, ndx, data, elf, &flags);
262 	}
263 
264 	/*
265 	 * If the section header has been re-allocated (known to occur with
266 	 * libCCexcept.so), then diagnose the section header difference and
267 	 * return the new section header.
268 	 */
269 	if (nshdr != *oshdr) {
270 		Dbg_shdr_modified(ofl->ofl_lml, flp->fl_obj,
271 		    ifl->ifl_ehdr->e_machine, *oshdr, nshdr, sname);
272 		*oshdr = nshdr;
273 	}
274 	return (0);
275 }
276 
277 void
278 ld_sup_section(Ofl_desc *ofl, const char *scn, Shdr *shdr, Word ndx,
279     Elf_Data *data, Elf *elf)
280 {
281 	Func_list	*flp;
282 	Listnode	*lnp;
283 
284 	for (LIST_TRAVERSE(&support[LDS_SEC].sup_funcs, lnp, flp)) {
285 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
286 		    support[LDS_SEC].sup_name, LDS_SEC, scn));
287 		(*flp->fl_fptr)(scn, shdr, ndx, data, elf);
288 	}
289 }
290 
291 void
292 ld_sup_input_done(Ofl_desc *ofl)
293 {
294 	Func_list	*flp;
295 	Listnode	*lnp;
296 	uint_t		flags = 0;
297 
298 	for (LIST_TRAVERSE(&support[LDS_INPUT_DONE].sup_funcs, lnp, flp)) {
299 		/*
300 		 * This interface was introduced in VERSION2.  Only call this
301 		 * function for libraries reporting support for version 2 or
302 		 * above.
303 		 */
304 		if (flp->fl_version < LD_SUP_VERSION2)
305 			continue;
306 
307 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
308 		    support[LDS_INPUT_DONE].sup_name, LDS_INPUT_DONE, 0));
309 		(*flp->fl_fptr)(&flags);
310 	}
311 }
312