Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/rump Build the kernel symbol table in rumpuser bootstrap...



details:   https://anonhg.NetBSD.org/src/rev/241098364c5c
branches:  trunk
changeset: 749313:241098364c5c
user:      pooka <pooka%NetBSD.org@localhost>
date:      Thu Nov 26 09:50:38 2009 +0000

description:
Build the kernel symbol table in rumpuser bootstrap and feed it to
the rump kernel.  After this change it is possible to use the
in-kernel linker and rump_sys_modctl() to load kernel modules at
runtime.

Previously loading modules at runtime was possible only through
using the host system ld.so.  Note that it is still preferred to
use shared libs when possible, since they are PIC and n virtual
kernels will only require one copy of r/o segments.  However, when
there is no access to source code, a binary kernel module is the
only thing available ...

diffstat:

 sys/rump/include/rump/rumpuser.h        |    5 +-
 sys/rump/librump/rumpkern/rump.c        |    6 +-
 sys/rump/librump/rumpuser/rumpuser_dl.c |  270 +++++++++++++++++++++++++++++++-
 3 files changed, 272 insertions(+), 9 deletions(-)

diffs (truncated from 363 to 300 lines):

diff -r 24c067282cf9 -r 241098364c5c sys/rump/include/rump/rumpuser.h
--- a/sys/rump/include/rump/rumpuser.h  Thu Nov 26 09:21:16 2009 +0000
+++ b/sys/rump/include/rump/rumpuser.h  Thu Nov 26 09:50:38 2009 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rumpuser.h,v 1.33 2009/11/19 14:44:58 pooka Exp $      */
+/*     $NetBSD: rumpuser.h,v 1.34 2009/11/26 09:50:38 pooka Exp $      */
 
 /*
  * Copyright (c) 2007 Antti Kantee.  All Rights Reserved.
@@ -196,6 +196,7 @@
 
 struct modinfo;
 typedef int (*rump_modinit_fn)(struct modinfo *, prop_dictionary_t);
-void rumpuser_dl_module_bootstrap(rump_modinit_fn);
+typedef int (*rump_symload_fn)(void *, uint64_t, char *, uint64_t);
+void rumpuser_dl_module_bootstrap(rump_modinit_fn, rump_symload_fn);
 
 #endif /* _RUMP_RUMPUSER_H_ */
