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 16namespace crazy { 17 18namespace { 19 20// A helper struct used when looking up symbols in libraries. 21struct 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 52LibraryList::LibraryList() : head_(0), count_(0), has_error_(false) { 53 // Nothing for now 54} 55 56LibraryList::~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 67LibraryView* 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 80void* 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 131LibraryView* 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__ 159int 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 175void 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 223LibraryView* 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 374void LibraryList::AddLibrary(LibraryView* wrap) { 375 known_libraries_.PushBack(wrap); 376} 377 378LibraryView* 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