1 // Copyright 2014 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.
5 #include "crazy_linker_library_list.h"
8 #include <crazy_linker.h>
11 #include "crazy_linker_debug.h"
12 #include "crazy_linker_library_view.h"
13 #include "crazy_linker_globals.h"
14 #include "crazy_linker_rdebug.h"
15 #include "crazy_linker_shared_library.h"
16 #include "crazy_linker_system.h"
17 #include "crazy_linker_util.h"
18 #include "crazy_linker_zip.h"
24 // Page size for alignment in a zip file.
25 const size_t kZipAlignmentPageSize = 4096;
26 static_assert(kZipAlignmentPageSize % PAGE_SIZE == 0,
27 "kZipAlignmentPageSize must be a multiple of PAGE_SIZE");
29 // A helper struct used when looking up symbols in libraries.
30 struct SymbolLookupState {
35 SymbolLookupState() : found_addr(NULL), weak_addr(NULL), weak_count(0) {}
37 // Check a symbol entry.
38 bool CheckSymbol(const char* symbol, SharedLibrary* lib) {
39 const ELF::Sym* entry = lib->LookupSymbolEntry(symbol);
43 void* address = reinterpret_cast<void*>(lib->load_bias() + entry->st_value);
45 // If this is a strong symbol, record it and return true.
46 if (ELF_ST_BIND(entry->st_info) == STB_GLOBAL) {
50 // If this is a weak symbol, record the first one and
51 // increment the weak_count.
52 if (++weak_count == 1)
61 LibraryList::LibraryList() : head_(0), count_(0), has_error_(false) {
65 LibraryList::~LibraryList() {
66 // Invalidate crazy library list.
69 // Destroy all known libraries.
70 while (!known_libraries_.IsEmpty()) {
71 LibraryView* wrap = known_libraries_.PopLast();
76 LibraryView* LibraryList::FindLibraryByName(const char* lib_name) {
81 for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
82 LibraryView* wrap = known_libraries_[n];
83 if (!strcmp(lib_name, wrap->GetName()))
89 void* LibraryList::FindSymbolFrom(const char* symbol_name, LibraryView* from) {
90 SymbolLookupState lookup_state;
95 // Use a work-queue and a set to ensure to perform a breadth-first
97 Vector<LibraryView*> work_queue;
98 Set<LibraryView*> visited_set;
100 work_queue.PushBack(from);
102 while (!work_queue.IsEmpty()) {
103 LibraryView* lib = work_queue.PopFirst();
104 if (lib->IsCrazy()) {
105 if (lookup_state.CheckSymbol(symbol_name, lib->GetCrazy()))
106 return lookup_state.found_addr;
107 } else if (lib->IsSystem()) {
108 // TODO(digit): Support weak symbols in system libraries.
109 // With the current code, all symbols in system libraries
110 // are assumed to be non-weak.
111 void* addr = lib->LookupSymbol(symbol_name);
116 // If this is a crazy library, add non-visited dependencies
117 // to the work queue.
118 if (lib->IsCrazy()) {
119 SharedLibrary::DependencyIterator iter(lib->GetCrazy());
120 while (iter.GetNext()) {
121 LibraryView* dependency = FindKnownLibrary(iter.GetName());
122 if (dependency && !visited_set.Has(dependency)) {
123 work_queue.PushBack(dependency);
124 visited_set.Add(dependency);
130 if (lookup_state.weak_count >= 1) {
131 // There was at least a single weak symbol definition, so use
132 // the first one found in breadth-first search order.
133 return lookup_state.weak_addr;
136 // There was no symbol definition.
140 LibraryView* LibraryList::FindLibraryForAddress(void* address) {
141 // Linearly scan all libraries, looking for one that contains
142 // a given address. NOTE: This doesn't check that this falls
143 // inside one of the mapped library segments.
144 for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
145 LibraryView* wrap = known_libraries_[n];
146 // TODO(digit): Search addresses inside system libraries.
147 if (wrap->IsCrazy()) {
148 SharedLibrary* lib = wrap->GetCrazy();
149 if (lib->ContainsAddress(address))
157 _Unwind_Ptr LibraryList::FindArmExIdx(void* pc, int* count) {
158 for (SharedLibrary* lib = head_; lib; lib = lib->list_next_) {
159 if (lib->ContainsAddress(pc)) {
160 *count = static_cast<int>(lib->arm_exidx_count_);
161 return reinterpret_cast<_Unwind_Ptr>(lib->arm_exidx_);
168 int LibraryList::IteratePhdr(PhdrIterationCallback callback, void* data) {
170 for (SharedLibrary* lib = head_; lib; lib = lib->list_next_) {
172 info.dlpi_addr = lib->link_map_.l_addr;
173 info.dlpi_name = lib->link_map_.l_name;
174 info.dlpi_phdr = lib->phdr();
175 info.dlpi_phnum = lib->phdr_count();
176 result = callback(&info, sizeof(info), data);
184 void LibraryList::UnloadLibrary(LibraryView* wrap) {
186 LOG("%s: for %s (ref_count=%d)\n",
191 if (!wrap->IsSystem() && !wrap->IsCrazy())
194 if (!wrap->SafeDecrementRef())
197 // If this is a crazy library, perform manual cleanup first.
198 if (wrap->IsCrazy()) {
199 SharedLibrary* lib = wrap->GetCrazy();
201 // Remove from internal list of crazy libraries.
203 lib->list_next_->list_prev_ = lib->list_prev_;
205 lib->list_prev_->list_next_ = lib->list_next_;
207 head_ = lib->list_next_;
209 // Call JNI_OnUnload, if necessary, then the destructors.
210 lib->CallJniOnUnload();
211 lib->CallDestructors();
213 // Unload the dependencies recursively.
214 SharedLibrary::DependencyIterator iter(lib);
215 while (iter.GetNext()) {
216 LibraryView* dependency = FindKnownLibrary(iter.GetName());
218 UnloadLibrary(dependency);
221 // Tell GDB of this removal.
222 Globals::GetRDebug()->DelEntry(&lib->link_map_);
225 known_libraries_.Remove(wrap);
227 // Delete the wrapper, which will delete the crazy library, or
228 // dlclose() the system one.
232 LibraryView* LibraryList::LoadLibrary(const char* lib_name,
234 uintptr_t load_address,
236 SearchPathList* search_path_list,
237 bool no_map_exec_support_fallback_enabled,
240 const char* base_name = GetBaseNamePtr(lib_name);
242 LOG("%s: lib_name='%s'\n", __FUNCTION__, lib_name);
244 // First check whether a library with the same base name was
246 LibraryView* wrap = FindKnownLibrary(lib_name);
249 // Check that this is a crazy library and that is was loaded at
250 // the correct address.
251 if (!wrap->IsCrazy()) {
252 error->Format("System library can't be loaded at fixed address %08x",
256 uintptr_t actual_address = wrap->GetCrazy()->load_address();
257 if (actual_address != load_address) {
258 error->Format("Library already loaded at @%08x, can't load it at @%08x",
268 if (IsSystemLibrary(lib_name)) {
269 // This is a system library, probably because we're loading the
270 // library as a dependency.
271 LOG("%s: Loading system library '%s'\n", __FUNCTION__, lib_name);
273 void* system_lib = dlopen(lib_name, dlopen_mode);
275 error->Format("Can't load system library %s: %s", lib_name, ::dlerror());
279 LibraryView* wrap = new LibraryView();
280 wrap->SetSystem(system_lib, lib_name);
281 known_libraries_.PushBack(wrap);
283 LOG("%s: System library %s loaded at %p\n", __FUNCTION__, lib_name, wrap);
284 LOG(" name=%s\n", wrap->GetName());
288 ScopedPtr<SharedLibrary> lib(new SharedLibrary());
290 // Find the full library path.
293 if (!strchr(lib_name, '/')) {
294 LOG("%s: Looking through the search path list\n", __FUNCTION__);
295 const char* path = search_path_list->FindFile(lib_name);
297 error->Format("Can't find library file %s", lib_name);
302 if (lib_name[0] != '/') {
303 // Need to transform this into a full path.
304 full_path = GetCurrentDirectory();
305 if (full_path.size() && full_path[full_path.size() - 1] != '/')
307 full_path += lib_name;
309 // Absolute path. Easy.
310 full_path = lib_name;
312 LOG("%s: Full library path: %s\n", __FUNCTION__, full_path.c_str());
313 if (!PathIsFile(full_path.c_str())) {
314 error->Format("Library file doesn't exist: %s", full_path.c_str());
320 if (!lib->Load(full_path.c_str(), load_address, file_offset,
321 no_map_exec_support_fallback_enabled, error))
324 // Load all dependendent libraries.
325 LOG("%s: Loading dependencies of %s\n", __FUNCTION__, base_name);
326 SharedLibrary::DependencyIterator iter(lib.Get());
327 Vector<LibraryView*> dependencies;
328 while (iter.GetNext()) {
330 LibraryView* dependency = LoadLibrary(iter.GetName(),
332 0U /* load address */,
333 0U /* file offset */,
335 no_map_exec_support_fallback_enabled,
338 error->Format("When loading %s: %s", base_name, dep_error.c_str());
341 dependencies.PushBack(dependency);
344 LOG("%s: Dependencies loaded for %s\n", __FUNCTION__, base_name);
345 for (size_t n = 0; n < dependencies.GetCount(); ++n)
346 LOG(" ... %p %s\n", dependencies[n], dependencies[n]->GetName());
347 LOG(" dependencies @%p\n", &dependencies);
350 // Relocate the library.
351 LOG("%s: Relocating %s\n", __FUNCTION__, base_name);
352 if (!lib->Relocate(this, &dependencies, error))
355 // Notify GDB of load.
356 lib->link_map_.l_addr = lib->load_address();
357 lib->link_map_.l_name = const_cast<char*>(lib->base_name_);
358 lib->link_map_.l_ld = reinterpret_cast<uintptr_t>(lib->view_.dynamic());
359 Globals::GetRDebug()->AddEntry(&lib->link_map_);
361 // The library was properly loaded, add it to the list of crazy
362 // libraries. IMPORTANT: Do this _before_ calling the constructors
363 // because these could call dlopen().
364 lib->list_next_ = head_;
365 lib->list_prev_ = NULL;
367 head_->list_prev_ = lib.Get();
370 // Then create a new LibraryView for it.
371 wrap = new LibraryView();
372 wrap->SetCrazy(lib.Get(), lib_name);
373 known_libraries_.PushBack(wrap);
375 LOG("%s: Running constructors for %s\n", __FUNCTION__, base_name);
377 // Now run the constructors.
378 lib->CallConstructors();
380 LOG("%s: Done loading %s\n", __FUNCTION__, base_name);
386 // We identify the abi tag for which the linker is running. This allows
387 // us to select the library which matches the abi of the linker.
389 #if defined(__arm__) && defined(__ARM_ARCH_7A__)
390 #define CURRENT_ABI "armeabi-v7a"
391 #elif defined(__arm__)
392 #define CURRENT_ABI "armeabi"
393 #elif defined(__i386__)
394 #define CURRENT_ABI "x86"
395 #elif defined(__mips__)
396 #define CURRENT_ABI "mips"
397 #elif defined(__x86_64__)
398 #define CURRENT_ABI "x86_64"
399 #elif defined(__aarch64__)
400 #define CURRENT_ABI "arm64-v8a"
402 #error "Unsupported target abi"
405 String LibraryList::GetLibraryFilePathInZipFile(const char* lib_name) {
407 path.Reserve(kMaxFilePathLengthInZip);
415 int LibraryList::FindMappableLibraryInZipFile(
416 const char* zip_file_path,
417 const char* lib_name,
419 String path = GetLibraryFilePathInZipFile(lib_name);
420 if (path.size() >= kMaxFilePathLengthInZip) {
421 error->Format("Filename too long for a file in a zip file %s\n",
423 return CRAZY_OFFSET_FAILED;
426 int offset = FindStartOffsetOfFileInZipFile(zip_file_path, path.c_str());
427 if (offset == CRAZY_OFFSET_FAILED) {
428 return CRAZY_OFFSET_FAILED;
431 static_assert((kZipAlignmentPageSize & (kZipAlignmentPageSize - 1)) == 0,
432 "kZipAlignmentPageSize must be a power of 2");
433 if ((offset & (kZipAlignmentPageSize - 1)) != 0) {
434 error->Format("Library %s is not page aligned in zipfile %s\n",
435 lib_name, zip_file_path);
436 return CRAZY_OFFSET_FAILED;
439 assert(offset != CRAZY_OFFSET_FAILED);
443 LibraryView* LibraryList::LoadLibraryInZipFile(
444 const char* zip_file_path,
445 const char* lib_name,
447 uintptr_t load_address,
448 SearchPathList* search_path_list,
449 bool no_map_exec_support_fallback_enabled,
451 int offset = FindMappableLibraryInZipFile(zip_file_path, lib_name, error);
452 if (offset == CRAZY_OFFSET_FAILED) {
457 zip_file_path, dlopen_flags, load_address, offset,
458 search_path_list, no_map_exec_support_fallback_enabled, error);
461 void LibraryList::AddLibrary(LibraryView* wrap) {
462 known_libraries_.PushBack(wrap);
465 LibraryView* LibraryList::FindKnownLibrary(const char* name) {
466 const char* base_name = GetBaseNamePtr(name);
467 for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
468 LibraryView* wrap = known_libraries_[n];
469 if (!strcmp(base_name, wrap->GetName()))