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