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