blob: a38a56603e5f195d6d2e03224067c17e7fb60eec [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002 * Copyright (C) 2008 The Android Open Source Project
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Dmitriy Ivanov19133522015-06-02 17:36:54 -070029#include <android/api-level.h>
Elliott Hughes46882792012-08-03 16:49:39 -070030#include <errno.h>
31#include <fcntl.h>
Elliott Hughes0266ae52014-02-10 17:46:57 -080032#include <inttypes.h>
Elliott Hughes46882792012-08-03 16:49:39 -070033#include <pthread.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
Elliott Hughes46882792012-08-03 16:49:39 -070037#include <sys/mman.h>
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -080038#include <sys/param.h>
Elliott Hughes46882792012-08-03 16:49:39 -070039#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070041#include <new>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070042#include <string>
Dmitriy Ivanovb4827502015-09-28 16:38:31 -070043#include <unordered_map>
Dmitriy Ivanovd165f562015-03-23 18:43:02 -070044#include <vector>
Dmitriy Ivanov0d150942014-08-22 12:25:04 -070045
Elliott Hughes46882792012-08-03 16:49:39 -070046// Private C library headers.
Elliott Hugheseb847bc2013-10-09 15:50:50 -070047#include "private/bionic_tls.h"
48#include "private/KernelArgumentBlock.h"
49#include "private/ScopedPthreadMutexLocker.h"
Dmitriy Ivanov14669a92014-09-05 16:42:53 -070050#include "private/ScopeGuard.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080051
52#include "linker.h"
Dmitriy Ivanovc9ce70d2015-03-10 15:30:26 -070053#include "linker_block_allocator.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080054#include "linker_debug.h"
Dimitry Ivanovdf91dc22016-02-25 15:22:04 -080055#include "linker_dlwarning.h"
Dmitriy Ivanov18870d32015-04-22 13:10:04 -070056#include "linker_sleb128.h"
David 'Digit' Turner23363ed2012-06-18 18:13:49 +020057#include "linker_phdr.h"
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -080058#include "linker_relocs.h"
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -080059#include "linker_reloc_iterators.h"
Dmitriy Ivanova1feb112015-10-01 18:41:57 -070060#include "linker_utils.h"
tony.ys_liub4474402015-07-29 18:00:22 +080061
Elliott Hughes939a7e02015-12-04 15:27:46 -080062#include "android-base/strings.h"
Simon Baldwinaef71952015-01-16 13:22:54 +000063#include "ziparchive/zip_archive.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080064
Josh Gao93c0f5e2015-10-06 11:08:13 -070065extern void __libc_init_globals(KernelArgumentBlock&);
Elliott Hughes1801db32015-06-08 18:04:00 -070066extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
67
68// Override macros to use C++ style casts.
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -080069#undef ELF_ST_TYPE
70#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
71
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070072struct android_namespace_t {
73 public:
74 android_namespace_t() : name_(nullptr), is_isolated_(false) {}
75
76 const char* get_name() const { return name_; }
77 void set_name(const char* name) { name_ = name; }
78
79 bool is_isolated() const { return is_isolated_; }
80 void set_isolated(bool isolated) { is_isolated_ = isolated; }
81
82 const std::vector<std::string>& get_ld_library_paths() const {
83 return ld_library_paths_;
84 }
85 void set_ld_library_paths(std::vector<std::string>&& library_paths) {
86 ld_library_paths_ = library_paths;
87 }
88
89 const std::vector<std::string>& get_default_library_paths() const {
90 return default_library_paths_;
91 }
92 void set_default_library_paths(std::vector<std::string>&& library_paths) {
93 default_library_paths_ = library_paths;
94 }
95
Dimitry Ivanov284ae352015-12-08 10:47:13 -080096 void set_permitted_paths(std::vector<std::string>&& permitted_paths) {
97 permitted_paths_ = permitted_paths;
98 }
99
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700100 soinfo::soinfo_list_t& soinfo_list() { return soinfo_list_; }
101
102 // For isolated namespaces - checks if the file is on the search path;
103 // always returns true for not isolated namespace.
104 bool is_accessible(const std::string& path);
105
106 private:
107 const char* name_;
108 bool is_isolated_;
109 std::vector<std::string> ld_library_paths_;
110 std::vector<std::string> default_library_paths_;
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800111 std::vector<std::string> permitted_paths_;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700112 soinfo::soinfo_list_t soinfo_list_;
113
114 DISALLOW_COPY_AND_ASSIGN(android_namespace_t);
115};
116
117android_namespace_t g_default_namespace;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800118android_namespace_t* g_anonymous_namespace = &g_default_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700119
Elliott Hughes0266ae52014-02-10 17:46:57 -0800120static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800121
Dmitriy Ivanov600bc3c2015-03-10 15:43:50 -0700122static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
123static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200124
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700125static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
126
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700127static soinfo* solist;
128static soinfo* sonext;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700129static soinfo* somain; // main process, always the one after libdl_info
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800130
Elliott Hughes1728b232014-05-14 10:02:03 -0700131static const char* const kDefaultLdPaths[] = {
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700132#if defined(__LP64__)
Elliott Hughes011bc0b2013-10-08 14:27:10 -0700133 "/system/lib64",
Dimitry Ivanov88f51112016-02-01 23:00:55 -0800134 "/vendor/lib64",
Elliott Hughes011bc0b2013-10-08 14:27:10 -0700135#else
Elliott Hughes124fae92012-10-31 14:20:03 -0700136 "/system/lib",
Dimitry Ivanov88f51112016-02-01 23:00:55 -0800137 "/vendor/lib",
Elliott Hughes011bc0b2013-10-08 14:27:10 -0700138#endif
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700139 nullptr
Elliott Hughes124fae92012-10-31 14:20:03 -0700140};
David Bartleybc3a5c22009-06-02 18:27:28 -0700141
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700142static const char* const kAsanDefaultLdPaths[] = {
143#if defined(__LP64__)
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700144 "/data/lib64",
145 "/system/lib64",
Dimitry Ivanov88f51112016-02-01 23:00:55 -0800146 "/data/vendor/lib64",
147 "/vendor/lib64",
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700148#else
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700149 "/data/lib",
150 "/system/lib",
Dimitry Ivanov88f51112016-02-01 23:00:55 -0800151 "/data/vendor/lib",
152 "/vendor/lib",
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700153#endif
154 nullptr
155};
156
Dimitry Ivanov36ac45f2016-01-07 18:43:20 -0800157static bool is_system_library(const std::string& realpath) {
158 for (const auto& dir : g_default_namespace.get_default_library_paths()) {
159 if (file_is_in_dir(realpath, dir)) {
160 return true;
161 }
162 }
163 return false;
164}
165
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800166// TODO(dimitry): This is workaround for http://b/26394120 - it will be removed before the release
Dimitry Ivanovb8e37692016-02-12 13:33:19 -0800167#if defined(__LP64__)
168static const char* const kSystemLibDir = "/system/lib64";
169#else
170static const char* const kSystemLibDir = "/system/lib";
171#endif
172
173static std::string dirname(const char *path);
174
Dimitry Ivanov36ac45f2016-01-07 18:43:20 -0800175static bool is_greylisted(const char* name, const soinfo* needed_by) {
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800176 static const char* const kLibraryGreyList[] = {
Dimitry Ivanov36ac45f2016-01-07 18:43:20 -0800177 "libandroid_runtime.so",
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800178 "libbinder.so",
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800179 "libcrypto.so",
180 "libcutils.so",
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800181 "libmedia.so",
182 "libnativehelper.so",
Dimitry Ivanova2a05012016-01-25 15:48:44 -0800183 "libskia.so",
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800184 "libssl.so",
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800185 "libstagefright.so",
Dimitry Ivanov78dfc402016-01-12 10:37:38 -0800186 "libui.so",
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800187 "libutils.so",
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800188 nullptr
189 };
190
Dimitry Ivanovf1db47a2016-01-11 10:20:15 -0800191 // limit greylisting to apps targeting sdk version 23 and below
192 if (get_application_target_sdk_version() > 23) {
193 return false;
194 }
195
Dimitry Ivanov36ac45f2016-01-07 18:43:20 -0800196 // if the library needed by a system library - implicitly assume it
197 // is greylisted
198
199 if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
200 return true;
201 }
202
Dimitry Ivanovb8e37692016-02-12 13:33:19 -0800203 // if this is an absolute path - make sure it points to /system/lib(64)
204 if (name[0] == '/' && dirname(name) == kSystemLibDir) {
205 // and reduce the path to basename
206 name = basename(name);
207 }
208
Dimitry Ivanova8bda262016-01-07 11:16:43 -0800209 for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
210 if (strcmp(name, kLibraryGreyList[i]) == 0) {
211 return true;
212 }
213 }
214
215 return false;
216}
217// END OF WORKAROUND
218
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700219static const ElfW(Versym) kVersymNotNeeded = 0;
220static const ElfW(Versym) kVersymGlobal = 1;
221
Evgenii Stepanovd640b222015-07-10 17:54:01 -0700222static const char* const* g_default_ld_paths;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700223static std::vector<std::string> g_ld_preload_names;
Elliott Hughesa4aafd12014-01-13 16:37:47 -0800224
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700225static std::vector<soinfo*> g_ld_preloads;
Matt Fischer4fd42c12009-12-31 12:09:10 -0600226
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700227static bool g_public_namespace_initialized;
228static soinfo::soinfo_list_t g_public_namespace;
229
Elliott Hughes1728b232014-05-14 10:02:03 -0700230__LIBC_HIDDEN__ int g_ld_debug_verbosity;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800231
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700232__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
Elliott Hughes0d787c12013-04-04 13:46:46 -0700233
Evgenii Stepanov68650822015-06-10 13:38:39 -0700234static std::string dirname(const char *path) {
235 const char* last_slash = strrchr(path, '/');
236 if (last_slash == path) return "/";
237 else if (last_slash == nullptr) return ".";
238 else
239 return std::string(path, last_slash - path);
240}
241
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800242#if STATS
Elliott Hughesbedfe382012-08-14 14:07:59 -0700243struct linker_stats_t {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700244 int count[kRelocMax];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700245};
246
247static linker_stats_t linker_stats;
248
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800249void count_relocation(RelocationKind kind) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700250 ++linker_stats.count[kind];
Elliott Hughesbedfe382012-08-14 14:07:59 -0700251}
252#else
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800253void count_relocation(RelocationKind) {
Elliott Hughesbedfe382012-08-14 14:07:59 -0700254}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800255#endif
256
257#if COUNT_PAGES
Dmitriy Ivanov114ff692015-01-14 11:36:38 -0800258uint32_t bitmask[4096];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800259#endif
260
Dima Zavin2e855792009-05-20 18:28:09 -0700261static char __linker_dl_err_buf[768];
Dima Zavin2e855792009-05-20 18:28:09 -0700262
Elliott Hughes650be4e2013-03-05 18:47:58 -0800263char* linker_get_error_buffer() {
Elliott Hughes5419b942012-10-16 15:54:46 -0700264 return &__linker_dl_err_buf[0];
Dima Zavin2e855792009-05-20 18:28:09 -0700265}
266
Elliott Hughes650be4e2013-03-05 18:47:58 -0800267size_t linker_get_error_buffer_size() {
268 return sizeof(__linker_dl_err_buf);
269}
270
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700271// This function is an empty stub where GDB locates a breakpoint to get notified
272// about linker activity.
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -0700273extern "C"
274void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800275
Elliott Hughes1728b232014-05-14 10:02:03 -0700276static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -0700277static r_debug _r_debug =
278 {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
279
Elliott Hughes3a9c5d62014-02-10 13:31:13 -0800280static link_map* r_debug_tail = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800281
Elliott Hughes3a9c5d62014-02-10 13:31:13 -0800282static void insert_soinfo_into_debug_map(soinfo* info) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700283 // Copy the necessary fields into the debug structure.
284 link_map* map = &(info->link_map_head);
285 map->l_addr = info->load_bias;
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700286 // link_map l_name field is not const.
287 map->l_name = const_cast<char*>(info->get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700288 map->l_ld = info->dynamic;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800289
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700290 // Stick the new library at the end of the list.
291 // gdb tends to care more about libc than it does
292 // about leaf libraries, and ordering it this way
293 // reduces the back-and-forth over the wire.
294 if (r_debug_tail) {
295 r_debug_tail->l_next = map;
296 map->l_prev = r_debug_tail;
297 map->l_next = 0;
298 } else {
299 _r_debug.r_map = map;
300 map->l_prev = 0;
301 map->l_next = 0;
302 }
303 r_debug_tail = map;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800304}
305
Elliott Hughesbedfe382012-08-14 14:07:59 -0700306static void remove_soinfo_from_debug_map(soinfo* info) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700307 link_map* map = &(info->link_map_head);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700308
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700309 if (r_debug_tail == map) {
310 r_debug_tail = map->l_prev;
311 }
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700312
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700313 if (map->l_prev) {
314 map->l_prev->l_next = map->l_next;
315 }
316 if (map->l_next) {
317 map->l_next->l_prev = map->l_prev;
318 }
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700319}
320
Elliott Hughesbedfe382012-08-14 14:07:59 -0700321static void notify_gdb_of_load(soinfo* info) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800322 if (info->is_main_executable()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700323 // GDB already knows about the main executable
324 return;
325 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800326
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700327 ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800328
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700329 _r_debug.r_state = r_debug::RT_ADD;
330 rtld_db_dlactivity();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800331
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700332 insert_soinfo_into_debug_map(info);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800333
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700334 _r_debug.r_state = r_debug::RT_CONSISTENT;
335 rtld_db_dlactivity();
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700336}
337
Elliott Hughesbedfe382012-08-14 14:07:59 -0700338static void notify_gdb_of_unload(soinfo* info) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800339 if (info->is_main_executable()) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700340 // GDB already knows about the main executable
341 return;
342 }
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700343
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700344 ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700345
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700346 _r_debug.r_state = r_debug::RT_DELETE;
347 rtld_db_dlactivity();
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700348
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700349 remove_soinfo_from_debug_map(info);
Iliyan Malchev5e12d7e2009-03-24 19:02:00 -0700350
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700351 _r_debug.r_state = r_debug::RT_CONSISTENT;
352 rtld_db_dlactivity();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800353}
354
Elliott Hughes18a206c2012-10-29 17:37:13 -0700355void notify_gdb_of_libraries() {
Elliott Hughes3a9c5d62014-02-10 13:31:13 -0800356 _r_debug.r_state = r_debug::RT_ADD;
357 rtld_db_dlactivity();
358 _r_debug.r_state = r_debug::RT_CONSISTENT;
359 rtld_db_dlactivity();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800360}
361
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700362bool android_namespace_t::is_accessible(const std::string& file) {
363 if (!is_isolated_) {
364 return true;
365 }
366
367 for (const auto& dir : ld_library_paths_) {
368 if (file_is_in_dir(file, dir)) {
369 return true;
370 }
371 }
372
373 for (const auto& dir : default_library_paths_) {
374 if (file_is_in_dir(file, dir)) {
375 return true;
376 }
377 }
378
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800379 for (const auto& dir : permitted_paths_) {
380 if (file_is_under_dir(file, dir)) {
381 return true;
382 }
383 }
384
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700385 return false;
386}
387
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700388LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
389 return g_soinfo_links_allocator.alloc();
390}
391
392void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
393 g_soinfo_links_allocator.free(entry);
394}
395
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700396static soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
397 struct stat* file_stat, off64_t file_offset,
398 uint32_t rtld_flags) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700399 if (strlen(name) >= PATH_MAX) {
Magnus Malmbornba98d922012-09-12 13:00:55 +0200400 DL_ERR("library name \"%s\" too long", name);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700401 return nullptr;
Magnus Malmbornba98d922012-09-12 13:00:55 +0200402 }
403
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700404 soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
405 file_offset, rtld_flags);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700406
Magnus Malmbornba98d922012-09-12 13:00:55 +0200407 sonext->next = si;
408 sonext = si;
409
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700410 ns->soinfo_list().push_back(si);
411
Elliott Hughesca0c11b2013-03-12 10:40:45 -0700412 TRACE("name %s: allocated soinfo @ %p", name, si);
Magnus Malmbornba98d922012-09-12 13:00:55 +0200413 return si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800414}
415
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800416static void soinfo_free(soinfo* si) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700417 if (si == nullptr) {
418 return;
419 }
420
421 if (si->base != 0 && si->size != 0) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800422 if (!si->is_mapped_by_caller()) {
423 munmap(reinterpret_cast<void*>(si->base), si->size);
424 } else {
425 // remap the region as PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE
426 mmap(reinterpret_cast<void*>(si->base), si->size, PROT_NONE,
427 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
428 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700429 }
430
431 soinfo *prev = nullptr, *trav;
432
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700433 TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700434
435 for (trav = solist; trav != nullptr; trav = trav->next) {
436 if (trav == si) {
437 break;
Elliott Hughes46882792012-08-03 16:49:39 -0700438 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700439 prev = trav;
440 }
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800441
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700442 if (trav == nullptr) {
443 // si was not in solist
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700444 DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700445 return;
446 }
Elliott Hughes46882792012-08-03 16:49:39 -0700447
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700448 // clear links to/from si
449 si->remove_all_links();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -0700450
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700451 // prev will never be null, because the first entry in solist is
452 // always the static libdl_info.
453 prev->next = si->next;
454 if (si == sonext) {
455 sonext = prev;
456 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800457
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700458 // remove from the namespace
459 si->get_namespace()->soinfo_list().remove_if([&](soinfo* candidate) {
460 return si == candidate;
461 });
462
Dmitriy Ivanov609f11b2015-07-08 15:26:46 -0700463 si->~soinfo();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700464 g_soinfo_allocator.free(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800465}
466
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700467// For every path element this function checks of it exists, and is a directory,
468// and normalizes it:
469// 1. For regular path it converts it to realpath()
470// 2. For path in a zip file it uses realpath on the zipfile
471// normalizes entry name by calling normalize_path function.
472static void resolve_paths(std::vector<std::string>& paths,
473 std::vector<std::string>* resolved_paths) {
474 resolved_paths->clear();
475 for (const auto& path : paths) {
476 char resolved_path[PATH_MAX];
477 const char* original_path = path.c_str();
478 if (realpath(original_path, resolved_path) != nullptr) {
479 struct stat s;
480 if (stat(resolved_path, &s) == 0) {
481 if (S_ISDIR(s.st_mode)) {
482 resolved_paths->push_back(resolved_path);
483 } else {
484 DL_WARN("Warning: \"%s\" is not a directory (excluding from path)", resolved_path);
485 continue;
486 }
487 } else {
488 DL_WARN("Warning: cannot stat file \"%s\": %s", resolved_path, strerror(errno));
489 continue;
490 }
491 } else {
492 std::string zip_path;
493 std::string entry_path;
494
495 std::string normalized_path;
496
497 if (!normalize_path(original_path, &normalized_path)) {
498 DL_WARN("Warning: unable to normalize \"%s\"", original_path);
499 continue;
500 }
501
502 if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) {
503 if (realpath(zip_path.c_str(), resolved_path) == nullptr) {
504 DL_WARN("Warning: unable to resolve \"%s\": %s", zip_path.c_str(), strerror(errno));
505 continue;
506 }
507
508 ZipArchiveHandle handle = nullptr;
509 if (OpenArchive(resolved_path, &handle) != 0) {
510 DL_WARN("Warning: unable to open zip archive: %s", resolved_path);
511 continue;
512 }
513
514 // Check if zip-file has a dir with entry_path name
515 void* cookie = nullptr;
516 std::string prefix_str = entry_path + "/";
517 ZipString prefix(prefix_str.c_str());
518
519 ZipEntry out_data;
520 ZipString out_name;
521
522 int32_t error_code;
523
524 if ((error_code = StartIteration(handle, &cookie, &prefix, nullptr)) != 0) {
525 DL_WARN("Unable to iterate over zip-archive entries \"%s\";"
526 " error code: %d", zip_path.c_str(), error_code);
527 continue;
528 }
529
530 if (Next(cookie, &out_data, &out_name) != 0) {
531 DL_WARN("Unable to find entries starting with \"%s\" in \"%s\"",
532 prefix_str.c_str(), zip_path.c_str());
533 continue;
534 }
535
536 auto zip_guard = make_scope_guard([&]() {
537 if (cookie != nullptr) {
538 EndIteration(cookie);
539 }
540 CloseArchive(handle);
541 });
542
543 resolved_paths->push_back(std::string(resolved_path) + kZipFileSeparator + entry_path);
544 }
545 }
546 }
547}
548
549static void split_path(const char* path, const char* delimiters,
Dmitriy Ivanovd165f562015-03-23 18:43:02 -0700550 std::vector<std::string>* paths) {
Dmitriy Ivanovfbfba642015-11-16 14:23:37 -0800551 if (path != nullptr && path[0] != 0) {
tony.ys_liub4474402015-07-29 18:00:22 +0800552 *paths = android::base::Split(path, delimiters);
Elliott Hughescade4c32012-12-20 14:42:14 -0800553 }
554}
555
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700556static void parse_path(const char* path, const char* delimiters,
557 std::vector<std::string>* resolved_paths) {
558 std::vector<std::string> paths;
559 split_path(path, delimiters, &paths);
560 resolve_paths(paths, resolved_paths);
561}
562
Elliott Hughescade4c32012-12-20 14:42:14 -0800563static void parse_LD_LIBRARY_PATH(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700564 std::vector<std::string> ld_libary_paths;
565 parse_path(path, ":", &ld_libary_paths);
566 g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
Elliott Hughescade4c32012-12-20 14:42:14 -0800567}
568
Evgenii Stepanov68650822015-06-10 13:38:39 -0700569void soinfo::set_dt_runpath(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700570 if (!has_min_version(3)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -0700571 return;
572 }
573
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700574 std::vector<std::string> runpaths;
575
576 split_path(path, ":", &runpaths);
Evgenii Stepanov68650822015-06-10 13:38:39 -0700577
578 std::string origin = dirname(get_realpath());
579 // FIXME: add $LIB and $PLATFORM.
580 std::pair<std::string, std::string> substs[] = {{"ORIGIN", origin}};
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700581 for (auto&& s : runpaths) {
Evgenii Stepanov68650822015-06-10 13:38:39 -0700582 size_t pos = 0;
583 while (pos < s.size()) {
584 pos = s.find("$", pos);
585 if (pos == std::string::npos) break;
586 for (const auto& subst : substs) {
587 const std::string& token = subst.first;
588 const std::string& replacement = subst.second;
589 if (s.substr(pos + 1, token.size()) == token) {
590 s.replace(pos, token.size() + 1, replacement);
591 // -1 to compensate for the ++pos below.
592 pos += replacement.size() - 1;
593 break;
594 } else if (s.substr(pos + 1, token.size() + 2) == "{" + token + "}") {
595 s.replace(pos, token.size() + 3, replacement);
596 pos += replacement.size() - 1;
597 break;
598 }
599 }
600 // Skip $ in case it did not match any of the known substitutions.
601 ++pos;
602 }
603 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700604
605 resolve_paths(runpaths, &dt_runpath_);
Evgenii Stepanov68650822015-06-10 13:38:39 -0700606}
607
Elliott Hughescade4c32012-12-20 14:42:14 -0800608static void parse_LD_PRELOAD(const char* path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700609 g_ld_preload_names.clear();
610 if (path != nullptr) {
611 // We have historically supported ':' as well as ' ' in LD_PRELOAD.
612 g_ld_preload_names = android::base::Split(path, " :");
613 }
Elliott Hughescade4c32012-12-20 14:42:14 -0800614}
615
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700616static bool realpath_fd(int fd, std::string* realpath) {
617 std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700618 __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700619 if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
Dmitriy Ivanov087005f2015-05-28 11:44:31 -0700620 PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700621 return false;
622 }
623
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700624 *realpath = &buf[0];
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700625 return true;
626}
627
Elliott Hughes4eeb1f12013-10-25 17:38:02 -0700628#if defined(__arm__)
Elliott Hughes46882792012-08-03 16:49:39 -0700629
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700630// For a given PC, find the .so that it belongs to.
631// Returns the base address of the .ARM.exidx section
632// for that .so, and the number of 8-byte entries
633// in that section (via *pcount).
634//
635// Intended to be called by libc's __gnu_Unwind_Find_exidx().
636//
637// This function is exposed via dlfcn.cpp and libdl.so.
Elliott Hughesfaf05ba2014-02-11 16:59:37 -0800638_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800639 uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800640
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700641 for (soinfo* si = solist; si != 0; si = si->next) {
642 if ((addr >= si->base) && (addr < (si->base + si->size))) {
643 *pcount = si->ARM_exidx_count;
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -0800644 return reinterpret_cast<_Unwind_Ptr>(si->ARM_exidx);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800645 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700646 }
647 *pcount = 0;
648 return nullptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800649}
Elliott Hughes46882792012-08-03 16:49:39 -0700650
Christopher Ferris24053a42013-08-19 17:45:09 -0700651#endif
Elliott Hughes46882792012-08-03 16:49:39 -0700652
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700653// Here, we only have to provide a callback to iterate across all the
654// loaded libraries. gcc_eh does the rest.
Dmitriy Ivanov7271caf2015-06-29 14:48:25 -0700655int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700656 int rv = 0;
657 for (soinfo* si = solist; si != nullptr; si = si->next) {
658 dl_phdr_info dl_info;
659 dl_info.dlpi_addr = si->link_map_head.l_addr;
660 dl_info.dlpi_name = si->link_map_head.l_name;
661 dl_info.dlpi_phdr = si->phdr;
662 dl_info.dlpi_phnum = si->phnum;
663 rv = cb(&dl_info, sizeof(dl_phdr_info), data);
664 if (rv != 0) {
665 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800666 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700667 }
668 return rv;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800669}
Elliott Hughes46882792012-08-03 16:49:39 -0700670
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700671const ElfW(Versym)* soinfo::get_versym(size_t n) const {
672 if (has_min_version(2) && versym_ != nullptr) {
673 return versym_ + n;
674 }
675
676 return nullptr;
677}
678
679ElfW(Addr) soinfo::get_verneed_ptr() const {
680 if (has_min_version(2)) {
681 return verneed_ptr_;
682 }
683
684 return 0;
685}
686
687size_t soinfo::get_verneed_cnt() const {
688 if (has_min_version(2)) {
689 return verneed_cnt_;
690 }
691
692 return 0;
693}
694
695ElfW(Addr) soinfo::get_verdef_ptr() const {
696 if (has_min_version(2)) {
697 return verdef_ptr_;
698 }
699
700 return 0;
701}
702
703size_t soinfo::get_verdef_cnt() const {
704 if (has_min_version(2)) {
705 return verdef_cnt_;
706 }
707
708 return 0;
709}
710
711template<typename F>
712static bool for_each_verdef(const soinfo* si, F functor) {
713 if (!si->has_min_version(2)) {
714 return true;
715 }
716
717 uintptr_t verdef_ptr = si->get_verdef_ptr();
718 if (verdef_ptr == 0) {
719 return true;
720 }
721
722 size_t offset = 0;
723
724 size_t verdef_cnt = si->get_verdef_cnt();
725 for (size_t i = 0; i<verdef_cnt; ++i) {
726 const ElfW(Verdef)* verdef = reinterpret_cast<ElfW(Verdef)*>(verdef_ptr + offset);
727 size_t verdaux_offset = offset + verdef->vd_aux;
728 offset += verdef->vd_next;
729
730 if (verdef->vd_version != 1) {
Dmitriy Ivanov3d7bea12015-04-20 17:40:39 -0700731 DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700732 i, verdef->vd_version, si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700733 return false;
734 }
735
736 if ((verdef->vd_flags & VER_FLG_BASE) != 0) {
737 // "this is the version of the file itself. It must not be used for
738 // matching a symbol. It can be used to match references."
739 //
740 // http://www.akkadia.org/drepper/symbol-versioning
741 continue;
742 }
743
744 if (verdef->vd_cnt == 0) {
745 DL_ERR("invalid verdef[%zd] vd_cnt == 0 (version without a name)", i);
746 return false;
747 }
748
749 const ElfW(Verdaux)* verdaux = reinterpret_cast<ElfW(Verdaux)*>(verdef_ptr + verdaux_offset);
750
751 if (functor(i, verdef, verdaux) == true) {
752 break;
753 }
754 }
755
756 return true;
757}
758
759bool soinfo::find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const {
760 if (vi == nullptr) {
761 *versym = kVersymNotNeeded;
762 return true;
763 }
764
765 *versym = kVersymGlobal;
766
767 return for_each_verdef(this,
768 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
769 if (verdef->vd_hash == vi->elf_hash &&
770 strcmp(vi->name, get_string(verdaux->vda_name)) == 0) {
771 *versym = verdef->vd_ndx;
772 return true;
773 }
774
775 return false;
776 }
777 );
778}
779
780bool soinfo::find_symbol_by_name(SymbolName& symbol_name,
781 const version_info* vi,
782 const ElfW(Sym)** symbol) const {
783 uint32_t symbol_index;
784 bool success =
785 is_gnu_hash() ?
786 gnu_lookup(symbol_name, vi, &symbol_index) :
787 elf_lookup(symbol_name, vi, &symbol_index);
788
789 if (success) {
790 *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index;
791 }
792
793 return success;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800794}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800795
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800796static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
797 if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
798 ELF_ST_BIND(s->st_info) == STB_WEAK) {
799 return s->st_shndx != SHN_UNDEF;
800 } else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
801 DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700802 ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800803 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800804
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800805 return false;
806}
807
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700808static const ElfW(Versym) kVersymHiddenBit = 0x8000;
809
810static inline bool is_versym_hidden(const ElfW(Versym)* versym) {
811 // the symbol is hidden if bit 15 of versym is set.
812 return versym != nullptr && (*versym & kVersymHiddenBit) != 0;
813}
814
815static inline bool check_symbol_version(const ElfW(Versym) verneed,
816 const ElfW(Versym)* verdef) {
817 return verneed == kVersymNotNeeded ||
818 verdef == nullptr ||
819 verneed == (*verdef & ~kVersymHiddenBit);
820}
821
822bool soinfo::gnu_lookup(SymbolName& symbol_name,
823 const version_info* vi,
824 uint32_t* symbol_index) const {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800825 uint32_t hash = symbol_name.gnu_hash();
Dmitriy Ivanov047b5932014-11-13 09:39:20 -0800826 uint32_t h2 = hash >> gnu_shift2_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800827
828 uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;
Dmitriy Ivanov047b5932014-11-13 09:39:20 -0800829 uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
830 ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800831
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700832 *symbol_index = 0;
833
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700834 TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700835 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700836
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800837 // test against bloom filter
838 if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700839 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700840 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700841
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700842 return true;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800843 }
844
845 // bloom test says "probably yes"...
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700846 uint32_t n = gnu_bucket_[hash % gnu_nbucket_];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800847
848 if (n == 0) {
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700849 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700850 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700851
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700852 return true;
853 }
854
855 // lookup versym for the version definition in this library
856 // note the difference between "version is not requested" (vi == nullptr)
857 // and "version not found". In the first case verneed is kVersymNotNeeded
858 // which implies that the default version can be accepted; the second case results in
859 // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols
860 // for this library and consider only *global* ones.
861 ElfW(Versym) verneed = 0;
862 if (!find_verdef_version_index(vi, &verneed)) {
863 return false;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800864 }
865
866 do {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -0800867 ElfW(Sym)* s = symtab_ + n;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700868 const ElfW(Versym)* verdef = get_versym(n);
869 // skip hidden versions when verneed == kVersymNotNeeded (0)
870 if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
871 continue;
872 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700873 if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700874 check_symbol_version(verneed, verdef) &&
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800875 strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
876 is_symbol_global_and_defined(this, s)) {
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700877 TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700878 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700879 static_cast<size_t>(s->st_size));
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700880 *symbol_index = n;
881 return true;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800882 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -0700883 } while ((gnu_chain_[n++] & 1) == 0);
884
885 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700886 symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800887
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700888 return true;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800889}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800890
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700891bool soinfo::elf_lookup(SymbolName& symbol_name,
892 const version_info* vi,
893 uint32_t* symbol_index) const {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800894 uint32_t hash = symbol_name.elf_hash();
895
896 TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700897 symbol_name.get_name(), get_realpath(),
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700898 reinterpret_cast<void*>(base), hash, hash % nbucket_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800899
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700900 ElfW(Versym) verneed = 0;
901 if (!find_verdef_version_index(vi, &verneed)) {
902 return false;
903 }
904
Dmitriy Ivanov047b5932014-11-13 09:39:20 -0800905 for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
906 ElfW(Sym)* s = symtab_ + n;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700907 const ElfW(Versym)* verdef = get_versym(n);
908
909 // skip hidden versions when verneed == 0
910 if (verneed == kVersymNotNeeded && is_versym_hidden(verdef)) {
911 continue;
912 }
913
914 if (check_symbol_version(verneed, verdef) &&
915 strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -0700916 is_symbol_global_and_defined(this, s)) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800917 TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700918 symbol_name.get_name(), get_realpath(),
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700919 reinterpret_cast<void*>(s->st_value),
920 static_cast<size_t>(s->st_size));
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700921 *symbol_index = n;
922 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800923 }
Elliott Hughes0266ae52014-02-10 17:46:57 -0800924 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800925
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700926 TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -0700927 symbol_name.get_name(), get_realpath(),
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700928 reinterpret_cast<void*>(base), hash, hash % nbucket_);
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -0700929
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700930 *symbol_index = 0;
931 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800932}
933
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700934soinfo::soinfo(android_namespace_t* ns, const char* realpath,
935 const struct stat* file_stat, off64_t file_offset,
936 int rtld_flags) {
Dmitriy Ivanov0d150942014-08-22 12:25:04 -0700937 memset(this, 0, sizeof(*this));
938
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700939 if (realpath != nullptr) {
940 realpath_ = realpath;
941 }
942
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800943 flags_ = FLAG_NEW_SOINFO;
Dmitriy Ivanov047b5932014-11-13 09:39:20 -0800944 version_ = SOINFO_VERSION;
Dmitriy Ivanov0d150942014-08-22 12:25:04 -0700945
Dmitriy Ivanov851135b2014-08-29 12:02:36 -0700946 if (file_stat != nullptr) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -0800947 this->st_dev_ = file_stat->st_dev;
948 this->st_ino_ = file_stat->st_ino;
949 this->file_offset_ = file_offset;
Dmitriy Ivanov0d150942014-08-22 12:25:04 -0700950 }
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700951
Dmitriy Ivanov047b5932014-11-13 09:39:20 -0800952 this->rtld_flags_ = rtld_flags;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700953 this->namespace_ = ns;
Dmitriy Ivanov0d150942014-08-22 12:25:04 -0700954}
955
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800956static uint32_t calculate_elf_hash(const char* name) {
957 const uint8_t* name_bytes = reinterpret_cast<const uint8_t*>(name);
958 uint32_t h = 0, g;
959
960 while (*name_bytes) {
961 h = (h << 4) + *name_bytes++;
962 g = h & 0xf0000000;
963 h ^= g;
964 h ^= g >> 24;
965 }
966
967 return h;
968}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800969
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800970uint32_t SymbolName::elf_hash() {
971 if (!has_elf_hash_) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -0800972 elf_hash_ = calculate_elf_hash(name_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800973 has_elf_hash_ = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -0700974 }
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800975
976 return elf_hash_;
977}
978
979uint32_t SymbolName::gnu_hash() {
980 if (!has_gnu_hash_) {
981 uint32_t h = 5381;
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700982 const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800983 while (*name != 0) {
984 h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
985 }
986
987 gnu_hash_ = h;
988 has_gnu_hash_ = true;
989 }
990
991 return gnu_hash_;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800992}
993
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700994bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
995 soinfo** si_found_in, const soinfo::soinfo_list_t& global_group,
996 const soinfo::soinfo_list_t& local_group, const ElfW(Sym)** symbol) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800997 SymbolName symbol_name(name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -0700998 const ElfW(Sym)* s = nullptr;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -0700999
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07001000 /* "This element's presence in a shared object library alters the dynamic linker's
1001 * symbol resolution algorithm for references within the library. Instead of starting
1002 * a symbol search with the executable file, the dynamic linker starts from the shared
1003 * object itself. If the shared object fails to supply the referenced symbol, the
1004 * dynamic linker then searches the executable file and other shared objects as usual."
1005 *
1006 * http://www.sco.com/developers/gabi/2012-12-31/ch5.dynamic.html
1007 *
1008 * Note that this is unlikely since static linker avoids generating
1009 * relocations for -Bsymbolic linked dynamic executables.
1010 */
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001011 if (si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07001012 DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001013 if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
1014 return false;
1015 }
1016
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07001017 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001018 *si_found_in = si_from;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07001019 }
1020 }
1021
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001022 // 1. Look for it in global_group
1023 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001024 bool error = false;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001025 global_group.visit([&](soinfo* global_si) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07001026 DEBUG("%s: looking up %s in %s (from global group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07001027 si_from->get_realpath(), name, global_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001028 if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
1029 error = true;
1030 return false;
1031 }
1032
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07001033 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001034 *si_found_in = global_si;
1035 return false;
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07001036 }
Dmitriy Ivanovc2048942014-08-29 10:15:25 -07001037
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001038 return true;
1039 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001040
1041 if (error) {
1042 return false;
1043 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07001044 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07001045
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001046 // 2. Look for it in the local group
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001047 if (s == nullptr) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001048 bool error = false;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001049 local_group.visit([&](soinfo* local_si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001050 if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
Dmitriy Ivanove47b3f82014-10-23 14:19:07 -07001051 // we already did this - skip
1052 return true;
1053 }
1054
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07001055 DEBUG("%s: looking up %s in %s (from local group)",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07001056 si_from->get_realpath(), name, local_si->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001057 if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
1058 error = true;
1059 return false;
1060 }
1061
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001062 if (s != nullptr) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001063 *si_found_in = local_si;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001064 return false;
1065 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07001066
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001067 return true;
1068 });
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001069
1070 if (error) {
1071 return false;
1072 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001073 }
1074
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07001075 if (s != nullptr) {
1076 TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
1077 "found in %s, base = %p, load bias = %p",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07001078 si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
1079 (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001080 reinterpret_cast<void*>((*si_found_in)->load_bias));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07001081 }
Iliyan Malchev6ed80c82009-09-28 19:38:04 -07001082
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001083 *symbol = s;
1084 return true;
Iliyan Malchev6ed80c82009-09-28 19:38:04 -07001085}
1086
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001087class ProtectedDataGuard {
1088 public:
1089 ProtectedDataGuard() {
1090 if (ref_count_++ == 0) {
1091 protect_data(PROT_READ | PROT_WRITE);
1092 }
1093 }
1094
1095 ~ProtectedDataGuard() {
1096 if (ref_count_ == 0) { // overflow
1097 __libc_fatal("Too many nested calls to dlopen()");
1098 }
1099
1100 if (--ref_count_ == 0) {
1101 protect_data(PROT_READ);
1102 }
1103 }
1104 private:
1105 void protect_data(int protection) {
1106 g_soinfo_allocator.protect_all(protection);
1107 g_soinfo_links_allocator.protect_all(protection);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001108 g_namespace_allocator.protect_all(protection);
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08001109 }
1110
1111 static size_t ref_count_;
1112};
1113
1114size_t ProtectedDataGuard::ref_count_ = 0;
1115
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -07001116// Each size has it's own allocator.
1117template<size_t size>
1118class SizeBasedAllocator {
1119 public:
1120 static void* alloc() {
1121 return allocator_.alloc();
1122 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -07001123
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -07001124 static void free(void* ptr) {
1125 allocator_.free(ptr);
1126 }
Dmitriy Ivanov4bea4982014-08-29 14:01:48 -07001127
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -07001128 private:
1129 static LinkerBlockAllocator allocator_;
1130};
1131
1132template<size_t size>
1133LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
1134
1135template<typename T>
1136class TypeBasedAllocator {
1137 public:
1138 static T* alloc() {
1139 return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
1140 }
1141
1142 static void free(T* ptr) {
1143 SizeBasedAllocator<sizeof(T)>::free(ptr);
1144 }
1145};
1146
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001147class LoadTask {
1148 public:
1149 struct deleter_t {
1150 void operator()(LoadTask* t) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001151 t->~LoadTask();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001152 TypeBasedAllocator<LoadTask>::free(t);
1153 }
1154 };
1155
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001156 static deleter_t deleter;
1157
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001158 static LoadTask* create(const char* name, soinfo* needed_by,
1159 std::unordered_map<const soinfo*, ElfReader>* readers_map) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001160 LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001161 return new (ptr) LoadTask(name, needed_by, readers_map);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001162 }
1163
1164 const char* get_name() const {
1165 return name_;
1166 }
1167
1168 soinfo* get_needed_by() const {
1169 return needed_by_;
1170 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001171
1172 soinfo* get_soinfo() const {
1173 return si_;
1174 }
1175
1176 void set_soinfo(soinfo* si) {
1177 si_ = si;
1178 }
1179
1180 off64_t get_file_offset() const {
1181 return file_offset_;
1182 }
1183
1184 void set_file_offset(off64_t offset) {
1185 file_offset_ = offset;
1186 }
1187
1188 int get_fd() const {
1189 return fd_;
1190 }
1191
1192 void set_fd(int fd, bool assume_ownership) {
1193 fd_ = fd;
1194 close_fd_ = assume_ownership;
1195 }
1196
1197 const android_dlextinfo* get_extinfo() const {
1198 return extinfo_;
1199 }
1200
1201 void set_extinfo(const android_dlextinfo* extinfo) {
1202 extinfo_ = extinfo;
1203 }
1204
Dimitry Ivanov10057482016-01-28 17:24:20 -08001205 bool is_dt_needed() const {
1206 return is_dt_needed_;
1207 }
1208
1209 void set_dt_needed(bool is_dt_needed) {
1210 is_dt_needed_ = is_dt_needed;
1211 }
1212
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001213 const ElfReader& get_elf_reader() const {
1214 CHECK(si_ != nullptr);
1215 return (*elf_readers_map_)[si_];
1216 }
1217
1218 ElfReader& get_elf_reader() {
1219 CHECK(si_ != nullptr);
1220 return (*elf_readers_map_)[si_];
1221 }
1222
1223 std::unordered_map<const soinfo*, ElfReader>* get_readers_map() {
1224 return elf_readers_map_;
1225 }
1226
1227 bool read(const char* realpath, off64_t file_size) {
1228 ElfReader& elf_reader = get_elf_reader();
1229 return elf_reader.Read(realpath, fd_, file_offset_, file_size);
1230 }
1231
1232 bool load() {
1233 ElfReader& elf_reader = get_elf_reader();
1234 if (!elf_reader.Load(extinfo_)) {
1235 return false;
1236 }
1237
1238 si_->base = elf_reader.load_start();
1239 si_->size = elf_reader.load_size();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -08001240 si_->set_mapped_by_caller(elf_reader.is_mapped_by_caller());
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001241 si_->load_bias = elf_reader.load_bias();
1242 si_->phnum = elf_reader.phdr_count();
1243 si_->phdr = elf_reader.loaded_phdr();
1244
1245 return true;
1246 }
1247
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001248 private:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001249 LoadTask(const char* name, soinfo* needed_by,
1250 std::unordered_map<const soinfo*, ElfReader>* readers_map)
1251 : name_(name), needed_by_(needed_by), si_(nullptr),
Dimitry Ivanov10057482016-01-28 17:24:20 -08001252 fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
1253 is_dt_needed_(false) {}
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001254
1255 ~LoadTask() {
1256 if (fd_ != -1 && close_fd_) {
1257 close(fd_);
1258 }
1259 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001260
1261 const char* name_;
1262 soinfo* needed_by_;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001263 soinfo* si_;
1264 const android_dlextinfo* extinfo_;
1265 int fd_;
1266 bool close_fd_;
1267 off64_t file_offset_;
1268 std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
Dimitry Ivanov10057482016-01-28 17:24:20 -08001269 // TODO(dimitry): workaround for http://b/26394120 - will be removed before the release
1270 bool is_dt_needed_;
1271 // END OF WORKAROUND
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001272
1273 DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
1274};
1275
Ningsheng Jiane93be992014-09-16 15:22:10 +08001276LoadTask::deleter_t LoadTask::deleter;
1277
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -07001278template <typename T>
1279using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
1280
1281typedef linked_list_t<soinfo> SoinfoLinkedList;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001282typedef linked_list_t<const char> StringLinkedList;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001283typedef std::vector<LoadTask*> LoadTaskList;
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -07001284
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -07001285
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001286// This function walks down the tree of soinfo dependencies
1287// in breadth-first order and
1288// * calls action(soinfo* si) for each node, and
1289// * terminates walk if action returns false.
1290//
1291// walk_dependencies_tree returns false if walk was terminated
1292// by the action and true otherwise.
1293template<typename F>
1294static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_size, F action) {
Dmitriy Ivanov0cd83eb2014-09-01 16:15:52 -07001295 SoinfoLinkedList visit_list;
1296 SoinfoLinkedList visited;
1297
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001298 for (size_t i = 0; i < root_soinfos_size; ++i) {
1299 visit_list.push_back(root_soinfos[i]);
1300 }
1301
1302 soinfo* si;
1303 while ((si = visit_list.pop_front()) != nullptr) {
1304 if (visited.contains(si)) {
Dmitriy Ivanov042426b2014-08-12 21:02:13 -07001305 continue;
1306 }
1307
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001308 if (!action(si)) {
1309 return false;
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -07001310 }
1311
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001312 visited.push_back(si);
1313
1314 si->get_children().for_each([&](soinfo* child) {
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -07001315 visit_list.push_back(child);
1316 });
1317 }
1318
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001319 return true;
1320}
1321
1322
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -07001323static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001324 soinfo** found, SymbolName& symbol_name,
1325 const version_info* vi) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001326 const ElfW(Sym)* result = nullptr;
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -07001327 bool skip_lookup = skip_until != nullptr;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001328
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -07001329 walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
1330 if (skip_lookup) {
1331 skip_lookup = current_soinfo != skip_until;
1332 return true;
1333 }
1334
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001335 if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001336 result = nullptr;
1337 return false;
1338 }
1339
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07001340 if (result != nullptr) {
1341 *found = current_soinfo;
1342 return false;
1343 }
1344
1345 return true;
1346 });
1347
1348 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001349}
1350
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001351static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
1352 const char* name,
1353 const version_info* vi,
1354 soinfo** found,
1355 soinfo* caller,
1356 void* handle);
1357
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -07001358// This is used by dlsym(3). It performs symbol lookup only within the
1359// specified soinfo object and its dependencies in breadth first order.
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001360static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found,
1361 const char* name, const version_info* vi) {
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -07001362 // According to man dlopen(3) and posix docs in the case when si is handle
1363 // of the main executable we need to search not only in the executable and its
1364 // dependencies but also in all libraries loaded with RTLD_GLOBAL.
1365 //
1366 // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
1367 // libraries and they are loaded in breath-first (correct) order we can just execute
1368 // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
1369 if (si == somain) {
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001370 return dlsym_linear_lookup(&g_default_namespace, name, vi, found, nullptr, RTLD_DEFAULT);
Dmitriy Ivanovf439b5a2015-05-30 13:04:39 -07001371 }
1372
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -07001373 SymbolName symbol_name(name);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001374 return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -07001375}
1376
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08001377/* This is used by dlsym(3) to performs a global symbol lookup. If the
1378 start value is null (for RTLD_DEFAULT), the search starts at the
1379 beginning of the global solist. Otherwise the search starts at the
1380 specified soinfo (for RTLD_NEXT).
Iliyan Malchev6ed80c82009-09-28 19:38:04 -07001381 */
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001382static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
1383 const char* name,
1384 const version_info* vi,
1385 soinfo** found,
1386 soinfo* caller,
1387 void* handle) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08001388 SymbolName symbol_name(name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001389
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001390 soinfo::soinfo_list_t& soinfo_list = ns->soinfo_list();
1391 soinfo::soinfo_list_t::iterator start = soinfo_list.begin();
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -07001392
1393 if (handle == RTLD_NEXT) {
Dmitriy Ivanovb96ac412015-05-22 12:34:42 -07001394 if (caller == nullptr) {
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -07001395 return nullptr;
1396 } else {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001397 soinfo::soinfo_list_t::iterator it = soinfo_list.find(caller);
1398 CHECK (it != soinfo_list.end());
1399 start = ++it;
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -07001400 }
Elliott Hughescade4c32012-12-20 14:42:14 -08001401 }
1402
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001403 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001404 for (soinfo::soinfo_list_t::iterator it = start, end = soinfo_list.end(); it != end; ++it) {
1405 soinfo* si = *it;
Dmitriy Ivanov19133522015-06-02 17:36:54 -07001406 // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
1407 // if the library is opened by application with target api level <= 22
1408 // See http://b/21565766
1409 if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001410 continue;
1411 }
1412
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001413 if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07001414 return nullptr;
1415 }
1416
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001417 if (s != nullptr) {
Elliott Hughescade4c32012-12-20 14:42:14 -08001418 *found = si;
1419 break;
Matt Fischer1698d9e2009-12-31 12:17:56 -06001420 }
Elliott Hughescade4c32012-12-20 14:42:14 -08001421 }
Matt Fischer1698d9e2009-12-31 12:17:56 -06001422
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -07001423 // If not found - use dlsym_handle_lookup for caller's
1424 // local_group unless it is part of the global group in which
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -07001425 // case we already did it.
1426 if (s == nullptr && caller != nullptr &&
1427 (caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
Dmitriy Ivanov697bd9f2015-05-12 11:12:27 -07001428 return dlsym_handle_lookup(caller->get_local_group_root(),
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08001429 (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -07001430 }
1431
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001432 if (s != nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07001433 TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
1434 name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
Elliott Hughescade4c32012-12-20 14:42:14 -08001435 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001436
Elliott Hughescade4c32012-12-20 14:42:14 -08001437 return s;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001438}
1439
Kito Chengfa8c05d2013-03-12 14:58:06 +08001440soinfo* find_containing_library(const void* p) {
Elliott Hughes0266ae52014-02-10 17:46:57 -08001441 ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001442 for (soinfo* si = solist; si != nullptr; si = si->next) {
Kito Chengfa8c05d2013-03-12 14:58:06 +08001443 if (address >= si->base && address - si->base < si->size) {
1444 return si;
Matt Fischere2a8b1f2009-12-31 12:17:40 -06001445 }
Kito Chengfa8c05d2013-03-12 14:58:06 +08001446 }
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001447 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -06001448}
1449
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08001450ElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
1451 return is_gnu_hash() ? gnu_addr_lookup(addr) : elf_addr_lookup(addr);
1452}
1453
1454static bool symbol_matches_soaddr(const ElfW(Sym)* sym, ElfW(Addr) soaddr) {
1455 return sym->st_shndx != SHN_UNDEF &&
1456 soaddr >= sym->st_value &&
1457 soaddr < sym->st_value + sym->st_size;
1458}
1459
1460ElfW(Sym)* soinfo::gnu_addr_lookup(const void* addr) {
Chris Dearman8e553812013-11-13 17:22:33 -08001461 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08001462
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07001463 for (size_t i = 0; i < gnu_nbucket_; ++i) {
1464 uint32_t n = gnu_bucket_[i];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08001465
1466 if (n == 0) {
1467 continue;
1468 }
1469
1470 do {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001471 ElfW(Sym)* sym = symtab_ + n;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08001472 if (symbol_matches_soaddr(sym, soaddr)) {
1473 return sym;
1474 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07001475 } while ((gnu_chain_[n++] & 1) == 0);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08001476 }
1477
1478 return nullptr;
1479}
1480
1481ElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
Chris Dearman8e553812013-11-13 17:22:33 -08001482 ElfW(Addr) soaddr = reinterpret_cast<ElfW(Addr)>(addr) - load_bias;
Matt Fischere2a8b1f2009-12-31 12:17:40 -06001483
Kito Chengfa8c05d2013-03-12 14:58:06 +08001484 // Search the library's symbol table for any defined symbol which
1485 // contains this address.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08001486 for (size_t i = 0; i < nchain_; ++i) {
1487 ElfW(Sym)* sym = symtab_ + i;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08001488 if (symbol_matches_soaddr(sym, soaddr)) {
Kito Chengfa8c05d2013-03-12 14:58:06 +08001489 return sym;
Matt Fischere2a8b1f2009-12-31 12:17:40 -06001490 }
Kito Chengfa8c05d2013-03-12 14:58:06 +08001491 }
Matt Fischere2a8b1f2009-12-31 12:17:40 -06001492
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001493 return nullptr;
Matt Fischere2a8b1f2009-12-31 12:17:40 -06001494}
1495
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001496class ZipArchiveCache {
1497 public:
1498 ZipArchiveCache() {}
1499 ~ZipArchiveCache();
1500
1501 bool get_or_open(const char* zip_path, ZipArchiveHandle* handle);
1502 private:
1503 DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache);
1504
1505 std::unordered_map<std::string, ZipArchiveHandle> cache_;
1506};
1507
1508bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) {
1509 std::string key(zip_path);
1510
1511 auto it = cache_.find(key);
1512 if (it != cache_.end()) {
1513 *handle = it->second;
1514 return true;
1515 }
1516
1517 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
1518 if (fd == -1) {
1519 return false;
1520 }
1521
1522 if (OpenArchiveFd(fd, "", handle) != 0) {
1523 // invalid zip-file (?)
1524 close(fd);
1525 return false;
1526 }
1527
1528 cache_[key] = *handle;
1529 return true;
1530}
1531
1532ZipArchiveCache::~ZipArchiveCache() {
Dmitriy Ivanov5dce8942015-10-13 12:14:16 -07001533 for (const auto& it : cache_) {
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001534 CloseArchive(it.second);
1535 }
1536}
1537
1538static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001539 const char* const input_path,
1540 off64_t* file_offset, std::string* realpath) {
1541 std::string normalized_path;
1542 if (!normalize_path(input_path, &normalized_path)) {
1543 return -1;
1544 }
1545
1546 const char* const path = normalized_path.c_str();
1547 TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path);
Simon Baldwinaef71952015-01-16 13:22:54 +00001548
Dmitriy Ivanov402a7502015-06-09 13:46:51 -07001549 // Treat an '!/' separator inside a path as the separator between the name
Simon Baldwinaef71952015-01-16 13:22:54 +00001550 // of the zip file on disk and the subdirectory to search within it.
Dmitriy Ivanov402a7502015-06-09 13:46:51 -07001551 // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
Simon Baldwinaef71952015-01-16 13:22:54 +00001552 // "bar/bas/x.so" within "foo.zip".
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001553 const char* const separator = strstr(path, kZipFileSeparator);
Simon Baldwinaef71952015-01-16 13:22:54 +00001554 if (separator == nullptr) {
1555 return -1;
Elliott Hughes124fae92012-10-31 14:20:03 -07001556 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001557
1558 char buf[512];
1559 if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
1560 PRINT("Warning: ignoring very long library path: %s", path);
1561 return -1;
1562 }
1563
1564 buf[separator - path] = '\0';
1565
1566 const char* zip_path = buf;
Dmitriy Ivanov402a7502015-06-09 13:46:51 -07001567 const char* file_path = &buf[separator - path + 2];
Simon Baldwinaef71952015-01-16 13:22:54 +00001568 int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
1569 if (fd == -1) {
1570 return -1;
1571 }
1572
1573 ZipArchiveHandle handle;
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001574 if (!zip_archive_cache->get_or_open(zip_path, &handle)) {
Simon Baldwinaef71952015-01-16 13:22:54 +00001575 // invalid zip-file (?)
1576 close(fd);
1577 return -1;
1578 }
1579
Simon Baldwinaef71952015-01-16 13:22:54 +00001580 ZipEntry entry;
1581
Yusuke Sato56f40fb2015-06-25 14:56:07 -07001582 if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
Simon Baldwinaef71952015-01-16 13:22:54 +00001583 // Entry was not found.
1584 close(fd);
1585 return -1;
1586 }
1587
1588 // Check if it is properly stored
1589 if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
1590 close(fd);
1591 return -1;
1592 }
1593
1594 *file_offset = entry.offset;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001595
1596 if (realpath_fd(fd, realpath)) {
1597 *realpath += separator;
1598 } else {
1599 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
1600 normalized_path.c_str());
1601 *realpath = normalized_path;
1602 }
1603
Simon Baldwinaef71952015-01-16 13:22:54 +00001604 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001605}
1606
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001607static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
1608 int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
1609 if (n < 0 || n >= static_cast<int>(buf_size)) {
1610 PRINT("Warning: ignoring very long library path: %s/%s", path, name);
1611 return false;
1612 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001613
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001614 return true;
1615}
1616
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001617static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
1618 const char* name, off64_t* file_offset,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001619 const std::vector<std::string>& paths,
1620 std::string* realpath) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001621 for (const auto& path : paths) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001622 char buf[512];
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001623 if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001624 continue;
1625 }
1626
1627 int fd = -1;
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001628 if (strstr(buf, kZipFileSeparator) != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001629 fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
Simon Baldwinaef71952015-01-16 13:22:54 +00001630 }
1631
1632 if (fd == -1) {
1633 fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
1634 if (fd != -1) {
1635 *file_offset = 0;
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001636 if (!realpath_fd(fd, realpath)) {
1637 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
1638 *realpath = buf;
1639 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001640 }
1641 }
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001642
1643 if (fd != -1) {
1644 return fd;
1645 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001646 }
1647
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07001648 return -1;
Simon Baldwinaef71952015-01-16 13:22:54 +00001649}
1650
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001651static int open_library(android_namespace_t* ns,
1652 ZipArchiveCache* zip_archive_cache,
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001653 const char* name, soinfo *needed_by,
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001654 off64_t* file_offset, std::string* realpath) {
Elliott Hughesca0c11b2013-03-12 10:40:45 -07001655 TRACE("[ opening %s ]", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001656
Elliott Hughes124fae92012-10-31 14:20:03 -07001657 // If the name contains a slash, we should attempt to open it directly and not search the paths.
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07001658 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001659 int fd = -1;
1660
Dmitriy Ivanov730ed9d2015-07-16 04:52:06 -07001661 if (strstr(name, kZipFileSeparator) != nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001662 fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
1663 }
1664
1665 if (fd == -1) {
1666 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
Simon Baldwinaef71952015-01-16 13:22:54 +00001667 if (fd != -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001668 *file_offset = 0;
1669 if (!realpath_fd(fd, realpath)) {
1670 PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
1671 *realpath = name;
1672 }
Simon Baldwinaef71952015-01-16 13:22:54 +00001673 }
1674 }
1675
Dmitriy Ivanove44fffd2015-03-17 17:12:18 -07001676 return fd;
Elliott Hughes124fae92012-10-31 14:20:03 -07001677 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001678
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001679 // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
1680 int fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_ld_library_paths(), realpath);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001681 if (fd == -1 && needed_by != nullptr) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001682 fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001683 // Check if the library is accessible
1684 if (fd != -1 && !ns->is_accessible(*realpath)) {
1685 fd = -1;
1686 }
Evgenii Stepanov68650822015-06-10 13:38:39 -07001687 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001688
Elliott Hughes124fae92012-10-31 14:20:03 -07001689 if (fd == -1) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001690 fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
Elliott Hughes124fae92012-10-31 14:20:03 -07001691 }
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07001692
Dimitry Ivanova8bda262016-01-07 11:16:43 -08001693 // TODO(dimitry): workaround for http://b/26394120 - will be removed before the release
Dimitry Ivanov36ac45f2016-01-07 18:43:20 -08001694 if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
Dimitry Ivanova8bda262016-01-07 11:16:43 -08001695 // try searching for it on default_namespace default_library_path
1696 fd = open_library_on_paths(zip_archive_cache, name, file_offset,
1697 g_default_namespace.get_default_library_paths(), realpath);
1698 }
1699 // END OF WORKAROUND
1700
Elliott Hughes124fae92012-10-31 14:20:03 -07001701 return fd;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001702}
1703
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001704static const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
1705#if !defined(__LP64__)
1706 // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
Dmitriy Ivanov19133522015-06-02 17:36:54 -07001707 if (get_application_target_sdk_version() <= 22) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001708 const char* bname = basename(dt_needed);
1709 if (bname != dt_needed) {
1710 DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
Dimitry Ivanovdf91dc22016-02-25 15:22:04 -08001711 add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001712 }
1713
1714 return bname;
1715 }
1716#endif
1717 return dt_needed;
1718}
1719
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001720template<typename F>
1721static void for_each_dt_needed(const soinfo* si, F action) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001722 for (const ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001723 if (d->d_tag == DT_NEEDED) {
Dmitriy Ivanovd974e882015-05-27 18:29:41 -07001724 action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
Dima Zavin2e855792009-05-20 18:28:09 -07001725 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001726 }
1727}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001728
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001729template<typename F>
1730static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
1731 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1732 if (d->d_tag == DT_NEEDED) {
1733 action(fix_dt_needed(elf_reader.get_string(d->d_un.d_val), elf_reader.name()));
1734 }
1735 }
1736}
1737
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001738static bool load_library(android_namespace_t* ns,
1739 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001740 LoadTaskList* load_tasks,
1741 int rtld_flags,
1742 const std::string& realpath) {
1743 off64_t file_offset = task->get_file_offset();
1744 const char* name = task->get_name();
1745 const android_dlextinfo* extinfo = task->get_extinfo();
1746
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001747 if ((file_offset % PAGE_SIZE) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001748 DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001749 return false;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001750 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001751 if (file_offset < 0) {
1752 DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001753 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001754 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07001755
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001756 struct stat file_stat;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001757 if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07001758 DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001759 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001760 }
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001761 if (file_offset >= file_stat.st_size) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07001762 DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1763 name, file_offset, file_stat.st_size);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001764 return false;
Yabin Cui16f7f8d2014-11-04 11:08:05 -08001765 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001766
1767 // Check for symlink and other situations where
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001768 // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1769 if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001770 auto predicate = [&](soinfo* si) {
1771 return si->get_st_dev() != 0 &&
1772 si->get_st_ino() != 0 &&
1773 si->get_st_dev() == file_stat.st_dev &&
1774 si->get_st_ino() == file_stat.st_ino &&
1775 si->get_file_offset() == file_offset;
1776 };
1777
1778 soinfo* si = ns->soinfo_list().find_if(predicate);
1779
1780 // check public namespace
1781 if (si == nullptr) {
1782 si = g_public_namespace.find_if(predicate);
1783 if (si != nullptr) {
1784 ns->soinfo_list().push_back(si);
Dmitriy Ivanov9b821362015-04-02 16:03:56 -07001785 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001786 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001787
1788 if (si != nullptr) {
1789 TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1790 "will return existing soinfo", name, si->get_realpath());
1791 task->set_soinfo(si);
1792 return true;
1793 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001794 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001795
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07001796 if ((rtld_flags & RTLD_NOLOAD) != 0) {
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -07001797 DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001798 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001799 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001800
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001801 if (!ns->is_accessible(realpath)) {
Dimitry Ivanova8bda262016-01-07 11:16:43 -08001802 // TODO(dimitry): workaround for http://b/26394120 - will be removed before the release
Dimitry Ivanov10057482016-01-28 17:24:20 -08001803 const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
Dimitry Ivanov36ac45f2016-01-07 18:43:20 -08001804 if (is_greylisted(name, needed_by)) {
1805 // print warning only if needed by non-system library
1806 if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
Dimitry Ivanovf53e7de2016-02-01 12:32:22 -08001807 const soinfo* needed_or_dlopened_by = task->get_needed_by();
Dimitry Ivanovdf91dc22016-02-25 15:22:04 -08001808 const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1809 needed_or_dlopened_by->get_realpath();
Dimitry Ivanovf53e7de2016-02-01 12:32:22 -08001810 DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
Dimitry Ivanovdc2bee92016-01-12 09:50:21 -08001811 " - the access is temporarily granted as a workaround for http://b/26394120",
Dimitry Ivanovdf91dc22016-02-25 15:22:04 -08001812 name, realpath.c_str(), sopath, ns->get_name());
1813 add_dlwarning(sopath, "unauthorized access to", name);
Dimitry Ivanov36ac45f2016-01-07 18:43:20 -08001814 }
Dimitry Ivanova8bda262016-01-07 11:16:43 -08001815 } else {
1816 // do not load libraries if they are not accessible for the specified namespace.
1817 DL_ERR("library \"%s\" is not accessible for the namespace \"%s\"",
1818 name, ns->get_name());
1819 return false;
1820 }
Dimitry Ivanov22840aa2015-12-04 18:28:49 -08001821 }
1822
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001823 soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001824 if (si == nullptr) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001825 return false;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001826 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001827
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001828 task->set_soinfo(si);
1829
1830 // Read the ELF header and some of the segments.
1831 if (!task->read(realpath.c_str(), file_stat.st_size)) {
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -08001832 soinfo_free(si);
1833 task->set_soinfo(nullptr);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001834 return false;
1835 }
1836
1837 // find and set DT_RUNPATH and dt_soname
1838 // Note that these field values are temporary and are
1839 // going to be overwritten on soinfo::prelink_image
1840 // with values from PT_LOAD segments.
1841 const ElfReader& elf_reader = task->get_elf_reader();
1842 for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1843 if (d->d_tag == DT_RUNPATH) {
1844 si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1845 }
1846 if (d->d_tag == DT_SONAME) {
1847 si->set_soname(elf_reader.get_string(d->d_un.d_val));
1848 }
1849 }
1850
1851 for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1852 load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001853 });
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07001854
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001855 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001856}
1857
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001858static bool load_library(android_namespace_t* ns,
1859 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001860 ZipArchiveCache* zip_archive_cache,
1861 LoadTaskList* load_tasks,
1862 int rtld_flags) {
1863 const char* name = task->get_name();
1864 soinfo* needed_by = task->get_needed_by();
1865 const android_dlextinfo* extinfo = task->get_extinfo();
1866
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001867 off64_t file_offset;
1868 std::string realpath;
Spencer Low0346ad72015-04-22 18:06:51 -07001869 if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001870 file_offset = 0;
Spencer Low0346ad72015-04-22 18:06:51 -07001871 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1872 file_offset = extinfo->library_fd_offset;
1873 }
Dmitriy Ivanova1feb112015-10-01 18:41:57 -07001874
1875 if (!realpath_fd(extinfo->library_fd, &realpath)) {
1876 PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1877 "Will use given name.", name);
1878 realpath = name;
1879 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001880
1881 task->set_fd(extinfo->library_fd, false);
1882 task->set_file_offset(file_offset);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001883 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001884 }
1885
1886 // Open the file.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001887 int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001888 if (fd == -1) {
1889 DL_ERR("library \"%s\" not found", name);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001890 return false;
Spencer Low0346ad72015-04-22 18:06:51 -07001891 }
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001892
1893 task->set_fd(fd, true);
1894 task->set_file_offset(file_offset);
1895
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001896 return load_library(ns, task, load_tasks, rtld_flags, realpath);
Spencer Low0346ad72015-04-22 18:06:51 -07001897}
1898
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001899// Returns true if library was found and false in 2 cases
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001900// 1. (for default namespace only) The library was found but loaded under different
1901// target_sdk_version (*candidate != nullptr)
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001902// 2. The library was not found by soname (*candidate is nullptr)
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001903static bool find_loaded_library_by_soname(android_namespace_t* ns,
1904 const char* name, soinfo** candidate) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001905 *candidate = nullptr;
1906
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001907 // Ignore filename with path.
1908 if (strchr(name, '/') != nullptr) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001909 return false;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001910 }
1911
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001912 uint32_t target_sdk_version = get_application_target_sdk_version();
1913
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001914 return !ns->soinfo_list().visit([&](soinfo* si) {
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07001915 const char* soname = si->get_soname();
1916 if (soname != nullptr && (strcmp(name, soname) == 0)) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001917 // If the library was opened under different target sdk version
1918 // skip this step and try to reopen it. The exceptions are
1919 // "libdl.so" and global group. There is no point in skipping
1920 // them because relocation process is going to use them
1921 // in any case.
1922 bool is_libdl = si == solist;
1923 if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001924 !si->is_linked() || si->get_target_sdk_version() == target_sdk_version ||
1925 ns != &g_default_namespace) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001926 *candidate = si;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001927 return false;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001928 } else if (*candidate == nullptr) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001929 // for the different sdk version in the default namespace
1930 // remember the first library.
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001931 *candidate = si;
1932 }
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001933 }
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001934
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001935 return true;
1936 });
Ard Biesheuvel12c78bb2012-08-14 12:30:09 +02001937}
1938
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001939static bool find_library_internal(android_namespace_t* ns,
1940 LoadTask* task,
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001941 ZipArchiveCache* zip_archive_cache,
1942 LoadTaskList* load_tasks,
1943 int rtld_flags) {
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001944 soinfo* candidate;
1945
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001946 if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001947 task->set_soinfo(candidate);
1948 return true;
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001949 }
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001950
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001951 if (ns != &g_default_namespace) {
1952 // check public namespace
1953 candidate = g_public_namespace.find_if([&](soinfo* si) {
1954 return strcmp(task->get_name(), si->get_soname()) == 0;
1955 });
1956
1957 if (candidate != nullptr) {
1958 ns->soinfo_list().push_back(candidate);
1959 task->set_soinfo(candidate);
1960 return true;
1961 }
1962 }
1963
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07001964 // Library might still be loaded, the accurate detection
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001965 // of this fact is done by load_library.
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001966 TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001967 task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
Dmitriy Ivanova9703332015-06-16 15:38:21 -07001968
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001969 if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001970 return true;
1971 } else {
1972 // In case we were unable to load the library but there
1973 // is a candidate loaded under the same soname but different
1974 // sdk level - return it anyways.
1975 if (candidate != nullptr) {
1976 task->set_soinfo(candidate);
1977 return true;
1978 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07001979 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001980
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07001981 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001982}
1983
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07001984static void soinfo_unload(soinfo* si);
1985
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001986// TODO: this is slightly unusual way to construct
1987// the global group for relocation. Not every RTLD_GLOBAL
1988// library is included in this group for backwards-compatibility
1989// reasons.
1990//
1991// This group consists of the main executable, LD_PRELOADs
1992// and libraries with the DF_1_GLOBAL flag set.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001993static soinfo::soinfo_list_t make_global_group(android_namespace_t* ns) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001994 soinfo::soinfo_list_t global_group;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001995 ns->soinfo_list().for_each([&](soinfo* si) {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07001996 if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1997 global_group.push_back(si);
1998 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07001999 });
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002000
2001 return global_group;
2002}
2003
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002004static void shuffle(std::vector<LoadTask*>* v) {
2005 for (size_t i = 0, size = v->size(); i < size; ++i) {
2006 size_t n = size - i;
2007 size_t r = arc4random_uniform(n);
2008 std::swap((*v)[n-1], (*v)[r]);
2009 }
2010}
2011
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07002012// add_as_children - add first-level loaded libraries (i.e. library_names[], but
2013// not their transitive dependencies) as children of the start_with library.
2014// This is false when find_libraries is called for dlopen(), when newly loaded
2015// libraries must form a disjoint tree.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002016static bool find_libraries(android_namespace_t* ns,
2017 soinfo* start_with,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07002018 const char* const library_names[],
2019 size_t library_names_count, soinfo* soinfos[],
2020 std::vector<soinfo*>* ld_preloads,
2021 size_t ld_preloads_count, int rtld_flags,
2022 const android_dlextinfo* extinfo,
2023 bool add_as_children) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002024 // Step 0: prepare.
2025 LoadTaskList load_tasks;
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002026 std::unordered_map<const soinfo*, ElfReader> readers_map;
2027
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002028 for (size_t i = 0; i < library_names_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002029 const char* name = library_names[i];
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002030 load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002031 }
2032
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002033 // Construct global_group.
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002034 soinfo::soinfo_list_t global_group = make_global_group(ns);
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07002035
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002036 // If soinfos array is null allocate one on stack.
2037 // The array is needed in case of failure; for example
2038 // when library_names[] = {libone.so, libtwo.so} and libone.so
2039 // is loaded correctly but libtwo.so failed for some reason.
2040 // In this case libone.so should be unloaded on return.
2041 // See also implementation of failure_guard below.
2042
2043 if (soinfos == nullptr) {
2044 size_t soinfos_size = sizeof(soinfo*)*library_names_count;
2045 soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
2046 memset(soinfos, 0, soinfos_size);
2047 }
2048
2049 // list of libraries to link - see step 2.
2050 size_t soinfos_count = 0;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002051
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002052 auto scope_guard = make_scope_guard([&]() {
2053 for (LoadTask* t : load_tasks) {
2054 LoadTask::deleter(t);
2055 }
2056 });
2057
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -07002058 auto failure_guard = make_scope_guard([&]() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002059 // Housekeeping
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002060 for (size_t i = 0; i<soinfos_count; ++i) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002061 soinfo_unload(soinfos[i]);
2062 }
2063 });
2064
Dmitriy Ivanovb4827502015-09-28 16:38:31 -07002065 ZipArchiveCache zip_archive_cache;
2066
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002067 // Step 1: expand the list of load_tasks to include
2068 // all DT_NEEDED libraries (do not load them just yet)
2069 for (size_t i = 0; i<load_tasks.size(); ++i) {
2070 LoadTask* task = load_tasks[i];
Evgenii Stepanov68650822015-06-10 13:38:39 -07002071 soinfo* needed_by = task->get_needed_by();
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002072
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07002073 bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002074 task->set_extinfo(is_dt_needed ? nullptr : extinfo);
Dimitry Ivanov10057482016-01-28 17:24:20 -08002075 task->set_dt_needed(is_dt_needed);
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07002076
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002077 if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002078 return false;
2079 }
2080
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002081 soinfo* si = task->get_soinfo();
2082
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -07002083 if (is_dt_needed) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002084 needed_by->add_child(si);
2085 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002086
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002087 if (si->is_linked()) {
2088 si->increment_ref_count();
2089 }
2090
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002091 // When ld_preloads is not null, the first
2092 // ld_preloads_count libs are in fact ld_preloads.
2093 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07002094 ld_preloads->push_back(si);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002095 }
2096
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002097 if (soinfos_count < library_names_count) {
2098 soinfos[soinfos_count++] = si;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002099 }
2100 }
2101
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07002102 // Step 2: Load libraries in random order (see b/24047022)
2103 LoadTaskList load_list;
2104 for (auto&& task : load_tasks) {
2105 soinfo* si = task->get_soinfo();
2106 auto pred = [&](const LoadTask* t) {
2107 return t->get_soinfo() == si;
2108 };
2109
2110 if (!si->is_linked() &&
2111 std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
2112 load_list.push_back(task);
2113 }
2114 }
2115 shuffle(&load_list);
2116
2117 for (auto&& task : load_list) {
2118 if (!task->load()) {
2119 return false;
2120 }
2121 }
2122
2123 // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
2124 for (auto&& task : load_tasks) {
2125 soinfo* si = task->get_soinfo();
2126 if (!si->is_linked() && !si->prelink_image()) {
2127 return false;
2128 }
2129 }
2130
2131 // Step 4: Add LD_PRELOADed libraries to the global group for
2132 // future runs. There is no need to explicitly add them to
2133 // the global group for this run because they are going to
2134 // appear in the local group in the correct order.
2135 if (ld_preloads != nullptr) {
2136 for (auto&& si : *ld_preloads) {
2137 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
2138 }
2139 }
2140
2141
2142 // Step 5: link libraries.
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002143 soinfo::soinfo_list_t local_group;
2144 walk_dependencies_tree(
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07002145 (start_with != nullptr && add_as_children) ? &start_with : soinfos,
2146 (start_with != nullptr && add_as_children) ? 1 : soinfos_count,
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002147 [&] (soinfo* si) {
2148 local_group.push_back(si);
2149 return true;
2150 });
2151
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002152 // We need to increment ref_count in case
2153 // the root of the local group was not linked.
2154 bool was_local_group_root_linked = local_group.front()->is_linked();
2155
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002156 bool linked = local_group.visit([&](soinfo* si) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002157 if (!si->is_linked()) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002158 if (!si->link_image(global_group, local_group, extinfo)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002159 return false;
2160 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002161 si->set_linked();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002162 }
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002163
2164 return true;
2165 });
2166
2167 if (linked) {
2168 failure_guard.disable();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002169 }
2170
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002171 if (!was_local_group_root_linked) {
2172 local_group.front()->increment_ref_count();
2173 }
2174
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -07002175 return linked;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002176}
2177
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002178static soinfo* find_library(android_namespace_t* ns,
2179 const char* name, int rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07002180 const android_dlextinfo* extinfo,
2181 soinfo* needed_by) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002182 soinfo* si;
2183
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002184 if (name == nullptr) {
2185 si = somain;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002186 } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07002187 extinfo, /* add_as_children */ false)) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002188 return nullptr;
2189 }
2190
Elliott Hughesd23736e2012-11-01 15:16:56 -07002191 return si;
2192}
Elliott Hughesbedfe382012-08-14 14:07:59 -07002193
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002194static void soinfo_unload(soinfo* root) {
2195 // Note that the library can be loaded but not linked;
2196 // in which case there is no root but we still need
2197 // to walk the tree and unload soinfos involved.
2198 //
2199 // This happens on unsuccessful dlopen, when one of
2200 // the DT_NEEDED libraries could not be linked/found.
2201 if (root->is_linked()) {
2202 root = root->get_local_group_root();
2203 }
2204
2205 if (!root->can_unload()) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002206 TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_realpath());
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002207 return;
2208 }
2209
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002210 size_t ref_count = root->is_linked() ? root->decrement_ref_count() : 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002211
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002212 if (ref_count == 0) {
2213 soinfo::soinfo_list_t local_unload_list;
2214 soinfo::soinfo_list_t external_unload_list;
2215 soinfo::soinfo_list_t depth_first_list;
2216 depth_first_list.push_back(root);
2217 soinfo* si = nullptr;
2218
2219 while ((si = depth_first_list.pop_front()) != nullptr) {
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08002220 if (local_unload_list.contains(si)) {
2221 continue;
2222 }
2223
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002224 local_unload_list.push_back(si);
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08002225
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002226 if (si->has_min_version(0)) {
2227 soinfo* child = nullptr;
2228 while ((child = si->get_children().pop_front()) != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002229 TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
2230 child->get_realpath(), child);
2231
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002232 if (local_unload_list.contains(child)) {
2233 continue;
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08002234 } else if (child->is_linked() && child->get_local_group_root() != root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002235 external_unload_list.push_back(child);
2236 } else {
2237 depth_first_list.push_front(child);
2238 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07002239 }
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002240 } else {
Dmitriy Ivanov280d5462015-09-28 10:14:17 -07002241#if !defined(__work_around_b_24465209__)
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002242 __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08002243#else
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002244 PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002245 for_each_dt_needed(si, [&] (const char* library_name) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002246 TRACE("deprecated (old format of soinfo): %s needs to unload %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002247 si->get_realpath(), library_name);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002248
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002249 soinfo* needed = find_library(si->get_namespace(),
2250 library_name, RTLD_NOLOAD, nullptr, nullptr);
2251
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002252 if (needed != nullptr) {
2253 // Not found: for example if symlink was deleted between dlopen and dlclose
2254 // Since we cannot really handle errors at this point - print and continue.
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002255 PRINT("warning: couldn't find %s needed by %s on unload.",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002256 library_name, si->get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002257 return;
2258 } else if (local_unload_list.contains(needed)) {
2259 // already visited
2260 return;
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08002261 } else if (needed->is_linked() && needed->get_local_group_root() != root) {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002262 // external group
2263 external_unload_list.push_back(needed);
2264 } else {
2265 // local group
2266 depth_first_list.push_front(needed);
2267 }
2268 });
Dmitriy Ivanov5ae82cb2014-12-02 17:08:42 -08002269#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002270 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002271 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07002272
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08002273 local_unload_list.for_each([](soinfo* si) {
2274 si->call_destructors();
2275 });
2276
2277 while ((si = local_unload_list.pop_front()) != nullptr) {
2278 notify_gdb_of_unload(si);
2279 soinfo_free(si);
2280 }
2281
2282 while ((si = external_unload_list.pop_front()) != nullptr) {
2283 soinfo_unload(si);
2284 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07002285 } else {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002286 TRACE("not unloading '%s' group, decrementing ref_count to %zd",
2287 root->get_realpath(), ref_count);
Dmitriy Ivanova2547052014-11-18 12:03:09 -08002288 }
2289}
2290
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002291static std::string symbol_display_name(const char* sym_name, const char* sym_ver) {
2292 if (sym_ver == nullptr) {
2293 return sym_name;
2294 }
2295
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08002296 return std::string(sym_name) + ", version " + sym_ver;
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002297}
2298
Elliott Hughesa4aafd12014-01-13 16:37:47 -08002299void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
Christopher Ferris052fa3a2014-08-26 20:48:11 -07002300 // Use basic string manipulation calls to avoid snprintf.
2301 // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
2302 // When debug malloc is enabled, this call returns 0. This in turn causes
2303 // snprintf to do nothing, which causes libraries to fail to load.
2304 // See b/17302493 for further details.
2305 // Once the above bug is fixed, this code can be modified to use
2306 // snprintf again.
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002307 size_t required_len = 0;
2308 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
2309 required_len += strlen(g_default_ld_paths[i]) + 1;
2310 }
Christopher Ferris052fa3a2014-08-26 20:48:11 -07002311 if (buffer_size < required_len) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002312 __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
2313 "buffer len %zu, required len %zu", buffer_size, required_len);
Christopher Ferris052fa3a2014-08-26 20:48:11 -07002314 }
Evgenii Stepanovd640b222015-07-10 17:54:01 -07002315 char* end = buffer;
2316 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
2317 if (i > 0) *end++ = ':';
2318 end = stpcpy(end, g_default_ld_paths[i]);
2319 }
Elliott Hughesa4aafd12014-01-13 16:37:47 -08002320}
2321
Elliott Hughescade4c32012-12-20 14:42:14 -08002322void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
Nick Kralevich6bb01b62015-03-07 13:37:05 -08002323 parse_LD_LIBRARY_PATH(ld_library_path);
Elliott Hughescade4c32012-12-20 14:42:14 -08002324}
2325
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002326soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
2327 void* caller_addr) {
2328 soinfo* const caller = find_containing_library(caller_addr);
2329
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07002330 if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
Elliott Hughese66190d2012-12-18 15:57:55 -08002331 DL_ERR("invalid flags to dlopen: %x", flags);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002332 return nullptr;
Elliott Hughese66190d2012-12-18 15:57:55 -08002333 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002334
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002335 android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002336
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002337 if (extinfo != nullptr) {
2338 if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
2339 DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
2340 return nullptr;
2341 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07002342
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002343 if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
Dmitriy Ivanova6c12792014-10-21 12:09:18 -07002344 (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002345 DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
2346 "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07002347 return nullptr;
2348 }
Dmitriy Ivanov126af752015-10-07 16:34:20 -07002349
2350 if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
2351 (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
2352 DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
2353 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
2354 return nullptr;
2355 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002356
2357 if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
2358 if (extinfo->library_namespace == nullptr) {
2359 DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
2360 return nullptr;
2361 }
2362 ns = extinfo->library_namespace;
2363 }
Torne (Richard Coles)012cb452014-02-06 14:34:21 +00002364 }
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002365
2366 ProtectedDataGuard guard;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002367 soinfo* si = find_library(ns, name, flags, extinfo, caller);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002368 if (si != nullptr) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002369 si->call_constructors();
Elliott Hughesd23736e2012-11-01 15:16:56 -07002370 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002371
Elliott Hughesd23736e2012-11-01 15:16:56 -07002372 return si;
2373}
2374
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002375int do_dladdr(const void* addr, Dl_info* info) {
2376 // Determine if this address can be found in any library currently mapped.
2377 soinfo* si = find_containing_library(addr);
2378 if (si == nullptr) {
2379 return 0;
2380 }
2381
2382 memset(info, 0, sizeof(Dl_info));
2383
2384 info->dli_fname = si->get_realpath();
2385 // Address at which the shared object is loaded.
2386 info->dli_fbase = reinterpret_cast<void*>(si->base);
2387
2388 // Determine if any symbol in the library contains the specified address.
2389 ElfW(Sym)* sym = si->find_symbol_by_address(addr);
2390 if (sym != nullptr) {
2391 info->dli_sname = si->get_string(sym->st_name);
2392 info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
2393 }
2394
2395 return 1;
2396}
2397
2398bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver,
2399 void* caller_addr, void** symbol) {
2400#if !defined(__LP64__)
2401 if (handle == nullptr) {
2402 DL_ERR("dlsym failed: library handle is null");
2403 return false;
2404 }
2405#endif
2406
2407 if (sym_name == nullptr) {
2408 DL_ERR("dlsym failed: symbol name is null");
2409 return false;
2410 }
2411
2412 soinfo* found = nullptr;
2413 const ElfW(Sym)* sym = nullptr;
2414 soinfo* caller = find_containing_library(caller_addr);
2415 android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
2416
2417 version_info vi_instance;
2418 version_info* vi = nullptr;
2419
2420 if (sym_ver != nullptr) {
Dimitry Ivanov9cf99cb2015-12-11 14:22:24 -08002421 vi_instance.name = sym_ver;
2422 vi_instance.elf_hash = calculate_elf_hash(sym_ver);
Dimitry Ivanov4a2c5aa2015-12-10 16:08:14 -08002423 vi = &vi_instance;
2424 }
2425
2426 if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
2427 sym = dlsym_linear_lookup(ns, sym_name, vi, &found, caller, handle);
2428 } else {
2429 sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, sym_name, vi);
2430 }
2431
2432 if (sym != nullptr) {
2433 uint32_t bind = ELF_ST_BIND(sym->st_info);
2434
2435 if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
2436 *symbol = reinterpret_cast<void*>(found->resolve_symbol_address(sym));
2437 return true;
2438 }
2439
2440 DL_ERR("symbol \"%s\" found but not global", symbol_display_name(sym_name, sym_ver).c_str());
2441 return false;
2442 }
2443
2444 DL_ERR("undefined symbol: %s", symbol_display_name(sym_name, sym_ver).c_str());
2445 return false;
2446}
2447
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002448void do_dlclose(soinfo* si) {
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08002449 ProtectedDataGuard guard;
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07002450 soinfo_unload(si);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002451}
2452
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002453bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
2454 CHECK(public_ns_sonames != nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002455 if (g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002456 DL_ERR("public namespace has already been initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002457 return false;
2458 }
2459
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002460 std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002461
2462 ProtectedDataGuard guard;
2463
2464 auto failure_guard = make_scope_guard([&]() {
2465 g_public_namespace.clear();
2466 });
2467
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002468 for (const auto& soname : sonames) {
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -08002469 soinfo* candidate = nullptr;
2470
2471 find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
2472
2473 if (candidate == nullptr) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002474 DL_ERR("error initializing public namespace: \"%s\" was not found"
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002475 " in the default namespace", soname.c_str());
2476 return false;
2477 }
2478
2479 candidate->set_nodelete();
2480 g_public_namespace.push_back(candidate);
2481 }
2482
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002483 g_public_namespace_initialized = true;
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002484
2485 // create anonymous namespace
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002486 // When the caller is nullptr - create_namespace will take global group
2487 // from the anonymous namespace, which is fine because anonymous namespace
2488 // is still pointing to the default one.
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002489 android_namespace_t* anon_ns =
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002490 create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
2491 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002492
2493 if (anon_ns == nullptr) {
2494 g_public_namespace_initialized = false;
2495 return false;
2496 }
2497 g_anonymous_namespace = anon_ns;
2498 failure_guard.disable();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002499 return true;
2500}
2501
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002502android_namespace_t* create_namespace(const void* caller_addr,
2503 const char* name,
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002504 const char* ld_library_path,
2505 const char* default_library_path,
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002506 uint64_t type,
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002507 const char* permitted_when_isolated_path) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002508 if (!g_public_namespace_initialized) {
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -08002509 DL_ERR("cannot create namespace: public namespace is not initialized.");
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002510 return nullptr;
2511 }
2512
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002513 soinfo* caller_soinfo = find_containing_library(caller_addr);
2514
2515 android_namespace_t* caller_ns = caller_soinfo != nullptr ?
2516 caller_soinfo->get_namespace() :
2517 g_anonymous_namespace;
2518
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002519 ProtectedDataGuard guard;
2520 std::vector<std::string> ld_library_paths;
2521 std::vector<std::string> default_library_paths;
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002522 std::vector<std::string> permitted_paths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002523
2524 parse_path(ld_library_path, ":", &ld_library_paths);
2525 parse_path(default_library_path, ":", &default_library_paths);
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002526 parse_path(permitted_when_isolated_path, ":", &permitted_paths);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002527
2528 android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
2529 ns->set_name(name);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002530 ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002531 ns->set_ld_library_paths(std::move(ld_library_paths));
2532 ns->set_default_library_paths(std::move(default_library_paths));
Dimitry Ivanov284ae352015-12-08 10:47:13 -08002533 ns->set_permitted_paths(std::move(permitted_paths));
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002534
Dimitry Ivanov7331fe12015-12-14 14:11:17 -08002535 if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
2536 // If shared - clone the caller namespace
2537 auto& soinfo_list = caller_ns->soinfo_list();
2538 std::copy(soinfo_list.begin(), soinfo_list.end(), std::back_inserter(ns->soinfo_list()));
2539 } else {
2540 // If not shared - copy only the global group
2541 auto global_group = make_global_group(caller_ns);
2542 std::copy(global_group.begin(), global_group.end(), std::back_inserter(ns->soinfo_list()));
2543 }
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07002544
2545 return ns;
2546}
2547
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002548static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
2549 typedef ElfW(Addr) (*ifunc_resolver_t)(void);
2550 ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
2551 ElfW(Addr) ifunc_addr = ifunc_resolver();
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002552 TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p",
2553 ifunc_resolver, reinterpret_cast<void*>(ifunc_addr));
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002554
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002555 return ifunc_addr;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002556}
Brigid Smithc5a13ef2014-07-23 11:22:25 -07002557
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002558const version_info* VersionTracker::get_version_info(ElfW(Versym) source_symver) const {
2559 if (source_symver < 2 ||
2560 source_symver >= version_infos.size() ||
2561 version_infos[source_symver].name == nullptr) {
2562 return nullptr;
2563 }
2564
2565 return &version_infos[source_symver];
2566}
2567
2568void VersionTracker::add_version_info(size_t source_index,
2569 ElfW(Word) elf_hash,
2570 const char* ver_name,
2571 const soinfo* target_si) {
2572 if (source_index >= version_infos.size()) {
2573 version_infos.resize(source_index+1);
2574 }
2575
2576 version_infos[source_index].elf_hash = elf_hash;
2577 version_infos[source_index].name = ver_name;
2578 version_infos[source_index].target_si = target_si;
2579}
2580
2581bool VersionTracker::init_verneed(const soinfo* si_from) {
2582 uintptr_t verneed_ptr = si_from->get_verneed_ptr();
2583
2584 if (verneed_ptr == 0) {
2585 return true;
2586 }
2587
2588 size_t verneed_cnt = si_from->get_verneed_cnt();
2589
2590 for (size_t i = 0, offset = 0; i<verneed_cnt; ++i) {
2591 const ElfW(Verneed)* verneed = reinterpret_cast<ElfW(Verneed)*>(verneed_ptr + offset);
2592 size_t vernaux_offset = offset + verneed->vn_aux;
2593 offset += verneed->vn_next;
2594
2595 if (verneed->vn_version != 1) {
2596 DL_ERR("unsupported verneed[%zd] vn_version: %d (expected 1)", i, verneed->vn_version);
2597 return false;
2598 }
2599
2600 const char* target_soname = si_from->get_string(verneed->vn_file);
2601 // find it in dependencies
2602 soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
Dmitriy Ivanov406d9962015-05-06 11:05:27 -07002603 return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002604 });
2605
2606 if (target_si == nullptr) {
2607 DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002608 target_soname, i, si_from->get_realpath());
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002609 return false;
2610 }
2611
2612 for (size_t j = 0; j<verneed->vn_cnt; ++j) {
2613 const ElfW(Vernaux)* vernaux = reinterpret_cast<ElfW(Vernaux)*>(verneed_ptr + vernaux_offset);
2614 vernaux_offset += vernaux->vna_next;
2615
2616 const ElfW(Word) elf_hash = vernaux->vna_hash;
2617 const char* ver_name = si_from->get_string(vernaux->vna_name);
2618 ElfW(Half) source_index = vernaux->vna_other;
2619
2620 add_version_info(source_index, elf_hash, ver_name, target_si);
2621 }
2622 }
2623
2624 return true;
2625}
2626
2627bool VersionTracker::init_verdef(const soinfo* si_from) {
2628 return for_each_verdef(si_from,
2629 [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
2630 add_version_info(verdef->vd_ndx, verdef->vd_hash,
2631 si_from->get_string(verdaux->vda_name), si_from);
2632 return false;
2633 }
2634 );
2635}
2636
2637bool VersionTracker::init(const soinfo* si_from) {
2638 if (!si_from->has_min_version(2)) {
2639 return true;
2640 }
2641
2642 return init_verneed(si_from) && init_verdef(si_from);
2643}
2644
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002645bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
2646 const char* sym_name, const version_info** vi) {
2647 const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
2648 ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
2649
2650 if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
2651 *vi = version_tracker.get_version_info(sym_ver);
2652
2653 if (*vi == nullptr) {
2654 DL_ERR("cannot find verneed/verdef for version index=%d "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002655 "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002656 return false;
2657 }
2658 } else {
2659 // there is no version info
2660 *vi = nullptr;
2661 }
2662
2663 return true;
2664}
2665
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002666#if !defined(__mips__)
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07002667#if defined(USE_RELA)
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002668static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
2669 return rela->r_addend;
2670}
2671#else
2672static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002673 if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
2674 ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002675 return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
2676 }
2677 return 0;
2678}
2679#endif
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002680
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002681template<typename ElfRelIteratorT>
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07002682bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
2683 const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
Dmitriy Ivanovfa26eee2015-02-03 16:06:47 -08002684 for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
2685 const auto rel = rel_iterator.next();
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002686 if (rel == nullptr) {
2687 return false;
2688 }
2689
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002690 ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
2691 ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
2692
2693 ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002694 ElfW(Addr) sym_addr = 0;
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002695 const char* sym_name = nullptr;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002696 ElfW(Addr) addend = get_addend(rel, reloc);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002697
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002698 DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002699 if (type == R_GENERIC_NONE) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002700 continue;
2701 }
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002702
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002703 const ElfW(Sym)* s = nullptr;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07002704 soinfo* lsi = nullptr;
2705
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002706 if (sym != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002707 sym_name = get_string(symtab_[sym].st_name);
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002708 const version_info* vi = nullptr;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002709
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002710 if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
2711 return false;
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07002712 }
Dmitriy Ivanov31b408d2015-04-30 16:11:48 -07002713
2714 if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
2715 return false;
2716 }
2717
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07002718 if (s == nullptr) {
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002719 // We only allow an undefined symbol if this is a weak reference...
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08002720 s = &symtab_[sym];
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002721 if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002722 DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002723 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002724 }
2725
2726 /* IHI0044C AAELF 4.5.1.1:
2727
2728 Libraries are not searched to resolve weak references.
2729 It is not an error for a weak reference to remain unsatisfied.
2730
2731 During linking, the value of an undefined weak reference is:
2732 - Zero if the relocation type is absolute
2733 - The address of the place if the relocation is pc-relative
2734 - The address of nominal base address if the relocation
2735 type is base-relative.
2736 */
2737
2738 switch (type) {
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002739 case R_GENERIC_JUMP_SLOT:
2740 case R_GENERIC_GLOB_DAT:
2741 case R_GENERIC_RELATIVE:
2742 case R_GENERIC_IRELATIVE:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002743#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002744 case R_AARCH64_ABS64:
2745 case R_AARCH64_ABS32:
2746 case R_AARCH64_ABS16:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002747#elif defined(__x86_64__)
2748 case R_X86_64_32:
2749 case R_X86_64_64:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002750#elif defined(__arm__)
2751 case R_ARM_ABS32:
2752#elif defined(__i386__)
2753 case R_386_32:
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002754#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002755 /*
2756 * The sym_addr was initialized to be zero above, or the relocation
2757 * code below does not care about value of sym_addr.
2758 * No need to do anything.
2759 */
2760 break;
Dmitriy Ivanov1b694692015-01-13 12:17:31 -08002761#if defined(__x86_64__)
Dimitry Ivanovd338aac2015-01-13 22:31:54 +00002762 case R_X86_64_PC32:
2763 sym_addr = reloc;
2764 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002765#elif defined(__i386__)
2766 case R_386_PC32:
2767 sym_addr = reloc;
2768 break;
2769#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002770 default:
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002771 DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002772 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002773 }
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002774 } else { // We got a definition.
2775#if !defined(__LP64__)
2776 // When relocating dso with text_relocation .text segment is
2777 // not executable. We need to restore elf flags before resolving
2778 // STT_GNU_IFUNC symbol.
2779 bool protect_segments = has_text_relocations &&
2780 lsi == this &&
2781 ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
2782 if (protect_segments) {
2783 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2784 DL_ERR("can't protect segments for \"%s\": %s",
2785 get_realpath(), strerror(errno));
2786 return false;
2787 }
2788 }
2789#endif
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07002790 sym_addr = lsi->resolve_symbol_address(s);
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002791#if !defined(__LP64__)
2792 if (protect_segments) {
2793 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2794 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2795 get_realpath(), strerror(errno));
2796 return false;
2797 }
2798 }
2799#endif
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002800 }
2801 count_relocation(kRelocSymbol);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07002802 }
2803
2804 switch (type) {
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002805 case R_GENERIC_JUMP_SLOT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002806 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002807 MARK(rel->r_offset);
2808 TRACE_TYPE(RELO, "RELO JMP_SLOT %16p <- %16p %s\n",
2809 reinterpret_cast<void*>(reloc),
2810 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2811
2812 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002813 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002814 case R_GENERIC_GLOB_DAT:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002815 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002816 MARK(rel->r_offset);
2817 TRACE_TYPE(RELO, "RELO GLOB_DAT %16p <- %16p %s\n",
2818 reinterpret_cast<void*>(reloc),
2819 reinterpret_cast<void*>(sym_addr + addend), sym_name);
2820 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002821 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002822 case R_GENERIC_RELATIVE:
2823 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002824 MARK(rel->r_offset);
2825 TRACE_TYPE(RELO, "RELO RELATIVE %16p <- %16p\n",
2826 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002827 reinterpret_cast<void*>(load_bias + addend));
2828 *reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002829 break;
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002830 case R_GENERIC_IRELATIVE:
2831 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002832 MARK(rel->r_offset);
2833 TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
2834 reinterpret_cast<void*>(reloc),
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08002835 reinterpret_cast<void*>(load_bias + addend));
Dmitriy Ivanovec83a612015-07-26 07:37:09 -07002836 {
2837#if !defined(__LP64__)
2838 // When relocating dso with text_relocation .text segment is
2839 // not executable. We need to restore elf flags for this
2840 // particular call.
2841 if (has_text_relocations) {
2842 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
2843 DL_ERR("can't protect segments for \"%s\": %s",
2844 get_realpath(), strerror(errno));
2845 return false;
2846 }
2847 }
2848#endif
2849 ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
2850#if !defined(__LP64__)
2851 // Unprotect it afterwards...
2852 if (has_text_relocations) {
2853 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
2854 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
2855 get_realpath(), strerror(errno));
2856 return false;
2857 }
2858 }
2859#endif
2860 *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
2861 }
Dmitriy Ivanovcefef7d2015-01-08 23:30:15 -08002862 break;
2863
2864#if defined(__aarch64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002865 case R_AARCH64_ABS64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002866 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002867 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002868 TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002869 reloc, sym_addr + addend, sym_name);
2870 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002871 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002872 case R_AARCH64_ABS32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002873 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002874 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002875 TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002876 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002877 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002878 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2879 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002880 if ((min_value <= (sym_addr + addend)) &&
2881 ((sym_addr + addend) <= max_value)) {
2882 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002883 } else {
2884 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002885 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002886 return false;
2887 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002888 }
2889 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002890 case R_AARCH64_ABS16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002891 count_relocation(kRelocAbsolute);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002892 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002893 TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002894 reloc, sym_addr + addend, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002895 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002896 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2897 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002898 if ((min_value <= (sym_addr + addend)) &&
2899 ((sym_addr + addend) <= max_value)) {
2900 *reinterpret_cast<ElfW(Addr)*>(reloc) = (sym_addr + addend);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002901 } else {
2902 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002903 sym_addr + addend, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002904 return false;
2905 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002906 }
2907 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002908 case R_AARCH64_PREL64:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002909 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002910 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002911 TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002912 reloc, sym_addr + addend, rel->r_offset, sym_name);
2913 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002914 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002915 case R_AARCH64_PREL32:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002916 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002917 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002918 TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002919 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002920 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002921 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN);
2922 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002923 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2924 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2925 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002926 } else {
2927 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002928 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002929 return false;
2930 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002931 }
2932 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002933 case R_AARCH64_PREL16:
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002934 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002935 MARK(rel->r_offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08002936 TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002937 reloc, sym_addr + addend, rel->r_offset, sym_name);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002938 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002939 const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN);
2940 const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX);
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002941 if ((min_value <= (sym_addr + addend - rel->r_offset)) &&
2942 ((sym_addr + addend - rel->r_offset) <= max_value)) {
2943 *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - rel->r_offset;
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002944 } else {
2945 DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx",
Dmitriy Ivanov77f91c62015-10-15 13:26:03 -07002946 sym_addr + addend - rel->r_offset, min_value, max_value);
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07002947 return false;
2948 }
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002949 }
2950 break;
2951
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002952 case R_AARCH64_COPY:
Nick Kralevich76e289c2014-07-03 12:04:31 -07002953 /*
2954 * ET_EXEC is not supported so this should not happen.
2955 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002956 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
Nick Kralevich76e289c2014-07-03 12:04:31 -07002957 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07002958 * Section 4.6.11 "Dynamic relocations"
Nick Kralevich76e289c2014-07-03 12:04:31 -07002959 * R_AARCH64_COPY may only appear in executable objects where e_type is
2960 * set to ET_EXEC.
2961 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07002962 DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08002963 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002964 case R_AARCH64_TLS_TPREL64:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002965 TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002966 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002967 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002968 case R_AARCH64_TLS_DTPREL32:
Elliott Hughes0266ae52014-02-10 17:46:57 -08002969 TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n",
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002970 reloc, (sym_addr + addend), rel->r_offset);
Marcus Oaklande365f9d2013-10-10 15:19:31 +01002971 break;
2972#elif defined(__x86_64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002973 case R_X86_64_32:
2974 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002975 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002976 TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2977 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002978 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002979 break;
2980 case R_X86_64_64:
2981 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002982 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002983 TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
2984 static_cast<size_t>(sym_addr), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002985 *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002986 break;
2987 case R_X86_64_PC32:
2988 count_relocation(kRelocRelative);
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002989 MARK(rel->r_offset);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002990 TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
2991 static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
2992 static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
Junichi Uekawaff35b1e2015-11-18 10:18:59 +09002993 *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002994 break;
Dmitriy Ivanovbcc04d02015-01-13 12:12:38 -08002995#elif defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07002996 case R_ARM_ABS32:
2997 count_relocation(kRelocAbsolute);
2998 MARK(rel->r_offset);
2999 TRACE_TYPE(RELO, "RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
3000 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
3001 break;
3002 case R_ARM_REL32:
3003 count_relocation(kRelocRelative);
3004 MARK(rel->r_offset);
3005 TRACE_TYPE(RELO, "RELO REL32 %08x <- %08x - %08x %s",
3006 reloc, sym_addr, rel->r_offset, sym_name);
3007 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr - rel->r_offset;
3008 break;
3009 case R_ARM_COPY:
3010 /*
3011 * ET_EXEC is not supported so this should not happen.
3012 *
3013 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf
3014 *
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003015 * Section 4.6.1.10 "Dynamic relocations"
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003016 * R_ARM_COPY may only appear in executable objects where e_type is
3017 * set to ET_EXEC.
3018 */
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003019 DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08003020 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003021#elif defined(__i386__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003022 case R_386_32:
3023 count_relocation(kRelocRelative);
3024 MARK(rel->r_offset);
3025 TRACE_TYPE(RELO, "RELO R_386_32 %08x <- +%08x %s", reloc, sym_addr, sym_name);
3026 *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
3027 break;
3028 case R_386_PC32:
3029 count_relocation(kRelocRelative);
3030 MARK(rel->r_offset);
3031 TRACE_TYPE(RELO, "RELO R_386_PC32 %08x <- +%08x (%08x - %08x) %s",
3032 reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
3033 *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
3034 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003035#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003036 default:
3037 DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003038 return false;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003039 }
3040 }
3041 return true;
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003042}
Dmitriy Ivanov114ff692015-01-14 11:36:38 -08003043#endif // !defined(__mips__)
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003044
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003045void soinfo::call_array(const char* array_name __unused, linker_function_t* functions,
3046 size_t count, bool reverse) {
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07003047 if (functions == nullptr) {
Elliott Hughesd23736e2012-11-01 15:16:56 -07003048 return;
3049 }
David 'Digit' Turner82156792009-05-18 14:37:41 +02003050
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003051 TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath());
Elliott Hughesca0c11b2013-03-12 10:40:45 -07003052
3053 int begin = reverse ? (count - 1) : 0;
3054 int end = reverse ? -1 : count;
3055 int step = reverse ? -1 : 1;
3056
3057 for (int i = begin; i != end; i += step) {
3058 TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003059 call_function("function", functions[i]);
Elliott Hughesd23736e2012-11-01 15:16:56 -07003060 }
David 'Digit' Turner82156792009-05-18 14:37:41 +02003061
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003062 TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003063}
3064
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003065void soinfo::call_function(const char* function_name __unused, linker_function_t function) {
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07003066 if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
Elliott Hughesd23736e2012-11-01 15:16:56 -07003067 return;
3068 }
3069
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003070 TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath());
Elliott Hughesd23736e2012-11-01 15:16:56 -07003071 function();
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003072 TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath());
Evgeniy Stepanov9181a5d2012-08-13 17:58:37 +04003073}
3074
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003075void soinfo::call_pre_init_constructors() {
Elliott Hughes8147d3c2013-05-09 14:19:58 -07003076 // DT_PREINIT_ARRAY functions are called before any other constructors for executables,
3077 // but ignored in a shared library.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003078 call_array("DT_PREINIT_ARRAY", preinit_array_, preinit_array_count_, false);
Elliott Hughesd23736e2012-11-01 15:16:56 -07003079}
Evgeniy Stepanove83c56d2011-12-21 13:03:54 +04003080
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003081void soinfo::call_constructors() {
Elliott Hughesd23736e2012-11-01 15:16:56 -07003082 if (constructors_called) {
3083 return;
3084 }
Jesse Hallf5d16932012-01-30 15:39:57 -08003085
Elliott Hughesd23736e2012-11-01 15:16:56 -07003086 // We set constructors_called before actually calling the constructors, otherwise it doesn't
3087 // protect against recursive constructor calls. One simple example of constructor recursion
3088 // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
3089 // 1. The program depends on libc, so libc's constructor is called here.
3090 // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
3091 // 3. dlopen() calls the constructors on the newly created
3092 // soinfo for libc_malloc_debug_leak.so.
3093 // 4. The debug .so depends on libc, so CallConstructors is
3094 // called again with the libc soinfo. If it doesn't trigger the early-
3095 // out above, the libc constructor will be called again (recursively!).
3096 constructors_called = true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003097
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003098 if (!is_main_executable() && preinit_array_ != nullptr) {
Elliott Hughes8147d3c2013-05-09 14:19:58 -07003099 // The GNU dynamic linker silently ignores these, but we warn the developer.
Elliott Hughesc6200592013-09-30 18:43:46 -07003100 PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003101 get_realpath(), preinit_array_count_);
Elliott Hughesd23736e2012-11-01 15:16:56 -07003102 }
3103
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003104 get_children().for_each([] (soinfo* si) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003105 si->call_constructors();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003106 });
Evgeniy Stepanove83c56d2011-12-21 13:03:54 +04003107
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003108 TRACE("\"%s\": calling constructors", get_realpath());
Elliott Hughes8147d3c2013-05-09 14:19:58 -07003109
3110 // DT_INIT should be called before DT_INIT_ARRAY if both are present.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003111 call_function("DT_INIT", init_func_);
3112 call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false);
Evgeniy Stepanove83c56d2011-12-21 13:03:54 +04003113}
David 'Digit' Turner82156792009-05-18 14:37:41 +02003114
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003115void soinfo::call_destructors() {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003116 if (!constructors_called) {
3117 return;
3118 }
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003119 TRACE("\"%s\": calling destructors", get_realpath());
Elliott Hughes8147d3c2013-05-09 14:19:58 -07003120
3121 // DT_FINI_ARRAY must be parsed in reverse order.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003122 call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true);
Elliott Hughes8147d3c2013-05-09 14:19:58 -07003123
3124 // DT_FINI should be called after DT_FINI_ARRAY if both are present.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003125 call_function("DT_FINI", fini_func_);
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -07003126
3127 // This is needed on second call to dlopen
3128 // after library has been unloaded with RTLD_NODELETE
3129 constructors_called = false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003130}
3131
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003132void soinfo::add_child(soinfo* child) {
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003133 if (has_min_version(0)) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003134 child->parents_.push_back(this);
3135 this->children_.push_back(child);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003136 }
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003137}
3138
3139void soinfo::remove_all_links() {
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003140 if (!has_min_version(0)) {
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003141 return;
3142 }
3143
3144 // 1. Untie connected soinfos from 'this'.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003145 children_.for_each([&] (soinfo* child) {
3146 child->parents_.remove_if([&] (const soinfo* parent) {
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003147 return parent == this;
3148 });
3149 });
3150
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003151 parents_.for_each([&] (soinfo* parent) {
3152 parent->children_.remove_if([&] (const soinfo* child) {
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003153 return child == this;
3154 });
3155 });
3156
3157 // 2. Once everything untied - clear local lists.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003158 parents_.clear();
3159 children_.clear();
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003160}
3161
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003162dev_t soinfo::get_st_dev() const {
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003163 if (has_min_version(0)) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003164 return st_dev_;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003165 }
3166
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003167 return 0;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003168};
3169
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003170ino_t soinfo::get_st_ino() const {
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003171 if (has_min_version(0)) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003172 return st_ino_;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003173 }
3174
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003175 return 0;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003176}
3177
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003178off64_t soinfo::get_file_offset() const {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07003179 if (has_min_version(1)) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003180 return file_offset_;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -07003181 }
3182
3183 return 0;
3184}
3185
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003186uint32_t soinfo::get_rtld_flags() const {
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07003187 if (has_min_version(1)) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003188 return rtld_flags_;
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -07003189 }
3190
3191 return 0;
3192}
3193
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003194uint32_t soinfo::get_dt_flags_1() const {
3195 if (has_min_version(1)) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003196 return dt_flags_1_;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003197 }
3198
3199 return 0;
3200}
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003201
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003202void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
3203 if (has_min_version(1)) {
3204 if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003205 rtld_flags_ |= RTLD_GLOBAL;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003206 }
3207
3208 if ((dt_flags_1 & DF_1_NODELETE) != 0) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003209 rtld_flags_ |= RTLD_NODELETE;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003210 }
3211
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003212 dt_flags_1_ = dt_flags_1;
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003213 }
3214}
3215
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003216void soinfo::set_nodelete() {
3217 rtld_flags_ |= RTLD_NODELETE;
3218}
3219
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003220const char* soinfo::get_realpath() const {
Dmitriy Ivanov280d5462015-09-28 10:14:17 -07003221#if defined(__work_around_b_24465209__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003222 if (has_min_version(2)) {
3223 return realpath_.c_str();
3224 } else {
3225 return old_name_;
3226 }
3227#else
3228 return realpath_.c_str();
3229#endif
3230}
3231
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003232void soinfo::set_soname(const char* soname) {
3233#if defined(__work_around_b_24465209__)
3234 if (has_min_version(2)) {
3235 soname_ = soname;
3236 }
3237 strlcpy(old_name_, soname_, sizeof(old_name_));
3238#else
3239 soname_ = soname;
3240#endif
3241}
3242
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003243const char* soinfo::get_soname() const {
Dmitriy Ivanov280d5462015-09-28 10:14:17 -07003244#if defined(__work_around_b_24465209__)
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003245 if (has_min_version(2)) {
3246 return soname_;
3247 } else {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003248 return old_name_;
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003249 }
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003250#else
3251 return soname_;
3252#endif
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003253}
3254
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003255// This is a return on get_children()/get_parents() if
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003256// 'this->flags' does not have FLAG_NEW_SOINFO set.
3257static soinfo::soinfo_list_t g_empty_list;
3258
3259soinfo::soinfo_list_t& soinfo::get_children() {
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003260 if (has_min_version(0)) {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003261 return children_;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003262 }
3263
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003264 return g_empty_list;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003265}
3266
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003267const soinfo::soinfo_list_t& soinfo::get_children() const {
3268 if (has_min_version(0)) {
3269 return children_;
3270 }
3271
3272 return g_empty_list;
3273}
3274
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003275soinfo::soinfo_list_t& soinfo::get_parents() {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003276 if (has_min_version(0)) {
3277 return parents_;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003278 }
3279
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003280 return g_empty_list;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003281}
3282
Evgenii Stepanov68650822015-06-10 13:38:39 -07003283static std::vector<std::string> g_empty_runpath;
3284
3285const std::vector<std::string>& soinfo::get_dt_runpath() const {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003286 if (has_min_version(3)) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003287 return dt_runpath_;
3288 }
3289
3290 return g_empty_runpath;
3291}
3292
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07003293android_namespace_t* soinfo::get_namespace() {
3294 if (has_min_version(3)) {
3295 return namespace_;
3296 }
3297
3298 return &g_default_namespace;
3299}
3300
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003301ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003302 if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
3303 return call_ifunc_resolver(s->st_value + load_bias);
3304 }
3305
3306 return static_cast<ElfW(Addr)>(s->st_value + load_bias);
3307}
3308
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003309const char* soinfo::get_string(ElfW(Word) index) const {
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003310 if (has_min_version(1) && (index >= strtab_size_)) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003311 __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003312 get_realpath(), strtab_size_, index);
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003313 }
3314
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003315 return strtab_ + index;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003316}
3317
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003318bool soinfo::is_gnu_hash() const {
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003319 return (flags_ & FLAG_GNU_HASH) != 0;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003320}
3321
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003322bool soinfo::can_unload() const {
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003323 return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0;
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003324}
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003325
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003326bool soinfo::is_linked() const {
3327 return (flags_ & FLAG_LINKED) != 0;
3328}
3329
3330bool soinfo::is_main_executable() const {
3331 return (flags_ & FLAG_EXE) != 0;
3332}
3333
3334void soinfo::set_linked() {
3335 flags_ |= FLAG_LINKED;
3336}
3337
3338void soinfo::set_linker_flag() {
3339 flags_ |= FLAG_LINKER;
3340}
3341
3342void soinfo::set_main_executable() {
3343 flags_ |= FLAG_EXE;
3344}
3345
3346void soinfo::increment_ref_count() {
3347 local_group_root_->ref_count_++;
3348}
3349
3350size_t soinfo::decrement_ref_count() {
3351 return --local_group_root_->ref_count_;
3352}
3353
3354soinfo* soinfo::get_local_group_root() const {
3355 return local_group_root_;
3356}
3357
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -08003358
3359void soinfo::set_mapped_by_caller(bool mapped_by_caller) {
3360 if (mapped_by_caller) {
3361 flags_ |= FLAG_MAPPED_BY_CALLER;
3362 } else {
3363 flags_ &= ~FLAG_MAPPED_BY_CALLER;
3364 }
3365}
3366
3367bool soinfo::is_mapped_by_caller() const {
3368 return (flags_ & FLAG_MAPPED_BY_CALLER) != 0;
3369}
3370
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003371// This function returns api-level at the time of
3372// dlopen/load. Note that libraries opened by system
3373// will always have 'current' api level.
3374uint32_t soinfo::get_target_sdk_version() const {
3375 if (!has_min_version(2)) {
3376 return __ANDROID_API__;
3377 }
3378
3379 return local_group_root_->target_sdk_version_;
3380}
3381
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003382bool soinfo::prelink_image() {
Ningsheng Jiane93be992014-09-16 15:22:10 +08003383 /* Extract dynamic section */
3384 ElfW(Word) dynamic_flags = 0;
3385 phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
Dmitriy Ivanov498eb182014-09-05 14:57:59 -07003386
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003387 /* We can't log anything until the linker is relocated */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003388 bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003389 if (!relocating_linker) {
Elliott Hughes116b5692016-01-04 17:45:36 -08003390 INFO("[ Linking '%s' ]", get_realpath());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003391 DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003392 }
3393
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003394 if (dynamic == nullptr) {
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02003395 if (!relocating_linker) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003396 DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
David 'Digit' Turnerb52e4382012-06-19 01:24:17 +02003397 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003398 return false;
3399 } else {
3400 if (!relocating_linker) {
3401 DEBUG("dynamic = %p", dynamic);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003402 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003403 }
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003404
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003405#if defined(__arm__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003406 (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
3407 &ARM_exidx, &ARM_exidx_count);
David 'Digit' Turner63f99f42012-06-19 00:08:39 +02003408#endif
3409
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003410 // Extract useful information from dynamic section.
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003411 // Note that: "Except for the DT_NULL element at the end of the array,
3412 // and the relative order of DT_NEEDED elements, entries may appear in any order."
3413 //
3414 // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003415 uint32_t needed_count = 0;
3416 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
3417 DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
3418 d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3419 switch (d->d_tag) {
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003420 case DT_SONAME:
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -07003421 // this is parsed after we have strtab initialized (see below).
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003422 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003423
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003424 case DT_HASH:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003425 nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
3426 nchain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
3427 bucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
3428 chain_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003429 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003430
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003431 case DT_GNU_HASH:
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003432 gnu_nbucket_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003433 // skip symndx
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003434 gnu_maskwords_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[2];
3435 gnu_shift2_ = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[3];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003436
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003437 gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>(load_bias + d->d_un.d_ptr + 16);
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003438 gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003439 // amend chain for symndx = header[1]
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003440 gnu_chain_ = gnu_bucket_ + gnu_nbucket_ -
3441 reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003442
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003443 if (!powerof2(gnu_maskwords_)) {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003444 DL_ERR("invalid maskwords for gnu_hash = 0x%x, in \"%s\" expecting power to two",
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003445 gnu_maskwords_, get_realpath());
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003446 return false;
3447 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003448 --gnu_maskwords_;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003449
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003450 flags_ |= FLAG_GNU_HASH;
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -08003451 break;
3452
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003453 case DT_STRTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003454 strtab_ = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003455 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003456
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003457 case DT_STRSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003458 strtab_size_ = d->d_un.d_val;
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003459 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003460
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003461 case DT_SYMTAB:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003462 symtab_ = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003463 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003464
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003465 case DT_SYMENT:
3466 if (d->d_un.d_val != sizeof(ElfW(Sym))) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003467 DL_ERR("invalid DT_SYMENT: %zd in \"%s\"",
3468 static_cast<size_t>(d->d_un.d_val), get_realpath());
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003469 return false;
3470 }
3471 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003472
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003473 case DT_PLTREL:
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003474#if defined(USE_RELA)
3475 if (d->d_un.d_val != DT_RELA) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003476 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_RELA", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003477 return false;
3478 }
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003479#else
3480 if (d->d_un.d_val != DT_REL) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003481 DL_ERR("unsupported DT_PLTREL in \"%s\"; expected DT_REL", get_realpath());
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003482 return false;
3483 }
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003484#endif
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003485 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003486
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003487 case DT_JMPREL:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003488#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003489 plt_rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003490#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003491 plt_rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003492#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003493 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003494
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003495 case DT_PLTRELSZ:
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003496#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003497 plt_rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003498#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003499 plt_rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003500#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003501 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003502
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003503 case DT_PLTGOT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003504#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003505 // Used by mips and mips64.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003506 plt_got_ = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003507#endif
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003508 // Ignore for other platforms... (because RTLD_LAZY is not supported)
3509 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003510
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003511 case DT_DEBUG:
3512 // Set the DT_DEBUG entry to the address of _r_debug for GDB
3513 // if the dynamic table is writable
Chris Dearman99186652014-02-06 20:36:51 -08003514// FIXME: not working currently for N64
3515// The flags for the LOAD and DYNAMIC program headers do not agree.
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003516// The LOAD section containing the dynamic table has been mapped as
Chris Dearman99186652014-02-06 20:36:51 -08003517// read-only, but the DYNAMIC header claims it is writable.
3518#if !(defined(__mips__) && defined(__LP64__))
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003519 if ((dynamic_flags & PF_W) != 0) {
3520 d->d_un.d_val = reinterpret_cast<uintptr_t>(&_r_debug);
3521 }
Chris Dearman99186652014-02-06 20:36:51 -08003522#endif
Dmitriy Ivanovc6292ea2015-02-13 16:29:50 -08003523 break;
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003524#if defined(USE_RELA)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003525 case DT_RELA:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003526 rela_ = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003527 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003528
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003529 case DT_RELASZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003530 rela_count_ = d->d_un.d_val / sizeof(ElfW(Rela));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003531 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003532
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003533 case DT_ANDROID_RELA:
3534 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3535 break;
3536
3537 case DT_ANDROID_RELASZ:
3538 android_relocs_size_ = d->d_un.d_val;
3539 break;
3540
3541 case DT_ANDROID_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003542 DL_ERR("unsupported DT_ANDROID_REL in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003543 return false;
3544
3545 case DT_ANDROID_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003546 DL_ERR("unsupported DT_ANDROID_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003547 return false;
3548
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003549 case DT_RELAENT:
3550 if (d->d_un.d_val != sizeof(ElfW(Rela))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07003551 DL_ERR("invalid DT_RELAENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003552 return false;
3553 }
3554 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003555
3556 // ignored (see DT_RELCOUNT comments for details)
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003557 case DT_RELACOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003558 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003559
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003560 case DT_REL:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003561 DL_ERR("unsupported DT_REL in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003562 return false;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003563
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003564 case DT_RELSZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003565 DL_ERR("unsupported DT_RELSZ in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003566 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003567
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003568#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003569 case DT_REL:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003570 rel_ = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003571 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003572
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003573 case DT_RELSZ:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003574 rel_count_ = d->d_un.d_val / sizeof(ElfW(Rel));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003575 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003576
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003577 case DT_RELENT:
3578 if (d->d_un.d_val != sizeof(ElfW(Rel))) {
Dmitriy Ivanovf240aa82014-09-16 23:34:20 -07003579 DL_ERR("invalid DT_RELENT: %zd", static_cast<size_t>(d->d_un.d_val));
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003580 return false;
3581 }
3582 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003583
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003584 case DT_ANDROID_REL:
3585 android_relocs_ = reinterpret_cast<uint8_t*>(load_bias + d->d_un.d_ptr);
3586 break;
3587
3588 case DT_ANDROID_RELSZ:
3589 android_relocs_size_ = d->d_un.d_val;
3590 break;
3591
3592 case DT_ANDROID_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003593 DL_ERR("unsupported DT_ANDROID_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003594 return false;
3595
3596 case DT_ANDROID_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003597 DL_ERR("unsupported DT_ANDROID_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003598 return false;
3599
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003600 // "Indicates that all RELATIVE relocations have been concatenated together,
3601 // and specifies the RELATIVE relocation count."
3602 //
3603 // TODO: Spec also mentions that this can be used to optimize relocation process;
3604 // Not currently used by bionic linker - ignored.
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003605 case DT_RELCOUNT:
Dmitriy Ivanov4a6e9a82014-09-16 15:51:25 -07003606 break;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003607
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003608 case DT_RELA:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003609 DL_ERR("unsupported DT_RELA in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003610 return false;
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003611
3612 case DT_RELASZ:
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003613 DL_ERR("unsupported DT_RELASZ in \"%s\"", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003614 return false;
3615
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003616#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003617 case DT_INIT:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003618 init_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003619 DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003620 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003621
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003622 case DT_FINI:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003623 fini_func_ = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003624 DEBUG("%s destructors (DT_FINI) found at %p", get_realpath(), fini_func_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003625 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003626
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003627 case DT_INIT_ARRAY:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003628 init_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003629 DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", get_realpath(), init_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003630 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003631
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003632 case DT_INIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003633 init_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003634 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003635
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003636 case DT_FINI_ARRAY:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003637 fini_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003638 DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", get_realpath(), fini_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003639 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003640
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003641 case DT_FINI_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003642 fini_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003643 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003644
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003645 case DT_PREINIT_ARRAY:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003646 preinit_array_ = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003647 DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", get_realpath(), preinit_array_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003648 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003649
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003650 case DT_PREINIT_ARRAYSZ:
Dmitriy Ivanov1649e7e2015-01-22 16:04:25 -08003651 preinit_array_count_ = static_cast<uint32_t>(d->d_un.d_val) / sizeof(ElfW(Addr));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003652 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003653
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003654 case DT_TEXTREL:
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003655#if defined(__LP64__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003656 DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003657 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003658#else
3659 has_text_relocations = true;
3660 break;
3661#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003662
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003663 case DT_SYMBOLIC:
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003664 has_DT_SYMBOLIC = true;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003665 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003666
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003667 case DT_NEEDED:
3668 ++needed_count;
3669 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003670
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003671 case DT_FLAGS:
3672 if (d->d_un.d_val & DF_TEXTREL) {
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003673#if defined(__LP64__)
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003674 DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003675 return false;
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003676#else
3677 has_text_relocations = true;
3678#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003679 }
Dmitriy Ivanov96bc37f2014-09-29 12:10:36 -07003680 if (d->d_un.d_val & DF_SYMBOLIC) {
3681 has_DT_SYMBOLIC = true;
3682 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003683 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003684
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003685 case DT_FLAGS_1:
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003686 set_dt_flags_1(d->d_un.d_val);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -07003687
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07003688 if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
Dmitriy Ivanov087005f2015-05-28 11:44:31 -07003689 DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
Dmitriy Ivanov6cdeb522014-09-29 19:14:45 -07003690 }
3691 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003692#if defined(__mips__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003693 case DT_MIPS_RLD_MAP:
3694 // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
3695 {
3696 r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
3697 *dp = &_r_debug;
3698 }
3699 break;
Raghu Gandham68815722014-12-18 19:12:19 -08003700 case DT_MIPS_RLD_MAP2:
3701 // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
3702 {
Dmitriy Ivanov20d89cb2015-03-30 18:43:38 -07003703 r_debug** dp = reinterpret_cast<r_debug**>(
3704 reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
Raghu Gandham68815722014-12-18 19:12:19 -08003705 *dp = &_r_debug;
3706 }
3707 break;
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003708
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003709 case DT_MIPS_RLD_VERSION:
3710 case DT_MIPS_FLAGS:
3711 case DT_MIPS_BASE_ADDRESS:
3712 case DT_MIPS_UNREFEXTNO:
3713 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003714
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003715 case DT_MIPS_SYMTABNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003716 mips_symtabno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003717 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003718
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003719 case DT_MIPS_LOCAL_GOTNO:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003720 mips_local_gotno_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003721 break;
3722
3723 case DT_MIPS_GOTSYM:
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003724 mips_gotsym_ = d->d_un.d_val;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003725 break;
3726#endif
Dmitriy Ivanovea6eae12014-10-15 14:59:01 -07003727 // Ignored: "Its use has been superseded by the DF_BIND_NOW flag"
3728 case DT_BIND_NOW:
3729 break;
3730
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003731 case DT_VERSYM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003732 versym_ = reinterpret_cast<ElfW(Versym)*>(load_bias + d->d_un.d_ptr);
3733 break;
3734
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003735 case DT_VERDEF:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003736 verdef_ptr_ = load_bias + d->d_un.d_ptr;
3737 break;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003738 case DT_VERDEFNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003739 verdef_cnt_ = d->d_un.d_val;
3740 break;
3741
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003742 case DT_VERNEED:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003743 verneed_ptr_ = load_bias + d->d_un.d_ptr;
3744 break;
3745
Alexander Ivchenkoe8314332014-12-02 15:32:25 +03003746 case DT_VERNEEDNUM:
Dmitriy Ivanov2a815362015-04-09 13:42:33 -07003747 verneed_cnt_ = d->d_un.d_val;
Dmitriy Ivanov513e29e2014-10-06 11:30:43 -07003748 break;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003749
Evgenii Stepanov68650822015-06-10 13:38:39 -07003750 case DT_RUNPATH:
3751 // this is parsed after we have strtab initialized (see below).
3752 break;
3753
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003754 default:
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003755 if (!relocating_linker) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003756 DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
Dmitriy Ivanov8f61d992014-09-16 14:31:06 -07003757 reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
3758 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003759 break;
Brian Carlstromd4ee82d2013-02-28 15:58:45 -08003760 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003761 }
3762
Duane Sandbc425c72015-06-01 16:29:14 -07003763#if defined(__mips__) && !defined(__LP64__)
3764 if (!mips_check_and_adjust_fp_modes()) {
3765 return false;
3766 }
3767#endif
3768
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003769 DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003770 reinterpret_cast<void*>(base), strtab_, symtab_);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003771
3772 // Sanity checks.
3773 if (relocating_linker && needed_count != 0) {
3774 DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
3775 return false;
3776 }
Dmitriy Ivanov3597b802015-03-09 12:02:02 -07003777 if (nbucket_ == 0 && gnu_nbucket_ == 0) {
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003778 DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003779 "(new hash type from the future?)", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003780 return false;
3781 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003782 if (strtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003783 DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003784 return false;
3785 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003786 if (symtab_ == 0) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003787 DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003788 return false;
3789 }
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003790
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003791 // second pass - parse entries relying on strtab
3792 for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
Evgenii Stepanov68650822015-06-10 13:38:39 -07003793 switch (d->d_tag) {
3794 case DT_SONAME:
Dmitriy Ivanov4f7a7ad2015-10-15 12:07:25 -07003795 set_soname(get_string(d->d_un.d_val));
Evgenii Stepanov68650822015-06-10 13:38:39 -07003796 break;
3797 case DT_RUNPATH:
Evgenii Stepanov68650822015-06-10 13:38:39 -07003798 set_dt_runpath(get_string(d->d_un.d_val));
3799 break;
Dmitriy Ivanov624b8f12015-06-08 10:41:33 -07003800 }
3801 }
3802
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003803 // Before M release linker was using basename in place of soname.
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003804 // In the case when dt_soname is absent some apps stop working
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003805 // because they can't find dt_needed library by soname.
3806 // This workaround should keep them working. (applies only
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003807 // for apps targeting sdk version <=22). Make an exception for
3808 // the main executable and linker; they do not need to have dt_soname
3809 if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
3810 get_application_target_sdk_version() <= 22) {
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003811 soname_ = basename(realpath_.c_str());
3812 DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
3813 get_realpath(), soname_);
Dimitry Ivanovdf91dc22016-02-25 15:22:04 -08003814 add_dlwarning(get_realpath(), "missing DT_SONAME");
Dmitriy Ivanov75108f42015-06-02 13:28:06 -07003815 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003816 return true;
Dmitriy Ivanov14669a92014-09-05 16:42:53 -07003817}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003818
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003819bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
3820 const android_dlextinfo* extinfo) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003821
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08003822 local_group_root_ = local_group.front();
3823 if (local_group_root_ == nullptr) {
3824 local_group_root_ = this;
3825 }
3826
Dmitriy Ivanov19133522015-06-02 17:36:54 -07003827 if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
3828 target_sdk_version_ = get_application_target_sdk_version();
3829 }
3830
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003831 VersionTracker version_tracker;
3832
3833 if (!version_tracker.init(this)) {
3834 return false;
3835 }
3836
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003837#if !defined(__LP64__)
3838 if (has_text_relocations) {
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003839 // Fail if app is targeting sdk version > 22
Dmitriy Ivanov80687862015-10-09 13:58:46 -07003840 if (get_application_target_sdk_version() > 22) {
Dmitriy Ivanovfae39d22015-10-13 11:07:56 -07003841 PRINT("%s: has text relocations", get_realpath());
Dmitriy Ivanove4ad91f2015-06-12 15:00:31 -07003842 DL_ERR("%s: has text relocations", get_realpath());
3843 return false;
3844 }
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003845 // Make segments writable to allow text relocations to work properly. We will later call
Dmitriy Ivanov7e039932015-10-01 14:02:19 -07003846 // phdr_table_protect_segments() after all of them are applied.
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003847 DL_WARN("%s has text relocations. This is wasting memory and prevents "
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003848 "security hardening. Please fix.", get_realpath());
Dimitry Ivanovdf91dc22016-02-25 15:22:04 -08003849 add_dlwarning(get_realpath(), "text relocations");
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003850 if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
3851 DL_ERR("can't unprotect loadable segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003852 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003853 return false;
3854 }
3855 }
3856#endif
3857
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003858 if (android_relocs_ != nullptr) {
3859 // check signature
3860 if (android_relocs_size_ > 3 &&
3861 android_relocs_[0] == 'A' &&
3862 android_relocs_[1] == 'P' &&
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003863 android_relocs_[2] == 'S' &&
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003864 android_relocs_[3] == '2') {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003865 DEBUG("[ android relocating %s ]", get_realpath());
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003866
3867 bool relocated = false;
3868 const uint8_t* packed_relocs = android_relocs_ + 4;
3869 const size_t packed_relocs_size = android_relocs_size_ - 4;
3870
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003871 relocated = relocate(
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003872 version_tracker,
Dmitriy Ivanov18870d32015-04-22 13:10:04 -07003873 packed_reloc_iterator<sleb128_decoder>(
3874 sleb128_decoder(packed_relocs, packed_relocs_size)),
3875 global_group, local_group);
Dmitriy Ivanov18a69562015-02-04 16:05:30 -08003876
3877 if (!relocated) {
3878 return false;
3879 }
3880 } else {
3881 DL_ERR("bad android relocation header.");
3882 return false;
3883 }
3884 }
3885
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003886#if defined(USE_RELA)
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003887 if (rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003888 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003889 if (!relocate(version_tracker,
3890 plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003891 return false;
Elliott Hughesc00f2cb2013-10-04 17:01:33 -07003892 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003893 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003894 if (plt_rela_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003895 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003896 if (!relocate(version_tracker,
3897 plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003898 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003899 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003900 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003901#else
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003902 if (rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003903 DEBUG("[ relocating %s ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003904 if (!relocate(version_tracker,
3905 plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003906 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003907 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003908 }
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003909 if (plt_rel_ != nullptr) {
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003910 DEBUG("[ relocating %s plt ]", get_realpath());
Dmitriy Ivanov7e4bbba2015-04-30 19:49:19 -07003911 if (!relocate(version_tracker,
3912 plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003913 return false;
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003914 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003915 }
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -07003916#endif
Brigid Smithc5a13ef2014-07-23 11:22:25 -07003917
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003918#if defined(__mips__)
Dmitriy Ivanovf39cb632015-04-30 20:17:03 -07003919 if (!mips_relocate_got(version_tracker, global_group, local_group)) {
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003920 return false;
3921 }
Raghu Gandhamd7daacb2012-07-31 12:07:22 -07003922#endif
3923
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003924 DEBUG("[ finished linking %s ]", get_realpath());
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003925
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003926#if !defined(__LP64__)
3927 if (has_text_relocations) {
3928 // All relocations are done, we can protect our segments back to read-only.
3929 if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
3930 DL_ERR("can't protect segments for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003931 get_realpath(), strerror(errno));
Dimitry Ivanov56be6ed2015-04-01 21:18:48 +00003932 return false;
3933 }
3934 }
3935#endif
3936
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003937 /* We can also turn on GNU RELRO protection */
3938 if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
3939 DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003940 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003941 return false;
3942 }
Nick Kralevich9ec0f032012-02-28 10:40:00 -08003943
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003944 /* Handle serializing/sharing the RELRO segment */
3945 if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
3946 if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
3947 extinfo->relro_fd) < 0) {
3948 DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003949 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003950 return false;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003951 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003952 } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
3953 if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
3954 extinfo->relro_fd) < 0) {
3955 DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07003956 get_realpath(), strerror(errno));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003957 return false;
3958 }
3959 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +00003960
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07003961 notify_gdb_of_load(this);
3962 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003963}
3964
Nick Kralevich468319c2011-11-11 15:53:17 -08003965/*
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003966 * This function add vdso to internal dso list.
3967 * It helps to stack unwinding through signal handlers.
3968 * Also, it makes bionic more like glibc.
3969 */
Kito Cheng812fd422014-03-25 22:53:56 +08003970static void add_vdso(KernelArgumentBlock& args __unused) {
Elliott Hughes4eeb1f12013-10-25 17:38:02 -07003971#if defined(AT_SYSINFO_EHDR)
Elliott Hughes0266ae52014-02-10 17:46:57 -08003972 ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07003973 if (ehdr_vdso == nullptr) {
Elliott Hughes0266ae52014-02-10 17:46:57 -08003974 return;
3975 }
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003976
Dmitriy Ivanovd9b08a02015-11-16 13:17:27 -08003977 soinfo* si = soinfo_alloc(&g_default_namespace, "[vdso]", nullptr, 0, 0);
Sergey Melnikovebd506c2013-10-31 18:02:12 +04003978
Elliott Hughes0266ae52014-02-10 17:46:57 -08003979 si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
3980 si->phnum = ehdr_vdso->e_phnum;
3981 si->base = reinterpret_cast<ElfW(Addr)>(ehdr_vdso);
3982 si->size = phdr_table_get_load_size(si->phdr, si->phnum);
Elliott Hughes0266ae52014-02-10 17:46:57 -08003983 si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
Sergey Melnikovebd506c2013-10-31 18:02:12 +04003984
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08003985 si->prelink_image();
3986 si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr);
Sergey Melnikovc45087b2013-01-25 16:40:13 +04003987#endif
3988}
3989
3990/*
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07003991 * This is linker soinfo for GDB. See details below.
3992 */
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07003993#if defined(__LP64__)
3994#define LINKER_PATH "/system/bin/linker64"
3995#else
3996#define LINKER_PATH "/system/bin/linker"
3997#endif
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07003998
3999// This is done to avoid calling c-tor prematurely
4000// because soinfo c-tor needs memory allocator
4001// which might be initialized after global variables.
4002static uint8_t linker_soinfo_for_gdb_buf[sizeof(soinfo)] __attribute__((aligned(8)));
4003static soinfo* linker_soinfo_for_gdb = nullptr;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07004004
4005/* gdb expects the linker to be in the debug shared object list.
4006 * Without this, gdb has trouble locating the linker's ".text"
4007 * and ".plt" sections. Gdb could also potentially use this to
4008 * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
4009 * Don't use soinfo_alloc(), because the linker shouldn't
4010 * be on the soinfo list.
4011 */
4012static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004013 linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(nullptr, LINKER_PATH,
4014 nullptr, 0, 0);
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07004015
Dmitriy Ivanov175dae92015-06-10 19:46:19 -07004016 linker_soinfo_for_gdb->load_bias = linker_base;
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07004017
4018 /*
4019 * Set the dynamic field in the link map otherwise gdb will complain with
4020 * the following:
4021 * warning: .dynamic section for "/system/bin/linker" is not at the
4022 * expected address (wrong library or version mismatch?)
4023 */
4024 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
4025 ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
4026 phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -07004027 &linker_soinfo_for_gdb->dynamic, nullptr);
4028 insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07004029}
4030
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004031static void init_default_namespace() {
4032 g_default_namespace.set_name("(default)");
4033 g_default_namespace.set_isolated(false);
4034
Evgenii Stepanovd640b222015-07-10 17:54:01 -07004035 const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
4036 somain->load_bias);
4037 const char* bname = basename(interp);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004038 if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07004039 g_default_ld_paths = kAsanDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004040 } else {
Evgenii Stepanovd640b222015-07-10 17:54:01 -07004041 g_default_ld_paths = kDefaultLdPaths;
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004042 }
4043
4044 std::vector<std::string> ld_default_paths;
4045 for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
4046 ld_default_paths.push_back(g_default_ld_paths[i]);
4047 }
4048
4049 g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
Evgenii Stepanovd640b222015-07-10 17:54:01 -07004050};
4051
Dmitriy Ivanovb4e50672015-04-28 15:49:26 -07004052extern "C" int __system_properties_init(void);
4053
Dmitriy Ivanovd59e5002014-05-09 09:10:14 -07004054/*
Nick Kralevich468319c2011-11-11 15:53:17 -08004055 * This code is called after the linker has linked itself and
4056 * fixed it's own GOT. It is safe to make references to externs
4057 * and other non-local data at this point.
4058 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08004059static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
Evgeniy Stepanov1a78fbb2012-03-22 18:01:53 +04004060#if TIMING
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004061 struct timeval t0, t1;
4062 gettimeofday(&t0, 0);
Evgeniy Stepanov1a78fbb2012-03-22 18:01:53 +04004063#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004064
Elliott Hughes1801db32015-06-08 18:04:00 -07004065 // Sanitize the environment.
4066 __libc_init_AT_SECURE(args);
David 'Digit' Turnerbe575592010-12-16 19:52:02 +01004067
Dmitriy Ivanovb4e50672015-04-28 15:49:26 -07004068 // Initialize system properties
4069 __system_properties_init(); // may use 'environ'
4070
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004071 debuggerd_init();
4072
4073 // Get a few environment variables.
Elliott Hughes1801db32015-06-08 18:04:00 -07004074 const char* LD_DEBUG = getenv("LD_DEBUG");
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004075 if (LD_DEBUG != nullptr) {
4076 g_ld_debug_verbosity = atoi(LD_DEBUG);
4077 }
4078
Elliott Hughes116b5692016-01-04 17:45:36 -08004079#if defined(__LP64__)
4080 INFO("[ Android dynamic linker (64-bit) ]");
4081#else
4082 INFO("[ Android dynamic linker (32-bit) ]");
4083#endif
4084
Elliott Hughes1801db32015-06-08 18:04:00 -07004085 // These should have been sanitized by __libc_init_AT_SECURE, but the test
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004086 // doesn't cost us anything.
4087 const char* ldpath_env = nullptr;
4088 const char* ldpreload_env = nullptr;
Elliott Hughes1801db32015-06-08 18:04:00 -07004089 if (!getauxval(AT_SECURE)) {
4090 ldpath_env = getenv("LD_LIBRARY_PATH");
Elliott Hughes116b5692016-01-04 17:45:36 -08004091 if (ldpath_env != nullptr) {
4092 INFO("[ LD_LIBRARY_PATH set to '%s' ]", ldpath_env);
4093 }
Elliott Hughes1801db32015-06-08 18:04:00 -07004094 ldpreload_env = getenv("LD_PRELOAD");
Elliott Hughes116b5692016-01-04 17:45:36 -08004095 if (ldpreload_env != nullptr) {
4096 INFO("[ LD_PRELOAD set to '%s' ]", ldpreload_env);
4097 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004098 }
4099
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004100 soinfo* si = soinfo_alloc(&g_default_namespace, args.argv[0], nullptr, 0, RTLD_GLOBAL);
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004101 if (si == nullptr) {
4102 exit(EXIT_FAILURE);
4103 }
4104
4105 /* bootstrap the link map, the main exe always needs to be first */
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08004106 si->set_main_executable();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004107 link_map* map = &(si->link_map_head);
4108
4109 map->l_addr = 0;
4110 map->l_name = args.argv[0];
4111 map->l_prev = nullptr;
4112 map->l_next = nullptr;
4113
4114 _r_debug.r_map = map;
4115 r_debug_tail = map;
4116
4117 init_linker_info_for_gdb(linker_base);
4118
4119 // Extract information passed from the kernel.
4120 si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
4121 si->phnum = args.getauxval(AT_PHNUM);
4122 si->entry = args.getauxval(AT_ENTRY);
4123
4124 /* Compute the value of si->base. We can't rely on the fact that
4125 * the first entry is the PHDR because this will not be true
4126 * for certain executables (e.g. some in the NDK unit test suite)
4127 */
4128 si->base = 0;
4129 si->size = phdr_table_get_load_size(si->phdr, si->phnum);
4130 si->load_bias = 0;
4131 for (size_t i = 0; i < si->phnum; ++i) {
4132 if (si->phdr[i].p_type == PT_PHDR) {
4133 si->load_bias = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_vaddr;
4134 si->base = reinterpret_cast<ElfW(Addr)>(si->phdr) - si->phdr[i].p_offset;
4135 break;
Nick Kralevich8d3e91d2013-04-25 13:15:24 -07004136 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004137 }
4138 si->dynamic = nullptr;
Nick Kralevich8d3e91d2013-04-25 13:15:24 -07004139
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004140 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
4141 if (elf_hdr->e_type != ET_DYN) {
4142 __libc_format_fd(2, "error: only position independent executables (PIE) are supported.\n");
4143 exit(EXIT_FAILURE);
4144 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004145
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004146 // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
4147 parse_LD_LIBRARY_PATH(ldpath_env);
4148 parse_LD_PRELOAD(ldpreload_env);
David 'Digit' Turnerbe575592010-12-16 19:52:02 +01004149
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004150 somain = si;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004151
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004152 init_default_namespace();
Evgenii Stepanovd640b222015-07-10 17:54:01 -07004153
Dmitriy Ivanov67181252015-01-07 15:48:25 -08004154 if (!si->prelink_image()) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004155 __libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
Dmitriy Ivanov67181252015-01-07 15:48:25 -08004156 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004157
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07004158 // add somain to global group
4159 si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
4160
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004161 // Load ld_preloads and dependencies.
4162 StringLinkedList needed_library_name_list;
4163 size_t needed_libraries_count = 0;
4164 size_t ld_preloads_count = 0;
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07004165
4166 for (const auto& ld_preload_name : g_ld_preload_names) {
4167 needed_library_name_list.push_back(ld_preload_name.c_str());
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004168 ++needed_libraries_count;
Dmitriy Ivanovf8093a92015-04-28 18:09:53 -07004169 ++ld_preloads_count;
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004170 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004171
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004172 for_each_dt_needed(si, [&](const char* name) {
4173 needed_library_name_list.push_back(name);
4174 ++needed_libraries_count;
4175 });
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004176
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004177 const char* needed_library_names[needed_libraries_count];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004178
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004179 memset(needed_library_names, 0, sizeof(needed_library_names));
4180 needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004181
Dmitriy Ivanovd165f562015-03-23 18:43:02 -07004182 if (needed_libraries_count > 0 &&
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004183 !find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count,
4184 nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
Evgenii Stepanov0cdef7e2015-07-06 17:56:31 -07004185 /* add_as_children */ true)) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004186 __libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08004187 } else if (needed_libraries_count == 0) {
4188 if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004189 __libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08004190 }
4191 si->increment_ref_count();
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004192 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004193
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004194 add_vdso(args);
Nick Kralevich2aebf542014-05-07 10:32:39 -07004195
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08004196 {
4197 ProtectedDataGuard guard;
Matt Fischer4fd42c12009-12-31 12:09:10 -06004198
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -08004199 si->call_pre_init_constructors();
4200
4201 /* After the prelink_image, the si->load_bias is initialized.
4202 * For so lib, the map->l_addr will be updated in notify_gdb_of_load.
4203 * We need to update this value for so exe here. So Unwind_Backtrace
4204 * for some arch like x86 could work correctly within so exe.
4205 */
4206 map->l_addr = si->load_bias;
4207 si->call_constructors();
4208 }
Evgeniy Stepanove83c56d2011-12-21 13:03:54 +04004209
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004210#if TIMING
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004211 gettimeofday(&t1, nullptr);
4212 PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) (
4213 (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
4214 (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004215#endif
4216#if STATS
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004217 PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol", args.argv[0],
4218 linker_stats.count[kRelocAbsolute],
4219 linker_stats.count[kRelocRelative],
4220 linker_stats.count[kRelocCopy],
4221 linker_stats.count[kRelocSymbol]);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004222#endif
4223#if COUNT_PAGES
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004224 {
4225 unsigned n;
4226 unsigned i;
4227 unsigned count = 0;
4228 for (n = 0; n < 4096; n++) {
4229 if (bitmask[n]) {
4230 unsigned x = bitmask[n];
Marcus Oaklande365f9d2013-10-10 15:19:31 +01004231#if defined(__LP64__)
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004232 for (i = 0; i < 32; i++) {
Marcus Oaklande365f9d2013-10-10 15:19:31 +01004233#else
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004234 for (i = 0; i < 8; i++) {
Marcus Oaklande365f9d2013-10-10 15:19:31 +01004235#endif
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004236 if (x & 1) {
4237 count++;
4238 }
4239 x >>= 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004240 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004241 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004242 }
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004243 PRINT("PAGES MODIFIED: %s: %d (%dKB)", args.argv[0], count, count * 4);
4244 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004245#endif
4246
4247#if TIMING || STATS || COUNT_PAGES
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004248 fflush(stdout);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004249#endif
4250
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07004251 TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry));
Dmitriy Ivanov6abf6242014-09-12 09:43:13 -07004252 return si->entry;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08004253}
Nick Kralevich468319c2011-11-11 15:53:17 -08004254
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02004255/* Compute the load-bias of an existing executable. This shall only
4256 * be used to compute the load bias of an executable or shared library
4257 * that was loaded by the kernel itself.
4258 *
4259 * Input:
4260 * elf -> address of ELF header, assumed to be at the start of the file.
4261 * Return:
4262 * load bias, i.e. add the value of any p_vaddr in the file to get
4263 * the corresponding address in memory.
4264 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08004265static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
4266 ElfW(Addr) offset = elf->e_phoff;
Dmitriy Ivanov3edb9182015-05-07 10:48:00 -07004267 const ElfW(Phdr)* phdr_table =
4268 reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
Elliott Hughes0266ae52014-02-10 17:46:57 -08004269 const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02004270
Elliott Hughes0266ae52014-02-10 17:46:57 -08004271 for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
Kito Chengfa8c05d2013-03-12 14:58:06 +08004272 if (phdr->p_type == PT_LOAD) {
Elliott Hughes0266ae52014-02-10 17:46:57 -08004273 return reinterpret_cast<ElfW(Addr)>(elf) + phdr->p_offset - phdr->p_vaddr;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02004274 }
Kito Chengfa8c05d2013-03-12 14:58:06 +08004275 }
4276 return 0;
David 'Digit' Turnerbea23e52012-06-18 23:38:46 +02004277}
4278
Elliott Hughes42d949f2016-01-06 19:51:43 -08004279extern "C" int __set_tls(void*);
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07004280extern "C" void _start();
4281
Nick Kralevich468319c2011-11-11 15:53:17 -08004282/*
4283 * This is the entry point for the linker, called from begin.S. This
4284 * method is responsible for fixing the linker's own relocations, and
4285 * then calling __linker_init_post_relocation().
4286 *
4287 * Because this method is called before the linker has fixed it's own
4288 * relocations, any attempt to reference an extern variable, extern
4289 * function, or other GOT reference will generate a segfault.
4290 */
Elliott Hughes0266ae52014-02-10 17:46:57 -08004291extern "C" ElfW(Addr) __linker_init(void* raw_args) {
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08004292 KernelArgumentBlock args(raw_args);
Nick Kralevich468319c2011-11-11 15:53:17 -08004293
Elliott Hughes42d949f2016-01-06 19:51:43 -08004294 void* tls[BIONIC_TLS_SLOTS];
4295 __set_tls(tls);
4296
Elliott Hughes0266ae52014-02-10 17:46:57 -08004297 ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07004298 ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
Elliott Hughes0266ae52014-02-10 17:46:57 -08004299 ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
Elliott Hughesfaf05ba2014-02-11 16:59:37 -08004300 ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
Nick Kralevich468319c2011-11-11 15:53:17 -08004301
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004302 soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);
Nick Kralevich468319c2011-11-11 15:53:17 -08004303
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07004304 // If the linker is not acting as PT_INTERP entry_point is equal to
4305 // _start. Which means that the linker is running as an executable and
4306 // already linked by PT_INTERP.
4307 //
4308 // This happens when user tries to run 'adb shell /system/bin/linker'
4309 // see also https://code.google.com/p/android/issues/detail?id=63174
4310 if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004311 __libc_fatal("This is %s, the helper program for shared library executables.", args.argv[0]);
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07004312 }
4313
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08004314 linker_so.base = linker_addr;
4315 linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
4316 linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
Dmitriy Ivanov851135b2014-08-29 12:02:36 -07004317 linker_so.dynamic = nullptr;
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08004318 linker_so.phdr = phdr;
4319 linker_so.phnum = elf_hdr->e_phnum;
Dmitriy Ivanovab972b92014-11-29 13:57:41 -08004320 linker_so.set_linker_flag();
Elliott Hughes5419b942012-10-16 15:54:46 -07004321
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -07004322 // This might not be obvious... The reasons why we pass g_empty_list
4323 // in place of local_group here are (1) we do not really need it, because
4324 // linker is built with DT_SYMBOLIC and therefore relocates its symbols against
4325 // itself without having to look into local_group and (2) allocators
4326 // are not yet initialized, and therefore we cannot use linked_list.push_*
4327 // functions at this point.
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08004328 if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004329 __libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08004330 }
Elliott Hughesd23736e2012-11-01 15:16:56 -07004331
Elliott Hughesd2948632015-07-21 11:57:09 -07004332 __libc_init_main_thread(args);
Dmitriy Ivanov14241402014-08-26 14:16:52 -07004333
Josh Gao93c0f5e2015-10-06 11:08:13 -07004334 // Initialize the linker's static libc's globals
4335 __libc_init_globals(args);
4336
Dmitriy Ivanovefe13832014-07-28 15:05:51 -07004337 // Initialize the linker's own global variables
Dmitriy Ivanov047b5932014-11-13 09:39:20 -08004338 linker_so.call_constructors();
Dmitriy Ivanov4151ea72014-07-24 15:33:25 -07004339
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07004340 // Initialize static variables. Note that in order to
4341 // get correct libdl_info we need to call constructors
4342 // before get_libdl_info().
4343 solist = get_libdl_info();
4344 sonext = get_libdl_info();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -07004345 g_default_namespace.soinfo_list().push_back(get_libdl_info());
Dmitriy Ivanov0d150942014-08-22 12:25:04 -07004346
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08004347 // We have successfully fixed our own relocations. It's safe to run
4348 // the main part of the linker now.
Elliott Hughes1728b232014-05-14 10:02:03 -07004349 args.abort_message_ptr = &g_abort_message;
Elliott Hughes0266ae52014-02-10 17:46:57 -08004350 ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08004351
Elliott Hughes116b5692016-01-04 17:45:36 -08004352 INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
Elliott Hughes611f9562015-01-23 10:43:58 -08004353
Elliott Hughes42b2c6a2013-02-07 10:14:39 -08004354 // Return the address that the calling assembly stub should jump to.
4355 return start_address;
Nick Kralevich468319c2011-11-11 15:53:17 -08004356}