11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 22a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov * Copyright (C) 2008 The Android Open Source Project 31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved. 41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without 61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions 71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met: 81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * * Redistributions of source code must retain the above copyright 91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * notice, this list of conditions and the following disclaimer. 101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * * Redistributions in binary form must reproduce the above copyright 111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * notice, this list of conditions and the following disclaimer in 121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the documentation and/or other materials provided with the 131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * distribution. 141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE. 271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 291913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov#include <android/api-level.h> 304688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <errno.h> 314688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <fcntl.h> 320266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#include <inttypes.h> 334688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <pthread.h> 341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h> 351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h> 361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h> 374688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <sys/mman.h> 38ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#include <sys/param.h> 394688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <unistd.h> 401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 410d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#include <new> 42d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <string> 43b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov#include <unordered_map> 44d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <vector> 450d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 464688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Private C library headers. 479ce09e423f24823d52f19ab8247e078977100132Mingwei Shi#include "private/bionic_globals.h" 48eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h" 49eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/KernelArgumentBlock.h" 50eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h" 5114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/ScopeGuard.h" 521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h" 54c9ce70d7838b6aae074fc3615cdf04e5c9ac612aDmitriy Ivanov#include "linker_block_allocator.h" 55ed70f6a2a03c3d172d3770039e65dc262d5b4075Dimitry Ivanov#include "linker_gdb_support.h" 561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h" 57df91dc2c192aa2789320c500037d28c919daa820Dimitry Ivanov#include "linker_dlwarning.h" 5818870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov#include "linker_sleb128.h" 5923363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h" 60cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#include "linker_relocs.h" 61fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#include "linker_reloc_iterators.h" 62a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov#include "linker_utils.h" 63b447440a4b5e1e300c6cb1a931b3fa1e22900c4ftony.ys_liu 64939a7e01197858fdb8463bb5a8284ba501a3e882Elliott Hughes#include "android-base/strings.h" 65aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin#include "ziparchive/zip_archive.h" 661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 6793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaoextern void __libc_init_globals(KernelArgumentBlock&); 681801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughesextern void __libc_init_AT_SECURE(KernelArgumentBlock&); 691801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes 709ce09e423f24823d52f19ab8247e078977100132Mingwei Shiextern "C" void _start(); 719ce09e423f24823d52f19ab8247e078977100132Mingwei Shi 721801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes// Override macros to use C++ style casts. 731649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#undef ELF_ST_TYPE 741649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf) 751649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov 7642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstruct android_namespace_t { 7742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov public: 7842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov android_namespace_t() : name_(nullptr), is_isolated_(false) {} 7942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 8042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const char* get_name() const { return name_; } 8142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov void set_name(const char* name) { name_ = name; } 8242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 8342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov bool is_isolated() const { return is_isolated_; } 8442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov void set_isolated(bool isolated) { is_isolated_ = isolated; } 8542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 8642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const std::vector<std::string>& get_ld_library_paths() const { 8742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return ld_library_paths_; 8842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 8942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov void set_ld_library_paths(std::vector<std::string>&& library_paths) { 9042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ld_library_paths_ = library_paths; 9142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 9242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 9342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const std::vector<std::string>& get_default_library_paths() const { 9442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return default_library_paths_; 9542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 9642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov void set_default_library_paths(std::vector<std::string>&& library_paths) { 9742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov default_library_paths_ = library_paths; 9842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 9942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 100350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov const std::vector<std::string>& get_permitted_paths() const { 101350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov return permitted_paths_; 102350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov } 103284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov void set_permitted_paths(std::vector<std::string>&& permitted_paths) { 104284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov permitted_paths_ = permitted_paths; 105284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov } 106284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov 107ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov void add_soinfo(soinfo* si) { 108ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov soinfo_list_.push_back(si); 109ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 110ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 111ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov void add_soinfos(const soinfo::soinfo_list_t& soinfos) { 112ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov for (auto si : soinfos) { 113ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov add_soinfo(si); 1140551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov si->add_secondary_namespace(this); 115ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 116ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 117ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 118ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov void remove_soinfo(soinfo* si) { 119ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov soinfo_list_.remove_if([&](soinfo* candidate) { 120ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return si == candidate; 121ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov }); 122ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 123ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 124ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov const soinfo::soinfo_list_t& soinfo_list() const { return soinfo_list_; } 12542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 12642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // For isolated namespaces - checks if the file is on the search path; 12742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // always returns true for not isolated namespace. 12842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov bool is_accessible(const std::string& path); 12942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 13042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov private: 13142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const char* name_; 13242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov bool is_isolated_; 13342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string> ld_library_paths_; 13442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string> default_library_paths_; 135284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov std::vector<std::string> permitted_paths_; 13642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo::soinfo_list_t soinfo_list_; 13742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 13842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov DISALLOW_COPY_AND_ASSIGN(android_namespace_t); 13942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov}; 14042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 14142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovandroid_namespace_t g_default_namespace; 14249cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov 143ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovstatic std::unordered_map<uintptr_t, soinfo*> g_soinfo_handles_map; 144ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovstatic android_namespace_t* g_anonymous_namespace = &g_default_namespace; 14542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 1460266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); 1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 148600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<soinfo> g_soinfo_allocator; 149600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator; 150ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn 15142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic LinkerTypeAllocator<android_namespace_t> g_namespace_allocator; 1520551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanovstatic LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator; 15342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 154d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist; 155d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext; 1566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info 1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1581728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = { 1594eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__) 160011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes "/system/lib64", 16188f5111123d9900fc4da05435aa8416a6f9f9bcdDimitry Ivanov "/vendor/lib64", 162011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else 163124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes "/system/lib", 16488f5111123d9900fc4da05435aa8416a6f9f9bcdDimitry Ivanov "/vendor/lib", 165011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif 166851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov nullptr 167124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes}; 168124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes 169d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanovstatic const char* const kAsanDefaultLdPaths[] = { 170d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov#if defined(__LP64__) 171d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov "/data/lib64", 172d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov "/system/lib64", 17388f5111123d9900fc4da05435aa8416a6f9f9bcdDimitry Ivanov "/data/vendor/lib64", 17488f5111123d9900fc4da05435aa8416a6f9f9bcdDimitry Ivanov "/vendor/lib64", 175d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov#else 176d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov "/data/lib", 177d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov "/system/lib", 17888f5111123d9900fc4da05435aa8416a6f9f9bcdDimitry Ivanov "/data/vendor/lib", 17988f5111123d9900fc4da05435aa8416a6f9f9bcdDimitry Ivanov "/vendor/lib", 180d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov#endif 181d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov nullptr 182d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov}; 183d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov 18436ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanovstatic bool is_system_library(const std::string& realpath) { 18536ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov for (const auto& dir : g_default_namespace.get_default_library_paths()) { 18636ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov if (file_is_in_dir(realpath, dir)) { 18736ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov return true; 18836ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov } 18936ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov } 19036ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov return false; 19136ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov} 19236ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov 193b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov#if defined(__LP64__) 194b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanovstatic const char* const kSystemLibDir = "/system/lib64"; 195b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov#else 196b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanovstatic const char* const kSystemLibDir = "/system/lib"; 197b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov#endif 198b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov 199b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanovstatic std::string dirname(const char *path); 200b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov 201f1d4a4959880eaf0f9c789c43c1bae383a605d9fDimitry Ivanov// TODO(dimitry): The grey-list is a workaround for http://b/26394120 --- 202f1d4a4959880eaf0f9c789c43c1bae383a605d9fDimitry Ivanov// gradually remove libraries from this list until it is gone. 20336ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanovstatic bool is_greylisted(const char* name, const soinfo* needed_by) { 204a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov static const char* const kLibraryGreyList[] = { 20536ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov "libandroid_runtime.so", 206a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov "libbinder.so", 207a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov "libcrypto.so", 208a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov "libcutils.so", 2095981d5beaf768fa5c65e89bafcba0f5462649d41Dimitry Ivanov "libexpat.so", 2108e3a3fb4f2b7b5183c00e299e9ab17fffced1124Dimitry Ivanov "libgui.so", 211a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov "libmedia.so", 212a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov "libnativehelper.so", 213a2a05016a0f2c8869c17a5dc616afa4b8247305cDimitry Ivanov "libskia.so", 214a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov "libssl.so", 215a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov "libstagefright.so", 21631e910c4070cdb014f2b312fefea2eae6c768906Dimitry Ivanov "libsqlite.so", 21778dfc4017de453f5a11ca86492d359931fdda997Dimitry Ivanov "libui.so", 218a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov "libutils.so", 21919b5e8cd5d5f6e8825ced4a7b37c87590fd244e6Dimitry Ivanov "libvorbisidec.so", 220a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov nullptr 221a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov }; 222a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov 223f1db47a1b36ead958a237117860c20997e8d1d16Dimitry Ivanov // limit greylisting to apps targeting sdk version 23 and below 224f1db47a1b36ead958a237117860c20997e8d1d16Dimitry Ivanov if (get_application_target_sdk_version() > 23) { 225f1db47a1b36ead958a237117860c20997e8d1d16Dimitry Ivanov return false; 226f1db47a1b36ead958a237117860c20997e8d1d16Dimitry Ivanov } 227f1db47a1b36ead958a237117860c20997e8d1d16Dimitry Ivanov 22836ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov // if the library needed by a system library - implicitly assume it 22936ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov // is greylisted 23036ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov 23136ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) { 23236ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov return true; 23336ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov } 23436ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov 235b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov // if this is an absolute path - make sure it points to /system/lib(64) 236b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov if (name[0] == '/' && dirname(name) == kSystemLibDir) { 237b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov // and reduce the path to basename 238b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov name = basename(name); 239b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov } 240b8e376906718fd4ea1ec7c9be258c99ec40900a9Dimitry Ivanov 241a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) { 242a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov if (strcmp(name, kLibraryGreyList[i]) == 0) { 243a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov return true; 244a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov } 245a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov } 246a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov 247a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov return false; 248a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov} 249a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov// END OF WORKAROUND 250a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov 2512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymNotNeeded = 0; 2522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymGlobal = 1; 2532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 254d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanovstatic const char* const* g_default_ld_paths; 255d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_preload_names; 256a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 257d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<soinfo*> g_ld_preloads; 2584fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 25942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic bool g_public_namespace_initialized; 26042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic soinfo::soinfo_list_t g_public_namespace; 26142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 2621728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity; 2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 264851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd. 2650d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 2666865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanovstatic std::string dirname(const char *path) { 2676865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov const char* last_slash = strrchr(path, '/'); 2686865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov if (last_slash == path) return "/"; 2696865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov else if (last_slash == nullptr) return "."; 2706865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov else 2716865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov return std::string(path, last_slash - path); 2726865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov} 2736865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov 2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 275bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t { 2766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int count[kRelocMax]; 277bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}; 278bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes 279bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats; 280bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes 281114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind kind) { 2826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++linker_stats.count[kind]; 283bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes} 284bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else 285114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind) { 286bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes} 2871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 290114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovuint32_t bitmask[4096]; 2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2932e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768]; 2942e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 295650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() { 2965419b9474753d25dff947c7740532f86d130c0beElliott Hughes return &__linker_dl_err_buf[0]; 2972e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin} 2982e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin 299650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() { 300650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes return sizeof(__linker_dl_err_buf); 301650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes} 302650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes 303bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) { 3049acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov if (info->is_linker() || info->is_main_executable()) { 3059acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov // gdb already knows about the linker and the main executable. 3066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 3076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 309ed70f6a2a03c3d172d3770039e65dc262d5b4075Dimitry Ivanov link_map* map = &(info->link_map_head); 3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 311ed70f6a2a03c3d172d3770039e65dc262d5b4075Dimitry Ivanov map->l_addr = info->load_bias; 312ed70f6a2a03c3d172d3770039e65dc262d5b4075Dimitry Ivanov // link_map l_name field is not const. 313ed70f6a2a03c3d172d3770039e65dc262d5b4075Dimitry Ivanov map->l_name = const_cast<char*>(info->get_realpath()); 314ed70f6a2a03c3d172d3770039e65dc262d5b4075Dimitry Ivanov map->l_ld = info->dynamic; 3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3169acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov CHECK(map->l_name != nullptr); 3179acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov CHECK(map->l_name[0] != '\0'); 3189acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov 319ed70f6a2a03c3d172d3770039e65dc262d5b4075Dimitry Ivanov notify_gdb_of_load(map); 3205e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev} 3215e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev 322bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) { 323ed70f6a2a03c3d172d3770039e65dc262d5b4075Dimitry Ivanov notify_gdb_of_unload(&(info->link_map_head)); 3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 32642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovbool android_namespace_t::is_accessible(const std::string& file) { 32742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (!is_isolated_) { 32842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return true; 32942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 33042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 33142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov for (const auto& dir : ld_library_paths_) { 33242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (file_is_in_dir(file, dir)) { 33342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return true; 33442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 33542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 33642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 33742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov for (const auto& dir : default_library_paths_) { 33842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (file_is_in_dir(file, dir)) { 33942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return true; 34042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 34142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 34242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 343284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov for (const auto& dir : permitted_paths_) { 344284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov if (file_is_under_dir(file, dir)) { 345284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov return true; 346284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov } 347284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov } 348284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov 34942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return false; 35042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov} 35142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 352d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() { 353d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return g_soinfo_links_allocator.alloc(); 354d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 355d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 356d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) { 357d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov g_soinfo_links_allocator.free(entry); 358d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 359d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3600551c1d47bad202ce6dd90757067bc0fd217497aDimitry IvanovLinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() { 3610551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov return g_namespace_list_allocator.alloc(); 3620551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov} 3630551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov 3640551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanovvoid NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) { 3650551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov g_namespace_list_allocator.free(entry); 3660551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov} 3670551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov 36842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic soinfo* soinfo_alloc(android_namespace_t* ns, const char* name, 36942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov struct stat* file_stat, off64_t file_offset, 37042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov uint32_t rtld_flags) { 371aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (strlen(name) >= PATH_MAX) { 372ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn DL_ERR("library name \"%s\" too long", name); 373851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 374ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn } 375ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn 37642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat, 37742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov file_offset, rtld_flags); 378d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 379ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn sonext->next = si; 380ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn sonext = si; 3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 382ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov si->generate_handle(); 383ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov ns->add_soinfo(si); 38442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 385ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("name %s: allocated soinfo @ %p", name, si); 386ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn return si; 3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 389faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) { 3906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 3916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 3926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3934688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 3946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->base != 0 && si->size != 0) { 395f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov if (!si->is_mapped_by_caller()) { 396f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov munmap(reinterpret_cast<void*>(si->base), si->size); 397f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov } else { 398f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE 399f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE, 400f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); 401f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov } 4026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 403d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 4046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov soinfo *prev = nullptr, *trav; 4051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4063edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si); 4071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (trav = solist; trav != nullptr; trav = trav->next) { 4096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (trav == si) { 4106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 4111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov prev = trav; 4136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 414ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 4156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (trav == nullptr) { 4166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // si was not in solist 4173edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si); 4186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return; 4196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 4201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // clear links to/from si 4226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->remove_all_links(); 423d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 4246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // prev will never be null, because the first entry in solist is 4256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // always the static libdl_info. 4266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov prev->next = si->next; 4276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == sonext) { 4286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov sonext = prev; 4296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 430d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov 431609f11b31ecedc4e9f2a1f6017b60b1f51b15c22Dmitriy Ivanov si->~soinfo(); 4326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g_soinfo_allocator.free(si); 4331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 43542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov// For every path element this function checks of it exists, and is a directory, 43642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov// and normalizes it: 43742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov// 1. For regular path it converts it to realpath() 43842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov// 2. For path in a zip file it uses realpath on the zipfile 43942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov// normalizes entry name by calling normalize_path function. 44042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic void resolve_paths(std::vector<std::string>& paths, 44142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string>* resolved_paths) { 44242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov resolved_paths->clear(); 44342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov for (const auto& path : paths) { 44442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov char resolved_path[PATH_MAX]; 44542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const char* original_path = path.c_str(); 44642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (realpath(original_path, resolved_path) != nullptr) { 44742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov struct stat s; 44842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (stat(resolved_path, &s) == 0) { 44942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (S_ISDIR(s.st_mode)) { 45042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov resolved_paths->push_back(resolved_path); 45142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } else { 45242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov DL_WARN("Warning: \"%s\" is not a directory (excluding from path)", resolved_path); 45342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov continue; 45442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 45542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } else { 45642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov DL_WARN("Warning: cannot stat file \"%s\": %s", resolved_path, strerror(errno)); 45742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov continue; 45842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 45942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } else { 46042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::string zip_path; 46142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::string entry_path; 46242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 46342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::string normalized_path; 46442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 46542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (!normalize_path(original_path, &normalized_path)) { 46642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov DL_WARN("Warning: unable to normalize \"%s\"", original_path); 46742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov continue; 46842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 46942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 47042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) { 47142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (realpath(zip_path.c_str(), resolved_path) == nullptr) { 47242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov DL_WARN("Warning: unable to resolve \"%s\": %s", zip_path.c_str(), strerror(errno)); 47342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov continue; 47442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 47542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 47642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov resolved_paths->push_back(std::string(resolved_path) + kZipFileSeparator + entry_path); 47742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 47842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 47942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 48042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov} 48142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 48242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic void split_path(const char* path, const char* delimiters, 483d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov std::vector<std::string>* paths) { 484fbfba640682b94e61632a58a0544f14ed6a57908Dmitriy Ivanov if (path != nullptr && path[0] != 0) { 485b447440a4b5e1e300c6cb1a931b3fa1e22900c4ftony.ys_liu *paths = android::base::Split(path, delimiters); 486cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 487cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 488cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 48942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic void parse_path(const char* path, const char* delimiters, 49042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string>* resolved_paths) { 49142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string> paths; 49242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov split_path(path, delimiters, &paths); 49342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov resolve_paths(paths, resolved_paths); 49442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov} 49542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 496cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_LIBRARY_PATH(const char* path) { 49742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string> ld_libary_paths; 49842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov parse_path(path, ":", &ld_libary_paths); 49942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths)); 500cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 501cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 5026865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanovvoid soinfo::set_dt_runpath(const char* path) { 50342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (!has_min_version(3)) { 5044f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return; 5054f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 5064f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 50742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string> runpaths; 50842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 50942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov split_path(path, ":", &runpaths); 5106865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov 5116865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov std::string origin = dirname(get_realpath()); 5126865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov // FIXME: add $LIB and $PLATFORM. 5136865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov std::pair<std::string, std::string> substs[] = {{"ORIGIN", origin}}; 51442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov for (auto&& s : runpaths) { 5156865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov size_t pos = 0; 5166865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov while (pos < s.size()) { 5176865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov pos = s.find("$", pos); 5186865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov if (pos == std::string::npos) break; 5196865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov for (const auto& subst : substs) { 5206865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov const std::string& token = subst.first; 5216865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov const std::string& replacement = subst.second; 5226865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov if (s.substr(pos + 1, token.size()) == token) { 5236865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov s.replace(pos, token.size() + 1, replacement); 5246865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov // -1 to compensate for the ++pos below. 5256865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov pos += replacement.size() - 1; 5266865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov break; 5276865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov } else if (s.substr(pos + 1, token.size() + 2) == "{" + token + "}") { 5286865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov s.replace(pos, token.size() + 3, replacement); 5296865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov pos += replacement.size() - 1; 5306865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov break; 5316865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov } 5326865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov } 5336865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov // Skip $ in case it did not match any of the known substitutions. 5346865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov ++pos; 5356865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov } 5366865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov } 53742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 53842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov resolve_paths(runpaths, &dt_runpath_); 5396865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov} 5406865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov 541cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_PRELOAD(const char* path) { 54242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_ld_preload_names.clear(); 54342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (path != nullptr) { 54442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // We have historically supported ':' as well as ' ' in LD_PRELOAD. 54542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_ld_preload_names = android::base::Split(path, " :"); 546bda20e78f0f314dbbf0f0bbcf0740cf2d6a4b85eDimitry Ivanov std::remove_if(g_ld_preload_names.begin(), 547bda20e78f0f314dbbf0f0bbcf0740cf2d6a4b85eDimitry Ivanov g_ld_preload_names.end(), 548bda20e78f0f314dbbf0f0bbcf0740cf2d6a4b85eDimitry Ivanov [] (const std::string& s) { return s.empty(); }); 54942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 550cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 551cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 552aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic bool realpath_fd(int fd, std::string* realpath) { 553aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX); 554a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd); 555aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) { 55638b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd); 557aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return false; 558aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } 559aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 560a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov *realpath = &buf[0]; 561aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return true; 562aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov} 563aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 5644eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 5654688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 5666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// For a given PC, find the .so that it belongs to. 5676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Returns the base address of the .ARM.exidx section 5686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// for that .so, and the number of 8-byte entries 5696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// in that section (via *pcount). 5706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// 5716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Intended to be called by libc's __gnu_Unwind_Find_exidx(). 5726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// 5736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is exposed via dlfcn.cpp and libdl.so. 574faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) { 5751649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov uintptr_t addr = reinterpret_cast<uintptr_t>(pc); 5761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (soinfo* si = solist; si != 0; si = si->next) { 5786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((addr >= si->base) && (addr < (si->base + si->size))) { 5796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *pcount = si->ARM_exidx_count; 5801649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx); 5811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 5826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 5836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *pcount = 0; 5846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return nullptr; 5851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 5864688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 58724053a461e7a20f34002262c1bb122023134989dChristopher Ferris#endif 5884688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 5896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Here, we only have to provide a callback to iterate across all the 5906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// loaded libraries. gcc_eh does the rest. 5917271caf93db6897cdbcfca169441045bb52de61bDmitriy Ivanovint do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) { 5926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov int rv = 0; 5936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 5946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_phdr_info dl_info; 5956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_addr = si->link_map_head.l_addr; 5966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_name = si->link_map_head.l_name; 5976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_phdr = si->phdr; 5986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov dl_info.dlpi_phnum = si->phnum; 5996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov rv = cb(&dl_info, sizeof(dl_phdr_info), data); 6006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (rv != 0) { 6016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 6021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 6036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 6046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return rv; 6051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 6064688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes 6072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst ElfW(Versym)* soinfo::get_versym(size_t n) const { 6082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2) && versym_ != nullptr) { 6092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return versym_ + n; 6102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return nullptr; 6132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 6142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6152a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::get_verneed_ptr() const { 6162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2)) { 6172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verneed_ptr_; 6182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return 0; 6212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 6222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovsize_t soinfo::get_verneed_cnt() const { 6242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2)) { 6252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verneed_cnt_; 6262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return 0; 6292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 6302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6312a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::get_verdef_ptr() const { 6322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2)) { 6332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verdef_ptr_; 6342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return 0; 6372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 6382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovsize_t soinfo::get_verdef_cnt() const { 6402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(2)) { 6412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verdef_cnt_; 6422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return 0; 6452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 6462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovtemplate<typename F> 6482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic bool for_each_verdef(const soinfo* si, F functor) { 6492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!si->has_min_version(2)) { 6502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 6512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uintptr_t verdef_ptr = si->get_verdef_ptr(); 6542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verdef_ptr == 0) { 6552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 6562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t offset = 0; 6592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t verdef_cnt = si->get_verdef_cnt(); 6612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov for (size_t i = 0; i<verdef_cnt; ++i) { 6622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset); 6632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t verdaux_offset = offset + verdef->vd_aux; 6642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov offset += verdef->vd_next; 6652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verdef->vd_version != 1) { 6673d7bea1fa00342f2a18331ea33a4b6e3332b3b02Dmitriy Ivanov DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s", 6683edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov i, verdef->vd_version, si->get_realpath()); 6692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 6702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if ((verdef->vd_flags & VER_FLG_BASE) != 0) { 6732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // "this is the version of the file itself. It must not be used for 6742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // matching a symbol. It can be used to match references." 6752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // 6762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // http://www.akkadia.org/drepper/symbol-versioning 6772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov continue; 6782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verdef->vd_cnt == 0) { 6812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i); 6822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 6832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset); 6862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (functor(i, verdef, verdaux) == true) { 6882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 6892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 6912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 6932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 6942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 6952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const { 6962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (vi == nullptr) { 6972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *versym = kVersymNotNeeded; 6982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 6992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 7002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *versym = kVersymGlobal; 7022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return for_each_verdef(this, 7042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) { 7052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verdef->vd_hash == vi->elf_hash && 7062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov strcmp(vi->name, get_string(verdaux->vda_name)) == 0) { 7072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *versym = verdef->vd_ndx; 7082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 7092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 7102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 7122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 7132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ); 7142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 7152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::find_symbol_by_name(SymbolName& symbol_name, 7172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const version_info* vi, 7182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)** symbol) const { 7192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uint32_t symbol_index; 7202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov bool success = 7212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov is_gnu_hash() ? 7222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov gnu_lookup(symbol_name, vi, &symbol_index) : 7232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov elf_lookup(symbol_name, vi, &symbol_index); 7242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (success) { 7262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index; 7272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 7282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return success; 730ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 731ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 732ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) { 733ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (ELF_ST_BIND(s->st_info) == STB_GLOBAL || 734ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov ELF_ST_BIND(s->st_info) == STB_WEAK) { 735ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return s->st_shndx != SHN_UNDEF; 736ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) { 73738b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes DL_WARN("unexpected ST_BIND value: %d for \"%s\" in \"%s\"", 73838b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath()); 739ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 740ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 741ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return false; 742ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 743ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 7442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymHiddenBit = 0x8000; 7452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic inline bool is_versym_hidden(const ElfW(Versym)* versym) { 7472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // the symbol is hidden if bit 15 of versym is set. 7482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return versym != nullptr && (*versym & kVersymHiddenBit) != 0; 7492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 7502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic inline bool check_symbol_version(const ElfW(Versym) verneed, 7522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Versym)* verdef) { 7532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return verneed == kVersymNotNeeded || 7542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verdef == nullptr || 7552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verneed == (*verdef & ~kVersymHiddenBit); 7562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 7572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::gnu_lookup(SymbolName& symbol_name, 7592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const version_info* vi, 7602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uint32_t* symbol_index) const { 761ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t hash = symbol_name.gnu_hash(); 762047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov uint32_t h2 = hash >> gnu_shift2_; 7631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 764ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8; 765047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_; 766047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num]; 7671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 7682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol_index = 0; 7692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7703597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)", 7713edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base)); 7723597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov 773ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // test against bloom filter 774ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) { 7753597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p", 7763edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base)); 7773597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov 7782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 779ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 780ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 781ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // bloom test says "probably yes"... 7823597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov uint32_t n = gnu_bucket_[hash % gnu_nbucket_]; 783ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 784ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (n == 0) { 7853597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p", 7863edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base)); 7873597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov 7882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 7892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 7902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 7912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // lookup versym for the version definition in this library 7922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // note the difference between "version is not requested" (vi == nullptr) 7932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // and "version not found". In the first case verneed is kVersymNotNeeded 7942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // which implies that the default version can be accepted; the second case results in 7952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols 7962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // for this library and consider only *global* ones. 7972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ElfW(Versym) verneed = 0; 7982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!find_verdef_version_index(vi, &verneed)) { 7992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 800ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 801ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 802ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov do { 803047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Sym)* s = symtab_ + n; 8042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Versym)* verdef = get_versym(n); 8052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // skip hidden versions when verneed == kVersymNotNeeded (0) 8062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) { 8072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov continue; 8082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 8093597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov if (((gnu_chain_[n] ^ hash) >> 1) == 0 && 8102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov check_symbol_version(verneed, verdef) && 811ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 && 812ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov is_symbol_global_and_defined(this, s)) { 8133597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd", 8143edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value), 8153597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov static_cast<size_t>(s->st_size)); 8162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol_index = n; 8172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 818ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 8193597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov } while ((gnu_chain_[n++] & 1) == 0); 8203597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov 8213597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p", 8223edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base)); 8231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 8242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 825ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 826ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 8272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::elf_lookup(SymbolName& symbol_name, 8282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const version_info* vi, 8292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uint32_t* symbol_index) const { 830ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t hash = symbol_name.elf_hash(); 831ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 832ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd", 8333edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov symbol_name.get_name(), get_realpath(), 834aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov reinterpret_cast<void*>(base), hash, hash % nbucket_); 835ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 8362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ElfW(Versym) verneed = 0; 8372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!find_verdef_version_index(vi, &verneed)) { 8382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 8392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 8402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 841047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) { 842047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Sym)* s = symtab_ + n; 8432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Versym)* verdef = get_versym(n); 8442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 8452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // skip hidden versions when verneed == 0 8462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) { 8472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov continue; 8482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 8492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 8502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (check_symbol_version(verneed, verdef) && 8512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 && 85220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov is_symbol_global_and_defined(this, s)) { 853ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd", 8543edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov symbol_name.get_name(), get_realpath(), 855aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov reinterpret_cast<void*>(s->st_value), 856aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov static_cast<size_t>(s->st_size)); 8572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol_index = n; 8582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 8591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 8600266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 8611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 862aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd", 8633edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov symbol_name.get_name(), get_realpath(), 864aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov reinterpret_cast<void*>(base), hash, hash % nbucket_); 865aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 8662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol_index = 0; 8672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 8681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 8691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 87042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovsoinfo::soinfo(android_namespace_t* ns, const char* realpath, 87142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const struct stat* file_stat, off64_t file_offset, 87242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov int rtld_flags) { 8730d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov memset(this, 0, sizeof(*this)); 8740d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 875aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (realpath != nullptr) { 876aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov realpath_ = realpath; 877aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } 878aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 879ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ = FLAG_NEW_SOINFO; 880047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov version_ = SOINFO_VERSION; 8810d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 882851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (file_stat != nullptr) { 883047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->st_dev_ = file_stat->st_dev; 884047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->st_ino_ = file_stat->st_ino; 885047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->file_offset_ = file_offset; 8860d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov } 887e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 888047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->rtld_flags_ = rtld_flags; 8890551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov this->primary_namespace_ = ns; 8900d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov} 8910d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 892ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovsoinfo::~soinfo() { 893ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov g_soinfo_handles_map.erase(handle_); 894ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov} 895ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 8964a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanovstatic uint32_t calculate_elf_hash(const char* name) { 8974a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov const uint8_t* name_bytes = reinterpret_cast<const uint8_t*>(name); 8984a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov uint32_t h = 0, g; 8996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 9004a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov while (*name_bytes) { 9014a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov h = (h << 4) + *name_bytes++; 9024a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov g = h & 0xf0000000; 9034a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov h ^= g; 9044a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov h ^= g >> 24; 9054a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 906ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 9074a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return h; 9084a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov} 909ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 9104a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanovuint32_t SymbolName::elf_hash() { 9114a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (!has_elf_hash_) { 9124a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov elf_hash_ = calculate_elf_hash(name_); 913ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov has_elf_hash_ = true; 9146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 915ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 916ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return elf_hash_; 917ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 918ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 919ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::gnu_hash() { 920ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (!has_gnu_hash_) { 921ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov uint32_t h = 5381; 922aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov const uint8_t* name = reinterpret_cast<const uint8_t*>(name_); 923ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov while (*name != 0) { 924ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c 925ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 926ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 927ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov gnu_hash_ = h; 928ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov has_gnu_hash_ = true; 929ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 930ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 931ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return gnu_hash_; 9321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 9331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 9342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi, 9352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov soinfo** si_found_in, const soinfo::soinfo_list_t& global_group, 9362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol) { 937ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov SymbolName symbol_name(name); 9382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* s = nullptr; 9396ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 94096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov /* "This element's presence in a shared object library alters the dynamic linker's 94196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * symbol resolution algorithm for references within the library. Instead of starting 94296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * a symbol search with the executable file, the dynamic linker starts from the shared 94396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * object itself. If the shared object fails to supply the referenced symbol, the 94496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * dynamic linker then searches the executable file and other shared objects as usual." 94596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * 94696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html 94796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * 94896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * Note that this is unlikely since static linker avoids generating 94996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov * relocations for -Bsymbolic linked dynamic executables. 95096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov */ 951d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (si_from->has_DT_SYMBOLIC) { 9523edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name); 9532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) { 9542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 9552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 9562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 9578f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (s != nullptr) { 958d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov *si_found_in = si_from; 95996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 96096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 96196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov 962d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // 1. Look for it in global_group 963d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (s == nullptr) { 9642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov bool error = false; 965d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov global_group.visit([&](soinfo* global_si) { 966aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s: looking up %s in %s (from global group)", 9673edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov si_from->get_realpath(), name, global_si->get_realpath()); 9682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) { 9692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov error = true; 9702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 9712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 9722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 97396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (s != nullptr) { 974d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov *si_found_in = global_si; 975d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return false; 97696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 977c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin 978d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return true; 979d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov }); 9802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 9812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (error) { 9822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 9832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 98496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 985c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin 986d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // 2. Look for it in the local group 987cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (s == nullptr) { 9882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov bool error = false; 989cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov local_group.visit([&](soinfo* local_si) { 990d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (local_si == si_from && si_from->has_DT_SYMBOLIC) { 991e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov // we already did this - skip 992e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov return true; 993e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov } 994e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov 995aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s: looking up %s in %s (from local group)", 9963edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov si_from->get_realpath(), name, local_si->get_realpath()); 9972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) { 9982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov error = true; 9992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 10002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 10012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 1002cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (s != nullptr) { 1003d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov *si_found_in = local_si; 1004cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return false; 1005cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 10066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 1007cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 1008cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov }); 10092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 10102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (error) { 10112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 10122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 1013cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 1014cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 10156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (s != nullptr) { 10166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " 10176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov "found in %s, base = %p, load bias = %p", 10183edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value), 10193edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base), 1020d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov reinterpret_cast<void*>((*si_found_in)->load_bias)); 10216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 10226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 10232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov *symbol = s; 10242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 10256ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev} 10266ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev 1027279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanovclass ProtectedDataGuard { 1028279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov public: 1029279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard() { 1030279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov if (ref_count_++ == 0) { 1031279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov protect_data(PROT_READ | PROT_WRITE); 1032279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 1033279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 1034279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 1035279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ~ProtectedDataGuard() { 1036279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov if (ref_count_ == 0) { // overflow 1037279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov __libc_fatal("Too many nested calls to dlopen()"); 1038279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 1039279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 1040279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov if (--ref_count_ == 0) { 1041279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov protect_data(PROT_READ); 1042279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 1043279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 1044279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov private: 1045279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov void protect_data(int protection) { 1046279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov g_soinfo_allocator.protect_all(protection); 1047279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov g_soinfo_links_allocator.protect_all(protection); 104842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_namespace_allocator.protect_all(protection); 10490551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov g_namespace_list_allocator.protect_all(protection); 1050279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 1051279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 1052279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov static size_t ref_count_; 1053279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov}; 1054279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 1055279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanovsize_t ProtectedDataGuard::ref_count_ = 0; 1056279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 10570cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov// Each size has it's own allocator. 10580cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size> 10590cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass SizeBasedAllocator { 10600cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public: 10610cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void* alloc() { 10620cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov return allocator_.alloc(); 10630cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 10640cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 10650cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void free(void* ptr) { 10660cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov allocator_.free(ptr); 10670cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 10684bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov 10690cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov private: 10700cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static LinkerBlockAllocator allocator_; 10710cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov}; 10720cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 10730cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size> 10740cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy IvanovLinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size); 10750cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 10760cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<typename T> 10770cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass TypeBasedAllocator { 10780cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public: 10790cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static T* alloc() { 10800cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc()); 10810cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 10820cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 10830cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov static void free(T* ptr) { 10840cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SizeBasedAllocator<sizeof(T)>::free(ptr); 10850cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov } 10860cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov}; 10870cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 108814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovclass LoadTask { 108914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov public: 109014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov struct deleter_t { 109114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov void operator()(LoadTask* t) { 10924f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov t->~LoadTask(); 109314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov TypeBasedAllocator<LoadTask>::free(t); 109414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 109514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }; 1096a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 109714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov static deleter_t deleter; 109814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 10994f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov static LoadTask* create(const char* name, soinfo* needed_by, 11004f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov std::unordered_map<const soinfo*, ElfReader>* readers_map) { 110114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc(); 11024f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return new (ptr) LoadTask(name, needed_by, readers_map); 1103aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 1104a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 110514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* get_name() const { 110614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return name_; 1107a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov } 110814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 110914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* get_needed_by() const { 111014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return needed_by_; 111114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 11124f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11134f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov soinfo* get_soinfo() const { 11144f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return si_; 11154f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11164f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11174f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov void set_soinfo(soinfo* si) { 11184f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si_ = si; 11194f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11204f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11214f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov off64_t get_file_offset() const { 11224f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return file_offset_; 11234f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11244f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11254f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov void set_file_offset(off64_t offset) { 11264f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov file_offset_ = offset; 11274f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11284f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11294f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov int get_fd() const { 11304f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return fd_; 11314f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11324f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11334f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov void set_fd(int fd, bool assume_ownership) { 11344f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov fd_ = fd; 11354f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov close_fd_ = assume_ownership; 11364f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11374f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11384f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const android_dlextinfo* get_extinfo() const { 11394f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return extinfo_; 11404f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11414f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11424f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov void set_extinfo(const android_dlextinfo* extinfo) { 11434f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov extinfo_ = extinfo; 11444f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11454f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11461005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov bool is_dt_needed() const { 11471005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov return is_dt_needed_; 11481005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov } 11491005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov 11501005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov void set_dt_needed(bool is_dt_needed) { 11511005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov is_dt_needed_ = is_dt_needed; 11521005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov } 11531005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov 11544f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const ElfReader& get_elf_reader() const { 11554f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov CHECK(si_ != nullptr); 11564f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return (*elf_readers_map_)[si_]; 11574f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11584f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11594f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov ElfReader& get_elf_reader() { 11604f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov CHECK(si_ != nullptr); 11614f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return (*elf_readers_map_)[si_]; 11624f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11634f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11644f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov std::unordered_map<const soinfo*, ElfReader>* get_readers_map() { 11654f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return elf_readers_map_; 11664f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11674f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11684f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov bool read(const char* realpath, off64_t file_size) { 11694f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov ElfReader& elf_reader = get_elf_reader(); 11704f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return elf_reader.Read(realpath, fd_, file_offset_, file_size); 11714f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11724f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11734f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov bool load() { 11744f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov ElfReader& elf_reader = get_elf_reader(); 11754f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (!elf_reader.Load(extinfo_)) { 11764f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 11774f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11784f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11794f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si_->base = elf_reader.load_start(); 11804f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si_->size = elf_reader.load_size(); 1181f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller()); 11824f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si_->load_bias = elf_reader.load_bias(); 11834f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si_->phnum = elf_reader.phdr_count(); 11844f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si_->phdr = elf_reader.loaded_phdr(); 11854f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11864f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return true; 11874f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 11884f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 118914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov private: 11904f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov LoadTask(const char* name, soinfo* needed_by, 11914f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov std::unordered_map<const soinfo*, ElfReader>* readers_map) 11924f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov : name_(name), needed_by_(needed_by), si_(nullptr), 11931005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map), 11941005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov is_dt_needed_(false) {} 11954f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 11964f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov ~LoadTask() { 11974f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (fd_ != -1 && close_fd_) { 11984f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov close(fd_); 11994f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 12004f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 120114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 120214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* name_; 120314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* needed_by_; 12044f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov soinfo* si_; 12054f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const android_dlextinfo* extinfo_; 12064f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov int fd_; 12074f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov bool close_fd_; 12084f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov off64_t file_offset_; 12094f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_; 1210f1d4a4959880eaf0f9c789c43c1bae383a605d9fDimitry Ivanov // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list) 12111005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov bool is_dt_needed_; 12121005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov // END OF WORKAROUND 121314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 121414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask); 1215aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}; 1216aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 1217e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng JianLoadTask::deleter_t LoadTask::deleter; 1218e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian 121914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate <typename T> 122014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovusing linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>; 122114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 122214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<soinfo> SoinfoLinkedList; 122314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<const char> StringLinkedList; 12244f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanovtypedef std::vector<LoadTask*> LoadTaskList; 122514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 122614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1227cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// This function walks down the tree of soinfo dependencies 1228cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// in breadth-first order and 1229cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// * calls action(soinfo* si) for each node, and 1230cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// * terminates walk if action returns false. 1231cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// 1232cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// walk_dependencies_tree returns false if walk was terminated 1233cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// by the action and true otherwise. 1234cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovtemplate<typename F> 1235cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovstatic bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) { 12360cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SoinfoLinkedList visit_list; 12370cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov SoinfoLinkedList visited; 12380cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov 1239cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov for (size_t i = 0; i < root_soinfos_size; ++i) { 1240cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov visit_list.push_back(root_soinfos[i]); 1241cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 1242cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1243cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov soinfo* si; 1244cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov while ((si = visit_list.pop_front()) != nullptr) { 1245cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (visited.contains(si)) { 1246042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov continue; 1247042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov } 1248042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov 1249cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (!action(si)) { 1250cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return false; 1251aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 1252aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 1253cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov visited.push_back(si); 1254cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1255cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov si->get_children().for_each([&](soinfo* child) { 1256aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov visit_list.push_back(child); 1257aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov }); 1258aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov } 1259aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov 1260cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 1261cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov} 1262cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1263cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1264697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanovstatic const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until, 12654a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo** found, SymbolName& symbol_name, 12664a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov const version_info* vi) { 12672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* result = nullptr; 1268697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov bool skip_lookup = skip_until != nullptr; 1269697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov 1270697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) { 1271697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov if (skip_lookup) { 1272697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov skip_lookup = current_soinfo != skip_until; 1273697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov return true; 1274697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov } 1275cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 12764a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) { 12772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov result = nullptr; 12782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 12792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 12802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 1281cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (result != nullptr) { 1282cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov *found = current_soinfo; 1283cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return false; 1284cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 1285cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1286cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 1287cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov }); 1288cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 1289cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return result; 12901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 12911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 12924a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanovstatic const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns, 12934a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov const char* name, 12944a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov const version_info* vi, 12954a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo** found, 12964a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo* caller, 12974a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov void* handle); 12984a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 1299697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov// This is used by dlsym(3). It performs symbol lookup only within the 1300697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov// specified soinfo object and its dependencies in breadth first order. 13014a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanovstatic const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, 13024a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov const char* name, const version_info* vi) { 1303f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov // According to man dlopen(3) and posix docs in the case when si is handle 1304f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov // of the main executable we need to search not only in the executable and its 1305f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov // dependencies but also in all libraries loaded with RTLD_GLOBAL. 1306f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov // 1307f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared 1308f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov // libraries and they are loaded in breath-first (correct) order we can just execute 1309f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup. 1310f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov if (si == somain) { 13114a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT); 1312f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov } 1313f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov 1314697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov SymbolName symbol_name(name); 13154a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi); 1316697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov} 1317697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov 1318d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom/* This is used by dlsym(3) to performs a global symbol lookup. If the 1319d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom start value is null (for RTLD_DEFAULT), the search starts at the 1320d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom beginning of the global solist. Otherwise the search starts at the 1321d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom specified soinfo (for RTLD_NEXT). 13226ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */ 13234a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanovstatic const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns, 13244a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov const char* name, 13254a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov const version_info* vi, 13264a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo** found, 13274a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo* caller, 13284a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov void* handle) { 1329ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov SymbolName symbol_name(name); 13301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1331ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov auto& soinfo_list = ns->soinfo_list(); 1332ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov auto start = soinfo_list.begin(); 133376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov 133476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov if (handle == RTLD_NEXT) { 1335b96ac41b32e61799c48f3fd07831cc168b95068dDmitriy Ivanov if (caller == nullptr) { 133676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov return nullptr; 133776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov } else { 1338ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov auto it = soinfo_list.find(caller); 133942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov CHECK (it != soinfo_list.end()); 134042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov start = ++it; 134176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov } 1342cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 13431698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer 13442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* s = nullptr; 1345ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov for (auto it = start, end = soinfo_list.end(); it != end; ++it) { 134642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo* si = *it; 13471913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...) 13481913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov // if the library is opened by application with target api level <= 22 13491913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov // See http://b/21565766 13501913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) { 1351e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov continue; 1352e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 1353e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 13544a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (!si->find_symbol_by_name(symbol_name, vi, &s)) { 13552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return nullptr; 13562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 13572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 1358851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s != nullptr) { 1359cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes *found = si; 1360cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes break; 13611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1362cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 13631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1364697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov // If not found - use dlsym_handle_lookup for caller's 1365697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov // local_group unless it is part of the global group in which 136676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov // case we already did it. 136776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov if (s == nullptr && caller != nullptr && 136876ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) { 1369697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov return dlsym_handle_lookup(caller->get_local_group_root(), 13704a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi); 137176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov } 137276ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov 1373851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s != nullptr) { 1374c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p", 1375c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base)); 1376cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes } 13771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1378cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes return s; 13791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 13801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1381fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Chengsoinfo* find_containing_library(const void* p) { 13820266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p); 1383851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov for (soinfo* si = solist; si != nullptr; si = si->next) { 1384fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (address >= si->base && address - si->base < si->size) { 1385fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return si; 1386e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer } 1387fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 1388851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 1389e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer} 1390e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 1391ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) { 1392ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr); 1393ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 1394ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1395ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) { 1396ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return sym->st_shndx != SHN_UNDEF && 1397ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov soaddr >= sym->st_value && 1398ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov soaddr < sym->st_value + sym->st_size; 1399ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 1400ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1401ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) { 14028e5538193915885ea859ac90a72b46ab04440ceaChris Dearman ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias; 1403ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 14043597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov for (size_t i = 0; i < gnu_nbucket_; ++i) { 14053597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov uint32_t n = gnu_bucket_[i]; 1406ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1407ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (n == 0) { 1408ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov continue; 1409ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 1410ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1411ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov do { 1412047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Sym)* sym = symtab_ + n; 1413ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (symbol_matches_soaddr(sym, soaddr)) { 1414ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return sym; 1415ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 14163597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov } while ((gnu_chain_[n++] & 1) == 0); 1417ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 1418ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1419ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return nullptr; 1420ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 1421ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 1422ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) { 14238e5538193915885ea859ac90a72b46ab04440ceaChris Dearman ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias; 1424fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 1425fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng // Search the library's symbol table for any defined symbol which 1426fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng // contains this address. 1427047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov for (size_t i = 0; i < nchain_; ++i) { 1428047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov ElfW(Sym)* sym = symtab_ + i; 1429ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov if (symbol_matches_soaddr(sym, soaddr)) { 1430fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return sym; 1431e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer } 1432fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 1433e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 1434851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 1435e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer} 1436e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer 1437b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanovclass ZipArchiveCache { 1438b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov public: 1439b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov ZipArchiveCache() {} 1440b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov ~ZipArchiveCache(); 1441b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1442b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov bool get_or_open(const char* zip_path, ZipArchiveHandle* handle); 1443b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov private: 1444b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache); 1445b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1446b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov std::unordered_map<std::string, ZipArchiveHandle> cache_; 1447b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov}; 1448b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1449b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanovbool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) { 1450b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov std::string key(zip_path); 1451b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1452b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov auto it = cache_.find(key); 1453b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov if (it != cache_.end()) { 1454b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov *handle = it->second; 1455b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov return true; 1456b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov } 1457b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1458b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); 1459b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov if (fd == -1) { 1460b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov return false; 1461b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov } 1462b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1463b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov if (OpenArchiveFd(fd, "", handle) != 0) { 1464b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov // invalid zip-file (?) 1465b3ee859bbd6ce5ff9ed252bb00ff0b6c452d0373Yabin Cui CloseArchive(handle); 1466b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov close(fd); 1467b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov return false; 1468b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov } 1469b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1470b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov cache_[key] = *handle; 1471b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov return true; 1472b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov} 1473b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1474b48275045de93cce292faaf5170af3ead89b3746Dmitriy IvanovZipArchiveCache::~ZipArchiveCache() { 14755dce8948b65cf9c2d81165056d914b999bb3a4d8Dmitriy Ivanov for (const auto& it : cache_) { 1476b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov CloseArchive(it.second); 1477b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov } 1478b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov} 1479b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1480b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanovstatic int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache, 1481a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov const char* const input_path, 1482a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov off64_t* file_offset, std::string* realpath) { 1483a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov std::string normalized_path; 1484a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov if (!normalize_path(input_path, &normalized_path)) { 1485a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov return -1; 1486a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov } 1487a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov 1488a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov const char* const path = normalized_path.c_str(); 148938b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path); 1490aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1491402a75060dcd194c1991a15df2aba51f0d868ac3Dmitriy Ivanov // Treat an '!/' separator inside a path as the separator between the name 1492aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // of the zip file on disk and the subdirectory to search within it. 1493402a75060dcd194c1991a15df2aba51f0d868ac3Dmitriy Ivanov // For example, if path is "foo.zip!/bar/bas/x.so", then we search for 1494aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // "bar/bas/x.so" within "foo.zip". 1495a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov const char* const separator = strstr(path, kZipFileSeparator); 1496aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (separator == nullptr) { 1497aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1498aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1499aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1500aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin char buf[512]; 1501aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) { 1502aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin PRINT("Warning: ignoring very long library path: %s", path); 1503aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1504aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1505aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1506aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin buf[separator - path] = '\0'; 1507aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1508aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin const char* zip_path = buf; 1509402a75060dcd194c1991a15df2aba51f0d868ac3Dmitriy Ivanov const char* file_path = &buf[separator - path + 2]; 1510aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); 1511aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (fd == -1) { 1512aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1513aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1514aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1515aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin ZipArchiveHandle handle; 1516b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov if (!zip_archive_cache->get_or_open(zip_path, &handle)) { 1517aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // invalid zip-file (?) 1518aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin close(fd); 1519aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1520aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1521aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1522aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin ZipEntry entry; 1523aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 152456f40fbb822b3b3066a490bdb62666039542987aYusuke Sato if (FindEntry(handle, ZipString(file_path), &entry) != 0) { 1525aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // Entry was not found. 1526aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin close(fd); 1527aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1528aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1529aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1530aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin // Check if it is properly stored 1531aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) { 1532aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin close(fd); 1533aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return -1; 1534aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1535aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1536aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin *file_offset = entry.offset; 1537a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov 1538a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov if (realpath_fd(fd, realpath)) { 1539a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov *realpath += separator; 1540a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov } else { 1541a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", 1542a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov normalized_path.c_str()); 1543a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov *realpath = normalized_path; 1544a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov } 1545a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov 1546aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin return fd; 1547aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin} 1548aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1549d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic bool format_path(char* buf, size_t buf_size, const char* path, const char* name) { 1550d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name); 1551d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (n < 0 || n >= static_cast<int>(buf_size)) { 1552d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov PRINT("Warning: ignoring very long library path: %s/%s", path, name); 1553d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return false; 1554d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 1555d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 1556d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return true; 1557d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov} 1558aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1559b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanovstatic int open_library_on_paths(ZipArchiveCache* zip_archive_cache, 1560b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov const char* name, off64_t* file_offset, 1561a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov const std::vector<std::string>& paths, 1562a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov std::string* realpath) { 156342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov for (const auto& path : paths) { 1564d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov char buf[512]; 156542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (!format_path(buf, sizeof(buf), path.c_str(), name)) { 1566d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov continue; 1567d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 1568d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 1569d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov int fd = -1; 1570730ed9dfec37441ae0cbb96f681381da6e113daaDmitriy Ivanov if (strstr(buf, kZipFileSeparator) != nullptr) { 1571a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath); 1572aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1573aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1574aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (fd == -1) { 1575aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC)); 1576aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (fd != -1) { 1577aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin *file_offset = 0; 1578a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov if (!realpath_fd(fd, realpath)) { 1579a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf); 1580a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov *realpath = buf; 1581a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov } 1582aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1583124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 1584d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 1585d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (fd != -1) { 1586d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return fd; 1587d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov } 1588124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 1589aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1590d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov return -1; 15911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 15921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 159342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic int open_library(android_namespace_t* ns, 159442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ZipArchiveCache* zip_archive_cache, 1595b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov const char* name, soinfo *needed_by, 1596a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov off64_t* file_offset, std::string* realpath) { 1597ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ opening %s ]", name); 15981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1599124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes // If the name contains a slash, we should attempt to open it directly and not search the paths. 1600851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (strchr(name, '/') != nullptr) { 160142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov int fd = -1; 160242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 1603730ed9dfec37441ae0cbb96f681381da6e113daaDmitriy Ivanov if (strstr(name, kZipFileSeparator) != nullptr) { 160442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath); 160542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 160642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 160742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (fd == -1) { 160842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC)); 1609aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin if (fd != -1) { 161042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov *file_offset = 0; 161142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (!realpath_fd(fd, realpath)) { 161242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name); 161342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov *realpath = name; 161442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 1615aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1616aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin } 1617aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin 1618e44fffd7f9b93b9ec9836cfc7acedf7e21107f8fDmitriy Ivanov return fd; 1619124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 16201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 162142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path 162242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov int fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_ld_library_paths(), realpath); 16234f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (fd == -1 && needed_by != nullptr) { 1624a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath); 162542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // Check if the library is accessible 162642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (fd != -1 && !ns->is_accessible(*realpath)) { 162742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov fd = -1; 162842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 16296865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov } 1630b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1631124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes if (fd == -1) { 163242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath); 1633124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes } 1634b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 1635f1d4a4959880eaf0f9c789c43c1bae383a605d9fDimitry Ivanov // TODO(dimitry): workaround for http://b/26394120 (the grey-list) 163636ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) { 1637a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov // try searching for it on default_namespace default_library_path 1638a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov fd = open_library_on_paths(zip_archive_cache, name, file_offset, 1639a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov g_default_namespace.get_default_library_paths(), realpath); 1640a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov } 1641a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov // END OF WORKAROUND 1642a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov 1643124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes return fd; 16441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 16451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1646d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanovstatic const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) { 1647d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov#if !defined(__LP64__) 1648d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029 16491913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov if (get_application_target_sdk_version() <= 22) { 1650d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov const char* bname = basename(dt_needed); 1651d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov if (bname != dt_needed) { 165238b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed); 1653df91dc2c192aa2789320c500037d28c919daa820Dimitry Ivanov add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed); 1654d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov } 1655d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov 1656d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov return bname; 1657d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov } 1658d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov#endif 1659d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov return dt_needed; 1660d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov} 1661d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov 166214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate<typename F> 166314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void for_each_dt_needed(const soinfo* si, F action) { 16644f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (const ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { 166514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (d->d_tag == DT_NEEDED) { 1666d974e8804689058714dc4fe9adcb57ee9a6996a8Dmitriy Ivanov action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath())); 1667d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 166814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 166914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 1670d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 16714f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanovtemplate<typename F> 16724f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanovstatic void for_each_dt_needed(const ElfReader& elf_reader, F action) { 16734f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) { 16744f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (d->d_tag == DT_NEEDED) { 16754f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name())); 16764f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 16774f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 16784f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov} 16794f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 168042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic bool load_library(android_namespace_t* ns, 168142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov LoadTask* task, 16824f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov LoadTaskList* load_tasks, 16834f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov int rtld_flags, 16844f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const std::string& realpath) { 16854f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov off64_t file_offset = task->get_file_offset(); 16864f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const char* name = task->get_name(); 16874f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const android_dlextinfo* extinfo = task->get_extinfo(); 16884f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 168907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((file_offset % PAGE_SIZE) != 0) { 1690a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset); 16914f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 169207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 169316f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui if (file_offset < 0) { 169416f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset); 16954f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 169616f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui } 169707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 169814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov struct stat file_stat; 16994f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) { 1700a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno)); 17014f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 170214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 170316f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui if (file_offset >= file_stat.st_size) { 170420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64, 170520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov name, file_offset, file_stat.st_size); 17064f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 170716f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui } 1708d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 170914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Check for symlink and other situations where 17109b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set 17119b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) { 171242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov auto predicate = [&](soinfo* si) { 171342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return si->get_st_dev() != 0 && 171442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov si->get_st_ino() != 0 && 171542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov si->get_st_dev() == file_stat.st_dev && 171642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov si->get_st_ino() == file_stat.st_ino && 171742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov si->get_file_offset() == file_offset; 171842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov }; 171942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 172042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo* si = ns->soinfo_list().find_if(predicate); 172142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 172242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // check public namespace 172342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (si == nullptr) { 172442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov si = g_public_namespace.find_if(predicate); 172542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (si != nullptr) { 1726ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov ns->add_soinfo(si); 17279b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov } 1728498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov } 172942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 173042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (si != nullptr) { 173142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov TRACE("library \"%s\" is already loaded under different name/path \"%s\" - " 173242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov "will return existing soinfo", name, si->get_realpath()); 173342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov task->set_soinfo(si); 173442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return true; 173542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 173614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1737d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 1738e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if ((rtld_flags & RTLD_NOLOAD) != 0) { 1739a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); 17404f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 174114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1742d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 174322840aab47763c88598b32d1edcac4d8b3ef21f0Dimitry Ivanov if (!ns->is_accessible(realpath)) { 1744f1d4a4959880eaf0f9c789c43c1bae383a605d9fDimitry Ivanov // TODO(dimitry): workaround for http://b/26394120 - the grey-list 17451005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr; 174636ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov if (is_greylisted(name, needed_by)) { 174736ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov // print warning only if needed by non-system library 174836ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) { 1749f53e7de4e97673195ef2faf52f777352660de2a8Dimitry Ivanov const soinfo* needed_or_dlopened_by = task->get_needed_by(); 1750df91dc2c192aa2789320c500037d28c919daa820Dimitry Ivanov const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" : 1751df91dc2c192aa2789320c500037d28c919daa820Dimitry Ivanov needed_or_dlopened_by->get_realpath(); 1752f53e7de4e97673195ef2faf52f777352660de2a8Dimitry Ivanov DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"" 1753f1d4a4959880eaf0f9c789c43c1bae383a605d9fDimitry Ivanov " - the access is temporarily granted as a workaround for http://b/26394120, note that the access" 1754f1d4a4959880eaf0f9c789c43c1bae383a605d9fDimitry Ivanov " will be removed in future releases of Android.", 1755df91dc2c192aa2789320c500037d28c919daa820Dimitry Ivanov name, realpath.c_str(), sopath, ns->get_name()); 1756df91dc2c192aa2789320c500037d28c919daa820Dimitry Ivanov add_dlwarning(sopath, "unauthorized access to", name); 175736ac45f783ed7668a483697025c0447d1c6fa955Dimitry Ivanov } 1758a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov } else { 1759a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov // do not load libraries if they are not accessible for the specified namespace. 1760350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ? 1761350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov "(unknown)" : 1762350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov task->get_needed_by()->get_realpath(); 1763350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov 1764350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"", 1765350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov name, needed_or_dlopened_by, ns->get_name()); 1766350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov 1767350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the" 1768350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\"," 1769350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov " permitted_paths=\"%s\"]", 1770350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov name, realpath.c_str(), 1771350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov needed_or_dlopened_by, 1772350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov ns->get_name(), 1773350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov android::base::Join(ns->get_ld_library_paths(), ':').c_str(), 1774350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov android::base::Join(ns->get_default_library_paths(), ':').c_str(), 1775350bdad61cc6551db649fcaeb8642f4a1d6b139aDimitry Ivanov android::base::Join(ns->get_permitted_paths(), ':').c_str()); 1776a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov return false; 1777a8bda26ec948dbd39ad648492f110edeb269f768Dimitry Ivanov } 177822840aab47763c88598b32d1edcac4d8b3ef21f0Dimitry Ivanov } 177922840aab47763c88598b32d1edcac4d8b3ef21f0Dimitry Ivanov 178042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags); 178114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (si == nullptr) { 17824f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 178314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 178414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 17854f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->set_soinfo(si); 17864f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 17874f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // Read the ELF header and some of the segments. 17884f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (!task->read(realpath.c_str(), file_stat.st_size)) { 1789fd7a91e69263a991f65fa458ff33de0670b4fd81Dmitriy Ivanov soinfo_free(si); 1790fd7a91e69263a991f65fa458ff33de0670b4fd81Dmitriy Ivanov task->set_soinfo(nullptr); 17914f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 179214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 1793a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov 17944f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // find and set DT_RUNPATH and dt_soname 17954f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // Note that these field values are temporary and are 17964f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // going to be overwritten on soinfo::prelink_image 17974f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // with values from PT_LOAD segments. 17984f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const ElfReader& elf_reader = task->get_elf_reader(); 17994f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) { 18004f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (d->d_tag == DT_RUNPATH) { 18014f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val)); 18024f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 18034f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (d->d_tag == DT_SONAME) { 18044f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si->set_soname(elf_reader.get_string(d->d_un.d_val)); 18054f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 18064f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 18074f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 18084f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for_each_dt_needed(task->get_elf_reader(), [&](const char* name) { 18094f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map())); 181014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 181114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 18124f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return true; 18131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 18141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 181542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic bool load_library(android_namespace_t* ns, 181642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov LoadTask* task, 18174f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov ZipArchiveCache* zip_archive_cache, 18184f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov LoadTaskList* load_tasks, 18194f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov int rtld_flags) { 18204f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const char* name = task->get_name(); 18214f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov soinfo* needed_by = task->get_needed_by(); 18224f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov const android_dlextinfo* extinfo = task->get_extinfo(); 18234f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 1824a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov off64_t file_offset; 1825a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov std::string realpath; 18260346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { 1827a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov file_offset = 0; 18280346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) { 18290346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low file_offset = extinfo->library_fd_offset; 18300346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low } 1831a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov 1832a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov if (!realpath_fd(extinfo->library_fd, &realpath)) { 1833a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. " 1834a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov "Will use given name.", name); 1835a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov realpath = name; 1836a1feb117e4d5614548574f28dede3443e073512bDmitriy Ivanov } 18374f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 18384f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->set_fd(extinfo->library_fd, false); 18394f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->set_file_offset(file_offset); 184042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return load_library(ns, task, load_tasks, rtld_flags, realpath); 18410346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low } 18420346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low 18430346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low // Open the file. 184442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath); 18450346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low if (fd == -1) { 18460346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low DL_ERR("library \"%s\" not found", name); 18474f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 18480346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low } 18494f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 18504f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->set_fd(fd, true); 18514f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->set_file_offset(file_offset); 18524f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 185342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return load_library(ns, task, load_tasks, rtld_flags, realpath); 18540346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low} 18550346ad7a4fb6e253317577ee8b9cc79d958f4349Spencer Low 1856a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov// Returns true if library was found and false in 2 cases 185742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov// 1. (for default namespace only) The library was found but loaded under different 185842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov// target_sdk_version (*candidate != nullptr) 1859a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov// 2. The library was not found by soname (*candidate is nullptr) 186042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic bool find_loaded_library_by_soname(android_namespace_t* ns, 186142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const char* name, soinfo** candidate) { 1862a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov *candidate = nullptr; 1863a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov 1864618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // Ignore filename with path. 1865618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov if (strchr(name, '/') != nullptr) { 1866a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov return false; 1867618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov } 1868618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov 1869a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov uint32_t target_sdk_version = get_application_target_sdk_version(); 1870a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov 187142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return !ns->soinfo_list().visit([&](soinfo* si) { 1872618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov const char* soname = si->get_soname(); 1873618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov if (soname != nullptr && (strcmp(name, soname) == 0)) { 1874a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov // If the library was opened under different target sdk version 1875a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov // skip this step and try to reopen it. The exceptions are 1876a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov // "libdl.so" and global group. There is no point in skipping 1877a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov // them because relocation process is going to use them 1878a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov // in any case. 1879a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov bool is_libdl = si == solist; 1880a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 || 188142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov !si->is_linked() || si->get_target_sdk_version() == target_sdk_version || 188242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ns != &g_default_namespace) { 1883a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov *candidate = si; 188442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return false; 1885a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov } else if (*candidate == nullptr) { 188642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // for the different sdk version in the default namespace 188742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // remember the first library. 1888a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov *candidate = si; 1889a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov } 189012c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel } 1891a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov 189242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return true; 189342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov }); 189412c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel} 189512c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel 189642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic bool find_library_internal(android_namespace_t* ns, 189742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov LoadTask* task, 18984f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov ZipArchiveCache* zip_archive_cache, 18994f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov LoadTaskList* load_tasks, 19004f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov int rtld_flags) { 1901a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov soinfo* candidate; 1902a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov 190342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) { 19044f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->set_soinfo(candidate); 19054f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return true; 1906a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov } 1907b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 190842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (ns != &g_default_namespace) { 190942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov // check public namespace 191042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov candidate = g_public_namespace.find_if([&](soinfo* si) { 191142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return strcmp(task->get_name(), si->get_soname()) == 0; 191242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov }); 191342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 191442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (candidate != nullptr) { 1915ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov ns->add_soinfo(candidate); 191642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov task->set_soinfo(candidate); 191742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return true; 191842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 191942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 192042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 1921b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // Library might still be loaded, the accurate detection 192214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // of this fact is done by load_library. 192338b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]", 19244f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate); 1925a9703332f6a2983ca40781e1e943c539d053d814Dmitriy Ivanov 192642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) { 19274f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return true; 19284f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } else { 19294f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // In case we were unable to load the library but there 19304f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // is a candidate loaded under the same soname but different 19314f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // sdk level - return it anyways. 19324f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (candidate != nullptr) { 19334f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->set_soinfo(candidate); 19344f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return true; 19354f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 1936b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov } 1937b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 19384f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 193914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 194014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 194114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void soinfo_unload(soinfo* si); 1942bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanovstatic void soinfo_unload(soinfo* soinfos[], size_t count); 194314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 1944d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// TODO: this is slightly unusual way to construct 1945d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// the global group for relocation. Not every RTLD_GLOBAL 1946d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// library is included in this group for backwards-compatibility 1947d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// reasons. 1948d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// 1949d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// This group consists of the main executable, LD_PRELOADs 1950d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// and libraries with the DF_1_GLOBAL flag set. 195142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic soinfo::soinfo_list_t make_global_group(android_namespace_t* ns) { 1952d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov soinfo::soinfo_list_t global_group; 195342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ns->soinfo_list().for_each([&](soinfo* si) { 1954d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) { 1955d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov global_group.push_back(si); 1956d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 195742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov }); 1958d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 1959d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return global_group; 1960d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov} 1961d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 196249cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov// This function provides a list of libraries to be shared 196349cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov// by the namespace. For the default namespace this is the global 196449cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov// group (see make_global_group). For all others this is a group 196549cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov// of RTLD_GLOBAL libraries (which includes the global group from 196649cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov// the default namespace). 196749cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanovstatic soinfo::soinfo_list_t get_shared_group(android_namespace_t* ns) { 196849cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov if (ns == &g_default_namespace) { 196949cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov return make_global_group(ns); 197049cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov } 197149cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov 197249cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov soinfo::soinfo_list_t shared_group; 197349cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov ns->soinfo_list().for_each([&](soinfo* si) { 197449cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) { 197549cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov shared_group.push_back(si); 197649cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov } 197749cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov }); 197849cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov 197949cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov return shared_group; 198049cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov} 198149cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov 19824f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanovstatic void shuffle(std::vector<LoadTask*>* v) { 19834f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (size_t i = 0, size = v->size(); i < size; ++i) { 19844f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov size_t n = size - i; 19854f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov size_t r = arc4random_uniform(n); 19864f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov std::swap((*v)[n-1], (*v)[r]); 19874f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 19884f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov} 19894f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 19900cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov// add_as_children - add first-level loaded libraries (i.e. library_names[], but 19910cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov// not their transitive dependencies) as children of the start_with library. 19920cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov// This is false when find_libraries is called for dlopen(), when newly loaded 19930cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov// libraries must form a disjoint tree. 199442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic bool find_libraries(android_namespace_t* ns, 199542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo* start_with, 19960cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov const char* const library_names[], 19970cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov size_t library_names_count, soinfo* soinfos[], 19980cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov std::vector<soinfo*>* ld_preloads, 19990cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov size_t ld_preloads_count, int rtld_flags, 20000cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov const android_dlextinfo* extinfo, 20010cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov bool add_as_children) { 200214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov // Step 0: prepare. 200314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTaskList load_tasks; 20044f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov std::unordered_map<const soinfo*, ElfReader> readers_map; 20054f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 2006cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov for (size_t i = 0; i < library_names_count; ++i) { 200714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov const char* name = library_names[i]; 20084f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov load_tasks.push_back(LoadTask::create(name, start_with, &readers_map)); 2009cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov } 2010cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 2011d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // Construct global_group. 201242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo::soinfo_list_t global_group = make_global_group(ns); 2013d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 2014cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // If soinfos array is null allocate one on stack. 2015cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // The array is needed in case of failure; for example 2016cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // when library_names[] = {libone.so, libtwo.so} and libone.so 2017cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // is loaded correctly but libtwo.so failed for some reason. 2018cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // In this case libone.so should be unloaded on return. 2019cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // See also implementation of failure_guard below. 2020cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 2021cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (soinfos == nullptr) { 2022cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov size_t soinfos_size = sizeof(soinfo*)*library_names_count; 2023cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size)); 2024cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov memset(soinfos, 0, soinfos_size); 202514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 202614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2027cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // list of libraries to link - see step 2. 2028cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov size_t soinfos_count = 0; 202914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 20304f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov auto scope_guard = make_scope_guard([&]() { 20314f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (LoadTask* t : load_tasks) { 203214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov LoadTask::deleter(t); 20334f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 20344f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov }); 203514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 20364f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov auto failure_guard = make_scope_guard([&]() { 20374f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // Housekeeping 2038bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo_unload(soinfos, soinfos_count); 203914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov }); 204014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2041b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov ZipArchiveCache zip_archive_cache; 2042b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 20434f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // Step 1: expand the list of load_tasks to include 20444f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // all DT_NEEDED libraries (do not load them just yet) 20454f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (size_t i = 0; i<load_tasks.size(); ++i) { 20464f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov LoadTask* task = load_tasks[i]; 20476865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov soinfo* needed_by = task->get_needed_by(); 2048edfc9f63a261994f2565492436607c04df980e21Dmitriy Ivanov 20494f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children); 20504f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov task->set_extinfo(is_dt_needed ? nullptr : extinfo); 20511005748da1ee257f4ba64a4ef1cae7ce05bdf946Dimitry Ivanov task->set_dt_needed(is_dt_needed); 2052b48275045de93cce292faaf5170af3ead89b3746Dmitriy Ivanov 205342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) { 205414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 205514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 205614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 20574f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov soinfo* si = task->get_soinfo(); 20584f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 2059edfc9f63a261994f2565492436607c04df980e21Dmitriy Ivanov if (is_dt_needed) { 206014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov needed_by->add_child(si); 206114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 206214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2063ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (si->is_linked()) { 2064ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->increment_ref_count(); 2065ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 2066ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2067cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // When ld_preloads is not null, the first 2068cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov // ld_preloads_count libs are in fact ld_preloads. 2069cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { 2070d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov ld_preloads->push_back(si); 207114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 207214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2073cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (soinfos_count < library_names_count) { 2074cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov soinfos[soinfos_count++] = si; 207514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 207614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 207714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 20784f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // Step 2: Load libraries in random order (see b/24047022) 20794f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov LoadTaskList load_list; 20804f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (auto&& task : load_tasks) { 20814f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov soinfo* si = task->get_soinfo(); 20824f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov auto pred = [&](const LoadTask* t) { 20834f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return t->get_soinfo() == si; 20844f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov }; 20854f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 20864f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (!si->is_linked() && 20874f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) { 20884f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov load_list.push_back(task); 20894f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 20904f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 20914f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov shuffle(&load_list); 20924f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 20934f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (auto&& task : load_list) { 20944f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (!task->load()) { 20954f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 20964f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 20974f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 20984f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 20994f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // Step 3: pre-link all DT_NEEDED libraries in breadth first order. 21004f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (auto&& task : load_tasks) { 21014f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov soinfo* si = task->get_soinfo(); 21024f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (!si->is_linked() && !si->prelink_image()) { 21034f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov return false; 21044f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 21054f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 21064f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 21074f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // Step 4: Add LD_PRELOADed libraries to the global group for 21084f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // future runs. There is no need to explicitly add them to 21094f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // the global group for this run because they are going to 21104f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // appear in the local group in the correct order. 21114f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (ld_preloads != nullptr) { 21124f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov for (auto&& si : *ld_preloads) { 21134f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); 21144f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 21154f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 21164f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 21174f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 21184f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov // Step 5: link libraries. 2119cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov soinfo::soinfo_list_t local_group; 2120cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov walk_dependencies_tree( 21210cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov (start_with != nullptr && add_as_children) ? &start_with : soinfos, 21220cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov (start_with != nullptr && add_as_children) ? 1 : soinfos_count, 2123cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov [&] (soinfo* si) { 2124cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov local_group.push_back(si); 2125cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 2126cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov }); 2127cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 2128ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // We need to increment ref_count in case 2129ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov // the root of the local group was not linked. 2130ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov bool was_local_group_root_linked = local_group.front()->is_linked(); 2131ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2132cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov bool linked = local_group.visit([&](soinfo* si) { 2133ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!si->is_linked()) { 2134047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (!si->link_image(global_group, local_group, extinfo)) { 213514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return false; 213614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 213714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 2138cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 2139cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return true; 2140cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov }); 2141cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov 2142cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov if (linked) { 2143bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov local_group.for_each([](soinfo* si) { 2144bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov if (!si->is_linked()) { 2145bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov si->set_linked(); 2146bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 2147bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov }); 2148bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov 2149cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov failure_guard.disable(); 2150a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov } 215114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2152ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!was_local_group_root_linked) { 2153ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group.front()->increment_ref_count(); 2154ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 2155ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2156cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov return linked; 215714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 215814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 215942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic soinfo* find_library(android_namespace_t* ns, 216042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const char* name, int rtld_flags, 21610cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov const android_dlextinfo* extinfo, 21620cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov soinfo* needed_by) { 216314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* si; 216414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2165ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (name == nullptr) { 2166ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si = somain; 216742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags, 21680cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov extinfo, /* add_as_children */ false)) { 216914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return nullptr; 217014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 217114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2172d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return si; 2173d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 2174d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 2175ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovstatic void soinfo_unload(soinfo* root) { 2176ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (root->is_linked()) { 2177ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov root = root->get_local_group_root(); 21781b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov } 21791b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov 2180ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!root->can_unload()) { 218138b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath()); 2182ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return; 2183ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 2184d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 2185bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo_unload(&root, 1); 2186bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov} 2187bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov 2188bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanovstatic void soinfo_unload(soinfo* soinfos[], size_t count) { 2189bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // Note that the library can be loaded but not linked; 2190bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // in which case there is no root but we still need 2191bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // to walk the tree and unload soinfos involved. 2192bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // 2193bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // This happens on unsuccessful dlopen, when one of 2194bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // the DT_NEEDED libraries could not be linked/found. 2195bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov if (count == 0) { 2196bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov return; 2197bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 2198ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2199bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo::soinfo_list_t unload_list; 2200bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov for (size_t i = 0; i < count; ++i) { 2201bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo* si = soinfos[i]; 2202ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 2203bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov if (si->can_unload()) { 2204bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov size_t ref_count = si->is_linked() ? si->decrement_ref_count() : 0; 2205bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov if (ref_count == 0) { 2206bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov unload_list.push_back(si); 2207bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } else { 2208bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov TRACE("not unloading '%s' group, decrementing ref_count to %zd", 2209bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov si->get_realpath(), ref_count); 22105ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov } 2211bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } else { 2212bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->get_realpath()); 2213bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov return; 2214bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 2215bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 22165ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov 2217bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // This is used to identify soinfos outside of the load-group 2218bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // note that we cannot have > 1 in the array and have any of them 2219bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // linked. This is why we can safely use the first one. 2220bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo* root = soinfos[0]; 22215ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov 2222bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo::soinfo_list_t local_unload_list; 2223bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo::soinfo_list_t external_unload_list; 2224bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo* si = nullptr; 22253edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov 2226bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov while ((si = unload_list.pop_front()) != nullptr) { 2227bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov if (local_unload_list.contains(si)) { 2228bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov continue; 2229bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 2230bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov 2231bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov local_unload_list.push_back(si); 2232bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov 2233bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov if (si->has_min_version(0)) { 2234bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo* child = nullptr; 2235bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov while ((child = si->get_children().pop_front()) != nullptr) { 2236bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si, 2237bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov child->get_realpath(), child); 2238bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov 2239bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov if (local_unload_list.contains(child)) { 2240bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov continue; 2241bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } else if (child->is_linked() && child->get_local_group_root() != root) { 2242bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov external_unload_list.push_back(child); 2243bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } else { 2244bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov unload_list.push_front(child); 2245d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 2246bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 2247bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } else { 2248280d54680d8842df5b0e37ec50acde48957d8e7aDmitriy Ivanov#if !defined(__work_around_b_24465209__) 2249bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si); 22505ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#else 2251bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si); 2252bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov for_each_dt_needed(si, [&] (const char* library_name) { 2253bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov TRACE("deprecated (old format of soinfo): %s needs to unload %s", 2254bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov si->get_realpath(), library_name); 2255bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov 2256bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo* needed = find_library(si->get_primary_namespace(), 2257bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov library_name, RTLD_NOLOAD, nullptr, nullptr); 2258bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov 2259bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov if (needed != nullptr) { 2260bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // Not found: for example if symlink was deleted between dlopen and dlclose 2261bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // Since we cannot really handle errors at this point - print and continue. 2262bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov PRINT("warning: couldn't find %s needed by %s on unload.", 2263bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov library_name, si->get_realpath()); 2264bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov return; 2265bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } else if (local_unload_list.contains(needed)) { 2266bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // already visited 2267bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov return; 2268bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } else if (needed->is_linked() && needed->get_local_group_root() != root) { 2269bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // external group 2270bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov external_unload_list.push_back(needed); 2271bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } else { 2272bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov // local group 2273bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov unload_list.push_front(needed); 2274bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 2275bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov }); 22765ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#endif 22771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 2278bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 22791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2280bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov local_unload_list.for_each([](soinfo* si) { 2281bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov si->call_destructors(); 2282bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov }); 22831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2284bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov while ((si = local_unload_list.pop_front()) != nullptr) { 2285bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov notify_gdb_of_unload(si); 2286bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo_free(si); 2287bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov } 2288a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov 2289bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov while ((si = external_unload_list.pop_front()) != nullptr) { 2290bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov soinfo_unload(si); 2291a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov } 2292a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov} 2293a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov 22944a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanovstatic std::string symbol_display_name(const char* sym_name, const char* sym_ver) { 22954a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (sym_ver == nullptr) { 22964a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return sym_name; 22974a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 22984a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 22999cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov return std::string(sym_name) + ", version " + sym_ver; 23004a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov} 23014a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 23020551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanovstatic android_namespace_t* get_caller_namespace(soinfo* caller) { 23030551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace; 23040551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov} 23050551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov 2306a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) { 2307052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // Use basic string manipulation calls to avoid snprintf. 2308052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf indirectly calls pthread_getspecific to get the size of a buffer. 2309052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // When debug malloc is enabled, this call returns 0. This in turn causes 2310052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf to do nothing, which causes libraries to fail to load. 2311052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // See b/17302493 for further details. 2312052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // Once the above bug is fixed, this code can be modified to use 2313052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris // snprintf again. 2314d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov size_t required_len = 0; 2315d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) { 2316d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov required_len += strlen(g_default_ld_paths[i]) + 1; 2317d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov } 2318052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris if (buffer_size < required_len) { 231920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: " 232020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov "buffer len %zu, required len %zu", buffer_size, required_len); 2321052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris } 2322d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov char* end = buffer; 2323d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) { 2324d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov if (i > 0) *end++ = ':'; 2325d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov end = stpcpy(end, g_default_ld_paths[i]); 2326d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov } 2327a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes} 2328a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes 2329cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { 23306bb01b6e6365ced7ca23c9ebecfaf1ea159d5ae2Nick Kralevich parse_LD_LIBRARY_PATH(ld_library_path); 2331cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes} 2332cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes 2333ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovvoid* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo, 23344a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov void* caller_addr) { 23354a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo* const caller = find_containing_library(caller_addr); 23364a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 23371b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) { 2338e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes DL_ERR("invalid flags to dlopen: %x", flags); 2339851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov return nullptr; 2340e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes } 234142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 23420551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov android_namespace_t* ns = get_caller_namespace(caller); 234342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 234407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if (extinfo != nullptr) { 234507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) { 234607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags); 234707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return nullptr; 234807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 2349126af757c6d6a6447c19236df8d98ba07f21996fDmitriy Ivanov 235007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 && 2351a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) { 235220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without " 235320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags); 235407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return nullptr; 235507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 2356126af757c6d6a6447c19236df8d98ba07f21996fDmitriy Ivanov 2357126af757c6d6a6447c19236df8d98ba07f21996fDmitriy Ivanov if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 && 2358126af757c6d6a6447c19236df8d98ba07f21996fDmitriy Ivanov (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) { 2359126af757c6d6a6447c19236df8d98ba07f21996fDmitriy Ivanov DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not " 2360126af757c6d6a6447c19236df8d98ba07f21996fDmitriy Ivanov "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT"); 2361126af757c6d6a6447c19236df8d98ba07f21996fDmitriy Ivanov return nullptr; 2362126af757c6d6a6447c19236df8d98ba07f21996fDmitriy Ivanov } 236342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 236442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) { 236542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (extinfo->library_namespace == nullptr) { 236642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null"); 236742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return nullptr; 236842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 236942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ns = extinfo->library_namespace; 237042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 2371012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles) } 2372279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 2373279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard guard; 237442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo* si = find_library(ns, name, flags, extinfo, caller); 2375851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (si != nullptr) { 2376047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->call_constructors(); 2377ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return si->to_handle(); 2378d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 237942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 2380ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return nullptr; 2381d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 23821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 23834a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanovint do_dladdr(const void* addr, Dl_info* info) { 23844a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov // Determine if this address can be found in any library currently mapped. 23854a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo* si = find_containing_library(addr); 23864a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (si == nullptr) { 23874a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return 0; 23884a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 23894a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 23904a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov memset(info, 0, sizeof(Dl_info)); 23914a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 23924a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov info->dli_fname = si->get_realpath(); 23934a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov // Address at which the shared object is loaded. 23944a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov info->dli_fbase = reinterpret_cast<void*>(si->base); 23954a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 23964a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov // Determine if any symbol in the library contains the specified address. 23974a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov ElfW(Sym)* sym = si->find_symbol_by_address(addr); 23984a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (sym != nullptr) { 23994a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov info->dli_sname = si->get_string(sym->st_name); 24004a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym)); 24014a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 24024a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24034a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return 1; 24044a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov} 24054a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 2406ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovstatic soinfo* soinfo_from_handle(void* handle) { 2407ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) { 2408ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle)); 2409ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov if (it == g_soinfo_handles_map.end()) { 2410ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return nullptr; 2411ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } else { 2412ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return it->second; 2413ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 2414ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 2415ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 2416ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return static_cast<soinfo*>(handle); 2417ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov} 2418ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 24194a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanovbool do_dlsym(void* handle, const char* sym_name, const char* sym_ver, 24204a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov void* caller_addr, void** symbol) { 24214a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov#if !defined(__LP64__) 24224a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (handle == nullptr) { 24234a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov DL_ERR("dlsym failed: library handle is null"); 24244a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return false; 24254a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 24264a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov#endif 24274a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24284a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (sym_name == nullptr) { 24294a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov DL_ERR("dlsym failed: symbol name is null"); 24304a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return false; 24314a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 24324a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24334a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo* found = nullptr; 24344a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov const ElfW(Sym)* sym = nullptr; 24354a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov soinfo* caller = find_containing_library(caller_addr); 24360551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov android_namespace_t* ns = get_caller_namespace(caller); 24374a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24384a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov version_info vi_instance; 24394a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov version_info* vi = nullptr; 24404a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24414a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (sym_ver != nullptr) { 24429cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov vi_instance.name = sym_ver; 24439cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov vi_instance.elf_hash = calculate_elf_hash(sym_ver); 24444a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov vi = &vi_instance; 24454a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 24464a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24474a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) { 24484a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle); 24494a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } else { 2450ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov soinfo* si = soinfo_from_handle(handle); 2451ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov if (si == nullptr) { 2452ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov DL_ERR("dlsym failed: invalid handle: %p", handle); 2453ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return false; 2454ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 2455ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov sym = dlsym_handle_lookup(si, &found, sym_name, vi); 24564a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 24574a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24584a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if (sym != nullptr) { 24594a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov uint32_t bind = ELF_ST_BIND(sym->st_info); 24604a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24614a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) { 24624a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym)); 24634a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return true; 24644a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 24654a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24664a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str()); 24674a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return false; 24684a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov } 24694a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 24704a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str()); 24714a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov return false; 24724a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov} 24734a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov 2474ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovint do_dlclose(void* handle) { 2475279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard guard; 2476ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov soinfo* si = soinfo_from_handle(handle); 2477ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov if (si == nullptr) { 2478ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov DL_ERR("invalid handle: %p", handle); 2479ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return -1; 2480ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 2481ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 2482b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov soinfo_unload(si); 2483ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return 0; 24841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 24851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 24861ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanovbool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) { 24871ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov CHECK(public_ns_sonames != nullptr); 248842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (g_public_namespace_initialized) { 24891ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov DL_ERR("public namespace has already been initialized."); 249042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return false; 249142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 249242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 24931ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":"); 249442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 249542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ProtectedDataGuard guard; 249642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 249742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov auto failure_guard = make_scope_guard([&]() { 249842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_public_namespace.clear(); 249942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov }); 250042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 250142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov for (const auto& soname : sonames) { 25023cc35e224c6fe6bb82685ff8b2758553563e2a05Dmitriy Ivanov soinfo* candidate = nullptr; 25033cc35e224c6fe6bb82685ff8b2758553563e2a05Dmitriy Ivanov 25043cc35e224c6fe6bb82685ff8b2758553563e2a05Dmitriy Ivanov find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate); 25053cc35e224c6fe6bb82685ff8b2758553563e2a05Dmitriy Ivanov 25063cc35e224c6fe6bb82685ff8b2758553563e2a05Dmitriy Ivanov if (candidate == nullptr) { 25071ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov DL_ERR("error initializing public namespace: \"%s\" was not found" 250842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov " in the default namespace", soname.c_str()); 250942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return false; 251042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 251142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 251242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov candidate->set_nodelete(); 251342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_public_namespace.push_back(candidate); 251442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 251542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 251642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_public_namespace_initialized = true; 25171ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov 25181ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov // create anonymous namespace 25197331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov // When the caller is nullptr - create_namespace will take global group 25207331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov // from the anonymous namespace, which is fine because anonymous namespace 25217331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov // is still pointing to the default one. 25221ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov android_namespace_t* anon_ns = 25237331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path, 25243c9624a2687a93db087544f2a2c53374bdb20bccDimitry Ivanov ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace); 25251ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov 25261ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov if (anon_ns == nullptr) { 25271ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov g_public_namespace_initialized = false; 25281ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov return false; 25291ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov } 25301ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov g_anonymous_namespace = anon_ns; 25311ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov failure_guard.disable(); 253242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return true; 253342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov} 253442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 25357331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanovandroid_namespace_t* create_namespace(const void* caller_addr, 25367331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov const char* name, 253742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const char* ld_library_path, 253842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov const char* default_library_path, 25397331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov uint64_t type, 254049cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov const char* permitted_when_isolated_path, 254149cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov android_namespace_t* parent_namespace) { 254242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (!g_public_namespace_initialized) { 25431ffec1cc4d0e283bb1ff6f49843769a3493b8d73Dmitriy Ivanov DL_ERR("cannot create namespace: public namespace is not initialized."); 254442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return nullptr; 254542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 254642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 254749cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov if (parent_namespace == nullptr) { 25483c9624a2687a93db087544f2a2c53374bdb20bccDimitry Ivanov // if parent_namespace is nullptr -> set it to the caller namespace 25493c9624a2687a93db087544f2a2c53374bdb20bccDimitry Ivanov soinfo* caller_soinfo = find_containing_library(caller_addr); 25503c9624a2687a93db087544f2a2c53374bdb20bccDimitry Ivanov 25513c9624a2687a93db087544f2a2c53374bdb20bccDimitry Ivanov parent_namespace = caller_soinfo != nullptr ? 25523c9624a2687a93db087544f2a2c53374bdb20bccDimitry Ivanov caller_soinfo->get_primary_namespace() : 25533c9624a2687a93db087544f2a2c53374bdb20bccDimitry Ivanov g_anonymous_namespace; 255449cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov } 255549cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov 255642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ProtectedDataGuard guard; 255742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string> ld_library_paths; 255842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string> default_library_paths; 2559284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov std::vector<std::string> permitted_paths; 256042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 256142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov parse_path(ld_library_path, ":", &ld_library_paths); 256242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov parse_path(default_library_path, ":", &default_library_paths); 2563284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov parse_path(permitted_when_isolated_path, ":", &permitted_paths); 256442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 256542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t(); 256642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ns->set_name(name); 25677331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0); 256842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ns->set_ld_library_paths(std::move(ld_library_paths)); 256942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ns->set_default_library_paths(std::move(default_library_paths)); 2570284ae3559ed909613b189b98bdc3efab94373a30Dimitry Ivanov ns->set_permitted_paths(std::move(permitted_paths)); 257142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 25727331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) { 257349cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov // If shared - clone the parent namespace 257449cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov ns->add_soinfos(parent_namespace->soinfo_list()); 25757331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov } else { 257649cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov // If not shared - copy only the shared group 257749cfc899a3708fae9175e44c0c02cd479fda8b36Dimitry Ivanov ns->add_soinfos(get_shared_group(parent_namespace)); 25787331fe18d7ffd550996e07b534bc7a6cf625afa5Dimitry Ivanov } 257942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 258042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return ns; 258142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov} 258242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 25839aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanovstatic ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) { 25849aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov typedef ElfW(Addr) (*ifunc_resolver_t)(void); 25859aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr); 25869aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov ElfW(Addr) ifunc_addr = ifunc_resolver(); 258720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", 258820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ifunc_resolver, reinterpret_cast<void*>(ifunc_addr)); 2589c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 25909aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return ifunc_addr; 2591c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith} 2592c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 25932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const { 25942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (source_symver < 2 || 25952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov source_symver >= version_infos.size() || 25962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos[source_symver].name == nullptr) { 25972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return nullptr; 25982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 25992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return &version_infos[source_symver]; 26012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 26022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovvoid VersionTracker::add_version_info(size_t source_index, 26042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ElfW(Word) elf_hash, 26052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const char* ver_name, 26062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const soinfo* target_si) { 26072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (source_index >= version_infos.size()) { 26082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos.resize(source_index+1); 26092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 26102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos[source_index].elf_hash = elf_hash; 26122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos[source_index].name = ver_name; 26132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov version_infos[source_index].target_si = target_si; 26142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 26152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init_verneed(const soinfo* si_from) { 26172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov uintptr_t verneed_ptr = si_from->get_verneed_ptr(); 26182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verneed_ptr == 0) { 26202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 26212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 26222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t verneed_cnt = si_from->get_verneed_cnt(); 26242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) { 26262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset); 26272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov size_t vernaux_offset = offset + verneed->vn_aux; 26282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov offset += verneed->vn_next; 26292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (verneed->vn_version != 1) { 26312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version); 26322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 26332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 26342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const char* target_soname = si_from->get_string(verneed->vn_file); 26362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov // find it in dependencies 26372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) { 2638406d99665c71cf95af278c3244eb80745daaa0eaDmitriy Ivanov return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0; 26392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov }); 26402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (target_si == nullptr) { 26422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"", 26433edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov target_soname, i, si_from->get_realpath()); 26442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 26452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 26462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov for (size_t j = 0; j<verneed->vn_cnt; ++j) { 26482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset); 26492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov vernaux_offset += vernaux->vna_next; 26502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Word) elf_hash = vernaux->vna_hash; 26522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const char* ver_name = si_from->get_string(vernaux->vna_name); 26532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ElfW(Half) source_index = vernaux->vna_other; 26542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov add_version_info(source_index, elf_hash, ver_name, target_si); 26562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 26572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 26582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 26602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 26612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init_verdef(const soinfo* si_from) { 26632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return for_each_verdef(si_from, 26642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) { 26652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov add_version_info(verdef->vd_ndx, verdef->vd_hash, 26662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov si_from->get_string(verdaux->vda_name), si_from); 26672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return false; 26682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 26692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov ); 26702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 26712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init(const soinfo* si_from) { 26732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (!si_from->has_min_version(2)) { 26742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return true; 26752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 26762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 26772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return init_verneed(si_from) && init_verdef(si_from); 26782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 26792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 268031b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanovbool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym, 268131b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov const char* sym_name, const version_info** vi) { 268231b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov const ElfW(Versym)* sym_ver_ptr = get_versym(sym); 268331b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr; 268431b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov 268531b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) { 268631b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov *vi = version_tracker.get_version_info(sym_ver); 268731b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov 268831b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov if (*vi == nullptr) { 268931b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov DL_ERR("cannot find verneed/verdef for version index=%d " 26903edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath()); 269131b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov return false; 269231b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov } 269331b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov } else { 269431b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov // there is no version info 269531b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov *vi = nullptr; 269631b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov } 269731b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov 269831b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov return true; 269931b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov} 270031b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov 2701bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#if !defined(__mips__) 27024eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 2703bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanovstatic ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) { 2704bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov return rela->r_addend; 2705bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov} 2706bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#else 2707bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanovstatic ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) { 270820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE || 270920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) { 2710bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov return *reinterpret_cast<ElfW(Addr)*>(reloc_addr); 2711bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov } 2712bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov return 0; 2713bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov} 2714bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#endif 2715bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov 2716fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanovtemplate<typename ElfRelIteratorT> 27177e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanovbool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator, 27187e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov const soinfo_list_t& global_group, const soinfo_list_t& local_group) { 2719fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov for (size_t idx = 0; rel_iterator.has_next(); ++idx) { 2720fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov const auto rel = rel_iterator.next(); 272118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (rel == nullptr) { 272218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 272318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 272418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 2725bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov ElfW(Word) type = ELFW(R_TYPE)(rel->r_info); 2726bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov ElfW(Word) sym = ELFW(R_SYM)(rel->r_info); 2727bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov 2728bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias); 27290266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) sym_addr = 0; 2730851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov const char* sym_name = nullptr; 2731bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov ElfW(Addr) addend = get_addend(rel, reloc); 2732c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 273338b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx); 2734cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov if (type == R_GENERIC_NONE) { 2735c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes continue; 2736c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 273714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 27382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov const ElfW(Sym)* s = nullptr; 273914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov soinfo* lsi = nullptr; 274014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 2741c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (sym != 0) { 2742047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov sym_name = get_string(symtab_[sym].st_name); 274331b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov const version_info* vi = nullptr; 27442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 274531b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) { 274631b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov return false; 274731b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov } 27482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 274931b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) { 275031b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov return false; 27512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 275231b408d2c2e070c35838e7859ca4a4e5eb0c45fcDmitriy Ivanov 2753851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (s == nullptr) { 2754c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes // We only allow an undefined symbol if this is a weak reference... 2755047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov s = &symtab_[sym]; 2756c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes if (ELF_ST_BIND(s->st_info) != STB_WEAK) { 27573edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath()); 2758114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 2759c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 2760c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 2761c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes /* IHI0044C AAELF 4.5.1.1: 2762c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 2763c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes Libraries are not searched to resolve weak references. 2764c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes It is not an error for a weak reference to remain unsatisfied. 2765c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 2766c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes During linking, the value of an undefined weak reference is: 2767c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - Zero if the relocation type is absolute 2768c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - The address of the place if the relocation is pc-relative 2769c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes - The address of nominal base address if the relocation 2770c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes type is base-relative. 2771c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes */ 2772c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 2773c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 27741b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_GENERIC_JUMP_SLOT: 27751b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_GENERIC_GLOB_DAT: 27761b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_GENERIC_RELATIVE: 27771b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_GENERIC_IRELATIVE: 2778e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__) 27796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 27806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 27816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS16: 27821b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#elif defined(__x86_64__) 27831b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_X86_64_32: 27841b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov case R_X86_64_64: 2785bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__) 2786bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov case R_ARM_ABS32: 2787bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__i386__) 2788bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov case R_386_32: 27891b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#endif 27906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 27916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * The sym_addr was initialized to be zero above, or the relocation 27926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * code below does not care about value of sym_addr. 27936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * No need to do anything. 27946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 27956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 27961b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#if defined(__x86_64__) 2797d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov case R_X86_64_PC32: 2798d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov sym_addr = reloc; 2799d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov break; 2800bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__i386__) 2801bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov case R_386_PC32: 2802bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov sym_addr = reloc; 2803bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov break; 2804bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#endif 28056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 2806bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx); 2807114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 2808c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 2809ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } else { // We got a definition. 2810ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov#if !defined(__LP64__) 2811ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov // When relocating dso with text_relocation .text segment is 2812ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov // not executable. We need to restore elf flags before resolving 2813ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov // STT_GNU_IFUNC symbol. 2814ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov bool protect_segments = has_text_relocations && 2815ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov lsi == this && 2816ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC; 2817ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov if (protect_segments) { 2818ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 2819ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov DL_ERR("can't protect segments for \"%s\": %s", 2820ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov get_realpath(), strerror(errno)); 2821ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov return false; 2822ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2823ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2824ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov#endif 28259aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov sym_addr = lsi->resolve_symbol_address(s); 2826ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov#if !defined(__LP64__) 2827ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov if (protect_segments) { 2828ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 2829ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 2830ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov get_realpath(), strerror(errno)); 2831ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov return false; 2832ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2833ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2834ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov#endif 2835c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 2836c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes count_relocation(kRelocSymbol); 2837c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 2838c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes 2839c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes switch (type) { 2840cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_JUMP_SLOT: 2841e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 2842bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 2843bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n", 2844bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 2845bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(sym_addr + addend), sym_name); 2846bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov 2847bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend); 2848e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 2849cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_GLOB_DAT: 2850e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 2851bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 2852bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n", 2853bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 2854bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(sym_addr + addend), sym_name); 2855bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend); 2856e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 2857cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_RELATIVE: 2858cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov count_relocation(kRelocRelative); 2859bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 2860bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n", 2861bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 286218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reinterpret_cast<void*>(load_bias + addend)); 286318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend); 2864cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov break; 2865cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov case R_GENERIC_IRELATIVE: 2866cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov count_relocation(kRelocRelative); 2867bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 2868bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n", 2869bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reinterpret_cast<void*>(reloc), 287018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reinterpret_cast<void*>(load_bias + addend)); 2871ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov { 2872ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov#if !defined(__LP64__) 2873ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov // When relocating dso with text_relocation .text segment is 2874ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov // not executable. We need to restore elf flags for this 2875ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov // particular call. 2876ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov if (has_text_relocations) { 2877ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 2878ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov DL_ERR("can't protect segments for \"%s\": %s", 2879ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov get_realpath(), strerror(errno)); 2880ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov return false; 2881ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2882ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2883ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov#endif 2884ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend); 2885ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov#if !defined(__LP64__) 2886ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov // Unprotect it afterwards... 2887ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov if (has_text_relocations) { 2888ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 2889ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 2890ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov get_realpath(), strerror(errno)); 2891ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov return false; 2892ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2893ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2894ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov#endif 2895ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr; 2896ec83a61c8b5e00c67c35c9b8f72031c55e7868b9Dmitriy Ivanov } 2897cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov break; 2898cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov 2899cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if defined(__aarch64__) 29006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS64: 2901e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 2902bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 29030266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n", 290477f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov reloc, sym_addr + addend, sym_name); 290577f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend; 2906e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 29076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS32: 2908e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 2909bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 29100266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n", 291177f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov reloc, sym_addr + addend, sym_name); 291220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 291320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN); 291420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX); 291577f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov if ((min_value <= (sym_addr + addend)) && 291677f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov ((sym_addr + addend) <= max_value)) { 291777f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend; 291820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 291920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 292077f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov sym_addr + addend, min_value, max_value); 292120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 292220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2923e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2924e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 29256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_ABS16: 2926e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocAbsolute); 2927bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 29280266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n", 292977f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov reloc, sym_addr + addend, sym_name); 293020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 293120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN); 293220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX); 293377f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov if ((min_value <= (sym_addr + addend)) && 293477f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov ((sym_addr + addend) <= max_value)) { 293577f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend); 293620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 293720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 293877f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov sym_addr + addend, min_value, max_value); 293920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 294020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2941e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2942e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 29436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL64: 2944e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2945bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 29460266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n", 294777f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov reloc, sym_addr + addend, rel->r_offset, sym_name); 294877f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset; 2949e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 29506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL32: 2951e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2952bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 29530266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n", 295477f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov reloc, sym_addr + addend, rel->r_offset, sym_name); 295520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 295620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN); 295720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX); 295877f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov if ((min_value <= (sym_addr + addend - rel->r_offset)) && 295977f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov ((sym_addr + addend - rel->r_offset) <= max_value)) { 296077f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset; 296120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 296220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 296377f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov sym_addr + addend - rel->r_offset, min_value, max_value); 296420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 296520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2966e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2967e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 29686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_PREL16: 2969e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland count_relocation(kRelocRelative); 2970bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 29710266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n", 297277f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov reloc, sym_addr + addend, rel->r_offset, sym_name); 297320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov { 297420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN); 297520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX); 297677f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov if ((min_value <= (sym_addr + addend - rel->r_offset)) && 297777f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov ((sym_addr + addend - rel->r_offset) <= max_value)) { 297877f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset; 297920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else { 298020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", 298177f91c6d99c25fce4fbf9704aa6f7232fb624ff4Dmitriy Ivanov sym_addr + addend - rel->r_offset, min_value, max_value); 298220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return false; 298320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 2984e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland } 2985e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 2986e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland 29876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_COPY: 298876e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich /* 298976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * ET_EXEC is not supported so this should not happen. 299076e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 2991aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf 299276e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * 2993aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * Section 4.6.11 "Dynamic relocations" 299476e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * R_AARCH64_COPY may only appear in executable objects where e_type is 299576e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich * set to ET_EXEC. 299676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich */ 29973edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath()); 2998114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 29996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_TPREL64: 30000266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", 3001bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset); 3002e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 30036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_AARCH64_TLS_DTPREL32: 30040266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n", 3005bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov reloc, (sym_addr + addend), rel->r_offset); 3006e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland break; 3007e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__) 30086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_32: 30096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 3010bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 30116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 30126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 3013ff35b1e659547644fb14f890eeec880cf4bafc4eJunichi Uekawa *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend; 30146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 30156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_64: 30166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 3017bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 30186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc), 30196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), sym_name); 3020ff35b1e659547644fb14f890eeec880cf4bafc4eJunichi Uekawa *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend; 30216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 30226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_X86_64_PC32: 30236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 3024bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov MARK(rel->r_offset); 30256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", 30266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc), 30276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name); 3028ff35b1e659547644fb14f890eeec880cf4bafc4eJunichi Uekawa *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc; 30296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3030bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__) 30316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_ABS32: 30326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocAbsolute); 30336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 30346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name); 30356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 30366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 30376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_REL32: 30386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 30396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 30406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s", 30416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, sym_addr, rel->r_offset, sym_name); 30426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset; 30436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 30446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_ARM_COPY: 30456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* 30466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * ET_EXEC is not supported so this should not happen. 30476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 30486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf 30496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * 3050aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov * Section 4.6.1.10 "Dynamic relocations" 30516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * R_ARM_COPY may only appear in executable objects where e_type is 30526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * set to ET_EXEC. 30536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 30543edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath()); 3055114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov return false; 30564eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__) 30576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_32: 30586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 30596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 30606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name); 30616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; 30626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 30636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case R_386_PC32: 30646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count_relocation(kRelocRelative); 30656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov MARK(rel->r_offset); 30666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s", 30676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov reloc, (sym_addr - reloc), sym_addr, reloc, sym_name); 30686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc); 30696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 30704eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 30716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 30726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx); 30736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 3074d7daacb46372132ae3f0121647074936c304b572Raghu Gandham } 30756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 30766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 3077d7daacb46372132ae3f0121647074936c304b572Raghu Gandham} 3078114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#endif // !defined(__mips__) 3079d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 308020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid soinfo::call_array(const char* array_name __unused, linker_function_t* functions, 308120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov size_t count, bool reverse) { 3082851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (functions == nullptr) { 3083d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 3084d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 30858215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 308638b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes TRACE("[ Calling %s (size %zd) @ %p for \"%s\" ]", array_name, count, functions, get_realpath()); 30878215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 3088ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int begin = reverse ? (count - 1) : 0; 3089ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int end = reverse ? -1 : count; 3090ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes int step = reverse ? -1 : 1; 30918215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 3092ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes for (int i = begin; i != end; i += step) { 3093ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]); 3094047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("function", functions[i]); 3095d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 3096d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 309738b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes TRACE("[ Done calling %s for \"%s\" ]", array_name, get_realpath()); 30981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 30991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3100047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_function(const char* function_name __unused, linker_function_t function) { 3101851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) { 3102d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 3103d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 3104d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 310538b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes TRACE("[ Calling %s @ %p for \"%s\" ]", function_name, function, get_realpath()); 3106d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes function(); 310738b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes TRACE("[ Done calling %s @ %p for \"%s\" ]", function_name, function, get_realpath()); 31089181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov} 31099181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 3110047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_pre_init_constructors() { 31118147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_PREINIT_ARRAY functions are called before any other constructors for executables, 31128147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // but ignored in a shared library. 3113047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false); 3114d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes} 3115e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 3116047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_constructors() { 3117d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes if (constructors_called) { 3118d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes return; 3119d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 3120e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 3121d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // We set constructors_called before actually calling the constructors, otherwise it doesn't 3122d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // protect against recursive constructor calls. One simple example of constructor recursion 3123d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so: 3124d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 1. The program depends on libc, so libc's constructor is called here. 3125d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so. 3126d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 3. dlopen() calls the constructors on the newly created 3127d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // soinfo for libc_malloc_debug_leak.so. 3128d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // 4. The debug .so depends on libc, so CallConstructors is 3129d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // called again with the libc soinfo. If it doesn't trigger the early- 3130d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes // out above, the libc constructor will be called again (recursively!). 3131d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes constructors_called = true; 3132d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes 3133ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!is_main_executable() && preinit_array_ != nullptr) { 31348147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // The GNU dynamic linker silently ignores these, but we warn the developer. 3135bee8572ca373f626ebe6cbcdd490808c054feb49Dimitry Ivanov PRINT("\"%s\": ignoring DT_PREINIT_ARRAY in shared library!", get_realpath()); 3136d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes } 31371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3138d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov get_children().for_each([] (soinfo* si) { 3139047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->call_constructors(); 3140d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 31411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 31423edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov TRACE("\"%s\": calling constructors", get_realpath()); 31438147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 31448147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_INIT should be called before DT_INIT_ARRAY if both are present. 3145047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("DT_INIT", init_func_); 3146047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false); 3147e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov} 31488215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner 3149047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_destructors() { 315014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov if (!constructors_called) { 315114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov return; 315214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 31533edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov TRACE("\"%s\": calling destructors", get_realpath()); 31548147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 31558147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI_ARRAY must be parsed in reverse order. 3156047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true); 31578147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes 31588147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes // DT_FINI should be called after DT_FINI_ARRAY if both are present. 3159047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov call_function("DT_FINI", fini_func_); 3160b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov 3161b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // This is needed on second call to dlopen 3162b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov // after library has been unloaded with RTLD_NODELETE 3163b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov constructors_called = false; 31641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 31651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3166d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) { 31670d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 3168047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov child->parents_.push_back(this); 3169047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov this->children_.push_back(child); 3170d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 3171d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 3172d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3173d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() { 31740d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (!has_min_version(0)) { 3175d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return; 3176d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 3177d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3178d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov // 1. Untie connected soinfos from 'this'. 3179047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov children_.for_each([&] (soinfo* child) { 3180047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov child->parents_.remove_if([&] (const soinfo* parent) { 3181d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return parent == this; 3182d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 3183d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 3184d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3185047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parents_.for_each([&] (soinfo* parent) { 3186047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parent->children_.remove_if([&] (const soinfo* child) { 3187d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov return child == this; 3188d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 3189d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov }); 3190d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 31910551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov // 2. Remove from the primary namespace 31920551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov primary_namespace_->remove_soinfo(this); 31930551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov primary_namespace_ = nullptr; 31940551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov 31950551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov // 3. Remove from secondary namespaces 31960551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov secondary_namespaces_.for_each([&](android_namespace_t* ns) { 31970551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov ns->remove_soinfo(this); 31980551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov }); 31990551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov 32000551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov 32010551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov // 4. Once everything untied - clear local lists. 3202047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov parents_.clear(); 3203047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov children_.clear(); 32040551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov secondary_namespaces_.clear(); 3205d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 3206d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3207d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovdev_t soinfo::get_st_dev() const { 32080d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 3209047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return st_dev_; 3210d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 3211d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 32120d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 3213d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}; 3214d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3215d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovino_t soinfo::get_st_ino() const { 32160d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 3217047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return st_ino_; 3218d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 3219d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 32200d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return 0; 3221d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 3222d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3223d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovoff64_t soinfo::get_file_offset() const { 322407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov if (has_min_version(1)) { 3225047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return file_offset_; 322607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov } 322707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 322807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov return 0; 322907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov} 323007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov 3231d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_rtld_flags() const { 3232e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov if (has_min_version(1)) { 3233047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return rtld_flags_; 3234e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov } 3235e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 3236e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov return 0; 3237e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov} 3238e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov 3239d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_dt_flags_1() const { 3240d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (has_min_version(1)) { 3241047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return dt_flags_1_; 3242d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 3243d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 3244d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov return 0; 3245d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov} 3246618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov 3247d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovvoid soinfo::set_dt_flags_1(uint32_t dt_flags_1) { 3248d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if (has_min_version(1)) { 3249d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((dt_flags_1 & DF_1_GLOBAL) != 0) { 3250047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rtld_flags_ |= RTLD_GLOBAL; 3251d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 3252d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 3253d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((dt_flags_1 & DF_1_NODELETE) != 0) { 3254047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rtld_flags_ |= RTLD_NODELETE; 3255d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 3256d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 3257047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov dt_flags_1_ = dt_flags_1; 3258d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov } 3259d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov} 3260d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 326142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovvoid soinfo::set_nodelete() { 326242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov rtld_flags_ |= RTLD_NODELETE; 326342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov} 326442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 3265aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_realpath() const { 3266280d54680d8842df5b0e37ec50acde48957d8e7aDmitriy Ivanov#if defined(__work_around_b_24465209__) 3267aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov if (has_min_version(2)) { 3268aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return realpath_.c_str(); 3269aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } else { 3270aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return old_name_; 3271aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov } 3272aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else 3273aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return realpath_.c_str(); 3274aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif 3275aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov} 3276aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 32774f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanovvoid soinfo::set_soname(const char* soname) { 32784f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov#if defined(__work_around_b_24465209__) 32794f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov if (has_min_version(2)) { 32804f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov soname_ = soname; 32814f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov } 32824f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov strlcpy(old_name_, soname_, sizeof(old_name_)); 32834f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov#else 32844f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov soname_ = soname; 32854f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov#endif 32864f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov} 32874f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov 3288aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_soname() const { 3289280d54680d8842df5b0e37ec50acde48957d8e7aDmitriy Ivanov#if defined(__work_around_b_24465209__) 3290618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov if (has_min_version(2)) { 3291618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov return soname_; 3292618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov } else { 3293aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return old_name_; 3294618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov } 3295aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else 3296aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov return soname_; 3297aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif 3298618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov} 3299618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov 330014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if 3301d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set. 3302d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list; 3303d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 3304d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() { 33050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov if (has_min_version(0)) { 3306047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return children_; 3307d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov } 3308d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 33090d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov return g_empty_list; 3310d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 3311d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 33122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst soinfo::soinfo_list_t& soinfo::get_children() const { 33132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov if (has_min_version(0)) { 33142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return children_; 33152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov } 33162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 33172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov return g_empty_list; 33182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov} 33192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 332014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() { 3321047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (has_min_version(0)) { 3322047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return parents_; 332314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov } 332414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 3325047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return g_empty_list; 332614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 332714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 33286865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanovstatic std::vector<std::string> g_empty_runpath; 33296865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov 33306865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanovconst std::vector<std::string>& soinfo::get_dt_runpath() const { 333142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (has_min_version(3)) { 33326865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov return dt_runpath_; 33336865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov } 33346865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov 33356865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov return g_empty_runpath; 33366865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov} 33376865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov 33380551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanovandroid_namespace_t* soinfo::get_primary_namespace() { 333942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (has_min_version(3)) { 33400551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov return primary_namespace_; 334142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 334242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 334342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov return &g_default_namespace; 334442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov} 334542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 33460551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanovvoid soinfo::add_secondary_namespace(android_namespace_t* secondary_ns) { 33470551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov CHECK(has_min_version(3)); 33480551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov secondary_namespaces_.push_back(secondary_ns); 33490551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov} 33500551c1d47bad202ce6dd90757067bc0fd217497aDimitry Ivanov 33512a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const { 33529aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { 33539aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return call_ifunc_resolver(s->st_value + load_bias); 33549aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov } 33559aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 33569aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov return static_cast<ElfW(Addr)>(s->st_value + load_bias); 33579aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov} 33589aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov 33596cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanovconst char* soinfo::get_string(ElfW(Word) index) const { 3360047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (has_min_version(1) && (index >= strtab_size_)) { 3361aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", 33623edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov get_realpath(), strtab_size_, index); 33636cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 33646cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 3365047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov return strtab_ + index; 33666cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov} 33676cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 3368ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovbool soinfo::is_gnu_hash() const { 3369ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_GNU_HASH) != 0; 3370ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov} 3371ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 33721b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanovbool soinfo::can_unload() const { 337379abce42146b27d523f309e0a1bc9f50175191cbDimitry Ivanov return !is_linked() || ((get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0); 33741b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov} 3375d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 3376ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_linked() const { 3377ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_LINKED) != 0; 3378ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 3379ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 3380ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_main_executable() const { 3381ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return (flags_ & FLAG_EXE) != 0; 3382ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 3383ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 33849acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanovbool soinfo::is_linker() const { 33859acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov return (flags_ & FLAG_LINKER) != 0; 33869acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov} 33879acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov 3388ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linked() { 3389ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_LINKED; 3390ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 3391ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 3392ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linker_flag() { 3393ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_LINKER; 3394ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 3395ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 3396ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_main_executable() { 3397ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_EXE; 3398ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 3399ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 3400ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::increment_ref_count() { 3401ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_->ref_count_++; 3402ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 3403ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 3404ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsize_t soinfo::decrement_ref_count() { 3405ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return --local_group_root_->ref_count_; 3406ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 3407ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 3408ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsoinfo* soinfo::get_local_group_root() const { 3409ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov return local_group_root_; 3410ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov} 3411ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 3412f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov 3413f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanovvoid soinfo::set_mapped_by_caller(bool mapped_by_caller) { 3414f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov if (mapped_by_caller) { 3415f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov flags_ |= FLAG_MAPPED_BY_CALLER; 3416f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov } else { 3417f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov flags_ &= ~FLAG_MAPPED_BY_CALLER; 3418f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov } 3419f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov} 3420f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov 3421f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanovbool soinfo::is_mapped_by_caller() const { 3422f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov return (flags_ & FLAG_MAPPED_BY_CALLER) != 0; 3423f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov} 3424f45b0e9edee72e97106c4b3d393b9bf1582303b3Dimitry Ivanov 34251913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov// This function returns api-level at the time of 34261913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov// dlopen/load. Note that libraries opened by system 34271913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov// will always have 'current' api level. 34281913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanovuint32_t soinfo::get_target_sdk_version() const { 34291913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov if (!has_min_version(2)) { 34301913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov return __ANDROID_API__; 34311913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov } 34321913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov 34331913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov return local_group_root_->target_sdk_version_; 34341913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov} 34351913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov 3436ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovuintptr_t soinfo::get_handle() const { 3437ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov CHECK(has_min_version(3)); 3438ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov CHECK(handle_ != 0); 3439ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return handle_; 3440ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov} 3441ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 3442ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovvoid* soinfo::to_handle() { 3443ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov if (get_application_target_sdk_version() <= 23 || !has_min_version(3)) { 3444ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return this; 3445ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } 3446ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 3447ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov return reinterpret_cast<void*>(get_handle()); 3448ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov} 3449ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 3450ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanovvoid soinfo::generate_handle() { 3451ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov CHECK(has_min_version(3)); 3452ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov CHECK(handle_ == 0); // Make sure this is the first call 3453ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 3454ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov // Make sure the handle is unique and does not collide 3455ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov // with special values which are RTLD_DEFAULT and RTLD_NEXT. 3456ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov do { 3457ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov arc4random_buf(&handle_, sizeof(handle_)); 3458ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov // the least significant bit for the handle is always 1 3459ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov // making it easy to test the type of handle passed to 3460ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov // dl* functions. 3461ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov handle_ = handle_ | 1; 3462ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov } while (handle_ == reinterpret_cast<uintptr_t>(RTLD_DEFAULT) || 3463ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov handle_ == reinterpret_cast<uintptr_t>(RTLD_NEXT) || 3464ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov g_soinfo_handles_map.find(handle_) != g_soinfo_handles_map.end()); 3465ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 3466ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov g_soinfo_handles_map[handle_] = this; 3467ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov} 3468ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov 3469047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovbool soinfo::prelink_image() { 3470e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian /* Extract dynamic section */ 3471e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian ElfW(Word) dynamic_flags = 0; 3472e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags); 3473498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov 34746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* We can't log anything until the linker is relocated */ 3475ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov bool relocating_linker = (flags_ & FLAG_LINKER) != 0; 34766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 347738b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes INFO("[ Linking \"%s\" ]", get_realpath()); 3478ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_); 34796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 34806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov 34816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (dynamic == nullptr) { 3482b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner if (!relocating_linker) { 34833edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath()); 3484b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner } 34856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 34866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else { 34876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (!relocating_linker) { 34886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("dynamic = %p", dynamic); 348963f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner } 34906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 349163f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 34924eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__) 34936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, 34946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov &ARM_exidx, &ARM_exidx_count); 349563f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif 349663f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner 34976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract useful information from dynamic section. 3498618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // Note that: "Except for the DT_NULL element at the end of the array, 3499618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // and the relative order of DT_NEEDED elements, entries may appear in any order." 3500618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // 3501618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html 35026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov uint32_t needed_count = 0; 35036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { 35046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", 35056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 35066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov switch (d->d_tag) { 35074a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SONAME: 3508618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov // this is parsed after we have strtab initialized (see below). 35094a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 3510ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_HASH: 3512047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 3513047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 3514047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8); 3515047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4); 35166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3517ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 3518ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov case DT_GNU_HASH: 35193597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; 3520ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // skip symndx 3521047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2]; 3522047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3]; 3523ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 3524047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16); 35253597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_); 3526ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov // amend chain for symndx = header[1] 352720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov gnu_chain_ = gnu_bucket_ + gnu_nbucket_ - 352820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; 3529ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 3530047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (!powerof2(gnu_maskwords_)) { 353120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two", 3532aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov gnu_maskwords_, get_realpath()); 3533ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov return false; 3534ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov } 3535047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov --gnu_maskwords_; 3536ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 3537ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov flags_ |= FLAG_GNU_HASH; 3538ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov break; 3539ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov 35406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_STRTAB: 3541047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr); 35426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3543ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35446cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov case DT_STRSZ: 3545047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov strtab_size_ = d->d_un.d_val; 35466cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov break; 3547ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMTAB: 3549047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr); 35506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3551ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35524a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_SYMENT: 35534a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Sym))) { 3554aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("invalid DT_SYMENT: %zd in \"%s\"", 3555aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov static_cast<size_t>(d->d_un.d_val), get_realpath()); 35564a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 35574a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 35584a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 3559ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTREL: 3561513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#if defined(USE_RELA) 3562513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov if (d->d_un.d_val != DT_RELA) { 3563aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath()); 3564513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov return false; 3565513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov } 3566513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#else 35676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val != DT_REL) { 3568aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath()); 35696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 35706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3571c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 3572513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov break; 3573ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_JMPREL: 35754eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 3576047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 3577c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 3578047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 3579c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 35806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3581ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTRELSZ: 35834eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 3584047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela)); 3585c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 3586047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel)); 3587c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 35886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3589ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PLTGOT: 35914a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__) 35926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Used by mips and mips64. 3593047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr); 3594c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 35954a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov // Ignore for other platforms... (because RTLD_LAZY is not supported) 35964a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 3597ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 35986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_DEBUG: 35996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_DEBUG entry to the address of _r_debug for GDB 36006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // if the dynamic table is writable 36019918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64 36029918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree. 360314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as 36049918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable. 36059918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__)) 36066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if ((dynamic_flags & PF_W) != 0) { 36076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug); 36086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 36099918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif 3610c6292ea39cce054175e4f9f797c05aeb8da0ac4bDmitriy Ivanov break; 36114eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 36126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 3613047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); 36146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3615ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 36166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELASZ: 3617047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela)); 36186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3619ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 362018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELA: 362118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr); 362218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 362318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 362418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELASZ: 362518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_size_ = d->d_un.d_val; 362618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 362718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 362818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_REL: 3629aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath()); 363018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 363118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 363218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELSZ: 3633aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath()); 363418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 363518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 36364a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELAENT: 36374a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rela))) { 3638f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val)); 36394a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 36404a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 36414a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 3642ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 3643ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // ignored (see DT_RELCOUNT comments for details) 36444a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELACOUNT: 36454a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 3646ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 36476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 3648aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_REL in \"%s\"", get_realpath()); 36496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 3650ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 36516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 3652aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath()); 36536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 365418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 3655c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else 36566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_REL: 3657047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); 36586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3659ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 36606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELSZ: 3661047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel)); 36626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3663ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 36644a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELENT: 36654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov if (d->d_un.d_val != sizeof(ElfW(Rel))) { 3666f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val)); 36674a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov return false; 36684a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov } 36694a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 3670ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 367118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_REL: 367218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr); 367318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 367418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 367518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELSZ: 367618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_size_ = d->d_un.d_val; 367718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov break; 367818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 367918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELA: 3680aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath()); 368118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 368218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 368318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_ANDROID_RELASZ: 3684aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath()); 368518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 368618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 3687ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // "Indicates that all RELATIVE relocations have been concatenated together, 3688ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // and specifies the RELATIVE relocation count." 3689ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // 3690ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // TODO: Spec also mentions that this can be used to optimize relocation process; 3691ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Not currently used by bionic linker - ignored. 36924a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov case DT_RELCOUNT: 36934a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov break; 369418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 36956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_RELA: 3696aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath()); 36976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 369818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 369918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov case DT_RELASZ: 3700aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath()); 370118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 370218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 3703c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif 37046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT: 3705047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 3706aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_); 37076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3708ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI: 3710047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); 3711aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_); 37126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3713ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAY: 3715047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 3716aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_); 37176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3718ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_INIT_ARRAYSZ: 37201649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 37216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3722ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAY: 3724047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 3725aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_); 37266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3727ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FINI_ARRAYSZ: 37291649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 37306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3731ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAY: 3733047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); 3734aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_); 37356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3736ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_PREINIT_ARRAYSZ: 37381649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr)); 37396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3740ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_TEXTREL: 374256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__) 3743aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath()); 37446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 374556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else 374656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov has_text_relocations = true; 374756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov break; 374856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 3749ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_SYMBOLIC: 375196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov has_DT_SYMBOLIC = true; 37526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3753ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_NEEDED: 37556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_count; 37566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3757ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_FLAGS: 37596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (d->d_un.d_val & DF_TEXTREL) { 376056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__) 3761aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath()); 37626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 376356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else 376456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov has_text_relocations = true; 376556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 37666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 376796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov if (d->d_un.d_val & DF_SYMBOLIC) { 376896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov has_DT_SYMBOLIC = true; 376996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov } 37706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3771ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37726cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov case DT_FLAGS_1: 3773d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov set_dt_flags_1(d->d_un.d_val); 37746cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov 3775d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) { 3776087005f37e02b48809746947159d824493885b1eDmitriy Ivanov DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val)); 37776cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov } 37786cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov break; 37794eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 37806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_MAP: 37816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. 37826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 37836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr); 37846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov *dp = &_r_debug; 37856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 37866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3787688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham case DT_MIPS_RLD_MAP2: 3788688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB. 3789688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham { 379020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov r_debug** dp = reinterpret_cast<r_debug**>( 379120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val); 3792688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham *dp = &_r_debug; 3793688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham } 3794688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham break; 3795ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 37966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_RLD_VERSION: 37976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_FLAGS: 37986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_BASE_ADDRESS: 37996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_UNREFEXTNO: 38006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3801d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 38026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_SYMTABNO: 3803047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_symtabno_ = d->d_un.d_val; 38046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3805d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 38066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_LOCAL_GOTNO: 3807047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_local_gotno_ = d->d_un.d_val; 38086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 3809d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 38106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov case DT_MIPS_GOTSYM: 3811047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov mips_gotsym_ = d->d_un.d_val; 38126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 38134eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif 3814ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov // Ignored: "Its use has been superseded by the DF_BIND_NOW flag" 3815ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov case DT_BIND_NOW: 3816ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov break; 3817ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov 3818513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERSYM: 38192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr); 38202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 38212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3822513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERDEF: 38232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verdef_ptr_ = load_bias + d->d_un.d_ptr; 38242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 3825513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov case DT_VERDEFNUM: 38262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verdef_cnt_ = d->d_un.d_val; 38272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 38282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3829e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko case DT_VERNEED: 38302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verneed_ptr_ = load_bias + d->d_un.d_ptr; 38312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov break; 38322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov 3833e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko case DT_VERNEEDNUM: 38342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov verneed_cnt_ = d->d_un.d_val; 3835513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov break; 3836d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 38376865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov case DT_RUNPATH: 38386865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov // this is parsed after we have strtab initialized (see below). 38396865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov break; 38406865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov 38416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov default: 38428f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov if (!relocating_linker) { 3843aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(), 38448f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); 38458f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov } 38466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 38471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 38486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 38491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3850bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#if defined(__mips__) && !defined(__LP64__) 3851bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand if (!mips_check_and_adjust_fp_modes()) { 3852bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand return false; 3853bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand } 3854bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand#endif 3855bc425c73e07dc150d1dcb64889ca7d379dace410Duane Sand 38566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", 3857047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov reinterpret_cast<void*>(base), strtab_, symtab_); 38581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 38596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Sanity checks. 38606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (relocating_linker && needed_count != 0) { 38616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); 38626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 38636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 38643597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov if (nbucket_ == 0 && gnu_nbucket_ == 0) { 3865aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" " 38663edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov "(new hash type from the future?)", get_realpath()); 38676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 38686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3869047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (strtab_ == 0) { 38703edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath()); 38716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 38726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3873047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (symtab_ == 0) { 38743edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath()); 38756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 38766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 387775108f4f830b533aced792d35e52841bf597f960Dmitriy Ivanov 3878624b8f17a1ce9b968f11e73231733442a07ac001Dmitriy Ivanov // second pass - parse entries relying on strtab 3879624b8f17a1ce9b968f11e73231733442a07ac001Dmitriy Ivanov for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { 38806865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov switch (d->d_tag) { 38816865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov case DT_SONAME: 38824f7a7ad3fed2ea90d454ec9f3cabfffb0deda8c4Dmitriy Ivanov set_soname(get_string(d->d_un.d_val)); 38836865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov break; 38846865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov case DT_RUNPATH: 38856865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov set_dt_runpath(get_string(d->d_un.d_val)); 38866865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov break; 3887624b8f17a1ce9b968f11e73231733442a07ac001Dmitriy Ivanov } 3888624b8f17a1ce9b968f11e73231733442a07ac001Dmitriy Ivanov } 3889624b8f17a1ce9b968f11e73231733442a07ac001Dmitriy Ivanov 389075108f4f830b533aced792d35e52841bf597f960Dmitriy Ivanov // Before M release linker was using basename in place of soname. 38911913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov // In the case when dt_soname is absent some apps stop working 389275108f4f830b533aced792d35e52841bf597f960Dmitriy Ivanov // because they can't find dt_needed library by soname. 389375108f4f830b533aced792d35e52841bf597f960Dmitriy Ivanov // This workaround should keep them working. (applies only 38941913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov // for apps targeting sdk version <=22). Make an exception for 38951913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov // the main executable and linker; they do not need to have dt_soname 38961913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 && 38971913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov get_application_target_sdk_version() <= 22) { 389875108f4f830b533aced792d35e52841bf597f960Dmitriy Ivanov soname_ = basename(realpath_.c_str()); 389975108f4f830b533aced792d35e52841bf597f960Dmitriy Ivanov DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"", 390075108f4f830b533aced792d35e52841bf597f960Dmitriy Ivanov get_realpath(), soname_); 390119930d5f6ef39e660d0cdab5e17445a7d3ed1310Dimitry Ivanov // Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI 390275108f4f830b533aced792d35e52841bf597f960Dmitriy Ivanov } 39036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 390414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov} 39051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 390618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovbool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group, 390718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const android_dlextinfo* extinfo) { 39081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3909ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_ = local_group.front(); 3910ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (local_group_root_ == nullptr) { 3911ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov local_group_root_ = this; 3912ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 3913ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov 39141913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) { 39151913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov target_sdk_version_ = get_application_target_sdk_version(); 39161913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov } 39171913352c6b3501893dfb45189754970f9dc6e7bbDmitriy Ivanov 39187e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov VersionTracker version_tracker; 39197e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov 39207e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov if (!version_tracker.init(this)) { 39217e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov return false; 39227e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov } 39237e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov 392456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__) 392556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (has_text_relocations) { 3926e4ad91f86a47b39612e030a162f4793cb3421d31Dmitriy Ivanov // Fail if app is targeting sdk version > 22 39278068786ae67835291521e52f39c695e40f3ad20dDmitriy Ivanov if (get_application_target_sdk_version() > 22) { 3928fae39d2bf9fb6f08da4a095f5fe3ff093bcdbee8Dmitriy Ivanov PRINT("%s: has text relocations", get_realpath()); 3929e4ad91f86a47b39612e030a162f4793cb3421d31Dmitriy Ivanov DL_ERR("%s: has text relocations", get_realpath()); 3930e4ad91f86a47b39612e030a162f4793cb3421d31Dmitriy Ivanov return false; 3931e4ad91f86a47b39612e030a162f4793cb3421d31Dmitriy Ivanov } 393256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov // Make segments writable to allow text relocations to work properly. We will later call 39337e039937b84ef8bc86da1dcd91c1a074f05a05bcDmitriy Ivanov // phdr_table_protect_segments() after all of them are applied. 393456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_WARN("%s has text relocations. This is wasting memory and prevents " 39353edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov "security hardening. Please fix.", get_realpath()); 3936df91dc2c192aa2789320c500037d28c919daa820Dimitry Ivanov add_dlwarning(get_realpath(), "text relocations"); 393756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { 393856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_ERR("can't unprotect loadable segments for \"%s\": %s", 39393edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov get_realpath(), strerror(errno)); 394056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov return false; 394156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 394256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 394356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 394456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov 394518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (android_relocs_ != nullptr) { 394618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov // check signature 394718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (android_relocs_size_ > 3 && 394818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[0] == 'A' && 394918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[1] == 'P' && 395018870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov android_relocs_[2] == 'S' && 395118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov android_relocs_[3] == '2') { 39523edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DEBUG("[ android relocating %s ]", get_realpath()); 395318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 395418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov bool relocated = false; 395518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const uint8_t* packed_relocs = android_relocs_ + 4; 395618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov const size_t packed_relocs_size = android_relocs_size_ - 4; 395718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 395818870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov relocated = relocate( 39597e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov version_tracker, 396018870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov packed_reloc_iterator<sleb128_decoder>( 396118870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov sleb128_decoder(packed_relocs, packed_relocs_size)), 396218870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov global_group, local_group); 396318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 396418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (!relocated) { 396518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 396618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 396718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } else { 396818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov DL_ERR("bad android relocation header."); 396918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 397018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 397118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 397218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 39734eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA) 3974047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (rela_ != nullptr) { 39753edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DEBUG("[ relocating %s ]", get_realpath()); 39767e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov if (!relocate(version_tracker, 39777e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) { 39786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 3979c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes } 39806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3981047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (plt_rela_ != nullptr) { 39823edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DEBUG("[ relocating %s plt ]", get_realpath()); 39837e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov if (!relocate(version_tracker, 39847e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) { 39856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 39861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 39876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 39889aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else 3989047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (rel_ != nullptr) { 39903edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DEBUG("[ relocating %s ]", get_realpath()); 39917e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov if (!relocate(version_tracker, 39927e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) { 39936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 39941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 39956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 3996047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov if (plt_rel_ != nullptr) { 39973edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DEBUG("[ relocating %s plt ]", get_realpath()); 39987e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov if (!relocate(version_tracker, 39997e4bbbae4a1e2034e6fa47ac2b0e1e7ca970acf0Dmitriy Ivanov plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) { 40006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 4001c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith } 40026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 40039aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif 4004c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith 40054eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__) 4006f39cb63603da949325b4d186e870d0c3de01eb30Dmitriy Ivanov if (!mips_relocate_got(version_tracker, global_group, local_group)) { 40076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 40086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 4009d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif 4010d7daacb46372132ae3f0121647074936c304b572Raghu Gandham 40113edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov DEBUG("[ finished linking %s ]", get_realpath()); 40121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 401356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__) 401456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (has_text_relocations) { 401556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov // All relocations are done, we can protect our segments back to read-only. 401656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { 401756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov DL_ERR("can't protect segments for \"%s\": %s", 40183edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov get_realpath(), strerror(errno)); 401956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov return false; 402056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 402156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov } 402256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif 402356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov 40249ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // We can also turn on GNU RELRO protection if we're not linking the dynamic linker 40259ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // itself --- it can't make system calls yet, and will have to call protect_relro later. 40269ce09e423f24823d52f19ab8247e078977100132Mingwei Shi if (!is_linker() && !protect_relro()) { 40276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 40286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 40299ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich 40306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Handle serializing/sharing the RELRO segment */ 40316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { 40326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, 40336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 40346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", 40353edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov get_realpath(), strerror(errno)); 40366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 4037183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) } 40386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { 40396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, 40406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov extinfo->relro_fd) < 0) { 40416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", 40423edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov get_realpath(), strerror(errno)); 40436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return false; 40446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 40456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 4046183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles) 40476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov notify_gdb_of_load(this); 40486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return true; 40491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 40501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 40519ce09e423f24823d52f19ab8247e078977100132Mingwei Shibool soinfo::protect_relro() { 40529ce09e423f24823d52f19ab8247e078977100132Mingwei Shi if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { 40539ce09e423f24823d52f19ab8247e078977100132Mingwei Shi DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", 40549ce09e423f24823d52f19ab8247e078977100132Mingwei Shi get_realpath(), strerror(errno)); 40559ce09e423f24823d52f19ab8247e078977100132Mingwei Shi return false; 40569ce09e423f24823d52f19ab8247e078977100132Mingwei Shi } 40579ce09e423f24823d52f19ab8247e078977100132Mingwei Shi return true; 40589ce09e423f24823d52f19ab8247e078977100132Mingwei Shi} 40599ce09e423f24823d52f19ab8247e078977100132Mingwei Shi 4060468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 4061c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list. 4062c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers. 4063c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc. 4064c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */ 4065812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) { 40664eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR) 40670266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR)); 4068851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov if (ehdr_vdso == nullptr) { 40690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return; 40700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes } 4071c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 4072d9b08a0bc082643b97fc9b11e0715e95be603c4cDmitriy Ivanov soinfo* si = soinfo_alloc(&g_default_namespace, "[vdso]", nullptr, 0, 0); 4073ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 40740266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff); 40750266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->phnum = ehdr_vdso->e_phnum; 40760266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso); 40770266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->size = phdr_table_get_load_size(si->phdr, si->phnum); 40780266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes si->load_bias = get_elf_exec_load_bias(ehdr_vdso); 4079ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov 4080047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->prelink_image(); 4081047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr); 4082c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif 4083c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov} 4084c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 4085d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list. 4086d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text" 4087d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to 4088d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol. 4089fefb4d3dcdbc01aabaa83f2da7c0388f6918b886Dimitry Ivanov * Note that the linker shouldn't be on the soinfo list. 4090d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 4091d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) { 409205b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov static link_map linker_link_map_for_gdb; 409305b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov#if defined(__LP64__) 409405b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov static char kLinkerPath[] = "/system/bin/linker64"; 409505b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov#else 409605b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov static char kLinkerPath[] = "/system/bin/linker"; 409705b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov#endif 4098aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov 409905b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov linker_link_map_for_gdb.l_addr = linker_base; 410005b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov linker_link_map_for_gdb.l_name = kLinkerPath; 4101d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 4102d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov /* 4103d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Set the dynamic field in the link map otherwise gdb will complain with 4104d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * the following: 4105d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * warning: .dynamic section for "/system/bin/linker" is not at the 4106d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * expected address (wrong library or version mismatch?) 4107d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */ 4108d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base); 4109d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff); 4110d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, 411105b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov &linker_link_map_for_gdb.l_ld, nullptr); 411205b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov 411305b60b24d9317ba84225fb21fc153cee47997e45Dimitry Ivanov insert_link_map_into_debug_map(&linker_link_map_for_gdb); 4114d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov} 4115d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov 411642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanovstatic void init_default_namespace() { 411742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_default_namespace.set_name("(default)"); 411842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_default_namespace.set_isolated(false); 411942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 4120d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum, 4121d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov somain->load_bias); 4122d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov const char* bname = basename(interp); 412342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) { 4124d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov g_default_ld_paths = kAsanDefaultLdPaths; 412542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } else { 4126d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov g_default_ld_paths = kDefaultLdPaths; 412742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 412842d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 412942d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov std::vector<std::string> ld_default_paths; 413042d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) { 413142d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov ld_default_paths.push_back(g_default_ld_paths[i]); 413242d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov } 413342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov 413442d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov g_default_namespace.set_default_library_paths(std::move(ld_default_paths)); 4135d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov}; 4136d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov 4137b4e5067cab9f17fa76bd7695f41a0b5070e10df8Dmitriy Ivanovextern "C" int __system_properties_init(void); 4138b4e5067cab9f17fa76bd7695f41a0b5070e10df8Dmitriy Ivanov 4139dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanovstatic const char* get_executable_path() { 4140dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov static std::string executable_path; 4141dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov if (executable_path.empty()) { 4142dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov char path[PATH_MAX]; 4143dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path)); 4144dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) { 4145dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno)); 4146dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov } 4147dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov executable_path = std::string(path, path_len); 4148dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov } 4149dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov 4150dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov return executable_path.c_str(); 4151dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov} 4152dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov 4153d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* 4154468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and 4155468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs 4156468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point. 4157468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 41580266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) { 41591a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING 41606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov struct timeval t0, t1; 41616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t0, 0); 41621a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif 41631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 41641801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes // Sanitize the environment. 41651801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes __libc_init_AT_SECURE(args); 4166be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 4167b4e5067cab9f17fa76bd7695f41a0b5070e10df8Dmitriy Ivanov // Initialize system properties 4168b4e5067cab9f17fa76bd7695f41a0b5070e10df8Dmitriy Ivanov __system_properties_init(); // may use 'environ' 4169b4e5067cab9f17fa76bd7695f41a0b5070e10df8Dmitriy Ivanov 41706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov debuggerd_init(); 41711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 41726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Get a few environment variables. 41731801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes const char* LD_DEBUG = getenv("LD_DEBUG"); 41746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (LD_DEBUG != nullptr) { 41756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov g_ld_debug_verbosity = atoi(LD_DEBUG); 41766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 4177be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner 4178116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes#if defined(__LP64__) 4179116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes INFO("[ Android dynamic linker (64-bit) ]"); 4180116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes#else 4181116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes INFO("[ Android dynamic linker (32-bit) ]"); 4182116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes#endif 4183116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes 41841801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes // These should have been sanitized by __libc_init_AT_SECURE, but the test 41856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // doesn't cost us anything. 41866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpath_env = nullptr; 41876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* ldpreload_env = nullptr; 41881801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes if (!getauxval(AT_SECURE)) { 41891801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes ldpath_env = getenv("LD_LIBRARY_PATH"); 4190116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes if (ldpath_env != nullptr) { 419138b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes INFO("[ LD_LIBRARY_PATH set to \"%s\" ]", ldpath_env); 4192116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes } 41931801db3d3fe17df543e721b9fb355e5c882dc6ccElliott Hughes ldpreload_env = getenv("LD_PRELOAD"); 4194116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes if (ldpreload_env != nullptr) { 419538b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env); 4196116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes } 41976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 41981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4199dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov const char* executable_path = get_executable_path(); 4200dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov struct stat file_stat; 4201dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov if (TEMP_FAILURE_RETRY(stat(executable_path, &file_stat)) != 0) { 4202dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov __libc_fatal("unable to stat file for the executable \"%s\": %s", executable_path, strerror(errno)); 4203dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov } 4204dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov 4205dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL); 42066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si == nullptr) { 4207b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov __libc_fatal("Couldn't allocate soinfo: out of memory?"); 42086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 42091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 42106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* bootstrap the link map, the main exe always needs to be first */ 4211ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->set_main_executable(); 42126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov link_map* map = &(si->link_map_head); 42131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 42149acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov // Register the main executable and the linker upfront to have 42159acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov // gdb aware of them before loading the rest of the dependency 42169acb3b747ce2e9a526cc6510029a6b432f551856Dimitry Ivanov // tree. 42176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov map->l_addr = 0; 4218dcaef3710df817db5652a1f3ab4646f43f5cd3eeDimitry Ivanov map->l_name = const_cast<char*>(executable_path); 42190f478e8b445a34f04916a79bae1b466e9256014aDimitry Ivanov insert_link_map_into_debug_map(map); 42206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov init_linker_info_for_gdb(linker_base); 42211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 42226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Extract information passed from the kernel. 42236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR)); 42246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->phnum = args.getauxval(AT_PHNUM); 42256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->entry = args.getauxval(AT_ENTRY); 42261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 42276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov /* Compute the value of si->base. We can't rely on the fact that 42286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * the first entry is the PHDR because this will not be true 42296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov * for certain executables (e.g. some in the NDK unit test suite) 42306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov */ 42316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = 0; 42326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->size = phdr_table_get_load_size(si->phdr, si->phnum); 42336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = 0; 42346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (size_t i = 0; i < si->phnum; ++i) { 42356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (si->phdr[i].p_type == PT_PHDR) { 42366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr; 42376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset; 42386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov break; 42398180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner } 42406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 42416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov si->dynamic = nullptr; 42421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 42436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base); 42446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (elf_hdr->e_type != ET_DYN) { 4245b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov __libc_fatal("\"%s\": error: only position independent executables (PIE) are supported.", 4246b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov args.argv[0]); 42476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 42482aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich 42496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). 42506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_LIBRARY_PATH(ldpath_env); 42516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov parse_LD_PRELOAD(ldpreload_env); 42524fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer 42536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov somain = si; 42545ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel 425542d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov init_default_namespace(); 4256d640b225ecdd6d2fb74076e9b80ce8afb42e31a0Evgenii Stepanov 42576718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov if (!si->prelink_image()) { 4258b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", args.argv[0], linker_get_error_buffer()); 42596718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov } 426014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 4261d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // add somain to global group 4262d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); 4263d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov 42646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov // Load ld_preloads and dependencies. 42656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov StringLinkedList needed_library_name_list; 42666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t needed_libraries_count = 0; 42676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov size_t ld_preloads_count = 0; 4268d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov 4269d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov for (const auto& ld_preload_name : g_ld_preload_names) { 4270d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov needed_library_name_list.push_back(ld_preload_name.c_str()); 42716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 4272f8093a9485402584f75b774ddf2ca051fa9b8aadDmitriy Ivanov ++ld_preloads_count; 42736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 427414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 42756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for_each_dt_needed(si, [&](const char* name) { 42766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.push_back(name); 42776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov ++needed_libraries_count; 42786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov }); 427914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 42806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov const char* needed_library_names[needed_libraries_count]; 428114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 42826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov memset(needed_library_names, 0, sizeof(needed_library_names)); 42836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count); 428414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov 4285d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov if (needed_libraries_count > 0 && 428642d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov !find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count, 428742d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr, 42880cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov /* add_as_children */ true)) { 4289b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", args.argv[0], linker_get_error_buffer()); 4290ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } else if (needed_libraries_count == 0) { 4291ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) { 4292b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", args.argv[0], linker_get_error_buffer()); 4293ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov } 4294ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov si->increment_ref_count(); 42956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 42961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 42976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov add_vdso(args); 4298c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov 4299279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov { 4300279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov ProtectedDataGuard guard; 43019181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov 4302279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov si->call_pre_init_constructors(); 4303279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov 4304279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov /* After the prelink_image, the si->load_bias is initialized. 4305279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * For so lib, the map->l_addr will be updated in notify_gdb_of_load. 4306279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * We need to update this value for so exe here. So Unwind_Backtrace 4307279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov * for some arch like x86 could work correctly within so exe. 4308279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov */ 4309279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov map->l_addr = si->load_bias; 4310279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov si->call_constructors(); 4311279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov } 4312e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov 43131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING 43146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov gettimeofday(&t1, nullptr); 43156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( 43166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - 43176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); 43181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 43191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS 43206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0], 43216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocAbsolute], 43226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocRelative], 43236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocCopy], 43246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov linker_stats.count[kRelocSymbol]); 43251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 43261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES 43276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov { 43286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned n; 43296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned i; 43306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned count = 0; 43316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (n = 0; n < 4096; n++) { 43326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (bitmask[n]) { 43336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov unsigned x = bitmask[n]; 4334e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__) 43356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 32; i++) { 4336e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else 43376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov for (i = 0; i < 8; i++) { 4338e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif 43396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov if (x & 1) { 43406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov count++; 43416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 43426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov x >>= 1; 43431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 43446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 43451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 43466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4); 43476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov } 43481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 43491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 43501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES 43516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov fflush(stdout); 43521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif 43531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 435438b88a4a6475160e64d963f7aa48c882d876737dElliott Hughes TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry)); 43556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov return si->entry; 43561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4357468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 4358bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only 4359bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library 4360bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself. 4361bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * 4362bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input: 4363bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * elf -> address of ELF header, assumed to be at the start of the file. 4364bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return: 4365bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * load bias, i.e. add the value of any p_vaddr in the file to get 4366bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * the corresponding address in memory. 4367bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */ 43680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) { 43690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) offset = elf->e_phoff; 43703edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov const ElfW(Phdr)* phdr_table = 43713edb9182ff2fddfa2d835aab0cad151616f2eac5Dmitriy Ivanov reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset); 43720266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum; 4373fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng 43740266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) { 4375fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng if (phdr->p_type == PT_LOAD) { 43760266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr; 4377bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner } 4378fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng } 4379fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng return 0; 4380bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner} 4381bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner 43829ce09e423f24823d52f19ab8247e078977100132Mingwei Shistatic void __linker_cannot_link(KernelArgumentBlock& args) { 43839ce09e423f24823d52f19ab8247e078977100132Mingwei Shi __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", args.argv[0], linker_get_error_buffer()); 43849ce09e423f24823d52f19ab8247e078977100132Mingwei Shi} 4385efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 4386468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/* 4387468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This 4388468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and 4389468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation(). 4390468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * 4391468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own 4392468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern 4393468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault. 4394468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */ 43950266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) { 439642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes KernelArgumentBlock args(raw_args); 439742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 43980266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) linker_addr = args.getauxval(AT_BASE); 4399efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov ElfW(Addr) entry_point = args.getauxval(AT_ENTRY); 44000266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); 4401faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); 440242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 440342d5fcb9f494eb45de3b6bf759f4a18076e84728Dmitriy Ivanov soinfo linker_so(nullptr, nullptr, nullptr, 0, 0); 440442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 4405efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // If the linker is not acting as PT_INTERP entry_point is equal to 4406efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // _start. Which means that the linker is running as an executable and 4407efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // already linked by PT_INTERP. 4408efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // 4409efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // This happens when user tries to run 'adb shell /system/bin/linker' 4410efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // see also https://code.google.com/p/android/issues/detail?id=63174 4411efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) { 4412b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov __libc_format_fd(STDOUT_FILENO, 4413b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov "This is %s, the helper program for shared library executables.\n", 4414b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov args.argv[0]); 4415b6ac9aa6f7ee8b71587d31d094645d322abc9640Dimitry Ivanov exit(0); 4416efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov } 4417efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov 441842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.base = linker_addr; 441942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); 442042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); 4421851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov linker_so.dynamic = nullptr; 442242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phdr = phdr; 442342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes linker_so.phnum = elf_hdr->e_phnum; 4424ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov linker_so.set_linker_flag(); 442542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 44269ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // Prelink the linker so we can access linker globals. 44279ce09e423f24823d52f19ab8247e078977100132Mingwei Shi if (!linker_so.prelink_image()) __linker_cannot_link(args); 44289ce09e423f24823d52f19ab8247e078977100132Mingwei Shi 4429d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // This might not be obvious... The reasons why we pass g_empty_list 4430d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // in place of local_group here are (1) we do not really need it, because 4431d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // linker is built with DT_SYMBOLIC and therefore relocates its symbols against 4432d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // itself without having to look into local_group and (2) allocators 4433d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // are not yet initialized, and therefore we cannot use linked_list.push_* 4434d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov // functions at this point. 44359ce09e423f24823d52f19ab8247e078977100132Mingwei Shi if (!linker_so.link_image(g_empty_list, g_empty_list, nullptr)) __linker_cannot_link(args); 44369ce09e423f24823d52f19ab8247e078977100132Mingwei Shi 44379ce09e423f24823d52f19ab8247e078977100132Mingwei Shi#if defined(__i386__) 44389ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // On x86, we can't make system calls before this point. 44399ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // We can't move this up because this needs to assign to a global. 44409ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // Note that until we call __libc_init_main_thread below we have 44419ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // no TLS, so you shouldn't make a system call that can fail, because 44429ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // it will SEGV when it tries to set errno. 44439ce09e423f24823d52f19ab8247e078977100132Mingwei Shi __libc_init_sysinfo(args); 44449ce09e423f24823d52f19ab8247e078977100132Mingwei Shi#endif 4445468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich 44469ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // Initialize the main thread (including TLS, so system calls really work). 4447d29486343a66cae37fc4fc74ed206fd29f25476bElliott Hughes __libc_init_main_thread(args); 444814241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov 44499ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // We didn't protect the linker's RELRO pages in link_image because we 44509ce09e423f24823d52f19ab8247e078977100132Mingwei Shi // couldn't make system calls on x86 at that point, but we can now... 44519ce09e423f24823d52f19ab8247e078977100132Mingwei Shi if (!linker_so.protect_relro()) __linker_cannot_link(args); 44529ce09e423f24823d52f19ab8247e078977100132Mingwei Shi 445393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao // Initialize the linker's static libc's globals 445493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao __libc_init_globals(args); 445593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 4456efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov // Initialize the linker's own global variables 4457047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov linker_so.call_constructors(); 44584151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov 44590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // Initialize static variables. Note that in order to 44600d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // get correct libdl_info we need to call constructors 44610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov // before get_libdl_info(). 44620d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov solist = get_libdl_info(); 44630d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov sonext = get_libdl_info(); 4464ae74e8750b9dae51b24a22fdb4b0e0a2d84f37b9Dimitry Ivanov g_default_namespace.add_soinfo(get_libdl_info()); 44650d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov 446642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // We have successfully fixed our own relocations. It's safe to run 446742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // the main part of the linker now. 44681728b2396591853345507a063ed6075dfd251706Elliott Hughes args.abort_message_ptr = &g_abort_message; 44690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr); 44705419b9474753d25dff947c7740532f86d130c0beElliott Hughes 4471116b5698d4fc9d037e3fda5b66e0ca5bb50b4ea7Elliott Hughes INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address)); 4472611f95689e1012283bd11917003d3740d3ce532dElliott Hughes 447342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // Return the address that the calling assembly stub should jump to. 447442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes return start_address; 4475468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich} 4476