diff -r 24c067282cf9 -r 241098364c5c sys/rump/librump/rumpkern/rump.c
--- a/sys/rump/librump/rumpkern/rump.c  Thu Nov 26 09:21:16 2009 +0000
+++ b/sys/rump/librump/rumpkern/rump.c  Thu Nov 26 09:50:38 2009 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rump.c,v 1.137 2009/11/26 09:20:07 pooka Exp $ */
+/*     $NetBSD: rump.c,v 1.138 2009/11/26 09:50:38 pooka Exp $ */
 
 /*
  * Copyright (c) 2007 Antti Kantee.  All Rights Reserved.
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.137 2009/11/26 09:20:07 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.138 2009/11/26 09:50:38 pooka Exp $");
 
 #include <sys/param.h>
 #include <sys/atomic.h>
@@ -310,7 +310,7 @@
                vmem_rehash_start();
 #endif
 
-       rumpuser_dl_module_bootstrap(rump_module_init);
+       rumpuser_dl_module_bootstrap(rump_module_init, rump_kernelfsym_load);
        rump_unschedule();
 
        return 0;
diff -r 24c067282cf9 -r 241098364c5c sys/rump/librump/rumpuser/rumpuser_dl.c
--- a/sys/rump/librump/rumpuser/rumpuser_dl.c   Thu Nov 26 09:21:16 2009 +0000
+++ b/sys/rump/librump/rumpuser/rumpuser_dl.c   Thu Nov 26 09:50:38 2009 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: rumpuser_dl.c,v 1.6 2009/11/23 14:39:35 pooka Exp $   */
+/*      $NetBSD: rumpuser_dl.c,v 1.7 2009/11/26 09:50:38 pooka Exp $   */
 
 /*
  * Copyright (c) 2009 Antti Kantee.  All Rights Reserved.
@@ -26,25 +26,270 @@
  */
 
 /*
- * Load all module link sets.  Called during rump bootstrap.
+ * Load all module link sets and feed symbol table to the kernel.
+ * Called during rump bootstrap.
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: rumpuser_dl.c,v 1.6 2009/11/23 14:39:35 pooka Exp $");
+__RCSID("$NetBSD: rumpuser_dl.c,v 1.7 2009/11/26 09:50:38 pooka Exp $");
 
 #include <sys/types.h>
 #include <sys/time.h>
 
 #include <assert.h>
 #include <dlfcn.h>
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <link.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <rump/rumpuser.h>
 
 #if defined(__ELF__) && (defined(__NetBSD__) || defined(__FreeBSD__)   \
     || (defined(__sun__) && defined(__svr4__)))
+static size_t symtabsize = 0, strtabsize = 0;
+static size_t symtaboff = 0, strtaboff = 0;
+static uint8_t *symtab = NULL;
+static char *strtab = NULL;
+static unsigned char eident;
+
+static void *
+reservespace(void *store, size_t *storesize,
+       size_t storeoff, int64_t required)
+{
+       size_t chunk, newsize;
+
+       assert(storeoff <= *storesize);
+       chunk = *storesize - storeoff;
+
+       if (chunk >= required)
+               return store;
+
+       newsize = *storesize + ((size_t)required - chunk);
+       store = realloc(store, newsize);
+       if (store == NULL) {
+               return NULL;
+       }
+       *((uint8_t *)store + storeoff) = '\0';
+       *storesize = newsize;
+
+       return store;
+}
+
+/*
+ * Macros to make handling elf32/64 in the code a little saner.
+ */
+
+#define EHDR_GETMEMBER(base, thevar, result)                           \
+do {                                                                   \
+       if (eident == ELFCLASS32) {                                     \
+               Elf32_Ehdr *ehdr = base;                                \
+               result = ehdr->thevar;                                  \
+       } else {                                                        \
+               Elf64_Ehdr *ehdr = base;                                \
+               result = ehdr->thevar;                                  \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+#define SHDRn_GETMEMBER(base, n, thevar, result)                       \
+do {                                                                   \
+       if (eident == ELFCLASS32) {                                     \
+               Elf32_Shdr *shdr = base;                                \
+               result = shdr[n].thevar;                                \
+       } else {                                                        \
+               Elf64_Shdr *shdr = base;                                \
+               result = shdr[n].thevar;                                \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+#define DYNn_GETMEMBER(base, n, thevar, result)                                \
+do {                                                                   \
+       if (eident == ELFCLASS32) {                                     \
+               Elf32_Dyn *dyn = base;                                  \
+               /*LINTED*/                                              \
+               result = dyn[n].thevar;                                 \
+       } else {                                                        \
+               Elf64_Dyn *dyn = base;                                  \
+               /*LINTED*/                                              \
+               result = dyn[n].thevar;                                 \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+#define SYMn_GETMEMBER(base, n, thevar, result)                                \
+do {                                                                   \
+       if (eident == ELFCLASS32) {                                     \
+               Elf32_Sym *sym = base;                                  \
+               /*LINTED*/                                              \
+               result = sym[n].thevar;                                 \
+       } else {                                                        \
+               Elf64_Sym *sym = base;                                  \
+               /*LINTED*/                                              \
+               result = sym[n].thevar;                                 \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+#define SYMn_SETMEMBER(base, n, thevar, value)                         \
+do {                                                                   \
+       if (eident == ELFCLASS32) {                                     \
+               Elf32_Sym *sym = base;                                  \
+               /*LINTED*/                                              \
+               sym[n].thevar = value;                                  \
+       } else {                                                        \
+               Elf64_Sym *sym = base;                                  \
+               /*LINTED*/                                              \
+               sym[n].thevar = value;                                  \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+#define SYM_GETSIZE() ((eident==ELFCLASS32)?sizeof(Elf32_Sym):sizeof(Elf64_Sym))
+
+static int
+getsymbols(struct link_map *map)
+{
+       void *libbase = map->l_addr;
+       int i = 0, fd;
+       char *str_base;
+       void *syms_base = NULL; /* XXXgcc */
+       int64_t cursymsize, curstrsize;
+       void *shdr_base;
+       size_t shnum, shsize;
+       uint64_t shoff;
+       void *ed_base;
+       uint64_t ed_tag;
+       int sverrno;
+
+       if (memcmp(libbase, ELFMAG, SELFMAG) != 0)
+               return ENOEXEC;
+       eident = *(unsigned char *)(map->l_addr + EI_CLASS);
+       if (eident != ELFCLASS32 && eident != ELFCLASS64)
+               return ENOEXEC;
+
+       /* read the section headers from disk to determine size of dynsym */
+       fd = open(map->l_name, O_RDONLY);
+       if (fd == -1) {
+               sverrno = errno;
+               fprintf(stderr, "open %s failed\n", map->l_name);
+               return sverrno;
+       }
+
+       EHDR_GETMEMBER(libbase, e_shnum, shnum);
+       EHDR_GETMEMBER(libbase, e_shentsize, shsize);
+       EHDR_GETMEMBER(libbase, e_shoff, shoff);
+       shdr_base = malloc(shnum * shsize);
+       if (pread(fd, shdr_base, shnum * shsize, (off_t)shoff) != shnum*shsize){
+               sverrno = errno;
+               fprintf(stderr, "read section headers for %s failed\n",
+                   map->l_name);
+               free(shdr_base);
+               close(fd);
+               return sverrno;
+       }
+       cursymsize = -1;
+       for (i = 1; i <= shnum; i++) {
+               int shtype;
+
+               SHDRn_GETMEMBER(shdr_base, i, sh_type, shtype);
+               if (shtype != SHT_DYNSYM)
+                       continue;
+               SHDRn_GETMEMBER(shdr_base, i, sh_size, cursymsize);
+               break;
+       }
+       free(shdr_base);
+       close(fd);
+       if (cursymsize == -1) {
+               fprintf(stderr, "could not find dynsym size from %s\n",
+                   map->l_name);
+               return ENOEXEC;
+       }
+
+       /* find symtab, strtab and strtab size */
+       str_base = NULL;
+       curstrsize = -1;
+       ed_base = map->l_ld;
+       i = 0;
+       DYNn_GETMEMBER(ed_base, i, d_tag, ed_tag);
+       while (ed_tag != DT_NULL) {
+               uintptr_t edptr;
+               uint64_t edval;
+
+               switch (ed_tag) {
+               case DT_SYMTAB:
+                       DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
+                       syms_base = map->l_addr + edptr;
+                       break;
+               case DT_STRTAB:
+                       DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
+                       str_base = map->l_addr + edptr;
+                       break;
+               case DT_STRSZ:
+                       DYNn_GETMEMBER(ed_base, i, d_un.d_val, edval);
+                       curstrsize = edval;
+                       break;
+               default:
+                       break;
+               }
+               i++;
+               DYNn_GETMEMBER(ed_base, i, d_tag, ed_tag);
+       } while (ed_tag != DT_NULL);
+
+       if (str_base == NULL || syms_base == NULL || curstrsize == -1) {
+               fprintf(stderr, "could not find strtab, symtab or strtab size "
+                   "in %s\n", map->l_name);
+               return ENOEXEC;
+       }
+
+       /*
+        * Make sure we have enough space for the contents of the symbol
+        * and string tables we are currently processing.  The total used
+        * space will be smaller due to undefined symbols we are not
+        * interested in.
+        */
+       symtab = reservespace(symtab, &symtabsize, symtaboff, cursymsize);
+       strtab = reservespace(strtab, &strtabsize, strtaboff, curstrsize);
+       if (symtab == NULL || strtab == NULL) {
+               fprintf(stderr, "failed to reserve memory");
+               return ENOMEM;
+       }
+
+       /* iterate over all symbols in current symtab */
+       for (i = 0; i * SYM_GETSIZE() < cursymsize; i++) {
+               char *cursymname;
+               int shndx, name;
+               uintptr_t value;
+               void *csym;
+
+               SYMn_GETMEMBER(syms_base, i, st_shndx, shndx);
+               SYMn_GETMEMBER(syms_base, i, st_value, value);
+               if (shndx == SHN_UNDEF || value == 0)
+                       continue;



Home | Main Index | Thread Index | Old Index