aboutsummaryrefslogtreecommitdiffstats
path: root/linker
diff options
context:
space:
mode:
authorDmitriy Ivanov2014-11-09 21:27:20 -0600
committerDmitriy Ivanov2014-11-12 18:38:12 -0600
commitec18ce06f2d007be40ad6f043058f5a4c7236573 (patch)
tree0e22f0d9ad23e06303584d05483ff5a881afe20b /linker
parente5cabca516252addb5e305c8e1e0f35cafbcafbe (diff)
downloadplatform-bionic-ec18ce06f2d007be40ad6f043058f5a4c7236573.tar.gz
platform-bionic-ec18ce06f2d007be40ad6f043058f5a4c7236573.tar.xz
platform-bionic-ec18ce06f2d007be40ad6f043058f5a4c7236573.zip
Add support for hash-style=gnu
Change-Id: I171434a587420895feac8a9b1ad2342087197568
Diffstat (limited to 'linker')
-rw-r--r--linker/dlfcn.cpp2
-rw-r--r--linker/linker.cpp223
-rw-r--r--linker/linker.h46
3 files changed, 214 insertions, 57 deletions
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 367179d8..799284ee 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -145,7 +145,7 @@ int dladdr(const void* addr, Dl_info* info) {
145 info->dli_fbase = reinterpret_cast<void*>(si->base); 145 info->dli_fbase = reinterpret_cast<void*>(si->base);
146 146
147 // Determine if any symbol in the library contains the specified address. 147 // Determine if any symbol in the library contains the specified address.
148 ElfW(Sym)* sym = dladdr_find_symbol(si, addr); 148 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
149 if (sym != nullptr) { 149 if (sym != nullptr) {
150 info->dli_sname = si->get_string(sym->st_name); 150 info->dli_sname = si->get_string(sym->st_name);
151 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym)); 151 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
diff --git a/linker/linker.cpp b/linker/linker.cpp
index b2911b8c..cefbc063 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -35,6 +35,7 @@
35#include <stdlib.h> 35#include <stdlib.h>
36#include <string.h> 36#include <string.h>
37#include <sys/mman.h> 37#include <sys/mman.h>
38#include <sys/param.h>
38#include <unistd.h> 39#include <unistd.h>
39 40
40#include <new> 41#include <new>
@@ -316,6 +317,7 @@ static void soinfo_free(soinfo* si) {
316 } 317 }
317 prev = trav; 318 prev = trav;
318 } 319 }
320
319 if (trav == nullptr) { 321 if (trav == nullptr) {
320 // si was not in solist 322 // si was not in solist
321 DL_ERR("name \"%s\" is not in solist!", si->name); 323 DL_ERR("name \"%s\" is not in solist!", si->name);
@@ -335,7 +337,6 @@ static void soinfo_free(soinfo* si) {
335 g_soinfo_allocator.free(si); 337 g_soinfo_allocator.free(si);
336} 338}
337 339
338
339static void parse_path(const char* path, const char* delimiters, 340static void parse_path(const char* path, const char* delimiters,
340 const char** array, char* buf, size_t buf_size, size_t max_count) { 341 const char** array, char* buf, size_t buf_size, size_t max_count) {
341 if (path == nullptr) { 342 if (path == nullptr) {
@@ -415,39 +416,72 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void
415 return rv; 416 return rv;
416} 417}
417 418
418static ElfW(Sym)* soinfo_elf_lookup(const soinfo* si, unsigned hash, const char* name) { 419ElfW(Sym)* soinfo::find_symbol_by_name(SymbolName& symbol_name) {
419 ElfW(Sym)* symtab = si->symtab; 420 return is_gnu_hash() ? gnu_lookup(symbol_name) : elf_lookup(symbol_name);
421}
422
423static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
424 if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
425 ELF_ST_BIND(s->st_info) == STB_WEAK) {
426 return s->st_shndx != SHN_UNDEF;
427 } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
428 DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
429 ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->name);
430 }
431
432 return false;
433}
434
435ElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name) {
436 uint32_t hash = symbol_name.gnu_hash();
437 uint32_t h2 = hash >> gnu_shift2;
420 438
421 TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd", 439 uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;
422 name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket); 440 uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords;
441 ElfW(Addr) bloom_word = gnu_bloom_filter[word_num];
423 442
424 for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) { 443 // test against bloom filter
444 if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
445 return nullptr;
446 }
447
448 // bloom test says "probably yes"...
449 uint32_t n = bucket[hash % nbucket];
450
451 if (n == 0) {
452 return nullptr;
453 }
454
455 do {
425 ElfW(Sym)* s = symtab + n; 456 ElfW(Sym)* s = symtab + n;
426 if (strcmp(si->get_string(s->st_name), name)) continue; 457 if (((chain[n] ^ hash) >> 1) == 0 &&
427 458 strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
428 // only concern ourselves with global and weak symbol definitions 459 is_symbol_global_and_defined(this, s)) {
429 switch (ELF_ST_BIND(s->st_info)) { 460 return s;
430 case STB_GLOBAL: 461 }
431 case STB_WEAK: 462 } while ((chain[n++] & 1) == 0);
432 if (s->st_shndx == SHN_UNDEF) {
433 continue;
434 }
435 463
436 TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd", 464 return nullptr;
437 name, si->name, reinterpret_cast<void*>(s->st_value), 465}
438 static_cast<size_t>(s->st_size)); 466
439 return s; 467ElfW(Sym)* soinfo::elf_lookup(SymbolName& symbol_name) {
440 case STB_LOCAL: 468 uint32_t hash = symbol_name.elf_hash();
441 continue; 469
442 default: 470 TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
443 __libc_fatal("ERROR: Unexpected ST_BIND value: %d for '%s' in '%s'", 471 symbol_name.get_name(), name, reinterpret_cast<void*>(base), hash, hash % nbucket);
444 ELF_ST_BIND(s->st_info), name, si->name); 472
473 for (uint32_t n = bucket[hash % nbucket]; n != 0; n = chain[n]) {
474 ElfW(Sym)* s = symtab + n;
475 if (strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 && is_symbol_global_and_defined(this, s)) {
476 TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
477 symbol_name.get_name(), name, reinterpret_cast<void*>(s->st_value),
478 static_cast<size_t>(s->st_size));
479 return s;
445 } 480 }
446 } 481 }
447 482
448 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd", 483 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
449 name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket); 484 symbol_name.get_name(), name, reinterpret_cast<void*>(base), hash, hash % nbucket);
450
451 485
452 return nullptr; 486 return nullptr;
453} 487}
@@ -468,22 +502,44 @@ soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offs
468 this->rtld_flags = rtld_flags; 502 this->rtld_flags = rtld_flags;
469} 503}
470 504
471static unsigned elfhash(const char* _name) {
472 const unsigned char* name = reinterpret_cast<const unsigned char*>(_name);
473 unsigned h = 0, g;
474 505
475 while (*name) { 506uint32_t SymbolName::elf_hash() {
476 h = (h << 4) + *name++; 507 if (!has_elf_hash_) {
477 g = h & 0xf0000000; 508 const unsigned char* name = reinterpret_cast<const unsigned char*>(name_);
478 h ^= g; 509 uint32_t h = 0, g;
479 h ^= g >> 24; 510
511 while (*name) {
512 h = (h << 4) + *name++;
513 g = h & 0xf0000000;
514 h ^= g;
515 h ^= g >> 24;
516 }
517
518 elf_hash_ = h;
519 has_elf_hash_ = true;
480 } 520 }
481 return h; 521
522 return elf_hash_;
523}
524
525uint32_t SymbolName::gnu_hash() {
526 if (!has_gnu_hash_) {
527 uint32_t h = 5381;
528 const unsigned char* name = reinterpret_cast<const unsigned char*>(name_);
529 while (*name != 0) {
530 h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
531 }
532
533 gnu_hash_ = h;
534 has_gnu_hash_ = true;
535 }
536
537 return gnu_hash_;
482} 538}
483 539
484static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in, 540static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in,
485 const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) { 541 const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) {
486 unsigned elf_hash = elfhash(name); 542 SymbolName symbol_name(name);
487 ElfW(Sym)* s = nullptr; 543 ElfW(Sym)* s = nullptr;
488 544
489 /* "This element's presence in a shared object library alters the dynamic linker's 545 /* "This element's presence in a shared object library alters the dynamic linker's
@@ -499,7 +555,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** s
499 */ 555 */
500 if (si_from->has_DT_SYMBOLIC) { 556 if (si_from->has_DT_SYMBOLIC) {
501 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->name, name); 557 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->name, name);
502 s = soinfo_elf_lookup(si_from, elf_hash, name); 558 s = si_from->find_symbol_by_name(symbol_name);
503 if (s != nullptr) { 559 if (s != nullptr) {
504 *si_found_in = si_from; 560 *si_found_in = si_from;
505 } 561 }
@@ -509,7 +565,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** s
509 if (s == nullptr) { 565 if (s == nullptr) {
510 global_group.visit([&](soinfo* global_si) { 566 global_group.visit([&](soinfo* global_si) {
511 DEBUG("%s: looking up %s in %s (from global group)", si_from->name, name, global_si->name); 567 DEBUG("%s: looking up %s in %s (from global group)", si_from->name, name, global_si->name);
512 s = soinfo_elf_lookup(global_si, elf_hash, name); 568 s = global_si->find_symbol_by_name(symbol_name);
513 if (s != nullptr) { 569 if (s != nullptr) {
514 *si_found_in = global_si; 570 *si_found_in = global_si;
515 return false; 571 return false;
@@ -528,7 +584,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** s
528 } 584 }
529 585
530 DEBUG("%s: looking up %s in %s (from local group)", si_from->name, name, local_si->name); 586 DEBUG("%s: looking up %s in %s (from local group)", si_from->name, name, local_si->name);
531 s = soinfo_elf_lookup(local_si, elf_hash, name); 587 s = local_si->find_symbol_by_name(symbol_name);
532 if (s != nullptr) { 588 if (s != nullptr) {
533 *si_found_in = local_si; 589 *si_found_in = local_si;
534 return false; 590 return false;
@@ -665,11 +721,11 @@ static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_s
665// specified soinfo object and its dependencies in breadth first order. 721// specified soinfo object and its dependencies in breadth first order.
666ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { 722ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
667 ElfW(Sym)* result = nullptr; 723 ElfW(Sym)* result = nullptr;
668 uint32_t elf_hash = elfhash(name); 724 SymbolName symbol_name(name);
669 725
670 726
671 walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) { 727 walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) {
672 result = soinfo_elf_lookup(current_soinfo, elf_hash, name); 728 result = current_soinfo->find_symbol_by_name(symbol_name);
673 if (result != nullptr) { 729 if (result != nullptr) {
674 *found = current_soinfo; 730 *found = current_soinfo;
675 return false; 731 return false;
@@ -687,7 +743,7 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
687 specified soinfo (for RTLD_NEXT). 743 specified soinfo (for RTLD_NEXT).
688 */ 744 */
689ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) { 745ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
690 unsigned elf_hash = elfhash(name); 746 SymbolName symbol_name(name);
691 747
692 if (start == nullptr) { 748 if (start == nullptr) {
693 start = solist; 749 start = solist;
@@ -699,7 +755,7 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start)
699 continue; 755 continue;
700 } 756 }
701 757
702 s = soinfo_elf_lookup(si, elf_hash, name); 758 s = si->find_symbol_by_name(symbol_name);
703 if (s != nullptr) { 759 if (s != nullptr) {
704 *found = si; 760 *found = si;
705 break; 761 break;
@@ -724,16 +780,45 @@ soinfo* find_containing_library(const void* p) {
724 return nullptr; 780 return nullptr;
725} 781}
726 782
727ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) { 783ElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
728 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - si->base; 784 return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
785}
786
787static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
788 return sym->st_shndx != SHN_UNDEF &&
789 soaddr >= sym->st_value &&
790 soaddr < sym->st_value + sym->st_size;
791}
792
793ElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
794 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - base;
795
796 for (size_t i = 0; i < nbucket; ++i) {
797 uint32_t n = bucket[i];
798
799 if (n == 0) {
800 continue;
801 }
802
803 do {
804 ElfW(Sym)* sym = symtab + n;
805 if (symbol_matches_soaddr(sym, soaddr)) {
806 return sym;
807 }
808 } while ((chain[n++] & 1) == 0);
809 }
810
811 return nullptr;
812}
813
814ElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
815 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - base;
729 816
730 // Search the library's symbol table for any defined symbol which 817 // Search the library's symbol table for any defined symbol which
731 // contains this address. 818 // contains this address.
732 for (size_t i = 0; i < si->nchain; ++i) { 819 for (size_t i = 0; i < nchain; ++i) {
733 ElfW(Sym)* sym = &si->symtab[i]; 820 ElfW(Sym)* sym = symtab + i;
734 if (sym->st_shndx != SHN_UNDEF && 821 if (symbol_matches_soaddr(sym, soaddr)) {
735 soaddr >= sym->st_value &&
736 soaddr < sym->st_value + sym->st_size) {
737 return sym; 822 return sym;
738 } 823 }
739 } 824 }
@@ -1898,6 +1983,10 @@ const char* soinfo::get_string(ElfW(Word) index) const {
1898 return strtab + index; 1983 return strtab + index;
1899} 1984}
1900 1985
1986bool soinfo::is_gnu_hash() const {
1987 return (flags & FLAG_GNU_HASH) != 0;
1988}
1989
1901bool soinfo::can_unload() const { 1990bool soinfo::can_unload() const {
1902 return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0; 1991 return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0;
1903} 1992}
@@ -2003,12 +2092,42 @@ bool soinfo::PrelinkImage() {
2003 break; 2092 break;
2004 2093
2005 case DT_HASH: 2094 case DT_HASH:
2095 if (nbucket != 0) {
2096 // in case of --hash-style=both, we prefer gnu
2097 break;
2098 }
2099
2006 nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 2100 nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2007 nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 2101 nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2008 bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8); 2102 bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2009 chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4); 2103 chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4);
2010 break; 2104 break;
2011 2105
2106 case DT_GNU_HASH:
2107 if (nbucket != 0) {
2108 // in case of --hash-style=both, we prefer gnu
2109 nchain = 0;
2110 }
2111
2112 nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2113 // skip symndx
2114 gnu_maskwords = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2115 gnu_shift2 = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
2116
2117 gnu_bloom_filter = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
2118 bucket = reinterpret_cast<uint32_t*>(gnu_bloom_filter + gnu_maskwords);
2119 // amend chain for symndx = header[1]
2120 chain = bucket + nbucket - reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2121
2122 if (!powerof2(gnu_maskwords)) {
2123 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two", gnu_maskwords, name);
2124 return false;
2125 }
2126 --gnu_maskwords;
2127
2128 flags |= FLAG_GNU_HASH;
2129 break;
2130
2012 case DT_STRTAB: 2131 case DT_STRTAB:
2013 strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr); 2132 strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
2014 break; 2133 break;
@@ -2023,7 +2142,7 @@ bool soinfo::PrelinkImage() {
2023 2142
2024 case DT_SYMENT: 2143 case DT_SYMENT:
2025 if (d->d_un.d_val != sizeof(ElfW(Sym))) { 2144 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
2026 DL_ERR("invalid DT_SYMENT: %zd", static_cast<size_t>(d->d_un.d_val)); 2145 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"", static_cast<size_t>(d->d_un.d_val), name);
2027 return false; 2146 return false;
2028 } 2147 }
2029 break; 2148 break;
@@ -2263,7 +2382,7 @@ bool soinfo::PrelinkImage() {
2263 return false; 2382 return false;
2264 } 2383 }
2265 if (nbucket == 0) { 2384 if (nbucket == 0) {
2266 DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name); 2385 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" (new hash type from the future?)", name);
2267 return false; 2386 return false;
2268 } 2387 }
2269 if (strtab == 0) { 2388 if (strtab == 0) {
diff --git a/linker/linker.h b/linker/linker.h
index 0a98b40d..69d8c7b5 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -87,6 +87,7 @@
87#define FLAG_LINKED 0x00000001 87#define FLAG_LINKED 0x00000001
88#define FLAG_EXE 0x00000004 // The main executable 88#define FLAG_EXE 0x00000004 // The main executable
89#define FLAG_LINKER 0x00000010 // The linker itself 89#define FLAG_LINKER 0x00000010 // The linker itself
90#define FLAG_GNU_HASH 0x00000040 // uses gnu hash
90#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format 91#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
91 92
92#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE) 93#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)
@@ -105,14 +106,38 @@ typedef void (*linker_function_t)();
105struct soinfo; 106struct soinfo;
106 107
107class SoinfoListAllocator { 108class SoinfoListAllocator {
108public: 109 public:
109 static LinkedListEntry<soinfo>* alloc(); 110 static LinkedListEntry<soinfo>* alloc();
110 static void free(LinkedListEntry<soinfo>* entry); 111 static void free(LinkedListEntry<soinfo>* entry);
111private: 112
113 private:
112 // unconstructable 114 // unconstructable
113 DISALLOW_IMPLICIT_CONSTRUCTORS(SoinfoListAllocator); 115 DISALLOW_IMPLICIT_CONSTRUCTORS(SoinfoListAllocator);
114}; 116};
115 117
118class SymbolName {
119 public:
120 explicit SymbolName(const char* name)
121 : name_(name), has_elf_hash_(false), has_gnu_hash_(false),
122 elf_hash_(0), gnu_hash_(0) { }
123
124 const char* get_name() {
125 return name_;
126 }
127
128 uint32_t elf_hash();
129 uint32_t gnu_hash();
130
131 private:
132 const char* name_;
133 bool has_elf_hash_;
134 bool has_gnu_hash_;
135 uint32_t elf_hash_;
136 uint32_t gnu_hash_;
137
138 DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolName);
139};
140
116struct soinfo { 141struct soinfo {
117 public: 142 public:
118 typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t; 143 typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
@@ -140,7 +165,6 @@ struct soinfo {
140 165
141 private: 166 private:
142 const char* strtab; 167 const char* strtab;
143 public:
144 ElfW(Sym)* symtab; 168 ElfW(Sym)* symtab;
145 169
146 size_t nbucket; 170 size_t nbucket;
@@ -148,6 +172,7 @@ struct soinfo {
148 uint32_t* bucket; 172 uint32_t* bucket;
149 uint32_t* chain; 173 uint32_t* chain;
150 174
175 public:
151#if defined(__mips__) || !defined(__LP64__) 176#if defined(__mips__) || !defined(__LP64__)
152 // This is only used by mips and mips64, but needs to be here for 177 // This is only used by mips and mips64, but needs to be here for
153 // all 32-bit architectures to preserve binary compatibility. 178 // all 32-bit architectures to preserve binary compatibility.
@@ -225,16 +250,24 @@ struct soinfo {
225 soinfo_list_t& get_children(); 250 soinfo_list_t& get_children();
226 soinfo_list_t& get_parents(); 251 soinfo_list_t& get_parents();
227 252
253 ElfW(Sym)* find_symbol_by_name(SymbolName& symbol_name);
254 ElfW(Sym)* find_symbol_by_address(const void* addr);
228 ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s); 255 ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s);
229 256
230 const char* get_string(ElfW(Word) index) const; 257 const char* get_string(ElfW(Word) index) const;
231 bool can_unload() const; 258 bool can_unload() const;
259 bool is_gnu_hash() const;
232 260
233 bool inline has_min_version(uint32_t min_version) const { 261 bool inline has_min_version(uint32_t min_version) const {
234 return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; 262 return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version;
235 } 263 }
236 264
237 private: 265 private:
266 ElfW(Sym)* elf_lookup(SymbolName& symbol_name);
267 ElfW(Sym)* elf_addr_lookup(const void* addr);
268 ElfW(Sym)* gnu_lookup(SymbolName& symbol_name);
269 ElfW(Sym)* gnu_addr_lookup(const void* addr);
270
238 void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); 271 void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
239 void CallFunction(const char* function_name, linker_function_t function); 272 void CallFunction(const char* function_name, linker_function_t function);
240#if defined(USE_RELA) 273#if defined(USE_RELA)
@@ -262,6 +295,12 @@ struct soinfo {
262 uint32_t dt_flags_1; 295 uint32_t dt_flags_1;
263 size_t strtab_size; 296 size_t strtab_size;
264 297
298 // version >= 2
299 uint32_t gnu_maskwords;
300 uint32_t gnu_shift2;
301
302 ElfW(Addr)* gnu_bloom_filter;
303
265 friend soinfo* get_libdl_info(); 304 friend soinfo* get_libdl_info();
266}; 305};
267 306
@@ -275,7 +314,6 @@ void do_dlclose(soinfo* si);
275ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start); 314ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start);
276soinfo* find_containing_library(const void* addr); 315soinfo* find_containing_library(const void* addr);
277 316
278ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr);
279ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name); 317ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
280 318
281void debuggerd_init(); 319void debuggerd_init();