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