blob: fbc7f8e92da185575c547697f29ce35f98837104 [file] [log] [blame]
// Copyright 2014 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 <utility>
#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_memory_mapping.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_; }
// Return name of the library as found in DT_SONAME entry, or same
// as base_name() if not available.
const char* soname() const { return soname_; }
// 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,
const Vector<LibraryView*>* preloads,
const 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 CallJniOnLoad(void* java_vm, int minimum_jni_version, Error* error);
// Call 'JNI_OnUnload()' is necessary, i.e. if there was a succesful call
// to CallJniOnLoad() before, or nothing otherwise.
void CallJniOnUnload();
// Release reserved memory mapping. Caller takes ownership. Used to delay
// the unmapping of the library segments in the case of delayed RDebug
// operations.
MemoryMapping ReleaseMapping() { return std::move(reserved_map_); }
// 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:
explicit 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_;
MemoryMapping reserved_map_;
ELF::Addr relro_start_ = 0;
ELF::Addr relro_size_ = 0;
bool relro_used_ = false;
SharedLibrary* list_next_ = nullptr;
SharedLibrary* list_prev_ = nullptr;
unsigned flags_ = 0;
linker_function_t* preinit_array_ = nullptr;
size_t preinit_array_count_ = 0;
linker_function_t* init_array_ = nullptr;
size_t init_array_count_ = 0;
linker_function_t* fini_array_ = nullptr;
size_t fini_array_count_ = 0;
linker_function_t init_func_ = nullptr;
linker_function_t fini_func_ = nullptr;
#ifdef __arm__
// ARM EABI section used for stack unwinding.
unsigned* arm_exidx_ = nullptr;
size_t arm_exidx_count_ = 0;
#endif
link_map_t link_map_ = {};
bool has_DT_SYMBOLIC_ = false;
void* java_vm_ = nullptr;
const char* soname_ = nullptr;
const char* base_name_ = nullptr;
char full_path_[512];
};
} // namespace crazy
#endif // CRAZY_LINKER_SHARED_LIBRARY_H