1*388550b0Srillig /* $NetBSD: rumpuser_dl.c,v 1.34 2022/04/19 20:32:17 rillig Exp $ */
26e4a9f91Spooka
36e4a9f91Spooka /*
46e4a9f91Spooka * Copyright (c) 2009 Antti Kantee. All Rights Reserved.
56e4a9f91Spooka *
66e4a9f91Spooka * Redistribution and use in source and binary forms, with or without
76e4a9f91Spooka * modification, are permitted provided that the following conditions
86e4a9f91Spooka * are met:
96e4a9f91Spooka * 1. Redistributions of source code must retain the above copyright
106e4a9f91Spooka * notice, this list of conditions and the following disclaimer.
116e4a9f91Spooka * 2. Redistributions in binary form must reproduce the above copyright
126e4a9f91Spooka * notice, this list of conditions and the following disclaimer in the
136e4a9f91Spooka * documentation and/or other materials provided with the distribution.
146e4a9f91Spooka *
156e4a9f91Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
166e4a9f91Spooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
176e4a9f91Spooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
186e4a9f91Spooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
196e4a9f91Spooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
206e4a9f91Spooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
216e4a9f91Spooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
226e4a9f91Spooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
236e4a9f91Spooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246e4a9f91Spooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256e4a9f91Spooka * SUCH DAMAGE.
266e4a9f91Spooka */
276e4a9f91Spooka
286e4a9f91Spooka /*
296e4a9f91Spooka * Load all module link sets and feed symbol table to the kernel.
306e4a9f91Spooka * Called during rump bootstrap.
316e4a9f91Spooka */
326e4a9f91Spooka
335ccc76a6Spooka /*
345ccc76a6Spooka * Solaris libelf.h doesn't support _FILE_OFFSET_BITS=64. Luckily,
355ccc76a6Spooka * for this module it doesn't matter.
365ccc76a6Spooka */
377415696eSpooka #if defined(__sun__)
387415696eSpooka #define RUMPUSER_NO_FILE_OFFSET_BITS
395ccc76a6Spooka #endif
403b3ffd70Spooka #include "rumpuser_port.h"
413b3ffd70Spooka
423b3ffd70Spooka #if !defined(lint)
43*388550b0Srillig __RCSID("$NetBSD: rumpuser_dl.c,v 1.34 2022/04/19 20:32:17 rillig Exp $");
443b3ffd70Spooka #endif /* !lint */
456e4a9f91Spooka
466e4a9f91Spooka #include <sys/types.h>
476e4a9f91Spooka #include <sys/time.h>
485996efe5Spgoyette #include <sys/evcnt.h>
495996efe5Spgoyette
506e4a9f91Spooka #include <assert.h>
513b3ffd70Spooka
526e4a9f91Spooka #include <dlfcn.h>
536e4a9f91Spooka #include <errno.h>
546e4a9f91Spooka #include <fcntl.h>
55d3852222Spooka #include <stdint.h>
566e4a9f91Spooka #include <stdio.h>
576e4a9f91Spooka #include <stdlib.h>
586e4a9f91Spooka #include <string.h>
596e4a9f91Spooka #include <unistd.h>
606e4a9f91Spooka
616e4a9f91Spooka #include <rump/rumpuser.h>
626e4a9f91Spooka
6323dfcd74Spooka #if defined(__ELF__) && defined(HAVE_DLINFO)
64d60eb8c1Srmind #include <elf.h>
65e0f5e003Spooka #include <link.h>
66e0f5e003Spooka
676e4a9f91Spooka static size_t symtabsize = 0, strtabsize = 0;
686e4a9f91Spooka static size_t symtaboff = 0, strtaboff = 0;
696e4a9f91Spooka static uint8_t *symtab = NULL;
706e4a9f91Spooka static char *strtab = NULL;
716e4a9f91Spooka static unsigned char eident;
726e4a9f91Spooka
73f347b449Spooka /* nb5 compat */
74f347b449Spooka #ifndef Elf_Symindx
75f347b449Spooka #define Elf_Symindx uint32_t
76f347b449Spooka #endif
77f347b449Spooka
786e4a9f91Spooka static void *
reservespace(void * store,size_t * storesize,size_t storeoff,size_t required)796e4a9f91Spooka reservespace(void *store, size_t *storesize,
806e4a9f91Spooka size_t storeoff, size_t required)
816e4a9f91Spooka {
826e4a9f91Spooka size_t chunk, newsize;
836e4a9f91Spooka
846e4a9f91Spooka assert(storeoff <= *storesize);
856e4a9f91Spooka chunk = *storesize - storeoff;
866e4a9f91Spooka
876e4a9f91Spooka if (chunk >= required)
886e4a9f91Spooka return store;
896e4a9f91Spooka
906e4a9f91Spooka newsize = *storesize + ((size_t)required - chunk);
916e4a9f91Spooka store = realloc(store, newsize);
926e4a9f91Spooka if (store == NULL) {
936e4a9f91Spooka return NULL;
946e4a9f91Spooka }
956e4a9f91Spooka *((uint8_t *)store + storeoff) = '\0';
966e4a9f91Spooka *storesize = newsize;
976e4a9f91Spooka
986e4a9f91Spooka return store;
996e4a9f91Spooka }
1006e4a9f91Spooka
1016e4a9f91Spooka /*
1026e4a9f91Spooka * Macros to make handling elf32/64 in the code a little saner.
1036e4a9f91Spooka */
1046e4a9f91Spooka
1056e4a9f91Spooka #define DYNn_GETMEMBER(base, n, thevar, result) \
1066e4a9f91Spooka do { \
1076e4a9f91Spooka if (eident == ELFCLASS32) { \
10823a1592dSpooka const Elf32_Dyn *dyn = base; \
1096e4a9f91Spooka /*LINTED*/ \
1106e4a9f91Spooka result = dyn[n].thevar; \
1116e4a9f91Spooka } else { \
11223a1592dSpooka const Elf64_Dyn *dyn = base; \
1136e4a9f91Spooka /*LINTED*/ \
1146e4a9f91Spooka result = dyn[n].thevar; \
1156e4a9f91Spooka } \
116*388550b0Srillig } while (0)
1176e4a9f91Spooka
1186e4a9f91Spooka #define SYMn_GETMEMBER(base, n, thevar, result) \
1196e4a9f91Spooka do { \
1206e4a9f91Spooka if (eident == ELFCLASS32) { \
12146ea1019Spooka const Elf32_Sym *sym = base; \
1226e4a9f91Spooka /*LINTED*/ \
1236e4a9f91Spooka result = sym[n].thevar; \
1246e4a9f91Spooka } else { \
12546ea1019Spooka const Elf64_Sym *sym = base; \
1266e4a9f91Spooka /*LINTED*/ \
1276e4a9f91Spooka result = sym[n].thevar; \
1286e4a9f91Spooka } \
129*388550b0Srillig } while (0)
1306e4a9f91Spooka
1316e4a9f91Spooka #define SYMn_SETMEMBER(base, n, thevar, value) \
1326e4a9f91Spooka do { \
1336e4a9f91Spooka if (eident == ELFCLASS32) { \
1346e4a9f91Spooka Elf32_Sym *sym = base; \
1356e4a9f91Spooka /*LINTED*/ \
1366e4a9f91Spooka sym[n].thevar = value; \
1376e4a9f91Spooka } else { \
1386e4a9f91Spooka Elf64_Sym *sym = base; \
1396e4a9f91Spooka /*LINTED*/ \
1406e4a9f91Spooka sym[n].thevar = value; \
1416e4a9f91Spooka } \
142*388550b0Srillig } while (0)
1436e4a9f91Spooka
1446e4a9f91Spooka #define SYM_GETSIZE() ((eident==ELFCLASS32)?sizeof(Elf32_Sym):sizeof(Elf64_Sym))
1456e4a9f91Spooka
1463b3ffd70Spooka /*
1473b3ffd70Spooka * On NetBSD, the dynamic section pointer values seem to be relative to
148aaf7a23bSpooka * the address the dso is mapped at. On glibc, they seem to contain
1493b3ffd70Spooka * the absolute address. I couldn't find anything definite from a quick
1503b3ffd70Spooka * read of the standard and therefore I will not go and figure beyond ifdef.
151aaf7a23bSpooka * On Solaris and DragonFly / FreeBSD, the main object works differently
152aaf7a23bSpooka * ... uuuuh.
1533b3ffd70Spooka */
154079cd210Spooka #if defined(__GLIBC__) && !defined(__mips__)
1553b3ffd70Spooka #define adjptr(_map_, _ptr_) ((void *)(_ptr_))
15669c4f929Spooka #elif defined(__sun__) || defined(__DragonFly__) || defined(__FreeBSD__)
1574b0fe892Spooka #define adjptr(_map_, _ptr_) \
158f9ef17b1Spooka (ismainobj ? (void *)(_ptr_) : (void *)(_map_->l_addr + (_ptr_)))
1593b3ffd70Spooka #else
160f3adf1e5Spooka /* NetBSD and some others, e.g. Linux + musl */
1613b3ffd70Spooka #define adjptr(_map_, _ptr_) ((void *)(_map_->l_addr + (_ptr_)))
1623b3ffd70Spooka #endif
1633b3ffd70Spooka
1646e4a9f91Spooka static int
getsymbols(struct link_map * map,int ismainobj)165f9ef17b1Spooka getsymbols(struct link_map *map, int ismainobj)
1666e4a9f91Spooka {
1676e4a9f91Spooka char *str_base;
1686e4a9f91Spooka void *syms_base = NULL; /* XXXgcc */
16946ea1019Spooka size_t curstrsize;
17023a1592dSpooka const void *ed_base;
1716e4a9f91Spooka uint64_t ed_tag;
17246ea1019Spooka size_t cursymcount;
17346ea1019Spooka unsigned i;
1746e4a9f91Spooka
17546ea1019Spooka if (map->l_addr) {
1763b3ffd70Spooka if (memcmp((void *)map->l_addr, ELFMAG, SELFMAG) != 0)
1776e4a9f91Spooka return ENOEXEC;
1786e4a9f91Spooka eident = *(unsigned char *)(map->l_addr + EI_CLASS);
1796e4a9f91Spooka if (eident != ELFCLASS32 && eident != ELFCLASS64)
1806e4a9f91Spooka return ENOEXEC;
1816e4a9f91Spooka }
1826e4a9f91Spooka
18346ea1019Spooka /*
18446ea1019Spooka * ok, we probably have only the main object. instead of going
18546ea1019Spooka * to disk and reading the ehdr, just try to guess the size.
18646ea1019Spooka */
18746ea1019Spooka if (eident == 0) {
18846ea1019Spooka if (/*CONSTCOND*/sizeof(void *) == 4)
18946ea1019Spooka eident = ELFCLASS32;
19046ea1019Spooka else
19146ea1019Spooka eident = ELFCLASS64;
1926e4a9f91Spooka }
1936e4a9f91Spooka
19446ea1019Spooka /*
19546ea1019Spooka * Find symtab and strtab and their sizes.
19646ea1019Spooka */
1976e4a9f91Spooka str_base = NULL;
19846ea1019Spooka curstrsize = 0;
19946ea1019Spooka cursymcount = 0;
2006e4a9f91Spooka ed_base = map->l_ld;
20146ea1019Spooka DYNn_GETMEMBER(ed_base, 0, d_tag, ed_tag);
20246ea1019Spooka for (i = 0; ed_tag != DT_NULL;) {
2036e4a9f91Spooka uintptr_t edptr;
2046e4a9f91Spooka size_t edval;
205603f3daeSnjoly Elf_Symindx *hashtab;
2066e4a9f91Spooka
2076e4a9f91Spooka switch (ed_tag) {
2086e4a9f91Spooka case DT_SYMTAB:
2096e4a9f91Spooka DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
2103b3ffd70Spooka syms_base = adjptr(map, edptr);
2116e4a9f91Spooka break;
2126e4a9f91Spooka case DT_STRTAB:
2136e4a9f91Spooka DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
2143b3ffd70Spooka str_base = adjptr(map, edptr);
2156e4a9f91Spooka break;
2166e4a9f91Spooka case DT_STRSZ:
2176e4a9f91Spooka DYNn_GETMEMBER(ed_base, i, d_un.d_val, edval);
2186e4a9f91Spooka curstrsize = edval;
2196e4a9f91Spooka break;
22046ea1019Spooka case DT_HASH:
22146ea1019Spooka DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
2223b3ffd70Spooka hashtab = (Elf_Symindx *)adjptr(map, edptr);
223603f3daeSnjoly cursymcount = hashtab[1];
22446ea1019Spooka break;
2254c7d25c0Spooka #ifdef DT_GNU_HASH
2264c7d25c0Spooka /*
2274c7d25c0Spooka * DT_GNU_HASH is a bit more complicated than DT_HASH
2284c7d25c0Spooka * in this regard since apparently there is no field
2294c7d25c0Spooka * telling us the total symbol count. Instead, we look
23040064e24Smsaitoh * for the last valid hash bucket and add its chain length
2314c7d25c0Spooka * to the bucket's base index.
2324c7d25c0Spooka */
2334c7d25c0Spooka case DT_GNU_HASH: {
2344c7d25c0Spooka Elf32_Word nbuck, symndx, maskwords, maxchain = 0;
2354c7d25c0Spooka Elf32_Word *gnuhash, *buckets, *ptr;
2364c7d25c0Spooka int bi;
2374c7d25c0Spooka
2384c7d25c0Spooka DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
2394c7d25c0Spooka gnuhash = (Elf32_Word *)adjptr(map, edptr);
2404c7d25c0Spooka
2414c7d25c0Spooka nbuck = gnuhash[0];
2424c7d25c0Spooka symndx = gnuhash[1];
2434c7d25c0Spooka maskwords = gnuhash[2];
2444c7d25c0Spooka
2454c7d25c0Spooka /*
2464c7d25c0Spooka * First, find the last valid bucket and grab its index
2474c7d25c0Spooka */
2484c7d25c0Spooka if (eident == ELFCLASS64)
2494c7d25c0Spooka maskwords *= 2; /* sizeof(*buckets) == 4 */
2504c7d25c0Spooka buckets = gnuhash + 4 + maskwords;
2514c7d25c0Spooka for (bi = nbuck-1; bi >= 0; bi--) {
2524c7d25c0Spooka if (buckets[bi] != 0) {
2534c7d25c0Spooka maxchain = buckets[bi];
2544c7d25c0Spooka break;
2554c7d25c0Spooka }
2564c7d25c0Spooka }
2574c7d25c0Spooka if (maxchain == 0 || maxchain < symndx)
2584c7d25c0Spooka break;
2594c7d25c0Spooka
2604c7d25c0Spooka /*
2614c7d25c0Spooka * Then, traverse the last chain and count symbols.
2624c7d25c0Spooka */
2634c7d25c0Spooka
2644c7d25c0Spooka cursymcount = maxchain;
2654c7d25c0Spooka ptr = buckets + nbuck + (maxchain - symndx);
2664c7d25c0Spooka do {
2674c7d25c0Spooka cursymcount++;
2684c7d25c0Spooka } while ((*ptr++ & 1) == 0);
2694c7d25c0Spooka }
2704c7d25c0Spooka break;
2714c7d25c0Spooka #endif
27246ea1019Spooka case DT_SYMENT:
27346ea1019Spooka DYNn_GETMEMBER(ed_base, i, d_un.d_val, edval);
27446ea1019Spooka assert(edval == SYM_GETSIZE());
27546ea1019Spooka break;
2766e4a9f91Spooka default:
2776e4a9f91Spooka break;
2786e4a9f91Spooka }
2796e4a9f91Spooka i++;
2806e4a9f91Spooka DYNn_GETMEMBER(ed_base, i, d_tag, ed_tag);
28146ea1019Spooka }
2826e4a9f91Spooka
28346ea1019Spooka if (str_base == NULL || syms_base == NULL ||
28446ea1019Spooka curstrsize == 0 || cursymcount == 0) {
28546ea1019Spooka fprintf(stderr, "could not find strtab, symtab or their sizes "
2866e4a9f91Spooka "in %s\n", map->l_name);
2876e4a9f91Spooka return ENOEXEC;
2886e4a9f91Spooka }
2896e4a9f91Spooka
2906e4a9f91Spooka /*
2916e4a9f91Spooka * Make sure we have enough space for the contents of the symbol
2926e4a9f91Spooka * and string tables we are currently processing. The total used
2936e4a9f91Spooka * space will be smaller due to undefined symbols we are not
2946e4a9f91Spooka * interested in.
2956e4a9f91Spooka */
29646ea1019Spooka symtab = reservespace(symtab, &symtabsize,
29746ea1019Spooka symtaboff, cursymcount * SYM_GETSIZE());
2986e4a9f91Spooka strtab = reservespace(strtab, &strtabsize, strtaboff, curstrsize);
2996e4a9f91Spooka if (symtab == NULL || strtab == NULL) {
3006e4a9f91Spooka fprintf(stderr, "failed to reserve memory");
3016e4a9f91Spooka return ENOMEM;
3026e4a9f91Spooka }
3036e4a9f91Spooka
3046e4a9f91Spooka /* iterate over all symbols in current symtab */
30546ea1019Spooka for (i = 0; i < cursymcount; i++) {
30646ea1019Spooka const char *cursymname;
3076e4a9f91Spooka int shndx, name;
3086e4a9f91Spooka uintptr_t value;
3096e4a9f91Spooka void *csym;
3106e4a9f91Spooka
3116e4a9f91Spooka SYMn_GETMEMBER(syms_base, i, st_shndx, shndx);
3126e4a9f91Spooka SYMn_GETMEMBER(syms_base, i, st_value, value);
3136e4a9f91Spooka if (shndx == SHN_UNDEF || value == 0)
3146e4a9f91Spooka continue;
3156e4a9f91Spooka
3166e4a9f91Spooka /* get symbol name */
3176e4a9f91Spooka SYMn_GETMEMBER(syms_base, i, st_name, name);
3186e4a9f91Spooka cursymname = name + str_base;
31946ea1019Spooka
32046ea1019Spooka /*
32146ea1019Spooka * Only accept symbols which are decidedly in
32246ea1019Spooka * the rump kernel namespace.
32346ea1019Spooka * XXX: quirks, but they wouldn't matter here
32446ea1019Spooka */
32546ea1019Spooka if (strncmp(cursymname, "rump", 4) != 0 &&
32646ea1019Spooka strncmp(cursymname, "RUMP", 4) != 0 &&
32746ea1019Spooka strncmp(cursymname, "__", 2) != 0) {
32846ea1019Spooka continue;
32946ea1019Spooka }
33046ea1019Spooka
3316e4a9f91Spooka memcpy(symtab + symtaboff,
33246ea1019Spooka (const uint8_t *)syms_base + i*SYM_GETSIZE(),SYM_GETSIZE());
3336e4a9f91Spooka
3346e4a9f91Spooka /*
3356e4a9f91Spooka * set name to point at new strtab, offset symbol value
3366e4a9f91Spooka * with lib base address.
3376e4a9f91Spooka */
3386e4a9f91Spooka csym = symtab + symtaboff;
3396e4a9f91Spooka SYMn_SETMEMBER(csym, 0, st_name, strtaboff);
3406e4a9f91Spooka SYMn_GETMEMBER(csym, 0, st_value, value);
3416e4a9f91Spooka SYMn_SETMEMBER(csym, 0, st_value,(intptr_t)(value+map->l_addr));
3426e4a9f91Spooka symtaboff += SYM_GETSIZE();
3436e4a9f91Spooka
3446e4a9f91Spooka strcpy(strtab + strtaboff, cursymname);
3456e4a9f91Spooka strtaboff += strlen(cursymname)+1;
3466e4a9f91Spooka }
3476e4a9f91Spooka
3486e4a9f91Spooka return 0;
3496e4a9f91Spooka }
3506e4a9f91Spooka
351c2efc592Spooka static void
process_object(void * handle,rump_modinit_fn domodinit,rump_compload_fn docompload,rump_evcntattach_fn doevcntattach)3524b0fe892Spooka process_object(void *handle,
353561f1f3cSpgoyette rump_modinit_fn domodinit, rump_compload_fn docompload,
354561f1f3cSpgoyette rump_evcntattach_fn doevcntattach)
3556e4a9f91Spooka {
356c2efc592Spooka const struct modinfo *const *mi_start, *const *mi_end;
3574b0fe892Spooka struct rump_component *const *rc, *const *rc_end;
3586e4a9f91Spooka
3595996efe5Spgoyette struct sysctllog;
3605996efe5Spgoyette typedef void sysctl_setup_func(struct sysctllog **);
3615996efe5Spgoyette sysctl_setup_func *const *sfp, *const *sfp_end;
3625996efe5Spgoyette
3635996efe5Spgoyette struct evcnt *const *evp, *const *evp_end;
3645996efe5Spgoyette
365c2efc592Spooka mi_start = dlsym(handle, "__start_link_set_modules");
3666e4a9f91Spooka mi_end = dlsym(handle, "__stop_link_set_modules");
3674b0fe892Spooka if (mi_start && mi_end)
368c2efc592Spooka domodinit(mi_start, (size_t)(mi_end-mi_start));
3696e4a9f91Spooka
3704b0fe892Spooka rc = dlsym(handle, "__start_link_set_rump_components");
3714b0fe892Spooka rc_end = dlsym(handle, "__stop_link_set_rump_components");
3724b0fe892Spooka if (rc && rc_end) {
3734b0fe892Spooka for (; rc < rc_end; rc++)
3744b0fe892Spooka docompload(*rc);
3754b0fe892Spooka assert(rc == rc_end);
3764b0fe892Spooka }
3775996efe5Spgoyette
3785996efe5Spgoyette /* handle link_set_sysctl_funcs */
3795996efe5Spgoyette sfp = dlsym(handle, "__start_link_set_sysctl_funcs");
3805996efe5Spgoyette sfp_end = dlsym(handle, "__stop_link_set_sysctl_funcs");
3815996efe5Spgoyette if (sfp && sfp_end) {
3825996efe5Spgoyette for (; sfp < sfp_end; sfp++)
3835996efe5Spgoyette (**sfp)(NULL);
3845996efe5Spgoyette assert(sfp == sfp_end);
3855996efe5Spgoyette }
3865996efe5Spgoyette
3875996efe5Spgoyette /* handle link_set_evcnts */
3885996efe5Spgoyette evp = dlsym(handle, "__start_link_set_evcnts");
3895996efe5Spgoyette evp_end = dlsym(handle, "__stop_link_set_evcnts");
3905996efe5Spgoyette if (evp && evp_end) {
3915996efe5Spgoyette for (; evp < evp_end; evp++)
392561f1f3cSpgoyette doevcntattach(*evp);
3935996efe5Spgoyette assert(evp == evp_end);
3945996efe5Spgoyette }
3956e4a9f91Spooka }
3966e4a9f91Spooka
3976e4a9f91Spooka /*
3986e4a9f91Spooka * Get the linkmap from the dynlinker. Try to load kernel modules
3996e4a9f91Spooka * from all objects in the linkmap.
4006e4a9f91Spooka */
4016e4a9f91Spooka void
rumpuser_dl_bootstrap(rump_modinit_fn domodinit,rump_symload_fn symload,rump_compload_fn compload,rump_evcntattach_fn doevcntattach)4026e4a9f91Spooka rumpuser_dl_bootstrap(rump_modinit_fn domodinit,
403561f1f3cSpgoyette rump_symload_fn symload, rump_compload_fn compload,
404561f1f3cSpgoyette rump_evcntattach_fn doevcntattach)
4056e4a9f91Spooka {
4064b0fe892Spooka struct link_map *map, *origmap, *mainmap;
4074b0fe892Spooka void *mainhandle;
4086e4a9f91Spooka int error;
4096e4a9f91Spooka
4103b3ffd70Spooka mainhandle = dlopen(NULL, RTLD_NOW);
41154d90457Sjustin /* Will be null if statically linked so just return */
41254d90457Sjustin if (mainhandle == NULL)
41354d90457Sjustin return;
4144b0fe892Spooka if (dlinfo(mainhandle, RTLD_DI_LINKMAP, &mainmap) == -1) {
4156e4a9f91Spooka fprintf(stderr, "warning: rumpuser module bootstrap "
4166e4a9f91Spooka "failed: %s\n", dlerror());
4176e4a9f91Spooka return;
4186e4a9f91Spooka }
4194b0fe892Spooka origmap = mainmap;
4204b0fe892Spooka
4216e4a9f91Spooka /*
422300f37afSpooka * Use a heuristic to determine if we are static linked.
423300f37afSpooka * A dynamically linked binary should always have at least
424300f37afSpooka * two objects: itself and ld.so.
425300f37afSpooka *
426300f37afSpooka * In a statically linked binary with glibc the linkmap
427300f37afSpooka * contains some "info" that leads to a segfault. Since we
428300f37afSpooka * can't really do anything useful in here without ld.so, just
429300f37afSpooka * simply bail and let the symbol references in librump do the
430300f37afSpooka * right things.
431300f37afSpooka */
432300f37afSpooka if (origmap->l_next == NULL && origmap->l_prev == NULL) {
433300f37afSpooka dlclose(mainhandle);
434300f37afSpooka return;
435300f37afSpooka }
436300f37afSpooka
437300f37afSpooka /*
4386e4a9f91Spooka * Process last->first because that's the most probable
4396e4a9f91Spooka * order for dependencies
4406e4a9f91Spooka */
4416e4a9f91Spooka for (; origmap->l_next; origmap = origmap->l_next)
4426e4a9f91Spooka continue;
4436e4a9f91Spooka
4446e4a9f91Spooka /*
4456e4a9f91Spooka * Build symbol table to hand to the rump kernel. Do this by
4466e4a9f91Spooka * iterating over all rump libraries and collecting symbol
4476e4a9f91Spooka * addresses and relocation info.
4486e4a9f91Spooka */
4496e4a9f91Spooka error = 0;
4506e4a9f91Spooka for (map = origmap; map && !error; map = map->l_prev) {
4514b0fe892Spooka if (strstr(map->l_name, "librump") != NULL || map == mainmap)
452f9ef17b1Spooka error = getsymbols(map, map == mainmap);
4536e4a9f91Spooka }
4546e4a9f91Spooka
4556e4a9f91Spooka if (error == 0) {
4566e4a9f91Spooka void *trimmedsym, *trimmedstr;
4576e4a9f91Spooka
4586e4a9f91Spooka /*
4596e4a9f91Spooka * Allocate optimum-sized memory for storing tables
4606e4a9f91Spooka * and feed to kernel. If memory allocation fails,
4616e4a9f91Spooka * just give the ones with extra context (although
4626e4a9f91Spooka * I'm pretty sure we'll die moments later due to
4636e4a9f91Spooka * memory running out).
4646e4a9f91Spooka */
4656e4a9f91Spooka if ((trimmedsym = malloc(symtaboff)) != NULL) {
4666e4a9f91Spooka memcpy(trimmedsym, symtab, symtaboff);
4676e4a9f91Spooka } else {
4686e4a9f91Spooka trimmedsym = symtab;
4696e4a9f91Spooka symtab = NULL;
4706e4a9f91Spooka }
4716e4a9f91Spooka if ((trimmedstr = malloc(strtaboff)) != NULL) {
4726e4a9f91Spooka memcpy(trimmedstr, strtab, strtaboff);
4736e4a9f91Spooka } else {
4746e4a9f91Spooka trimmedstr = strtab;
4756e4a9f91Spooka strtab = NULL;
4766e4a9f91Spooka }
4776e4a9f91Spooka symload(trimmedsym, symtaboff, trimmedstr, strtaboff);
4786e4a9f91Spooka }
4796e4a9f91Spooka free(symtab);
4806e4a9f91Spooka free(strtab);
4816e4a9f91Spooka
4826e4a9f91Spooka /*
4834b0fe892Spooka * Next, load modules and components.
4844b0fe892Spooka *
4854b0fe892Spooka * Simply loop through all objects, ones unrelated to rump kernels
4864b0fe892Spooka * will not contain link_set_rump_components (well, not including
4874b0fe892Spooka * "sabotage", but that needs to be solved at another level anyway).
4886e4a9f91Spooka */
4894b0fe892Spooka for (map = origmap; map; map = map->l_prev) {
490510a73e0Spooka void *handle;
491510a73e0Spooka
4924b0fe892Spooka if (map == mainmap) {
4934b0fe892Spooka handle = mainhandle;
4944b0fe892Spooka } else {
495510a73e0Spooka handle = dlopen(map->l_name, RTLD_LAZY);
496510a73e0Spooka if (handle == NULL)
497510a73e0Spooka continue;
4984b0fe892Spooka }
499561f1f3cSpgoyette process_object(handle, domodinit, compload, doevcntattach);
5004b0fe892Spooka if (map != mainmap)
501510a73e0Spooka dlclose(handle);
502510a73e0Spooka }
503510a73e0Spooka }
5046e4a9f91Spooka #else
505e0f5e003Spooka /*
50686c3d192Spooka * no dynamic linking supported
507e0f5e003Spooka */
5084b0fe892Spooka void
rumpuser_dl_bootstrap(rump_modinit_fn domodinit,rump_symload_fn symload,rump_compload_fn compload,rump_evcntattach_fn doevcntattach)5094b0fe892Spooka rumpuser_dl_bootstrap(rump_modinit_fn domodinit,
510561f1f3cSpgoyette rump_symload_fn symload, rump_compload_fn compload,
511561f1f3cSpgoyette rump_evcntattach_fn doevcntattach)
5124b0fe892Spooka {
513510a73e0Spooka
51486c3d192Spooka return;
515510a73e0Spooka }
5166e4a9f91Spooka #endif
517