text: // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef CRAZY_LINKER_SHARED_LIBRARY_H
  #define CRAZY_LINKER_SHARED_LIBRARY_H
  
  #include <link.h>
  
  #include "crazy_linker_elf_relro.h"
  #include "crazy_linker_elf_symbols.h"
  #include "crazy_linker_elf_view.h"
  #include "crazy_linker_error.h"
  #include "crazy_linker_rdebug.h"
  #include "crazy_linker_util.h"
  #include "elf_traits.h"
  
  namespace crazy {
  
  class LibraryList;
  class LibraryView;
  
  // A class that models a shared library loaded by the crazy linker.
  
  // Libraries have dependencies (which are listed in their dynamic section
  // as DT_NEEDED entries). Circular dependencies are forbidden, so they
  // form an ADG, where the root is the crazy linker itself, since all
  // libraries that it loads will depend on it (to ensure their
  // dlopen/dlsym/dlclose calls are properly wrapped).
  
  class SharedLibrary {
   public:
    SharedLibrary();
    ~SharedLibrary();
  
    size_t load_address() const { return view_.load_address(); }
    size_t load_size() const { return view_.load_size(); }
    size_t load_bias() const { return view_.load_bias(); }
    const ELF::Phdr* phdr() const { return view_.phdr(); }
    size_t phdr_count() const { return view_.phdr_count(); }
    const char* base_name() const { return base_name_; }
  
    // Load a library (without its dependents) from an ELF file.
    // Note: This does not apply relocations, nor runs constructors.
    // |full_path| if the file full path.
    // |load_address| is the page-aligned load address in memory, or 0.
    // |file_offset| is the page-aligned file offset.
    // On failure, return false and set |error| message.
    //
    // After this, the caller should load all library dependencies,
    // Then call Relocate() and CallConstructors() to complete the
    // operation.
    bool Load(const char* full_path,
              size_t load_address,
              size_t file_offset,
              Error* error);
  
    // Relocate this library, assuming all its dependencies are already
    // loaded in |lib_list|. On failure, return false and set |error|
    // message.
    bool Relocate(LibraryList* lib_list,
                  Vector<LibraryView*>* dependencies,
                  Error* error);
  
    void GetInfo(size_t* load_address,
                 size_t* load_size,
                 size_t* relro_start,
                 size_t* relro_size) {
      *load_address = view_.load_address();
      *load_size = view_.load_size();
      *relro_start = relro_start_;
      *relro_size = relro_size_;
    }
  
    // Returns true iff a given library is mapped to a virtual address range
    // that contains a given address.
    bool ContainsAddress(void* address) const {
      size_t addr = reinterpret_cast<size_t>(address);
      return load_address() <= addr && addr <= load_address() + load_size();
    }
  
    // Call all constructors in the library.
    void CallConstructors();
  
    // Call all destructors in the library.
    void CallDestructors();
  
    // Return the ELF symbol entry for a given symbol, if defined by
    // this library, or NULL otherwise.
    const ELF::Sym* LookupSymbolEntry(const char* symbol_name);
  
    // Find the nearest symbol near a given |address|. On success, return
    // true and set |*sym_name| to the symbol name, |*sym_addr| to its address
    // in memory, and |*sym_size| to its size in bytes, if any.
    bool FindNearestSymbolForAddress(void* address,
                                     const char** sym_name,
                                     void** sym_addr,
                                     size_t* sym_size) {
      return symbols_.LookupNearestByAddress(
          address, load_bias(), sym_name, sym_addr, sym_size);
    }
  
    // Return the address of a given |symbol_name| if it is exported
    // by the library, NULL otherwise.
    void* FindAddressForSymbol(const char* symbol_name);
  
    // Create a new Ashmem region holding a copy of the library's RELRO section,
    // potentially relocated for a new |load_address|. On success, return true
    // and sets |*relro_start|, |*relro_size| and |*relro_fd|. Note that the
    // RELRO start address is adjusted for |load_address|, and that the caller
    // becomes the owner of |*relro_fd|. On failure, return false and set
    // |error| message.
    bool CreateSharedRelro(size_t load_address,
                           size_t* relro_start,
                           size_t* relro_size,
                           int* relro_fd,
                           Error* error);
  
    // Try to use a shared relro section from another process.
    // On success, return true. On failure return false and
    // sets |error| message.
    bool UseSharedRelro(size_t relro_start,
                        size_t relro_size,
                        int relro_fd,
                        Error* error);
  
    // Look for a symbol named 'JNI_OnLoad' in this library, and if it
    // exists, call it with |java_vm| as the first parameter. If the
    // function result is less than |minimum_jni_version|, fail with
    // a message in |error|. On success, return true, and record
    // |java_vm| to call 'JNI_OnUnload' at unload time, if present.
    bool SetJavaVM(void* java_vm, int minimum_jni_version, Error* error);
  
    // Call 'JNI_OnUnload()' is necessary, i.e. if there was a succesful call
    // to SetJavaVM() before. This will pass the same |java_vm| value to the
    // callback, if it is present in the library.
    void CallJniOnUnload();
  
    // Helper class to iterate over dependencies in a given SharedLibrary.
    // Usage:
    //    SharedLibary::DependencyIterator iter(lib);
    //    while (iter.GetNext() {
    //      dependency_name = iter.GetName();
    //      ...
    //    }
    class DependencyIterator {
     public:
      DependencyIterator(SharedLibrary* lib)
          : iter_(&lib->view_), symbols_(&lib->symbols_), dep_name_(NULL) {}
  
      bool GetNext();
  
      const char* GetName() const { return dep_name_; }
  
     private:
      DependencyIterator();
      DependencyIterator(const DependencyIterator&);
      DependencyIterator& operator=(const DependencyIterator&);
  
      ElfView::DynamicIterator iter_;
      const ElfSymbols* symbols_;
      const char* dep_name_;
    };
  
    typedef void (*linker_function_t)();
  
   private:
    friend class LibraryList;
  
    ElfView view_;
    ElfSymbols symbols_;
  
    ELF::Addr relro_start_;
    ELF::Addr relro_size_;
    bool relro_used_;
  
    SharedLibrary* list_next_;
    SharedLibrary* list_prev_;
    unsigned flags_;
  
    linker_function_t* preinit_array_;
    size_t preinit_array_count_;
    linker_function_t* init_array_;
    size_t init_array_count_;
    linker_function_t* fini_array_;
    size_t fini_array_count_;
    linker_function_t init_func_;
    linker_function_t fini_func_;
  
  #ifdef __arm__
    // ARM EABI section used for stack unwinding.
    unsigned* arm_exidx_;
    size_t arm_exidx_count_;
  #endif
  
    link_map_t link_map_;
  
    bool has_DT_SYMBOLIC_;
  
    void* java_vm_;
  
    const char* base_name_;
    char full_path_[512];
  };
  
  }  // namespace crazy
  
  #endif  // CRAZY_LINKER_SHARED_LIBRARY_H
  