1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include "linker_soinfo.h"
30
31 #include <dlfcn.h>
32 #include <elf.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36
37 #include "linker_debug.h"
38 #include "linker_globals.h"
39 #include "linker_logger.h"
40 #include "linker_utils.h"
41
42 // TODO(dimitry): These functions are currently located in linker.cpp - find a better place for it
43 bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym);
44 ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr);
45 uint32_t get_application_target_sdk_version();
46
soinfo(android_namespace_t * ns,const char * realpath,const struct stat * file_stat,off64_t file_offset,int rtld_flags)47 soinfo::soinfo(android_namespace_t* ns, const char* realpath,
48 const struct stat* file_stat, off64_t file_offset,
49 int rtld_flags) {
50 memset(this, 0, sizeof(*this));
51
52 if (realpath != nullptr) {
53 realpath_ = realpath;
54 }
55
56 flags_ = FLAG_NEW_SOINFO;
57 version_ = SOINFO_VERSION;
58
59 if (file_stat != nullptr) {
60 this->st_dev_ = file_stat->st_dev;
61 this->st_ino_ = file_stat->st_ino;
62 this->file_offset_ = file_offset;
63 }
64
65 this->rtld_flags_ = rtld_flags;
66 this->primary_namespace_ = ns;
67 }
68
~soinfo()69 soinfo::~soinfo() {
70 g_soinfo_handles_map.erase(handle_);
71 }
72
set_dt_runpath(const char * path)73 void soinfo::set_dt_runpath(const char* path) {
74 if (!has_min_version(3)) {
75 return;
76 }
77
78 std::vector<std::string> runpaths;
79
80 split_path(path, ":", &runpaths);
81
82 std::string origin = dirname(get_realpath());
83 // FIXME: add $LIB and $PLATFORM.
84 std::vector<std::pair<std::string, std::string>> params = {{"ORIGIN", origin}};
85 for (auto&& s : runpaths) {
86 format_string(&s, params);
87 }
88
89 resolve_paths(runpaths, &dt_runpath_);
90 }
91
ElfW(Versym)92 const ElfW(Versym)* soinfo::get_versym(size_t n) const {
93 if (has_min_version(2) && versym_ != nullptr) {
94 return versym_ + n;
95 }
96
97 return nullptr;
98 }
99
ElfW(Addr)100 ElfW(Addr) soinfo::get_verneed_ptr() const {
101 if (has_min_version(2)) {
102 return verneed_ptr_;
103 }
104
105 return 0;
106 }
107
get_verneed_cnt() const108 size_t soinfo::get_verneed_cnt() const {
109 if (has_min_version(2)) {
110 return verneed_cnt_;
111 }
112
113 return 0;
114 }
115
ElfW(Addr)116 ElfW(Addr) soinfo::get_verdef_ptr() const {
117 if (has_min_version(2)) {
118 return verdef_ptr_;
119 }
120
121 return 0;
122 }
123
get_verdef_cnt() const124 size_t soinfo::get_verdef_cnt() const {
125 if (has_min_version(2)) {
126 return verdef_cnt_;
127 }
128
129 return 0;
130 }
131
find_symbol_by_name(SymbolName & symbol_name,const version_info * vi,const ElfW (Sym)** symbol) const132 bool soinfo::find_symbol_by_name(SymbolName& symbol_name,
133 const version_info* vi,
134 const ElfW(Sym)** symbol) const {
135 uint32_t symbol_index;
136 bool success =
137 is_gnu_hash() ?
138 gnu_lookup(symbol_name, vi, &symbol_index) :
139 elf_lookup(symbol_name, vi, &symbol_index);
140
141 if (success) {
142 *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index;
143 }
144
145 return success;
146 }
147
is_symbol_global_and_defined(const soinfo * si,const ElfW (Sym)* s)148 static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
149 if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
150 ELF_ST_BIND(s->st_info) == STB_WEAK) {
151 return s->st_shndx != SHN_UNDEF;
152 } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
153 DL_WARN("unexpected ST_BIND value: %d for \"%s\" in \"%s\"",
154 ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
155 }
156
157 return false;
158 }
159
160 static const ElfW(Versym) kVersymHiddenBit = 0x8000;
161
is_versym_hidden(const ElfW (Versym)* versym)162 static inline bool is_versym_hidden(const ElfW(Versym)* versym) {
163 // the symbol is hidden if bit 15 of versym is set.
164 return versym != nullptr && (*versym & kVersymHiddenBit) != 0;
165 }
166
check_symbol_version(const ElfW (Versym)verneed,const ElfW (Versym)* verdef)167 static inline bool check_symbol_version(const ElfW(Versym) verneed,
168 const ElfW(Versym)* verdef) {
169 return verneed == kVersymNotNeeded ||
170 verdef == nullptr ||
171 verneed == (*verdef & ~kVersymHiddenBit);
172 }
173
gnu_lookup(SymbolName & symbol_name,const version_info * vi,uint32_t * symbol_index) const174 bool soinfo::gnu_lookup(SymbolName& symbol_name,
175 const version_info* vi,
176 uint32_t* symbol_index) const {
177 uint32_t hash = symbol_name.gnu_hash();
178 uint32_t h2 = hash >> gnu_shift2_;
179
180 uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;
181 uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
182 ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
183
184 *symbol_index = 0;
185
186 TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
187 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
188
189 // test against bloom filter
190 if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
191 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
192 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
193
194 return true;
195 }
196
197 // bloom test says "probably yes"...
198 uint32_t n = gnu_bucket_[hash % gnu_nbucket_];
199
200 if (n == 0) {
201 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
202 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
203
204 return true;
205 }
206
207 // lookup versym for the version definition in this library
208 // note the difference between "version is not requested" (vi == nullptr)
209 // and "version not found". In the first case verneed is kVersymNotNeeded
210 // which implies that the default version can be accepted; the second case results in
211 // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols
212 // for this library and consider only *global* ones.
213 ElfW(Versym) verneed = 0;
214 if (!find_verdef_version_index(this, vi, &verneed)) {
215 return false;
216 }
217
218 do {
219 ElfW(Sym)* s = symtab_ + n;
220 const ElfW(Versym)* verdef = get_versym(n);
221 // skip hidden versions when verneed == kVersymNotNeeded (0)
222 if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
223 continue;
224 }
225 if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
226 check_symbol_version(verneed, verdef) &&
227 strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
228 is_symbol_global_and_defined(this, s)) {
229 TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
230 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
231 static_cast<size_t>(s->st_size));
232 *symbol_index = n;
233 return true;
234 }
235 } while ((gnu_chain_[n++] & 1) == 0);
236
237 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
238 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
239
240 return true;
241 }
242
elf_lookup(SymbolName & symbol_name,const version_info * vi,uint32_t * symbol_index) const243 bool soinfo::elf_lookup(SymbolName& symbol_name,
244 const version_info* vi,
245 uint32_t* symbol_index) const {
246 uint32_t hash = symbol_name.elf_hash();
247
248 TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
249 symbol_name.get_name(), get_realpath(),
250 reinterpret_cast<void*>(base), hash, hash % nbucket_);
251
252 ElfW(Versym) verneed = 0;
253 if (!find_verdef_version_index(this, vi, &verneed)) {
254 return false;
255 }
256
257 for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
258 ElfW(Sym)* s = symtab_ + n;
259 const ElfW(Versym)* verdef = get_versym(n);
260
261 // skip hidden versions when verneed == 0
262 if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
263 continue;
264 }
265
266 if (check_symbol_version(verneed, verdef) &&
267 strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
268 is_symbol_global_and_defined(this, s)) {
269 TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
270 symbol_name.get_name(), get_realpath(),
271 reinterpret_cast<void*>(s->st_value),
272 static_cast<size_t>(s->st_size));
273 *symbol_index = n;
274 return true;
275 }
276 }
277
278 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
279 symbol_name.get_name(), get_realpath(),
280 reinterpret_cast<void*>(base), hash, hash % nbucket_);
281
282 *symbol_index = 0;
283 return true;
284 }
285
ElfW(Sym)286 ElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
287 return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
288 }
289
symbol_matches_soaddr(const ElfW (Sym)* sym,ElfW (Addr)soaddr)290 static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
291 return sym->st_shndx != SHN_UNDEF &&
292 soaddr >= sym->st_value &&
293 soaddr < sym->st_value + sym->st_size;
294 }
295
ElfW(Sym)296 ElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
297 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
298
299 for (size_t i = 0; i < gnu_nbucket_; ++i) {
300 uint32_t n = gnu_bucket_[i];
301
302 if (n == 0) {
303 continue;
304 }
305
306 do {
307 ElfW(Sym)* sym = symtab_ + n;
308 if (symbol_matches_soaddr(sym, soaddr)) {
309 return sym;
310 }
311 } while ((gnu_chain_[n++] & 1) == 0);
312 }
313
314 return nullptr;
315 }
316
ElfW(Sym)317 ElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
318 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
319
320 // Search the library's symbol table for any defined symbol which
321 // contains this address.
322 for (size_t i = 0; i < nchain_; ++i) {
323 ElfW(Sym)* sym = symtab_ + i;
324 if (symbol_matches_soaddr(sym, soaddr)) {
325 return sym;
326 }
327 }
328
329 return nullptr;
330 }
331
call_function(const char * function_name __unused,linker_ctor_function_t function,const char * realpath __unused)332 static void call_function(const char* function_name __unused,
333 linker_ctor_function_t function,
334 const char* realpath __unused) {
335 if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
336 return;
337 }
338
339 TRACE("[ Calling c-tor %s @ %p for '%s' ]", function_name, function, realpath);
340 function(g_argc, g_argv, g_envp);
341 TRACE("[ Done calling c-tor %s @ %p for '%s' ]", function_name, function, realpath);
342 }
343
call_function(const char * function_name __unused,linker_dtor_function_t function,const char * realpath __unused)344 static void call_function(const char* function_name __unused,
345 linker_dtor_function_t function,
346 const char* realpath __unused) {
347 if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
348 return;
349 }
350
351 TRACE("[ Calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
352 function();
353 TRACE("[ Done calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
354 }
355
356 template <typename F>
call_array(const char * array_name __unused,F * functions,size_t count,bool reverse,const char * realpath)357 static void call_array(const char* array_name __unused,
358 F* functions,
359 size_t count,
360 bool reverse,
361 const char* realpath) {
362 if (functions == nullptr) {
363 return;
364 }
365
366 TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, realpath);
367
368 int begin = reverse ? (count - 1) : 0;
369 int end = reverse ? -1 : count;
370 int step = reverse ? -1 : 1;
371
372 for (int i = begin; i != end; i += step) {
373 TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
374 call_function("function", functions[i], realpath);
375 }
376
377 TRACE("[ Done calling %s for '%s' ]", array_name, realpath);
378 }
379
call_pre_init_constructors()380 void soinfo::call_pre_init_constructors() {
381 // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
382 // but ignored in a shared library.
383 call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false, get_realpath());
384 }
385
call_constructors()386 void soinfo::call_constructors() {
387 if (constructors_called) {
388 return;
389 }
390
391 // We set constructors_called before actually calling the constructors, otherwise it doesn't
392 // protect against recursive constructor calls. One simple example of constructor recursion
393 // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
394 // 1. The program depends on libc, so libc's constructor is called here.
395 // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
396 // 3. dlopen() calls the constructors on the newly created
397 // soinfo for libc_malloc_debug_leak.so.
398 // 4. The debug .so depends on libc, so CallConstructors is
399 // called again with the libc soinfo. If it doesn't trigger the early-
400 // out above, the libc constructor will be called again (recursively!).
401 constructors_called = true;
402
403 if (!is_main_executable() && preinit_array_ != nullptr) {
404 // The GNU dynamic linker silently ignores these, but we warn the developer.
405 PRINT("\"%s\": ignoring DT_PREINIT_ARRAY in shared library!", get_realpath());
406 }
407
408 get_children().for_each([] (soinfo* si) {
409 si->call_constructors();
410 });
411
412 if (!is_linker()) {
413 bionic_trace_begin((std::string("calling constructors: ") + get_realpath()).c_str());
414 }
415
416 // DT_INIT should be called before DT_INIT_ARRAY if both are present.
417 call_function("DT_INIT", init_func_, get_realpath());
418 call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false, get_realpath());
419
420 if (!is_linker()) {
421 bionic_trace_end();
422 }
423 }
424
call_destructors()425 void soinfo::call_destructors() {
426 if (!constructors_called) {
427 return;
428 }
429
430 ScopedTrace trace((std::string("calling destructors: ") + get_realpath()).c_str());
431
432 // DT_FINI_ARRAY must be parsed in reverse order.
433 call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true, get_realpath());
434
435 // DT_FINI should be called after DT_FINI_ARRAY if both are present.
436 call_function("DT_FINI", fini_func_, get_realpath());
437 }
438
add_child(soinfo * child)439 void soinfo::add_child(soinfo* child) {
440 if (has_min_version(0)) {
441 child->parents_.push_back(this);
442 this->children_.push_back(child);
443 }
444 }
445
remove_all_links()446 void soinfo::remove_all_links() {
447 if (!has_min_version(0)) {
448 return;
449 }
450
451 // 1. Untie connected soinfos from 'this'.
452 children_.for_each([&] (soinfo* child) {
453 child->parents_.remove_if([&] (const soinfo* parent) {
454 return parent == this;
455 });
456 });
457
458 parents_.for_each([&] (soinfo* parent) {
459 parent->children_.remove_if([&] (const soinfo* child) {
460 return child == this;
461 });
462 });
463
464 // 2. Remove from the primary namespace
465 primary_namespace_->remove_soinfo(this);
466 primary_namespace_ = nullptr;
467
468 // 3. Remove from secondary namespaces
469 secondary_namespaces_.for_each([&](android_namespace_t* ns) {
470 ns->remove_soinfo(this);
471 });
472
473
474 // 4. Once everything untied - clear local lists.
475 parents_.clear();
476 children_.clear();
477 secondary_namespaces_.clear();
478 }
479
get_st_dev() const480 dev_t soinfo::get_st_dev() const {
481 if (has_min_version(0)) {
482 return st_dev_;
483 }
484
485 return 0;
486 };
487
get_st_ino() const488 ino_t soinfo::get_st_ino() const {
489 if (has_min_version(0)) {
490 return st_ino_;
491 }
492
493 return 0;
494 }
495
get_file_offset() const496 off64_t soinfo::get_file_offset() const {
497 if (has_min_version(1)) {
498 return file_offset_;
499 }
500
501 return 0;
502 }
503
get_rtld_flags() const504 uint32_t soinfo::get_rtld_flags() const {
505 if (has_min_version(1)) {
506 return rtld_flags_;
507 }
508
509 return 0;
510 }
511
get_dt_flags_1() const512 uint32_t soinfo::get_dt_flags_1() const {
513 if (has_min_version(1)) {
514 return dt_flags_1_;
515 }
516
517 return 0;
518 }
519
set_dt_flags_1(uint32_t dt_flags_1)520 void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
521 if (has_min_version(1)) {
522 if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
523 rtld_flags_ |= RTLD_GLOBAL;
524 }
525
526 if ((dt_flags_1 & DF_1_NODELETE) != 0) {
527 rtld_flags_ |= RTLD_NODELETE;
528 }
529
530 dt_flags_1_ = dt_flags_1;
531 }
532 }
533
set_nodelete()534 void soinfo::set_nodelete() {
535 rtld_flags_ |= RTLD_NODELETE;
536 }
537
get_realpath() const538 const char* soinfo::get_realpath() const {
539 #if defined(__work_around_b_24465209__)
540 if (has_min_version(2)) {
541 return realpath_.c_str();
542 } else {
543 return old_name_;
544 }
545 #else
546 return realpath_.c_str();
547 #endif
548 }
549
set_soname(const char * soname)550 void soinfo::set_soname(const char* soname) {
551 #if defined(__work_around_b_24465209__)
552 if (has_min_version(2)) {
553 soname_ = soname;
554 }
555 strlcpy(old_name_, soname_, sizeof(old_name_));
556 #else
557 soname_ = soname;
558 #endif
559 }
560
get_soname() const561 const char* soinfo::get_soname() const {
562 #if defined(__work_around_b_24465209__)
563 if (has_min_version(2)) {
564 return soname_;
565 } else {
566 return old_name_;
567 }
568 #else
569 return soname_;
570 #endif
571 }
572
573 // This is a return on get_children()/get_parents() if
574 // 'this->flags' does not have FLAG_NEW_SOINFO set.
575 static soinfo_list_t g_empty_list;
576
get_children()577 soinfo_list_t& soinfo::get_children() {
578 if (has_min_version(0)) {
579 return children_;
580 }
581
582 return g_empty_list;
583 }
584
get_children() const585 const soinfo_list_t& soinfo::get_children() const {
586 if (has_min_version(0)) {
587 return children_;
588 }
589
590 return g_empty_list;
591 }
592
get_parents()593 soinfo_list_t& soinfo::get_parents() {
594 if (has_min_version(0)) {
595 return parents_;
596 }
597
598 return g_empty_list;
599 }
600
601 static std::vector<std::string> g_empty_runpath;
602
get_dt_runpath() const603 const std::vector<std::string>& soinfo::get_dt_runpath() const {
604 if (has_min_version(3)) {
605 return dt_runpath_;
606 }
607
608 return g_empty_runpath;
609 }
610
get_primary_namespace()611 android_namespace_t* soinfo::get_primary_namespace() {
612 if (has_min_version(3)) {
613 return primary_namespace_;
614 }
615
616 return &g_default_namespace;
617 }
618
add_secondary_namespace(android_namespace_t * secondary_ns)619 void soinfo::add_secondary_namespace(android_namespace_t* secondary_ns) {
620 CHECK(has_min_version(3));
621 secondary_namespaces_.push_back(secondary_ns);
622 }
623
get_secondary_namespaces()624 android_namespace_list_t& soinfo::get_secondary_namespaces() {
625 CHECK(has_min_version(3));
626 return secondary_namespaces_;
627 }
628
ElfW(Addr)629 ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
630 if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
631 return call_ifunc_resolver(s->st_value + load_bias);
632 }
633
634 return static_cast<ElfW(Addr)>(s->st_value + load_bias);
635 }
636
get_string(ElfW (Word)index) const637 const char* soinfo::get_string(ElfW(Word) index) const {
638 if (has_min_version(1) && (index >= strtab_size_)) {
639 __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
640 get_realpath(), strtab_size_, index);
641 }
642
643 return strtab_ + index;
644 }
645
is_gnu_hash() const646 bool soinfo::is_gnu_hash() const {
647 return (flags_ & FLAG_GNU_HASH) != 0;
648 }
649
can_unload() const650 bool soinfo::can_unload() const {
651 return !is_linked() || ((get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0);
652 }
653
is_linked() const654 bool soinfo::is_linked() const {
655 return (flags_ & FLAG_LINKED) != 0;
656 }
657
is_main_executable() const658 bool soinfo::is_main_executable() const {
659 return (flags_ & FLAG_EXE) != 0;
660 }
661
is_linker() const662 bool soinfo::is_linker() const {
663 return (flags_ & FLAG_LINKER) != 0;
664 }
665
set_linked()666 void soinfo::set_linked() {
667 flags_ |= FLAG_LINKED;
668 }
669
set_linker_flag()670 void soinfo::set_linker_flag() {
671 flags_ |= FLAG_LINKER;
672 }
673
set_main_executable()674 void soinfo::set_main_executable() {
675 flags_ |= FLAG_EXE;
676 }
677
increment_ref_count()678 void soinfo::increment_ref_count() {
679 local_group_root_->ref_count_++;
680 }
681
decrement_ref_count()682 size_t soinfo::decrement_ref_count() {
683 return --local_group_root_->ref_count_;
684 }
685
get_local_group_root() const686 soinfo* soinfo::get_local_group_root() const {
687 return local_group_root_;
688 }
689
set_mapped_by_caller(bool mapped_by_caller)690 void soinfo::set_mapped_by_caller(bool mapped_by_caller) {
691 if (mapped_by_caller) {
692 flags_ |= FLAG_MAPPED_BY_CALLER;
693 } else {
694 flags_ &= ~FLAG_MAPPED_BY_CALLER;
695 }
696 }
697
is_mapped_by_caller() const698 bool soinfo::is_mapped_by_caller() const {
699 return (flags_ & FLAG_MAPPED_BY_CALLER) != 0;
700 }
701
702 // This function returns api-level at the time of
703 // dlopen/load. Note that libraries opened by system
704 // will always have 'current' api level.
get_target_sdk_version() const705 uint32_t soinfo::get_target_sdk_version() const {
706 if (!has_min_version(2)) {
707 return __ANDROID_API__;
708 }
709
710 return local_group_root_->target_sdk_version_;
711 }
712
get_handle() const713 uintptr_t soinfo::get_handle() const {
714 CHECK(has_min_version(3));
715 CHECK(handle_ != 0);
716 return handle_;
717 }
718
to_handle()719 void* soinfo::to_handle() {
720 if (get_application_target_sdk_version() < __ANDROID_API_N__ || !has_min_version(3)) {
721 return this;
722 }
723
724 return reinterpret_cast<void*>(get_handle());
725 }
726
generate_handle()727 void soinfo::generate_handle() {
728 CHECK(has_min_version(3));
729 CHECK(handle_ == 0); // Make sure this is the first call
730
731 // Make sure the handle is unique and does not collide
732 // with special values which are RTLD_DEFAULT and RTLD_NEXT.
733 do {
734 arc4random_buf(&handle_, sizeof(handle_));
735 // the least significant bit for the handle is always 1
736 // making it easy to test the type of handle passed to
737 // dl* functions.
738 handle_ = handle_ | 1;
739 } while (handle_ == reinterpret_cast<uintptr_t>(RTLD_DEFAULT) ||
740 handle_ == reinterpret_cast<uintptr_t>(RTLD_NEXT) ||
741 g_soinfo_handles_map.find(handle_) != g_soinfo_handles_map.end());
742
743 g_soinfo_handles_map[handle_] = this;
744 }
745
746 // TODO(dimitry): Move SymbolName methods to a separate file.
747
calculate_elf_hash(const char * name)748 uint32_t calculate_elf_hash(const char* name) {
749 const uint8_t* name_bytes = reinterpret_cast<const uint8_t*>(name);
750 uint32_t h = 0, g;
751
752 while (*name_bytes) {
753 h = (h << 4) + *name_bytes++;
754 g = h & 0xf0000000;
755 h ^= g;
756 h ^= g >> 24;
757 }
758
759 return h;
760 }
761
elf_hash()762 uint32_t SymbolName::elf_hash() {
763 if (!has_elf_hash_) {
764 elf_hash_ = calculate_elf_hash(name_);
765 has_elf_hash_ = true;
766 }
767
768 return elf_hash_;
769 }
770
gnu_hash()771 uint32_t SymbolName::gnu_hash() {
772 if (!has_gnu_hash_) {
773 uint32_t h = 5381;
774 const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
775 while (*name != 0) {
776 h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
777 }
778
779 gnu_hash_ = h;
780 has_gnu_hash_ = true;
781 }
782
783 return gnu_hash_;
784 }
785