Bug 930627 - Implement __gnu_Unwind_Find_exidx in custom linker on ARM. r=glandium
authorJim Chen <nchen@mozilla.com>
Thu, 31 Oct 2013 11:40:32 -0400
changeset 152838 88ac9143dd30ba7eadc72ff28e5ae4288deef9eb
parent 152837 c63ff7228f229aaed3e80d23027a5ed8c4463b76
child 152839 ba3b81d178deb38ee269beac65de5e3ed51e0b6d
push id3270
push userryanvm@gmail.com
push dateThu, 31 Oct 2013 20:11:16 +0000
treeherderfx-team@e6b861af3117 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs930627
milestone28.0a1
Bug 930627 - Implement __gnu_Unwind_Find_exidx in custom linker on ARM. r=glandium
mozglue/linker/CustomElf.cpp
mozglue/linker/CustomElf.h
mozglue/linker/ElfLoader.cpp
mozglue/linker/ElfLoader.h
mozglue/linker/Elfxx.h
--- a/mozglue/linker/CustomElf.cpp
+++ b/mozglue/linker/CustomElf.cpp
@@ -113,16 +113,19 @@ CustomElf::Load(Mappable *mappable, cons
   std::vector<const Phdr *> pt_loads;
   Addr min_vaddr = (Addr) -1; // We want to find the lowest and biggest
   Addr max_vaddr = 0;         // virtual address used by this Elf.
   const Phdr *dyn = NULL;
 
   const Phdr *first_phdr = reinterpret_cast<const Phdr *>(
                            reinterpret_cast<const char *>(ehdr) + ehdr->e_phoff);
   const Phdr *end_phdr = &first_phdr[ehdr->e_phnum];
+#ifdef __ARM_EABI__
+  const Phdr *arm_exidx_phdr = NULL;
+#endif
 
   for (const Phdr *phdr = first_phdr; phdr < end_phdr; phdr++) {
     switch (phdr->p_type) {
       case PT_LOAD:
         debug_phdr("PT_LOAD", phdr);
         pt_loads.push_back(phdr);
         if (phdr->p_vaddr < min_vaddr)
           min_vaddr = phdr->p_vaddr;
@@ -150,16 +153,23 @@ CustomElf::Load(Mappable *mappable, cons
 // Skip on Android until bug 706116 is fixed
 #ifndef ANDROID
         if (phdr->p_flags & PF_X) {
           LOG("%s: Executable stack is not supported", elf->GetPath());
           return NULL;
         }
 #endif
         break;
+#ifdef __ARM_EABI__
+      case PT_ARM_EXIDX:
+        /* We cannot initialize arm_exidx here
+           because we don't have a base yet */
+        arm_exidx_phdr = phdr;
+        break;
+#endif
       default:
         DEBUG_LOG("%s: Warning: program header type #%d not handled",
                   elf->GetPath(), phdr->p_type);
     }
   }
 
   if (min_vaddr != 0) {
     LOG("%s: Unsupported minimal virtual address: 0x%08" PRIxAddr,
@@ -205,16 +215,22 @@ CustomElf::Load(Mappable *mappable, cons
   elf->l_addr = elf->base;
   elf->l_name = elf->GetPath();
   elf->l_ld = elf->GetPtr<Dyn>(dyn->p_vaddr);
   ElfLoader::Singleton.Register(elf);
 
   if (!elf->InitDyn(dyn))
     return NULL;
 
+#ifdef __ARM_EABI__
+  if (arm_exidx_phdr)
+    elf->arm_exidx.InitSize(elf->GetPtr(arm_exidx_phdr->p_vaddr),
+                            arm_exidx_phdr->p_memsz);
+#endif
+
   elf->stats("oneLibLoaded");
   DEBUG_LOG("CustomElf::Load(\"%s\", 0x%x) = %p", path, flags,
             static_cast<void *>(elf));
   return elf;
 }
 
 CustomElf::~CustomElf()
 {
@@ -294,16 +310,20 @@ CustomElf::GetSymbolPtrInDeps(const char
       return FunctionPtr(&ElfLoader::__wrap_cxa_atexit);
 #endif
     if (strcmp(symbol + 2, "cxa_finalize") == 0)
       return FunctionPtr(&ElfLoader::__wrap_cxa_finalize);
     if (strcmp(symbol + 2, "dso_handle") == 0)
       return const_cast<CustomElf *>(this);
     if (strcmp(symbol + 2, "moz_linker_stats") == 0)
       return FunctionPtr(&ElfLoader::stats);
+#ifdef __ARM_EABI__
+    if (strcmp(symbol + 2, "gnu_Unwind_Find_exidx") == 0)
+      return FunctionPtr(__wrap___gnu_Unwind_Find_exidx);
+#endif
   }
 
   void *sym;
   /* Search the symbol in the main program. Note this also tries all libraries
    * the system linker will have loaded RTLD_GLOBAL. Unfortunately, that doesn't
    * work with bionic, but its linker doesn't normally search the main binary
    * anyways. Moreover, on android, the main binary is dalvik. */
 #ifdef __GLIBC__
@@ -356,16 +376,29 @@ CustomElf::GetSymbol(const char *symbol,
 }
 
 bool
 CustomElf::Contains(void *addr) const
 {
   return base.Contains(addr);
 }
 
+#ifdef __ARM_EABI__
+const void *
+CustomElf::FindExidx(int *pcount) const
+{
+  if (arm_exidx) {
+    *pcount = arm_exidx.numElements();
+    return arm_exidx;
+  }
+  *pcount = 0;
+  return NULL;
+}
+#endif
+
 void
 CustomElf::stats(const char *when) const
 {
   mappable->stats(when, GetPath());
 }
 
 bool
 CustomElf::LoadSegment(const Phdr *pt_load) const
--- a/mozglue/linker/CustomElf.h
+++ b/mozglue/linker/CustomElf.h
@@ -32,16 +32,20 @@ public:
 
   /**
    * Inherited from LibHandle
    */
   virtual ~CustomElf();
   virtual void *GetSymbolPtr(const char *symbol) const;
   virtual bool Contains(void *addr) const;
 
+#ifdef __ARM_EABI__
+  virtual const void *FindExidx(int *pcount) const;
+#endif
+
 protected:
   virtual Mappable *GetMappable() const;
 
 public:
   /**
    * Shows some stats about the Mappable instance. The when argument is to be
    * used by the caller to give an identifier of the when the stats call is
    * made.
@@ -183,11 +187,16 @@ private:
    * (.init/.fini) */
   Elf::Addr init, fini;
 
   /* List of initialization and destruction functions
    * (.init_array/.fini_array) */
   Array<void *> init_array, fini_array;
 
   bool initialized;
+
+#ifdef __ARM_EABI__
+  /* ARM.exidx information used by FindExidx */
+  Array<uint32_t[2]> arm_exidx;
+#endif
 };
 
 #endif /* CustomElf_h */
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -28,16 +28,21 @@ extern "C" {
 inline int sigaltstack(const stack_t *ss, stack_t *oss) {
   return syscall(__NR_sigaltstack, ss, oss);
 }
 
 } /* extern "C" */
 #endif /* __ANDROID_API__ */
 #endif /* ANDROID */
 
+#ifdef __ARM_EABI__
+extern "C" const void *
+__gnu_Unwind_Find_exidx(void *pc, int *pcount) __attribute__((weak));
+#endif
+
 using namespace mozilla;
 
 /**
  * dlfcn.h replacements functions
  */
 
 void *
 __wrap_dlopen(const char *path, int flags)
@@ -120,16 +125,30 @@ int
 
     int ret = callback(&info, sizeof(dl_phdr_info), data);
     if (ret)
       return ret;
   }
   return 0;
 }
 
+#ifdef __ARM_EABI__
+const void *
+__wrap___gnu_Unwind_Find_exidx(void *pc, int *pcount)
+{
+  RefPtr<LibHandle> handle = ElfLoader::Singleton.GetHandleByPtr(pc);
+  if (handle)
+    return handle->FindExidx(pcount);
+  if (__gnu_Unwind_Find_exidx)
+    return __gnu_Unwind_Find_exidx(pc, pcount);
+  *pcount = 0;
+  return NULL;
+}
+#endif
+
 /**
  * faulty.lib public API
  */
 
 MFBT_API size_t
 __dl_get_mappable_length(void *handle) {
   if (!handle)
     return 0;
@@ -281,16 +300,27 @@ SystemElf::GetMappable() const
     systemPath += path;
     path = systemPath.c_str();
   }
 #endif
 
   return MappableFile::Create(path);
 }
 
+#ifdef __ARM_EABI__
+const void *
+SystemElf::FindExidx(int *pcount) const
+{
+  /* TODO: properly implement when ElfLoader::GetHandleByPtr
+     does return SystemElf handles */
+  *pcount = 0;
+  return NULL;
+}
+#endif
+
 /**
  * ElfLoader
  */
 
 /* Unique ElfLoader instance */
 ElfLoader ElfLoader::Singleton;
 
 TemporaryRef<LibHandle>
--- a/mozglue/linker/ElfLoader.h
+++ b/mozglue/linker/ElfLoader.h
@@ -37,16 +37,20 @@ extern "C" {
     const char *dlpi_name;
     const Elf::Phdr *dlpi_phdr;
     Elf::Half dlpi_phnum;
   };
 
   typedef int (*dl_phdr_cb)(struct dl_phdr_info *, size_t, void *);
   int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data);
 
