1 /* $NetBSD: rumpuser_dl.c,v 1.10 2009/12/07 17:38:16 pooka Exp $ */
4 * Copyright (c) 2009 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * Load all module link sets and feed symbol table to the kernel.
30 * Called during rump bootstrap.
33 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: rumpuser_dl.c,v 1.10 2009/12/07 17:38:16 pooka Exp $");
36 #include <sys/types.h>
50 #include <rump/rumpuser.h>
52 #if defined(__ELF__) && (defined(__NetBSD__) || defined(__FreeBSD__) \
53 || (defined(__sun__) && defined(__svr4__)))
54 static size_t symtabsize
= 0, strtabsize
= 0;
55 static size_t symtaboff
= 0, strtaboff
= 0;
56 static uint8_t *symtab
= NULL
;
57 static char *strtab
= NULL
;
58 static unsigned char eident
;
61 reservespace(void *store
, size_t *storesize
,
62 size_t storeoff
, size_t required
)
64 size_t chunk
, newsize
;
66 assert(storeoff
<= *storesize
);
67 chunk
= *storesize
- storeoff
;
69 if (chunk
>= required
)
72 newsize
= *storesize
+ ((size_t)required
- chunk
);
73 store
= realloc(store
, newsize
);
77 *((uint8_t *)store
+ storeoff
) = '\0';
84 * Macros to make handling elf32/64 in the code a little saner.
87 #define EHDR_GETMEMBER(base, thevar, result) \
89 if (eident == ELFCLASS32) { \
90 Elf32_Ehdr *ehdr = base; \
92 result = ehdr->thevar; \
94 Elf64_Ehdr *ehdr = base; \
96 result = ehdr->thevar; \
98 } while (/*CONSTCOND*/0)
100 #define SHDRn_GETMEMBER(base, n, thevar, result) \
102 if (eident == ELFCLASS32) { \
103 Elf32_Shdr *shdr = base; \
105 result = shdr[n].thevar; \
107 Elf64_Shdr *shdr = base; \
109 result = shdr[n].thevar; \
111 } while (/*CONSTCOND*/0)
113 #define DYNn_GETMEMBER(base, n, thevar, result) \
115 if (eident == ELFCLASS32) { \
116 Elf32_Dyn *dyn = base; \
118 result = dyn[n].thevar; \
120 Elf64_Dyn *dyn = base; \
122 result = dyn[n].thevar; \
124 } while (/*CONSTCOND*/0)
126 #define SYMn_GETMEMBER(base, n, thevar, result) \
128 if (eident == ELFCLASS32) { \
129 Elf32_Sym *sym = base; \
131 result = sym[n].thevar; \
133 Elf64_Sym *sym = base; \
135 result = sym[n].thevar; \
137 } while (/*CONSTCOND*/0)
139 #define SYMn_SETMEMBER(base, n, thevar, value) \
141 if (eident == ELFCLASS32) { \
142 Elf32_Sym *sym = base; \
144 sym[n].thevar = value; \
146 Elf64_Sym *sym = base; \
148 sym[n].thevar = value; \
150 } while (/*CONSTCOND*/0)
152 #define SYM_GETSIZE() ((eident==ELFCLASS32)?sizeof(Elf32_Sym):sizeof(Elf64_Sym))
155 getsymbols(struct link_map
*map
)
157 void *libbase
= map
->l_addr
;
160 void *syms_base
= NULL
; /* XXXgcc */
161 size_t cursymsize
, curstrsize
;
170 if (memcmp(libbase
, ELFMAG
, SELFMAG
) != 0)
172 eident
= *(unsigned char *)(map
->l_addr
+ EI_CLASS
);
173 if (eident
!= ELFCLASS32
&& eident
!= ELFCLASS64
)
176 /* read the section headers from disk to determine size of dynsym */
177 fd
= open(map
->l_name
, O_RDONLY
);
180 fprintf(stderr
, "open %s failed\n", map
->l_name
);
184 EHDR_GETMEMBER(libbase
, e_shnum
, shnum
);
185 EHDR_GETMEMBER(libbase
, e_shentsize
, shsize
);
186 EHDR_GETMEMBER(libbase
, e_shoff
, shoff
);
187 shdr_base
= malloc(shnum
* shsize
);
188 if (pread(fd
, shdr_base
, shnum
* shsize
, (off_t
)shoff
)
189 != (ssize_t
)(shnum
*shsize
)){
191 fprintf(stderr
, "read section headers for %s failed\n",
197 cursymsize
= (size_t)-1;
198 for (i
= 1; i
<= shnum
; i
++) {
201 SHDRn_GETMEMBER(shdr_base
, i
, sh_type
, shtype
);
202 if (shtype
!= SHT_DYNSYM
)
204 SHDRn_GETMEMBER(shdr_base
, i
, sh_size
, cursymsize
);
209 if (cursymsize
== (size_t)-1) {
210 fprintf(stderr
, "could not find dynsym size from %s\n",
215 /* find symtab, strtab and strtab size */
217 curstrsize
= (size_t)-1;
220 DYNn_GETMEMBER(ed_base
, i
, d_tag
, ed_tag
);
221 while (ed_tag
!= DT_NULL
) {
227 DYNn_GETMEMBER(ed_base
, i
, d_un
.d_ptr
, edptr
);
228 syms_base
= map
->l_addr
+ edptr
;
231 DYNn_GETMEMBER(ed_base
, i
, d_un
.d_ptr
, edptr
);
232 str_base
= map
->l_addr
+ edptr
;
235 DYNn_GETMEMBER(ed_base
, i
, d_un
.d_val
, edval
);
242 DYNn_GETMEMBER(ed_base
, i
, d_tag
, ed_tag
);
243 } while (ed_tag
!= DT_NULL
);
245 if (str_base
== NULL
|| syms_base
== NULL
|| curstrsize
== (size_t)-1) {
246 fprintf(stderr
, "could not find strtab, symtab or strtab size "
247 "in %s\n", map
->l_name
);
252 * Make sure we have enough space for the contents of the symbol
253 * and string tables we are currently processing. The total used
254 * space will be smaller due to undefined symbols we are not
257 symtab
= reservespace(symtab
, &symtabsize
, symtaboff
, cursymsize
);
258 strtab
= reservespace(strtab
, &strtabsize
, strtaboff
, curstrsize
);
259 if (symtab
== NULL
|| strtab
== NULL
) {
260 fprintf(stderr
, "failed to reserve memory");
264 /* iterate over all symbols in current symtab */
265 for (i
= 0; i
* SYM_GETSIZE() < cursymsize
; i
++) {
271 SYMn_GETMEMBER(syms_base
, i
, st_shndx
, shndx
);
272 SYMn_GETMEMBER(syms_base
, i
, st_value
, value
);
273 if (shndx
== SHN_UNDEF
|| value
== 0)
276 /* get symbol name */
277 SYMn_GETMEMBER(syms_base
, i
, st_name
, name
);
278 cursymname
= name
+ str_base
;
279 memcpy(symtab
+ symtaboff
,
280 (uint8_t *)syms_base
+ i
*SYM_GETSIZE(), SYM_GETSIZE());
283 * set name to point at new strtab, offset symbol value
284 * with lib base address.
286 csym
= symtab
+ symtaboff
;
287 SYMn_SETMEMBER(csym
, 0, st_name
, strtaboff
);
288 SYMn_GETMEMBER(csym
, 0, st_value
, value
);
289 SYMn_SETMEMBER(csym
, 0, st_value
,(intptr_t)(value
+map
->l_addr
));
290 symtaboff
+= SYM_GETSIZE();
292 strcpy(strtab
+ strtaboff
, cursymname
);
293 strtaboff
+= strlen(cursymname
)+1;
300 process(const char *soname
, rump_modinit_fn domodinit
)
303 struct modinfo
**mi
, **mi_end
;
306 if (strstr(soname
, "librump") == NULL
)
309 handle
= dlopen(soname
, RTLD_LAZY
);
313 mi
= dlsym(handle
, "__start_link_set_modules");
316 mi_end
= dlsym(handle
, "__stop_link_set_modules");
320 for (; mi
< mi_end
; mi
++)
321 if (domodinit(*mi
, NULL
) == 0)
323 assert(mi
== mi_end
);
331 * Get the linkmap from the dynlinker. Try to load kernel modules
332 * from all objects in the linkmap.
335 rumpuser_dl_module_bootstrap(rump_modinit_fn domodinit
,
336 rump_symload_fn symload
)
338 struct link_map
*map
, *origmap
;
342 if (dlinfo(RTLD_SELF
, RTLD_DI_LINKMAP
, &origmap
) == -1) {
343 fprintf(stderr
, "warning: rumpuser module bootstrap "
344 "failed: %s\n", dlerror());
348 * Process last->first because that's the most probable
349 * order for dependencies
351 for (; origmap
->l_next
; origmap
= origmap
->l_next
)
355 * Build symbol table to hand to the rump kernel. Do this by
356 * iterating over all rump libraries and collecting symbol
357 * addresses and relocation info.
360 for (map
= origmap
; map
&& !error
; map
= map
->l_prev
) {
361 if (map
->l_addr
== NULL
)
363 if (strstr(map
->l_name
, "librump") != NULL
)
364 error
= getsymbols(map
);
368 void *trimmedsym
, *trimmedstr
;
371 * Allocate optimum-sized memory for storing tables
372 * and feed to kernel. If memory allocation fails,
373 * just give the ones with extra context (although
374 * I'm pretty sure we'll die moments later due to
375 * memory running out).
377 if ((trimmedsym
= malloc(symtaboff
)) != NULL
) {
378 memcpy(trimmedsym
, symtab
, symtaboff
);
383 if ((trimmedstr
= malloc(strtaboff
)) != NULL
) {
384 memcpy(trimmedstr
, strtab
, strtaboff
);
389 symload(trimmedsym
, symtaboff
, trimmedstr
, strtaboff
);
395 * Next, load modules from dynlibs.
400 for (; map
; map
= map
->l_prev
)
401 if (process(map
->l_name
, domodinit
))
407 rumpuser_dl_module_bootstrap(rump_modinit_fn domodinit
,
408 rump_symload_fn symload
)
411 fprintf(stderr
, "Warning, dlinfo() unsupported on host?\n");
412 fprintf(stderr
, "module bootstrap unavailable\n");