LibraryView* LibraryList::FindKnownLibrary(const char* name) { const char* base_name = GetBaseNamePtr(name); for (size_t n = 0; n < known_libraries_.GetCount(); ++n) { LibraryView* wrap = known_libraries_[n]; if (!strcmp(base_name, wrap->GetName())) return wrap; } return NULL; }
bool SharedLibrary::Load(const char* full_path, size_t load_address, size_t file_offset, Error* error) { // First, record the path. LOG("%s: full path '%s'\n", __FUNCTION__, full_path); size_t full_path_len = strlen(full_path); if (full_path_len >= sizeof(full_path_)) { error->Format("Path too long: %s", full_path); return false; } strlcpy(full_path_, full_path, sizeof(full_path_)); base_name_ = GetBaseNamePtr(full_path_); // Load the ELF binary in memory. LOG("%s: Loading ELF segments for %s\n", __FUNCTION__, base_name_); { ElfLoader loader; if (!loader.LoadAt(full_path_, file_offset, load_address, error)) { return false; } if (!view_.InitUnmapped(loader.load_start(), loader.loaded_phdr(), loader.phdr_count(), error)) { return false; } if (!symbols_.Init(&view_)) { *error = "Missing or malformed symbol table"; return false; } } if (phdr_table_get_relro_info(view_.phdr(), view_.phdr_count(), view_.load_bias(), &relro_start_, &relro_size_) < 0) { relro_start_ = 0; relro_size_ = 0; } #ifdef __arm__ LOG("%s: Extracting ARM.exidx table for %s\n", __FUNCTION__, base_name_); (void)phdr_table_get_arm_exidx( phdr(), phdr_count(), load_bias(), &arm_exidx_, &arm_exidx_count_); #endif LOG("%s: Parsing dynamic table for %s\n", __FUNCTION__, base_name_); ElfView::DynamicIterator dyn(&view_); for (; dyn.HasNext(); dyn.GetNext()) { ELF::Addr dyn_value = dyn.GetValue(); uintptr_t dyn_addr = dyn.GetAddress(load_bias()); switch (dyn.GetTag()) { case DT_DEBUG: if (view_.dynamic_flags() & PF_W) { *dyn.GetValuePointer() = reinterpret_cast<uintptr_t>(Globals::GetRDebug()->GetAddress()); } break; case DT_INIT: LOG(" DT_INIT addr=%p\n", dyn_addr); init_func_ = reinterpret_cast<linker_function_t>(dyn_addr); break; case DT_FINI: LOG(" DT_FINI addr=%p\n", dyn_addr); fini_func_ = reinterpret_cast<linker_function_t>(dyn_addr); break; case DT_INIT_ARRAY: LOG(" DT_INIT_ARRAY addr=%p\n", dyn_addr); init_array_ = reinterpret_cast<linker_function_t*>(dyn_addr); break; case DT_INIT_ARRAYSZ: init_array_count_ = dyn_value / sizeof(ELF::Addr); LOG(" DT_INIT_ARRAYSZ value=%p count=%p\n", dyn_value, init_array_count_); break; case DT_FINI_ARRAY: LOG(" DT_FINI_ARRAY addr=%p\n", dyn_addr); fini_array_ = reinterpret_cast<linker_function_t*>(dyn_addr); break; case DT_FINI_ARRAYSZ: fini_array_count_ = dyn_value / sizeof(ELF::Addr); LOG(" DT_FINI_ARRAYSZ value=%p count=%p\n", dyn_value, fini_array_count_); break; case DT_PREINIT_ARRAY: LOG(" DT_PREINIT_ARRAY addr=%p\n", dyn_addr); preinit_array_ = reinterpret_cast<linker_function_t*>(dyn_addr); break; case DT_PREINIT_ARRAYSZ: preinit_array_count_ = dyn_value / sizeof(ELF::Addr); LOG(" DT_PREINIT_ARRAYSZ value=%p count=%p\n", dyn_value, preinit_array_count_); break; case DT_SYMBOLIC: LOG(" DT_SYMBOLIC\n"); has_DT_SYMBOLIC_ = true; break; case DT_FLAGS: if (dyn_value & DF_SYMBOLIC) has_DT_SYMBOLIC_ = true; break; #if defined(__mips__) case DT_MIPS_RLD_MAP: *dyn.GetValuePointer() = reinterpret_cast<ELF::Addr>(Globals::GetRDebug()->GetAddress()); break; #endif default: ; } } LOG("%s: Load complete for %s\n", __FUNCTION__, base_name_); return true; }
TEST(GetBaseNamePtr, Test) { const char kString[] = "/tmp/foo"; EXPECT_EQ(kString + 5, GetBaseNamePtr(kString)); }
LibraryView* LibraryList::LoadLibrary(const char* lib_name, int dlopen_mode, uintptr_t load_address, off_t file_offset, SearchPathList* search_path_list, Error* error) { const char* base_name = GetBaseNamePtr(lib_name); LOG("%s: lib_name='%s'\n", __FUNCTION__, lib_name); // First check whether a library with the same base name was // already loaded. LibraryView* wrap = FindKnownLibrary(lib_name); if (wrap) { if (load_address) { // Check that this is a crazy library and that is was loaded at // the correct address. if (!wrap->IsCrazy()) { error->Format("System library can't be loaded at fixed address %08x", load_address); return NULL; } uintptr_t actual_address = wrap->GetCrazy()->load_address(); if (actual_address != load_address) { error->Format("Library already loaded at @%08x, can't load it at @%08x", actual_address, load_address); return NULL; } } wrap->AddRef(); return wrap; } if (IsSystemLibrary(lib_name)) { // This is a system library, probably because we're loading the // library as a dependency. LOG("%s: Loading system library '%s'\n", __FUNCTION__, lib_name); ::dlerror(); void* system_lib = dlopen(lib_name, dlopen_mode); if (!system_lib) { error->Format("Can't load system library %s: %s", lib_name, ::dlerror()); return NULL; } LibraryView* wrap = new LibraryView(); wrap->SetSystem(system_lib, lib_name); known_libraries_.PushBack(wrap); LOG("%s: System library %s loaded at %p\n", __FUNCTION__, lib_name, wrap); LOG(" name=%s\n", wrap->GetName()); return wrap; } ScopedPtr<SharedLibrary> lib(new SharedLibrary()); // Find the full library path. String full_path; if (!strchr(lib_name, '/')) { LOG("%s: Looking through the search path list\n", __FUNCTION__); const char* path = search_path_list->FindFile(lib_name); if (!path) { error->Format("Can't find library file %s", lib_name); return NULL; } full_path = path; } else { if (lib_name[0] != '/') { // Need to transform this into a full path. full_path = GetCurrentDirectory(); if (full_path.size() && full_path[full_path.size() - 1] != '/') full_path += '/'; full_path += lib_name; } else { // Absolute path. Easy. full_path = lib_name; } LOG("%s: Full library path: %s\n", __FUNCTION__, full_path.c_str()); if (!PathIsFile(full_path.c_str())) { error->Format("Library file doesn't exist: %s", full_path.c_str()); return NULL; } } // Load the library if (!lib->Load(full_path.c_str(), load_address, file_offset, error)) return NULL; // Load all dependendent libraries. LOG("%s: Loading dependencies of %s\n", __FUNCTION__, base_name); SharedLibrary::DependencyIterator iter(lib.Get()); Vector<LibraryView*> dependencies; while (iter.GetNext()) { Error dep_error; LibraryView* dependency = LoadLibrary(iter.GetName(), dlopen_mode, 0U /* load address */, 0U /* file offset */, search_path_list, &dep_error); if (!dependency) { error->Format("When loading %s: %s", base_name, dep_error.c_str()); return NULL; } dependencies.PushBack(dependency); } if (CRAZY_DEBUG) { LOG("%s: Dependencies loaded for %s\n", __FUNCTION__, base_name); for (size_t n = 0; n < dependencies.GetCount(); ++n) LOG(" ... %p %s\n", dependencies[n], dependencies[n]->GetName()); LOG(" dependencies @%p\n", &dependencies); } // Relocate the library. LOG("%s: Relocating %s\n", __FUNCTION__, base_name); if (!lib->Relocate(this, &dependencies, error)) return NULL; // Notify GDB of load. lib->link_map_.l_addr = lib->load_address(); lib->link_map_.l_name = const_cast<char*>(lib->base_name_); lib->link_map_.l_ld = reinterpret_cast<uintptr_t>(lib->view_.dynamic()); Globals::GetRDebug()->AddEntry(&lib->link_map_); // The library was properly loaded, add it to the list of crazy // libraries. IMPORTANT: Do this _before_ calling the constructors // because these could call dlopen(). lib->list_next_ = head_; lib->list_prev_ = NULL; if (head_) head_->list_prev_ = lib.Get(); head_ = lib.Get(); // Then create a new LibraryView for it. wrap = new LibraryView(); wrap->SetCrazy(lib.Get(), lib_name); known_libraries_.PushBack(wrap); LOG("%s: Running constructors for %s\n", __FUNCTION__, base_name); // Now run the constructors. lib->CallConstructors(); LOG("%s: Done loading %s\n", __FUNCTION__, base_name); lib.Release(); return wrap; }