Source-Changes-HG archive

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

[src/trunk]: src/lib/librumpuser Allow loading the symbols from objects which...



details:   https://anonhg.NetBSD.org/src/rev/b7ed4a603b81
branches:  trunk
changeset: 755528:b7ed4a603b81
user:      pooka <pooka%NetBSD.org@localhost>
date:      Tue Jun 08 15:32:55 2010 +0000

description:
Allow loading the symbols from objects which are not directly mapped
into memory, namely the main object (i.e. map->l_addr is NULL).

diffstat:

 lib/librumpuser/rumpuser_dl.c |  167 ++++++++++++++++++-----------------------
 1 files changed, 74 insertions(+), 93 deletions(-)

diffs (267 lines):

diff -r 34862abb76b6 -r b7ed4a603b81 lib/librumpuser/rumpuser_dl.c
--- a/lib/librumpuser/rumpuser_dl.c     Tue Jun 08 13:48:58 2010 +0000
+++ b/lib/librumpuser/rumpuser_dl.c     Tue Jun 08 15:32:55 2010 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: rumpuser_dl.c,v 1.3 2010/03/05 18:47:50 pooka Exp $   */
+/*      $NetBSD: rumpuser_dl.c,v 1.4 2010/06/08 15:32:55 pooka Exp $   */
 
 /*
  * Copyright (c) 2009 Antti Kantee.  All Rights Reserved.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: rumpuser_dl.c,v 1.3 2010/03/05 18:47:50 pooka Exp $");
+__RCSID("$NetBSD: rumpuser_dl.c,v 1.4 2010/06/08 15:32:55 pooka Exp $");
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -84,32 +84,6 @@
  * 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;                                \
-               /*LINTED*/                                              \
-               result = ehdr->thevar;                                  \
-       } else {                                                        \
-               Elf64_Ehdr *ehdr = base;                                \
-               /*LINTED*/                                              \
-               result = ehdr->thevar;                                  \
-       }                                                               \
-} while (/*CONSTCOND*/0)
-
-#define SHDRn_GETMEMBER(base, n, thevar, result)                       \
-do {                                                                   \
-       if (eident == ELFCLASS32) {                                     \
-               Elf32_Shdr *shdr = base;                                \
-               /*LINTED*/                                              \
-               result = shdr[n].thevar;                                \
-       } else {                                                        \
-               Elf64_Shdr *shdr = base;                                \
-               /*LINTED*/                                              \
-               result = shdr[n].thevar;                                \
-       }                                                               \
-} while (/*CONSTCOND*/0)
-
 #define DYNn_GETMEMBER(base, n, thevar, result)                                \
 do {                                                                   \
        if (eident == ELFCLASS32) {                                     \
@@ -126,11 +100,11 @@
 #define SYMn_GETMEMBER(base, n, thevar, result)                                \
 do {                                                                   \
        if (eident == ELFCLASS32) {                                     \
-               Elf32_Sym *sym = base;                                  \
+               const Elf32_Sym *sym = base;                            \
                /*LINTED*/                                              \
                result = sym[n].thevar;                                 \
        } else {                                                        \
-               Elf64_Sym *sym = base;                                  \
+               const Elf64_Sym *sym = base;                            \
                /*LINTED*/                                              \
                result = sym[n].thevar;                                 \
        }                                                               \
@@ -149,78 +123,61 @@
        }                                                               \
 } while (/*CONSTCOND*/0)
 
+#define GETVECWORDn(base, n, result)                                   \
+do {                                                                   \
+       if (eident == ELFCLASS32) {                                     \
+               Elf32_Word *vec = base;                                 \
+               result = vec[n];                                        \
+       } else {                                                        \
+               Elf64_Word *vec = base;                                 \
+               result = vec[n];                                        \
+       }                                                               \
+} 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 */
-       size_t cursymsize, curstrsize;
-       void *shdr_base;
-       size_t shsize;
-       int shnum;
-       uint64_t shoff;
+       size_t curstrsize;
        void *ed_base;
        uint64_t ed_tag;
-       int sverrno;
+       size_t cursymcount;
+       unsigned i;
 
-       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;
+       if (map->l_addr) {
+               if (memcmp(map->l_addr, ELFMAG, SELFMAG) != 0)
+                       return ENOEXEC;
+               eident = *(unsigned char *)(map->l_addr + EI_CLASS);
+               if (eident != ELFCLASS32 && eident != ELFCLASS64)
+                       return ENOEXEC;
        }
 
-       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)
-           != (ssize_t)(shnum*shsize)){
-               sverrno = errno;
-               fprintf(stderr, "read section headers for %s failed\n",
-                   map->l_name);
-               free(shdr_base);
-               close(fd);
-               return sverrno;
-       }
-       cursymsize = (size_t)-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 == (size_t)-1) {
-               fprintf(stderr, "could not find dynsym size from %s\n",
-                   map->l_name);
-               return ENOEXEC;
+       /*
+        * ok, we probably have only the main object.  instead of going
+        * to disk and reading the ehdr, just try to guess the size.
+        */
+       if (eident == 0) {
+               if (/*CONSTCOND*/sizeof(void *) == 4)
+                       eident = ELFCLASS32;
+               else
+                       eident = ELFCLASS64;
        }
 
-       /* find symtab, strtab and strtab size */
+       /*
+        * Find symtab and strtab and their sizes.
+        */
        str_base = NULL;
-       curstrsize = (size_t)-1;
+       curstrsize = 0;
+       cursymcount = 0;
        ed_base = map->l_ld;
-       i = 0;
-       DYNn_GETMEMBER(ed_base, i, d_tag, ed_tag);
-       while (ed_tag != DT_NULL) {
+       DYNn_GETMEMBER(ed_base, 0, d_tag, ed_tag);
+       for (i = 0; ed_tag != DT_NULL;) {
                uintptr_t edptr;
                size_t edval;
+               void *hashtab;
 
                switch (ed_tag) {
                case DT_SYMTAB:
@@ -235,15 +192,25 @@
                        DYNn_GETMEMBER(ed_base, i, d_un.d_val, edval);
                        curstrsize = edval;
                        break;
+               case DT_HASH:
+                       DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
+                       hashtab = map->l_addr + edptr;
+                       GETVECWORDn(hashtab, 1, cursymcount);
+                       break;
+               case DT_SYMENT:
+                       DYNn_GETMEMBER(ed_base, i, d_un.d_val, edval);
+                       assert(edval == SYM_GETSIZE());
+                       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 == (size_t)-1) {
-               fprintf(stderr, "could not find strtab, symtab or strtab size "
+       if (str_base == NULL || syms_base == NULL ||
+           curstrsize == 0 || cursymcount == 0) {
+               fprintf(stderr, "could not find strtab, symtab or their sizes "
                    "in %s\n", map->l_name);
                return ENOEXEC;
        }
@@ -254,7 +221,8 @@
         * space will be smaller due to undefined symbols we are not
         * interested in.
         */
-       symtab = reservespace(symtab, &symtabsize, symtaboff, cursymsize);
+       symtab = reservespace(symtab, &symtabsize,
+           symtaboff, cursymcount * SYM_GETSIZE());
        strtab = reservespace(strtab, &strtabsize, strtaboff, curstrsize);
        if (symtab == NULL || strtab == NULL) {
                fprintf(stderr, "failed to reserve memory");
@@ -262,8 +230,8 @@
        }
 
        /* iterate over all symbols in current symtab */
-       for (i = 0; i * SYM_GETSIZE() < cursymsize; i++) {
-               char *cursymname;
+       for (i = 0; i < cursymcount; i++) {
+               const char *cursymname;
                int shndx, name;
                uintptr_t value;
                void *csym;
@@ -276,8 +244,20 @@
                /* get symbol name */
                SYMn_GETMEMBER(syms_base, i, st_name, name);
                cursymname = name + str_base;
+
+               /*
+                * Only accept symbols which are decidedly in
+                * the rump kernel namespace.
+                * XXX: quirks, but they wouldn't matter here
+                */
+               if (strncmp(cursymname, "rump", 4) != 0 &&
+                   strncmp(cursymname, "RUMP", 4) != 0 &&
+                   strncmp(cursymname, "__", 2) != 0) {
+                       continue;
+               }
+
                memcpy(symtab + symtaboff,
-                   (uint8_t *)syms_base + i*SYM_GETSIZE(), SYM_GETSIZE());
+                   (const uint8_t *)syms_base + i*SYM_GETSIZE(),SYM_GETSIZE());
 
                /*
                 * set name to point at new strtab, offset symbol value
@@ -352,10 +332,11 @@
         */
        error = 0;
        for (map = origmap; map && !error; map = map->l_prev) {
-               if (map->l_addr == NULL)
-                       continue;
                if (strstr(map->l_name, "librump") != NULL)
                        error = getsymbols(map);
+               /* this should be the main object */
+               else if (map->l_addr == NULL && map->l_prev == NULL)
+                       error = getsymbols(map);
        }
 
        if (error == 0) {



Home | Main Index | Thread Index | Old Index