From 91480beb18835278bcf08958b72f940a2d00967c Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Wed, 25 Apr 2012 09:05:02 +0200 Subject: [PATCH] Bug 747033 - Implement dl_iterate_phdr in the custom linker. r=froydnj --HG-- rename : mozglue/linker/CustomElf.h => mozglue/linker/Elfxx.h --- mozglue/linker/CustomElf.cpp | 2 + mozglue/linker/CustomElf.h | 227 +-------------------------------- mozglue/linker/ElfLoader.cpp | 20 +++ mozglue/linker/ElfLoader.h | 56 +++++++++ mozglue/linker/Elfxx.h | 236 +++++++++++++++++++++++++++++++++++ 5 files changed, 315 insertions(+), 226 deletions(-) create mode 100644 mozglue/linker/Elfxx.h diff --git a/mozglue/linker/CustomElf.cpp b/mozglue/linker/CustomElf.cpp index 4eac8a71e84..4f5152f2faf 100644 --- a/mozglue/linker/CustomElf.cpp +++ b/mozglue/linker/CustomElf.cpp @@ -291,6 +291,8 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const return FunctionPtr(__wrap_dlsym); if (strcmp(symbol + 2, "addr") == 0) return FunctionPtr(__wrap_dladdr); + if (strcmp(symbol + 2, "_iterate_phdr") == 0) + return FunctionPtr(__wrap_dl_iterate_phdr); } else if (symbol[0] == '_' && symbol[1] == '_') { /* Resolve a few C++ ABI specific functions to point to ours */ #ifdef __ARM_EABI__ diff --git a/mozglue/linker/CustomElf.h b/mozglue/linker/CustomElf.h index 043ea2c1fb4..74f789b27c3 100644 --- a/mozglue/linker/CustomElf.h +++ b/mozglue/linker/CustomElf.h @@ -5,234 +5,9 @@ #ifndef CustomElf_h #define CustomElf_h -/** - * Android system headers have two different elf.h file. The one under linux/ - * is the most complete. - */ -#ifdef ANDROID -#include -#else -#include -#endif -#include #include "ElfLoader.h" #include "Logging.h" - -/** - * Generic ELF macros for the target system - */ -#ifdef HAVE_64BIT_OS -#define Elf_(type) Elf64_ ## type -#define ELFCLASS ELFCLASS64 -#define ELF_R_TYPE ELF64_R_TYPE -#define ELF_R_SYM ELF64_R_SYM -#ifndef ELF_ST_BIND -#define ELF_ST_BIND ELF64_ST_BIND -#endif -#define PRIxAddr "lx" -#else -#define Elf_(type) Elf32_ ## type -#define ELFCLASS ELFCLASS32 -#define ELF_R_TYPE ELF32_R_TYPE -#define ELF_R_SYM ELF32_R_SYM -#ifndef ELF_ST_BIND -#define ELF_ST_BIND ELF32_ST_BIND -#endif -#define PRIxAddr "x" -#endif - -#ifndef __BYTE_ORDER -#error Cannot find endianness -#endif - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define ELFDATA ELFDATA2LSB -#elif __BYTE_ORDER == __BIG_ENDIAN -#define ELFDATA ELFDATA2MSB -#endif - -#ifdef __linux__ -#define ELFOSABI ELFOSABI_LINUX -#ifdef EI_ABIVERSION -#define ELFABIVERSION 0 -#endif -#else -#error Unknown ELF OSABI -#endif - -#if defined(__i386__) -#define ELFMACHINE EM_386 - -// Doing this way probably doesn't scale to other architectures -#define R_ABS R_386_32 -#define R_GLOB_DAT R_386_GLOB_DAT -#define R_JMP_SLOT R_386_JMP_SLOT -#define R_RELATIVE R_386_RELATIVE -#define RELOC(n) DT_REL ## n -#define UNSUPPORTED_RELOC(n) DT_RELA ## n -#define STR_RELOC(n) "DT_REL" # n -#define Reloc Rel - -#elif defined(__x86_64__) -#define ELFMACHINE EM_X86_64 - -#define R_ABS R_X86_64_64 -#define R_GLOB_DAT R_X86_64_GLOB_DAT -#define R_JMP_SLOT R_X86_64_JUMP_SLOT -#define R_RELATIVE R_X86_64_RELATIVE -#define RELOC(n) DT_RELA ## n -#define UNSUPPORTED_RELOC(n) DT_REL ## n -#define STR_RELOC(n) "DT_RELA" # n -#define Reloc Rela - -#elif defined(__arm__) -#define ELFMACHINE EM_ARM - -#ifndef R_ARM_ABS32 -#define R_ARM_ABS32 2 -#endif -#ifndef R_ARM_GLOB_DAT -#define R_ARM_GLOB_DAT 21 -#endif -#ifndef R_ARM_JUMP_SLOT -#define R_ARM_JUMP_SLOT 22 -#endif -#ifndef R_ARM_RELATIVE -#define R_ARM_RELATIVE 23 -#endif - -#define R_ABS R_ARM_ABS32 -#define R_GLOB_DAT R_ARM_GLOB_DAT -#define R_JMP_SLOT R_ARM_JUMP_SLOT -#define R_RELATIVE R_ARM_RELATIVE -#define RELOC(n) DT_REL ## n -#define UNSUPPORTED_RELOC(n) DT_RELA ## n -#define STR_RELOC(n) "DT_REL" # n -#define Reloc Rel - -#else -#error Unknown ELF machine type -#endif - -/** - * Android system headers don't have all definitions - */ -#ifndef STN_UNDEF -#define STN_UNDEF 0 -#endif -#ifndef DT_INIT_ARRAY -#define DT_INIT_ARRAY 25 -#endif -#ifndef DT_FINI_ARRAY -#define DT_FINI_ARRAY 26 -#endif -#ifndef DT_INIT_ARRAYSZ -#define DT_INIT_ARRAYSZ 27 -#endif -#ifndef DT_FINI_ARRAYSZ -#define DT_FINI_ARRAYSZ 28 -#endif -#ifndef DT_RELACOUNT -#define DT_RELACOUNT 0x6ffffff9 -#endif -#ifndef DT_RELCOUNT -#define DT_RELCOUNT 0x6ffffffa -#endif -#ifndef DT_VERSYM -#define DT_VERSYM 0x6ffffff0 -#endif -#ifndef DT_VERDEF -#define DT_VERDEF 0x6ffffffc -#endif -#ifndef DT_VERDEFNUM -#define DT_VERDEFNUM 0x6ffffffd -#endif -#ifndef DT_VERNEED -#define DT_VERNEED 0x6ffffffe -#endif -#ifndef DT_VERNEEDNUM -#define DT_VERNEEDNUM 0x6fffffff -#endif -#ifndef DT_FLAGS -#define DT_FLAGS 30 -#endif -#ifndef DF_SYMBOLIC -#define DF_SYMBOLIC 0x00000002 -#endif -#ifndef DF_TEXTREL -#define DF_TEXTREL 0x00000004 -#endif - -namespace Elf { - -/** - * Define a few basic Elf Types - */ -typedef Elf_(Phdr) Phdr; -typedef Elf_(Dyn) Dyn; -typedef Elf_(Sym) Sym; -typedef Elf_(Addr) Addr; -typedef Elf_(Word) Word; - -/** - * Helper class around the standard Elf header struct - */ -struct Ehdr: public Elf_(Ehdr) -{ - /** - * Equivalent to reinterpret_cast(buf), but additionally - * checking that this is indeed an Elf header and that the Elf type - * corresponds to that of the system - */ - static const Ehdr *validate(const void *buf); -}; - -/** - * Elf String table - */ -class Strtab: public UnsizedArray -{ -public: - /** - * Returns the string at the given index in the table - */ - const char *GetStringAt(off_t index) const - { - return &UnsizedArray::operator[](index); - } -}; - -/** - * Helper class around Elf relocation. - */ -struct Rel: public Elf_(Rel) -{ - /** - * Returns the addend for the relocation, which is the value stored - * at r_offset. - */ - Addr GetAddend(void *base) const - { - return *(reinterpret_cast( - reinterpret_cast(base) + r_offset)); - } -}; - -/** - * Helper class around Elf relocation with addend. - */ -struct Rela: public Elf_(Rela) -{ - /** - * Returns the addend for the relocation. - */ - Addr GetAddend(void *base) const - { - return r_addend; - } -}; - -} /* namespace Elf */ +#include "Elfxx.h" class Mappable; diff --git a/mozglue/linker/ElfLoader.cpp b/mozglue/linker/ElfLoader.cpp index d33aa67eb45..7cdb1bd48fb 100644 --- a/mozglue/linker/ElfLoader.cpp +++ b/mozglue/linker/ElfLoader.cpp @@ -92,6 +92,26 @@ __wrap_dladdr(void *addr, Dl_info *info) return 1; } +int +__wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data) +{ + if (ElfLoader::Singleton.dbg == NULL) + return -1; + + for (ElfLoader::r_debug::iterator it = ElfLoader::Singleton.dbg->begin(); + it < ElfLoader::Singleton.dbg->end(); ++it) { + dl_phdr_info info; + info.dlpi_addr = reinterpret_cast(it->l_addr); + info.dlpi_name = it->l_name; + info.dlpi_phdr = NULL; + info.dlpi_phnum = 0; + int ret = callback(&info, sizeof(dl_phdr_info), data); + if (ret) + return ret; + } + return 0; +} + namespace { /** diff --git a/mozglue/linker/ElfLoader.h b/mozglue/linker/ElfLoader.h index d5df3f5f943..2c0a6fa0765 100644 --- a/mozglue/linker/ElfLoader.h +++ b/mozglue/linker/ElfLoader.h @@ -10,6 +10,7 @@ #include #include "mozilla/RefPtr.h" #include "Zip.h" +#include "Elfxx.h" /** * dlfcn.h replacement functions @@ -33,6 +34,16 @@ extern "C" { sighandler_t __wrap_signal(int signum, sighandler_t handler); int __wrap_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); + + struct dl_phdr_info { + Elf::Addr dlpi_addr; + 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); } /** @@ -356,6 +367,8 @@ private: /* Keep track of Zips used for library loading */ ZipCollection zips; + /* Forward declaration, see further below */ + class r_debug; public: /* Loaded object descriptor for the debugger interface below*/ struct link_map { @@ -365,6 +378,9 @@ public: const char *l_name; /* Address of the PT_DYNAMIC segment. */ const void *l_ld; + + private: + friend class ElfLoader::r_debug; /* Double linked list of loaded objects. */ link_map *l_next, *l_prev; }; @@ -381,6 +397,45 @@ private: /* Make the debugger aware of the unloading of an object */ void Remove(link_map *map); + /* Iterates over all link_maps */ + class iterator + { + public: + const link_map *operator ->() const + { + return item; + } + + const link_map &operator ++() + { + item = item->l_next; + return *item; + } + + bool operator<(const iterator &other) const + { + if (other.item == NULL) + return item ? true : false; + MOZ_NOT_REACHED("r_debug::iterator::operator< called with something else than r_debug::end()"); + } + protected: + friend class r_debug; + iterator(const link_map *item): item(item) { } + + private: + const link_map *item; + }; + + iterator begin() const + { + return iterator(r_map); + } + + iterator end() const + { + return iterator(NULL); + } + private: /* Version number of the protocol. */ int r_version; @@ -401,6 +456,7 @@ private: RT_DELETE /* Beginning to remove an object */ } r_state; }; + friend int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data); r_debug *dbg; /** diff --git a/mozglue/linker/Elfxx.h b/mozglue/linker/Elfxx.h new file mode 100644 index 00000000000..cd871561bda --- /dev/null +++ b/mozglue/linker/Elfxx.h @@ -0,0 +1,236 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef Elfxx_h +#define Elfxx_h + +/** + * Android system headers have two different elf.h file. The one under linux/ + * is the most complete. + */ +#ifdef ANDROID +#include +#else +#include +#endif +#include + +/** + * Generic ELF macros for the target system + */ +#ifdef HAVE_64BIT_OS +#define Elf_(type) Elf64_ ## type +#define ELFCLASS ELFCLASS64 +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_SYM ELF64_R_SYM +#ifndef ELF_ST_BIND +#define ELF_ST_BIND ELF64_ST_BIND +#endif +#define PRIxAddr "lx" +#else +#define Elf_(type) Elf32_ ## type +#define ELFCLASS ELFCLASS32 +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_SYM ELF32_R_SYM +#ifndef ELF_ST_BIND +#define ELF_ST_BIND ELF32_ST_BIND +#endif +#define PRIxAddr "x" +#endif + +#ifndef __BYTE_ORDER +#error Cannot find endianness +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ELFDATA ELFDATA2LSB +#elif __BYTE_ORDER == __BIG_ENDIAN +#define ELFDATA ELFDATA2MSB +#endif + +#ifdef __linux__ +#define ELFOSABI ELFOSABI_LINUX +#ifdef EI_ABIVERSION +#define ELFABIVERSION 0 +#endif +#else +#error Unknown ELF OSABI +#endif + +#if defined(__i386__) +#define ELFMACHINE EM_386 + +// Doing this way probably doesn't scale to other architectures +#define R_ABS R_386_32 +#define R_GLOB_DAT R_386_GLOB_DAT +#define R_JMP_SLOT R_386_JMP_SLOT +#define R_RELATIVE R_386_RELATIVE +#define RELOC(n) DT_REL ## n +#define UNSUPPORTED_RELOC(n) DT_RELA ## n +#define STR_RELOC(n) "DT_REL" # n +#define Reloc Rel + +#elif defined(__x86_64__) +#define ELFMACHINE EM_X86_64 + +#define R_ABS R_X86_64_64 +#define R_GLOB_DAT R_X86_64_GLOB_DAT +#define R_JMP_SLOT R_X86_64_JUMP_SLOT +#define R_RELATIVE R_X86_64_RELATIVE +#define RELOC(n) DT_RELA ## n +#define UNSUPPORTED_RELOC(n) DT_REL ## n +#define STR_RELOC(n) "DT_RELA" # n +#define Reloc Rela + +#elif defined(__arm__) +#define ELFMACHINE EM_ARM + +#ifndef R_ARM_ABS32 +#define R_ARM_ABS32 2 +#endif +#ifndef R_ARM_GLOB_DAT +#define R_ARM_GLOB_DAT 21 +#endif +#ifndef R_ARM_JUMP_SLOT +#define R_ARM_JUMP_SLOT 22 +#endif +#ifndef R_ARM_RELATIVE +#define R_ARM_RELATIVE 23 +#endif + +#define R_ABS R_ARM_ABS32 +#define R_GLOB_DAT R_ARM_GLOB_DAT +#define R_JMP_SLOT R_ARM_JUMP_SLOT +#define R_RELATIVE R_ARM_RELATIVE +#define RELOC(n) DT_REL ## n +#define UNSUPPORTED_RELOC(n) DT_RELA ## n +#define STR_RELOC(n) "DT_REL" # n +#define Reloc Rel + +#else +#error Unknown ELF machine type +#endif + +/** + * Android system headers don't have all definitions + */ +#ifndef STN_UNDEF +#define STN_UNDEF 0 +#endif +#ifndef DT_INIT_ARRAY +#define DT_INIT_ARRAY 25 +#endif +#ifndef DT_FINI_ARRAY +#define DT_FINI_ARRAY 26 +#endif +#ifndef DT_INIT_ARRAYSZ +#define DT_INIT_ARRAYSZ 27 +#endif +#ifndef DT_FINI_ARRAYSZ +#define DT_FINI_ARRAYSZ 28 +#endif +#ifndef DT_RELACOUNT +#define DT_RELACOUNT 0x6ffffff9 +#endif +#ifndef DT_RELCOUNT +#define DT_RELCOUNT 0x6ffffffa +#endif +#ifndef DT_VERSYM +#define DT_VERSYM 0x6ffffff0 +#endif +#ifndef DT_VERDEF +#define DT_VERDEF 0x6ffffffc +#endif +#ifndef DT_VERDEFNUM +#define DT_VERDEFNUM 0x6ffffffd +#endif +#ifndef DT_VERNEED +#define DT_VERNEED 0x6ffffffe +#endif +#ifndef DT_VERNEEDNUM +#define DT_VERNEEDNUM 0x6fffffff +#endif +#ifndef DT_FLAGS +#define DT_FLAGS 30 +#endif +#ifndef DF_SYMBOLIC +#define DF_SYMBOLIC 0x00000002 +#endif +#ifndef DF_TEXTREL +#define DF_TEXTREL 0x00000004 +#endif + +namespace Elf { + +/** + * Define a few basic Elf Types + */ +typedef Elf_(Phdr) Phdr; +typedef Elf_(Dyn) Dyn; +typedef Elf_(Sym) Sym; +typedef Elf_(Addr) Addr; +typedef Elf_(Word) Word; +typedef Elf_(Half) Half; + +/** + * Helper class around the standard Elf header struct + */ +struct Ehdr: public Elf_(Ehdr) +{ + /** + * Equivalent to reinterpret_cast(buf), but additionally + * checking that this is indeed an Elf header and that the Elf type + * corresponds to that of the system + */ + static const Ehdr *validate(const void *buf); +}; + +/** + * Elf String table + */ +class Strtab: public UnsizedArray +{ +public: + /** + * Returns the string at the given index in the table + */ + const char *GetStringAt(off_t index) const + { + return &UnsizedArray::operator[](index); + } +}; + +/** + * Helper class around Elf relocation. + */ +struct Rel: public Elf_(Rel) +{ + /** + * Returns the addend for the relocation, which is the value stored + * at r_offset. + */ + Addr GetAddend(void *base) const + { + return *(reinterpret_cast( + reinterpret_cast(base) + r_offset)); + } +}; + +/** + * Helper class around Elf relocation with addend. + */ +struct Rela: public Elf_(Rela) +{ + /** + * Returns the addend for the relocation. + */ + Addr GetAddend(void *base) const + { + return r_addend; + } +}; + +} /* namespace Elf */ + +#endif /* Elfxx_h */