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::__anon7f4280850111::SymbolLookupState26 SymbolLookupState() : found_addr(NULL), weak_addr(NULL), weak_count(0) {}
27
28 // Check a symbol entry.
CheckSymbolcrazy::__anon7f4280850111::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