+#ifdef __ARM_EABI__
+  const void *__wrap___gnu_Unwind_Find_exidx(void *pc, int *pcount);
+#endif
+
 /**
  * faulty.lib public API
  */
 MFBT_API size_t
 __dl_get_mappable_length(void *handle);
 
 MFBT_API void *
 __dl_mmap(void *handle, void *addr, size_t length, off_t offset);
@@ -176,16 +180,24 @@ public:
   void *MappableMMap(void *addr, size_t length, off_t offset) const;
 
   /**
    * Unmaps a memory mapping of the file or stream behind the library
    * handle.
    */
   void MappableMUnmap(void *addr, size_t length) const;
 
+#ifdef __ARM_EABI__
+  /**
+   * Find the address and entry count of the ARM.exidx section
+   * associated with the library
+   */
+  virtual const void *FindExidx(int *pcount) const = 0;
+#endif
+
 protected:
   /**
    * Returns a mappable object for use by MappableMMap and related functions.
    */
   virtual Mappable *GetMappable() const = 0;
 
   /**
    * Returns whether the handle is a SystemElf or not. (short of a better way
@@ -250,16 +262,20 @@ public:
 
   /**
    * Inherited from LibHandle
    */
   virtual ~SystemElf();
   virtual void *GetSymbolPtr(const char *symbol) const;
   virtual bool Contains(void *addr) const { return false; /* UNIMPLEMENTED */ }
 
+#ifdef __ARM_EABI__
+  virtual const void *FindExidx(int *pcount) const;
+#endif
+
 protected:
   virtual Mappable *GetMappable() const;
 
   /**
    * Returns whether the handle is a SystemElf or not. (short of a better way
    * to do this without RTTI)
    */
   friend class ElfLoader;
--- a/mozglue/linker/Elfxx.h
+++ b/mozglue/linker/Elfxx.h
@@ -11,16 +11,20 @@
  */
 #ifdef ANDROID
 #include <linux/elf.h>
 #else
 #include <elf.h>
 #endif
 #include <endian.h>
 
+#if defined(__ARM_EABI__) && !defined(PT_ARM_EXIDX)
+#define PT_ARM_EXIDX 0x70000001
+#endif
+
 /**
  * Generic ELF macros for the target system
  */
 #ifdef __LP64__
 #define Elf_(type) Elf64_ ## type
 #define ELFCLASS ELFCLASS64
 #define ELF_R_TYPE ELF64_R_TYPE
 #define ELF_R_SYM ELF64_R_SYM