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>
404688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes#include <unistd.h>
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
420d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#include <new>
43d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <string>
44d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov#include <vector>
450d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
464688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes// Private C library headers.
47eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h"
48eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/KernelArgumentBlock.h"
49eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/ScopedPthreadMutexLocker.h"
5014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/ScopeGuard.h"
5114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov#include "private/UniquePtr.h"
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h"
54c9ce70d7838b6aae074fc3615cdf04e5c9ac612aDmitriy Ivanov#include "linker_block_allocator.h"
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h"
5618870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov#include "linker_sleb128.h"
5723363ed7503c25ef4024ce0d517f7415c096645dDavid 'Digit' Turner#include "linker_phdr.h"
58cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#include "linker_relocs.h"
59fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#include "linker_reloc_iterators.h"
60aef719510a57274e73ca02ab5ecdc5bf17d3985cSimon Baldwin#include "ziparchive/zip_archive.h"
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6266c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughesextern void __libc_init_AT_SECURE(KernelArgumentBlock&);
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6466c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes// Override macros to use C++ style casts.
651649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#undef ELF_ST_TYPE
661649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
671649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov
680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
70600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<soinfo> g_soinfo_allocator;
71600bc3cb9342fbb1dc16ea25f5b676ce072e3e1bDmitriy Ivanovstatic LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
72ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
73d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* solist;
74d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo* sonext;
756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanovstatic soinfo* somain; // main process, always the one after libdl_info
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
771728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic const char* const kDefaultLdPaths[] = {
784eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__LP64__)
79011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/vendor/lib64",
80011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes  "/system/lib64",
81011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#else
82124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/vendor/lib",
83124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  "/system/lib",
84011bc0ba45a8b7766a205cb21269dbafb32294b6Elliott Hughes#endif
85851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  nullptr
86124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes};
87124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymNotNeeded = 0;
892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovstatic const ElfW(Versym) kVersymGlobal = 1;
902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
91d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_library_paths;
92d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<std::string> g_ld_preload_names;
93a4aafd156068ee174012f28cd894dbecf0e4ab90Elliott Hughes
94d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanovstatic std::vector<soinfo*> g_ld_preloads;
954fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
961728b2396591853345507a063ed6075dfd251706Elliott Hughes__LIBC_HIDDEN__ int g_ld_debug_verbosity;
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
98851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
990d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
101bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstruct linker_stats_t {
1026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  int count[kRelocMax];
103bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes};
104bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
105bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic linker_stats_t linker_stats;
106bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes
107114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind kind) {
1086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ++linker_stats.count[kind];
109bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
110bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes#else
111114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovvoid count_relocation(RelocationKind) {
112bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughes}
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
116114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanovuint32_t bitmask[4096];
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1192e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768];
1202e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
121650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hugheschar* linker_get_error_buffer() {
1225419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return &__linker_dl_err_buf[0];
1232e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin}
1242e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
125650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughessize_t linker_get_error_buffer_size() {
126650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes  return sizeof(__linker_dl_err_buf);
127650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes}
128650be4e584eeab3591b9e273bfd6d169eea60853Elliott Hughes
1296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// This function is an empty stub where GDB locates a breakpoint to get notified
1306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov// about linker activity.
13120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovextern "C"
13220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1341728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
13520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic r_debug _r_debug =
13620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov    {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
13720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov
1383a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic link_map* r_debug_tail = 0;
1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1403a9c5d66dc8d41272f51482b713717af7049697eElliott Hughesstatic void insert_soinfo_into_debug_map(soinfo* info) {
1416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Copy the necessary fields into the debug structure.
1426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
1436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = info->load_bias;
144aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  // link_map l_name field is not const.
145aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  map->l_name = const_cast<char*>(info->get_realpath());
1466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_ld = info->dynamic;
1476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
1486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Stick the new library at the end of the list.
1496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // gdb tends to care more about libc than it does
1506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // about leaf libraries, and ordering it this way
1516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // reduces the back-and-forth over the wire.
1526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail) {
1536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail->l_next = map;
1546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = r_debug_tail;
1556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
1566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
1576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    _r_debug.r_map = map;
1586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev = 0;
1596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next = 0;
1606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
164bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void remove_soinfo_from_debug_map(soinfo* info) {
1656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(info->link_map_head);
1665e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (r_debug_tail == map) {
1686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    r_debug_tail = map->l_prev;
1696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1705e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
1716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_prev) {
1726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_prev->l_next = map->l_next;
1736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (map->l_next) {
1756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    map->l_next->l_prev = map->l_prev;
1766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1775e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
1785e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
179bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_load(soinfo* info) {
180ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (info->is_main_executable()) {
1816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
1826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
1836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
1841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
1861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_ADD;
1886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
1891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  insert_soinfo_into_debug_map(info);
1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
1936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
1945e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
1955e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
196bedfe38b8ba512dd6236c00e8b4a9b01c2bd1281Elliott Hughesstatic void notify_gdb_of_unload(soinfo* info) {
197ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (info->is_main_executable()) {
1986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // GDB already knows about the main executable
1996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2015e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
2035e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_DELETE;
2056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2065e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  remove_soinfo_from_debug_map(info);
2085e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_state = r_debug::RT_CONSISTENT;
2106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  rtld_db_dlactivity();
2111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21318a206c81d9743481e364384affd43306911283dElliott Hughesvoid notify_gdb_of_libraries() {
2143a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_ADD;
2153a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2163a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  _r_debug.r_state = r_debug::RT_CONSISTENT;
2173a9c5d66dc8d41272f51482b713717af7049697eElliott Hughes  rtld_db_dlactivity();
2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
220d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy IvanovLinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
221d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  return g_soinfo_links_allocator.alloc();
222d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
223d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
224d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
225d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  g_soinfo_links_allocator.free(entry);
226d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
227d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
22820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovstatic soinfo* soinfo_alloc(const char* name, struct stat* file_stat,
22920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                            off64_t file_offset, uint32_t rtld_flags) {
230aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (strlen(name) >= PATH_MAX) {
231ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn    DL_ERR("library name \"%s\" too long", name);
232851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov    return nullptr;
233ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  }
234ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn
23507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags);
236d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
237ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext->next = si;
238ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  sonext = si;
2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
240ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  TRACE("name %s: allocated soinfo @ %p", name, si);
241ba98d9237b0eabc1d8caf2600fd787b988645249Magnus Malmborn  return si;
2421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
244faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughesstatic void soinfo_free(soinfo* si) {
2456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
2466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2484688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughes
2496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si->base != 0 && si->size != 0) {
2506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    munmap(reinterpret_cast<void*>(si->base), si->size);
2516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
252d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  soinfo *prev = nullptr, *trav;
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
255b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (trav = solist; trav != nullptr; trav = trav->next) {
2586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (trav == si) {
2596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    prev = trav;
2626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
263ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (trav == nullptr) {
2656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    // si was not in solist
266b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
2676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return;
2686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // clear links to/from si
2716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->remove_all_links();
272d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // prev will never be null, because the first entry in solist is
2746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // always the static libdl_info.
2756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  prev->next = si->next;
2766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == sonext) {
2776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    sonext = prev;
2786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
279d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
280a5bb841df799e10e7d0ae3202b097da8a1c23507Dmitriy Ivanov  si->~soinfo();
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.
356f7d5bf334dc4bc5b7399d4c8268e1b0bf676548fDmitriy Ivanovint do_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.
129606700b2b5e92a365505b15d0d05e2d5b0706c511Dmitriy Ivanov  ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
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        }
1924de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov      } else { // We got a definition.
1925de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#if !defined(__LP64__)
1926de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        // When relocating dso with text_relocation .text segment is
1927de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        // not executable. We need to restore elf flags before resolving
1928de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        // STT_GNU_IFUNC symbol.
1929de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        bool protect_segments = has_text_relocations &&
1930de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov                                lsi == this &&
1931de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov                                ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
1932de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        if (protect_segments) {
1933de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
1934de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov            DL_ERR("can't protect segments for \"%s\": %s",
1935de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov                   get_realpath(), strerror(errno));
1936de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov            return false;
1937de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          }
1938de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        }
1939de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#endif
19409aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov        sym_addr = lsi->resolve_symbol_address(s);
1941de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#if !defined(__LP64__)
1942de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        if (protect_segments) {
1943de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
1944de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov            DL_ERR("can't unprotect loadable segments for \"%s\": %s",
1945de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov                   get_realpath(), strerror(errno));
1946de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov            return false;
1947de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          }
1948de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        }
1949de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#endif
1950c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      }
1951c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes      count_relocation(kRelocSymbol);
1952c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
1953c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes
1954c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    switch (type) {
1955cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_JUMP_SLOT:
1956e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1957bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1958bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
1959bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
1960bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
1961bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov
1962bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
1963e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1964cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_GLOB_DAT:
1965e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
1966bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1967bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
1968bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
1969bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(sym_addr + addend), sym_name);
1970bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
1971e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
1972cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_RELATIVE:
1973cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1974bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1975bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
1976bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reinterpret_cast<void*>(reloc),
197718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                   reinterpret_cast<void*>(load_bias + addend));
197818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
1979cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
1980cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov      case R_GENERIC_IRELATIVE:
1981cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        count_relocation(kRelocRelative);
1982bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
1983bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
1984bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                    reinterpret_cast<void*>(reloc),
198518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                    reinterpret_cast<void*>(load_bias + addend));
1986de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        {
1987de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#if !defined(__LP64__)
1988de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          // When relocating dso with text_relocation .text segment is
1989de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          // not executable. We need to restore elf flags for this
1990de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          // particular call.
1991de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          if (has_text_relocations) {
1992de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov            if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
1993de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov              DL_ERR("can't protect segments for \"%s\": %s",
1994de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov                     get_realpath(), strerror(errno));
1995de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov              return false;
1996de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov            }
1997de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          }
1998de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#endif
1999de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2000de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#if !defined(__LP64__)
2001de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          // Unprotect it afterwards...
2002de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          if (has_text_relocations) {
2003de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov            if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2004de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov              DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2005de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov                     get_realpath(), strerror(errno));
2006de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov              return false;
2007de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov            }
2008de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          }
2009de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov#endif
2010de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov          *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2011de0fb393ae8136a5958fe17eee0c6285e2f7f91aDmitriy Ivanov        }
2012cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov        break;
2013cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov
2014cefef7dab67472d59d45ef1d002a20edf8edde75Dmitriy Ivanov#if defined(__aarch64__)
20156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS64:
2016e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
2017bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20180266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
2019bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
2020bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
2021e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS32:
2023e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
2024bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20250266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
2026bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
202720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
202820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
202920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
203020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
203120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
203220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + (sym_addr + addend)) <= max_value)) {
203320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
203420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
203520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
203620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   (reloc_value + (sym_addr + addend)), min_value, max_value);
203720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
203820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2039e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2040e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_ABS16:
2042e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocAbsolute);
2043bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20440266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
2045bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), sym_name);
204620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
204720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
204820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
204920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
205020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + (sym_addr + addend))) &&
205120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + (sym_addr + addend)) <= max_value)) {
205220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend);
205320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
205420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
205520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + (sym_addr + addend), min_value, max_value);
205620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
205720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2058e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2059e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL64:
2061e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
2062bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20630266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
2064bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
2065bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend) - rel->r_offset;
2066e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL32:
2068e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
2069bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
2071bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
207220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
207320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
207420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
207520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
207620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
207720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
207820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
207920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
208020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
208120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
208220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
208320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2084e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2085e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
20866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_PREL16:
2087e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        count_relocation(kRelocRelative);
2088bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
20890266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
2090bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset, sym_name);
209120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        {
209220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) reloc_value = *reinterpret_cast<ElfW(Addr)*>(reloc);
209320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
209420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
209520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) &&
209620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) {
209720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            *reinterpret_cast<ElfW(Addr)*>(reloc) += ((sym_addr + addend) - rel->r_offset);
209820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          } else {
209920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
210020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                   reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value);
210120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            return false;
210220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          }
2103e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        }
2104e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
2105e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland
21066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_COPY:
210776e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich        /*
210876e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * ET_EXEC is not supported so this should not happen.
210976e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
2110aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
211176e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         *
2112aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * Section 4.6.11 "Dynamic relocations"
211376e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * R_AARCH64_COPY may only appear in executable objects where e_type is
211476e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         * set to ET_EXEC.
211576e289c026f11126fc88841b3019fd5bb419bb67Nick Kralevich         */
2116b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
2117114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov        return false;
21186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_TPREL64:
21190266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
2120bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset);
2121e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
21226abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_AARCH64_TLS_DTPREL32:
21230266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes        TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
2124bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov                   reloc, (sym_addr + addend), rel->r_offset);
2125e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland        break;
2126e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#elif defined(__x86_64__)
21276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_32:
21286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2129bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
21306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
21316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
2132bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
21336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_64:
21356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2136bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
21376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
21386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), sym_name);
2139bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
21406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_X86_64_PC32:
21426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
2143bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        MARK(rel->r_offset);
21446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
21456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
21466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
2147bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - reloc;
21486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2149bcc04d0069a919a6ac4a2b378e15dd0a50c46aecDmitriy Ivanov#elif defined(__arm__)
21506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_ABS32:
21516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocAbsolute);
21526abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
21546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
21556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_REL32:
21576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
21586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21596abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
21606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, sym_addr, rel->r_offset, sym_name);
21616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
21626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_ARM_COPY:
21646abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        /*
21656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * ET_EXEC is not supported so this should not happen.
21666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
21676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
21686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         *
2169aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov         * Section 4.6.1.10 "Dynamic relocations"
21706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * R_ARM_COPY may only appear in executable objects where e_type is
21716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         * set to ET_EXEC.
21726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         */
2173b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
2174114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov        return false;
21754eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#elif defined(__i386__)
21766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_32:
21776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
21786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
21806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
21816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case R_386_PC32:
21836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        count_relocation(kRelocRelative);
21846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        MARK(rel->r_offset);
21856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
21866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                   reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
21876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
21886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
21894eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
21906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
21916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
21926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2193d7daacb46372132ae3f0121647074936c304b572Raghu Gandham    }
21946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
21956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
2196d7daacb46372132ae3f0121647074936c304b572Raghu Gandham}
2197114ff69f1753c7fe4d749f8fb0c082b80e0d43f4Dmitriy Ivanov#endif  // !defined(__mips__)
2198d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
219920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovvoid soinfo::call_array(const char* array_name __unused, linker_function_t* functions,
220020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov                        size_t count, bool reverse) {
2201851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (functions == nullptr) {
2202d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2203d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
22048215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2205b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath());
22068215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2207ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int begin = reverse ? (count - 1) : 0;
2208ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int end = reverse ? -1 : count;
2209ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  int step = reverse ? -1 : 1;
22108215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2211ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes  for (int i = begin; i != end; i += step) {
2212ca0c11bd823f37f03cc8067cb182876827d5275aElliott Hughes    TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
2213047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    call_function("function", functions[i]);
2214d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2215d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2216b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath());
22171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
22181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2219047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_function(const char* function_name __unused, linker_function_t function) {
2220851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
2221d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2222d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2223d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2224b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath());
2225d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  function();
2226b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath());
22279181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov}
22289181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
2229047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_pre_init_constructors() {
22308147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
22318147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // but ignored in a shared library.
2232047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false);
2233d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes}
2234e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
2235047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_constructors() {
2236d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  if (constructors_called) {
2237d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes    return;
2238d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
2239e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
2240d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // We set constructors_called before actually calling the constructors, otherwise it doesn't
2241d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // protect against recursive constructor calls. One simple example of constructor recursion
2242d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
2243d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 1. The program depends on libc, so libc's constructor is called here.
2244d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
2245d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 3. dlopen() calls the constructors on the newly created
2246d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    soinfo for libc_malloc_debug_leak.so.
2247d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  // 4. The debug .so depends on libc, so CallConstructors is
2248d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    called again with the libc soinfo. If it doesn't trigger the early-
2249d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  //    out above, the libc constructor will be called again (recursively!).
2250d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  constructors_called = true;
2251d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes
2252ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (!is_main_executable() && preinit_array_ != nullptr) {
22538147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes    // The GNU dynamic linker silently ignores these, but we warn the developer.
2254c620059479c47a78d57086d73726c9adc2f337adElliott Hughes    PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
2255b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov          get_realpath(), preinit_array_count_);
2256d23736e4f228e46304b7cbc674a1d0094d73e0f5Elliott Hughes  }
22571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2258d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  get_children().for_each([] (soinfo* si) {
2259047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    si->call_constructors();
2260d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
22611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2262b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("\"%s\": calling constructors", get_realpath());
22638147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
22648147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_INIT should be called before DT_INIT_ARRAY if both are present.
2265047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_function("DT_INIT", init_func_);
2266047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false);
2267e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov}
22688215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
2269047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovvoid soinfo::call_destructors() {
227014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  if (!constructors_called) {
227114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov    return;
227214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
2273b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("\"%s\": calling destructors", get_realpath());
22748147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
22758147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI_ARRAY must be parsed in reverse order.
2276047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true);
22778147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes
22788147d3c284932896ab6095232b355979b9eb33d3Elliott Hughes  // DT_FINI should be called after DT_FINI_ARRAY if both are present.
2279047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  call_function("DT_FINI", fini_func_);
2280b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
2281b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // This is needed on second call to dlopen
2282b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  // after library has been unloaded with RTLD_NODELETE
2283b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  constructors_called = false;
22841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
22851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2286d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::add_child(soinfo* child) {
22870d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2288047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    child->parents_.push_back(this);
2289047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    this->children_.push_back(child);
2290d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2291d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2292d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2293d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovvoid soinfo::remove_all_links() {
22940d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (!has_min_version(0)) {
2295d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    return;
2296d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2297d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2298d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 1. Untie connected soinfos from 'this'.
2299047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  children_.for_each([&] (soinfo* child) {
2300047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    child->parents_.remove_if([&] (const soinfo* parent) {
2301d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return parent == this;
2302d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
2303d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
2304d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2305047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  parents_.for_each([&] (soinfo* parent) {
2306047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    parent->children_.remove_if([&] (const soinfo* child) {
2307d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov      return child == this;
2308d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov    });
2309d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  });
2310d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2311d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  // 2. Once everything untied - clear local lists.
2312047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  parents_.clear();
2313047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  children_.clear();
2314d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2315d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2316d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovdev_t soinfo::get_st_dev() const {
23170d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2318047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return st_dev_;
2319d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2320d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
23210d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
2322d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov};
2323d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2324d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovino_t soinfo::get_st_ino() const {
23250d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2326047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return st_ino_;
2327d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2328d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
23290d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return 0;
2330d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2331d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2332d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovoff64_t soinfo::get_file_offset() const {
233307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  if (has_min_version(1)) {
2334047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return file_offset_;
233507e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  }
233607e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
233707e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  return 0;
233807e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov}
233907e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov
2340d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_rtld_flags() const {
2341e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  if (has_min_version(1)) {
2342047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return rtld_flags_;
2343e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  }
2344e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
2345e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  return 0;
2346e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
2347e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
2348d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovuint32_t soinfo::get_dt_flags_1() const {
2349d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (has_min_version(1)) {
2350047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return dt_flags_1_;
2351d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
2352d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2353d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return 0;
2354d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
2355618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
2356d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanovvoid soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
2357d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  if (has_min_version(1)) {
2358d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
2359047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      rtld_flags_ |= RTLD_GLOBAL;
2360d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
2361d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2362d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    if ((dt_flags_1 & DF_1_NODELETE) != 0) {
2363047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov      rtld_flags_ |= RTLD_NODELETE;
2364d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov    }
2365d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2366047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    dt_flags_1_ = dt_flags_1;
2367d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  }
2368d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
2369d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2370aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_realpath() const {
237169a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__)
2372aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  if (has_min_version(2)) {
2373aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return realpath_.c_str();
2374aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  } else {
2375aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return old_name_;
2376aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  }
2377aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
2378aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  return realpath_.c_str();
2379aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
2380aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov}
2381aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
2382aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovconst char* soinfo::get_soname() const {
238369a5fb951d69689dedd83cb033ae3dcd0ef05b65Dmitriy Ivanov#if defined(__work_around_b_19059885__)
2384618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  if (has_min_version(2)) {
2385618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov    return soname_;
2386618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  } else {
2387aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    return old_name_;
2388618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  }
2389aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
2390aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  return soname_;
2391aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
2392618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov}
2393618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
239414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// This is a return on get_children()/get_parents() if
2395d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov// 'this->flags' does not have FLAG_NEW_SOINFO set.
2396d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic soinfo::soinfo_list_t g_empty_list;
2397d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
2398d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_children() {
23990d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  if (has_min_version(0)) {
2400047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return children_;
2401d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  }
2402d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
24030d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  return g_empty_list;
2404d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
2405d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
24062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovconst soinfo::soinfo_list_t& soinfo::get_children() const {
24072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  if (has_min_version(0)) {
24082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov    return children_;
24092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  }
24102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
24112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return g_empty_list;
24122a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
24132a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
241414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanovsoinfo::soinfo_list_t& soinfo::get_parents() {
2415047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (has_min_version(0)) {
2416047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov    return parents_;
241714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  }
241814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
2419047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  return g_empty_list;
242014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
242114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
24222a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
24239aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
24249aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov    return call_ifunc_resolver(s->st_value + load_bias);
24259aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  }
24269aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
24279aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  return static_cast<ElfW(Addr)>(s->st_value + load_bias);
24289aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov}
24299aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
24306cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanovconst char* soinfo::get_string(ElfW(Word) index) const {
2431047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (has_min_version(1) && (index >= strtab_size_)) {
2432aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
2433b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        get_realpath(), strtab_size_, index);
24346cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov  }
24356cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2436047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  return strtab_ + index;
24376cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov}
24386cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2439ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanovbool soinfo::is_gnu_hash() const {
2440ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_GNU_HASH) != 0;
2441ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
2442ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
24431b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanovbool soinfo::can_unload() const {
2444d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0;
24451b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
2446d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
2447ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_linked() const {
2448ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_LINKED) != 0;
2449ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2450ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2451ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovbool soinfo::is_main_executable() const {
2452ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return (flags_ & FLAG_EXE) != 0;
2453ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2454ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2455ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linked() {
2456ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_LINKED;
2457ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2458ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2459ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_linker_flag() {
2460ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_LINKER;
2461ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2462ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2463ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::set_main_executable() {
2464ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  flags_ |= FLAG_EXE;
2465ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2466ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2467ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovvoid soinfo::increment_ref_count() {
2468ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  local_group_root_->ref_count_++;
2469ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2470ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2471ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsize_t soinfo::decrement_ref_count() {
2472ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return --local_group_root_->ref_count_;
2473ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2474ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
2475ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanovsoinfo* soinfo::get_local_group_root() const {
2476ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  return local_group_root_;
2477ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
2478ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
247904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// This function returns api-level at the time of
248004f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// dlopen/load. Note that libraries opened by system
248104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov// will always have 'current' api level.
248204f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanovuint32_t soinfo::get_target_sdk_version() const {
248304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if (!has_min_version(2)) {
248404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    return __ANDROID_API__;
248504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  }
248604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
248704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  return local_group_root_->target_sdk_version_;
248804f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov}
248904f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
2490047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanovbool soinfo::prelink_image() {
2491e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  /* Extract dynamic section */
2492e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  ElfW(Word) dynamic_flags = 0;
2493e93be99da0614ff38cbf8b2bb0624ff1dc79b8d0Ningsheng Jian  phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
2494498eb18b82a425f9f30132e4832f327b2ee0e545Dmitriy Ivanov
24956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can't log anything until the linker is relocated */
2496ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
24976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (!relocating_linker) {
249853ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov    INFO("[ linking %s ]", get_realpath());
2499ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
25006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
25016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov
25026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (dynamic == nullptr) {
2503b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    if (!relocating_linker) {
2504b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
2505b52e4385c403d18a68309e568ac729c787d900c4David 'Digit' Turner    }
25066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
25076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else {
25086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (!relocating_linker) {
25096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DEBUG("dynamic = %p", dynamic);
251063f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner    }
25116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
251263f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
25134eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__arm__)
25146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
25156abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                  &ARM_exidx, &ARM_exidx_count);
251663f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner#endif
251763f99f4a4e05353de2e8ba3d7bd4d882d716167aDavid 'Digit' Turner
25186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract useful information from dynamic section.
2519618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // Note that: "Except for the DT_NULL element at the end of the array,
2520618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // and the relative order of DT_NEEDED elements, entries may appear in any order."
2521618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  //
2522618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
25236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  uint32_t needed_count = 0;
25246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
25256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
25266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
25276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    switch (d->d_tag) {
25284a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SONAME:
2529618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov        // this is parsed after we have strtab initialized (see below).
25304a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2531ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25326abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_HASH:
2533047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2534047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2535047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
2536047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
25376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2538ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2539ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov      case DT_GNU_HASH:
25403597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov        gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
2541ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        // skip symndx
2542047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
2543047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
2544ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2545047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
25463597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov        gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
2547ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        // amend chain for symndx = header[1]
254820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov        gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
254920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov            reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
2550ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2551047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        if (!powerof2(gnu_maskwords_)) {
255220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
2553aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov              gnu_maskwords_, get_realpath());
2554ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov          return false;
2555ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        }
2556047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        --gnu_maskwords_;
2557ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
2558ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov        flags_ |= FLAG_GNU_HASH;
2559ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov        break;
2560ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
25616abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_STRTAB:
2562047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
25636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2564ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25656cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      case DT_STRSZ:
2566047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        strtab_size_ = d->d_un.d_val;
25676cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        break;
2568ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMTAB:
2570047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
25716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2572ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25734a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_SYMENT:
25744a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Sym))) {
2575aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
2576aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov              static_cast<size_t>(d->d_un.d_val), get_realpath());
25774a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
25784a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
25794a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2580ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTREL:
2582513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#if defined(USE_RELA)
2583513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        if (d->d_un.d_val != DT_RELA) {
2584aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
2585513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov          return false;
2586513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        }
2587513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov#else
25886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val != DT_REL) {
2589aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
25906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
25916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
2592c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
2593513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        break;
2594ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
25956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_JMPREL:
25964eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2597047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
2598c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
2599047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
2600c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
26016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2602ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTRELSZ:
26044eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2605047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
2606c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
2607047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
2608c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
26096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2610ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PLTGOT:
26124a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov#if defined(__mips__)
26136abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Used by mips and mips64.
2614047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
2615c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
26164a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        // Ignore for other platforms... (because RTLD_LAZY is not supported)
26174a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2618ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_DEBUG:
26206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_DEBUG entry to the address of _r_debug for GDB
26216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // if the dynamic table is writable
26229918665a45095ad135576f005c0e5307feb366a1Chris Dearman// FIXME: not working currently for N64
26239918665a45095ad135576f005c0e5307feb366a1Chris Dearman// The flags for the LOAD and DYNAMIC program headers do not agree.
262414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// The LOAD section containing the dynamic table has been mapped as
26259918665a45095ad135576f005c0e5307feb366a1Chris Dearman// read-only, but the DYNAMIC header claims it is writable.
26269918665a45095ad135576f005c0e5307feb366a1Chris Dearman#if !(defined(__mips__) && defined(__LP64__))
26276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if ((dynamic_flags & PF_W) != 0) {
26286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
26296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
26309918665a45095ad135576f005c0e5307feb366a1Chris Dearman#endif
2631c6292ea39cce054175e4f9f797c05aeb8da0ac4bDmitriy Ivanov        break;
26324eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
26336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
2634047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
26356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2636ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELASZ:
2638047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
26396abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2640ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
264118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELA:
264218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
264318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
264418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
264518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELASZ:
264618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_size_ = d->d_un.d_val;
264718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
264818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
264918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_REL:
2650aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
265118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
265218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
265318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELSZ:
2654aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
265518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
265618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
26574a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELAENT:
26584a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rela))) {
2659f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
26604a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
26614a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
26624a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2663ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2664ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // ignored (see DT_RELCOUNT comments for details)
26654a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELACOUNT:
26664a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2667ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26686abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
2669aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
26706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
2671ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
2673aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
26746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
267518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2676c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#else
26776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_REL:
2678047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
26796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2680ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELSZ:
2682047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
26836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2684ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
26854a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELENT:
26864a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        if (d->d_un.d_val != sizeof(ElfW(Rel))) {
2687f240aa8089ea1574a7d799720efb66528f6ceb99Dmitriy Ivanov          DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
26884a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov          return false;
26894a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        }
26904a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
2691ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
269218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_REL:
269318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
269418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
269518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
269618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELSZ:
269718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_size_ = d->d_un.d_val;
269818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        break;
269918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
270018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELA:
2701aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
270218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
270318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
270418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_ANDROID_RELASZ:
2705aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
270618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
270718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2708ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // "Indicates that all RELATIVE relocations have been concatenated together,
2709ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // and specifies the RELATIVE relocation count."
2710ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      //
2711ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // TODO: Spec also mentions that this can be used to optimize relocation process;
2712ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Not currently used by bionic linker - ignored.
27134a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov      case DT_RELCOUNT:
27144a6e9a835a84aca965f0170f604381dae7f130beDmitriy Ivanov        break;
271518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
27166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_RELA:
2717aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
27186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
271918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
272018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      case DT_RELASZ:
2721aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
272218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
272318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
2724c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes#endif
27256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT:
2726047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
2727aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
27286abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2729ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27306abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI:
2731047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
2732aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
27336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2734ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAY:
2736047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2737aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
27386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2739ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_INIT_ARRAYSZ:
27411649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
27426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2743ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAY:
2745047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2746aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
27476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2748ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FINI_ARRAYSZ:
27501649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
27516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2752ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAY:
2754047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
2755aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
27566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2757ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_PREINIT_ARRAYSZ:
27591649e7ee5b9bb4122be67903d55c4c8cc0549bbaDmitriy Ivanov        preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
27606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2761ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_TEXTREL:
276356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__)
2764aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov        DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
27656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        return false;
276656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else
276756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov        has_text_relocations = true;
276856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov        break;
276956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
2770ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_SYMBOLIC:
277296bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        has_DT_SYMBOLIC = true;
27736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2774ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_NEEDED:
27766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        ++needed_count;
27776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2778ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_FLAGS:
27806abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        if (d->d_un.d_val & DF_TEXTREL) {
278156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if defined(__LP64__)
2782aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
27836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          return false;
278456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#else
278556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov          has_text_relocations = true;
278656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
27876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
278896bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        if (d->d_un.d_val & DF_SYMBOLIC) {
278996bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov          has_DT_SYMBOLIC = true;
279096bc37f2e1093416a432135265fd7a4db6c3df17Dmitriy Ivanov        }
27916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2792ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
27936cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov      case DT_FLAGS_1:
2794d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        set_dt_flags_1(d->d_un.d_val);
27956cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov
2796d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov        if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
2797ca10ac6dd45f73752e8822fee606d83116a5721aDmitriy Ivanov          DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
27986cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        }
27996cdeb5234d7f4523fe9d83974f265d80f10512a6Dmitriy Ivanov        break;
28004eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
28016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_MAP:
28026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
28036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        {
28046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
28056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          *dp = &_r_debug;
28066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        }
28076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2808688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham      case DT_MIPS_RLD_MAP2:
2809688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
2810688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        {
281120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov          r_debug** dp = reinterpret_cast<r_debug**>(
281220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov              reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
2813688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham          *dp = &_r_debug;
2814688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        }
2815688157295f55edbfddb2277e7bdf5635f6be591aRaghu Gandham        break;
2816ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
28176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_RLD_VERSION:
28186abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_FLAGS:
28196abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_BASE_ADDRESS:
28206abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_UNREFEXTNO:
28216abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2822d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28236abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_SYMTABNO:
2824047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_symtabno_ = d->d_un.d_val;
28256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2826d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_LOCAL_GOTNO:
2828047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_local_gotno_ = d->d_un.d_val;
28296abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
2830d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      case DT_MIPS_GOTSYM:
2832047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        mips_gotsym_ = d->d_un.d_val;
28336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
28344eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#endif
2835ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
2836ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov      case DT_BIND_NOW:
2837ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov        break;
2838ea6eae182ad64312f80b9adddac511d8938e23e7Dmitriy Ivanov
2839513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERSYM:
28402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
28412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
28422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2843513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERDEF:
28442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verdef_ptr_ = load_bias + d->d_un.d_ptr;
28452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
2846513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov      case DT_VERDEFNUM:
28472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verdef_cnt_ = d->d_un.d_val;
28482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
28492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2850e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko      case DT_VERNEED:
28512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verneed_ptr_ = load_bias + d->d_un.d_ptr;
28522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        break;
28532a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
2854e831433fe1173cd4eb2bc44b977a373425e615a6Alexander Ivchenko      case DT_VERNEEDNUM:
28552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov        verneed_cnt_ = d->d_un.d_val;
2856513e29e16f16a6ffa1636ba282d599fd6b437aebDmitriy Ivanov        break;
2857d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
28586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      default:
28598f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        if (!relocating_linker) {
2860aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov          DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
28618f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov              reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
28628f61d991831f0ea515fa50a5c38dbbcfbab0dd28Dmitriy Ivanov        }
28636abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        break;
28641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
28656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
28661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
28676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
2868047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov        reinterpret_cast<void*>(base), strtab_, symtab_);
28691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
28706abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Sanity checks.
28716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (relocating_linker && needed_count != 0) {
28726abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
28736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
28753597b8055da090ef3f1ee662e96dcb952bba2c30Dmitriy Ivanov  if (nbucket_ == 0 && gnu_nbucket_ == 0) {
2876aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
2877b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov        "(new hash type from the future?)", get_realpath());
28786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2880047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (strtab_ == 0) {
2881b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
28826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2884047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (symtab_ == 0) {
2885b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
28866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
28876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
288838c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov
288907f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  // second pass - parse entries relying on strtab
289007f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
289107f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov    if (d->d_tag == DT_SONAME) {
289207f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      soname_ = get_string(d->d_un.d_val);
289307f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#if defined(__work_around_b_19059885__)
289407f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      strlcpy(old_name_, soname_, sizeof(old_name_));
289507f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov#endif
289607f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov      break;
289707f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov    }
289807f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov  }
289907f4f5f9edc33d22c41f51224f8be0c0a51e5b6bDmitriy Ivanov
290038c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // Before M release linker was using basename in place of soname.
290104f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // In the case when dt_soname is absent some apps stop working
290238c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // because they can't find dt_needed library by soname.
290338c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  // This workaround should keep them working. (applies only
290404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // for apps targeting sdk version <=22). Make an exception for
290504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  // the main executable and linker; they do not need to have dt_soname
290604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
290704f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov      get_application_target_sdk_version() <= 22) {
290838c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov    soname_ = basename(realpath_.c_str());
290938c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov    DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
291038c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov        get_realpath(), soname_);
291138c37d6705f420ecac4146c11d79bee6e0ca8a03Dmitriy Ivanov  }
29126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
291314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
29141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
291518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovbool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
291618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov                        const android_dlextinfo* extinfo) {
29171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2918ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  local_group_root_ = local_group.front();
2919ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  if (local_group_root_ == nullptr) {
2920ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    local_group_root_ = this;
2921ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  }
2922ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
292304f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
292404f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov    target_sdk_version_ = get_application_target_sdk_version();
292504f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov  }
292604f7e3e955ba7de5f449c995e667659319dc1cceDmitriy Ivanov
2927f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  VersionTracker version_tracker;
2928f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov
2929f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  if (!version_tracker.init(this)) {
2930f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    return false;
2931f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov  }
2932f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov
293356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__)
293456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  if (has_text_relocations) {
29353e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov    // Fail if app is targeting sdk version > 22
29363e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov    // TODO (dimitry): remove != __ANDROID_API__ check once http://b/20020312 is fixed
29373e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov    if (get_application_target_sdk_version() != __ANDROID_API__
29383e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov        && get_application_target_sdk_version() > 22) {
29393e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov      DL_ERR("%s: has text relocations", get_realpath());
29403e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov      return false;
29413e6f7807541bab8157f9c26e55829fd193683349Dmitriy Ivanov    }
294256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // Make segments writable to allow text relocations to work properly. We will later call
294356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // phdr_table_protect_segments() after all of them are applied and all constructors are run.
294456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    DL_WARN("%s has text relocations. This is wasting memory and prevents "
2945b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov            "security hardening. Please fix.", get_realpath());
294656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
294756be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2948b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
294956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      return false;
295056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    }
295156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  }
295256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
295356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov
295418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov  if (android_relocs_ != nullptr) {
295518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    // check signature
295618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    if (android_relocs_size_ > 3 &&
295718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[0] == 'A' &&
295818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[1] == 'P' &&
295918870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov        android_relocs_[2] == 'S' &&
296018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        android_relocs_[3] == '2') {
2961b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      DEBUG("[ android relocating %s ]", get_realpath());
296218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
296318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      bool relocated = false;
296418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      const uint8_t* packed_relocs = android_relocs_ + 4;
296518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      const size_t packed_relocs_size = android_relocs_size_ - 4;
296618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
296718870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov      relocated = relocate(
2968f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov          version_tracker,
296918870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov          packed_reloc_iterator<sleb128_decoder>(
297018870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov            sleb128_decoder(packed_relocs, packed_relocs_size)),
297118870d350c29c83bdcecbe5cf3715b2c800275f7Dmitriy Ivanov          global_group, local_group);
297218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
297318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      if (!relocated) {
297418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov        return false;
297518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      }
297618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    } else {
297718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      DL_ERR("bad android relocation header.");
297818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov      return false;
297918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov    }
298018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov  }
298118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov
29824eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(USE_RELA)
2983047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (rela_ != nullptr) {
2984b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s ]", get_realpath());
2985f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2986f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
29876abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
2988c00f2cb587630d5e954c7f548749f1e3170b3cb1Elliott Hughes    }
29896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
2990047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (plt_rela_ != nullptr) {
2991b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s plt ]", get_realpath());
2992f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
2993f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
29946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
29951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
29966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
29979aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#else
2998047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (rel_ != nullptr) {
2999b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s ]", get_realpath());
3000f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
3001f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
30026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
30031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
30046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3005047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (plt_rel_ != nullptr) {
3006b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov    DEBUG("[ relocating %s plt ]", get_realpath());
3007f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov    if (!relocate(version_tracker,
3008f92a417d07d70730fda15d7d98d36968a6a7362eDmitriy Ivanov            plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
30096abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
3010c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith    }
30116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
30129aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#endif
3013c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
30144eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(__mips__)
3015dc145b510640202a60b0dfaef9d56cd8fc1c05a9Dmitriy Ivanov  if (!mips_relocate_got(version_tracker, global_group, local_group)) {
30166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
30176abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3018d7daacb46372132ae3f0121647074936c304b572Raghu Gandham#endif
3019d7daacb46372132ae3f0121647074936c304b572Raghu Gandham
3020b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  DEBUG("[ finished linking %s ]", get_realpath());
30211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
302256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#if !defined(__LP64__)
302356be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  if (has_text_relocations) {
302456be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    // All relocations are done, we can protect our segments back to read-only.
302556be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
302656be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      DL_ERR("can't protect segments for \"%s\": %s",
3027b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
302856be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov      return false;
302956be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov    }
303056be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov  }
303156be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov#endif
303256be6ed9e4ac99fdd920090ee89c57e3cf55e885Dimitry Ivanov
30336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* We can also turn on GNU RELRO protection */
30346abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
30356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
3036b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov           get_realpath(), strerror(errno));
30376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    return false;
30386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
30399ec0f03a0d0b17bbb94ac0b9fef6add28a133c3aNick Kralevich
30406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Handle serializing/sharing the RELRO segment */
30416abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
30426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
30436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                       extinfo->relro_fd) < 0) {
30446abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
3045b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
30466abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
3047183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)    }
30486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
30496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
30506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov                                 extinfo->relro_fd) < 0) {
30516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
3052b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov             get_realpath(), strerror(errno));
30536abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      return false;
30546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    }
30556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3056183ad9df536ab04ef35a397a1f4724e4e401d11fTorne (Richard Coles)
30576abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  notify_gdb_of_load(this);
30586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return true;
30591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
30601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3061468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
3062c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * This function add vdso to internal dso list.
3063c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * It helps to stack unwinding through signal handlers.
3064c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov * Also, it makes bionic more like glibc.
3065c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov */
3066812fd4263a005b88f3b4222baa910114f938d594Kito Chengstatic void add_vdso(KernelArgumentBlock& args __unused) {
30674eeb1f12a8b63afc0d0ad4d466b16fbffb21cd5aElliott Hughes#if defined(AT_SYSINFO_EHDR)
30680266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
3069851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  if (ehdr_vdso == nullptr) {
30700266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes    return;
30710266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  }
3072c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
307307e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0);
3074ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
30750266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
30760266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->phnum = ehdr_vdso->e_phnum;
30770266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
30780266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
30790266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
3080ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
3081047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->prelink_image();
3082047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr);
3083c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov#endif
3084c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov}
3085c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
3086c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov/*
3087d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * This is linker soinfo for GDB. See details below.
3088d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
30890d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#if defined(__LP64__)
30900d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker64"
30910d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#else
30920d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#define LINKER_PATH "/system/bin/linker"
30930d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov#endif
3094aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
3095aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// This is done to avoid calling c-tor prematurely
3096aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// because soinfo c-tor needs memory allocator
3097aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov// which might be initialized after global variables.
3098aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic uint8_t linker_soinfo_for_gdb_buf[sizeof(soinfo)] __attribute__((aligned(8)));
3099aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanovstatic soinfo* linker_soinfo_for_gdb = nullptr;
3100d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3101d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/* gdb expects the linker to be in the debug shared object list.
3102d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Without this, gdb has trouble locating the linker's ".text"
3103d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * and ".plt" sections. Gdb could also potentially use this to
3104d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
3105d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * Don't use soinfo_alloc(), because the linker shouldn't
3106d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov * be on the soinfo list.
3107d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov */
3108d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanovstatic void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
3109aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0);
3110aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
311138263dd91a4b68e2ad0afe458c9a20cb360dafebDmitriy Ivanov  linker_soinfo_for_gdb->load_bias = linker_base;
3112d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
3113d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  /*
3114d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * Set the dynamic field in the link map otherwise gdb will complain with
3115d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   * the following:
3116d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   warning: .dynamic section for "/system/bin/linker" is not at the
3117d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   *   expected address (wrong library or version mismatch?)
3118d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov   */
3119d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
3120d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
3121d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov  phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
3122aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov                                 &linker_soinfo_for_gdb->dynamic, nullptr);
3123aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
3124d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov}
3125d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov
31260b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanovextern "C" int __system_properties_init(void);
31270b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov
3128d59e50063ad708509f3ad83350be33f5612c4f54Dmitriy Ivanov/*
3129468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This code is called after the linker has linked itself and
3130468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * fixed it's own GOT. It is safe to make references to externs
3131468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * and other non-local data at this point.
3132468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
31330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
31341a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#if TIMING
31356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  struct timeval t0, t1;
31366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t0, 0);
31371a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov#endif
31381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
313966c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  // Sanitize the environment.
314066c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  __libc_init_AT_SECURE(args);
3141be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
31420b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov  // Initialize system properties
31430b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov  __system_properties_init(); // may use 'environ'
31440b9e1c6051a6c75bf9040fd1da6109988900d0acDmitriy Ivanov
31456abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  debuggerd_init();
31461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31476abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Get a few environment variables.
314866c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  const char* LD_DEBUG = getenv("LD_DEBUG");
31496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (LD_DEBUG != nullptr) {
31506abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    g_ld_debug_verbosity = atoi(LD_DEBUG);
31516abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
3152be5755969d70668bbab0e0c0ed75ebd867189723David 'Digit' Turner
315366c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  // These should have been sanitized by __libc_init_AT_SECURE, but the test
31546abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // doesn't cost us anything.
31556abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpath_env = nullptr;
31566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* ldpreload_env = nullptr;
315766c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes  if (!getauxval(AT_SECURE)) {
315866c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes    ldpath_env = getenv("LD_LIBRARY_PATH");
315966c3b2db2f036ee55e06c1a861d0da82c5f10b3dElliott Hughes    ldpreload_env = getenv("LD_PRELOAD");
31606abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31626abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  INFO("[ android linker & debugger ]");
31631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
316407e5bc152d8a3ad4c50808bb86f3c0f2c5e2f514Dmitriy Ivanov  soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
31656abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (si == nullptr) {
31666abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
31676abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
31681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31696abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* bootstrap the link map, the main exe always needs to be first */
3170ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  si->set_main_executable();
31716abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  link_map* map = &(si->link_map_head);
31721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31736abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_addr = 0;
31746abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_name = args.argv[0];
31756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_prev = nullptr;
31766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  map->l_next = nullptr;
31771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  _r_debug.r_map = map;
31796abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  r_debug_tail = map;
31801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  init_linker_info_for_gdb(linker_base);
31821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Extract information passed from the kernel.
31846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
31856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->phnum = args.getauxval(AT_PHNUM);
31866abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->entry = args.getauxval(AT_ENTRY);
31871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  /* Compute the value of si->base. We can't rely on the fact that
31896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * the first entry is the PHDR because this will not be true
31906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   * for certain executables (e.g. some in the NDK unit test suite)
31916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov   */
31926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->base = 0;
31936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->size = phdr_table_get_load_size(si->phdr, si->phnum);
31946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->load_bias = 0;
31956abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for (size_t i = 0; i < si->phnum; ++i) {
31966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    if (si->phdr[i].p_type == PT_PHDR) {
31976abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
31986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
31996abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      break;
32008180b08fb2f27052f9df2ae4787bb5bf409f13e0David 'Digit' Turner    }
32016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
32026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  si->dynamic = nullptr;
32031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
32046abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
32056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  if (elf_hdr->e_type != ET_DYN) {
32066abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n");
32076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
32086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
32092aebf5429bb1241a3298b5b642d38f73124c2026Nick Kralevich
32106abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
32116abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_LIBRARY_PATH(ldpath_env);
32126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  parse_LD_PRELOAD(ldpreload_env);
32134fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
32146abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  somain = si;
32155ae44f302b7d1d19f25c4c6f125e32dc369961d9Ard Biesheuvel
32166718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov  if (!si->prelink_image()) {
32176718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
32186718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov    exit(EXIT_FAILURE);
32196718125ac71cca5d1868c33017bbc29059491349Dmitriy Ivanov  }
322014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
3221d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // add somain to global group
3222d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
3223d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
32246abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  // Load ld_preloads and dependencies.
32256abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  StringLinkedList needed_library_name_list;
32266abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t needed_libraries_count = 0;
32276abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  size_t ld_preloads_count = 0;
3228d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov
3229d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  for (const auto& ld_preload_name : g_ld_preload_names) {
3230d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov    needed_library_name_list.push_back(ld_preload_name.c_str());
32316abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
323253ba6636178b7fb5d837b52aa6b2983263e3df4eDmitriy Ivanov    ++ld_preloads_count;
32336abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
323414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
32356abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  for_each_dt_needed(si, [&](const char* name) {
32366abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    needed_library_name_list.push_back(name);
32376abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    ++needed_libraries_count;
32386abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  });
323914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
32406abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  const char* needed_library_names[needed_libraries_count];
324114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
32426abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  memset(needed_library_names, 0, sizeof(needed_library_names));
32436abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
324414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
3245d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov  if (needed_libraries_count > 0 &&
3246d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov      !find_libraries(si, needed_library_names, needed_libraries_count, nullptr,
3247d165f56fb69f39e41bc2c952bf51c3eb3b127d2eDmitriy Ivanov          &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
32486abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
32496abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    exit(EXIT_FAILURE);
3250ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  } else if (needed_libraries_count == 0) {
3251ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
3252ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
3253ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov      exit(EXIT_FAILURE);
3254ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    }
3255ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    si->increment_ref_count();
32566abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
32571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
32586abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  add_vdso(args);
3259c45087bffa528c0809f0df2e0a3708eba7018b33Sergey Melnikov
3260279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  {
3261279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    ProtectedDataGuard guard;
32629181a5dcfe69199415c7aebf93524cc3dd6f8a6fEvgeniy Stepanov
3263279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    si->call_pre_init_constructors();
3264279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
3265279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    /* After the prelink_image, the si->load_bias is initialized.
3266279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
3267279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * We need to update this value for so exe here. So Unwind_Backtrace
3268279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     * for some arch like x86 could work correctly within so exe.
3269279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov     */
3270279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    map->l_addr = si->load_bias;
3271279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov    si->call_constructors();
3272279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  }
3273e83c56dfbb6a9a61f0f18031620322af97e80162Evgeniy Stepanov
32741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
32756abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  gettimeofday(&t1, nullptr);
32766abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) (
32776abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
32786abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov           (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
32791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
32801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
32816abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0],
32826abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocAbsolute],
32836abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocRelative],
32846abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocCopy],
32856abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov         linker_stats.count[kRelocSymbol]);
32861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
32871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
32886abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  {
32896abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned n;
32906abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned i;
32916abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    unsigned count = 0;
32926abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    for (n = 0; n < 4096; n++) {
32936abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      if (bitmask[n]) {
32946abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        unsigned x = bitmask[n];
3295e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#if defined(__LP64__)
32966abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 32; i++) {
3297e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#else
32986abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov        for (i = 0; i < 8; i++) {
3299e365f9d6543bc6607864ef61257505239dde15d1Marcus Oakland#endif
33006abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          if (x & 1) {
33016abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov            count++;
33026abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          }
33036abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov          x >>= 1;
33041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
33056abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov      }
33061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
33076abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov    PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4);
33086abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  }
33091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
33101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
33111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
33126abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  fflush(stdout);
33131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
33141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3315b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry));
33166abf624d122bec8c80cc9fe1b692265bf1b28b1bDmitriy Ivanov  return si->entry;
33171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3318468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
3319bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner/* Compute the load-bias of an existing executable. This shall only
3320bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * be used to compute the load bias of an executable or shared library
3321bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * that was loaded by the kernel itself.
3322bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *
3323bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Input:
3324bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    elf    -> address of ELF header, assumed to be at the start of the file.
3325bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner * Return:
3326bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    load bias, i.e. add the value of any p_vaddr in the file to get
3327bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner *    the corresponding address in memory.
3328bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner */
33290266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesstatic ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
33300266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) offset = elf->e_phoff;
3331b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov  const ElfW(Phdr)* phdr_table =
3332b3c01d05387e8576edcb0df1ad80a326d1d3a418Dmitriy Ivanov      reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
33330266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
3334fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng
33350266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
3336fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng    if (phdr->p_type == PT_LOAD) {
33370266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes      return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
3338bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner    }
3339fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  }
3340fa8c05dc00bb41ae8fe5cb5e4f82816e30f7f7b2Kito Cheng  return 0;
3341bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner}
3342bea23e59f7145537fd4e600ae67fa92a798872cfDavid 'Digit' Turner
3343efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanovextern "C" void _start();
3344efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
3345468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich/*
3346468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * This is the entry point for the linker, called from begin.S. This
3347468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * method is responsible for fixing the linker's own relocations, and
3348468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * then calling __linker_init_post_relocation().
3349468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich *
3350468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * Because this method is called before the linker has fixed it's own
3351468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * relocations, any attempt to reference an extern variable, extern
3352468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich * function, or other GOT reference will generate a segfault.
3353468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich */
33540266ae5f884d72da58f33a072e865ba131234a5eElliott Hughesextern "C" ElfW(Addr) __linker_init(void* raw_args) {
335542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  KernelArgumentBlock args(raw_args);
335642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
33570266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
3358efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
33590266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
3360faf05bacd45719291b371f24b1b89543881b37f6Elliott Hughes  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
336142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3362aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  soinfo linker_so(nullptr, nullptr, 0, 0);
336342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3364efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // If the linker is not acting as PT_INTERP entry_point is equal to
3365efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // _start. Which means that the linker is running as an executable and
3366efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // already linked by PT_INTERP.
3367efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  //
3368efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // This happens when user tries to run 'adb shell /system/bin/linker'
3369efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // see also https://code.google.com/p/android/issues/detail?id=63174
3370efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
3371efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov    __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
3372efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  }
3373efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov
337442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.base = linker_addr;
337542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
337642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
3377851135bf9941b3813adb9b4f43d76e040c4ba157Dmitriy Ivanov  linker_so.dynamic = nullptr;
337842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phdr = phdr;
337942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  linker_so.phnum = elf_hdr->e_phnum;
3380ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  linker_so.set_linker_flag();
338142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes
3382d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // This might not be obvious... The reasons why we pass g_empty_list
3383d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // in place of local_group here are (1) we do not really need it, because
3384d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
3385d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // itself without having to look into local_group and (2) allocators
3386d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // are not yet initialized, and therefore we cannot use linked_list.push_*
3387d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  // functions at this point.
3388047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
338942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // It would be nice to print an error message, but if the linker
339042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes    // can't link itself, there's no guarantee that we'll be able to
3391b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // call write() (because it involves a GOT reference). We may as
3392b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    // well try though...
3393b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    const char* msg = "CANNOT LINK EXECUTABLE: ";
3394b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, msg, strlen(msg));
3395b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
3396b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    write(2, "\n", 1);
3397b93702a0463fa0b87bf25d7ae9bdb09a35ea6a50Elliott Hughes    _exit(EXIT_FAILURE);
339842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  }
3399468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich
340014241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov  __libc_init_tls(args);
340114241402de0faa4b244b1bd6b1f0799ce169b880Dmitriy Ivanov
3402efe13832dccf2cec2898b89ca4418a6aac29d3ebDmitriy Ivanov  // Initialize the linker's own global variables
3403047b5934b5f1c62502fc9262ce634529c6cc1420Dmitriy Ivanov  linker_so.call_constructors();
34044151ea73b75e274d1ff80b42d9d457a783208516Dmitriy Ivanov
34050d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // Initialize static variables. Note that in order to
34060d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // get correct libdl_info we need to call constructors
34070d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  // before get_libdl_info().
34080d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  solist = get_libdl_info();
34090d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov  sonext = get_libdl_info();
34100d15094287fe0f288d9c258953143fc1998b6b5aDmitriy Ivanov
341142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // We have successfully fixed our own relocations. It's safe to run
341242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // the main part of the linker now.
34131728b2396591853345507a063ed6075dfd251706Elliott Hughes  args.abort_message_ptr = &g_abort_message;
34140266ae5f884d72da58f33a072e865ba131234a5eElliott Hughes  ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
34155419b9474753d25dff947c7740532f86d130c0beElliott Hughes
3416611f95689e1012283bd11917003d3740d3ce532dElliott Hughes  INFO("[ jumping to _start ]");
3417611f95689e1012283bd11917003d3740d3ce532dElliott Hughes
341842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  // Return the address that the calling assembly stub should jump to.
341942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes  return start_address;
3420468319ce4f3f7383d788b76c09cda2a405311f36Nick Kralevich}
3421