guile-commits
[Top][All Lists]
Advanced

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

[Guile-commits] 03/08: Add support for reading ELF symbol table from C


From: Andy Wingo
Subject: [Guile-commits] 03/08: Add support for reading ELF symbol table from C
Date: Fri, 20 Jul 2018 05:58:55 -0400 (EDT)

wingo pushed a commit to branch lightning
in repository guile.

commit e95f15c932650783f34253e396216c66050905f0
Author: Andy Wingo <address@hidden>
Date:   Wed Jul 4 14:32:45 2018 +0200

    Add support for reading ELF symbol table from C
    
    * libguile/loader.c (scm_i_program_address_range): New function.
      Currently unused, will wire up once we correct the compiler to emit
      symbols whose values are relative to the base addr.  Will be used by
      JIT so it needs to be fast.
      (register_elf): Rework to be less verbose, and record symtab/strtab.
      (struct mapped_elf_image): Add symtab and strtab members.
      (load_thunk_from_memory, process_dynamic_segment): Parse out DT_SYMTAB
      and DT_STRTAB.
      (Elf_Sym): New definition.
---
 libguile/loader.c | 123 ++++++++++++++++++++++++++++++++++++++----------------
 libguile/loader.h |   7 +++-
 2 files changed, 92 insertions(+), 38 deletions(-)

diff --git a/libguile/loader.c b/libguile/loader.c
index b37721c..8f25040 100644
--- a/libguile/loader.c
+++ b/libguile/loader.c
@@ -61,6 +61,7 @@
 #define ELFCLASS ELFCLASS32
 #define Elf_Phdr Elf32_Phdr
 #define Elf_Dyn Elf32_Dyn
+#define Elf_Sym Elf32_Sym
 #elif SIZEOF_UINTPTR_T == 8
 #define Elf_Half Elf64_Half
 #define Elf_Word Elf64_Word
@@ -68,6 +69,7 @@
 #define ELFCLASS ELFCLASS64
 #define Elf_Phdr Elf64_Phdr
 #define Elf_Dyn Elf64_Dyn
+#define Elf_Sym Elf64_Sym
 #else
 #error
 #endif
@@ -90,7 +92,8 @@
 /* The page size.  */
 static size_t page_size;
 
-static void register_elf (char *data, size_t len, char *frame_maps);
+static void register_elf (char *data, size_t len, char *frame_maps,
+                          char *symtab, char *strtab);
 
 enum bytecode_kind
   {
@@ -258,12 +261,14 @@ segment_flags_to_prot (Elf_Word flags)
 
 static char*
 process_dynamic_segment (char *base, Elf_Phdr *dyn_phdr,
-                         SCM *init_out, SCM *entry_out, char **frame_maps_out)
+                         SCM *init_out, SCM *entry_out, char **frame_maps_out,
+                         char **symtab_out, char **strtab_out)
 {
   char *dyn_addr = base + dyn_phdr->p_vaddr;
   Elf_Dyn *dyn = (Elf_Dyn *) dyn_addr;
   size_t i, dyn_size = dyn_phdr->p_memsz / sizeof (Elf_Dyn);
   char *init = 0, *gc_root = 0, *entry = 0, *frame_maps = 0;
+  char *symtab = 0, *strtab = 0;
   ptrdiff_t gc_root_size = 0;
   enum bytecode_kind bytecode_kind = BYTECODE_KIND_NONE;
 
@@ -279,6 +284,12 @@ process_dynamic_segment (char *base, Elf_Phdr *dyn_phdr,
             return "duplicate DT_INIT";
           init = base + dyn[i].d_un.d_val;
           break;
+        case DT_SYMTAB:
+          symtab = base + dyn[i].d_un.d_val;
+          break;
+        case DT_STRTAB:
+          strtab = base + dyn[i].d_un.d_val;
+          break;
         case DT_GUILE_GC_ROOT:
           if (gc_root)
             return "duplicate DT_GUILE_GC_ROOT";
@@ -344,6 +355,8 @@ process_dynamic_segment (char *base, Elf_Phdr *dyn_phdr,
   *init_out = init ? pointer_to_procedure (bytecode_kind, init) : SCM_BOOL_F;
   *entry_out = pointer_to_procedure (bytecode_kind, entry);
   *frame_maps_out = frame_maps;
+  *symtab_out = symtab;
+  *strtab_out = strtab;
 
   return NULL;
 }
@@ -361,7 +374,7 @@ load_thunk_from_memory (char *data, size_t len, int 
is_read_only)
   int i;
   int dynamic_segment = -1;
   SCM init = SCM_BOOL_F, entry = SCM_BOOL_F;
-  char *frame_maps = 0;
+  char *frame_maps = 0, *symtab = 0, *strtab = 0;
 
   errno = 0;
 
@@ -465,13 +478,14 @@ load_thunk_from_memory (char *data, size_t len, int 
is_read_only)
     }
 
   if ((err_msg = process_dynamic_segment (data, &ph[dynamic_segment],
-                                          &init, &entry, &frame_maps)))
+                                          &init, &entry, &frame_maps,
+                                          &symtab, &strtab)))
     goto cleanup;
 
   if (scm_is_true (init))
     scm_call_0 (init);
 
