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