xref: /illumos-gate/usr/src/cmd/sgs/libld/common/support.c (revision 88f8b78a88cbdc6d8c1af5c3e54bc49d25095c98)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	Copyright (c) 2001 by Sun Microsystems, Inc.
24  *	All rights reserved.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include	<stdio.h>
29 #include	<dlfcn.h>
30 #include	<libelf.h>
31 #include	<link.h>
32 #include	"debug.h"
33 #include	"msg.h"
34 #include	"_libld.h"
35 
36 
37 
38 /*
39  * Table which defines the default functions to be called by the library
40  * SUPPORT (-S <libname>).  These functions can be redefined by the
41  * ld_support_loadso() routine.
42  */
43 static Support_list support[LDS_NUM] = {
44 	{MSG_ORIG(MSG_SUP_VERSION),	{ 0, 0 }},	/* LDS_VERSION */
45 	{MSG_ORIG(MSG_SUP_INPUT_DONE),	{ 0, 0 }},	/* LDS_INPUT_DONE */
46 #ifdef _ELF64
47 	{MSG_ORIG(MSG_SUP_START_64),	{ 0, 0 }},	/* LDS_START64 */
48 	{MSG_ORIG(MSG_SUP_ATEXIT_64),	{ 0, 0 }},	/* LDS_ATEXIT64 */
49 	{MSG_ORIG(MSG_SUP_FILE_64),	{ 0, 0 }},	/* LDS_FILE64 */
50 	{MSG_ORIG(MSG_SUP_INP_SECTION_64), { 0, 0 }},	/* LDS_INP_SECTION64 */
51 	{MSG_ORIG(MSG_SUP_SECTION_64),	{ 0, 0 }}	/* LDS_SECTION64 */
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_FILE),	{ 0, 0 }},	/* LDS_FILE */
56 	{MSG_ORIG(MSG_SUP_INP_SECTION),	{ 0, 0 }},	/* LDS_INP_SECTION */
57 	{MSG_ORIG(MSG_SUP_SECTION),	{ 0, 0 }}	/* LDS_SECTION */
58 #endif
59 };
60 
61 /*
62  * Loads in a support shared object specified using the SGS_SUPPORT environment
63  * variable or the -S ld option, and determines which interface functions are
64  * provided by that object.
65  *
66  * return values for ld_support_loadso:
67  *	1 -	shared object loaded sucessfully
68  *	S_ERROR - aww, damn!
69  */
70 uintptr_t
71 ld_support_loadso(const char *obj)
72 {
73 	void		*handle;
74 	void		(*fptr)();
75 	Func_list	*flp;
76 	int 		i;
77 	uint_t		ver_level;
78 
79 	/*
80 	 * Load the required support library.  If we are unable to load it fail
81 	 * with a fatal error.
82 	 */
83 	if ((handle = dlopen(obj, RTLD_LAZY)) == NULL) {
84 		eprintf(ERR_FATAL, MSG_INTL(MSG_SUP_NOLOAD), obj, dlerror());
85 		return (S_ERROR);
86 	}
87 
88 	ver_level = LD_SUP_VERSION1;
89 	for (i = 0; i < LDS_NUM; i++) {
90 		if (fptr = (void (*)())dlsym(handle, support[i].sup_name)) {
91 
92 			if ((flp = (Func_list *)
93 			    libld_malloc(sizeof (Func_list))) == NULL)
94 				return (S_ERROR);
95 
96 			flp->fl_obj = obj;
97 			flp->fl_fptr = fptr;
98 			DBG_CALL(Dbg_support_load(obj, support[i].sup_name));
99 			if (i == LDS_VERSION) {
100 				DBG_CALL(Dbg_support_action(flp->fl_obj,
101 				    support[LDS_VERSION].sup_name,
102 				    LDS_VERSION, 0));
103 				ver_level = ((uint_t(*)())
104 				    flp->fl_fptr)(LD_SUP_VCURRENT);
105 				if ((ver_level == LD_SUP_VNONE) ||
106 				    (ver_level > LD_SUP_VCURRENT)) {
107 					eprintf(ERR_FATAL,
108 						MSG_INTL(MSG_SUP_BADVERSION),
109 						LD_SUP_VCURRENT,
110 						ver_level);
111 					(void) dlclose(handle);
112 					return (S_ERROR);
113 				}
114 
115 			}
116 			flp->fl_version = ver_level;
117 			if (list_appendc(&support[i].sup_funcs, flp) == 0)
118 				return (S_ERROR);
119 		}
120 	}
121 	return (1);
122 }
123 
124 
125 /*
126  * Wrapper routines for the ld support library calls.
127  */
128 void
129 lds_start(const char *ofile, const Half etype, const char *caller)
130 {
131 	Func_list	*flp;
132 	Listnode	*lnp;
133 
134 	for (LIST_TRAVERSE(&support[LDS_START].sup_funcs, lnp, flp)) {
135 		DBG_CALL(Dbg_support_action(flp->fl_obj,
136 		    support[LDS_START].sup_name, LDS_START, ofile));
137 		(*flp->fl_fptr)(ofile, etype, caller);
138 	}
139 }
140 
141 
142 void
143 lds_atexit(int exit_code)
144 {
145 	Func_list	*flp;
146 	Listnode	*lnp;
147 
148 	for (LIST_TRAVERSE(&support[LDS_ATEXIT].sup_funcs, lnp, flp)) {
149 		DBG_CALL(Dbg_support_action(flp->fl_obj,
150 		    support[LDS_ATEXIT].sup_name, LDS_ATEXIT, 0));
151 		(*flp->fl_fptr)(exit_code);
152 	}
153 }
154 
155 
156 void
157 lds_file(const char *ifile, const Elf_Kind ekind, int flags, Elf *elf)
158 {
159 	Func_list	*flp;
160 	Listnode	*lnp;
161 
162 	for (LIST_TRAVERSE(&support[LDS_FILE].sup_funcs, lnp, flp)) {
163 		int	_flags = 0;
164 
165 		if (!(flags & FLG_IF_CMDLINE))
166 			_flags |= LD_SUP_DERIVED;
167 		if (!(flags & FLG_IF_NEEDED))
168 			_flags |= LD_SUP_INHERITED;
169 		if (flags & FLG_IF_EXTRACT)
170 			_flags |= LD_SUP_EXTRACTED;
171 
172 		DBG_CALL(Dbg_support_action(flp->fl_obj,
173 		    support[LDS_FILE].sup_name, LDS_FILE, ifile));
174 		(*flp->fl_fptr)(ifile, ekind, _flags, elf);
175 	}
176 }
177 
178 uintptr_t
179 lds_input_section(const char *scnname, Shdr **shdr, Word ndx,
180     const char *file, Elf_Scn *scn, Elf *elf, Ofl_desc *ofl)
181 {
182 	Func_list	*flp;
183 	Listnode	*lnp;
184 	uint_t		flags = 0;
185 	Elf_Data	*data = NULL;
186 
187 	for (LIST_TRAVERSE(&support[LDS_INP_SECTION].sup_funcs, lnp, flp)) {
188 		/*
189 		 * This interface was introduced in VERSION2 - so only
190 		 * call it for libraries reporting support for
191 		 * version 2 or above.
192 		 */
193 		if (flp->fl_version < LD_SUP_VERSION2)
194 			continue;
195 		if ((data == NULL) &&
196 		    ((data = elf_getdata(scn, NULL)) == NULL)) {
197 			eprintf(ERR_ELF, MSG_INTL(MSG_ELF_GETDATA),
198 				file);
199 			ofl->ofl_flags |= FLG_OF_FATAL;
200 			return (S_ERROR);
201 		}
202 
203 		DBG_CALL(Dbg_support_action(flp->fl_obj,
204 		    support[LDS_INP_SECTION].sup_name, LDS_INP_SECTION,
205 		    scnname));
206 		(*flp->fl_fptr)(scnname, shdr, ndx, data, elf, &flags);
207 	}
208 	return (0);
209 }
210 
211 void
212 lds_section(const char *scn, Shdr *shdr, Word ndx,
213     Elf_Data *data, Elf *elf)
214 {
215 	Func_list	*flp;
216 	Listnode	*lnp;
217 
218 	for (LIST_TRAVERSE(&support[LDS_SECTION].sup_funcs, lnp, flp)) {
219 		DBG_CALL(Dbg_support_action(flp->fl_obj,
220 		    support[LDS_SECTION].sup_name, LDS_SECTION, scn));
221 		(*flp->fl_fptr)(scn, shdr, ndx, data, elf);
222 	}
223 }
224 
225 void
226 lds_input_done(void)
227 {
228 	Func_list	*flp;
229 	Listnode	*lnp;
230 	uint_t		flags = 0;
231 
232 	for (LIST_TRAVERSE(&support[LDS_INPUT_DONE].sup_funcs, lnp, flp)) {
233 		/*
234 		 * This interface was introduced in VERSION2 - so only
235 		 * call it for libraries reporting support for
236 		 * version 2 or above.
237 		 */
238 		if (flp->fl_version < LD_SUP_VERSION2)
239 			continue;
240 		DBG_CALL(Dbg_support_action(flp->fl_obj,
241 		    support[LDS_INPUT_DONE].sup_name, LDS_INPUT_DONE, 0));
242 		(*flp->fl_fptr)(&flags);
243 	}
244 }
245