xref: /netbsd-src/lib/libc/dlfcn/dlfcn_elf.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
1 /*	$NetBSD: dlfcn_elf.c,v 1.10 2011/06/25 05:45:11 nonaka Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 Takuya SHIOZAKI
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #if defined(LIBC_SCCS) && !defined(lint)
30 __RCSID("$NetBSD: dlfcn_elf.c,v 1.10 2011/06/25 05:45:11 nonaka Exp $");
31 #endif /* LIBC_SCCS and not lint */
32 
33 #include "namespace.h"
34 #include <sys/atomic.h>
35 #include <elf.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdbool.h>
39 
40 #undef dlopen
41 #undef dlclose
42 #undef dlsym
43 #undef dlerror
44 #undef dladdr
45 #undef dfinfo
46 
47 #define	dlopen		___dlopen
48 #define	dlclose		___dlclose
49 #define	dlsym		___dlsym
50 #define	dlvsym		___dlvsym
51 #define	dlerror		___dlerror
52 #define	dladdr		___dladdr
53 #define	dlinfo		___dlinfo
54 #define	dl_iterate_phdr		___dl_iterate_phdr
55 
56 #define ELFSIZE ARCH_ELFSIZE
57 #include "rtld.h"
58 
59 #ifdef __weak_alias
60 __weak_alias(dlopen,___dlopen)
61 __weak_alias(dlclose,___dlclose)
62 __weak_alias(dlsym,___dlsym)
63 __weak_alias(dlvsym,___dlvsym)
64 __weak_alias(dlerror,___dlerror)
65 __weak_alias(dladdr,___dladdr)
66 __weak_alias(dlinfo,___dlinfo)
67 __weak_alias(dl_iterate_phdr,___dl_iterate_phdr)
68 
69 __weak_alias(__dlopen,___dlopen)
70 __weak_alias(__dlclose,___dlclose)
71 __weak_alias(__dlsym,___dlsym)
72 __weak_alias(__dlvsym,___dlvsym)
73 __weak_alias(__dlerror,___dlerror)
74 __weak_alias(__dladdr,___dladdr)
75 __weak_alias(__dlinfo,___dlinfo)
76 __weak_alias(__dl_iterate_phdr,___dl_iterate_phdr)
77 #endif
78 
79 /*
80  * For ELF, the dynamic linker directly resolves references to its
81  * services to functions inside the dynamic linker itself.  These
82  * weak-symbol stubs are necessary so that "ld" won't complain about
83  * undefined symbols.  The stubs are executed only when the program is
84  * linked statically, or when a given service isn't implemented in the
85  * dynamic linker.  They must return an error if called, and they must
86  * be weak symbols so that the dynamic linker can override them.
87  */
88 
89 static char dlfcn_error[] = "Service unavailable";
90 
91 /*ARGSUSED*/
92 void *
93 dlopen(const char *name, int mode)
94 {
95 
96 	return NULL;
97 }
98 
99 /*ARGSUSED*/
100 int
101 dlclose(void *fd)
102 {
103 
104 	return -1;
105 }
106 
107 /*ARGSUSED*/
108 void *
109 dlsym(void *handle, const char *name)
110 {
111 
112 	return NULL;
113 }
114 
115 /*ARGSUSED*/
116 void *
117 dlvsym(void *handle, const char *name, const char *version)
118 {
119 
120 	return NULL;
121 }
122 
123 /*ARGSUSED*/
124 __aconst char *
125 dlerror()
126 {
127 
128 	return dlfcn_error;
129 }
130 
131 /*ARGSUSED*/
132 int
133 dladdr(const void *addr, Dl_info *dli)
134 {
135 
136 	return 0;
137 }
138 
139 /*ARGSUSED*/
140 int
141 dlinfo(void *handle, int req, void *v)
142 {
143 
144 	return -1;
145 }
146 
147 static const char *dlpi_name;
148 static Elf_Addr dlpi_addr;
149 static const Elf_Phdr *dlpi_phdr;
150 static Elf_Half dlpi_phnum;
151 
152 /*
153  * Declare as common symbol to allow new libc with older binaries to
154  * not trigger an undefined reference.
155  */
156 extern __dso_hidden void *__auxinfo;
157 
158 static void
159 dl_iterate_phdr_setup(void)
160 {
161 	const AuxInfo *aux;
162 
163 	if (__auxinfo == NULL)
164 		return;
165 
166 	for (aux = __auxinfo; aux->a_type != AT_NULL; ++aux) {
167 		switch (aux->a_type) {
168 		case AT_BASE:
169 			dlpi_addr = aux->a_v;
170 			break;
171 		case AT_PHDR:
172 			dlpi_phdr = (void *)aux->a_v;
173 			break;
174 		case AT_PHNUM:
175 			dlpi_phnum = aux->a_v;
176 			break;
177 		case AT_SUN_EXECNAME:
178 			dlpi_name = (void *)aux->a_v;
179 			break;
180 		}
181 	}
182 }
183 
184 /*ARGSUSED*/
185 int
186 dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *),
187     void *data)
188 {
189 	static bool setup_done;
190 	struct dl_phdr_info phdr_info;
191 
192 	if (__auxinfo == NULL)
193 		return EOPNOTSUPP;
194 
195 	if (!setup_done) {
196 		/*
197 		 * This can race on the first call to dl_iterate_phdr.
198 		 * dl_iterate_phdr_setup only touches field of pointer size
199 		 * and smaller and such stores are atomic.
200 		 */
201 		dl_iterate_phdr_setup();
202 		membar_producer();
203 		setup_done = true;
204 	}
205 
206 	memset(&phdr_info, 0, sizeof(phdr_info));
207 	phdr_info.dlpi_addr = dlpi_addr;
208 	phdr_info.dlpi_phdr = dlpi_phdr;
209 	phdr_info.dlpi_phnum = dlpi_phnum;
210 	phdr_info.dlpi_name = dlpi_name;
211 
212 	return callback(&phdr_info, sizeof(phdr_info), data);
213 }
214