1881a4a6d703751365f4cfe9b6f087171d3f35b2
[platform/framework/web/crosswalk.git] / src / third_party / android_crazy_linker / src / src / crazy_linker_library_list.cpp
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.
4
5 #include "crazy_linker_library_list.h"
6
7 #include <assert.h>
8 #include <crazy_linker.h>
9 #include <dlfcn.h>
10
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"
19
20 namespace crazy {
21
22 namespace {
23
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");
28
29 // A helper struct used when looking up symbols in libraries.
30 struct SymbolLookupState {
31   void* found_addr;
32   void* weak_addr;
33   int weak_count;
34
35   SymbolLookupState() : found_addr(NULL), weak_addr(NULL), weak_count(0) {}
36
37   // Check a symbol entry.
38   bool CheckSymbol(const char* symbol, SharedLibrary* lib) {
39     const ELF::Sym* entry = lib->LookupSymbolEntry(symbol);
40     if (!entry)
41       return false;
42
43     void* address = reinterpret_cast<void*>(lib->load_bias() + entry->st_value);
44
45     // If this is a strong symbol, record it and return true.
46     if (ELF_ST_BIND(entry->st_info) == STB_GLOBAL) {
47       found_addr = address;
48       return true;
49     }
50     // If this is a weak symbol, record the first one and
51     // increment the weak_count.
52     if (++weak_count == 1)
53       weak_addr = address;
54
55     return false;
56   }
57 };
58
59 }  // namespace
60
61 LibraryList::LibraryList() : head_(0), count_(0), has_error_(false) {
62   // Nothing for now
63 }
64
65 LibraryList::~LibraryList() {
66   // Invalidate crazy library list.
67   head_ = NULL;
68
69   // Destroy all known libraries.
70   while (!known_libraries_.IsEmpty()) {
71     LibraryView* wrap = known_libraries_.PopLast();
72     delete wrap;
73   }
74 }
75
76 LibraryView* LibraryList::FindLibraryByName(const char* lib_name) {
77   // Sanity check.
78   if (!lib_name)
79     return NULL;
80
81   for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
82     LibraryView* wrap = known_libraries_[n];
83     if (!strcmp(lib_name, wrap->GetName()))
84       return wrap;
85   }
86   return NULL;
87 }
88
89 void* LibraryList::FindSymbolFrom(const char* symbol_name, LibraryView* from) {
90   SymbolLookupState lookup_state;
91
92   if (!from)
93     return NULL;
94
95   // Use a work-queue and a set to ensure to perform a breadth-first
96   // search.
97   Vector<LibraryView*> work_queue;
98   Set<LibraryView*> visited_set;
99
100   work_queue.PushBack(from);
101
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);
112       if (addr)
113         return addr;
114     }
115
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);
125         }
126       }
127     }
128   }
129
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;
134   }
135
136   // There was no symbol definition.
137   return NULL;
138 }
139
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))
150         return wrap;
151     }
152   }
153   return NULL;
154 }
155
156 #ifdef __arm__
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_);
162     }
163   }
164   *count = 0;
165   return NULL;
166 }
167 #else  // !__arm__
168 int LibraryList::IteratePhdr(PhdrIterationCallback callback, void* data) {
169   int result = 0;
170   for (SharedLibrary* lib = head_; lib; lib = lib->list_next_) {
171     dl_phdr_info info;
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);
177     if (result)
178       break;
179   }
180   return result;
181 }
182 #endif  // !__arm__
183
184 void LibraryList::UnloadLibrary(LibraryView* wrap) {
185   // Sanity check.
186   LOG("%s: for %s (ref_count=%d)\n",
187       __FUNCTION__,
188       wrap->GetName(),
189       wrap->ref_count());
190
191   if (!wrap->IsSystem() && !wrap->IsCrazy())
192     return;
193
194   if (!wrap->SafeDecrementRef())
195     return;
196
197   // If this is a crazy library, perform manual cleanup first.
198   if (wrap->IsCrazy()) {
199     SharedLibrary* lib = wrap->GetCrazy();
200
201     // Remove from internal list of crazy libraries.
202     if (lib->list_next_)
203       lib->list_next_->list_prev_ = lib->list_prev_;
204     if (lib->list_prev_)
205       lib->list_prev_->list_next_ = lib->list_next_;
206     if (lib == head_)
207       head_ = lib->list_next_;
208
209     // Call JNI_OnUnload, if necessary, then the destructors.
210     lib->CallJniOnUnload();
211     lib->CallDestructors();
212
213     // Unload the dependencies recursively.
214     SharedLibrary::DependencyIterator iter(lib);
215     while (iter.GetNext()) {
216       LibraryView* dependency = FindKnownLibrary(iter.GetName());
217       if (dependency)
218         UnloadLibrary(dependency);
219     }
220
221     // Tell GDB of this removal.
222     Globals::GetRDebug()->DelEntry(&lib->link_map_);
223   }
224
225   known_libraries_.Remove(wrap);
226
227   // Delete the wrapper, which will delete the crazy library, or
228   // dlclose() the system one.
229   delete wrap;
230 }
231
232 LibraryView* LibraryList::LoadLibrary(const char* lib_name,
233                                       int dlopen_mode,
234                                       uintptr_t load_address,
235                                       off_t file_offset,
236                                       SearchPathList* search_path_list,
237                                       bool no_map_exec_support_fallback_enabled,
238                                       Error* error) {
239
240   const char* base_name = GetBaseNamePtr(lib_name);
241
242   LOG("%s: lib_name='%s'\n", __FUNCTION__, lib_name);
243
244   // First check whether a library with the same base name was
245   // already loaded.
246   LibraryView* wrap = FindKnownLibrary(lib_name);
247   if (wrap) {
248     if (load_address) {
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",
253                       load_address);
254         return NULL;
255       }
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",
259                       actual_address,
260                       load_address);
261         return NULL;
262       }
263     }
264     wrap->AddRef();
265     return wrap;
266   }
267
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);
272     ::dlerror();
273     void* system_lib = dlopen(lib_name, dlopen_mode);
274     if (!system_lib) {
275       error->Format("Can't load system library %s: %s", lib_name, ::dlerror());
276       return NULL;
277     }
278
279     LibraryView* wrap = new LibraryView();
280     wrap->SetSystem(system_lib, lib_name);
281     known_libraries_.PushBack(wrap);
282
283     LOG("%s: System library %s loaded at %p\n", __FUNCTION__, lib_name, wrap);
284     LOG("  name=%s\n", wrap->GetName());
285     return wrap;
286   }
287
288   ScopedPtr<SharedLibrary> lib(new SharedLibrary());
289
290   // Find the full library path.
291   String full_path;
292
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);
296     if (!path) {
297       error->Format("Can't find library file %s", lib_name);
298       return NULL;
299     }
300     full_path = path;
301   } else {
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] != '/')
306         full_path += '/';
307       full_path += lib_name;
308     } else {
309       // Absolute path. Easy.
310       full_path = lib_name;
311     }
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());
315       return NULL;
316     }
317   }
318
319   // Load the library
320   if (!lib->Load(full_path.c_str(), load_address, file_offset,
321                  no_map_exec_support_fallback_enabled, error))
322     return NULL;
323
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()) {
329     Error dep_error;
330     LibraryView* dependency = LoadLibrary(iter.GetName(),
331                                           dlopen_mode,
332                                           0U /* load address */,
333                                           0U /* file offset */,
334                                           search_path_list,
335                                           no_map_exec_support_fallback_enabled,
336                                           &dep_error);
337     if (!dependency) {
338       error->Format("When loading %s: %s", base_name, dep_error.c_str());
339       return NULL;
340     }
341     dependencies.PushBack(dependency);
342   }
343   if (CRAZY_DEBUG) {
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);
348   }
349
350   // Relocate the library.
351   LOG("%s: Relocating %s\n", __FUNCTION__, base_name);
352   if (!lib->Relocate(this, &dependencies, error))
353     return NULL;
354
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_);
360
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;
366   if (head_)
367     head_->list_prev_ = lib.Get();
368   head_ = lib.Get();
369
370   // Then create a new LibraryView for it.
371   wrap = new LibraryView();
372   wrap->SetCrazy(lib.Get(), lib_name);
373   known_libraries_.PushBack(wrap);
374
375   LOG("%s: Running constructors for %s\n", __FUNCTION__, base_name);
376
377   // Now run the constructors.
378   lib->CallConstructors();
379
380   LOG("%s: Done loading %s\n", __FUNCTION__, base_name);
381   lib.Release();
382
383   return wrap;
384 }
385
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.
388
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"
401 #else
402 #error "Unsupported target abi"
403 #endif
404
405 String LibraryList::GetLibraryFilePathInZipFile(const char* lib_name) {
406   String path;
407   path.Reserve(kMaxFilePathLengthInZip);
408   path = "lib/";
409   path += CURRENT_ABI;
410   path += "/crazy.";
411   path += lib_name;
412   return path;
413 }
414
415 int LibraryList::FindMappableLibraryInZipFile(
416     const char* zip_file_path,
417     const char* lib_name,
418     Error* error) {
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",
422                   path.c_str());
423     return CRAZY_OFFSET_FAILED;
424   }
425
426   int offset = FindStartOffsetOfFileInZipFile(zip_file_path, path.c_str());
427   if (offset == CRAZY_OFFSET_FAILED) {
428     return CRAZY_OFFSET_FAILED;
429   }
430
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;
437   }
438
439   assert(offset != CRAZY_OFFSET_FAILED);
440   return offset;
441 }
442
443 LibraryView* LibraryList::LoadLibraryInZipFile(
444     const char* zip_file_path,
445     const char* lib_name,
446     int dlopen_flags,
447     uintptr_t load_address,
448     SearchPathList* search_path_list,
449     bool no_map_exec_support_fallback_enabled,
450     Error* error) {
451   int offset = FindMappableLibraryInZipFile(zip_file_path, lib_name, error);
452   if (offset == CRAZY_OFFSET_FAILED) {
453     return NULL;
454   }
455
456   return LoadLibrary(
457       zip_file_path, dlopen_flags, load_address, offset,
458       search_path_list, no_map_exec_support_fallback_enabled, error);
459 }
460
461 void LibraryList::AddLibrary(LibraryView* wrap) {
462   known_libraries_.PushBack(wrap);
463 }
464
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()))
470       return wrap;
471   }
472   return NULL;
473 }
474
475 }  // namespace crazy