xref: /illumos-gate/usr/src/cmd/sgs/libld/common/support.c (revision 355b4669e025ff377602b6fc7caaf30dbc218371)
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_START64 */
47 	{MSG_ORIG(MSG_SUP_ATEXIT_64),	{ 0, 0 }},	/* LDS_ATEXIT64 */
48 	{MSG_ORIG(MSG_SUP_FILE_64),	{ 0, 0 }},	/* LDS_FILE64 */
49 	{MSG_ORIG(MSG_SUP_INP_SECTION_64), { 0, 0 }},	/* LDS_INP_SECTION64 */
50 	{MSG_ORIG(MSG_SUP_SECTION_64),	{ 0, 0 }}	/* LDS_SECTION64 */
51 #else	/* Elf32 */
52 	{MSG_ORIG(MSG_SUP_START),	{ 0, 0 }},	/* LDS_START */
53 	{MSG_ORIG(MSG_SUP_ATEXIT),	{ 0, 0 }},	/* LDS_ATEXIT */
54 	{MSG_ORIG(MSG_SUP_FILE),	{ 0, 0 }},	/* LDS_FILE */
55 	{MSG_ORIG(MSG_SUP_INP_SECTION),	{ 0, 0 }},	/* LDS_INP_SECTION */
56 	{MSG_ORIG(MSG_SUP_SECTION),	{ 0, 0 }}	/* LDS_SECTION */
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;
69 	void		(*fptr)();
70 	Func_list	*flp;
71 	int 		i;
72 	uint_t		ver_level;
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)) == NULL) {
79 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SUP_NOLOAD),
80 		    obj, dlerror());
81 		return (S_ERROR);
82 	}
83 
84 	ver_level = LD_SUP_VERSION1;
85 	for (i = 0; i < LDS_NUM; i++) {
86 		if (fptr = (void (*)())dlsym(handle, support[i].sup_name)) {
87 
88 			if ((flp = libld_malloc(sizeof (Func_list))) == NULL)
89 				return (S_ERROR);
90 
91 			flp->fl_obj = obj;
92 			flp->fl_fptr = fptr;
93 			DBG_CALL(Dbg_support_load(ofl->ofl_lml, obj,
94 			    support[i].sup_name));
95 
96 			if (i == LDS_VERSION) {
97 				DBG_CALL(Dbg_support_action(ofl->ofl_lml,
98 				    flp->fl_obj, support[LDS_VERSION].sup_name,
99 				    LDS_VERSION, 0));
100 				ver_level = ((uint_t(*)())
101 				    flp->fl_fptr)(LD_SUP_VCURRENT);
102 				if ((ver_level == LD_SUP_VNONE) ||
103 				    (ver_level > LD_SUP_VCURRENT)) {
104 					eprintf(ofl->ofl_lml, ERR_FATAL,
105 					    MSG_INTL(MSG_SUP_BADVERSION),
106 					    LD_SUP_VCURRENT, ver_level);
107 					(void) dlclose(handle);
108 					return (S_ERROR);
109 				}
110 
111 			}
112 			flp->fl_version = ver_level;
113 			if (list_appendc(&support[i].sup_funcs, flp) == 0)
114 				return (S_ERROR);
115 		}
116 	}
117 	return (1);
118 }
119 
120 /*
121  * Wrapper routines for the ld support library calls.
122  */
123 void
124 ld_sup_start(Ofl_desc *ofl, const Half etype, const char *caller)
125 {
126 	Func_list	*flp;
127 	Listnode	*lnp;
128 
129 	for (LIST_TRAVERSE(&support[LDS_START].sup_funcs, lnp, flp)) {
130 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
131 		    support[LDS_START].sup_name, LDS_START, ofl->ofl_name));
132 		(*flp->fl_fptr)(ofl->ofl_name, etype, caller);
133 	}
134 }
135 
136 void
137 ld_sup_atexit(Ofl_desc *ofl, int ecode)
138 {
139 	Func_list	*flp;
140 	Listnode	*lnp;
141 
142 	for (LIST_TRAVERSE(&support[LDS_ATEXIT].sup_funcs, lnp, flp)) {
143 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
144 		    support[LDS_ATEXIT].sup_name, LDS_ATEXIT, 0));
145 		(*flp->fl_fptr)(ecode);
146 	}
147 }
148 
149 void
150 ld_sup_file(Ofl_desc *ofl, const char *ifile, const Elf_Kind ekind, int flags,
151     Elf *elf)
152 {
153 	Func_list	*flp;
154 	Listnode	*lnp;
155 
156 	for (LIST_TRAVERSE(&support[LDS_FILE].sup_funcs, lnp, flp)) {
157 		int	_flags = 0;
158 
159 		if (!(flags & FLG_IF_CMDLINE))
160 			_flags |= LD_SUP_DERIVED;
161 		if (!(flags & FLG_IF_NEEDED))
162 			_flags |= LD_SUP_INHERITED;
163 		if (flags & FLG_IF_EXTRACT)
164 			_flags |= LD_SUP_EXTRACTED;
165 
166 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
167 		    support[LDS_FILE].sup_name, LDS_FILE, ifile));
168 		(*flp->fl_fptr)(ifile, ekind, _flags, elf);
169 	}
170 }
171 
172 uintptr_t
173 ld_sup_input_section(Ofl_desc * ofl, const char *scnname, Shdr **shdr, Word ndx,
174     const char *file, Elf_Scn *scn, Elf *elf)
175 {
176 	Func_list	*flp;
177 	Listnode	*lnp;
178 	uint_t		flags = 0;
179 	Elf_Data	*data = NULL;
180 
181 	for (LIST_TRAVERSE(&support[LDS_INP_SECTION].sup_funcs, lnp, flp)) {
182 		/*
183 		 * This interface was introduced in VERSION2 - so only call it
184 		 * for libraries reporting support for * version 2 or above.
185 		 */
186 		if (flp->fl_version < LD_SUP_VERSION2)
187 			continue;
188 		if ((data == NULL) &&
189 		    ((data = elf_getdata(scn, NULL)) == NULL)) {
190 			eprintf(ofl->ofl_lml, ERR_ELF,
191 			    MSG_INTL(MSG_ELF_GETDATA), file);
192 			ofl->ofl_flags |= FLG_OF_FATAL;
193 			return (S_ERROR);
194 		}
195 
196 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
197 		    support[LDS_INP_SECTION].sup_name, LDS_INP_SECTION,
198 		    scnname));
199 		(*flp->fl_fptr)(scnname, shdr, ndx, data, elf, &flags);
200 	}
201 	return (0);
202 }
203 
204 void
205 ld_sup_section(Ofl_desc *ofl, const char *scn, Shdr *shdr, Word ndx,
206     Elf_Data *data, Elf *elf)
207 {
208 	Func_list	*flp;
209 	Listnode	*lnp;
210 
211 	for (LIST_TRAVERSE(&support[LDS_SECTION].sup_funcs, lnp, flp)) {
212 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
213 		    support[LDS_SECTION].sup_name, LDS_SECTION, scn));
214 		(*flp->fl_fptr)(scn, shdr, ndx, data, elf);
215 	}
216 }
217 
218 void
219 ld_sup_input_done(Ofl_desc *ofl)
220 {
221 	Func_list	*flp;
222 	Listnode	*lnp;
223 	uint_t		flags = 0;
224 
225 	for (LIST_TRAVERSE(&support[LDS_INPUT_DONE].sup_funcs, lnp, flp)) {
226 		/*
227 		 * This interface was introduced in VERSION2 - so only call it
228 		 * for libraries reporting support for version 2 or above.
229 		 */
230 		if (flp->fl_version < LD_SUP_VERSION2)
231 			continue;
232 		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
233 		    support[LDS_INPUT_DONE].sup_name, LDS_INPUT_DONE, 0));
234 		(*flp->fl_fptr)(&flags);
235 	}
236 }
237