blob: 15f2502b0ebf5a7ffa4dda6a638339854c0254c7 [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.
Dimitry Ivanov2a6d9b22017-03-11 14:35:38 -080084 std::vector<std::pair<std::string, std::string>> params = {{"ORIGIN", origin}};
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070085 for (auto&& s : runpaths) {
Dimitry Ivanov2a6d9b22017-03-11 14:35:38 -080086 format_string(&s, params);
Dimitry Ivanov48ec2882016-08-04 11:50:36 -070087 }
88
89 resolve_paths(runpaths, &dt_runpath_);
90}
91
92const 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
100ElfW(Addr) soinfo::get_verneed_ptr() const {
101 if (has_min_version(2)) {
102 return verneed_ptr_;
103 }
104
105 return 0;
106}
107
108size_t soinfo::get_verneed_cnt() const {
109 if (has_min_version(2)) {
110 return verneed_cnt_;
111 }
112
113 return 0;
114}
115
116ElfW(Addr) soinfo::get_verdef_ptr() const {
117 if (has_min_version(2)) {
118 return verdef_ptr_;
119 }
120
121 return 0;
122}
123
124size_t soinfo::get_verdef_cnt() const {
125 if (has_min_version(2)) {
126 return verdef_cnt_;
127 }
128
129 return 0;
130}
131
132bool 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
148static 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
160static const ElfW(Versym) kVersymHiddenBit = 0x8000;
161
162static 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
167static 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
174bool 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
243bool 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
286ElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
287 return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
288}
289
290static 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
296ElfW(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
317ElfW(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
332static 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
344static 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
356template <typename F>
357static 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
380void 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
386void 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
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -0700412 if (!is_linker()) {
413 bionic_trace_begin((std::string("calling constructors: ") + get_realpath()).c_str());
414 }
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700415
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());
Dimitry Ivanov5c4a5802017-03-17 16:41:34 -0700419
420 if (!is_linker()) {
421 bionic_trace_end();
422 }
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700423}
424
425void soinfo::call_destructors() {
426 if (!constructors_called) {
427 return;
428 }
429 TRACE("\"%s\": calling destructors", get_realpath());
430
431 // DT_FINI_ARRAY must be parsed in reverse order.
432 call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true, get_realpath());
433
434 // DT_FINI should be called after DT_FINI_ARRAY if both are present.
435 call_function("DT_FINI", fini_func_, get_realpath());
436}
437
438void soinfo::add_child(soinfo* child) {
439 if (has_min_version(0)) {
440 child->parents_.push_back(this);
441 this->children_.push_back(child);
442 }
443}
444
445void soinfo::remove_all_links() {
446 if (!has_min_version(0)) {
447 return;
448 }
449
450 // 1. Untie connected soinfos from 'this'.
451 children_.for_each([&] (soinfo* child) {
452 child->parents_.remove_if([&] (const soinfo* parent) {
453 return parent == this;
454 });
455 });
456
457 parents_.for_each([&] (soinfo* parent) {
458 parent->children_.remove_if([&] (const soinfo* child) {
459 return child == this;
460 });
461 });
462
463 // 2. Remove from the primary namespace
464 primary_namespace_->remove_soinfo(this);
465 primary_namespace_ = nullptr;
466
467 // 3. Remove from secondary namespaces
468 secondary_namespaces_.for_each([&](android_namespace_t* ns) {
469 ns->remove_soinfo(this);
470 });
471
472
473 // 4. Once everything untied - clear local lists.
474 parents_.clear();
475 children_.clear();
476 secondary_namespaces_.clear();
477}
478
479dev_t soinfo::get_st_dev() const {
480 if (has_min_version(0)) {
481 return st_dev_;
482 }
483
484 return 0;
485};
486
487ino_t soinfo::get_st_ino() const {
488 if (has_min_version(0)) {
489 return st_ino_;
490 }
491
492 return 0;
493}
494
495off64_t soinfo::get_file_offset() const {
496 if (has_min_version(1)) {
497 return file_offset_;
498 }
499
500 return 0;
501}
502
503uint32_t soinfo::get_rtld_flags() const {
504 if (has_min_version(1)) {
505 return rtld_flags_;
506 }
507
508 return 0;
509}
510
511uint32_t soinfo::get_dt_flags_1() const {
512 if (has_min_version(1)) {
513 return dt_flags_1_;
514 }
515
516 return 0;
517}
518
519void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
520 if (has_min_version(1)) {
521 if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
522 rtld_flags_ |= RTLD_GLOBAL;
523 }
524
525 if ((dt_flags_1 & DF_1_NODELETE) != 0) {
526 rtld_flags_ |= RTLD_NODELETE;
527 }
528
529 dt_flags_1_ = dt_flags_1;
530 }
531}
532
533void soinfo::set_nodelete() {
534 rtld_flags_ |= RTLD_NODELETE;
535}
536
537const char* soinfo::get_realpath() const {
538#if defined(__work_around_b_24465209__)
539 if (has_min_version(2)) {
540 return realpath_.c_str();
541 } else {
542 return old_name_;
543 }
544#else
545 return realpath_.c_str();
546#endif
547}
548
549void soinfo::set_soname(const char* soname) {
550#if defined(__work_around_b_24465209__)
551 if (has_min_version(2)) {
552 soname_ = soname;
553 }
554 strlcpy(old_name_, soname_, sizeof(old_name_));
555#else
556 soname_ = soname;
557#endif
558}
559
560const char* soinfo::get_soname() const {
561#if defined(__work_around_b_24465209__)
562 if (has_min_version(2)) {
563 return soname_;
564 } else {
565 return old_name_;
566 }
567#else
568 return soname_;
569#endif
570}
571
572// This is a return on get_children()/get_parents() if
573// 'this->flags' does not have FLAG_NEW_SOINFO set.
574static soinfo_list_t g_empty_list;
575
576soinfo_list_t& soinfo::get_children() {
577 if (has_min_version(0)) {
578 return children_;
579 }
580
581 return g_empty_list;
582}
583
584const soinfo_list_t& soinfo::get_children() const {
585 if (has_min_version(0)) {
586 return children_;
587 }
588
589 return g_empty_list;
590}
591
592soinfo_list_t& soinfo::get_parents() {
593 if (has_min_version(0)) {
594 return parents_;
595 }
596
597 return g_empty_list;
598}
599
600static std::vector<std::string> g_empty_runpath;
601
602const std::vector<std::string>& soinfo::get_dt_runpath() const {
603 if (has_min_version(3)) {
604 return dt_runpath_;
605 }
606
607 return g_empty_runpath;
608}
609
610android_namespace_t* soinfo::get_primary_namespace() {
611 if (has_min_version(3)) {
612 return primary_namespace_;
613 }
614
615 return &g_default_namespace;
616}
617
618void soinfo::add_secondary_namespace(android_namespace_t* secondary_ns) {
619 CHECK(has_min_version(3));
620 secondary_namespaces_.push_back(secondary_ns);
621}
622
Dimitry Ivanov7a34b9d2017-02-03 14:07:34 -0800623android_namespace_list_t& soinfo::get_secondary_namespaces() {
624 CHECK(has_min_version(3));
625 return secondary_namespaces_;
626}
627
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700628ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
629 if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
630 return call_ifunc_resolver(s->st_value + load_bias);
631 }
632
633 return static_cast<ElfW(Addr)>(s->st_value + load_bias);
634}
635
636const char* soinfo::get_string(ElfW(Word) index) const {
637 if (has_min_version(1) && (index >= strtab_size_)) {
638 __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
639 get_realpath(), strtab_size_, index);
640 }
641
642 return strtab_ + index;
643}
644
645bool soinfo::is_gnu_hash() const {
646 return (flags_ & FLAG_GNU_HASH) != 0;
647}
648
649bool soinfo::can_unload() const {
650 return !is_linked() || ((get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0);
651}
652
653bool soinfo::is_linked() const {
654 return (flags_ & FLAG_LINKED) != 0;
655}
656
657bool soinfo::is_main_executable() const {
658 return (flags_ & FLAG_EXE) != 0;
659}
660
661bool soinfo::is_linker() const {
662 return (flags_ & FLAG_LINKER) != 0;
663}
664
665void soinfo::set_linked() {
666 flags_ |= FLAG_LINKED;
667}
668
669void soinfo::set_linker_flag() {
670 flags_ |= FLAG_LINKER;
671}
672
673void soinfo::set_main_executable() {
674 flags_ |= FLAG_EXE;
675}
676
677void soinfo::increment_ref_count() {
678 local_group_root_->ref_count_++;
679}
680
681size_t soinfo::decrement_ref_count() {
682 return --local_group_root_->ref_count_;
683}
684
685soinfo* soinfo::get_local_group_root() const {
686 return local_group_root_;
687}
688
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700689void soinfo::set_mapped_by_caller(bool mapped_by_caller) {
690 if (mapped_by_caller) {
691 flags_ |= FLAG_MAPPED_BY_CALLER;
692 } else {
693 flags_ &= ~FLAG_MAPPED_BY_CALLER;
694 }
695}
696
697bool soinfo::is_mapped_by_caller() const {
698 return (flags_ & FLAG_MAPPED_BY_CALLER) != 0;
699}
700
701// This function returns api-level at the time of
702// dlopen/load. Note that libraries opened by system
703// will always have 'current' api level.
704uint32_t soinfo::get_target_sdk_version() const {
705 if (!has_min_version(2)) {
706 return __ANDROID_API__;
707 }
708
709 return local_group_root_->target_sdk_version_;
710}
711
712uintptr_t soinfo::get_handle() const {
713 CHECK(has_min_version(3));
714 CHECK(handle_ != 0);
715 return handle_;
716}
717
718void* soinfo::to_handle() {
Elliott Hughes5bc78c82016-11-16 11:35:43 -0800719 if (get_application_target_sdk_version() < __ANDROID_API_N__ || !has_min_version(3)) {
Dimitry Ivanov48ec2882016-08-04 11:50:36 -0700720 return this;
721 }
722
723 return reinterpret_cast<void*>(get_handle());
724}
725
726void soinfo::generate_handle() {
727 CHECK(has_min_version(3));
728 CHECK(handle_ == 0); // Make sure this is the first call
729
730 // Make sure the handle is unique and does not collide
731 // with special values which are RTLD_DEFAULT and RTLD_NEXT.
732 do {
733 arc4random_buf(&handle_, sizeof(handle_));
734 // the least significant bit for the handle is always 1
735 // making it easy to test the type of handle passed to
736 // dl* functions.
737 handle_ = handle_ | 1;
738 } while (handle_ == reinterpret_cast<uintptr_t>(RTLD_DEFAULT) ||
739 handle_ == reinterpret_cast<uintptr_t>(RTLD_NEXT) ||
740 g_soinfo_handles_map.find(handle_) != g_soinfo_handles_map.end());
741
742 g_soinfo_handles_map[handle_] = this;
743}
744
745// TODO(dimitry): Move SymbolName methods to a separate file.
746
747uint32_t calculate_elf_hash(const char* name) {
748 const uint8_t* name_bytes = reinterpret_cast<const uint8_t*>(name);
749 uint32_t h = 0, g;
750
751 while (*name_bytes) {
752 h = (h << 4) + *name_bytes++;
753 g = h & 0xf0000000;
754 h ^= g;
755 h ^= g >> 24;
756 }
757
758 return h;
759}
760
761uint32_t SymbolName::elf_hash() {
762 if (!has_elf_hash_) {
763 elf_hash_ = calculate_elf_hash(name_);
764 has_elf_hash_ = true;
765 }
766
767 return elf_hash_;
768}
769
770uint32_t SymbolName::gnu_hash() {
771 if (!has_gnu_hash_) {
772 uint32_t h = 5381;
773 const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
774 while (*name != 0) {
775 h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
776 }
777
778 gnu_hash_ = h;
779 has_gnu_hash_ = true;
780 }
781
782 return gnu_hash_;
783}