linker.cpp revision 28154f5c56dc4a64270cae2374b47a168d1bd7fa
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
2904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov#include <android/api-level.h>
304688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <dlfcn.h>
314688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <errno.h>
324688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <fcntl.h>
330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes#include <inttypes.h>
344688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <pthread.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h>
384688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <sys/mman.h>
39ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#include <sys/param.h>
40bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#include <sys/personality.h>
414688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <unistd.h>
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
430d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#include <new>
44d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <string>
45d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <vector>
460d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
474688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Private C library headers.
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"
5214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/UniquePtr.h"
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h"
55c9ce70d7838b6aae074fc3615cdf04e5c9ac612aDmitriy Ivanov#include "linker_block_allocator.h"
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h"
5718870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov#include "linker_sleb128.h"
5823363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h"
59cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#include "linker_relocs.h"
60fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#include "linker_reloc_iterators.h"
61aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin#include "ziparchive/zip_archive.h"
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6366c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughesextern void __libc_init_AT_SECURE(KernelArgumentBlock&);
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6566c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes// Override macros to use C++ style casts.
661649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#undef ELF_ST_TYPE
671649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
681649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov
690266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
71600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<soinfo> g_soinfo_allocator;
72600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
73ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
74d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist;
75d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext;
766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
781728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = {
794eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__)
80011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/vendor/lib64",
81011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/system/lib64",
82011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else
83124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/vendor/lib",
84124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/system/lib",
85011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif
86851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  nullptr
87124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes};
88124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymNotNeeded = 0;
902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymGlobal = 1;
912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
92d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_library_paths;
93d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_preload_names;
94a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
95d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<soinfo*> g_ld_preloads;
964fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
971728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity;
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
99851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
1000d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
102bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t {
1036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int count[kRelocMax];
104bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes};
105bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
106bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats;
107bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
108114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind kind) {
1096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ++linker_stats.count[kind];
110bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
111bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else
112114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind) {
113bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
117114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovuint32_t bitmask[4096];
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1202e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768];
1212e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
122650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() {
1235419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return &__linker_dl_err_buf[0];
1242e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin}
1252e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
126650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() {
127650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes  return sizeof(__linker_dl_err_buf);
128650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes}
129650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes
1306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is an empty stub where GDB locates a breakpoint to get notified
1316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// about linker activity.
13220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovextern "C"
13320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1351728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
13620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic r_debug _r_debug =
13720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov    {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
13820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov
1393a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic link_map* r_debug_tail = 0;
1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1413a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic void insert_soinfo_into_debug_map(soinfo* info) {
1426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Copy the necessary fields into the debug structure.
1436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
1446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = info->load_bias;
145aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  // link_map l_name field is not const.
146aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  map->l_name = const_cast<char*>(info->get_realpath());
1476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_ld = info->dynamic;
1486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
1496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Stick the new library at the end of the list.
1506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // gdb tends to care more about libc than it does
1516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // about leaf libraries, and ordering it this way
1526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // reduces the back-and-forth over the wire.
1536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail) {
1546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail->l_next = map;
1556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = r_debug_tail;
1566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
1576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
1586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    _r_debug.r_map = map;
1596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = 0;
1606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
1616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
165bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void remove_soinfo_from_debug_map(soinfo* info) {
1666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
1675e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail == map) {
1696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail = map->l_prev;
1706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1715e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_prev) {
1736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev->l_next = map->l_next;
1746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_next) {
1766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next->l_prev = map->l_prev;
1776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1785e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
1795e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
180bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) {
181ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (info->is_main_executable()) {
1826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
1836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
1846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
1871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_ADD;
1896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
1901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  insert_soinfo_into_debug_map(info);
1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
1946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
1955e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
1965e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
197bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) {
198ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (info->is_main_executable()) {
1996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
2006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2025e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
2045e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_DELETE;
2066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2075e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  remove_soinfo_from_debug_map(info);
2095e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
2116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21418a206c81d9743481e364384affd43306911283dElliott Hughesvoid notify_gdb_of_libraries() {
2153a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_ADD;
2163a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2173a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_CONSISTENT;
2183a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
221d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
222d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  return g_soinfo_links_allocator.alloc();
223d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
224d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
225d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
226d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_links_allocator.free(entry);
227d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
228d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
22920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat,
23020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                            off64_t file_offset, uint32_t rtld_flags) {
231aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (strlen(name) >= PATH_MAX) {
232ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn    DL_ERR("library name \"%s\" too long", name);
233851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
234ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  }
235ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
23607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags);
237d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
238ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext->next = si;
239ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext = si;
2401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
241ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("name %s: allocated soinfo @ %p", name, si);
242ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  return si;
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
245faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) {
2466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
2476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2494688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
2506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si->base != 0 && si->size != 0) {
2516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    munmap(reinterpret_cast<void*>(si->base), si->size);
2526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
253d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  soinfo *prev = nullptr, *trav;
2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
256b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (trav = solist; trav != nullptr; trav = trav->next) {
2596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (trav == si) {
2606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    prev = trav;
2636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
264ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (trav == nullptr) {
2666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // si was not in solist
267b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
2686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // clear links to/from si
2726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->remove_all_links();
273d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // prev will never be null, because the first entry in solist is
2756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // always the static libdl_info.
2766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  prev->next = si->next;
2776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == sonext) {
2786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    sonext = prev;
2796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
280d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
2816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  g_soinfo_allocator.free(si);
2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
284cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_path(const char* path, const char* delimiters,
285d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov                       std::vector<std::string>* paths) {
286851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (path == nullptr) {
287cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    return;
288cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
289cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
290d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  paths->clear();
291cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
292d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (const char *p = path; ; ++p) {
293d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    size_t len = strcspn(p, delimiters);
294d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    // skip empty tokens
295d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (len == 0) {
296d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      continue;
297cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes    }
298cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
299d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    paths->push_back(std::string(p, len));
300d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    p += len;
301d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
302d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (*p == '\0') {
303d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      break;
304d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    }
305cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
306cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
307cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
308cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_LIBRARY_PATH(const char* path) {
309d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  parse_path(path, ":", &g_ld_library_paths);
310cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
311cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
312cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesstatic void parse_LD_PRELOAD(const char* path) {
313cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  // We have historically supported ':' as well as ' ' in LD_PRELOAD.
314d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  parse_path(path, " :", &g_ld_preload_names);
315cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
316cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
317aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic bool realpath_fd(int fd, std::string* realpath) {
318aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
319aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
320aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
321ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov    PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
322aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return false;
323aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
324aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
325aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  *realpath = std::string(&buf[0]);
326aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  return true;
327aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov}
328aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
3294eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
3304688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// For a given PC, find the .so that it belongs to.
3326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Returns the base address of the .ARM.exidx section
3336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// for that .so, and the number of 8-byte entries
3346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// in that section (via *pcount).
3356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov//
3366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Intended to be called by libc's __gnu_Unwind_Find_exidx().
3376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov//
3386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is exposed via dlfcn.cpp and libdl.so.
339faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
3401649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov  uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (soinfo* si = solist; si != 0; si = si->next) {
3436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if ((addr >= si->base) && (addr < (si->base + si->size))) {
3446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *pcount = si->ARM_exidx_count;
3451649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  *pcount = 0;
3496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return nullptr;
3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3514688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
35224053a461e7a20f34002262c1bb122023134989dChristopher Ferris#endif
3534688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// Here, we only have to provide a callback to iterate across all the
3556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// loaded libraries. gcc_eh does the rest.
356faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesint dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
3576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int rv = 0;
3586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
3596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_phdr_info dl_info;
3606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_addr = si->link_map_head.l_addr;
3616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_name = si->link_map_head.l_name;
3626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_phdr = si->phdr;
3636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    dl_info.dlpi_phnum = si->phnum;
3646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    rv = cb(&dl_info, sizeof(dl_phdr_info), data);
3656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (rv != 0) {
3666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return rv;
3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3714688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
3722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst ElfW(Versym)* soinfo::get_versym(size_t n) const {
3732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2) && versym_ != nullptr) {
3742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return versym_ + n;
3752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
3762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return nullptr;
3782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
3792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3802a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::get_verneed_ptr() const {
3812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2)) {
3822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return verneed_ptr_;
3832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
3842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
3862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
3872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovsize_t soinfo::get_verneed_cnt() const {
3892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2)) {
3902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return verneed_cnt_;
3912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
3922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
3942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
3952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
3962a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::get_verdef_ptr() const {
3972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2)) {
3982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return verdef_ptr_;
3992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
4022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovsize_t soinfo::get_verdef_cnt() const {
4052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(2)) {
4062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return verdef_cnt_;
4072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
4102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovtemplate<typename F>
4132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic bool for_each_verdef(const soinfo* si, F functor) {
4142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (!si->has_min_version(2)) {
4152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
4162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  uintptr_t verdef_ptr = si->get_verdef_ptr();
4192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (verdef_ptr == 0) {
4202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
4212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  size_t offset = 0;
4242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  size_t verdef_cnt = si->get_verdef_cnt();
4262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  for (size_t i = 0; i<verdef_cnt; ++i) {
4272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
4282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    size_t verdaux_offset = offset + verdef->vd_aux;
4292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    offset += verdef->vd_next;
4302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verdef->vd_version != 1) {
4323d7bea1fa00342f2a18331ea33a4b6e3332b3b02Dmitriy Ivanov      DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
433b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          i, verdef->vd_version, si->get_realpath());
4342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
4352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
4382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      // "this is the version of the file itself.  It must not be used for
4392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      //  matching a symbol. It can be used to match references."
4402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      //
4412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      // http://www.akkadia.org/drepper/symbol-versioning
4422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      continue;
4432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verdef->vd_cnt == 0) {
4462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
4472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
4482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
4512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (functor(i, verdef, verdaux) == true) {
4532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      break;
4542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
4582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const {
4612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (vi == nullptr) {
4622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    *versym = kVersymNotNeeded;
4632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
4642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  *versym = kVersymGlobal;
4672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return for_each_verdef(this,
4692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
4702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      if (verdef->vd_hash == vi->elf_hash &&
4712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov          strcmp(vi->name, get_string(verdaux->vda_name)) == 0) {
4722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        *versym = verdef->vd_ndx;
4732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        return true;
4742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      }
4752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
4772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
4782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  );
4792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
4802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::find_symbol_by_name(SymbolName& symbol_name,
4822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                 const version_info* vi,
4832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                 const ElfW(Sym)** symbol) const {
4842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  uint32_t symbol_index;
4852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  bool success =
4862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      is_gnu_hash() ?
4872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      gnu_lookup(symbol_name, vi, &symbol_index) :
4882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      elf_lookup(symbol_name, vi, &symbol_index);
4892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (success) {
4912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index;
4922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
4932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
4942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return success;
495ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
496ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
497ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
498ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
499ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      ELF_ST_BIND(s->st_info) == STB_WEAK) {
500ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    return s->st_shndx != SHN_UNDEF;
501ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
502ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
503b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
504ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
505ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
506ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return false;
507ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
508ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
5092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymHiddenBit = 0x8000;
5102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic inline bool is_versym_hidden(const ElfW(Versym)* versym) {
5122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // the symbol is hidden if bit 15 of versym is set.
5132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return versym != nullptr && (*versym & kVersymHiddenBit) != 0;
5142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
5152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic inline bool check_symbol_version(const ElfW(Versym) verneed,
5172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                        const ElfW(Versym)* verdef) {
5182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return verneed == kVersymNotNeeded ||
5192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      verdef == nullptr ||
5202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      verneed == (*verdef & ~kVersymHiddenBit);
5212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
5222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::gnu_lookup(SymbolName& symbol_name,
5242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                        const version_info* vi,
5252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                        uint32_t* symbol_index) const {
526ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t hash = symbol_name.gnu_hash();
527047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  uint32_t h2 = hash >> gnu_shift2_;
5281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
529ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;
530047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
531047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
5321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  *symbol_index = 0;
5342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5353597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
536b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
5373597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov
538ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  // test against bloom filter
539ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
5403597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
541b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
5423597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov
5432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
544ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
545ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
546ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  // bloom test says "probably yes"...
5473597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  uint32_t n = gnu_bucket_[hash % gnu_nbucket_];
548ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
549ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (n == 0) {
5503597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
551b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
5523597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov
5532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
5542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
5552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
5562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // lookup versym for the version definition in this library
5572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // note the difference between "version is not requested" (vi == nullptr)
5582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // and "version not found". In the first case verneed is kVersymNotNeeded
5592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // which implies that the default version can be accepted; the second case results in
5602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols
5612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  // for this library and consider only *global* ones.
5622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ElfW(Versym) verneed = 0;
5632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (!find_verdef_version_index(vi, &verneed)) {
5642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return false;
565ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
566ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
567ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  do {
568047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* s = symtab_ + n;
5692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Versym)* verdef = get_versym(n);
5702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    // skip hidden versions when verneed == kVersymNotNeeded (0)
5712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
5722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        continue;
5732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
5743597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
5752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        check_symbol_version(verneed, verdef) &&
576ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
577ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        is_symbol_global_and_defined(this, s)) {
5783597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov      TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
579b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
5803597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov          static_cast<size_t>(s->st_size));
5812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      *symbol_index = n;
5822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return true;
583ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
5843597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  } while ((gnu_chain_[n++] & 1) == 0);
5853597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov
5863597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
587b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
5881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
590ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
591ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
5922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo::elf_lookup(SymbolName& symbol_name,
5932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                        const version_info* vi,
5942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                        uint32_t* symbol_index) const {
595ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  uint32_t hash = symbol_name.elf_hash();
596ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
597ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
598b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             symbol_name.get_name(), get_realpath(),
599aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov             reinterpret_cast<void*>(base), hash, hash % nbucket_);
600ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
6012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ElfW(Versym) verneed = 0;
6022a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (!find_verdef_version_index(vi, &verneed)) {
6032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return false;
6042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
6052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
606047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
607047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* s = symtab_ + n;
6082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Versym)* verdef = get_versym(n);
6092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
6102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    // skip hidden versions when verneed == 0
6112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
6122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        continue;
6132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
6142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
6152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (check_symbol_version(verneed, verdef) &&
6162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
61720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        is_symbol_global_and_defined(this, s)) {
618ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
619b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov                 symbol_name.get_name(), get_realpath(),
620aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov                 reinterpret_cast<void*>(s->st_value),
621aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov                 static_cast<size_t>(s->st_size));
6222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      *symbol_index = n;
6232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return true;
6241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
6261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
627aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
628b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             symbol_name.get_name(), get_realpath(),
629aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov             reinterpret_cast<void*>(base), hash, hash % nbucket_);
630aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
6312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  *symbol_index = 0;
6322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
6331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
635aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovsoinfo::soinfo(const char* realpath, const struct stat* file_stat,
63620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov               off64_t file_offset, int rtld_flags) {
6370d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  memset(this, 0, sizeof(*this));
6380d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
639aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (realpath != nullptr) {
640aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    realpath_ = realpath;
641aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
642aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
643ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ = FLAG_NEW_SOINFO;
644047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  version_ = SOINFO_VERSION;
6450d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
646851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (file_stat != nullptr) {
647047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->st_dev_ = file_stat->st_dev;
648047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->st_ino_ = file_stat->st_ino;
649047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->file_offset_ = file_offset;
6500d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  }
651e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
652047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  this->rtld_flags_ = rtld_flags;
6530d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov}
6540d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
6556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
656ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::elf_hash() {
657ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (!has_elf_hash_) {
658aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
659ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    uint32_t h = 0, g;
660ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
661ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    while (*name) {
662ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h = (h << 4) + *name++;
663ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      g = h & 0xf0000000;
664ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h ^= g;
665ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h ^= g >> 24;
666ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
667ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
668ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    elf_hash_ = h;
669ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    has_elf_hash_ = true;
6706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
671ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
672ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return elf_hash_;
673ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
674ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
675ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovuint32_t SymbolName::gnu_hash() {
676ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  if (!has_gnu_hash_) {
677ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    uint32_t h = 5381;
678aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
679ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    while (*name != 0) {
680ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
681ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
682ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
683ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    gnu_hash_ =  h;
684ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    has_gnu_hash_ = true;
685ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
686ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
687ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return gnu_hash_;
6881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
6912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                      soinfo** si_found_in, const soinfo::soinfo_list_t& global_group,
6922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                      const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
693ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  SymbolName symbol_name(name);
6942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  const ElfW(Sym)* s = nullptr;
6956ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
69696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  /* "This element's presence in a shared object library alters the dynamic linker's
69796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * symbol resolution algorithm for references within the library. Instead of starting
69896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * a symbol search with the executable file, the dynamic linker starts from the shared
69996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * object itself. If the shared object fails to supply the referenced symbol, the
70096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * dynamic linker then searches the executable file and other shared objects as usual."
70196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   *
70296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
70396bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   *
70496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * Note that this is unlikely since static linker avoids generating
70596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   * relocations for -Bsymbolic linked dynamic executables.
70696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov   */
707d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (si_from->has_DT_SYMBOLIC) {
708b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
7092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
7102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
7112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
7122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
7138f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov    if (s != nullptr) {
714d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      *si_found_in = si_from;
71596bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov    }
71696bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  }
71796bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov
718d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // 1. Look for it in global_group
719d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (s == nullptr) {
7202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    bool error = false;
721d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    global_group.visit([&](soinfo* global_si) {
722aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      DEBUG("%s: looking up %s in %s (from global group)",
723b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          si_from->get_realpath(), name, global_si->get_realpath());
7242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
7252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        error = true;
7262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        return false;
7272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      }
7282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
72996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov      if (s != nullptr) {
730d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        *si_found_in = global_si;
731d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        return false;
73296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov      }
733c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin
734d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      return true;
735d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    });
7362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
7372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (error) {
7382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
7392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
74096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov  }
741c77c434149959e135ba21d1dd8a78a408fef2489Pavel Chupin
742d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // 2. Look for it in the local group
743cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (s == nullptr) {
7442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    bool error = false;
745cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    local_group.visit([&](soinfo* local_si) {
746d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
747e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov        // we already did this - skip
748e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov        return true;
749e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov      }
750e47b3f8456fc34ac136e9fddef59a9ae37febcbeDmitriy Ivanov
751aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      DEBUG("%s: looking up %s in %s (from local group)",
752b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          si_from->get_realpath(), name, local_si->get_realpath());
7532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
7542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        error = true;
7552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        return false;
7562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      }
7572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
758cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      if (s != nullptr) {
759d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        *si_found_in = local_si;
760cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov        return false;
761cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      }
7626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
763cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return true;
764cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    });
7652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
7662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (error) {
7672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
7682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
769cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
770cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
7716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (s != nullptr) {
7726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
7736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov               "found in %s, base = %p, load bias = %p",
774b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov               si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
775b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov               (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
776d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov               reinterpret_cast<void*>((*si_found_in)->load_bias));
7776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
7786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
7792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  *symbol = s;
7802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
7816ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev}
7826ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
783279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanovclass ProtectedDataGuard {
784279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov public:
785279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ProtectedDataGuard() {
786279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    if (ref_count_++ == 0) {
787279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov      protect_data(PROT_READ | PROT_WRITE);
788279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    }
789279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
790279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
791279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ~ProtectedDataGuard() {
792279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    if (ref_count_ == 0) { // overflow
793279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov      __libc_fatal("Too many nested calls to dlopen()");
794279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    }
795279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
796279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    if (--ref_count_ == 0) {
797279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov      protect_data(PROT_READ);
798279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    }
799279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
800279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov private:
801279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  void protect_data(int protection) {
802279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    g_soinfo_allocator.protect_all(protection);
803279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    g_soinfo_links_allocator.protect_all(protection);
804279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
805279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
806279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  static size_t ref_count_;
807279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov};
808279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
809279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanovsize_t ProtectedDataGuard::ref_count_ = 0;
810279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
8110cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov// Each size has it's own allocator.
8120cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size>
8130cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass SizeBasedAllocator {
8140cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public:
8150cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void* alloc() {
8160cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    return allocator_.alloc();
8170cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
8180cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
8190cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void free(void* ptr) {
8200cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    allocator_.free(ptr);
8210cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
8224bea498544bb1377f610520d7f58856382a6e5fcDmitriy Ivanov
8230cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov private:
8240cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static LinkerBlockAllocator allocator_;
8250cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov};
8260cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
8270cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<size_t size>
8280cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy IvanovLinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
8290cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
8300cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovtemplate<typename T>
8310cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanovclass TypeBasedAllocator {
8320cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov public:
8330cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static T* alloc() {
8340cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
8350cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
8360cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
8370cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  static void free(T* ptr) {
8380cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov    SizeBasedAllocator<sizeof(T)>::free(ptr);
8390cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  }
8400cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov};
8410cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
84214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovclass LoadTask {
84314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov public:
84414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  struct deleter_t {
84514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    void operator()(LoadTask* t) {
84614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      TypeBasedAllocator<LoadTask>::free(t);
84714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
84814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  };
849a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
85014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef UniquePtr<LoadTask, deleter_t> unique_ptr;
851d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom
85214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  static deleter_t deleter;
85314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
85414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  static LoadTask* create(const char* name, soinfo* needed_by) {
85514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
85614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return new (ptr) LoadTask(name, needed_by);
857aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  }
858a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
85914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  const char* get_name() const {
86014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return name_;
861a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov  }
86214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
86314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* get_needed_by() const {
86414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return needed_by_;
86514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
86614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov private:
86714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  LoadTask(const char* name, soinfo* needed_by)
86814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    : name_(name), needed_by_(needed_by) {}
86914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
87014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  const char* name_;
87114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* needed_by_;
87214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
87314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
874aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov};
875aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
876e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng JianLoadTask::deleter_t LoadTask::deleter;
877e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian
87814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate <typename T>
87914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovusing linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
88014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
88114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<soinfo> SoinfoLinkedList;
88214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<const char> StringLinkedList;
88314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtypedef linked_list_t<LoadTask> LoadTaskList;
88414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
88514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
886cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// This function walks down the tree of soinfo dependencies
887cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// in breadth-first order and
888cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//   * calls action(soinfo* si) for each node, and
889cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//   * terminates walk if action returns false.
890cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov//
891cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// walk_dependencies_tree returns false if walk was terminated
892cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov// by the action and true otherwise.
893cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovtemplate<typename F>
894cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovstatic bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
8950cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  SoinfoLinkedList visit_list;
8960cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov  SoinfoLinkedList visited;
8970cd83ebb0e9784827d9ec0a8028a710e73a28b2bDmitriy Ivanov
898cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  for (size_t i = 0; i < root_soinfos_size; ++i) {
899cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    visit_list.push_back(root_soinfos[i]);
900cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
901cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
902cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  soinfo* si;
903cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  while ((si = visit_list.pop_front()) != nullptr) {
904cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (visited.contains(si)) {
905042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov      continue;
906042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov    }
907042426ba6375f5c145379e598486ec6d675533c9Dmitriy Ivanov
908cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (!action(si)) {
909cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return false;
910aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    }
911aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
912cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    visited.push_back(si);
913cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
914cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    si->get_children().for_each([&](soinfo* child) {
915aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov      visit_list.push_back(child);
916aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov    });
917aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  }
918aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
919cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return true;
920cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
921cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
922cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
9234bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanovstatic const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
9244bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov                                            soinfo** found, SymbolName& symbol_name) {
9252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  const ElfW(Sym)* result = nullptr;
9264bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  bool skip_lookup = skip_until != nullptr;
9274bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov
9284bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
9294bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov    if (skip_lookup) {
9304bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov      skip_lookup = current_soinfo != skip_until;
9314bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov      return true;
9324bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov    }
933cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
9342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) {
9352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      result = nullptr;
9362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
9372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
9382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
939cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (result != nullptr) {
940cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      *found = current_soinfo;
941cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      return false;
942cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    }
943cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
944cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
945cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
946cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
947cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return result;
9481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9504bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov// This is used by dlsym(3).  It performs symbol lookup only within the
9514bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov// specified soinfo object and its dependencies in breadth first order.
9524bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanovconst ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
953c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // According to man dlopen(3) and posix docs in the case when si is handle
954c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // of the main executable we need to search not only in the executable and its
955c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // dependencies but also in all libraries loaded with RTLD_GLOBAL.
956c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  //
957c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
958c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // libraries and they are loaded in breath-first (correct) order we can just execute
959c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
960c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  if (si == somain) {
961c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov    return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT);
962c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov  }
963c4ebe60e1a2fc165ff11442765325628e27f2a05Dmitriy Ivanov
9644bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  SymbolName symbol_name(name);
9654bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  return dlsym_handle_lookup(si, nullptr, found, symbol_name);
9664bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov}
9674bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov
968d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom/* This is used by dlsym(3) to performs a global symbol lookup. If the
969d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   start value is null (for RTLD_DEFAULT), the search starts at the
970d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   beginning of the global solist. Otherwise the search starts at the
971d4ee82dfa3ba01baa10e3ca48fcb31a27b8a4e81Brian Carlstrom   specified soinfo (for RTLD_NEXT).
9726ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */
9732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst ElfW(Sym)* dlsym_linear_lookup(const char* name,
9742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                     soinfo** found,
9752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                     soinfo* caller,
9762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                     void* handle) {
977ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  SymbolName symbol_name(name);
9781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
97976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  soinfo* start = solist;
98076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
98176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  if (handle == RTLD_NEXT) {
98215309fde91b3989a1af139db422acf68e16a9258Dmitriy Ivanov    if (caller == nullptr) {
98376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov      return nullptr;
98476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov    } else {
98576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov      start = caller->next;
98676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov    }
987cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
9881698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer
9892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  const ElfW(Sym)* s = nullptr;
99076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  for (soinfo* si = start; si != nullptr; si = si->next) {
99104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
99204f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    // if the library is opened by application with target api level <= 22
99304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    // See http://b/21565766
99404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
995e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov      continue;
996e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    }
997e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
9982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
9992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return nullptr;
10002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
10012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1002851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    if (s != nullptr) {
1003cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      *found = si;
1004cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes      break;
10051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1006cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
10071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10084bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  // If not found - use dlsym_handle_lookup for caller's
10094bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov  // local_group unless it is part of the global group in which
101076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  // case we already did it.
101176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  if (s == nullptr && caller != nullptr &&
101276ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov      (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
10134bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov    return dlsym_handle_lookup(caller->get_local_group_root(),
10144bac6ea463a8f20793f5c1425965729ded1419feDmitriy Ivanov        (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name);
101576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  }
101676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
1017851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (s != nullptr) {
1018c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
1019c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes               name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
1020cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  }
10211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1022cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes  return s;
10231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1025fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Chengsoinfo* find_containing_library(const void* p) {
10260266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
1027851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
1028fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (address >= si->base && address - si->base < si->size) {
1029fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng      return si;
1030e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
1031fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
1032851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
1033e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
1034e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
1035ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
1036ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
1037ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1038ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1039ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovstatic bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
1040ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return sym->st_shndx != SHN_UNDEF &&
1041ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      soaddr >= sym->st_value &&
1042ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      soaddr < sym->st_value + sym->st_size;
1043ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1044ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1045ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
10468e5538193915885ea859ac90a72b46ab04440ceaChris Dearman  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
1047ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
10483597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  for (size_t i = 0; i < gnu_nbucket_; ++i) {
10493597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    uint32_t n = gnu_bucket_[i];
1050ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1051ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    if (n == 0) {
1052ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      continue;
1053ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    }
1054ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1055ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    do {
1056047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      ElfW(Sym)* sym = symtab_ + n;
1057ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      if (symbol_matches_soaddr(sym, soaddr)) {
1058ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        return sym;
1059ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      }
10603597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov    } while ((gnu_chain_[n++] & 1) == 0);
1061ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  }
1062ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1063ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  return nullptr;
1064ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1065ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1066ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy IvanovElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
10678e5538193915885ea859ac90a72b46ab04440ceaChris Dearman  ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
1068fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
1069fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  // Search the library's symbol table for any defined symbol which
1070fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  // contains this address.
1071047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  for (size_t i = 0; i < nchain_; ++i) {
1072047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    ElfW(Sym)* sym = symtab_ + i;
1073ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    if (symbol_matches_soaddr(sym, soaddr)) {
1074fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng      return sym;
1075e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
1076fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
1077e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
1078851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  return nullptr;
1079e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
1080e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
1081aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwinstatic int open_library_in_zipfile(const char* const path,
1082aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin                                   off64_t* file_offset) {
1083aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  TRACE("Trying zip file open from path '%s'", path);
1084aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1085524f1f1efe0cb32714c61e26f21701ac952b9e42Dmitriy Ivanov  // Treat an '!/' separator inside a path as the separator between the name
1086aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  // of the zip file on disk and the subdirectory to search within it.
1087524f1f1efe0cb32714c61e26f21701ac952b9e42Dmitriy Ivanov  // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
1088aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  // "bar/bas/x.so" within "foo.zip".
1089524f1f1efe0cb32714c61e26f21701ac952b9e42Dmitriy Ivanov  const char* separator = strstr(path, "!/");
1090aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (separator == nullptr) {
1091aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1092aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1093aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1094aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  char buf[512];
1095aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
1096aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    PRINT("Warning: ignoring very long library path: %s", path);
1097aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1098aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1099aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1100aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  buf[separator - path] = '\0';
1101aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1102aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  const char* zip_path = buf;
1103524f1f1efe0cb32714c61e26f21701ac952b9e42Dmitriy Ivanov  const char* file_path = &buf[separator - path + 2];
1104aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
1105aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (fd == -1) {
1106aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1107aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1108aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1109aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  ZipArchiveHandle handle;
1110aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (OpenArchiveFd(fd, "", &handle, false) != 0) {
1111aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    // invalid zip-file (?)
1112aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    close(fd);
1113aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1114aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1115aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1116aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  auto archive_guard = make_scope_guard([&]() {
1117aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    CloseArchive(handle);
1118aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  });
1119aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1120aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  ZipEntry entry;
1121aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1122aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (FindEntry(handle, ZipEntryName(file_path), &entry) != 0) {
1123aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    // Entry was not found.
1124aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    close(fd);
1125aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1126aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1127aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1128aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  // Check if it is properly stored
1129aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
1130aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    close(fd);
1131aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    return -1;
1132aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  }
1133aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1134aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  *file_offset = entry.offset;
1135aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin  return fd;
1136aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin}
1137aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1138d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
1139d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
1140d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  if (n < 0 || n >= static_cast<int>(buf_size)) {
1141d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    PRINT("Warning: ignoring very long library path: %s/%s", path, name);
1142d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    return false;
1143d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  }
1144d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
1145d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  return true;
1146d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov}
1147aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1148d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic int open_library_on_default_path(const char* name, off64_t* file_offset) {
1149d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (size_t i = 0; kDefaultLdPaths[i] != nullptr; ++i) {
1150d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    char buf[512];
1151aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    if (!format_path(buf, sizeof(buf), kDefaultLdPaths[i], name)) {
1152d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      continue;
1153d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    }
1154d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
1155d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1156d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (fd != -1) {
1157d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      *file_offset = 0;
1158d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      return fd;
11591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1160d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  }
1161aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1162d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  return -1;
1163d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov}
1164aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1165d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic int open_library_on_ld_library_path(const char* name, off64_t* file_offset) {
1166d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (const auto& path_str : g_ld_library_paths) {
1167d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    char buf[512];
1168d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    const char* const path = path_str.c_str();
1169d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (!format_path(buf, sizeof(buf), path, name)) {
1170d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      continue;
1171d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    }
1172d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
1173d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    int fd = -1;
1174d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (strchr(buf, '!') != nullptr) {
1175aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      fd = open_library_in_zipfile(buf, file_offset);
1176aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    }
1177aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1178aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    if (fd == -1) {
1179aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1180aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      if (fd != -1) {
1181aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin        *file_offset = 0;
1182aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      }
1183124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes    }
1184d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
1185d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    if (fd != -1) {
1186d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      return fd;
1187d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    }
1188124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
1189aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
1190d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  return -1;
11911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
11921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1193aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwinstatic int open_library(const char* name, off64_t* file_offset) {
1194ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("[ opening %s ]", name);
11951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1196124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  // If the name contains a slash, we should attempt to open it directly and not search the paths.
1197851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (strchr(name, '/') != nullptr) {
1198aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    if (strchr(name, '!') != nullptr) {
1199aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      int fd = open_library_in_zipfile(name, file_offset);
1200aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      if (fd != -1) {
1201aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin        return fd;
1202aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      }
1203aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin    }
1204aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin
12056971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
12066971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    if (fd != -1) {
1207aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin      *file_offset = 0;
12086971fe4ca52ebdaa85ba676a044412b01d2ef1bfElliott Hughes    }
1209e44fffd7f9b93b9ec9836cfc7acedf7e21107f8fDmitriy Ivanov    return fd;
1210124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
12111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1212124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
1213d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  int fd = open_library_on_ld_library_path(name, file_offset);
1214124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  if (fd == -1) {
1215d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    fd = open_library_on_default_path(name, file_offset);
1216124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  }
1217124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  return fd;
12181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12204a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanovstatic const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
12214a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov#if !defined(__LP64__)
12224a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov  // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
122304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if (get_application_target_sdk_version() <= 22) {
12244a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov    const char* bname = basename(dt_needed);
12254a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov    if (bname != dt_needed) {
12264a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov      DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
12274a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov    }
12284a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov
12294a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov    return bname;
12304a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov  }
12314a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov#endif
12324a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov  return dt_needed;
12334a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov}
12344a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov
123514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovtemplate<typename F>
123614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void for_each_dt_needed(const soinfo* si, F action) {
123714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
123814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (d->d_tag == DT_NEEDED) {
12394a7c3af054fdb525c8e458434f57f20696f43e31Dmitriy Ivanov      action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
1240d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    }
124114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
124214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
1243d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
12442a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Lowstatic soinfo* load_library(int fd, off64_t file_offset,
12452a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low                            LoadTaskList& load_tasks,
1246aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin                            const char* name, int rtld_flags,
1247aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin                            const android_dlextinfo* extinfo) {
124807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if ((file_offset % PAGE_SIZE) != 0) {
1249a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov    DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
125007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    return nullptr;
125107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  }
125216f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  if (file_offset < 0) {
125316f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
125416f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    return nullptr;
125516f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  }
125607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
125714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  struct stat file_stat;
125814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
1259a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov    DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
126014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
126114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
126216f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  if (file_offset >= file_stat.st_size) {
126320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov    DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
126420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        name, file_offset, file_stat.st_size);
126516f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui    return nullptr;
126616f7f8d2503a9033a09a4d7e857561d63471bb82Yabin Cui  }
1267d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
126814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Check for symlink and other situations where
12699b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov  // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
12709b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov  if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
12719b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov    for (soinfo* si = solist; si != nullptr; si = si->next) {
12729b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov      if (si->get_st_dev() != 0 &&
12739b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov          si->get_st_ino() != 0 &&
12749b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov          si->get_st_dev() == file_stat.st_dev &&
12759b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov          si->get_st_ino() == file_stat.st_ino &&
12769b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov          si->get_file_offset() == file_offset) {
12779b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov        TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1278aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov            "will return existing soinfo", name, si->get_realpath());
12799b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov        return si;
12809b82136b987bc01224e3b42732334ea27c97d188Dmitriy Ivanov      }
1281498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov    }
128214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
1283d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1284e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if ((rtld_flags & RTLD_NOLOAD) != 0) {
1285a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov    DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
128614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
128714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
1288a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
1289aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  std::string realpath = name;
1290aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (!realpath_fd(fd, &realpath)) {
1291ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov    PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name);
1292aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    realpath = name;
1293aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
1294aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
129514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Read the ELF header and load the segments.
1296aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ElfReader elf_reader(realpath.c_str(), fd, file_offset);
129714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!elf_reader.Load(extinfo)) {
129814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
129914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
1300d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
1301aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags);
130214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (si == nullptr) {
130314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
130414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
130514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->base = elf_reader.load_start();
130614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->size = elf_reader.load_size();
130714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->load_bias = elf_reader.load_bias();
130814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->phnum = elf_reader.phdr_count();
130914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  si->phdr = elf_reader.loaded_phdr();
131014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1311047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (!si->prelink_image()) {
131214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo_free(si);
131314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
131414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
1315a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov
131614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  for_each_dt_needed(si, [&] (const char* name) {
131714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.push_back(LoadTask::create(name, si));
131814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
131914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
132014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return si;
13211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13232a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Lowstatic soinfo* load_library(LoadTaskList& load_tasks,
13242a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low                            const char* name, int rtld_flags,
13252a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low                            const android_dlextinfo* extinfo) {
13262a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
13272a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    off64_t file_offset = 0;
13282a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
13292a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low      file_offset = extinfo->library_fd_offset;
13302a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    }
13312a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo);
13322a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  }
13332a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low
13342a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  // Open the file.
13352a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  off64_t file_offset;
13362a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  int fd = open_library(name, &file_offset);
13372a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  if (fd == -1) {
13382a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    DL_ERR("library \"%s\" not found", name);
13392a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low    return nullptr;
13402a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  }
13412a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
13422a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  close(fd);
13432a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low  return result;
13442a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low}
13452a44cfbd7d64596795836e9ae6f6c642869d6d78Spencer Low
134628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov// Returns true if library was found and false in 2 cases
134728154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov// 1. The library was found but loaded under different target_sdk_version
134828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov//    (*candidate != nullptr)
134928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov// 2. The library was not found by soname (*candidate is nullptr)
135028154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanovstatic bool find_loaded_library_by_soname(const char* name, soinfo** candidate) {
135128154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  *candidate = nullptr;
135228154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov
1353618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // Ignore filename with path.
1354618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  if (strchr(name, '/') != nullptr) {
135528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov    return false;
1356618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  }
1357618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
135828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  uint32_t target_sdk_version = get_application_target_sdk_version();
135928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov
1360851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  for (soinfo* si = solist; si != nullptr; si = si->next) {
1361618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    const char* soname = si->get_soname();
1362618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    if (soname != nullptr && (strcmp(name, soname) == 0)) {
136328154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      // If the library was opened under different target sdk version
136428154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      // skip this step and try to reopen it. The exceptions are
136528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      // "libdl.so" and global group. There is no point in skipping
136628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      // them because relocation process is going to use them
136728154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      // in any case.
136828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      bool is_libdl = si == solist;
136928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
137028154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov          !si->is_linked() || si->get_target_sdk_version() == target_sdk_version) {
137128154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov        *candidate = si;
137228154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov        return true;
137328154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      } else if (*candidate == nullptr) {
137428154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov        // for the different sdk version - remember the first library.
137528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov        *candidate = si;
137628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      }
137712c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel    }
1378489e498434f53269c44e3c13039eb630e86e1fd9Dmitriy Ivanov  }
137928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov
138028154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  return false;
138112c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel}
138212c78bbded8ec03f821dfa09174464c04836e4eaArd Biesheuvel
138320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
138420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                                     int rtld_flags, const android_dlextinfo* extinfo) {
138528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  soinfo* candidate;
138628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov
138728154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  if (find_loaded_library_by_soname(name, &candidate)) {
138828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov    return candidate;
138928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  }
1390b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
1391b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // Library might still be loaded, the accurate detection
139214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // of this fact is done by load_library.
139328154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
139428154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov      name, candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
139528154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov
139628154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  soinfo* si = load_library(load_tasks, name, rtld_flags, extinfo);
139728154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov
139828154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  // In case we were unable to load the library but there
139928154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  // is a candidate loaded under the same soname but different
140028154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  // sdk level - return it anyways.
140128154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov  if (si == nullptr && candidate != nullptr) {
140228154f5c56dc4a64270cae2374b47a168d1bd7faDmitriy Ivanov    si = candidate;
1403b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  }
1404b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
140514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  return si;
140614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
140714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
140814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovstatic void soinfo_unload(soinfo* si);
140914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1410d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// TODO: this is slightly unusual way to construct
1411d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// the global group for relocation. Not every RTLD_GLOBAL
1412d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// library is included in this group for backwards-compatibility
1413d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// reasons.
1414d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov//
1415d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// This group consists of the main executable, LD_PRELOADs
1416d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov// and libraries with the DF_1_GLOBAL flag set.
1417d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovstatic soinfo::soinfo_list_t make_global_group() {
1418d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  soinfo::soinfo_list_t global_group;
1419d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  for (soinfo* si = somain; si != nullptr; si = si->next) {
1420d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1421d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      global_group.push_back(si);
1422d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
1423d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
1424d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1425d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return global_group;
1426d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
1427d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1428d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic bool find_libraries(soinfo* start_with, const char* const library_names[],
1429d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      size_t library_names_count, soinfo* soinfos[], std::vector<soinfo*>* ld_preloads,
1430d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      size_t ld_preloads_count, int rtld_flags, const android_dlextinfo* extinfo) {
143114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 0: prepare.
143214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  LoadTaskList load_tasks;
1433cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  for (size_t i = 0; i < library_names_count; ++i) {
143414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    const char* name = library_names[i];
1435cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    load_tasks.push_back(LoadTask::create(name, start_with));
1436cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  }
1437cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1438d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // Construct global_group.
1439d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  soinfo::soinfo_list_t global_group = make_global_group();
1440d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
1441cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // If soinfos array is null allocate one on stack.
1442cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // The array is needed in case of failure; for example
1443cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // when library_names[] = {libone.so, libtwo.so} and libone.so
1444cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // is loaded correctly but libtwo.so failed for some reason.
1445cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // In this case libone.so should be unloaded on return.
1446cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // See also implementation of failure_guard below.
1447cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1448cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (soinfos == nullptr) {
1449cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1450cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1451cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    memset(soinfos, 0, soinfos_size);
145214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
145314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1454cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // list of libraries to link - see step 2.
1455cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  size_t soinfos_count = 0;
145614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1457d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov  auto failure_guard = make_scope_guard([&]() {
145814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    // Housekeeping
145914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    load_tasks.for_each([] (LoadTask* t) {
146014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      LoadTask::deleter(t);
146114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    });
146214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1463cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    for (size_t i = 0; i<soinfos_count; ++i) {
146414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      soinfo_unload(soinfos[i]);
146514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
146614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  });
146714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
146814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
146920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov  for (LoadTask::unique_ptr task(load_tasks.pop_front());
147020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov      task.get() != nullptr; task.reset(load_tasks.pop_front())) {
1471e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov    soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
147214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (si == nullptr) {
147314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      return false;
147414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
147514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
147614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo* needed_by = task->get_needed_by();
147714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
147814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    if (needed_by != nullptr) {
147914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      needed_by->add_child(si);
148014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
148114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1482ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (si->is_linked()) {
1483ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->increment_ref_count();
1484ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1485ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1486cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    // When ld_preloads is not null, the first
1487cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    // ld_preloads_count libs are in fact ld_preloads.
1488cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
1489d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // Add LD_PRELOADed libraries to the global group for future runs.
1490d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // There is no need to explicitly add them to the global group
1491d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // for this run because they are going to appear in the local
1492d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      // group in the correct order.
1493d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov      si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1494d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      ld_preloads->push_back(si);
149514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
149614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1497cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    if (soinfos_count < library_names_count) {
1498cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      soinfos[soinfos_count++] = si;
149914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
150014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
150114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
150214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Step 2: link libraries.
1503cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  soinfo::soinfo_list_t local_group;
1504cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  walk_dependencies_tree(
1505cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      start_with == nullptr ? soinfos : &start_with,
1506cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      start_with == nullptr ? soinfos_count : 1,
1507cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov      [&] (soinfo* si) {
1508cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    local_group.push_back(si);
1509cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
1510cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
1511cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1512ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // We need to increment ref_count in case
1513ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // the root of the local group was not linked.
1514ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  bool was_local_group_root_linked = local_group.front()->is_linked();
1515ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1516cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  bool linked = local_group.visit([&](soinfo* si) {
1517ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (!si->is_linked()) {
1518047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      if (!si->link_image(global_group, local_group, extinfo)) {
151914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov        return false;
152014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov      }
1521ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->set_linked();
152214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    }
1523cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1524cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    return true;
1525cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  });
1526cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
1527cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  if (linked) {
1528cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov    failure_guard.disable();
1529a3ad450a2e3fb6b3fe359683b247eba20896f646Dmitriy Ivanov  }
153014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1531ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!was_local_group_root_linked) {
1532ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_group.front()->increment_ref_count();
1533ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
1534ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1535cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return linked;
153614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
153714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1538e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanovstatic soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
153914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  soinfo* si;
154014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1541ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (name == nullptr) {
1542ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    si = somain;
1543ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else if (!find_libraries(nullptr, &name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
154414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return nullptr;
154514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
154614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1547d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  return si;
1548d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
1549d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1550ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovstatic void soinfo_unload(soinfo* root) {
1551ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // Note that the library can be loaded but not linked;
1552ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // in which case there is no root but we still need
1553ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // to walk the tree and unload soinfos involved.
1554ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
1555ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // This happens on unsuccessful dlopen, when one of
1556ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // the DT_NEEDED libraries could not be linked/found.
1557ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (root->is_linked()) {
1558ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    root = root->get_local_group_root();
15591b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  }
15601b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
1561ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!root->can_unload()) {
1562b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_realpath());
1563ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    return;
1564ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
1565d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
1566ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  size_t ref_count = root->is_linked() ? root->decrement_ref_count() : 0;
1567ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1568ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (ref_count == 0) {
1569ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t local_unload_list;
1570ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t external_unload_list;
1571ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo::soinfo_list_t depth_first_list;
1572ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    depth_first_list.push_back(root);
1573ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    soinfo* si = nullptr;
1574ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
1575ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = depth_first_list.pop_front()) != nullptr) {
15765ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov      if (local_unload_list.contains(si)) {
15775ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov        continue;
15785ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov      }
15795ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov
1580ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      local_unload_list.push_back(si);
15815ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov
1582ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      if (si->has_min_version(0)) {
1583ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        soinfo* child = nullptr;
1584ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        while ((child = si->get_children().pop_front()) != nullptr) {
1585b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
1586b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov              child->get_realpath(), child);
1587b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov
1588ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          if (local_unload_list.contains(child)) {
1589ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            continue;
15905ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov          } else if (child->is_linked() && child->get_local_group_root() != root) {
1591ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            external_unload_list.push_back(child);
1592ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else {
1593ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            depth_first_list.push_front(child);
1594ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          }
1595d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov        }
1596ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      } else {
159769a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if !defined(__work_around_b_19059885__)
1598b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
15995ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#else
1600b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
1601ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        for_each_dt_needed(si, [&] (const char* library_name) {
1602aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          TRACE("deprecated (old format of soinfo): %s needs to unload %s",
1603b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov              si->get_realpath(), library_name);
1604aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
1605ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
1606ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          if (needed != nullptr) {
1607ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // Not found: for example if symlink was deleted between dlopen and dlclose
1608ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // Since we cannot really handle errors at this point - print and continue.
1609aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov            PRINT("warning: couldn't find %s needed by %s on unload.",
1610b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov                library_name, si->get_realpath());
1611ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            return;
1612ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else if (local_unload_list.contains(needed)) {
1613ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // already visited
1614ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            return;
16155ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov          } else if (needed->is_linked() && needed->get_local_group_root() != root) {
1616ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // external group
1617ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            external_unload_list.push_back(needed);
1618ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          } else {
1619ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            // local group
1620ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov            depth_first_list.push_front(needed);
1621ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov          }
1622ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        });
16235ae82cba595d15e955aafb8da3fca9c5bcdeb551Dmitriy Ivanov#endif
1624ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      }
16251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1627ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_unload_list.for_each([](soinfo* si) {
1628ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      si->call_destructors();
1629ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    });
16301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1631ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = local_unload_list.pop_front()) != nullptr) {
1632ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      notify_gdb_of_unload(si);
1633ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      soinfo_free(si);
1634ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1635a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov
1636ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    while ((si = external_unload_list.pop_front()) != nullptr) {
1637ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      soinfo_unload(si);
1638ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
1639ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else {
1640b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    TRACE("not unloading '%s' group, decrementing ref_count to %zd",
1641b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        root->get_realpath(), ref_count);
1642a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov  }
1643a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov}
1644a2547055f25db614601ee8651f2e42ece01f7842Dmitriy Ivanov
1645a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughesvoid do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
1646052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // Use basic string manipulation calls to avoid snprintf.
1647052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
1648052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // When debug malloc is enabled, this call returns 0. This in turn causes
1649052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf to do nothing, which causes libraries to fail to load.
1650052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // See b/17302493 for further details.
1651052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // Once the above bug is fixed, this code can be modified to use
1652052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  // snprintf again.
1653052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
1654052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  if (buffer_size < required_len) {
165520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
165620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                 "buffer len %zu, required len %zu", buffer_size, required_len);
1657052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  }
1658052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  char* end = stpcpy(buffer, kDefaultLdPaths[0]);
1659052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  *end = ':';
1660052fa3a34c07b9b361c30565f029dd543da14e30Christopher Ferris  strcpy(end + 1, kDefaultLdPaths[1]);
1661a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes}
1662a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
1663cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughesvoid do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
16646bb01b6e6365ced7ca23c9ebecfaf1ea159d5ae2Nick Kralevich  parse_LD_LIBRARY_PATH(ld_library_path);
1665cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes}
1666cade4c36e7c9c62db3f476a0f9cfc329bac9acb7Elliott Hughes
16671a586293400d0e1d73e6eb82f7dfe9d2d9ed3c4bElliott Hughessoinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
16681b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
1669e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes    DL_ERR("invalid flags to dlopen: %x", flags);
1670851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
1671e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  }
167207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if (extinfo != nullptr) {
167307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
167407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
167507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      return nullptr;
167607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    }
167707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
1678a6c1279098f24a675d0df74ce1946f5d534b425eDmitriy Ivanov        (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
167920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
168020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
168107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov      return nullptr;
168207e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov    }
1683012cb4583a5f8564059142bb1900ea3a31e7cfa9Torne (Richard Coles)  }
1684279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
1685279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ProtectedDataGuard guard;
16869fb216f844bb15c8e8f27c5ac0490a2f6faacb57Dmitriy Ivanov  soinfo* si = find_library(name, flags, extinfo);
1687851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (si != nullptr) {
1688047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    si->call_constructors();
1689d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
1690d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  return si;
1691d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
16921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1693b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanovvoid do_dlclose(soinfo* si) {
1694279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ProtectedDataGuard guard;
1695b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  soinfo_unload(si);
16961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16989aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanovstatic ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
16999aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  typedef ElfW(Addr) (*ifunc_resolver_t)(void);
17009aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
17019aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ElfW(Addr) ifunc_addr = ifunc_resolver();
170220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov  TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
170320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov      ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
1704c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
17059aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return ifunc_addr;
1706c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
1707c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
17082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
17092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (source_symver < 2 ||
17102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      source_symver >= version_infos.size() ||
17112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      version_infos[source_symver].name == nullptr) {
17122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return nullptr;
17132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17142a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17152a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return &version_infos[source_symver];
17162a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17172a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17182a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovvoid VersionTracker::add_version_info(size_t source_index,
17192a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                      ElfW(Word) elf_hash,
17202a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                      const char* ver_name,
17212a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov                                      const soinfo* target_si) {
17222a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (source_index >= version_infos.size()) {
17232a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    version_infos.resize(source_index+1);
17242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  version_infos[source_index].elf_hash = elf_hash;
17272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  version_infos[source_index].name = ver_name;
17282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  version_infos[source_index].target_si = target_si;
17292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init_verneed(const soinfo* si_from) {
17322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  uintptr_t verneed_ptr = si_from->get_verneed_ptr();
17332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (verneed_ptr == 0) {
17352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
17362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  size_t verneed_cnt = si_from->get_verneed_cnt();
17392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
17412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
17422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    size_t vernaux_offset = offset + verneed->vn_aux;
17432a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    offset += verneed->vn_next;
17442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (verneed->vn_version != 1) {
17462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
17472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
17482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
17492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const char* target_soname = si_from->get_string(verneed->vn_file);
17512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    // find it in dependencies
17522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
17538264afb37778bea2a3c6e9aa7144f4877401c3f8Dmitriy Ivanov      return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
17542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    });
17552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    if (target_si == nullptr) {
17572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
1758b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          target_soname, i, si_from->get_realpath());
17592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
17602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
17612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    for (size_t j = 0; j<verneed->vn_cnt; ++j) {
17632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
17642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      vernaux_offset += vernaux->vna_next;
17652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      const ElfW(Word) elf_hash = vernaux->vna_hash;
17672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      const char* ver_name = si_from->get_string(vernaux->vna_name);
17682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      ElfW(Half) source_index = vernaux->vna_other;
17692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      add_version_info(source_index, elf_hash, ver_name, target_si);
17712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
17722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return true;
17752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init_verdef(const soinfo* si_from) {
17782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return for_each_verdef(si_from,
17792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
17802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      add_version_info(verdef->vd_ndx, verdef->vd_hash,
17812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov          si_from->get_string(verdaux->vda_name), si_from);
17822a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      return false;
17832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    }
17842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  );
17852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovbool VersionTracker::init(const soinfo* si_from) {
17882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (!si_from->has_min_version(2)) {
17892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return true;
17902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
17912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
17922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return init_verneed(si_from) && init_verdef(si_from);
17932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
17942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1795114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanovbool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
1796114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov                                 const char* sym_name, const version_info** vi) {
1797114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
1798114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
1799114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1800114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
1801114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    *vi = version_tracker.get_version_info(sym_ver);
1802114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1803114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    if (*vi == nullptr) {
1804114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      DL_ERR("cannot find verneed/verdef for version index=%d "
1805b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
1806114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      return false;
1807114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    }
1808114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  } else {
1809114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    // there is no version info
1810114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov    *vi = nullptr;
1811114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  }
1812114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1813114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov  return true;
1814114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov}
1815114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1816bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#if !defined(__mips__)
18174eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
1818bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanovstatic ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
1819bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov  return rela->r_addend;
1820bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov}
1821bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#else
1822bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanovstatic ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
182320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov  if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
182420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
1825bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
1826bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov  }
1827bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov  return 0;
1828bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov}
1829bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#endif
1830bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov
1831fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanovtemplate<typename ElfRelIteratorT>
1832f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanovbool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
1833f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov                      const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
1834fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov  for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
1835fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov    const auto rel = rel_iterator.next();
183618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    if (rel == nullptr) {
183718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      return false;
183818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    }
183918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
1840bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
1841bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
1842bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov
1843bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
18440266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    ElfW(Addr) sym_addr = 0;
1845851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    const char* sym_name = nullptr;
1846bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov    ElfW(Addr) addend = get_addend(rel, reloc);
1847c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1848b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx);
1849cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov    if (type == R_GENERIC_NONE) {
1850c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      continue;
1851c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
185214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
18532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    const ElfW(Sym)* s = nullptr;
185414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    soinfo* lsi = nullptr;
185514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
1856c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    if (sym != 0) {
1857047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      sym_name = get_string(symtab_[sym].st_name);
1858114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      const version_info* vi = nullptr;
18592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1860114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
1861114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov        return false;
1862114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      }
18632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1864114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov      if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
1865114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov        return false;
18662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov      }
1867114bd835a756f782c119ed7f76b6cacb2cd723dcDmitriy Ivanov
1868851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov      if (s == nullptr) {
1869c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        // We only allow an undefined symbol if this is a weak reference...
1870047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        s = &symtab_[sym];
1871c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
1872b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
1873114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov          return false;
1874c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        }
1875c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1876c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        /* IHI0044C AAELF 4.5.1.1:
1877c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1878c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           Libraries are not searched to resolve weak references.
1879c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           It is not an error for a weak reference to remain unsatisfied.
1880c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1881c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           During linking, the value of an undefined weak reference is:
1882c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - Zero if the relocation type is absolute
1883c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - The address of the place if the relocation is pc-relative
1884c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes           - The address of nominal base address if the relocation
1885c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes             type is base-relative.
1886c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes         */
1887c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1888c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        switch (type) {
18891b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_JUMP_SLOT:
18901b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_GLOB_DAT:
18911b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_RELATIVE:
18921b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_GENERIC_IRELATIVE:
1893e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__aarch64__)
18946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS64:
18956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS32:
18966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          case R_AARCH64_ABS16:
18971b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#elif defined(__x86_64__)
18981b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_X86_64_32:
18991b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov          case R_X86_64_64:
1900bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__)
1901bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov          case R_ARM_ABS32:
1902bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__i386__)
1903bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov          case R_386_32:
19041b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#endif
19056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            /*
19066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * The sym_addr was initialized to be zero above, or the relocation
19076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * code below does not care about value of sym_addr.
19086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             * No need to do anything.
19096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov             */
19106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            break;
19111b694693b47785c5350916eafc9200cf9aa4a920Dmitriy Ivanov#if defined(__x86_64__)
1912d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov          case R_X86_64_PC32:
1913d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov            sym_addr = reloc;
1914d338aac19c91bf06f529364f0d1ca3ba8b98bd13Dimitry Ivanov            break;
1915bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__i386__)
1916bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov          case R_386_PC32:
1917bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov            sym_addr = reloc;
1918bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov            break;
1919bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#endif
19206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          default:
1921bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov            DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
1922114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov            return false;
1923c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        }
1924c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      } else {
1925c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes        // We got a definition.
19269aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov        sym_addr = lsi->resolve_symbol_address(s);
1927c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      }
1928c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      count_relocation(kRelocSymbol);
1929c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
1930c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1931c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    switch (type) {
1932cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_JUMP_SLOT:
1933e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1934bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1935bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
1936bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
1937bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
1938bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov
1939bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
1940e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1941cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_GLOB_DAT:
1942e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1943bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1944bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
1945bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
1946bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
1947bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
1948e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1949cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_RELATIVE:
1950cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1951bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1952bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
1953bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
195418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                   reinterpret_cast<void*>(load_bias + addend));
195518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
1956cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1957cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_IRELATIVE:
1958cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1959bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1960bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
1961bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                    reinterpret_cast<void*>(reloc),
196218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                    reinterpret_cast<void*>(load_bias + addend));
196318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(load_bias + addend);
1964cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1965cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
1966cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if defined(__aarch64__)
19676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS64:
1968e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1969bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
19700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
1971bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
1972bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
1973e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
19746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS32:
1975e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1976bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
19770266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
1978bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
197920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
198020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
198120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
198220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
198320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
198420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + (sym_addr + addend)) <= max_value)) {
198520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
198620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
198720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
198820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   (reloc_value + (sym_addr + addend)), min_value, max_value);
198920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
199020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
1991e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
1992e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
19936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS16:
1994e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1995bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
19960266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
1997bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
199820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
199920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
200020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
200120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
200220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
200320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + (sym_addr + addend)) <= max_value)) {
200420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
200520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
200620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
200720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + (sym_addr + addend), min_value, max_value);
200820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
200920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2010e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2011e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL64:
2013e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
2014bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20150266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
2016bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
2017bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend) - rel->r_offset;
2018e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL32:
2020e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
2021bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
2023bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
202420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
202520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
202620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
202720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
202820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
202920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
203020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
203120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
203220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
203320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
203420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
203520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2036e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2037e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL16:
2039e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
2040bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20410266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
2042bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
204320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
204420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
204520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
204620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
204720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
204820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
204920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
205020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
205120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
205220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
205320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
205420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2055e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2056e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
2057e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland
20586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_COPY:
205976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich        /*
206076e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * ET_EXEC is not supported so this should not happen.
206176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
2062aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
206376e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
2064aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * Section 4.6.11 "Dynamic relocations"
206576e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * R_AARCH64_COPY may only appear in executable objects where e_type is
206676e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * set to ET_EXEC.
206776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         */
2068b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
2069114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov        return false;
20706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_TPREL64:
20710266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
2072bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset);
2073e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_DTPREL32:
20750266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
2076bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset);
2077e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
2078e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__)
20796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_32:
20806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2081bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
20836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
2084bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
20856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_64:
20876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2088bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
20906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
2091bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
20926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
20936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_PC32:
20946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2095bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
20976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
20986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
2099bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - reloc;
21006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2101bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__)
21026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_ABS32:
21036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
21046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
21066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
21076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_REL32:
21096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
21106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
21126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, sym_addr, rel->r_offset, sym_name);
21136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
21146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_COPY:
21166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        /*
21176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * ET_EXEC is not supported so this should not happen.
21186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
21196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
21206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
2121aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * Section 4.6.1.10 "Dynamic relocations"
21226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * R_ARM_COPY may only appear in executable objects where e_type is
21236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * set to ET_EXEC.
21246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         */
2125b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
2126114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov        return false;
21274eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__)
21286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_32:
21296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
21306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
21326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
21336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_PC32:
21356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
21366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
21386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
21396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
21406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21414eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
21426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
21436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
21446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2145d7daacb46372132ae3f0121647074936c304b572Raghu Gandham    }
21466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
21476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
2148d7daacb46372132ae3f0121647074936c304b572Raghu Gandham}
2149114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#endif  // !defined(__mips__)
2150d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
215120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid soinfo::call_array(const char* array_name __unused, linker_function_t* functions,
215220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                        size_t count, bool reverse) {
2153851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (functions == nullptr) {
2154d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2155d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
21568215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2157b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath());
21588215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2159ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int begin = reverse ? (count - 1) : 0;
2160ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int end = reverse ? -1 : count;
2161ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int step = reverse ? -1 : 1;
21628215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2163ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  for (int i = begin; i != end; i += step) {
2164ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
2165047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    call_function("function", functions[i]);
2166d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2167d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2168b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath());
21691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
21701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2171047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_function(const char* function_name __unused, linker_function_t function) {
2172851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
2173d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2174d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2175d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2176b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath());
2177d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  function();
2178b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath());
21799181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov}
21809181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
2181047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_pre_init_constructors() {
21828147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
21838147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // but ignored in a shared library.
2184047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false);
2185d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
2186e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
2187047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_constructors() {
2188d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  if (constructors_called) {
2189d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2190d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2191e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
2192d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // We set constructors_called before actually calling the constructors, otherwise it doesn't
2193d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // protect against recursive constructor calls. One simple example of constructor recursion
2194d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
2195d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 1. The program depends on libc, so libc's constructor is called here.
2196d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
2197d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 3. dlopen() calls the constructors on the newly created
2198d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    soinfo for libc_malloc_debug_leak.so.
2199d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 4. The debug .so depends on libc, so CallConstructors is
2200d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    called again with the libc soinfo. If it doesn't trigger the early-
2201d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    out above, the libc constructor will be called again (recursively!).
2202d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  constructors_called = true;
2203d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2204ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!is_main_executable() && preinit_array_ != nullptr) {
22058147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes    // The GNU dynamic linker silently ignores these, but we warn the developer.
2206c620059479c47a78d57086d73726c9adc2f337adElliott Hughes    PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
2207b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          get_realpath(), preinit_array_count_);
2208d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
22091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2210d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  get_children().for_each([] (soinfo* si) {
2211047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    si->call_constructors();
2212d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
22131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2214b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("\"%s\": calling constructors", get_realpath());
22158147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
22168147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_INIT should be called before DT_INIT_ARRAY if both are present.
2217047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_function("DT_INIT", init_func_);
2218047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false);
2219e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov}
22208215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2221047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_destructors() {
222214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!constructors_called) {
222314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return;
222414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
2225b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("\"%s\": calling destructors", get_realpath());
22268147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
22278147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI_ARRAY must be parsed in reverse order.
2228047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true);
22298147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
22308147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI should be called after DT_FINI_ARRAY if both are present.
2231047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_function("DT_FINI", fini_func_);
2232b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
2233b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // This is needed on second call to dlopen
2234b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // after library has been unloaded with RTLD_NODELETE
2235b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  constructors_called = false;
22361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
22371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2238d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) {
22390d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2240047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    child->parents_.push_back(this);
2241047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->children_.push_back(child);
2242d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2243d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2244d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2245d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() {
22460d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (!has_min_version(0)) {
2247d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    return;
2248d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2249d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2250d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 1. Untie connected soinfos from 'this'.
2251047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  children_.for_each([&] (soinfo* child) {
2252047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    child->parents_.remove_if([&] (const soinfo* parent) {
2253d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return parent == this;
2254d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
2255d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
2256d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2257047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  parents_.for_each([&] (soinfo* parent) {
2258047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    parent->children_.remove_if([&] (const soinfo* child) {
2259d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return child == this;
2260d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
2261d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
2262d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2263d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 2. Once everything untied - clear local lists.
2264047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  parents_.clear();
2265047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  children_.clear();
2266d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2267d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2268d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovdev_t soinfo::get_st_dev() const {
22690d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2270047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return st_dev_;
2271d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2272d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
22730d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
2274d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov};
2275d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2276d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovino_t soinfo::get_st_ino() const {
22770d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2278047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return st_ino_;
2279d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2280d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
22810d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
2282d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2283d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2284d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovoff64_t soinfo::get_file_offset() const {
228507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if (has_min_version(1)) {
2286047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return file_offset_;
228707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  }
228807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
228907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  return 0;
229007e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov}
229107e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
2292d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_rtld_flags() const {
2293e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if (has_min_version(1)) {
2294047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return rtld_flags_;
2295e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  }
2296e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
2297e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  return 0;
2298e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
2299e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
2300d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_dt_flags_1() const {
2301d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (has_min_version(1)) {
2302047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return dt_flags_1_;
2303d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
2304d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2305d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return 0;
2306d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
2307618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
2308d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovvoid soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
2309d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (has_min_version(1)) {
2310d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
2311047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      rtld_flags_ |= RTLD_GLOBAL;
2312d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
2313d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2314d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((dt_flags_1 & DF_1_NODELETE) != 0) {
2315047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      rtld_flags_ |= RTLD_NODELETE;
2316d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
2317d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2318047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    dt_flags_1_ = dt_flags_1;
2319d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
2320d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
2321d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2322aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_realpath() const {
232369a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__)
2324aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (has_min_version(2)) {
2325aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return realpath_.c_str();
2326aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  } else {
2327aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return old_name_;
2328aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
2329aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
2330aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  return realpath_.c_str();
2331aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
2332aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov}
2333aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
2334aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_soname() const {
233569a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__)
2336618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  if (has_min_version(2)) {
2337618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    return soname_;
2338618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  } else {
2339aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return old_name_;
2340618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  }
2341aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
2342aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  return soname_;
2343aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
2344618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov}
2345618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
234614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if
2347d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set.
2348d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list;
2349d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2350d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() {
23510d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2352047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return children_;
2353d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2354d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
23550d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return g_empty_list;
2356d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2357d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
23582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst soinfo::soinfo_list_t& soinfo::get_children() const {
23592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(0)) {
23602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return children_;
23612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
23622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
23632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return g_empty_list;
23642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
23652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
236614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() {
2367047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (has_min_version(0)) {
2368047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return parents_;
236914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
237014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
2371047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  return g_empty_list;
237214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
237314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
23742a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
23759aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
23769aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov    return call_ifunc_resolver(s->st_value + load_bias);
23779aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  }
23789aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
23799aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return static_cast<ElfW(Addr)>(s->st_value + load_bias);
23809aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov}
23819aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
23826cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanovconst char* soinfo::get_string(ElfW(Word) index) const {
2383047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (has_min_version(1) && (index >= strtab_size_)) {
2384aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
2385b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        get_realpath(), strtab_size_, index);
23866cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov  }
23876cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2388047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  return strtab_ + index;
23896cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov}
23906cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2391ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovbool soinfo::is_gnu_hash() const {
2392ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_GNU_HASH) != 0;
2393ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
2394ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
23951b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanovbool soinfo::can_unload() const {
2396d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0;
23971b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
2398d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2399ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_linked() const {
2400ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_LINKED) != 0;
2401ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2402ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2403ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_main_executable() const {
2404ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_EXE) != 0;
2405ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2406ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2407ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linked() {
2408ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_LINKED;
2409ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2410ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2411ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linker_flag() {
2412ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_LINKER;
2413ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2414ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2415ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_main_executable() {
2416ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_EXE;
2417ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2418ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2419ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::increment_ref_count() {
2420ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  local_group_root_->ref_count_++;
2421ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2422ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2423ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsize_t soinfo::decrement_ref_count() {
2424ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return --local_group_root_->ref_count_;
2425ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2426ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2427ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsoinfo* soinfo::get_local_group_root() const {
2428ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return local_group_root_;
2429ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2430ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
243104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// This function returns api-level at the time of
243204f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// dlopen/load. Note that libraries opened by system
243304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// will always have 'current' api level.
243404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanovuint32_t soinfo::get_target_sdk_version() const {
243504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if (!has_min_version(2)) {
243604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    return __ANDROID_API__;
243704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  }
243804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
243904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  return local_group_root_->target_sdk_version_;
244004f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov}
244104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
2442047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovbool soinfo::prelink_image() {
2443e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  /* Extract dynamic section */
2444e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  ElfW(Word) dynamic_flags = 0;
2445e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
2446498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov
24476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can't log anything until the linker is relocated */
2448ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
24496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!relocating_linker) {
245053ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov    INFO("[ linking %s ]", get_realpath());
2451ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
24526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
24536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
24546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dynamic == nullptr) {
2455b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    if (!relocating_linker) {
2456b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
2457b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    }
24586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
24596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
24606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (!relocating_linker) {
24616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DEBUG("dynamic = %p", dynamic);
246263f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner    }
24636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
246463f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
24654eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
24666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
24676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                  &ARM_exidx, &ARM_exidx_count);
246863f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif
246963f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
24706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract useful information from dynamic section.
2471618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // Note that: "Except for the DT_NULL element at the end of the array,
2472618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // and the relative order of DT_NEEDED elements, entries may appear in any order."
2473618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  //
2474618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
24756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  uint32_t needed_count = 0;
24766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
24776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
24786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
24796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    switch (d->d_tag) {
24804a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SONAME:
2481618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov        // this is parsed after we have strtab initialized (see below).
24824a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2483ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
24846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_HASH:
2485047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2486047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2487047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2488047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
24896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2490ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2491ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      case DT_GNU_HASH:
24923597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov        gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2493ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        // skip symndx
2494047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2495047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
2496ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2497047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
24983597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov        gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
2499ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        // amend chain for symndx = header[1]
250020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
250120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2502ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2503047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        if (!powerof2(gnu_maskwords_)) {
250420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
2505aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov              gnu_maskwords_, get_realpath());
2506ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov          return false;
2507ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        }
2508047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        --gnu_maskwords_;
2509ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2510ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        flags_ |= FLAG_GNU_HASH;
2511ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        break;
2512ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
25136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_STRTAB:
2514047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
25156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2516ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25176cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      case DT_STRSZ:
2518047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        strtab_size_ = d->d_un.d_val;
25196cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        break;
2520ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMTAB:
2522047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
25236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2524ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25254a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SYMENT:
25264a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Sym))) {
2527aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2528aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov              static_cast<size_t>(d->d_un.d_val), get_realpath());
25294a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
25304a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
25314a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2532ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTREL:
2534513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#if defined(USE_RELA)
2535513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        if (d->d_un.d_val != DT_RELA) {
2536aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
2537513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov          return false;
2538513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        }
2539513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#else
25406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val != DT_REL) {
2541aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
25426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
25436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
2544c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
2545513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        break;
2546ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_JMPREL:
25484eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2549047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
2550c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
2551047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
2552c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
25536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2554ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTRELSZ:
25564eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2557047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
2558c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
2559047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
2560c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
25616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2562ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTGOT:
25644a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__)
25656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Used by mips and mips64.
2566047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
2567c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
25684a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // Ignore for other platforms... (because RTLD_LAZY is not supported)
25694a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2570ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_DEBUG:
25726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_DEBUG entry to the address of _r_debug for GDB
25736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // if the dynamic table is writable
25749918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64
25759918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree.
257614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as
25779918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable.
25789918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__))
25796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if ((dynamic_flags & PF_W) != 0) {
25806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
25816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
25829918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif
2583c6292ea39cce054175e4f9f797c05aeb8da0ac4bDmitriy Ivanov        break;
25844eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
25856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
2586047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
25876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2588ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELASZ:
2590047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
25916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2592ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
259318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELA:
259418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
259518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
259618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
259718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELASZ:
259818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_size_ = d->d_un.d_val;
259918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
260018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
260118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_REL:
2602aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
260318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
260418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
260518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELSZ:
2606aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
260718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
260818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
26094a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELAENT:
26104a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rela))) {
2611f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
26124a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
26134a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
26144a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2615ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2616ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // ignored (see DT_RELCOUNT comments for details)
26174a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELACOUNT:
26184a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2619ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
2621aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
26226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2623ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
2625aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
26266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
262718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2628c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
26296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
2630047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
26316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2632ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
2634047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
26356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2636ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26374a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELENT:
26384a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rel))) {
2639f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
26404a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
26414a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
26424a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2643ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
264418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_REL:
264518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
264618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
264718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
264818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELSZ:
264918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_size_ = d->d_un.d_val;
265018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
265118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
265218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELA:
2653aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
265418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
265518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
265618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELASZ:
2657aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
265818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
265918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2660ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // "Indicates that all RELATIVE relocations have been concatenated together,
2661ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // and specifies the RELATIVE relocation count."
2662ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      //
2663ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // TODO: Spec also mentions that this can be used to optimize relocation process;
2664ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Not currently used by bionic linker - ignored.
26654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELCOUNT:
26664a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
266718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
26686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
2669aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
26706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
267118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
267218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_RELASZ:
2673aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
267418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
267518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2676c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
26776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT:
2678047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
2679aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
26806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2681ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI:
2683047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
2684aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
26856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2686ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAY:
2688047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2689aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
26906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2691ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAYSZ:
26931649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
26946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2695ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAY:
2697047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2698aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
26996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2700ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAYSZ:
27021649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
27036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2704ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAY:
2706047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2707aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
27086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2709ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAYSZ:
27111649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
27126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2713ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_TEXTREL:
271556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__)
2716aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
27176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
271856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else
271956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov        has_text_relocations = true;
272056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov        break;
272156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
2722ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMBOLIC:
272496bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        has_DT_SYMBOLIC = true;
27256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2726ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_NEEDED:
27286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        ++needed_count;
27296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2730ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FLAGS:
27326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val & DF_TEXTREL) {
273356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__)
2734aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
27356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
273656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else
273756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov          has_text_relocations = true;
273856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
27396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
274096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        if (d->d_un.d_val & DF_SYMBOLIC) {
274196bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov          has_DT_SYMBOLIC = true;
274296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        }
27436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2744ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27456cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      case DT_FLAGS_1:
2746d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        set_dt_flags_1(d->d_un.d_val);
27476cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2748d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
2749ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov          DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
27506cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        }
27516cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        break;
27524eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
27536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_MAP:
27546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
27556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        {
27566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
27576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *dp = &_r_debug;
27586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
27596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2760688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham      case DT_MIPS_RLD_MAP2:
2761688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
2762688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        {
276320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          r_debug** dp = reinterpret_cast<r_debug**>(
276420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
2765688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham          *dp = &_r_debug;
2766688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        }
2767688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        break;
2768ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_VERSION:
27706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_FLAGS:
27716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_BASE_ADDRESS:
27726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_UNREFEXTNO:
27736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2774d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
27756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_SYMTABNO:
2776047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_symtabno_ = d->d_un.d_val;
27776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2778d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
27796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_LOCAL_GOTNO:
2780047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_local_gotno_ = d->d_un.d_val;
27816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2782d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
27836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_GOTSYM:
2784047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_gotsym_ = d->d_un.d_val;
27856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
27864eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
2787ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
2788ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      case DT_BIND_NOW:
2789ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov        break;
2790ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2791513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERSYM:
27922a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
27932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
27942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2795513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERDEF:
27962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verdef_ptr_ = load_bias + d->d_un.d_ptr;
27972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
2798513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERDEFNUM:
27992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verdef_cnt_ = d->d_un.d_val;
28002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
28012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2802e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko      case DT_VERNEED:
28032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verneed_ptr_ = load_bias + d->d_un.d_ptr;
28042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
28052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2806e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko      case DT_VERNEEDNUM:
28072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verneed_cnt_ = d->d_un.d_val;
2808513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        break;
2809d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
28118f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        if (!relocating_linker) {
2812aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
28138f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov              reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
28148f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        }
28156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
28161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
28176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
28181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
28196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
2820047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        reinterpret_cast<void*>(base), strtab_, symtab_);
28211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
28226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Sanity checks.
28236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (relocating_linker && needed_count != 0) {
28246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
28256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
28273597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  if (nbucket_ == 0 && gnu_nbucket_ == 0) {
2828aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
2829b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        "(new hash type from the future?)", get_realpath());
28306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2832047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (strtab_ == 0) {
2833b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
28346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2836047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (symtab_ == 0) {
2837b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
28386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
284038c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov
284107f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  // second pass - parse entries relying on strtab
284207f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
284307f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov    if (d->d_tag == DT_SONAME) {
284407f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      soname_ = get_string(d->d_un.d_val);
284507f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#if defined(__work_around_b_19059885__)
284607f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      strlcpy(old_name_, soname_, sizeof(old_name_));
284707f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#endif
284807f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      break;
284907f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov    }
285007f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  }
285107f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov
285238c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // Before M release linker was using basename in place of soname.
285304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // In the case when dt_soname is absent some apps stop working
285438c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // because they can't find dt_needed library by soname.
285538c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // This workaround should keep them working. (applies only
285604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // for apps targeting sdk version <=22). Make an exception for
285704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // the main executable and linker; they do not need to have dt_soname
285804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
285904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov      get_application_target_sdk_version() <= 22) {
286038c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov    soname_ = basename(realpath_.c_str());
286138c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov    DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
286238c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov        get_realpath(), soname_);
286338c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  }
28646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
286514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
28661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
286718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovbool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
286818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                        const android_dlextinfo* extinfo) {
28691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2870ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  local_group_root_ = local_group.front();
2871ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (local_group_root_ == nullptr) {
2872ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_group_root_ = this;
2873ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
2874ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
287504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
287604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    target_sdk_version_ = get_application_target_sdk_version();
287704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  }
287804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
2879f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  VersionTracker version_tracker;
2880f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov
2881f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  if (!version_tracker.init(this)) {
2882f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    return false;
2883f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  }
2884f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov
288556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__)
288656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  if (has_text_relocations) {
288756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // Make segments writable to allow text relocations to work properly. We will later call
288856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
288956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    DL_WARN("%s has text relocations. This is wasting memory and prevents "
2890b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov            "security hardening. Please fix.", get_realpath());
289156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
289256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2893b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
289456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      return false;
289556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    }
289656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  }
289756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
289856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov
289918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov  if (android_relocs_ != nullptr) {
290018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    // check signature
290118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    if (android_relocs_size_ > 3 &&
290218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[0] == 'A' &&
290318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[1] == 'P' &&
290418870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov        android_relocs_[2] == 'S' &&
290518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[3] == '2') {
2906b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      DEBUG("[ android relocating %s ]", get_realpath());
290718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
290818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      bool relocated = false;
290918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      const uint8_t* packed_relocs = android_relocs_ + 4;
291018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      const size_t packed_relocs_size = android_relocs_size_ - 4;
291118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
291218870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov      relocated = relocate(
2913f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov          version_tracker,
291418870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov          packed_reloc_iterator<sleb128_decoder>(
291518870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov            sleb128_decoder(packed_relocs, packed_relocs_size)),
291618870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov          global_group, local_group);
291718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
291818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      if (!relocated) {
291918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
292018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      }
292118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    } else {
292218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      DL_ERR("bad android relocation header.");
292318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      return false;
292418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    }
292518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov  }
292618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
29274eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2928047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (rela_ != nullptr) {
2929b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s ]", get_realpath());
2930f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2931f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
29326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2933c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
29346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2935047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (plt_rela_ != nullptr) {
2936b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s plt ]", get_realpath());
2937f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2938f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
29396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
29401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
29416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
29429aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else
2943047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (rel_ != nullptr) {
2944b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s ]", get_realpath());
2945f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2946f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
29476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
29481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
29496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2950047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (plt_rel_ != nullptr) {
2951b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s plt ]", get_realpath());
2952f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2953f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
29546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2955c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith    }
29566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
29579aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif
2958c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
29594eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
2960dc145b510640202a60b0dfaef9d56cd8fc1c05a9Dmitriy Ivanov  if (!mips_relocate_got(version_tracker, global_group, local_group)) {
29616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
29626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2963d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif
2964d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
2965b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  DEBUG("[ finished linking %s ]", get_realpath());
29661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
296756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__)
296856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  if (has_text_relocations) {
296956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // All relocations are done, we can protect our segments back to read-only.
297056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
297156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      DL_ERR("can't protect segments for \"%s\": %s",
2972b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
297356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      return false;
297456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    }
297556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  }
297656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
297756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov
29786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can also turn on GNU RELRO protection */
29796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
29806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
2981b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov           get_realpath(), strerror(errno));
29826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
29836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
29849ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich
29856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Handle serializing/sharing the RELRO segment */
29866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
29876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
29886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                       extinfo->relro_fd) < 0) {
29896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
2990b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
29916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2992183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)    }
29936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
29946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
29956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                 extinfo->relro_fd) < 0) {
29966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
2997b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
29986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
29996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
30006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3001183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)
30026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  notify_gdb_of_load(this);
30036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
30041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
30051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3006468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
3007c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list.
3008c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers.
3009c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc.
3010c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */
3011812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) {
30124eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR)
30130266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
3014851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (ehdr_vdso == nullptr) {
30150266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    return;
30160266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
3017c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
301807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0);
3019ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
30200266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
30210266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phnum = ehdr_vdso->e_phnum;
30220266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
30230266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
30240266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
3025ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
3026047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->prelink_image();
3027047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr);
3028c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif
3029c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
3030c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
3031c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/*
3032d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below.
3033d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
30340d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__)
30350d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64"
30360d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else
30370d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker"
30380d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif
3039aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
3040aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// This is done to avoid calling c-tor prematurely
3041aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// because soinfo c-tor needs memory allocator
3042aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// which might be initialized after global variables.
3043aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic uint8_t linker_soinfo_for_gdb_buf[sizeof(soinfo)] __attribute__((aligned(8)));
3044aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic soinfo* linker_soinfo_for_gdb = nullptr;
3045d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3046d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list.
3047d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text"
3048d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to
3049d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
3050d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't
3051d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list.
3052d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
3053d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
3054aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0);
3055aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
305638263dd91a4b68e2ad0afe458c9a20cb360dafebDmitriy Ivanov  linker_soinfo_for_gdb->load_bias = linker_base;
3057d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3058d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  /*
3059d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * Set the dynamic field in the link map otherwise gdb will complain with
3060d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * the following:
3061d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   warning: .dynamic section for "/system/bin/linker" is not at the
3062d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   expected address (wrong library or version mismatch?)
3063d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   */
3064d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
3065d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
3066d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
3067aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov                                 &linker_soinfo_for_gdb->dynamic, nullptr);
3068aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
3069d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
3070d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
30710b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanovextern "C" int __system_properties_init(void);
30720b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov
3073d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/*
3074468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and
3075468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs
3076468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point.
3077468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
30780266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
30791a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING
30806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  struct timeval t0, t1;
30816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t0, 0);
30821a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif
30831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
308466c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  // Sanitize the environment.
308566c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  __libc_init_AT_SECURE(args);
3086be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
30870b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov  // Initialize system properties
30880b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov  __system_properties_init(); // may use 'environ'
30890b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov
30906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  debuggerd_init();
30911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
30926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Get a few environment variables.
309366c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  const char* LD_DEBUG = getenv("LD_DEBUG");
30946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (LD_DEBUG != nullptr) {
30956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    g_ld_debug_verbosity = atoi(LD_DEBUG);
30966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3097be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
309866c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  // These should have been sanitized by __libc_init_AT_SECURE, but the test
30996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // doesn't cost us anything.
31006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpath_env = nullptr;
31016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpreload_env = nullptr;
310266c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  if (!getauxval(AT_SECURE)) {
310366c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes    ldpath_env = getenv("LD_LIBRARY_PATH");
310466c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes    ldpreload_env = getenv("LD_PRELOAD");
31056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3107bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#if !defined(__LP64__)
3108bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov  if (personality(PER_LINUX32) == -1) {
3109bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov    __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
3110bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov  }
3111bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov#endif
3112bfa15e464ecfb43d93e468f166d91e4e6265f300Dmitriy Ivanov
31136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  INFO("[ android linker & debugger ]");
31141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
311507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
31166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
31176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
31186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* bootstrap the link map, the main exe always needs to be first */
3121ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  si->set_main_executable();
31226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(si->link_map_head);
31231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = 0;
31256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_name = args.argv[0];
31266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_prev = nullptr;
31276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_next = nullptr;
31281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_map = map;
31306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
31311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  init_linker_info_for_gdb(linker_base);
31331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract information passed from the kernel.
31356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
31366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phnum = args.getauxval(AT_PHNUM);
31376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->entry = args.getauxval(AT_ENTRY);
31381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Compute the value of si->base. We can't rely on the fact that
31406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * the first entry is the PHDR because this will not be true
31416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * for certain executables (e.g. some in the NDK unit test suite)
31426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   */
31436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->base = 0;
31446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
31456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->load_bias = 0;
31466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t i = 0; i < si->phnum; ++i) {
31476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (si->phdr[i].p_type == PT_PHDR) {
31486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
31496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
31506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
31518180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner    }
31526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->dynamic = nullptr;
31541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
31566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (elf_hdr->e_type != ET_DYN) {
31576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n");
31586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
31596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31602aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich
31616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
31626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_LIBRARY_PATH(ldpath_env);
31636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_PRELOAD(ldpreload_env);
31644fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
31656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  somain = si;
31665ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel
31676718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov  if (!si->prelink_image()) {
31686718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
31696718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov    exit(EXIT_FAILURE);
31706718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov  }
317114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
3172d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // add somain to global group
3173d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
3174d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
31756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Load ld_preloads and dependencies.
31766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  StringLinkedList needed_library_name_list;
31776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t needed_libraries_count = 0;
31786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t ld_preloads_count = 0;
3179d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
3180d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (const auto& ld_preload_name : g_ld_preload_names) {
3181d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    needed_library_name_list.push_back(ld_preload_name.c_str());
31826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
318353ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov    ++ld_preloads_count;
31846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
318514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
31866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for_each_dt_needed(si, [&](const char* name) {
31876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    needed_library_name_list.push_back(name);
31886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
31896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  });
319014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
31916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* needed_library_names[needed_libraries_count];
319214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
31936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  memset(needed_library_names, 0, sizeof(needed_library_names));
31946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
319514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
3196d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  if (needed_libraries_count > 0 &&
3197d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      !find_libraries(si, needed_library_names, needed_libraries_count, nullptr,
3198d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov          &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
31996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
32006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
3201ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else if (needed_libraries_count == 0) {
3202ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
3203ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
3204ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      exit(EXIT_FAILURE);
3205ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
3206ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    si->increment_ref_count();
32076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
32081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
32096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  add_vdso(args);
3210c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
3211279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  {
3212279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    ProtectedDataGuard guard;
32139181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
3214279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    si->call_pre_init_constructors();
3215279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
3216279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    /* After the prelink_image, the si->load_bias is initialized.
3217279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
3218279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * We need to update this value for so exe here. So Unwind_Backtrace
3219279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * for some arch like x86 could work correctly within so exe.
3220279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     */
3221279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    map->l_addr = si->load_bias;
3222279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    si->call_constructors();
3223279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
3224e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
32251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
32266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t1, nullptr);
32276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) (
32286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
32296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
32301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
32311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
32326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0],
32336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocAbsolute],
32346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocRelative],
32356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocCopy],
32366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocSymbol]);
32371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
32381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
32396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  {
32406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned n;
32416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned i;
32426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned count = 0;
32436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    for (n = 0; n < 4096; n++) {
32446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (bitmask[n]) {
32456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        unsigned x = bitmask[n];
3246e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__)
32476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 32; i++) {
3248e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else
32496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 8; i++) {
3250e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif
32516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          if (x & 1) {
32526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            count++;
32536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          }
32546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          x >>= 1;
32551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
32566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
32571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
32586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4);
32596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
32601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
32611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
32621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
32636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  fflush(stdout);
32641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
32651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3266b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry));
32676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return si->entry;
32681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3269468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
3270bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only
3271bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library
3272bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself.
3273bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *
3274bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input:
3275bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    elf    -> address of ELF header, assumed to be at the start of the file.
3276bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return:
3277bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    load bias, i.e. add the value of any p_vaddr in the file to get
3278bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    the corresponding address in memory.
3279bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */
32800266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
32810266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) offset = elf->e_phoff;
3282b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  const ElfW(Phdr)* phdr_table =
3283b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
32840266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
3285fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
32860266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
3287fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (phdr->p_type == PT_LOAD) {
32880266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
3289bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner    }
3290fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
3291fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  return 0;
3292bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner}
3293bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner
3294efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start();
3295efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
3296468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
3297468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This
3298468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and
3299468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation().
3300468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich *
3301468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own
3302468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern
3303468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault.
3304468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
33050266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) {
330642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  KernelArgumentBlock args(raw_args);
330742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
33080266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
3309efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
33100266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
3311faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
331242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3313aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  soinfo linker_so(nullptr, nullptr, 0, 0);
331442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3315efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // If the linker is not acting as PT_INTERP entry_point is equal to
3316efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // _start. Which means that the linker is running as an executable and
3317efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // already linked by PT_INTERP.
3318efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  //
3319efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // This happens when user tries to run 'adb shell /system/bin/linker'
3320efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // see also https://code.google.com/p/android/issues/detail?id=63174
3321efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
3322efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov    __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
3323efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  }
3324efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
332542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.base = linker_addr;
332642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
332742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
3328851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  linker_so.dynamic = nullptr;
332942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phdr = phdr;
333042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phnum = elf_hdr->e_phnum;
3331ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  linker_so.set_linker_flag();
333242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3333d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // This might not be obvious... The reasons why we pass g_empty_list
3334d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // in place of local_group here are (1) we do not really need it, because
3335d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
3336d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // itself without having to look into local_group and (2) allocators
3337d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // are not yet initialized, and therefore we cannot use linked_list.push_*
3338d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // functions at this point.
3339047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
334042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // It would be nice to print an error message, but if the linker
334142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // can't link itself, there's no guarantee that we'll be able to
3342b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // call write() (because it involves a GOT reference). We may as
3343b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // well try though...
3344b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    const char* msg = "CANNOT LINK EXECUTABLE: ";
3345b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, msg, strlen(msg));
3346b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
3347b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, "\n", 1);
3348b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    _exit(EXIT_FAILURE);
334942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
3350468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
335114241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov  __libc_init_tls(args);
335214241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov
3353efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // Initialize the linker's own global variables
3354047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  linker_so.call_constructors();
33554151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov
33560d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // Initialize static variables. Note that in order to
33570d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // get correct libdl_info we need to call constructors
33580d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // before get_libdl_info().
33590d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  solist = get_libdl_info();
33600d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  sonext = get_libdl_info();
33610d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
336242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // We have successfully fixed our own relocations. It's safe to run
336342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // the main part of the linker now.
33641728b2396591853345507a063ed6075dfd251706Elliott Hughes  args.abort_message_ptr = &g_abort_message;
33650266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
33665419b9474753d25dff947c7740532f86d130c0beElliott Hughes
3367611f95689e1012283bd11917003d3740d3ce532dElliott Hughes  INFO("[ jumping to _start ]");
3368611f95689e1012283bd11917003d3740d3ce532dElliott Hughes
336942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // Return the address that the calling assembly stub should jump to.
337042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  return start_address;
3371468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich}
3372