1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker *
5*8d67ca89SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker * are met:
8*8d67ca89SAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker * the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker * distribution.
14*8d67ca89SAndroid Build Coastguard Worker *
15*8d67ca89SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker */
28*8d67ca89SAndroid Build Coastguard Worker
29*8d67ca89SAndroid Build Coastguard Worker #include "linker_soinfo.h"
30*8d67ca89SAndroid Build Coastguard Worker
31*8d67ca89SAndroid Build Coastguard Worker #include <dlfcn.h>
32*8d67ca89SAndroid Build Coastguard Worker #include <elf.h>
33*8d67ca89SAndroid Build Coastguard Worker #include <string.h>
34*8d67ca89SAndroid Build Coastguard Worker #include <sys/stat.h>
35*8d67ca89SAndroid Build Coastguard Worker #include <unistd.h>
36*8d67ca89SAndroid Build Coastguard Worker
37*8d67ca89SAndroid Build Coastguard Worker #include <async_safe/log.h>
38*8d67ca89SAndroid Build Coastguard Worker
39*8d67ca89SAndroid Build Coastguard Worker #include "linker.h"
40*8d67ca89SAndroid Build Coastguard Worker #include "linker_config.h"
41*8d67ca89SAndroid Build Coastguard Worker #include "linker_debug.h"
42*8d67ca89SAndroid Build Coastguard Worker #include "linker_globals.h"
43*8d67ca89SAndroid Build Coastguard Worker #include "linker_gnu_hash.h"
44*8d67ca89SAndroid Build Coastguard Worker #include "linker_logger.h"
45*8d67ca89SAndroid Build Coastguard Worker #include "linker_relocate.h"
46*8d67ca89SAndroid Build Coastguard Worker #include "linker_utils.h"
47*8d67ca89SAndroid Build Coastguard Worker #include "platform/bionic/mte.h"
48*8d67ca89SAndroid Build Coastguard Worker #include "private/bionic_globals.h"
49*8d67ca89SAndroid Build Coastguard Worker
SymbolLookupList(soinfo * si)50*8d67ca89SAndroid Build Coastguard Worker SymbolLookupList::SymbolLookupList(soinfo* si)
51*8d67ca89SAndroid Build Coastguard Worker : sole_lib_(si->get_lookup_lib()), begin_(&sole_lib_), end_(&sole_lib_ + 1) {
52*8d67ca89SAndroid Build Coastguard Worker CHECK(si != nullptr);
53*8d67ca89SAndroid Build Coastguard Worker slow_path_count_ += !!g_linker_debug_config.lookup;
54*8d67ca89SAndroid Build Coastguard Worker slow_path_count_ += sole_lib_.needs_sysv_lookup();
55*8d67ca89SAndroid Build Coastguard Worker }
56*8d67ca89SAndroid Build Coastguard Worker
SymbolLookupList(const soinfo_list_t & global_group,const soinfo_list_t & local_group)57*8d67ca89SAndroid Build Coastguard Worker SymbolLookupList::SymbolLookupList(const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
58*8d67ca89SAndroid Build Coastguard Worker slow_path_count_ += !!g_linker_debug_config.lookup;
59*8d67ca89SAndroid Build Coastguard Worker libs_.reserve(1 + global_group.size() + local_group.size());
60*8d67ca89SAndroid Build Coastguard Worker
61*8d67ca89SAndroid Build Coastguard Worker // Reserve a space in front for DT_SYMBOLIC lookup.
62*8d67ca89SAndroid Build Coastguard Worker libs_.push_back(SymbolLookupLib {});
63*8d67ca89SAndroid Build Coastguard Worker
64*8d67ca89SAndroid Build Coastguard Worker global_group.for_each([this](soinfo* si) {
65*8d67ca89SAndroid Build Coastguard Worker libs_.push_back(si->get_lookup_lib());
66*8d67ca89SAndroid Build Coastguard Worker slow_path_count_ += libs_.back().needs_sysv_lookup();
67*8d67ca89SAndroid Build Coastguard Worker });
68*8d67ca89SAndroid Build Coastguard Worker
69*8d67ca89SAndroid Build Coastguard Worker local_group.for_each([this](soinfo* si) {
70*8d67ca89SAndroid Build Coastguard Worker libs_.push_back(si->get_lookup_lib());
71*8d67ca89SAndroid Build Coastguard Worker slow_path_count_ += libs_.back().needs_sysv_lookup();
72*8d67ca89SAndroid Build Coastguard Worker });
73*8d67ca89SAndroid Build Coastguard Worker
74*8d67ca89SAndroid Build Coastguard Worker begin_ = &libs_[1];
75*8d67ca89SAndroid Build Coastguard Worker end_ = &libs_[0] + libs_.size();
76*8d67ca89SAndroid Build Coastguard Worker }
77*8d67ca89SAndroid Build Coastguard Worker
78*8d67ca89SAndroid Build Coastguard Worker /* "This element's presence in a shared object library alters the dynamic linker's
79*8d67ca89SAndroid Build Coastguard Worker * symbol resolution algorithm for references within the library. Instead of starting
80*8d67ca89SAndroid Build Coastguard Worker * a symbol search with the executable file, the dynamic linker starts from the shared
81*8d67ca89SAndroid Build Coastguard Worker * object itself. If the shared object fails to supply the referenced symbol, the
82*8d67ca89SAndroid Build Coastguard Worker * dynamic linker then searches the executable file and other shared objects as usual."
83*8d67ca89SAndroid Build Coastguard Worker *
84*8d67ca89SAndroid Build Coastguard Worker * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
85*8d67ca89SAndroid Build Coastguard Worker *
86*8d67ca89SAndroid Build Coastguard Worker * Note that this is unlikely since static linker avoids generating
87*8d67ca89SAndroid Build Coastguard Worker * relocations for -Bsymbolic linked dynamic executables.
88*8d67ca89SAndroid Build Coastguard Worker */
set_dt_symbolic_lib(soinfo * lib)89*8d67ca89SAndroid Build Coastguard Worker void SymbolLookupList::set_dt_symbolic_lib(soinfo* lib) {
90*8d67ca89SAndroid Build Coastguard Worker CHECK(!libs_.empty());
91*8d67ca89SAndroid Build Coastguard Worker slow_path_count_ -= libs_[0].needs_sysv_lookup();
92*8d67ca89SAndroid Build Coastguard Worker libs_[0] = lib ? lib->get_lookup_lib() : SymbolLookupLib();
93*8d67ca89SAndroid Build Coastguard Worker slow_path_count_ += libs_[0].needs_sysv_lookup();
94*8d67ca89SAndroid Build Coastguard Worker begin_ = lib ? &libs_[0] : &libs_[1];
95*8d67ca89SAndroid Build Coastguard Worker }
96*8d67ca89SAndroid Build Coastguard Worker
97*8d67ca89SAndroid Build Coastguard Worker // Check whether a requested version matches the version on a symbol definition. There are a few
98*8d67ca89SAndroid Build Coastguard Worker // special cases:
99*8d67ca89SAndroid Build Coastguard Worker // - If the defining DSO has no version info at all, then any version matches.
100*8d67ca89SAndroid Build Coastguard Worker // - If no version is requested (vi==nullptr, verneed==kVersymNotNeeded), then any non-hidden
101*8d67ca89SAndroid Build Coastguard Worker // version matches.
102*8d67ca89SAndroid Build Coastguard Worker // - If the requested version is not defined by the DSO, then verneed is kVersymGlobal, and only
103*8d67ca89SAndroid Build Coastguard Worker // global symbol definitions match. (This special case is handled as part of the ordinary case
104*8d67ca89SAndroid Build Coastguard Worker // where the version must match exactly.)
check_symbol_version(const ElfW (Versym)* ver_table,uint32_t sym_idx,const ElfW (Versym)verneed)105*8d67ca89SAndroid Build Coastguard Worker static inline bool check_symbol_version(const ElfW(Versym)* ver_table, uint32_t sym_idx,
106*8d67ca89SAndroid Build Coastguard Worker const ElfW(Versym) verneed) {
107*8d67ca89SAndroid Build Coastguard Worker if (ver_table == nullptr) return true;
108*8d67ca89SAndroid Build Coastguard Worker const uint32_t verdef = ver_table[sym_idx];
109*8d67ca89SAndroid Build Coastguard Worker return (verneed == kVersymNotNeeded) ?
110*8d67ca89SAndroid Build Coastguard Worker !(verdef & kVersymHiddenBit) :
111*8d67ca89SAndroid Build Coastguard Worker verneed == (verdef & ~kVersymHiddenBit);
112*8d67ca89SAndroid Build Coastguard Worker }
113*8d67ca89SAndroid Build Coastguard Worker
114*8d67ca89SAndroid Build Coastguard Worker template <bool IsGeneral>
ElfW(Sym)115*8d67ca89SAndroid Build Coastguard Worker __attribute__((noinline)) static const ElfW(Sym)*
116*8d67ca89SAndroid Build Coastguard Worker soinfo_do_lookup_impl(const char* name, const version_info* vi,
117*8d67ca89SAndroid Build Coastguard Worker soinfo** si_found_in, const SymbolLookupList& lookup_list) {
118*8d67ca89SAndroid Build Coastguard Worker const auto [ hash, name_len ] = calculate_gnu_hash(name);
119*8d67ca89SAndroid Build Coastguard Worker constexpr uint32_t kBloomMaskBits = sizeof(ElfW(Addr)) * 8;
120*8d67ca89SAndroid Build Coastguard Worker SymbolName elf_symbol_name(name);
121*8d67ca89SAndroid Build Coastguard Worker
122*8d67ca89SAndroid Build Coastguard Worker const SymbolLookupLib* end = lookup_list.end();
123*8d67ca89SAndroid Build Coastguard Worker const SymbolLookupLib* it = lookup_list.begin();
124*8d67ca89SAndroid Build Coastguard Worker
125*8d67ca89SAndroid Build Coastguard Worker while (true) {
126*8d67ca89SAndroid Build Coastguard Worker const SymbolLookupLib* lib;
127*8d67ca89SAndroid Build Coastguard Worker uint32_t sym_idx;
128*8d67ca89SAndroid Build Coastguard Worker
129*8d67ca89SAndroid Build Coastguard Worker // Iterate over libraries until we find one whose Bloom filter matches the symbol we're
130*8d67ca89SAndroid Build Coastguard Worker // searching for.
131*8d67ca89SAndroid Build Coastguard Worker while (true) {
132*8d67ca89SAndroid Build Coastguard Worker if (it == end) return nullptr;
133*8d67ca89SAndroid Build Coastguard Worker lib = it++;
134*8d67ca89SAndroid Build Coastguard Worker
135*8d67ca89SAndroid Build Coastguard Worker if (IsGeneral && lib->needs_sysv_lookup()) {
136*8d67ca89SAndroid Build Coastguard Worker if (const ElfW(Sym)* sym = lib->si_->find_symbol_by_name(elf_symbol_name, vi)) {
137*8d67ca89SAndroid Build Coastguard Worker *si_found_in = lib->si_;
138*8d67ca89SAndroid Build Coastguard Worker return sym;
139*8d67ca89SAndroid Build Coastguard Worker }
140*8d67ca89SAndroid Build Coastguard Worker continue;
141*8d67ca89SAndroid Build Coastguard Worker }
142*8d67ca89SAndroid Build Coastguard Worker
143*8d67ca89SAndroid Build Coastguard Worker if (IsGeneral) {
144*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(lookup, "SEARCH %s in %s@%p (gnu)",
145*8d67ca89SAndroid Build Coastguard Worker name, lib->si_->get_realpath(), reinterpret_cast<void*>(lib->si_->base));
146*8d67ca89SAndroid Build Coastguard Worker }
147*8d67ca89SAndroid Build Coastguard Worker
148*8d67ca89SAndroid Build Coastguard Worker const uint32_t word_num = (hash / kBloomMaskBits) & lib->gnu_maskwords_;
149*8d67ca89SAndroid Build Coastguard Worker const ElfW(Addr) bloom_word = lib->gnu_bloom_filter_[word_num];
150*8d67ca89SAndroid Build Coastguard Worker const uint32_t h1 = hash % kBloomMaskBits;
151*8d67ca89SAndroid Build Coastguard Worker const uint32_t h2 = (hash >> lib->gnu_shift2_) % kBloomMaskBits;
152*8d67ca89SAndroid Build Coastguard Worker
153*8d67ca89SAndroid Build Coastguard Worker if ((1 & (bloom_word >> h1) & (bloom_word >> h2)) == 1) {
154*8d67ca89SAndroid Build Coastguard Worker sym_idx = lib->gnu_bucket_[hash % lib->gnu_nbucket_];
155*8d67ca89SAndroid Build Coastguard Worker if (sym_idx != 0) {
156*8d67ca89SAndroid Build Coastguard Worker break;
157*8d67ca89SAndroid Build Coastguard Worker }
158*8d67ca89SAndroid Build Coastguard Worker }
159*8d67ca89SAndroid Build Coastguard Worker }
160*8d67ca89SAndroid Build Coastguard Worker
161*8d67ca89SAndroid Build Coastguard Worker // Search the library's hash table chain.
162*8d67ca89SAndroid Build Coastguard Worker ElfW(Versym) verneed = kVersymNotNeeded;
163*8d67ca89SAndroid Build Coastguard Worker bool calculated_verneed = false;
164*8d67ca89SAndroid Build Coastguard Worker
165*8d67ca89SAndroid Build Coastguard Worker uint32_t chain_value = 0;
166*8d67ca89SAndroid Build Coastguard Worker const ElfW(Sym)* sym = nullptr;
167*8d67ca89SAndroid Build Coastguard Worker
168*8d67ca89SAndroid Build Coastguard Worker do {
169*8d67ca89SAndroid Build Coastguard Worker sym = lib->symtab_ + sym_idx;
170*8d67ca89SAndroid Build Coastguard Worker chain_value = lib->gnu_chain_[sym_idx];
171*8d67ca89SAndroid Build Coastguard Worker if ((chain_value >> 1) == (hash >> 1)) {
172*8d67ca89SAndroid Build Coastguard Worker if (vi != nullptr && !calculated_verneed) {
173*8d67ca89SAndroid Build Coastguard Worker calculated_verneed = true;
174*8d67ca89SAndroid Build Coastguard Worker verneed = find_verdef_version_index(lib->si_, vi);
175*8d67ca89SAndroid Build Coastguard Worker }
176*8d67ca89SAndroid Build Coastguard Worker if (check_symbol_version(lib->versym_, sym_idx, verneed) &&
177*8d67ca89SAndroid Build Coastguard Worker static_cast<size_t>(sym->st_name) + name_len + 1 <= lib->strtab_size_ &&
178*8d67ca89SAndroid Build Coastguard Worker memcmp(lib->strtab_ + sym->st_name, name, name_len + 1) == 0 &&
179*8d67ca89SAndroid Build Coastguard Worker is_symbol_global_and_defined(lib->si_, sym)) {
180*8d67ca89SAndroid Build Coastguard Worker *si_found_in = lib->si_;
181*8d67ca89SAndroid Build Coastguard Worker return sym;
182*8d67ca89SAndroid Build Coastguard Worker }
183*8d67ca89SAndroid Build Coastguard Worker }
184*8d67ca89SAndroid Build Coastguard Worker ++sym_idx;
185*8d67ca89SAndroid Build Coastguard Worker } while ((chain_value & 1) == 0);
186*8d67ca89SAndroid Build Coastguard Worker }
187*8d67ca89SAndroid Build Coastguard Worker }
188*8d67ca89SAndroid Build Coastguard Worker
ElfW(Sym)189*8d67ca89SAndroid Build Coastguard Worker const ElfW(Sym)* soinfo_do_lookup(const char* name, const version_info* vi,
190*8d67ca89SAndroid Build Coastguard Worker soinfo** si_found_in, const SymbolLookupList& lookup_list) {
191*8d67ca89SAndroid Build Coastguard Worker return lookup_list.needs_slow_path() ?
192*8d67ca89SAndroid Build Coastguard Worker soinfo_do_lookup_impl<true>(name, vi, si_found_in, lookup_list) :
193*8d67ca89SAndroid Build Coastguard Worker soinfo_do_lookup_impl<false>(name, vi, si_found_in, lookup_list);
194*8d67ca89SAndroid Build Coastguard Worker }
195*8d67ca89SAndroid Build Coastguard Worker
soinfo(android_namespace_t * ns,const char * realpath,const struct stat * file_stat,off64_t file_offset,int rtld_flags)196*8d67ca89SAndroid Build Coastguard Worker soinfo::soinfo(android_namespace_t* ns, const char* realpath, const struct stat* file_stat,
197*8d67ca89SAndroid Build Coastguard Worker off64_t file_offset, int rtld_flags) {
198*8d67ca89SAndroid Build Coastguard Worker if (realpath != nullptr) {
199*8d67ca89SAndroid Build Coastguard Worker realpath_ = realpath;
200*8d67ca89SAndroid Build Coastguard Worker }
201*8d67ca89SAndroid Build Coastguard Worker
202*8d67ca89SAndroid Build Coastguard Worker flags_ = FLAG_NEW_SOINFO;
203*8d67ca89SAndroid Build Coastguard Worker version_ = SOINFO_VERSION;
204*8d67ca89SAndroid Build Coastguard Worker
205*8d67ca89SAndroid Build Coastguard Worker if (file_stat != nullptr) {
206*8d67ca89SAndroid Build Coastguard Worker this->st_dev_ = file_stat->st_dev;
207*8d67ca89SAndroid Build Coastguard Worker this->st_ino_ = file_stat->st_ino;
208*8d67ca89SAndroid Build Coastguard Worker this->file_offset_ = file_offset;
209*8d67ca89SAndroid Build Coastguard Worker }
210*8d67ca89SAndroid Build Coastguard Worker
211*8d67ca89SAndroid Build Coastguard Worker this->rtld_flags_ = rtld_flags;
212*8d67ca89SAndroid Build Coastguard Worker this->primary_namespace_ = ns;
213*8d67ca89SAndroid Build Coastguard Worker }
214*8d67ca89SAndroid Build Coastguard Worker
~soinfo()215*8d67ca89SAndroid Build Coastguard Worker soinfo::~soinfo() {
216*8d67ca89SAndroid Build Coastguard Worker g_soinfo_handles_map.erase(handle_);
217*8d67ca89SAndroid Build Coastguard Worker }
218*8d67ca89SAndroid Build Coastguard Worker
set_dt_runpath(const char * path)219*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_dt_runpath(const char* path) {
220*8d67ca89SAndroid Build Coastguard Worker if (!has_min_version(3)) {
221*8d67ca89SAndroid Build Coastguard Worker return;
222*8d67ca89SAndroid Build Coastguard Worker }
223*8d67ca89SAndroid Build Coastguard Worker
224*8d67ca89SAndroid Build Coastguard Worker std::vector<std::string> runpaths;
225*8d67ca89SAndroid Build Coastguard Worker
226*8d67ca89SAndroid Build Coastguard Worker split_path(path, ":", &runpaths);
227*8d67ca89SAndroid Build Coastguard Worker
228*8d67ca89SAndroid Build Coastguard Worker std::string origin = dirname(get_realpath());
229*8d67ca89SAndroid Build Coastguard Worker // FIXME: add $PLATFORM.
230*8d67ca89SAndroid Build Coastguard Worker std::vector<std::pair<std::string, std::string>> params = {
231*8d67ca89SAndroid Build Coastguard Worker {"ORIGIN", origin},
232*8d67ca89SAndroid Build Coastguard Worker {"LIB", kLibPath},
233*8d67ca89SAndroid Build Coastguard Worker };
234*8d67ca89SAndroid Build Coastguard Worker for (auto&& s : runpaths) {
235*8d67ca89SAndroid Build Coastguard Worker format_string(&s, params);
236*8d67ca89SAndroid Build Coastguard Worker }
237*8d67ca89SAndroid Build Coastguard Worker
238*8d67ca89SAndroid Build Coastguard Worker resolve_paths(runpaths, &dt_runpath_);
239*8d67ca89SAndroid Build Coastguard Worker }
240*8d67ca89SAndroid Build Coastguard Worker
ElfW(Versym)241*8d67ca89SAndroid Build Coastguard Worker const ElfW(Versym)* soinfo::get_versym(size_t n) const {
242*8d67ca89SAndroid Build Coastguard Worker auto table = get_versym_table();
243*8d67ca89SAndroid Build Coastguard Worker return table ? table + n : nullptr;
244*8d67ca89SAndroid Build Coastguard Worker }
245*8d67ca89SAndroid Build Coastguard Worker
ElfW(Addr)246*8d67ca89SAndroid Build Coastguard Worker ElfW(Addr) soinfo::get_verneed_ptr() const {
247*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(2)) {
248*8d67ca89SAndroid Build Coastguard Worker return verneed_ptr_;
249*8d67ca89SAndroid Build Coastguard Worker }
250*8d67ca89SAndroid Build Coastguard Worker
251*8d67ca89SAndroid Build Coastguard Worker return 0;
252*8d67ca89SAndroid Build Coastguard Worker }
253*8d67ca89SAndroid Build Coastguard Worker
get_verneed_cnt() const254*8d67ca89SAndroid Build Coastguard Worker size_t soinfo::get_verneed_cnt() const {
255*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(2)) {
256*8d67ca89SAndroid Build Coastguard Worker return verneed_cnt_;
257*8d67ca89SAndroid Build Coastguard Worker }
258*8d67ca89SAndroid Build Coastguard Worker
259*8d67ca89SAndroid Build Coastguard Worker return 0;
260*8d67ca89SAndroid Build Coastguard Worker }
261*8d67ca89SAndroid Build Coastguard Worker
ElfW(Addr)262*8d67ca89SAndroid Build Coastguard Worker ElfW(Addr) soinfo::get_verdef_ptr() const {
263*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(2)) {
264*8d67ca89SAndroid Build Coastguard Worker return verdef_ptr_;
265*8d67ca89SAndroid Build Coastguard Worker }
266*8d67ca89SAndroid Build Coastguard Worker
267*8d67ca89SAndroid Build Coastguard Worker return 0;
268*8d67ca89SAndroid Build Coastguard Worker }
269*8d67ca89SAndroid Build Coastguard Worker
get_verdef_cnt() const270*8d67ca89SAndroid Build Coastguard Worker size_t soinfo::get_verdef_cnt() const {
271*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(2)) {
272*8d67ca89SAndroid Build Coastguard Worker return verdef_cnt_;
273*8d67ca89SAndroid Build Coastguard Worker }
274*8d67ca89SAndroid Build Coastguard Worker
275*8d67ca89SAndroid Build Coastguard Worker return 0;
276*8d67ca89SAndroid Build Coastguard Worker }
277*8d67ca89SAndroid Build Coastguard Worker
get_lookup_lib()278*8d67ca89SAndroid Build Coastguard Worker SymbolLookupLib soinfo::get_lookup_lib() {
279*8d67ca89SAndroid Build Coastguard Worker SymbolLookupLib result {};
280*8d67ca89SAndroid Build Coastguard Worker result.si_ = this;
281*8d67ca89SAndroid Build Coastguard Worker
282*8d67ca89SAndroid Build Coastguard Worker // For libs that only have SysV hashes, leave the gnu_bloom_filter_ field NULL to signal that
283*8d67ca89SAndroid Build Coastguard Worker // the fallback code path is needed.
284*8d67ca89SAndroid Build Coastguard Worker if (!is_gnu_hash()) {
285*8d67ca89SAndroid Build Coastguard Worker return result;
286*8d67ca89SAndroid Build Coastguard Worker }
287*8d67ca89SAndroid Build Coastguard Worker
288*8d67ca89SAndroid Build Coastguard Worker result.gnu_maskwords_ = gnu_maskwords_;
289*8d67ca89SAndroid Build Coastguard Worker result.gnu_shift2_ = gnu_shift2_;
290*8d67ca89SAndroid Build Coastguard Worker result.gnu_bloom_filter_ = gnu_bloom_filter_;
291*8d67ca89SAndroid Build Coastguard Worker
292*8d67ca89SAndroid Build Coastguard Worker result.strtab_ = strtab_;
293*8d67ca89SAndroid Build Coastguard Worker result.strtab_size_ = strtab_size_;
294*8d67ca89SAndroid Build Coastguard Worker result.symtab_ = symtab_;
295*8d67ca89SAndroid Build Coastguard Worker result.versym_ = get_versym_table();
296*8d67ca89SAndroid Build Coastguard Worker
297*8d67ca89SAndroid Build Coastguard Worker result.gnu_chain_ = gnu_chain_;
298*8d67ca89SAndroid Build Coastguard Worker result.gnu_nbucket_ = gnu_nbucket_;
299*8d67ca89SAndroid Build Coastguard Worker result.gnu_bucket_ = gnu_bucket_;
300*8d67ca89SAndroid Build Coastguard Worker
301*8d67ca89SAndroid Build Coastguard Worker return result;
302*8d67ca89SAndroid Build Coastguard Worker }
303*8d67ca89SAndroid Build Coastguard Worker
ElfW(Sym)304*8d67ca89SAndroid Build Coastguard Worker const ElfW(Sym)* soinfo::find_symbol_by_name(SymbolName& symbol_name,
305*8d67ca89SAndroid Build Coastguard Worker const version_info* vi) const {
306*8d67ca89SAndroid Build Coastguard Worker return is_gnu_hash() ? gnu_lookup(symbol_name, vi) : elf_lookup(symbol_name, vi);
307*8d67ca89SAndroid Build Coastguard Worker }
308*8d67ca89SAndroid Build Coastguard Worker
ElfW(Addr)309*8d67ca89SAndroid Build Coastguard Worker ElfW(Addr) soinfo::apply_memtag_if_mte_globals(ElfW(Addr) sym_addr) const {
310*8d67ca89SAndroid Build Coastguard Worker if (!should_tag_memtag_globals()) return sym_addr;
311*8d67ca89SAndroid Build Coastguard Worker if (sym_addr == 0) return sym_addr; // Handle undefined weak symbols.
312*8d67ca89SAndroid Build Coastguard Worker return reinterpret_cast<ElfW(Addr)>(get_tagged_address(reinterpret_cast<void*>(sym_addr)));
313*8d67ca89SAndroid Build Coastguard Worker }
314*8d67ca89SAndroid Build Coastguard Worker
ElfW(Sym)315*8d67ca89SAndroid Build Coastguard Worker const ElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name, const version_info* vi) const {
316*8d67ca89SAndroid Build Coastguard Worker const uint32_t hash = symbol_name.gnu_hash();
317*8d67ca89SAndroid Build Coastguard Worker
318*8d67ca89SAndroid Build Coastguard Worker constexpr uint32_t kBloomMaskBits = sizeof(ElfW(Addr)) * 8;
319*8d67ca89SAndroid Build Coastguard Worker const uint32_t word_num = (hash / kBloomMaskBits) & gnu_maskwords_;
320*8d67ca89SAndroid Build Coastguard Worker const ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
321*8d67ca89SAndroid Build Coastguard Worker const uint32_t h1 = hash % kBloomMaskBits;
322*8d67ca89SAndroid Build Coastguard Worker const uint32_t h2 = (hash >> gnu_shift2_) % kBloomMaskBits;
323*8d67ca89SAndroid Build Coastguard Worker
324*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(lookup, "SEARCH %s in %s@%p (gnu)",
325*8d67ca89SAndroid Build Coastguard Worker symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
326*8d67ca89SAndroid Build Coastguard Worker
327*8d67ca89SAndroid Build Coastguard Worker // test against bloom filter
328*8d67ca89SAndroid Build Coastguard Worker if ((1 & (bloom_word >> h1) & (bloom_word >> h2)) == 0) {
329*8d67ca89SAndroid Build Coastguard Worker return nullptr;
330*8d67ca89SAndroid Build Coastguard Worker }
331*8d67ca89SAndroid Build Coastguard Worker
332*8d67ca89SAndroid Build Coastguard Worker // bloom test says "probably yes"...
333*8d67ca89SAndroid Build Coastguard Worker uint32_t n = gnu_bucket_[hash % gnu_nbucket_];
334*8d67ca89SAndroid Build Coastguard Worker
335*8d67ca89SAndroid Build Coastguard Worker if (n == 0) {
336*8d67ca89SAndroid Build Coastguard Worker return nullptr;
337*8d67ca89SAndroid Build Coastguard Worker }
338*8d67ca89SAndroid Build Coastguard Worker
339*8d67ca89SAndroid Build Coastguard Worker const ElfW(Versym) verneed = find_verdef_version_index(this, vi);
340*8d67ca89SAndroid Build Coastguard Worker const ElfW(Versym)* versym = get_versym_table();
341*8d67ca89SAndroid Build Coastguard Worker
342*8d67ca89SAndroid Build Coastguard Worker do {
343*8d67ca89SAndroid Build Coastguard Worker ElfW(Sym)* s = symtab_ + n;
344*8d67ca89SAndroid Build Coastguard Worker if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
345*8d67ca89SAndroid Build Coastguard Worker check_symbol_version(versym, n, verneed) &&
346*8d67ca89SAndroid Build Coastguard Worker strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
347*8d67ca89SAndroid Build Coastguard Worker is_symbol_global_and_defined(this, s)) {
348*8d67ca89SAndroid Build Coastguard Worker return symtab_ + n;
349*8d67ca89SAndroid Build Coastguard Worker }
350*8d67ca89SAndroid Build Coastguard Worker } while ((gnu_chain_[n++] & 1) == 0);
351*8d67ca89SAndroid Build Coastguard Worker
352*8d67ca89SAndroid Build Coastguard Worker return nullptr;
353*8d67ca89SAndroid Build Coastguard Worker }
354*8d67ca89SAndroid Build Coastguard Worker
ElfW(Sym)355*8d67ca89SAndroid Build Coastguard Worker const ElfW(Sym)* soinfo::elf_lookup(SymbolName& symbol_name, const version_info* vi) const {
356*8d67ca89SAndroid Build Coastguard Worker uint32_t hash = symbol_name.elf_hash();
357*8d67ca89SAndroid Build Coastguard Worker
358*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(lookup, "SEARCH %s in %s@%p h=%x(elf) %zd",
359*8d67ca89SAndroid Build Coastguard Worker symbol_name.get_name(), get_realpath(),
360*8d67ca89SAndroid Build Coastguard Worker reinterpret_cast<void*>(base), hash, hash % nbucket_);
361*8d67ca89SAndroid Build Coastguard Worker
362*8d67ca89SAndroid Build Coastguard Worker const ElfW(Versym) verneed = find_verdef_version_index(this, vi);
363*8d67ca89SAndroid Build Coastguard Worker const ElfW(Versym)* versym = get_versym_table();
364*8d67ca89SAndroid Build Coastguard Worker
365*8d67ca89SAndroid Build Coastguard Worker for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
366*8d67ca89SAndroid Build Coastguard Worker ElfW(Sym)* s = symtab_ + n;
367*8d67ca89SAndroid Build Coastguard Worker
368*8d67ca89SAndroid Build Coastguard Worker if (check_symbol_version(versym, n, verneed) &&
369*8d67ca89SAndroid Build Coastguard Worker strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
370*8d67ca89SAndroid Build Coastguard Worker is_symbol_global_and_defined(this, s)) {
371*8d67ca89SAndroid Build Coastguard Worker return symtab_ + n;
372*8d67ca89SAndroid Build Coastguard Worker }
373*8d67ca89SAndroid Build Coastguard Worker }
374*8d67ca89SAndroid Build Coastguard Worker
375*8d67ca89SAndroid Build Coastguard Worker return nullptr;
376*8d67ca89SAndroid Build Coastguard Worker }
377*8d67ca89SAndroid Build Coastguard Worker
ElfW(Sym)378*8d67ca89SAndroid Build Coastguard Worker ElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
379*8d67ca89SAndroid Build Coastguard Worker return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
380*8d67ca89SAndroid Build Coastguard Worker }
381*8d67ca89SAndroid Build Coastguard Worker
symbol_matches_soaddr(const ElfW (Sym)* sym,ElfW (Addr)soaddr)382*8d67ca89SAndroid Build Coastguard Worker static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
383*8d67ca89SAndroid Build Coastguard Worker // Skip TLS symbols. A TLS symbol's value is relative to the start of the TLS segment rather than
384*8d67ca89SAndroid Build Coastguard Worker // to the start of the solib. The solib only reserves space for the initialized part of the TLS
385*8d67ca89SAndroid Build Coastguard Worker // segment. (i.e. .tdata is followed by .tbss, and .tbss overlaps other sections.)
386*8d67ca89SAndroid Build Coastguard Worker return sym->st_shndx != SHN_UNDEF &&
387*8d67ca89SAndroid Build Coastguard Worker ELF_ST_TYPE(sym->st_info) != STT_TLS &&
388*8d67ca89SAndroid Build Coastguard Worker soaddr >= sym->st_value &&
389*8d67ca89SAndroid Build Coastguard Worker soaddr < sym->st_value + sym->st_size;
390*8d67ca89SAndroid Build Coastguard Worker }
391*8d67ca89SAndroid Build Coastguard Worker
ElfW(Sym)392*8d67ca89SAndroid Build Coastguard Worker ElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
393*8d67ca89SAndroid Build Coastguard Worker ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
394*8d67ca89SAndroid Build Coastguard Worker
395*8d67ca89SAndroid Build Coastguard Worker for (size_t i = 0; i < gnu_nbucket_; ++i) {
396*8d67ca89SAndroid Build Coastguard Worker uint32_t n = gnu_bucket_[i];
397*8d67ca89SAndroid Build Coastguard Worker
398*8d67ca89SAndroid Build Coastguard Worker if (n == 0) {
399*8d67ca89SAndroid Build Coastguard Worker continue;
400*8d67ca89SAndroid Build Coastguard Worker }
401*8d67ca89SAndroid Build Coastguard Worker
402*8d67ca89SAndroid Build Coastguard Worker do {
403*8d67ca89SAndroid Build Coastguard Worker ElfW(Sym)* sym = symtab_ + n;
404*8d67ca89SAndroid Build Coastguard Worker if (symbol_matches_soaddr(sym, soaddr)) {
405*8d67ca89SAndroid Build Coastguard Worker return sym;
406*8d67ca89SAndroid Build Coastguard Worker }
407*8d67ca89SAndroid Build Coastguard Worker } while ((gnu_chain_[n++] & 1) == 0);
408*8d67ca89SAndroid Build Coastguard Worker }
409*8d67ca89SAndroid Build Coastguard Worker
410*8d67ca89SAndroid Build Coastguard Worker return nullptr;
411*8d67ca89SAndroid Build Coastguard Worker }
412*8d67ca89SAndroid Build Coastguard Worker
ElfW(Sym)413*8d67ca89SAndroid Build Coastguard Worker ElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
414*8d67ca89SAndroid Build Coastguard Worker ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
415*8d67ca89SAndroid Build Coastguard Worker
416*8d67ca89SAndroid Build Coastguard Worker // Search the library's symbol table for any defined symbol which
417*8d67ca89SAndroid Build Coastguard Worker // contains this address.
418*8d67ca89SAndroid Build Coastguard Worker for (size_t i = 0; i < nchain_; ++i) {
419*8d67ca89SAndroid Build Coastguard Worker ElfW(Sym)* sym = symtab_ + i;
420*8d67ca89SAndroid Build Coastguard Worker if (symbol_matches_soaddr(sym, soaddr)) {
421*8d67ca89SAndroid Build Coastguard Worker return sym;
422*8d67ca89SAndroid Build Coastguard Worker }
423*8d67ca89SAndroid Build Coastguard Worker }
424*8d67ca89SAndroid Build Coastguard Worker
425*8d67ca89SAndroid Build Coastguard Worker return nullptr;
426*8d67ca89SAndroid Build Coastguard Worker }
427*8d67ca89SAndroid Build Coastguard Worker
call_function(const char * function_name __unused,linker_ctor_function_t function,const char * realpath __unused)428*8d67ca89SAndroid Build Coastguard Worker static void call_function(const char* function_name __unused,
429*8d67ca89SAndroid Build Coastguard Worker linker_ctor_function_t function,
430*8d67ca89SAndroid Build Coastguard Worker const char* realpath __unused) {
431*8d67ca89SAndroid Build Coastguard Worker if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
432*8d67ca89SAndroid Build Coastguard Worker return;
433*8d67ca89SAndroid Build Coastguard Worker }
434*8d67ca89SAndroid Build Coastguard Worker
435*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(calls, "[ Calling c-tor %s @ %p for '%s' ]", function_name, function, realpath);
436*8d67ca89SAndroid Build Coastguard Worker function(g_argc, g_argv, g_envp);
437*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(calls, "[ Done calling c-tor %s @ %p for '%s' ]", function_name, function, realpath);
438*8d67ca89SAndroid Build Coastguard Worker }
439*8d67ca89SAndroid Build Coastguard Worker
call_function(const char * function_name __unused,linker_dtor_function_t function,const char * realpath __unused)440*8d67ca89SAndroid Build Coastguard Worker static void call_function(const char* function_name __unused,
441*8d67ca89SAndroid Build Coastguard Worker linker_dtor_function_t function,
442*8d67ca89SAndroid Build Coastguard Worker const char* realpath __unused) {
443*8d67ca89SAndroid Build Coastguard Worker if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
444*8d67ca89SAndroid Build Coastguard Worker return;
445*8d67ca89SAndroid Build Coastguard Worker }
446*8d67ca89SAndroid Build Coastguard Worker
447*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(calls, "[ Calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
448*8d67ca89SAndroid Build Coastguard Worker function();
449*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(calls, "[ Done calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
450*8d67ca89SAndroid Build Coastguard Worker }
451*8d67ca89SAndroid Build Coastguard Worker
452*8d67ca89SAndroid Build Coastguard Worker template <typename F>
call_array(const char * array_name __unused,F * functions,size_t count,bool reverse,const char * realpath)453*8d67ca89SAndroid Build Coastguard Worker static inline void call_array(const char* array_name __unused, F* functions, size_t count,
454*8d67ca89SAndroid Build Coastguard Worker bool reverse, const char* realpath) {
455*8d67ca89SAndroid Build Coastguard Worker if (functions == nullptr) {
456*8d67ca89SAndroid Build Coastguard Worker return;
457*8d67ca89SAndroid Build Coastguard Worker }
458*8d67ca89SAndroid Build Coastguard Worker
459*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(calls, "[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, realpath);
460*8d67ca89SAndroid Build Coastguard Worker
461*8d67ca89SAndroid Build Coastguard Worker int begin = reverse ? (count - 1) : 0;
462*8d67ca89SAndroid Build Coastguard Worker int end = reverse ? -1 : count;
463*8d67ca89SAndroid Build Coastguard Worker int step = reverse ? -1 : 1;
464*8d67ca89SAndroid Build Coastguard Worker
465*8d67ca89SAndroid Build Coastguard Worker for (int i = begin; i != end; i += step) {
466*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(calls, "[ %s[%d] == %p ]", array_name, i, functions[i]);
467*8d67ca89SAndroid Build Coastguard Worker call_function("function", functions[i], realpath);
468*8d67ca89SAndroid Build Coastguard Worker }
469*8d67ca89SAndroid Build Coastguard Worker
470*8d67ca89SAndroid Build Coastguard Worker LD_DEBUG(calls, "[ Done calling %s for '%s' ]", array_name, realpath);
471*8d67ca89SAndroid Build Coastguard Worker }
472*8d67ca89SAndroid Build Coastguard Worker
call_pre_init_constructors()473*8d67ca89SAndroid Build Coastguard Worker void soinfo::call_pre_init_constructors() {
474*8d67ca89SAndroid Build Coastguard Worker // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
475*8d67ca89SAndroid Build Coastguard Worker // but ignored in a shared library.
476*8d67ca89SAndroid Build Coastguard Worker call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false, get_realpath());
477*8d67ca89SAndroid Build Coastguard Worker }
478*8d67ca89SAndroid Build Coastguard Worker
call_constructors()479*8d67ca89SAndroid Build Coastguard Worker void soinfo::call_constructors() {
480*8d67ca89SAndroid Build Coastguard Worker if (constructors_called) {
481*8d67ca89SAndroid Build Coastguard Worker return;
482*8d67ca89SAndroid Build Coastguard Worker }
483*8d67ca89SAndroid Build Coastguard Worker
484*8d67ca89SAndroid Build Coastguard Worker // We set constructors_called before actually calling the constructors, otherwise it doesn't
485*8d67ca89SAndroid Build Coastguard Worker // protect against recursive constructor calls. One simple example of constructor recursion
486*8d67ca89SAndroid Build Coastguard Worker // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
487*8d67ca89SAndroid Build Coastguard Worker // 1. The program depends on libc, so libc's constructor is called here.
488*8d67ca89SAndroid Build Coastguard Worker // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
489*8d67ca89SAndroid Build Coastguard Worker // 3. dlopen() calls the constructors on the newly created
490*8d67ca89SAndroid Build Coastguard Worker // soinfo for libc_malloc_debug_leak.so.
491*8d67ca89SAndroid Build Coastguard Worker // 4. The debug .so depends on libc, so CallConstructors is
492*8d67ca89SAndroid Build Coastguard Worker // called again with the libc soinfo. If it doesn't trigger the early-
493*8d67ca89SAndroid Build Coastguard Worker // out above, the libc constructor will be called again (recursively!).
494*8d67ca89SAndroid Build Coastguard Worker constructors_called = true;
495*8d67ca89SAndroid Build Coastguard Worker
496*8d67ca89SAndroid Build Coastguard Worker if (!is_main_executable() && preinit_array_ != nullptr) {
497*8d67ca89SAndroid Build Coastguard Worker // The GNU dynamic linker silently ignores these, but we warn the developer.
498*8d67ca89SAndroid Build Coastguard Worker DL_WARN("\"%s\": ignoring DT_PREINIT_ARRAY in shared library!", get_realpath());
499*8d67ca89SAndroid Build Coastguard Worker }
500*8d67ca89SAndroid Build Coastguard Worker
501*8d67ca89SAndroid Build Coastguard Worker get_children().for_each([] (soinfo* si) {
502*8d67ca89SAndroid Build Coastguard Worker si->call_constructors();
503*8d67ca89SAndroid Build Coastguard Worker });
504*8d67ca89SAndroid Build Coastguard Worker
505*8d67ca89SAndroid Build Coastguard Worker if (!is_linker()) {
506*8d67ca89SAndroid Build Coastguard Worker bionic_trace_begin((std::string("calling constructors: ") + get_realpath()).c_str());
507*8d67ca89SAndroid Build Coastguard Worker }
508*8d67ca89SAndroid Build Coastguard Worker
509*8d67ca89SAndroid Build Coastguard Worker // DT_INIT should be called before DT_INIT_ARRAY if both are present.
510*8d67ca89SAndroid Build Coastguard Worker call_function("DT_INIT", init_func_, get_realpath());
511*8d67ca89SAndroid Build Coastguard Worker call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false, get_realpath());
512*8d67ca89SAndroid Build Coastguard Worker
513*8d67ca89SAndroid Build Coastguard Worker if (!is_linker()) {
514*8d67ca89SAndroid Build Coastguard Worker bionic_trace_end();
515*8d67ca89SAndroid Build Coastguard Worker }
516*8d67ca89SAndroid Build Coastguard Worker }
517*8d67ca89SAndroid Build Coastguard Worker
call_destructors()518*8d67ca89SAndroid Build Coastguard Worker void soinfo::call_destructors() {
519*8d67ca89SAndroid Build Coastguard Worker if (!constructors_called) {
520*8d67ca89SAndroid Build Coastguard Worker return;
521*8d67ca89SAndroid Build Coastguard Worker }
522*8d67ca89SAndroid Build Coastguard Worker
523*8d67ca89SAndroid Build Coastguard Worker ScopedTrace trace((std::string("calling destructors: ") + get_realpath()).c_str());
524*8d67ca89SAndroid Build Coastguard Worker
525*8d67ca89SAndroid Build Coastguard Worker // DT_FINI_ARRAY must be parsed in reverse order.
526*8d67ca89SAndroid Build Coastguard Worker call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true, get_realpath());
527*8d67ca89SAndroid Build Coastguard Worker
528*8d67ca89SAndroid Build Coastguard Worker // DT_FINI should be called after DT_FINI_ARRAY if both are present.
529*8d67ca89SAndroid Build Coastguard Worker call_function("DT_FINI", fini_func_, get_realpath());
530*8d67ca89SAndroid Build Coastguard Worker }
531*8d67ca89SAndroid Build Coastguard Worker
add_child(soinfo * child)532*8d67ca89SAndroid Build Coastguard Worker void soinfo::add_child(soinfo* child) {
533*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(0)) {
534*8d67ca89SAndroid Build Coastguard Worker child->parents_.push_back(this);
535*8d67ca89SAndroid Build Coastguard Worker this->children_.push_back(child);
536*8d67ca89SAndroid Build Coastguard Worker }
537*8d67ca89SAndroid Build Coastguard Worker }
538*8d67ca89SAndroid Build Coastguard Worker
remove_all_links()539*8d67ca89SAndroid Build Coastguard Worker void soinfo::remove_all_links() {
540*8d67ca89SAndroid Build Coastguard Worker if (!has_min_version(0)) {
541*8d67ca89SAndroid Build Coastguard Worker return;
542*8d67ca89SAndroid Build Coastguard Worker }
543*8d67ca89SAndroid Build Coastguard Worker
544*8d67ca89SAndroid Build Coastguard Worker // 1. Untie connected soinfos from 'this'.
545*8d67ca89SAndroid Build Coastguard Worker children_.for_each([&] (soinfo* child) {
546*8d67ca89SAndroid Build Coastguard Worker child->parents_.remove_if([&] (const soinfo* parent) {
547*8d67ca89SAndroid Build Coastguard Worker return parent == this;
548*8d67ca89SAndroid Build Coastguard Worker });
549*8d67ca89SAndroid Build Coastguard Worker });
550*8d67ca89SAndroid Build Coastguard Worker
551*8d67ca89SAndroid Build Coastguard Worker parents_.for_each([&] (soinfo* parent) {
552*8d67ca89SAndroid Build Coastguard Worker parent->children_.remove_if([&] (const soinfo* child) {
553*8d67ca89SAndroid Build Coastguard Worker return child == this;
554*8d67ca89SAndroid Build Coastguard Worker });
555*8d67ca89SAndroid Build Coastguard Worker });
556*8d67ca89SAndroid Build Coastguard Worker
557*8d67ca89SAndroid Build Coastguard Worker // 2. Remove from the primary namespace
558*8d67ca89SAndroid Build Coastguard Worker primary_namespace_->remove_soinfo(this);
559*8d67ca89SAndroid Build Coastguard Worker primary_namespace_ = nullptr;
560*8d67ca89SAndroid Build Coastguard Worker
561*8d67ca89SAndroid Build Coastguard Worker // 3. Remove from secondary namespaces
562*8d67ca89SAndroid Build Coastguard Worker secondary_namespaces_.for_each([&](android_namespace_t* ns) {
563*8d67ca89SAndroid Build Coastguard Worker ns->remove_soinfo(this);
564*8d67ca89SAndroid Build Coastguard Worker });
565*8d67ca89SAndroid Build Coastguard Worker
566*8d67ca89SAndroid Build Coastguard Worker
567*8d67ca89SAndroid Build Coastguard Worker // 4. Once everything untied - clear local lists.
568*8d67ca89SAndroid Build Coastguard Worker parents_.clear();
569*8d67ca89SAndroid Build Coastguard Worker children_.clear();
570*8d67ca89SAndroid Build Coastguard Worker secondary_namespaces_.clear();
571*8d67ca89SAndroid Build Coastguard Worker }
572*8d67ca89SAndroid Build Coastguard Worker
get_st_dev() const573*8d67ca89SAndroid Build Coastguard Worker dev_t soinfo::get_st_dev() const {
574*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(0)) {
575*8d67ca89SAndroid Build Coastguard Worker return st_dev_;
576*8d67ca89SAndroid Build Coastguard Worker }
577*8d67ca89SAndroid Build Coastguard Worker
578*8d67ca89SAndroid Build Coastguard Worker return 0;
579*8d67ca89SAndroid Build Coastguard Worker };
580*8d67ca89SAndroid Build Coastguard Worker
get_st_ino() const581*8d67ca89SAndroid Build Coastguard Worker ino_t soinfo::get_st_ino() const {
582*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(0)) {
583*8d67ca89SAndroid Build Coastguard Worker return st_ino_;
584*8d67ca89SAndroid Build Coastguard Worker }
585*8d67ca89SAndroid Build Coastguard Worker
586*8d67ca89SAndroid Build Coastguard Worker return 0;
587*8d67ca89SAndroid Build Coastguard Worker }
588*8d67ca89SAndroid Build Coastguard Worker
get_file_offset() const589*8d67ca89SAndroid Build Coastguard Worker off64_t soinfo::get_file_offset() const {
590*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(1)) {
591*8d67ca89SAndroid Build Coastguard Worker return file_offset_;
592*8d67ca89SAndroid Build Coastguard Worker }
593*8d67ca89SAndroid Build Coastguard Worker
594*8d67ca89SAndroid Build Coastguard Worker return 0;
595*8d67ca89SAndroid Build Coastguard Worker }
596*8d67ca89SAndroid Build Coastguard Worker
get_rtld_flags() const597*8d67ca89SAndroid Build Coastguard Worker uint32_t soinfo::get_rtld_flags() const {
598*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(1)) {
599*8d67ca89SAndroid Build Coastguard Worker return rtld_flags_;
600*8d67ca89SAndroid Build Coastguard Worker }
601*8d67ca89SAndroid Build Coastguard Worker
602*8d67ca89SAndroid Build Coastguard Worker return 0;
603*8d67ca89SAndroid Build Coastguard Worker }
604*8d67ca89SAndroid Build Coastguard Worker
get_dt_flags_1() const605*8d67ca89SAndroid Build Coastguard Worker uint32_t soinfo::get_dt_flags_1() const {
606*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(1)) {
607*8d67ca89SAndroid Build Coastguard Worker return dt_flags_1_;
608*8d67ca89SAndroid Build Coastguard Worker }
609*8d67ca89SAndroid Build Coastguard Worker
610*8d67ca89SAndroid Build Coastguard Worker return 0;
611*8d67ca89SAndroid Build Coastguard Worker }
612*8d67ca89SAndroid Build Coastguard Worker
set_dt_flags_1(uint32_t dt_flags_1)613*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
614*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(1)) {
615*8d67ca89SAndroid Build Coastguard Worker if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
616*8d67ca89SAndroid Build Coastguard Worker rtld_flags_ |= RTLD_GLOBAL;
617*8d67ca89SAndroid Build Coastguard Worker }
618*8d67ca89SAndroid Build Coastguard Worker
619*8d67ca89SAndroid Build Coastguard Worker if ((dt_flags_1 & DF_1_NODELETE) != 0) {
620*8d67ca89SAndroid Build Coastguard Worker rtld_flags_ |= RTLD_NODELETE;
621*8d67ca89SAndroid Build Coastguard Worker }
622*8d67ca89SAndroid Build Coastguard Worker
623*8d67ca89SAndroid Build Coastguard Worker dt_flags_1_ = dt_flags_1;
624*8d67ca89SAndroid Build Coastguard Worker }
625*8d67ca89SAndroid Build Coastguard Worker }
626*8d67ca89SAndroid Build Coastguard Worker
set_nodelete()627*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_nodelete() {
628*8d67ca89SAndroid Build Coastguard Worker rtld_flags_ |= RTLD_NODELETE;
629*8d67ca89SAndroid Build Coastguard Worker }
630*8d67ca89SAndroid Build Coastguard Worker
set_realpath(const char * path)631*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_realpath(const char* path) {
632*8d67ca89SAndroid Build Coastguard Worker #if defined(__work_around_b_24465209__)
633*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(2)) {
634*8d67ca89SAndroid Build Coastguard Worker realpath_ = path;
635*8d67ca89SAndroid Build Coastguard Worker }
636*8d67ca89SAndroid Build Coastguard Worker #else
637*8d67ca89SAndroid Build Coastguard Worker realpath_ = path;
638*8d67ca89SAndroid Build Coastguard Worker #endif
639*8d67ca89SAndroid Build Coastguard Worker }
640*8d67ca89SAndroid Build Coastguard Worker
get_realpath() const641*8d67ca89SAndroid Build Coastguard Worker const char* soinfo::get_realpath() const {
642*8d67ca89SAndroid Build Coastguard Worker #if defined(__work_around_b_24465209__)
643*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(2)) {
644*8d67ca89SAndroid Build Coastguard Worker return realpath_.c_str();
645*8d67ca89SAndroid Build Coastguard Worker } else {
646*8d67ca89SAndroid Build Coastguard Worker return old_name_;
647*8d67ca89SAndroid Build Coastguard Worker }
648*8d67ca89SAndroid Build Coastguard Worker #else
649*8d67ca89SAndroid Build Coastguard Worker return realpath_.c_str();
650*8d67ca89SAndroid Build Coastguard Worker #endif
651*8d67ca89SAndroid Build Coastguard Worker }
652*8d67ca89SAndroid Build Coastguard Worker
set_soname(const char * soname)653*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_soname(const char* soname) {
654*8d67ca89SAndroid Build Coastguard Worker #if defined(__work_around_b_24465209__)
655*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(2)) {
656*8d67ca89SAndroid Build Coastguard Worker soname_ = soname;
657*8d67ca89SAndroid Build Coastguard Worker }
658*8d67ca89SAndroid Build Coastguard Worker strlcpy(old_name_, soname_.c_str(), sizeof(old_name_));
659*8d67ca89SAndroid Build Coastguard Worker #else
660*8d67ca89SAndroid Build Coastguard Worker soname_ = soname;
661*8d67ca89SAndroid Build Coastguard Worker #endif
662*8d67ca89SAndroid Build Coastguard Worker }
663*8d67ca89SAndroid Build Coastguard Worker
get_soname() const664*8d67ca89SAndroid Build Coastguard Worker const char* soinfo::get_soname() const {
665*8d67ca89SAndroid Build Coastguard Worker #if defined(__work_around_b_24465209__)
666*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(2)) {
667*8d67ca89SAndroid Build Coastguard Worker return soname_.c_str();
668*8d67ca89SAndroid Build Coastguard Worker } else {
669*8d67ca89SAndroid Build Coastguard Worker return old_name_;
670*8d67ca89SAndroid Build Coastguard Worker }
671*8d67ca89SAndroid Build Coastguard Worker #else
672*8d67ca89SAndroid Build Coastguard Worker return soname_.c_str();
673*8d67ca89SAndroid Build Coastguard Worker #endif
674*8d67ca89SAndroid Build Coastguard Worker }
675*8d67ca89SAndroid Build Coastguard Worker
676*8d67ca89SAndroid Build Coastguard Worker // This is a return on get_children()/get_parents() if
677*8d67ca89SAndroid Build Coastguard Worker // 'this->flags' does not have FLAG_NEW_SOINFO set.
678*8d67ca89SAndroid Build Coastguard Worker static soinfo_list_t g_empty_list;
679*8d67ca89SAndroid Build Coastguard Worker
get_children()680*8d67ca89SAndroid Build Coastguard Worker soinfo_list_t& soinfo::get_children() {
681*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(0)) {
682*8d67ca89SAndroid Build Coastguard Worker return children_;
683*8d67ca89SAndroid Build Coastguard Worker }
684*8d67ca89SAndroid Build Coastguard Worker
685*8d67ca89SAndroid Build Coastguard Worker return g_empty_list;
686*8d67ca89SAndroid Build Coastguard Worker }
687*8d67ca89SAndroid Build Coastguard Worker
get_children() const688*8d67ca89SAndroid Build Coastguard Worker const soinfo_list_t& soinfo::get_children() const {
689*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(0)) {
690*8d67ca89SAndroid Build Coastguard Worker return children_;
691*8d67ca89SAndroid Build Coastguard Worker }
692*8d67ca89SAndroid Build Coastguard Worker
693*8d67ca89SAndroid Build Coastguard Worker return g_empty_list;
694*8d67ca89SAndroid Build Coastguard Worker }
695*8d67ca89SAndroid Build Coastguard Worker
get_parents()696*8d67ca89SAndroid Build Coastguard Worker soinfo_list_t& soinfo::get_parents() {
697*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(0)) {
698*8d67ca89SAndroid Build Coastguard Worker return parents_;
699*8d67ca89SAndroid Build Coastguard Worker }
700*8d67ca89SAndroid Build Coastguard Worker
701*8d67ca89SAndroid Build Coastguard Worker return g_empty_list;
702*8d67ca89SAndroid Build Coastguard Worker }
703*8d67ca89SAndroid Build Coastguard Worker
704*8d67ca89SAndroid Build Coastguard Worker static std::vector<std::string> g_empty_runpath;
705*8d67ca89SAndroid Build Coastguard Worker
get_dt_runpath() const706*8d67ca89SAndroid Build Coastguard Worker const std::vector<std::string>& soinfo::get_dt_runpath() const {
707*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(3)) {
708*8d67ca89SAndroid Build Coastguard Worker return dt_runpath_;
709*8d67ca89SAndroid Build Coastguard Worker }
710*8d67ca89SAndroid Build Coastguard Worker
711*8d67ca89SAndroid Build Coastguard Worker return g_empty_runpath;
712*8d67ca89SAndroid Build Coastguard Worker }
713*8d67ca89SAndroid Build Coastguard Worker
get_primary_namespace()714*8d67ca89SAndroid Build Coastguard Worker android_namespace_t* soinfo::get_primary_namespace() {
715*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(3)) {
716*8d67ca89SAndroid Build Coastguard Worker return primary_namespace_;
717*8d67ca89SAndroid Build Coastguard Worker }
718*8d67ca89SAndroid Build Coastguard Worker
719*8d67ca89SAndroid Build Coastguard Worker return &g_default_namespace;
720*8d67ca89SAndroid Build Coastguard Worker }
721*8d67ca89SAndroid Build Coastguard Worker
add_secondary_namespace(android_namespace_t * secondary_ns)722*8d67ca89SAndroid Build Coastguard Worker void soinfo::add_secondary_namespace(android_namespace_t* secondary_ns) {
723*8d67ca89SAndroid Build Coastguard Worker CHECK(has_min_version(3));
724*8d67ca89SAndroid Build Coastguard Worker secondary_namespaces_.push_back(secondary_ns);
725*8d67ca89SAndroid Build Coastguard Worker }
726*8d67ca89SAndroid Build Coastguard Worker
get_secondary_namespaces()727*8d67ca89SAndroid Build Coastguard Worker android_namespace_list_t& soinfo::get_secondary_namespaces() {
728*8d67ca89SAndroid Build Coastguard Worker CHECK(has_min_version(3));
729*8d67ca89SAndroid Build Coastguard Worker return secondary_namespaces_;
730*8d67ca89SAndroid Build Coastguard Worker }
731*8d67ca89SAndroid Build Coastguard Worker
get_string(ElfW (Word)index) const732*8d67ca89SAndroid Build Coastguard Worker const char* soinfo::get_string(ElfW(Word) index) const {
733*8d67ca89SAndroid Build Coastguard Worker if (has_min_version(1) && (index >= strtab_size_)) {
734*8d67ca89SAndroid Build Coastguard Worker async_safe_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
735*8d67ca89SAndroid Build Coastguard Worker get_realpath(), strtab_size_, index);
736*8d67ca89SAndroid Build Coastguard Worker }
737*8d67ca89SAndroid Build Coastguard Worker
738*8d67ca89SAndroid Build Coastguard Worker return strtab_ + index;
739*8d67ca89SAndroid Build Coastguard Worker }
740*8d67ca89SAndroid Build Coastguard Worker
is_gnu_hash() const741*8d67ca89SAndroid Build Coastguard Worker bool soinfo::is_gnu_hash() const {
742*8d67ca89SAndroid Build Coastguard Worker return (flags_ & FLAG_GNU_HASH) != 0;
743*8d67ca89SAndroid Build Coastguard Worker }
744*8d67ca89SAndroid Build Coastguard Worker
can_unload() const745*8d67ca89SAndroid Build Coastguard Worker bool soinfo::can_unload() const {
746*8d67ca89SAndroid Build Coastguard Worker return !is_linked() ||
747*8d67ca89SAndroid Build Coastguard Worker (
748*8d67ca89SAndroid Build Coastguard Worker (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0
749*8d67ca89SAndroid Build Coastguard Worker );
750*8d67ca89SAndroid Build Coastguard Worker }
751*8d67ca89SAndroid Build Coastguard Worker
is_linked() const752*8d67ca89SAndroid Build Coastguard Worker bool soinfo::is_linked() const {
753*8d67ca89SAndroid Build Coastguard Worker return (flags_ & FLAG_LINKED) != 0;
754*8d67ca89SAndroid Build Coastguard Worker }
755*8d67ca89SAndroid Build Coastguard Worker
is_image_linked() const756*8d67ca89SAndroid Build Coastguard Worker bool soinfo::is_image_linked() const {
757*8d67ca89SAndroid Build Coastguard Worker return (flags_ & FLAG_IMAGE_LINKED) != 0;
758*8d67ca89SAndroid Build Coastguard Worker }
759*8d67ca89SAndroid Build Coastguard Worker
is_main_executable() const760*8d67ca89SAndroid Build Coastguard Worker bool soinfo::is_main_executable() const {
761*8d67ca89SAndroid Build Coastguard Worker return (flags_ & FLAG_EXE) != 0;
762*8d67ca89SAndroid Build Coastguard Worker }
763*8d67ca89SAndroid Build Coastguard Worker
is_linker() const764*8d67ca89SAndroid Build Coastguard Worker bool soinfo::is_linker() const {
765*8d67ca89SAndroid Build Coastguard Worker return (flags_ & FLAG_LINKER) != 0;
766*8d67ca89SAndroid Build Coastguard Worker }
767*8d67ca89SAndroid Build Coastguard Worker
set_linked()768*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_linked() {
769*8d67ca89SAndroid Build Coastguard Worker flags_ |= FLAG_LINKED;
770*8d67ca89SAndroid Build Coastguard Worker }
771*8d67ca89SAndroid Build Coastguard Worker
set_image_linked()772*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_image_linked() {
773*8d67ca89SAndroid Build Coastguard Worker flags_ |= FLAG_IMAGE_LINKED;
774*8d67ca89SAndroid Build Coastguard Worker }
775*8d67ca89SAndroid Build Coastguard Worker
set_linker_flag()776*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_linker_flag() {
777*8d67ca89SAndroid Build Coastguard Worker flags_ |= FLAG_LINKER;
778*8d67ca89SAndroid Build Coastguard Worker }
779*8d67ca89SAndroid Build Coastguard Worker
set_main_executable()780*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_main_executable() {
781*8d67ca89SAndroid Build Coastguard Worker flags_ |= FLAG_EXE;
782*8d67ca89SAndroid Build Coastguard Worker }
783*8d67ca89SAndroid Build Coastguard Worker
increment_ref_count()784*8d67ca89SAndroid Build Coastguard Worker size_t soinfo::increment_ref_count() {
785*8d67ca89SAndroid Build Coastguard Worker return ++local_group_root_->ref_count_;
786*8d67ca89SAndroid Build Coastguard Worker }
787*8d67ca89SAndroid Build Coastguard Worker
decrement_ref_count()788*8d67ca89SAndroid Build Coastguard Worker size_t soinfo::decrement_ref_count() {
789*8d67ca89SAndroid Build Coastguard Worker return --local_group_root_->ref_count_;
790*8d67ca89SAndroid Build Coastguard Worker }
791*8d67ca89SAndroid Build Coastguard Worker
get_ref_count() const792*8d67ca89SAndroid Build Coastguard Worker size_t soinfo::get_ref_count() const {
793*8d67ca89SAndroid Build Coastguard Worker return local_group_root_->ref_count_;
794*8d67ca89SAndroid Build Coastguard Worker }
795*8d67ca89SAndroid Build Coastguard Worker
get_local_group_root() const796*8d67ca89SAndroid Build Coastguard Worker soinfo* soinfo::get_local_group_root() const {
797*8d67ca89SAndroid Build Coastguard Worker return local_group_root_;
798*8d67ca89SAndroid Build Coastguard Worker }
799*8d67ca89SAndroid Build Coastguard Worker
set_mapped_by_caller(bool mapped_by_caller)800*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_mapped_by_caller(bool mapped_by_caller) {
801*8d67ca89SAndroid Build Coastguard Worker if (mapped_by_caller) {
802*8d67ca89SAndroid Build Coastguard Worker flags_ |= FLAG_MAPPED_BY_CALLER;
803*8d67ca89SAndroid Build Coastguard Worker } else {
804*8d67ca89SAndroid Build Coastguard Worker flags_ &= ~FLAG_MAPPED_BY_CALLER;
805*8d67ca89SAndroid Build Coastguard Worker }
806*8d67ca89SAndroid Build Coastguard Worker }
807*8d67ca89SAndroid Build Coastguard Worker
is_mapped_by_caller() const808*8d67ca89SAndroid Build Coastguard Worker bool soinfo::is_mapped_by_caller() const {
809*8d67ca89SAndroid Build Coastguard Worker return (flags_ & FLAG_MAPPED_BY_CALLER) != 0;
810*8d67ca89SAndroid Build Coastguard Worker }
811*8d67ca89SAndroid Build Coastguard Worker
812*8d67ca89SAndroid Build Coastguard Worker // This function returns api-level at the time of
813*8d67ca89SAndroid Build Coastguard Worker // dlopen/load. Note that libraries opened by system
814*8d67ca89SAndroid Build Coastguard Worker // will always have 'current' api level.
get_target_sdk_version() const815*8d67ca89SAndroid Build Coastguard Worker int soinfo::get_target_sdk_version() const {
816*8d67ca89SAndroid Build Coastguard Worker if (!has_min_version(2)) {
817*8d67ca89SAndroid Build Coastguard Worker return __ANDROID_API__;
818*8d67ca89SAndroid Build Coastguard Worker }
819*8d67ca89SAndroid Build Coastguard Worker
820*8d67ca89SAndroid Build Coastguard Worker return local_group_root_->target_sdk_version_;
821*8d67ca89SAndroid Build Coastguard Worker }
822*8d67ca89SAndroid Build Coastguard Worker
get_handle() const823*8d67ca89SAndroid Build Coastguard Worker uintptr_t soinfo::get_handle() const {
824*8d67ca89SAndroid Build Coastguard Worker CHECK(has_min_version(3));
825*8d67ca89SAndroid Build Coastguard Worker CHECK(handle_ != 0);
826*8d67ca89SAndroid Build Coastguard Worker return handle_;
827*8d67ca89SAndroid Build Coastguard Worker }
828*8d67ca89SAndroid Build Coastguard Worker
to_handle()829*8d67ca89SAndroid Build Coastguard Worker void* soinfo::to_handle() {
830*8d67ca89SAndroid Build Coastguard Worker if (get_application_target_sdk_version() < 24 || !has_min_version(3)) {
831*8d67ca89SAndroid Build Coastguard Worker return this;
832*8d67ca89SAndroid Build Coastguard Worker }
833*8d67ca89SAndroid Build Coastguard Worker
834*8d67ca89SAndroid Build Coastguard Worker return reinterpret_cast<void*>(get_handle());
835*8d67ca89SAndroid Build Coastguard Worker }
836*8d67ca89SAndroid Build Coastguard Worker
generate_handle()837*8d67ca89SAndroid Build Coastguard Worker void soinfo::generate_handle() {
838*8d67ca89SAndroid Build Coastguard Worker CHECK(has_min_version(3));
839*8d67ca89SAndroid Build Coastguard Worker CHECK(handle_ == 0); // Make sure this is the first call
840*8d67ca89SAndroid Build Coastguard Worker
841*8d67ca89SAndroid Build Coastguard Worker // Make sure the handle is unique and does not collide
842*8d67ca89SAndroid Build Coastguard Worker // with special values which are RTLD_DEFAULT and RTLD_NEXT.
843*8d67ca89SAndroid Build Coastguard Worker do {
844*8d67ca89SAndroid Build Coastguard Worker if (!is_first_stage_init()) {
845*8d67ca89SAndroid Build Coastguard Worker arc4random_buf(&handle_, sizeof(handle_));
846*8d67ca89SAndroid Build Coastguard Worker } else {
847*8d67ca89SAndroid Build Coastguard Worker // arc4random* is not available in init because /dev/urandom hasn't yet been
848*8d67ca89SAndroid Build Coastguard Worker // created. So, when running with init, use the monotonically increasing
849*8d67ca89SAndroid Build Coastguard Worker // numbers as handles
850*8d67ca89SAndroid Build Coastguard Worker handle_ += 2;
851*8d67ca89SAndroid Build Coastguard Worker }
852*8d67ca89SAndroid Build Coastguard Worker // the least significant bit for the handle is always 1
853*8d67ca89SAndroid Build Coastguard Worker // making it easy to test the type of handle passed to
854*8d67ca89SAndroid Build Coastguard Worker // dl* functions.
855*8d67ca89SAndroid Build Coastguard Worker handle_ = handle_ | 1;
856*8d67ca89SAndroid Build Coastguard Worker } while (handle_ == reinterpret_cast<uintptr_t>(RTLD_DEFAULT) ||
857*8d67ca89SAndroid Build Coastguard Worker handle_ == reinterpret_cast<uintptr_t>(RTLD_NEXT) ||
858*8d67ca89SAndroid Build Coastguard Worker g_soinfo_handles_map.contains(handle_));
859*8d67ca89SAndroid Build Coastguard Worker
860*8d67ca89SAndroid Build Coastguard Worker g_soinfo_handles_map[handle_] = this;
861*8d67ca89SAndroid Build Coastguard Worker }
862*8d67ca89SAndroid Build Coastguard Worker
set_gap_start(ElfW (Addr)gap_start)863*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_gap_start(ElfW(Addr) gap_start) {
864*8d67ca89SAndroid Build Coastguard Worker CHECK(has_min_version(6));
865*8d67ca89SAndroid Build Coastguard Worker gap_start_ = gap_start;
866*8d67ca89SAndroid Build Coastguard Worker }
ElfW(Addr)867*8d67ca89SAndroid Build Coastguard Worker ElfW(Addr) soinfo::get_gap_start() const {
868*8d67ca89SAndroid Build Coastguard Worker CHECK(has_min_version(6));
869*8d67ca89SAndroid Build Coastguard Worker return gap_start_;
870*8d67ca89SAndroid Build Coastguard Worker }
871*8d67ca89SAndroid Build Coastguard Worker
set_gap_size(size_t gap_size)872*8d67ca89SAndroid Build Coastguard Worker void soinfo::set_gap_size(size_t gap_size) {
873*8d67ca89SAndroid Build Coastguard Worker CHECK(has_min_version(6));
874*8d67ca89SAndroid Build Coastguard Worker gap_size_ = gap_size;
875*8d67ca89SAndroid Build Coastguard Worker }
get_gap_size() const876*8d67ca89SAndroid Build Coastguard Worker size_t soinfo::get_gap_size() const {
877*8d67ca89SAndroid Build Coastguard Worker CHECK(has_min_version(6));
878*8d67ca89SAndroid Build Coastguard Worker return gap_size_;
879*8d67ca89SAndroid Build Coastguard Worker }
880*8d67ca89SAndroid Build Coastguard Worker
881*8d67ca89SAndroid Build Coastguard Worker // TODO(dimitry): Move SymbolName methods to a separate file.
882*8d67ca89SAndroid Build Coastguard Worker
calculate_elf_hash(const char * name)883*8d67ca89SAndroid Build Coastguard Worker uint32_t calculate_elf_hash(const char* name) {
884*8d67ca89SAndroid Build Coastguard Worker const uint8_t* name_bytes = reinterpret_cast<const uint8_t*>(name);
885*8d67ca89SAndroid Build Coastguard Worker uint32_t h = 0, g;
886*8d67ca89SAndroid Build Coastguard Worker
887*8d67ca89SAndroid Build Coastguard Worker while (*name_bytes) {
888*8d67ca89SAndroid Build Coastguard Worker h = (h << 4) + *name_bytes++;
889*8d67ca89SAndroid Build Coastguard Worker g = h & 0xf0000000;
890*8d67ca89SAndroid Build Coastguard Worker h ^= g;
891*8d67ca89SAndroid Build Coastguard Worker h ^= g >> 24;
892*8d67ca89SAndroid Build Coastguard Worker }
893*8d67ca89SAndroid Build Coastguard Worker
894*8d67ca89SAndroid Build Coastguard Worker return h;
895*8d67ca89SAndroid Build Coastguard Worker }
896*8d67ca89SAndroid Build Coastguard Worker
elf_hash()897*8d67ca89SAndroid Build Coastguard Worker uint32_t SymbolName::elf_hash() {
898*8d67ca89SAndroid Build Coastguard Worker if (!has_elf_hash_) {
899*8d67ca89SAndroid Build Coastguard Worker elf_hash_ = calculate_elf_hash(name_);
900*8d67ca89SAndroid Build Coastguard Worker has_elf_hash_ = true;
901*8d67ca89SAndroid Build Coastguard Worker }
902*8d67ca89SAndroid Build Coastguard Worker
903*8d67ca89SAndroid Build Coastguard Worker return elf_hash_;
904*8d67ca89SAndroid Build Coastguard Worker }
905*8d67ca89SAndroid Build Coastguard Worker
gnu_hash()906*8d67ca89SAndroid Build Coastguard Worker uint32_t SymbolName::gnu_hash() {
907*8d67ca89SAndroid Build Coastguard Worker if (!has_gnu_hash_) {
908*8d67ca89SAndroid Build Coastguard Worker gnu_hash_ = calculate_gnu_hash(name_).first;
909*8d67ca89SAndroid Build Coastguard Worker has_gnu_hash_ = true;
910*8d67ca89SAndroid Build Coastguard Worker }
911*8d67ca89SAndroid Build Coastguard Worker
912*8d67ca89SAndroid Build Coastguard Worker return gnu_hash_;
913*8d67ca89SAndroid Build Coastguard Worker }
914