blob: 6601dc1d42e24723f25fefe7ce4213deb6b45565 [file] [log] [blame]
Dimitry Ivanov48ec2882016-08-04 11:50:36 -07001/*
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
43bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym);
44ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr);
45uint32_t get_application_target_sdk_version();
46
47soinfo::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
69soinfo::~soinfo() {
70 g_soinfo_handles_map.erase(handle_);
71}
72
73void 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::pair<std::string, std::string> substs[] = {{"ORIGIN", origin}};
85 for (auto&& s : runpaths) {
86 size_t pos = 0;
87 while (pos < s.size()) {
88 pos = s.find("$", pos);
89 if (pos == std::string::npos) break;
90 for (const auto& subst : substs) {
91 const std::string& token = subst.first;
92 const std::string& replacement = subst.second;
93 if (s.substr(pos + 1, token.size()) == token) {
94 s.replace(pos, token.size() + 1, replacement);
95 // -1 to compensate for the ++pos below.
96 pos += replacement.size() - 1;
97 break;
98 } else if (s.substr(pos + 1, token.size() + 2) == "{" + token + "}") {
99 s.replace(pos, token.size() + 3, replacement);
100 pos += replacement.size() - 1;
101 break;
102 }
103 }
104 // Skip $ in case it did not match any of the known substitutions.
105 ++pos;
106 }
107 }
108
109 resolve_paths(runpaths, &dt_runpath_);
110}
111
112const ElfW(Versym)* soinfo::get_versym(size_t n) const {
113 if (has_min_version(2) && versym_ != nullptr) {
114 return versym_ + n;
115 }
116
117 return nullptr;
118}
119
120ElfW(Addr) soinfo::get_verneed_ptr() const {
121 if (has_min_version(2)) {
122 return verneed_ptr_;
123 }
124
125 return 0;
126}
127
128size_t soinfo::get_verneed_cnt() const {
129 if (has_min_version(2)) {
130 return verneed_cnt_;
131 }
132
133 return 0;
134}
135
136ElfW(Addr) soinfo::get_verdef_ptr() const {
137 if (has_min_version(2)) {
138 return verdef_ptr_;
139 }
140
141 return 0;
142}
143
144size_t soinfo::get_verdef_cnt() const {
145 if (has_min_version(2)) {
146 return verdef_cnt_;
147 }
148
149 return 0;
150}
151
152bool soinfo::find_symbol_by_name(SymbolName& symbol_name,
153 const version_info* vi,
154 const ElfW(Sym)** symbol) const {
155 uint32_t symbol_index;
156 bool success =
157 is_gnu_hash() ?
158 gnu_lookup(symbol_name, vi, &symbol_index) :
159 elf_lookup(symbol_name, vi, &symbol_index);
160
161 if (success) {
162 *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index;
163 }
164
165 return success;
166}
167
168static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
169 if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
170 ELF_ST_BIND(s->st_info) == STB_WEAK) {
171 return s->st_shndx != SHN_UNDEF;
172 } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
173 DL_WARN("unexpected ST_BIND value: %d for \"%s\" in \"%s\"",
174 ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
175 }
176
177 return false;
178}
179
180static const ElfW(Versym) kVersymHiddenBit = 0x8000;
181
182static inline bool is_versym_hidden(const ElfW(Versym)* versym) {
183 // the symbol is hidden if bit 15 of versym is set.
184 return versym != nullptr && (*versym & kVersymHiddenBit) != 0;
185}
186
187static inline bool check_symbol_version(const ElfW(Versym) verneed,
188 const ElfW(Versym)* verdef) {
189 return verneed == kVersymNotNeeded ||
190 verdef == nullptr ||
191 verneed == (*verdef & ~kVersymHiddenBit);
192}
193
194bool soinfo::gnu_lookup(SymbolName& symbol_name,
195 const version_info* vi,
196 uint32_t* symbol_index) const {
197 uint32_t hash = symbol_name.gnu_hash();
198 uint32_t h2 = hash >> gnu_shift2_;
199
200 uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;
201 uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
202 ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
203
204 *symbol_index = 0;
205
206 TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
207 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
208
209 // test against bloom filter
210 if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
211 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
212 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
213
214 return true;
215 }
216
217 // bloom test says "probably yes"...
218 uint32_t n = gnu_bucket_[hash % gnu_nbucket_];
219
220 if (n == 0) {
221 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
222 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
223
224 return true;
225 }
226
227 // lookup versym for the version definition in this library
228 // note the difference between "version is not requested" (vi == nullptr)
229 // and "version not found". In the first case verneed is kVersymNotNeeded
230 // which implies that the default version can be accepted; the second case results in
231 // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols
232 // for this library and consider only *global* ones.
233 ElfW(Versym) verneed = 0;
234 if (!find_verdef_version_index(this, vi, &verneed)) {
235 return false;
236 }
237
238 do {
239 ElfW(Sym)* s = symtab_ + n;
240 const ElfW(Versym)* verdef = get_versym(n);
241 // skip hidden versions when verneed == kVersymNotNeeded (0)
242 if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
243 continue;
244 }
245 if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
246 check_symbol_version(verneed, verdef) &&
247 strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
248 is_symbol_global_and_defined(this, s)) {
249 TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
250 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
251 static_cast<size_t>(s->st_size));
252 *symbol_index = n;
253 return true;
254 }
255 } while ((gnu_chain_[n++] & 1) == 0);
256
257 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
258 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
259
260 return true;
261}
262
263bool soinfo::elf_lookup(SymbolName& symbol_name,
264 const version_info* vi,
265 uint32_t* symbol_index) const {
266 uint32_t hash = symbol_name.elf_hash();
267
268 TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
269 symbol_name.get_name(), get_realpath(),
270 reinterpret_cast<void*>(base), hash, hash % nbucket_);
271
272 ElfW(Versym) verneed = 0;
273 if (!find_verdef_version_index(this, vi, &verneed)) {
274 return false;
275 }
276
277 for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
278 ElfW(Sym)* s = symtab_ + n;
279 const ElfW(Versym)* verdef = get_versym(n);
280
281 // skip hidden versions when verneed == 0
282 if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
283 continue;
284 }
285
286 if (check_symbol_version(verneed, verdef) &&
287 strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
288 is_symbol_global_and_defined(this, s)) {
289 TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
290 symbol_name.get_name(), get_realpath(),
291 reinterpret_cast<void*>(s->st_value),
292 static_cast<size_t>(s->st_size));
293 *symbol_index = n;
294 return true;
295 }
296 }
297
298 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
299 symbol_name.get_name(), get_realpath(),
300 reinterpret_cast<void*>(base), hash, hash % nbucket_);
301
302 *symbol_index = 0;
303 return true;
304}
305
306ElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
307 return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
308}
309
310static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
311 return sym->st_shndx != SHN_UNDEF &&
312 soaddr >= sym->st_value &&
313 soaddr < sym->st_value + sym->st_size;
314}
315
316ElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
317 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
318
319 for (size_t i = 0; i < gnu_nbucket_; ++i) {
320 uint32_t n = gnu_bucket_[i];
321
322 if (n == 0) {
323 continue;
324 }
325
326 do {
327 ElfW(Sym)* sym = symtab_ + n;
328 if (symbol_matches_soaddr(sym, soaddr)) {
329 return sym;
330 }
331 } while ((gnu_chain_[n++] & 1) == 0);
332 }
333
334 return nullptr;
335}
336
337ElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
338 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
339
340 // Search the library's symbol table for any defined symbol which
341 // contains this address.
342 for (size_t i = 0; i < nchain_; ++i) {
343 ElfW(Sym)* sym = symtab_ + i;
344 if (symbol_matches_soaddr(sym, soaddr)) {
345 return sym;
346 }
347 }
348
349 return nullptr;
350}
351
352static void call_function(const char* function_name __unused,
353 linker_ctor_function_t function,
354 const char* realpath __unused) {
355 if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
356 return;
357 }
358
359 TRACE("[ Calling c-tor %s @ %p for '%s' ]", function_name, function, realpath);
360 function(g_argc, g_argv, g_envp);
361 TRACE("[ Done calling c-tor %s @ %p for '%s' ]", function_name, function, realpath);
362}
363
364static void call_function(const char* function_name __unused,
365 linker_dtor_function_t function,
366 const char* realpath __unused) {
367 if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
368 return;
369 }
370
371 TRACE("[ Calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
372 function();
373 TRACE("[ Done calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
374}
375
376template <typename F>
377static void call_array(const char* array_name __unused,
378 F* functions,
379 size_t count,
380 bool reverse,
381 const char* realpath) {
382 if (functions == nullptr) {
383 return;
384 }
385
386 TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, realpath);
387
388 int begin = reverse ? (count - 1) : 0;
389 int end = reverse ? -1 : count;
390 int step = reverse ? -1 : 1;
391
392 for (int i = begin; i != end; i += step) {
393 TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
394 call_function("function", functions[i], realpath);
395 }
396
397 TRACE("[ Done calling %s for '%s' ]", array_name, realpath);
398}
399
400void soinfo::call_pre_init_constructors() {
401 // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
402 // but ignored in a shared library.
403 call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false, get_realpath());
404}
405
406void soinfo::call_constructors() {
407 if (constructors_called) {
408 return;
409 }
410
411 // We set constructors_called before actually calling the constructors, otherwise it doesn't
412 // protect against recursive constructor calls. One simple example of constructor recursion
413 // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
414 // 1. The program depends on libc, so libc's constructor is called here.
415 // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
416 // 3. dlopen() calls the constructors on the newly created
417 // soinfo for libc_malloc_debug_leak.so.
418 // 4. The debug .so depends on libc, so CallConstructors is
419 // called again with the libc soinfo. If it doesn't trigger the early-
420 // out above, the libc constructor will be called again (recursively!).
421 constructors_called = true;
422
423 if (!is_main_executable() && preinit_array_ != nullptr) {
424 // The GNU dynamic linker silently ignores these, but we warn the developer.
425 PRINT("\"%s\": ignoring DT_PREINIT_ARRAY in shared library!", get_realpath());
426 }
427
428 get_children().for_each([] (soinfo* si) {
429 si->call_constructors();
430 });
431
432 TRACE("\"%s\": calling constructors", get_realpath());
433
434 // DT_INIT should be called before DT_INIT_ARRAY if both are present.
435 call_function("DT_INIT", init_func_, get_realpath());
436 call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false, get_realpath());
437}
438
439void soinfo::call_destructors() {
440 if (!constructors_called) {
441 return;
442 }
443 TRACE("\"%s\": calling destructors", get_realpath());
444
445 // DT_FINI_ARRAY must be parsed in reverse order.
446 call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true, get_realpath());
447
448 // DT_FINI should be called after DT_FINI_ARRAY if both are present.
449 call_function("DT_FINI", fini_func_, get_realpath());
450}
451
452void soinfo::add_child(soinfo* child) {
453 if (has_min_version(0)) {
454 child->parents_.push_back(this);
455 this->children_.push_back(child);
456 }
457}
458
459void soinfo::remove_all_links() {
460 if (!has_min_version(0)) {
461 return;
462 }
463
464 // 1. Untie connected soinfos from 'this'.
465 children_.for_each([&] (soinfo* child) {
466 child->parents_.remove_if([&] (const soinfo* parent) {
467 return parent == this;
468 });
469 });
470
471 parents_.for_each([&] (soinfo* parent) {
472 parent->children_.remove_if([&] (const soinfo* child) {
473 return child == this;
474 });
475 });
476
477 // 2. Remove from the primary namespace
478 primary_namespace_->remove_soinfo(this);
479 primary_namespace_ = nullptr;
480
481 // 3. Remove from secondary namespaces
482 secondary_namespaces_.for_each([&](android_namespace_t* ns) {
483 ns->remove_soinfo(this);
484 });
485
486
487 // 4. Once everything untied - clear local lists.
488 parents_.clear();
489 children_.clear();
490 secondary_namespaces_.clear();
491}
492
493dev_t soinfo::get_st_dev() const {
494 if (has_min_version(0)) {
495 return st_dev_;
496 }
497
498 return 0;
499};
500
501ino_t soinfo::get_st_ino() const {
502 if (has_min_version(0)) {
503 return st_ino_;
504 }
505
506 return 0;
507}
508
509off64_t soinfo::get_file_offset() const {
510 if (has_min_version(1)) {
511 return file_offset_;
512 }
513
514 return 0;
515}
516
517uint32_t soinfo::get_rtld_flags() const {
518 if (has_min_version(1)) {
519 return rtld_flags_;
520 }
521
522 return 0;
523}
524
525uint32_t soinfo::get_dt_flags_1() const {
526 if (has_min_version(1)) {
527 return dt_flags_1_;
528 }
529
530 return 0;
531}
532
533void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
534 if (has_min_version(1)) {
535 if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
536 rtld_flags_ |= RTLD_GLOBAL;
537 }
538
539 if ((dt_flags_1 & DF_1_NODELETE) != 0) {
540 rtld_flags_ |= RTLD_NODELETE;
541 }
542
543 dt_flags_1_ = dt_flags_1;
544 }
545}
546
547void soinfo::set_nodelete() {
548 rtld_flags_ |= RTLD_NODELETE;
549}
550
551const char* soinfo::get_realpath() const {
552#if defined(__work_around_b_24465209__)
553 if (has_min_version(2)) {
554 return realpath_.c_str();
555 } else {
556 return old_name_;
557 }
558#else
559 return realpath_.c_str();
560#endif
561}
562
563void soinfo::set_soname(const char* soname) {
564#if defined(__work_around_b_24465209__)
565 if (has_min_version(2)) {
566 soname_ = soname;
567 }
568 strlcpy(old_name_, soname_, sizeof(old_name_));
569#else
570 soname_ = soname;
571#endif
572}
573
574const char* soinfo::get_soname() const {
575#if defined(__work_around_b_24465209__)
576 if (has_min_version(2)) {
577 return soname_;
578 } else {
579 return old_name_;
580 }
581#else
582 return soname_;
583#endif
584}
585
586// This is a return on get_children()/get_parents() if
587// 'this->flags' does not have FLAG_NEW_SOINFO set.
588static soinfo_list_t g_empty_list;
589
590soinfo_list_t& soinfo::get_children() {
591 if (has_min_version(0)) {
592 return children_;
593 }
594
595 return g_empty_list;
596}
597
598const soinfo_list_t& soinfo::get_children() const {
599 if (has_min_version(0)) {
600 return children_;
601 }
602
603 return g_empty_list;
604}
605
606soinfo_list_t& soinfo::get_parents() {
607 if (has_min_version(0)) {
608 return parents_;
609 }
610
611 return g_empty_list;
612}
613
614static std::vector<std::string> g_empty_runpath;
615
616const std::vector<std::string>& soinfo::get_dt_runpath() const {
617 if (has_min_version(3)) {
618 return dt_runpath_;
619 }
620
621 return g_empty_runpath;
622}
623
624android_namespace_t* soinfo::get_primary_namespace() {
625 if (has_min_version(3)) {
626 return primary_namespace_;
627 }
628
629 return &g_default_namespace;
630}
631
632void soinfo::add_secondary_namespace(android_namespace_t* secondary_ns) {
633 CHECK(has_min_version(3));
634 secondary_namespaces_.push_back(secondary_ns);
635}
636
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800637android_namespace_list_t& soinfo::get_secondary_namespaces() {
638 CHECK(has_min_version(3));
639 return secondary_namespaces_;
640}
641
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700642ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
643 if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
644 return call_ifunc_resolver(s->st_value + load_bias);
645 }
646
647 return static_cast<ElfW(Addr)>(s->st_value + load_bias);
648}
649
650const char* soinfo::get_string(ElfW(Word) index) const {
651 if (has_min_version(1) && (index >= strtab_size_)) {
652 __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
653 get_realpath(), strtab_size_, index);
654 }
655
656 return strtab_ + index;
657}
658
659bool soinfo::is_gnu_hash() const {
660 return (flags_ & FLAG_GNU_HASH) != 0;
661}
662
663bool soinfo::can_unload() const {
664 return !is_linked() || ((get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0);
665}
666
667bool soinfo::is_linked() const {
668 return (flags_ & FLAG_LINKED) != 0;
669}
670
671bool soinfo::is_main_executable() const {
672 return (flags_ & FLAG_EXE) != 0;
673}
674
675bool soinfo::is_linker() const {
676 return (flags_ & FLAG_LINKER) != 0;
677}
678
679void soinfo::set_linked() {
680 flags_ |= FLAG_LINKED;
681}
682
683void soinfo::set_linker_flag() {
684 flags_ |= FLAG_LINKER;
685}
686
687void soinfo::set_main_executable() {
688 flags_ |= FLAG_EXE;
689}
690
691void soinfo::increment_ref_count() {
692 local_group_root_->ref_count_++;
693}
694
695size_t soinfo::decrement_ref_count() {
696 return --local_group_root_->ref_count_;
697}
698
699soinfo* soinfo::get_local_group_root() const {
700 return local_group_root_;
701}
702
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700703void soinfo::set_mapped_by_caller(bool mapped_by_caller) {
704 if (mapped_by_caller) {
705 flags_ |= FLAG_MAPPED_BY_CALLER;
706 } else {
707 flags_ &= ~FLAG_MAPPED_BY_CALLER;
708 }
709}
710
711bool soinfo::is_mapped_by_caller() const {
712 return (flags_ & FLAG_MAPPED_BY_CALLER) != 0;
713}
714
715// This function returns api-level at the time of
716// dlopen/load. Note that libraries opened by system
717// will always have 'current' api level.
718uint32_t soinfo::get_target_sdk_version() const {
719 if (!has_min_version(2)) {
720 return __ANDROID_API__;
721 }
722
723 return local_group_root_->target_sdk_version_;
724}
725
726uintptr_t soinfo::get_handle() const {
727 CHECK(has_min_version(3));
728 CHECK(handle_ != 0);
729 return handle_;
730}
731
732void* soinfo::to_handle() {
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800733 if (get_application_target_sdk_version() < __ANDROID_API_N__ || !has_min_version(3)) {
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700734 return this;
735 }
736
737 return reinterpret_cast<void*>(get_handle());
738}
739
740void soinfo::generate_handle() {
741 CHECK(has_min_version(3));
742 CHECK(handle_ == 0); // Make sure this is the first call
743
744 // Make sure the handle is unique and does not collide
745 // with special values which are RTLD_DEFAULT and RTLD_NEXT.
746 do {
747 arc4random_buf(&handle_, sizeof(handle_));
748 // the least significant bit for the handle is always 1
749 // making it easy to test the type of handle passed to
750 // dl* functions.
751 handle_ = handle_ | 1;
752 } while (handle_ == reinterpret_cast<uintptr_t>(RTLD_DEFAULT) ||
753 handle_ == reinterpret_cast<uintptr_t>(RTLD_NEXT) ||
754 g_soinfo_handles_map.find(handle_) != g_soinfo_handles_map.end());
755
756 g_soinfo_handles_map[handle_] = this;
757}
758
759// TODO(dimitry): Move SymbolName methods to a separate file.
760
761uint32_t calculate_elf_hash(const char* name) {
762 const uint8_t* name_bytes = reinterpret_cast<const uint8_t*>(name);
763 uint32_t h = 0, g;
764
765 while (*name_bytes) {
766 h = (h << 4) + *name_bytes++;
767 g = h & 0xf0000000;
768 h ^= g;
769 h ^= g >> 24;
770 }
771
772 return h;
773}
774
775uint32_t SymbolName::elf_hash() {
776 if (!has_elf_hash_) {
777 elf_hash_ = calculate_elf_hash(name_);
778 has_elf_hash_ = true;
779 }
780
781 return elf_hash_;
782}
783
784uint32_t SymbolName::gnu_hash() {
785 if (!has_gnu_hash_) {
786 uint32_t h = 5381;
787 const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
788 while (*name != 0) {
789 h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
790 }
791
792 gnu_hash_ = h;
793 has_gnu_hash_ = true;
794 }
795
796 return gnu_hash_;
797}