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 167406 88ac9143dd30ba7eadc72ff28e5ae4288deef9eb
parent 167405 c63ff7228f229aaed3e80d23027a5ed8c4463b76
child 167407 ba3b81d178deb38ee269beac65de5e3ed51e0b6d
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs930627
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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