Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "crazy_linker_library_list.h"
      6 
      7 #include <dlfcn.h>
      8 
      9 #include "crazy_linker_debug.h"
     10 #include "crazy_linker_library_view.h"
     11 #include "crazy_linker_globals.h"
     12 #include "crazy_linker_rdebug.h"
     13 #include "crazy_linker_shared_library.h"
     14 #include "crazy_linker_system.h"
     15 
     16 namespace crazy {
     17 
     18 namespace {
     19 
     20 // A helper struct used when looking up symbols in libraries.
     21 struct SymbolLookupState {
     22   void* found_addr;
     23   void* weak_addr;
     24   int weak_count;
     25 
     26   SymbolLookupState() : found_addr(NULL), weak_addr(NULL), weak_count(0) {}
     27 
     28   // Check a symbol entry.
     29   bool CheckSymbol(const char* symbol, SharedLibrary* lib) {
     30     const ELF::Sym* entry = lib->LookupSymbolEntry(symbol);
     31     if (!entry)
     32       return false;
     33 
     34     void* address = reinterpret_cast<void*>(lib->load_bias() + entry->st_value);
     35 
     36     // If this is a strong symbol, record it and return true.
     37     if (ELF_ST_BIND(entry->st_info) == STB_GLOBAL) {
     38       found_addr = address;
     39       return true;
     40     }
     41     // If this is a weak symbol, record the first one and
     42     // increment the weak_count.
     43     if (++weak_count == 1)
     44       weak_addr = address;
     45 
     46     return false;
     47   }
     48 };
     49 
     50 }  // namespace
     51 
     52 LibraryList::LibraryList() : head_(0), count_(0), has_error_(false) {
     53   // Nothing for now
     54 }
     55 
     56 LibraryList::~LibraryList() {
     57   // Invalidate crazy library list.
     58   head_ = NULL;
     59 
     60   // Destroy all known libraries.
     61   while (!known_libraries_.IsEmpty()) {
     62     LibraryView* wrap = known_libraries_.PopLast();
     63     delete wrap;
     64   }
     65 }
     66 
     67 LibraryView* LibraryList::FindLibraryByName(const char* base_name) {
     68   // Sanity check.
     69   if (!base_name || strchr(base_name, '/'))
     70     return NULL;
     71 
     72   for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
     73     LibraryView* wrap = known_libraries_[n];
     74     if (!strcmp(base_name, wrap->GetName()))
     75       return wrap;
     76   }
     77   return NULL;
     78 }
     79 
     80 void* LibraryList::FindSymbolFrom(const char* symbol_name, LibraryView* from) {
     81   SymbolLookupState lookup_state;
     82 
     83   if (!from)
     84     return NULL;
     85 
     86   // Use a work-queue and a set to ensure to perform a breadth-first
     87   // search.
     88   Vector<LibraryView*> work_queue;
     89   Set<LibraryView*> visited_set;
     90 
     91   work_queue.PushBack(from);
     92 
     93   while (!work_queue.IsEmpty()) {
     94     LibraryView* lib = work_queue.PopFirst();
     95     if (lib->IsCrazy()) {
     96       if (lookup_state.CheckSymbol(symbol_name, lib->GetCrazy()))
     97         return lookup_state.found_addr;
     98     } else if (lib->IsSystem()) {
     99       // TODO(digit): Support weak symbols in system libraries.
    100       // With the current code, all symbols in system libraries
    101       // are assumed to be non-weak.
    102       void* addr = lib->LookupSymbol(symbol_name);
    103       if (addr)
    104         return addr;
    105     }
    106 
    107     // If this is a crazy library, add non-visited dependencies
    108     // to the work queue.
    109     if (lib->IsCrazy()) {
    110       SharedLibrary::DependencyIterator iter(lib->GetCrazy());
    111       while (iter.GetNext()) {
    112         LibraryView* dependency = FindKnownLibrary(iter.GetName());
    113         if (dependency && !visited_set.Has(dependency)) {
    114           work_queue.PushBack(dependency);
    115           visited_set.Add(dependency);
    116         }
    117       }
    118     }
    119   }
    120 
    121   if (lookup_state.weak_count >= 1) {
    122     // There was at least a single weak symbol definition, so use
    123     // the first one found in breadth-first search order.
    124     return lookup_state.weak_addr;
    125   }
    126 
    127   // There was no symbol definition.
    128   return NULL;
    129 }
    130 
    131 LibraryView* LibraryList::FindLibraryForAddress(void* address) {
    132   // Linearly scan all libraries, looking for one that contains
    133   // a given address. NOTE: This doesn't check that this falls
    134   // inside one of the mapped library segments.
    135   for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
    136     LibraryView* wrap = known_libraries_[n];
    137     // TODO(digit): Search addresses inside system libraries.
    138     if (wrap->IsCrazy()) {
    139       SharedLibrary* lib = wrap->GetCrazy();
    140       if (lib->ContainsAddress(address))
    141         return wrap;
    142     }
    143   }
    144   return NULL;
    145 }
    146 
    147 #ifdef __arm__
    148 _Unwind_Ptr LibraryList::FindArmExIdx(void* pc, int* count) {
    149   for (SharedLibrary* lib = head_; lib; lib = lib->list_next_) {
    150     if (lib->ContainsAddress(pc)) {
    151       *count = static_cast<int>(lib->arm_exidx_count_);
    152       return reinterpret_cast<_Unwind_Ptr>(lib->arm_exidx_);
    153     }
    154   }
    155   *count = 0;
    156   return NULL;
    157 }
    158 #else  // !__arm__
    159 int LibraryList::IteratePhdr(PhdrIterationCallback callback, void* data) {
    160   int result = 0;
    161   for (SharedLibrary* lib = head_; lib; lib = lib->list_next_) {
    162     dl_phdr_info info;
    163     info.dlpi_addr = lib->link_map_.l_addr;
    164     info.dlpi_name = lib->link_map_.l_name;
    165     info.dlpi_phdr = lib->phdr();
    166     info.dlpi_phnum = lib->phdr_count();
    167     result = callback(&info, sizeof(info), data);
    168     if (result)
    169       break;
    170   }
    171   return result;
    172 }
    173 #endif  // !__arm__
    174 
    175 void LibraryList::UnloadLibrary(LibraryView* wrap) {
    176   // Sanity check.
    177   LOG("%s: for %s (ref_count=%d)\n",
    178       __FUNCTION__,
    179       wrap->GetName(),
    180       wrap->ref_count());
    181 
    182   if (!wrap->IsSystem() && !wrap->IsCrazy())
    183     return;
    184 
    185   if (!wrap->SafeDecrementRef())
    186     return;
    187 
    188   // If this is a crazy library, perform manual cleanup first.
    189   if (wrap->IsCrazy()) {
    190     SharedLibrary* lib = wrap->GetCrazy();
    191 
    192     // Remove from internal list of crazy libraries.
    193     if (lib->list_next_)
    194       lib->list_next_->list_prev_ = lib->list_prev_;
    195     if (lib->list_prev_)
    196       lib->list_prev_->list_next_ = lib->list_next_;
    197     if (lib == head_)
    198       head_ = lib->list_next_;
    199 
    200     // Call JNI_OnUnload, if necessary, then the destructors.
    201     lib->CallJniOnUnload();
    202     lib->CallDestructors();
    203 
    204     // Unload the dependencies recursively.
    205     SharedLibrary::DependencyIterator iter(lib);
    206     while (iter.GetNext()) {
    207       LibraryView* dependency = FindKnownLibrary(iter.GetName());
    208       if (dependency)
    209         UnloadLibrary(dependency);
    210     }
    211 
    212     // Tell GDB of this removal.
    213     Globals::GetRDebug()->DelEntry(&lib->link_map_);
    214   }
    215 
    216   known_libraries_.Remove(wrap);
    217 
    218   // Delete the wrapper, which will delete the crazy library, or
    219   // dlclose() the system one.
    220   delete wrap;
    221 }
    222 
    223 LibraryView* LibraryList::LoadLibrary(const char* lib_name,
    224                                       int dlopen_mode,
    225                                       uintptr_t load_address,
    226                                       off_t file_offset,
    227                                       SearchPathList* search_path_list,
    228                                       Error* error) {
    229 
    230   const char* base_name = GetBaseNamePtr(lib_name);
    231 
    232   LOG("%s: lib_name='%s'\n", __FUNCTION__, lib_name);
    233 
    234   // First check whether a library with the same base name was
    235   // already loaded.
    236   LibraryView* wrap = FindKnownLibrary(lib_name);
    237   if (wrap) {
    238     if (load_address) {
    239       // Check that this is a crazy library and that is was loaded at
    240       // the correct address.
    241       if (!wrap->IsCrazy()) {
    242         error->Format("System library can't be loaded at fixed address %08x",
    243                       load_address);
    244         return NULL;
    245       }
    246       uintptr_t actual_address = wrap->GetCrazy()->load_address();
    247       if (actual_address != load_address) {
    248         error->Format("Library already loaded at @%08x, can't load it at @%08x",
    249                       actual_address,
    250                       load_address);
    251         return NULL;
    252       }
    253     }
    254     wrap->AddRef();
    255     return wrap;
    256   }
    257 
    258   if (IsSystemLibrary(lib_name)) {
    259     // This is a system library, probably because we're loading the
    260     // library as a dependency.
    261     LOG("%s: Loading system library '%s'\n", __FUNCTION__, lib_name);
    262     ::dlerror();
    263     void* system_lib = dlopen(lib_name, dlopen_mode);
    264     if (!system_lib) {
    265       error->Format("Can't load system library %s: %s", lib_name, ::dlerror());
    266       return NULL;
    267     }
    268 
    269     LibraryView* wrap = new LibraryView();
    270     wrap->SetSystem(system_lib, lib_name);
    271     known_libraries_.PushBack(wrap);
    272 
    273     LOG("%s: System library %s loaded at %p\n", __FUNCTION__, lib_name, wrap);
    274     LOG("  name=%s\n", wrap->GetName());
    275     return wrap;
    276   }
    277 
    278   ScopedPtr<SharedLibrary> lib(new SharedLibrary());
    279 
    280   // Find the full library path.
    281   String full_path;
    282 
    283   if (!strchr(lib_name, '/')) {
    284     LOG("%s: Looking through the search path list\n", __FUNCTION__);
    285     const char* path = search_path_list->FindFile(lib_name);
    286     if (!path) {
    287       error->Format("Can't find library file %s", lib_name);
    288       return NULL;
    289     }
    290     full_path = path;
    291   } else {
    292     if (lib_name[0] != '/') {
    293       // Need to transform this into a full path.
    294       full_path = GetCurrentDirectory();
    295       if (full_path.size() && full_path[full_path.size() - 1] != '/')
    296         full_path += '/';
    297       full_path += lib_name;
    298     } else {
    299       // Absolute path. Easy.
    300       full_path = lib_name;
    301     }
    302     LOG("%s: Full library path: %s\n", __FUNCTION__, full_path.c_str());
    303     if (!PathIsFile(full_path.c_str())) {
    304       error->Format("Library file doesn't exist: %s", full_path.c_str());
    305       return NULL;
    306     }
    307   }
    308 
    309   // Load the library
    310   if (!lib->Load(full_path.c_str(), load_address, file_offset, error))
    311     return NULL;
    312 
    313   // Load all dependendent libraries.
    314   LOG("%s: Loading dependencies of %s\n", __FUNCTION__, base_name);
    315   SharedLibrary::DependencyIterator iter(lib.Get());
    316   Vector<LibraryView*> dependencies;
    317   while (iter.GetNext()) {
    318     Error dep_error;
    319     LibraryView* dependency = LoadLibrary(iter.GetName(),
    320                                           dlopen_mode,
    321                                           0U /* load address */,
    322                                           0U /* file offset */,
    323                                           search_path_list,
    324                                           &dep_error);
    325     if (!dependency) {
    326       error->Format("When loading %s: %s", base_name, dep_error.c_str());
    327       return NULL;
    328     }
    329     dependencies.PushBack(dependency);
    330   }
    331   if (CRAZY_DEBUG) {
    332     LOG("%s: Dependencies loaded for %s\n", __FUNCTION__, base_name);
    333     for (size_t n = 0; n < dependencies.GetCount(); ++n)
    334       LOG("  ... %p %s\n", dependencies[n], dependencies[n]->GetName());
    335     LOG("    dependencies @%p\n", &dependencies);
    336   }
    337 
    338   // Relocate the library.
    339   LOG("%s: Relocating %s\n", __FUNCTION__, base_name);
    340   if (!lib->Relocate(this, &dependencies, error))
    341     return NULL;
    342 
    343   // Notify GDB of load.
    344   lib->link_map_.l_addr = lib->load_address();
    345   lib->link_map_.l_name = const_cast<char*>(lib->base_name_);
    346   lib->link_map_.l_ld = reinterpret_cast<uintptr_t>(lib->view_.dynamic());
    347   Globals::GetRDebug()->AddEntry(&lib->link_map_);
    348 
    349   // The library was properly loaded, add it to the list of crazy
    350   // libraries. IMPORTANT: Do this _before_ calling the constructors
    351   // because these could call dlopen().
    352   lib->list_next_ = head_;
    353   lib->list_prev_ = NULL;
    354   if (head_)
    355     head_->list_prev_ = lib.Get();
    356   head_ = lib.Get();
    357 
    358   // Then create a new LibraryView for it.
    359   wrap = new LibraryView();
    360   wrap->SetCrazy(lib.Get(), lib_name);
    361   known_libraries_.PushBack(wrap);
    362 
    363   LOG("%s: Running constructors for %s\n", __FUNCTION__, base_name);
    364 
    365   // Now run the constructors.
    366   lib->CallConstructors();
    367 
    368   LOG("%s: Done loading %s\n", __FUNCTION__, base_name);
    369   lib.Release();
    370 
    371   return wrap;
    372 }
    373 
    374 void LibraryList::AddLibrary(LibraryView* wrap) {
    375   known_libraries_.PushBack(wrap);
    376 }
    377 
    378 LibraryView* LibraryList::FindKnownLibrary(const char* name) {
    379   const char* base_name = GetBaseNamePtr(name);
    380   for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
    381     LibraryView* wrap = known_libraries_[n];
    382     if (!strcmp(base_name, wrap->GetName()))
    383       return wrap;
    384   }
    385   return NULL;
    386 }
    387 
    388 }  // namespace crazy
    389