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 
SymbolLookupStatecrazy::__anon7b6ae6ee0111::SymbolLookupState26   SymbolLookupState() : found_addr(NULL), weak_addr(NULL), weak_count(0) {}
27 
28   // Check a symbol entry.
CheckSymbolcrazy::__anon7b6ae6ee0111::SymbolLookupState29   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 
LibraryList()52 LibraryList::LibraryList() : head_(0), count_(0), has_error_(false) {
53   // Nothing for now
54 }
55 
~LibraryList()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 
FindLibraryByName(const char * base_name)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 
FindSymbolFrom(const char * symbol_name,LibraryView * from)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 
FindLibraryForAddress(void * address)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__
FindArmExIdx(void * pc,int * count)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__
IteratePhdr(PhdrIterationCallback callback,void * data)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 
UnloadLibrary(LibraryView * wrap)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 
LoadLibrary(const char * lib_name,int dlopen_mode,uintptr_t load_address,off_t file_offset,SearchPathList * search_path_list,Error * error)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 
AddLibrary(LibraryView * wrap)374 void LibraryList::AddLibrary(LibraryView* wrap) {
375   known_libraries_.PushBack(wrap);
376 }
377 
FindKnownLibrary(const char * name)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