-  register_elf (data, len, frame_maps);
+  register_elf (data, len, frame_maps, symtab, strtab);
 
   /* Finally!  Return the thunk.  */
   return entry;
@@ -602,9 +616,11 @@ SCM_DEFINE (scm_load_thunk_from_memory, 
"load-thunk-from-memory", 1, 0, 0,
 
 struct mapped_elf_image
 {
-  char *start;
-  char *end;
-  char *frame_maps;
+  const char *start;
+  const char *end;
+  const char *frame_maps;
+  const char *symtab;
+  const char *strtab;
 };
 
 static struct mapped_elf_image *mapped_elf_images = NULL;
@@ -612,7 +628,7 @@ static size_t mapped_elf_images_count = 0;
 static size_t mapped_elf_images_allocated = 0;
 
 static size_t
-find_mapped_elf_insertion_index (char *ptr)
+find_mapped_elf_insertion_index (const char *ptr)
 {
   /* "mapped_elf_images_count" must never be dereferenced.  */
   size_t start = 0, end = mapped_elf_images_count;
@@ -631,7 +647,8 @@ find_mapped_elf_insertion_index (char *ptr)
 }
 
 static void
-register_elf (char *data, size_t len, char *frame_maps)
+register_elf (char *data, size_t len, char *frame_maps, char *symtab,
+              char *strtab)
 {
   scm_i_pthread_mutex_lock (&scm_i_misc_mutex);
   {
@@ -639,7 +656,7 @@ register_elf (char *data, size_t len, char *frame_maps)
     if (mapped_elf_images_count == mapped_elf_images_allocated)
       {
         struct mapped_elf_image *prev;
-        size_t n;
+        size_t old_size, new_size;
 
         if (mapped_elf_images_allocated)
           mapped_elf_images_allocated *= 2;
@@ -647,42 +664,33 @@ register_elf (char *data, size_t len, char *frame_maps)
           mapped_elf_images_allocated = 16;
 
         prev = mapped_elf_images;
-        mapped_elf_images =
-          scm_gc_malloc_pointerless (sizeof (*mapped_elf_images)
-                                     * mapped_elf_images_allocated,
-                                     "mapped elf images");
+        old_size = mapped_elf_images_count * sizeof (*mapped_elf_images);
+        new_size = mapped_elf_images_allocated * sizeof (*mapped_elf_images);
+        mapped_elf_images = scm_gc_malloc_pointerless (new_size, "mapped elf");
 
-        for (n = 0; n < mapped_elf_images_count; n++)
-          {
-            mapped_elf_images[n].start = prev[n].start;
-            mapped_elf_images[n].end = prev[n].end;
-            mapped_elf_images[n].frame_maps = prev[n].frame_maps;
-          }
+        memcpy (mapped_elf_images, prev, old_size);
       }
 
     {
-      size_t end;
       size_t n = find_mapped_elf_insertion_index (data);
 
-      for (end = mapped_elf_images_count; n < end; end--)
-        {
-          const struct mapped_elf_image *prev = &mapped_elf_images[end - 1];
-          mapped_elf_images[end].start = prev->start;
-          mapped_elf_images[end].end = prev->end;
-          mapped_elf_images[end].frame_maps = prev->frame_maps;
-        }
+      memmove (&mapped_elf_images[n+1], &mapped_elf_images[n],
+               (mapped_elf_images_count - n) * sizeof (*mapped_elf_images));
+
       mapped_elf_images_count++;
 
       mapped_elf_images[n].start = data;
       mapped_elf_images[n].end = data + len;
       mapped_elf_images[n].frame_maps = frame_maps;
+      mapped_elf_images[n].symtab = symtab;
+      mapped_elf_images[n].strtab = strtab;
     }
   }
   scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
 }
 
 static struct mapped_elf_image *
-find_mapped_elf_image_unlocked (char *ptr)
+find_mapped_elf_image_unlocked (const char *ptr)
 {
   size_t n = find_mapped_elf_insertion_index ((char *) ptr);
 
@@ -695,7 +703,7 @@ find_mapped_elf_image_unlocked (char *ptr)
 }
 
 static int
-find_mapped_elf_image (char *ptr, struct mapped_elf_image *image)
+find_mapped_elf_image (const char *ptr, struct mapped_elf_image *image)
 {
   int result;
 
@@ -771,9 +779,9 @@ const uint8_t *
 scm_find_slot_map_unlocked (const uint32_t *ip)
 {
   struct mapped_elf_image *image;
-  char *base;
-  struct frame_map_prefix *prefix;
-  struct frame_map_header *headers;
+  const char *base;
+  const struct frame_map_prefix *prefix;
+  const struct frame_map_header *headers;
   uintptr_t addr = (uintptr_t) ip;
   size_t start, end;
 
@@ -782,8 +790,8 @@ scm_find_slot_map_unlocked (const uint32_t *ip)
     return NULL;
 
   base = image->frame_maps;
-  prefix = (struct frame_map_prefix *) base;
-  headers = (struct frame_map_header *) (base + sizeof (*prefix));
+  prefix = (const struct frame_map_prefix *) base;
+  headers = (const struct frame_map_header *) (base + sizeof (*prefix));
 
   if (addr < ((uintptr_t) image->start) + prefix->text_offset)
     return NULL;
@@ -810,6 +818,49 @@ scm_find_slot_map_unlocked (const uint32_t *ip)
   return NULL;
 }
 
+int
+scm_i_program_address_range (const char *code, const char **start,
+                             const char **end)
+{
+  struct mapped_elf_image image;
+  ptrdiff_t size;
+  const Elf_Sym *symtab, *sym;
+  ptrdiff_t lo, hi, offset;
+
+  if (!find_mapped_elf_image (code, &image))
+    return 0;
+
+  if (!image.symtab || !image.strtab)
+    return 0;
+
+  /* The compiler will put the strtab directly after the symtab, which
+     lets us know the symtab size without traversing the section
+     table.  It's hacky but it's what glibc does.  */
+  if (image.symtab >= image.strtab)
+    abort ();
+
+  size = (image.strtab - image.symtab) / sizeof (Elf_Sym);
+  symtab = (const Elf_Sym *) image.symtab;
+  lo = 0, hi = size, offset = code - image.start;
+  while (lo < hi)
+    {
+      ptrdiff_t test = (lo + hi) / 2;
+      sym = symtab + test;
+      if (offset < sym->st_value)
+        hi = test;
+      else if (offset < sym->st_value + sym->st_size)
+        {
+          *start = image.start + sym->st_value;
+          *end = *start + sym->st_size;
+          return 1;
+        }
+      else
+        lo = test + 1;
+    }
+
+  return 0;
+}
+
 
 void
 scm_bootstrap_loader (void)
diff --git a/libguile/loader.h b/libguile/loader.h
index d9f632d..54ec9f7 100644
--- a/libguile/loader.h
+++ b/libguile/loader.h
@@ -55,8 +55,11 @@
 SCM_API SCM scm_load_thunk_from_file (SCM filename);
 SCM_API SCM scm_load_thunk_from_memory (SCM bv);
 
-SCM_INTERNAL const uint8_t *
-scm_find_slot_map_unlocked (const uint32_t *ip);
+SCM_INTERNAL const uint8_t * scm_find_slot_map_unlocked (const uint32_t *ip);
+
+SCM_INTERNAL int scm_i_program_address_range (const char *code,
+                                              const char **start,
+                                              const char **end);
 
 SCM_INTERNAL void scm_bootstrap_loader (void);
 SCM_INTERNAL void scm_init_loader (void);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]