1acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao/*
2acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Copyright (C) 2012 The Android Open Source Project
3acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
4acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Licensed under the Apache License, Version 2.0 (the "License");
5acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * you may not use this file except in compliance with the License.
6acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * You may obtain a copy of the License at
7acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
8acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *      http://www.apache.org/licenses/LICENSE-2.0
9acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
10acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Unless required by applicable law or agreed to in writing, software
11acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * distributed under the License is distributed on an "AS IS" BASIS,
12acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * See the License for the specific language governing permissions and
14acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * limitations under the License.
15acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao */
16acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
17acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao#include <gtest/gtest.h>
18acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
19acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao#include <dlfcn.h>
208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <limits.h>
218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdio.h>
228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdint.h>
23708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov#include <string.h>
24b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry#if __has_include(<sys/auxv.h>)
25b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry#include <sys/auxv.h>
26b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry#endif
27109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry#include <sys/user.h>
288e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
298e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <string>
30c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov#include <thread>
31acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
32b8ab61804cec48e4ca585f4508fb1b7c6c5a04c5Tom Cherry#include <android-base/scopeguard.h>
33b8ab61804cec48e4ca585f4508fb1b7c6c5a04c5Tom Cherry
34927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov#include "gtest_globals.h"
35708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov#include "dlfcn_symlink_support.h"
36aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#include "utils.h"
37aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
38ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#if defined(__BIONIC__) && (defined(__arm__) || defined(__i386__))
39ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#pragma clang diagnostic push
40ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#pragma clang diagnostic ignored "-Wunused-parameter"
41ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
42ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#include <llvm/ADT/StringRef.h>
43ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#include <llvm/Object/Binary.h>
44ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#include <llvm/Object/ELFObjectFile.h>
45ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#include <llvm/Object/ObjectFile.h>
46ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
47ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#pragma clang diagnostic pop
48ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#endif //  defined(__ANDROID__) && (defined(__arm__) || defined(__i386__))
49ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
503b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ASSERT_SUBSTR(needle, haystack) \
513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
53aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
541728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic bool g_called = false;
55acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() {
561728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = true;
57acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
58acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
59f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovstatic int g_ctor_function_called = 0;
60554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovstatic int g_ctor_argc = 0;
61554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovstatic char** g_ctor_argv = reinterpret_cast<char**>(0xDEADBEEF);
62554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovstatic char** g_ctor_envp = g_ctor_envp;
63f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
64554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovextern "C" void ctor_function(int argc, char** argv, char** envp) __attribute__ ((constructor));
65f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
66554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovextern "C" void ctor_function(int argc, char** argv, char** envp) {
67f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  g_ctor_function_called = 17;
68554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  g_ctor_argc = argc;
69554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  g_ctor_argv = argv;
70554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  g_ctor_envp = envp;
71f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
72f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
73f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy IvanovTEST(dlfcn, ctor_function_call) {
74f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  ASSERT_EQ(17, g_ctor_function_called);
75554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  ASSERT_TRUE(g_ctor_argc = get_argc());
76554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  ASSERT_TRUE(g_ctor_argv = get_argv());
77554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  ASSERT_TRUE(g_ctor_envp = get_envp());
78f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
79f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
8076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy IvanovTEST(dlfcn, dlsym_in_executable) {
813b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
82aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  void* self = dlopen(nullptr, RTLD_NOW);
83aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(self != nullptr);
84aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr);
85acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
86acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* sym = dlsym(self, "DlSymTestFunction");
87aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
88acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
89acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void (*function)() = reinterpret_cast<void(*)()>(sym);
90acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
911728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = false;
92acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  function();
931728b2396591853345507a063ed6075dfd251706Elliott Hughes  ASSERT_TRUE(g_called);
941a6961650c82168864afe040dbdc05977db701dfElliott Hughes
951a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
96acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
978e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9876ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy IvanovTEST(dlfcn, dlsym_from_sofile) {
9976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
10076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
10176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
102697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
10376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
10476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(symbol == nullptr);
10576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
10676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
10776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  typedef int* (*fn_t)();
108697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
109697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
110697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
11176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
112697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
113697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
114697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(42, *ptr);
115697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
116697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
117697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
118697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
119697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
120697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
121697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
122697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(44, *ptr);
123697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
124697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
125697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
126697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
127697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
128697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
129697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
130697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(43, *ptr);
131697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
132697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  dlclose(handle);
133697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov}
134697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
135697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy IvanovTEST(dlfcn, dlsym_from_sofile_with_preload) {
136697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL);
137697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(preload != nullptr) << dlerror();
138697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
139697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
140697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
141697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
142697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
143697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
144697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(symbol == nullptr);
145697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
146697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
147697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  typedef int* (*fn_t)();
148697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
149697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
150697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
15176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
152697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
15376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
15476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_EQ(42, *ptr);
15576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
156697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
157697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
158697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
159697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
160697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
161697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
162697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(44, *ptr);
163697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
164697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
165697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
166697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
167697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
168697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
169697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
170697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(43, *ptr);
171697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
17276ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  dlclose(handle);
173697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  dlclose(preload);
17476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov}
17576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
176f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy IvanovTEST(dlfcn, dlsym_handle_global_sym) {
177f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // check that we do not look into global group
178f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // when looking up symbol by handle
179f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  void* handle = dlopen("libtest_empty.so", RTLD_NOW);
180f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
181f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
182f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
183f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror());
184f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov
185f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  sym = dlsym(handle, "DlSymTestFunction");
186f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
187f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror());
188f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  dlclose(handle);
189f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov}
190f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov
191d5b578ac15330d7a872c198427628b723e0cc1cbDimitry IvanovTEST(dlfcn, dlsym_handle_empty_symbol) {
192d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  // check that dlsym of an empty symbol fails (see http://b/33530622)
193d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW);
194d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
195d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  void* sym = dlsym(handle, "");
196d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  ASSERT_TRUE(sym == nullptr);
197d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  ASSERT_SUBSTR("undefined symbol: ", dlerror());
198d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  dlclose(handle);
199d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov}
200d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov
201aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy IvanovTEST(dlfcn, dlsym_with_dependencies) {
202aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
203f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
204aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlerror();
205aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  // This symbol is in DT_NEEDED library.
206aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
207f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
208aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  int (*fn)(void);
209aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
210aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  EXPECT_EQ(4, fn());
211aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlclose(handle);
212aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}
213aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
214b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy IvanovTEST(dlfcn, dlopen_noload) {
215b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
216aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
217b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW);
218b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
219aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
220aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle2 != nullptr);
221b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == handle2);
222b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
223b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
224b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov}
225b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
226618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy IvanovTEST(dlfcn, dlopen_by_soname) {
227618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  static const char* soname = "libdlext_test_soname.so";
228618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  static const char* filename = "libdlext_test_different_soname.so";
229618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 1. Make sure there is no library with soname in default search path
230618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle = dlopen(soname, RTLD_NOW);
231618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
232618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
233618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 2. Load a library using filename
234618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  handle = dlopen(filename, RTLD_NOW);
235618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
236618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
237618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 3. Find library by soname
238618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
239618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle_soname != nullptr) << dlerror();
240618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_EQ(handle, handle_soname);
241618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
242618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 4. RTLD_NOLOAD should still work with filename
243618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
244618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle_filename != nullptr) << dlerror();
245618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_EQ(handle, handle_filename);
246618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
247618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle_filename);
248618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle_soname);
249618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle);
250618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov}
251618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
252c18de1bd47a558c9a24c6a4645df27df2c4738b4dimitryTEST(dlfcn, dlopen_vdso) {
253b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry#if __has_include(<sys/auxv.h>)
254b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry  if (getauxval(AT_SYSINFO_EHDR) == 0) {
255b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry    GTEST_LOG_(INFO) << "getauxval(AT_SYSINFO_EHDR) == 0, skipping this test.";
256b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry    return;
257b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry  }
258b9555a9251467bc2d0b05a4e2f011531c1d3bd4adimitry#endif
259da1bb113408030cebd1b7f2ce4b10b0e1852666dElliott Hughes
260da1bb113408030cebd1b7f2ce4b10b0e1852666dElliott Hughes  const char* vdso_name = "linux-vdso.so.1";
261da1bb113408030cebd1b7f2ce4b10b0e1852666dElliott Hughes#if defined(__i386__)
262da1bb113408030cebd1b7f2ce4b10b0e1852666dElliott Hughes  vdso_name = "linux-gate.so.1";
263da1bb113408030cebd1b7f2ce4b10b0e1852666dElliott Hughes#endif
264da1bb113408030cebd1b7f2ce4b10b0e1852666dElliott Hughes  void* handle = dlopen(vdso_name, RTLD_NOW);
265c18de1bd47a558c9a24c6a4645df27df2c4738b4dimitry  ASSERT_TRUE(handle != nullptr) << dlerror();
266c18de1bd47a558c9a24c6a4645df27df2c4738b4dimitry  dlclose(handle);
267c18de1bd47a558c9a24c6a4645df27df2c4738b4dimitry}
268c18de1bd47a558c9a24c6a4645df27df2c4738b4dimitry
2690a2ab0203cc12c9b4b7647b18caf0343af8ca1a4Dimitry Ivanov// mips doesn't support ifuncs
2700a2ab0203cc12c9b4b7647b18caf0343af8ca1a4Dimitry Ivanov#if !defined(__mips__)
27121975b2861d859fb580ddfba50d323740486b7bcDimitry IvanovTEST(dlfcn, ifunc_variable) {
27221975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  typedef const char* (*fn_ptr)();
27321975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov
27421975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  // ifunc's choice depends on whether IFUNC_CHOICE has a value
27521975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  // first check the set case
27621975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  setenv("IFUNC_CHOICE", "set", 1);
27721975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  // preload libtest_ifunc_variable_impl.so
27821975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  void* handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
27921975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  void* handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
28021975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
28121975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  const char** foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
28221975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
28321975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
28421975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
28521975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_EQ(strncmp("set", *foo_ptr, 3), 0);
28621975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
28721975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  dlclose(handle);
28821975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  dlclose(handle_impl);
28921975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov
29021975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  // then check the unset case
29121975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  unsetenv("IFUNC_CHOICE");
29221975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
29321975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
29421975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
29521975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
29621975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
29721975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
29821975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
29921975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_EQ(strncmp("unset", *foo_ptr, 5), 0);
30021975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
30121975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  dlclose(handle);
30221975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  dlclose(handle_impl);
30321975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov}
30421975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov
305c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid SmithTEST(dlfcn, ifunc) {
3069598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
307c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
308c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // ifunc's choice depends on whether IFUNC_CHOICE has a value
309c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // first check the set case
310c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  setenv("IFUNC_CHOICE", "set", 1);
311c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
31221975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
3139598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
3149598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
31521975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
31621975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
3179598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
3189598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
319c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
320c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
321c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // then check the unset case
322c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  unsetenv("IFUNC_CHOICE");
323c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
32421975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
3259598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
3269598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
32721975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
32821975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
3299598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
33021975b2861d859fb580ddfba50d323740486b7bcDimitry Ivanov  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
3319598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  dlclose(handle);
3329598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov}
3339598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
3349598b8c415e2fa9f240508185fe8c964b83f538dDmitriy IvanovTEST(dlfcn, ifunc_ctor_call) {
3359598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
3369598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
3379598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
3389aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
3399aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
3409aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
3419aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_STREQ("false", is_ctor_called());
3429aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
3439aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
3449aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
3459598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_STREQ("true", is_ctor_called());
346c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
347c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
348ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov
349ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry IvanovTEST(dlfcn, ifunc_ctor_call_rtld_lazy) {
350ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  typedef const char* (*fn_ptr)();
351ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov
352ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  void* handle = dlopen("libtest_ifunc.so", RTLD_LAZY);
353ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
354ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
355ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
356ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_STREQ("false", is_ctor_called());
357ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov
358ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
359ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
360ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_STREQ("true", is_ctor_called());
361ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  dlclose(handle);
362ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov}
3630a2ab0203cc12c9b4b7647b18caf0343af8ca1a4Dimitry Ivanov#endif
364c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
365b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy IvanovTEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
366b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // This is the structure of the test library and
367b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // its dt_needed libraries
368b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // libtest_relo_check_dt_needed_order.so
369b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
370b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_1.so
371b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
372b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_2.so
373b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  //
374b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // The root library references relo_test_get_answer_lib - which is defined
375b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // in both dt_needed libraries, the correct relocation should
376b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // use the function defined in libtest_relo_check_dt_needed_order_1.so
377b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  void* handle = nullptr;
378b8ab61804cec48e4ca585f4508fb1b7c6c5a04c5Tom Cherry  auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
379b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
380b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
381b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
382b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
383b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  typedef int (*fn_t) (void);
384b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
385b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
386b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_EQ(1, fn());
387b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov}
388b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
389cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_dlsym) {
39014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Here is how the test library and its dt_needed
39114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // libraries are arranged
39214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
393cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  libtest_check_order_children.so
39414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
395cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._1_left.so
39614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
397cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._a.so
39814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
399cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ...r_b.so
40014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
401cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._2_right.so
40214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
403cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._d.so
40414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |       |
405cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |       +-> ..._b.so
40614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
407cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._3_c.so
40814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
40914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  load order should be (1, 2, 3, a, b, d)
41014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
41114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer() is defined in (2, 3, a, b, c)
41214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer2() is defined in (b, d)
413cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
41414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
415cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
416cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
41714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef int (*fn_t) (void);
41814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  fn_t fn, fn2;
419cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
420aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
421cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
422aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(fn2 != nullptr) << dlerror();
42314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
42414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(42, fn());
42514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(43, fn2());
42614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  dlclose(handle);
42714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
42814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
429cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings) {
430cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
431cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer which is defined in '_2.so'
432cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
433cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
434cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
435cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
436cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
437cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
438cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
439cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
440cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
441cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
442cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
443cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
444cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
445cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
446cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
447cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
448cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
449cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
450cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
451cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
452cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
453cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- empty
454cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
455cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
456cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
457cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
458cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //                     implements incorrect get_answer_impl()
459cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
460cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
461cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
462cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
463cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
464cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
465cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
466cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
467cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
468cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
469cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
470cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
471cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
472cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
473cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
474cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
475cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
476cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
477cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
478cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
479cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This test uses the same library as dlopen_check_order_reloc_siblings.
480cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Unlike dlopen_check_order_reloc_siblings it preloads
481cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
482cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // dlopen(libtest_check_order_reloc_siblings.so)
483cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
484cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
485cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
486cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
487cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
488cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
489cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
490cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
491cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
492cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
493cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
494cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
495cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle_for_1));
496cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
497cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
498cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
499cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
500cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
501cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
502cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
503cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
504cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
5057699d13a74769fe8063fcca95588c87c571226c0Dmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_grandchild) {
5067699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // This is how this one works:
5077699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // we lookup and call grandchild_get_answer which is defined in '_2.so'
5087699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
5097699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // the correct _impl() is implemented by '_c_1.so';
5107699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //
5117699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // Here is the picture of subtree:
5127699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //
5137699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // libtest_check_order_reloc_siblings.so
5147699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // |
5157699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // +-> ..._2.so <- grandchild_get_answer()
5167699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |
5177699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     +-> ..._c.so <- empty
5187699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   |
5197699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   +-> _c_1.so <- exports correct answer_impl()
5207699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   |
5217699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   +-> _c_2.so <- exports incorrect answer_impl()
5227699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |
5237699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     +-> ..._d.so <- empty
5247699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
5257699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
5267699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
5277699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov#ifdef __BIONIC__
5287699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
5297699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
5307699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov#endif
5317699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
5327699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
5337699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
5347699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
5357699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  typedef int (*fn_t) (void);
5367699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
5377699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
5387699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_EQ(42, fn());
5397699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
5407699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
5417699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov}
5427699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
543cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_nephew) {
544cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
545cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call nephew_get_answer which is defined in '_2.so'
546cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_[a-f].so'
547cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
548cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
549cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
550cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
551cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
552cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
553cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
554cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
555cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
556cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
557cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
558cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
559cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
560cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
561cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
562cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
563cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
564cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
565cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
566cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
567cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
568cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
569cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so
570cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
571cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
572cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
573cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
574cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
575cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
576cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
577cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
578cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
579cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
580cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
581cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
582cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
583cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
584cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
585cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
586cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
587cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
588cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
589ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy IvanovTEST(dlfcn, check_unload_after_reloc) {
590ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // This is how this one works:
591ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
592ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // |
593ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // +-> libtest_two_parents_child
594ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
595ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
596ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // |
597ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // +-> libtest_two_parents_child
598ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
599ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
600ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // as a second step it dlopens parent2 and dlcloses parent1...
601ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
602cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
603cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
604ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
605cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
606cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle2 != nullptr) << dlerror();
607ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
608cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  typedef int (*fn_t) (void);
609cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
610cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
611cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(42, fn());
612ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
613cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
614ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
615cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
616cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
617cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
618ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
619cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
620cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
621cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(42, fn());
622ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
623cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
624ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
625cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
626cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
627ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
628ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
629cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovextern "C" int check_order_reloc_root_get_answer_impl() {
630cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return 42;
631cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
632cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
633cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_main_executable) {
634cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
635cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer3 which is defined in 'root.so'
636cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external root_get_answer_impl() defined in _2.so and
637cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // above the correct _impl() is one in the executable.
638cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
639cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_root.so
640cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
641cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
642cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
643cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
644cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
645cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
646cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
647cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
648cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
649cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
650cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
651cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
652cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
653cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
654cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
655cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
656cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
657cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
658cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
659cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
660cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
661cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
662cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
663cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
664e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_local) {
665e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
666e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
667e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
668e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // implicit RTLD_LOCAL
669e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
670e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
671e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
672e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
673e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
674e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
675e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
676e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
677e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
678e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // explicit RTLD_LOCAL
679e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
680e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
681e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
682e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
683e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
684e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
685e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
686e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
687e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
688e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
689e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_global) {
690e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
691e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
692e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
693e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
6941b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
695e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
696e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
697e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
698e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
6991b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7001b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
7011b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
7021b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(sym, sym_after_dlclose);
703f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov
704f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // Check if dlsym() for main program's handle searches RTLD_GLOBAL
705f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // shared libraries after symbol was not found in the main executable
706f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // and dependent libraries.
707f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW);
708f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func");
709f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
710f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov
711f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  dlclose(handle_for_main_executable);
712e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
713e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
71414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
71514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
71614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_a.so
71714669a939d113214a4a20b9318fca0992d5453f0Dmitriy IvanovTEST(dlfcn, dlopen_check_loop) {
718cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
719cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
720cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* f = dlsym(handle, "dlopen_test_loopy_function");
721cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(f != nullptr) << dlerror();
722cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
723cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
724cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov
725cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  // dlopen second time to make sure that the library was unloaded correctly
726cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
727cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
728ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov#ifdef __BIONIC__
729cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
7309cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov#else
7319cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
7329cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  ASSERT_TRUE(dlerror() == nullptr);
733eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov#endif
734ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
735cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
736cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
73714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
73814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
7391b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete) {
7401b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
7411b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7421b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
7431b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
7441b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
7451b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
7461b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
7471b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
7481b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7491b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
7501b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
7511b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
7521b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
7531b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7541b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
7551b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
7561b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7571b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
7581b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
7591b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number_after_dlclose);
7601b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7611b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7621b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
7631b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
7641b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number2, taxicab_number);
7651b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7661b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number2);
7671b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7681b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
7691b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
7701b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
7711b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7721b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
7731b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
7741b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7751b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
7761b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
7771b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
7781b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
7791b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
7801b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
7811b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7821b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
7831b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
7841b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7851b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
7861b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
7871b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7881b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // This RTLD_NODELETE should be ignored
7891b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
7901b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle1 != nullptr) << dlerror();
7911b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(handle, handle1);
7921b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7931b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle1);
7941b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
7951b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7961b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(is_unloaded);
7971b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
7981b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7991b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_dt_flags_1) {
8001b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
8011b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
8021b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
8031b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
8041b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
8051b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
8061b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
8071b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
8081b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
8091b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
8101b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
8111b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
8121b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
813d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy IvanovTEST(dlfcn, dlsym_df_1_global) {
814d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
815d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
816d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  int (*get_answer)();
817d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
818d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(get_answer != nullptr) << dlerror();
819d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(42, get_answer());
820d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
821d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
822d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
823e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_failure) {
8243b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen("/does/not/exist", RTLD_NOW);
825aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(self == nullptr);
826063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
8273b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
8283b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
8293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
8303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
8313b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
8323b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
833109040c868230d2f37c2f3964c6b62f63ff30c6cdimitryTEST(dlfcn, dlclose_unload) {
834109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
835109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  ASSERT_TRUE(handle != nullptr) << dlerror();
836109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  uint32_t* taxicab_number = static_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
837109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
838109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  EXPECT_EQ(1729U, *taxicab_number);
839109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  dlclose(handle);
840109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  // Making sure that the library has been unmapped as part of library unload
841109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  // process. Note that mprotect somewhat counter-intuitively returns ENOMEM in
842109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  // this case.
843109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  uintptr_t page_start = reinterpret_cast<uintptr_t>(taxicab_number) & ~(PAGE_SIZE - 1);
844109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  ASSERT_TRUE(mprotect(reinterpret_cast<void*>(page_start), PAGE_SIZE, PROT_NONE) != 0);
845109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry  ASSERT_EQ(ENOMEM, errno) << strerror(errno);
846109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry}
847109040c868230d2f37c2f3964c6b62f63ff30c6cdimitry
848c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanovstatic void ConcurrentDlErrorFn(std::string& error) {
849c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(dlerror() == nullptr);
850c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
851c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  void* handle = dlopen("/child/thread", RTLD_NOW);
852c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
853c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
854c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  const char* err = dlerror();
855c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(err != nullptr);
856c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
857c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  error = err;
8585419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
8595419b9474753d25dff947c7740532f86d130c0beElliott Hughes
860c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry IvanovTEST(dlfcn, dlerror_concurrent_buffer) {
861c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  void* handle = dlopen("/main/thread", RTLD_NOW);
862c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
8635419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* main_thread_error = dlerror();
864c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(main_thread_error != nullptr);
8655419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
8665419b9474753d25dff947c7740532f86d130c0beElliott Hughes
867c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  std::string child_thread_error;
868c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  std::thread t(ConcurrentDlErrorFn, std::ref(child_thread_error));
869c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  t.join();
870c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_SUBSTR("/child/thread", child_thread_error.c_str());
8715419b9474753d25dff947c7740532f86d130c0beElliott Hughes
872c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  // Check that main thread local buffer was not modified.
873c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_SUBSTR("/main/thread", main_thread_error);
874c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov}
875c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
876c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry IvanovTEST(dlfcn, dlerror_concurrent) {
877c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  void* handle = dlopen("/main/thread", RTLD_NOW);
878c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
879c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
880c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  std::string child_thread_error;
881c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  std::thread t(ConcurrentDlErrorFn, std::ref(child_thread_error));
882c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  t.join();
883c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_SUBSTR("/child/thread", child_thread_error.c_str());
884c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
885c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  const char* main_thread_error = dlerror();
886c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(main_thread_error != nullptr);
8875419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
8885419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
8895419b9474753d25dff947c7740532f86d130c0beElliott Hughes
890e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_failures) {
8913b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
892aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  void* self = dlopen(nullptr, RTLD_NOW);
893aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(self != nullptr);
894aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr);
8953b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
8963b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* sym;
8973b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
89844adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov#if defined(__BIONIC__) && !defined(__LP64__)
89944adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // RTLD_DEFAULT in lp32 bionic is not (void*)0
90044adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // so it can be distinguished from the NULL handle.
901aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  sym = dlsym(nullptr, "test");
902aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
9034a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov  ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
9043b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
9053b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
9063b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Symbol that doesn't exist.
9073b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, "ThisSymbolDoesNotExist");
908aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
9093b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
9101a6961650c82168864afe040dbdc05977db701dfElliott Hughes
9111a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
9123b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
9133b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
914aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy IvanovTEST(dlfcn, dladdr_executable) {
9153b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
916aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  void* self = dlopen(nullptr, RTLD_NOW);
917aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(self != nullptr);
918aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr);
9198e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* sym = dlsym(self, "DlSymTestFunction");
921aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
9228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
9248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
9258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9268e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
9278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  int rc = dladdr(addr, &info);
9288e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
9298e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9308e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Get the name of this executable.
9312ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  const std::string& executable_path = get_executable_path();
9328e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9338e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The filename should be that of this executable.
934aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  char dli_realpath[PATH_MAX];
935aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(realpath(info.dli_fname, dli_realpath) != nullptr);
9362ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  ASSERT_STREQ(executable_path.c_str(), dli_realpath);
9378e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9388e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The symbol name should be the symbol we looked up.
9398e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
9408e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9418e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The address should be the exact address of the symbol.
9428e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_saddr, sym);
9438e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
944aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  std::vector<map_record> maps;
945aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(Maps::parse_maps(&maps));
946aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
947aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  void* base_address = nullptr;
948aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  for (const map_record& rec : maps) {
949aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    if (executable_path == rec.pathname) {
950aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      base_address = reinterpret_cast<void*>(rec.addr_start);
9518e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      break;
9528e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    }
9538e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  }
9548e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9558e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The base address should be the address we were loaded at.
9568e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_fbase, base_address);
9571a6961650c82168864afe040dbdc05977db701dfElliott Hughes
9581a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
9598e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
9608e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9612ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry IvanovTEST(dlfcn, dlopen_executable_by_absolute_path) {
9622ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  void* handle1 = dlopen(nullptr, RTLD_NOW);
9632ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  ASSERT_TRUE(handle1 != nullptr) << dlerror();
9642ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov
9652ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  void* handle2 = dlopen(get_executable_path().c_str(), RTLD_NOW);
9662ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  ASSERT_TRUE(handle2 != nullptr) << dlerror();
9672ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov
9682ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov#if defined(__BIONIC__)
9692ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  ASSERT_EQ(handle1, handle2);
9702ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov#else
9712ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  GTEST_LOG_(INFO) << "Skipping ASSERT_EQ(handle1, handle2) for glibc: "
9722ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov                      "it loads a separate copy of the main executable "
9732ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov                      "on dlopen by absolute path.";
9742ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov#endif
9752ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov}
9762ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov
97714b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#if defined (__aarch64__)
97814b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm64/"
97914b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#elif defined (__arm__)
98014b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm/"
98114b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#elif defined (__i386__)
98214b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86/"
98314b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#elif defined (__x86_64__)
98414b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86_64/"
98514b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#elif defined (__mips__)
98614b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#if defined(__LP64__)
98714b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips64/"
98814b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#else
98914b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips/"
99014b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#endif
99114b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#else
99214b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#error "Unknown architecture"
99314b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#endif
9946f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
99514b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "libc.so"
996aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
997aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy IvanovTEST(dlfcn, dladdr_libc) {
998aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#if defined(__BIONIC__)
999aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  Dl_info info;
1000aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  void* addr = reinterpret_cast<void*>(puts); // well-known libc function
1001aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(dladdr(addr, &info) != 0);
1002aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
1003ef25592f14d23ce6294ea103e9edf894779d141dDmitriy Ivanov  char libc_realpath[PATH_MAX];
100414b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko
100514b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  // Check if libc is in canonical path or in alternate path.
100614b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  if (strncmp(ALTERNATE_PATH_TO_SYSTEM_LIB,
100714b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko              info.dli_fname,
100814b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko              sizeof(ALTERNATE_PATH_TO_SYSTEM_LIB) - 1) == 0) {
100914b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    // Platform with emulated architecture.  Symlink on ARC++.
101014b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    ASSERT_TRUE(realpath(ALTERNATE_PATH_TO_LIBC, libc_realpath) == libc_realpath);
101114b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  } else {
101214b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    // /system/lib is symlink when this test is executed on host.
101314b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath);
101414b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  }
1015ef25592f14d23ce6294ea103e9edf894779d141dDmitriy Ivanov
1016ef25592f14d23ce6294ea103e9edf894779d141dDmitriy Ivanov  ASSERT_STREQ(libc_realpath, info.dli_fname);
1017aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  // TODO: add check for dfi_fbase
1018aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_STREQ("puts", info.dli_sname);
1019aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_EQ(addr, info.dli_saddr);
1020aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
1021aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing for glibc. Glibc returns path from ldconfig "
1022aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      "for libc.so, which is symlink itself (not a realpath).\n";
1023aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
1024aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov}
1025aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
1026e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr_invalid) {
10278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
10288e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
10293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
10303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
10318e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to NULL.
1032aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_EQ(dladdr(nullptr, &info), 0); // Zero on error, non-zero on success.
1033aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
10348e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
10358e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to a stack address.
10368e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
1037aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
10388e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
1039124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
1040a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// GNU-style ELF hash tables are incompatible with the MIPS ABI.
1041a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
1042e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_library_with_only_gnu_hash) {
1043ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#if !defined(__mips__)
1044124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  dlerror(); // Clear any pending errors.
1045ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
1046ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1047b8ab61804cec48e4ca585f4508fb1b7c6c5a04c5Tom Cherry  auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
1048ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
1049ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
1050ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  int (*fn)(void);
1051ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
1052ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  EXPECT_EQ(4, fn());
1053ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1054ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  Dl_info dlinfo;
1055ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
1056ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1057ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
1058ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
1059b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
1060ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#else
1061ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
1062a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#endif
1063ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1064e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
1065b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy IvanovTEST(dlfcn, dlopen_library_with_only_sysv_hash) {
1066b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
1067b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1068b8ab61804cec48e4ca585f4508fb1b7c6c5a04c5Tom Cherry  auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
1069b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
1070b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
1071b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  int (*fn)(void);
1072b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
1073b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  EXPECT_EQ(4, fn());
1074b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
1075b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  Dl_info dlinfo;
1076b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
1077b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
1078b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
1079b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
1080b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
1081b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov}
1082b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
108345a93c13bfa15e8621010570bb98aaee8c5803fcElliott HughesTEST(dlfcn, dlopen_library_with_ELF_TLS) {
108445a93c13bfa15e8621010570bb98aaee8c5803fcElliott Hughes  dlerror(); // Clear any pending errors.
108545a93c13bfa15e8621010570bb98aaee8c5803fcElliott Hughes  void* handle = dlopen("libelf-tls-library.so", RTLD_NOW);
108645a93c13bfa15e8621010570bb98aaee8c5803fcElliott Hughes  ASSERT_TRUE(handle == nullptr);
108745a93c13bfa15e8621010570bb98aaee8c5803fcElliott Hughes  ASSERT_SUBSTR("unsupported ELF TLS", dlerror());
108845a93c13bfa15e8621010570bb98aaee8c5803fcElliott Hughes}
108945a93c13bfa15e8621010570bb98aaee8c5803fcElliott Hughes
1090e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_bad_flags) {
1091e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  dlerror(); // Clear any pending errors.
1092e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  void* handle;
1093e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
1094063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__GLIBC__)
1095e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
1096aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  handle = dlopen(nullptr, 0);
1097aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
1098e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
1099e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes#endif
1100e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
1101aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  handle = dlopen(nullptr, 0xffffffff);
1102aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
1103e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
1104e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
1105e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
1106aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  handle = dlopen(nullptr, RTLD_NOW|RTLD_LAZY);
1107aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
1108aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_SUBSTR(nullptr, dlerror());
1109e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes}
1110ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
1111ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_unknown_symbol) {
11122ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
1113aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(addr == nullptr);
1114ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
1115ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
1116ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_known_symbol) {
11172ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "fopen");
1118aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(addr != nullptr);
11192ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
11202ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
11212ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_unknown_symbol) {
11222ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
1123aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(addr == nullptr);
11242ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
11252ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
11262ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_known_symbol) {
11272ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "fopen");
1128aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(addr != nullptr);
1129ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
11307db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov
1131d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov// Check that RTLD_NEXT of a libc symbol works in dlopened library
1132d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry IvanovTEST(dlfcn, rtld_next_from_library) {
1133153168c855962082d23b3124286005f90ccb39f8dimitry  void* library_with_fclose = dlopen("libtest_check_rtld_next_from_library.so", RTLD_NOW | RTLD_GLOBAL);
1134527229cb72121dbd09e40369f67d2cf636d3bf03Raj Mamadgi  ASSERT_TRUE(library_with_fclose != nullptr) << dlerror();
1135527229cb72121dbd09e40369f67d2cf636d3bf03Raj Mamadgi  void* expected_addr = dlsym(RTLD_DEFAULT, "fclose");
1136d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  ASSERT_TRUE(expected_addr != nullptr) << dlerror();
1137527229cb72121dbd09e40369f67d2cf636d3bf03Raj Mamadgi  typedef void* (*get_libc_fclose_ptr_fn_t)();
1138527229cb72121dbd09e40369f67d2cf636d3bf03Raj Mamadgi  get_libc_fclose_ptr_fn_t get_libc_fclose_ptr =
1139527229cb72121dbd09e40369f67d2cf636d3bf03Raj Mamadgi      reinterpret_cast<get_libc_fclose_ptr_fn_t>(dlsym(library_with_fclose, "get_libc_fclose_ptr"));
1140527229cb72121dbd09e40369f67d2cf636d3bf03Raj Mamadgi  ASSERT_TRUE(get_libc_fclose_ptr != nullptr) << dlerror();
1141527229cb72121dbd09e40369f67d2cf636d3bf03Raj Mamadgi  ASSERT_EQ(expected_addr, get_libc_fclose_ptr());
1142d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov
1143527229cb72121dbd09e40369f67d2cf636d3bf03Raj Mamadgi  dlclose(library_with_fclose);
1144d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov}
1145d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov
1146d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov
1147ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy IvanovTEST(dlfcn, dlsym_weak_func) {
1148ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlerror();
1149bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
1150aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
1151ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
1152ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  int (*weak_func)();
1153ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
1154aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(weak_func != nullptr) << "dlerror: " << dlerror();
1155ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  EXPECT_EQ(42, weak_func());
1156ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlclose(handle);
1157ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov}
1158ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
1159bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy IvanovTEST(dlfcn, dlopen_undefined_weak_func) {
1160cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
1161cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1162cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  int (*weak_func)();
1163cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
1164cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(weak_func != nullptr) << dlerror();
1165cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  EXPECT_EQ(6551, weak_func());
1166cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  dlclose(handle);
1167bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov}
1168bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov
11697db180919c335287b201e859faa8ee0dbe281cdeDmitriy IvanovTEST(dlfcn, dlopen_symlink) {
1170708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov  DlfcnSymlink symlink("dlopen_symlink");
1171708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov  const std::string symlink_name = basename(symlink.get_symlink_path().c_str());
11727db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
1173708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov  void* handle2 = dlopen(symlink_name.c_str(), RTLD_NOW);
1174aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle1 != nullptr);
1175aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle2 != nullptr);
11767db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_EQ(handle1, handle2);
1177319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle1);
1178319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle2);
11797db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov}
1180279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
1181279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// libtest_dlopen_from_ctor_main.so depends on
1182279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// libtest_dlopen_from_ctor.so which has a constructor
1183279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// that calls dlopen(libc...). This is to test the situation
1184279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// described in b/7941716.
1185279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy IvanovTEST(dlfcn, dlopen_dlopen_from_ctor) {
1186279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#if defined(__BIONIC__)
1187279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
1188279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1189279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  dlclose(handle);
1190279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#else
1191279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
1192279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#endif
1193279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov}
11942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1195ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanovstatic std::string g_fini_call_order_str;
1196ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov
1197ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanovstatic void register_fini_call(const char* s) {
1198ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  g_fini_call_order_str += s;
1199ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov}
1200ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov
1201ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanovstatic void test_init_fini_call_order_for(const char* libname) {
1202ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov  g_fini_call_order_str.clear();
1203ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov  void* handle = dlopen(libname, RTLD_NOW);
1204ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1205ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  typedef int (*get_init_order_number_t)();
1206ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  get_init_order_number_t get_init_order_number =
1207ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov          reinterpret_cast<get_init_order_number_t>(dlsym(handle, "get_init_order_number"));
1208ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  ASSERT_EQ(321, get_init_order_number());
1209ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov
1210ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  typedef void (*set_fini_callback_t)(void (*f)(const char*));
1211ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  set_fini_callback_t set_fini_callback =
1212ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov          reinterpret_cast<set_fini_callback_t>(dlsym(handle, "set_fini_callback"));
1213ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  set_fini_callback(register_fini_call);
1214ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  dlclose(handle);
1215ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  ASSERT_EQ("(root)(child)(grandchild)", g_fini_call_order_str);
1216ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov}
1217ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov
1218ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry IvanovTEST(dlfcn, init_fini_call_order) {
1219ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov  test_init_fini_call_order_for("libtest_init_fini_order_root.so");
1220ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov  test_init_fini_call_order_for("libtest_init_fini_order_root2.so");
1221ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov}
1222ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov
12232a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_use_v1) {
12242a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
12252a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12262a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
12272a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
12282a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
12292a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(1, fn());
12302a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
12312a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12332a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_use_v2) {
12342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_uselibv2.so", RTLD_NOW);
12352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
12372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
12382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
12392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(2, fn());
12402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
12412a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12422a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12432a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_use_other_v2) {
12442a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_uselibv2_other.so", RTLD_NOW);
12452a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12462a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
12472a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
12482a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
12492a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(20, fn());
12502a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
12512a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12522a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12532a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_use_other_v3) {
12542a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_uselibv3_other.so", RTLD_NOW);
12552a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12562a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
12572a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
12582a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
12592a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(3, fn());
12602a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
12612a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12622a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12632a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_default_via_dlsym) {
12642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
12652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
12672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "versioned_function"));
12682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
12692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(3, fn()); // the default version is 3
12702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
12712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12722a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12739cf99cbad89c8495828788ce693a99ced434f66fDimitry IvanovTEST(dlfcn, dlvsym_smoke) {
12749cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
12759cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12769cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  typedef int (*fn_t)();
12779cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov
12789cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  {
12799cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "nonversion"));
12809cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    ASSERT_TRUE(fn == nullptr);
12819cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    ASSERT_SUBSTR("undefined symbol: versioned_function, version nonversion", dlerror());
12829cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  }
12839cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov
12849cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  {
12859cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "TESTLIB_V2"));
12869cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    ASSERT_TRUE(fn != nullptr) << dlerror();
12879cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    ASSERT_EQ(2, fn());
12889cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  }
12899cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov
12909cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  dlclose(handle);
12919cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov}
12929cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov
12932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov// This preempts the implementation from libtest_versioned_lib.so
12942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovextern "C" int version_zero_function() {
12952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
12962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov// This preempts the implementation from libtest_versioned_uselibv*.so
12992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovextern "C" int version_zero_function2() {
13002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
13012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
13026865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov
13036f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar TrsicTEST(dlfcn, dt_runpath_smoke) {
13046865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW);
13056865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  ASSERT_TRUE(handle != nullptr) << dlerror();
13066865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov
13076865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  typedef void *(* dlopen_b_fn)();
13086865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
13096865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  ASSERT_TRUE(fn != nullptr) << dlerror();
13106865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov
13116865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  void *p = fn();
13120cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov  ASSERT_TRUE(p != nullptr);
13136865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov
13146865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  dlclose(handle);
13156865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov}
13166f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic
1317db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry IvanovTEST(dlfcn, dt_runpath_absolute_path) {
1318db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  std::string libpath = get_testlib_root() + "/libtest_dt_runpath_d.so";
1319db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1320db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1321db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov
1322db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  typedef void *(* dlopen_b_fn)();
1323db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
1324db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
1325db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov
1326db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  void *p = fn();
1327db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  ASSERT_TRUE(p != nullptr);
1328db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov
1329db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov  dlclose(handle);
1330db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov}
1331db6ab3d5ecfe9934cb91a09bc4ccdbf2d15b49fcDimitry Ivanov
133206016f226efe7aff2736643cb8e719c513948eccdimitryTEST(dlfcn, dlclose_after_thread_local_dtor) {
133306016f226efe7aff2736643cb8e719c513948eccdimitry  bool is_dtor_triggered = false;
133406016f226efe7aff2736643cb8e719c513948eccdimitry
133506016f226efe7aff2736643cb8e719c513948eccdimitry  auto f = [](void* handle, bool* is_dtor_triggered) {
133606016f226efe7aff2736643cb8e719c513948eccdimitry    typedef void (*fn_t)(bool*);
133706016f226efe7aff2736643cb8e719c513948eccdimitry    fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
133806016f226efe7aff2736643cb8e719c513948eccdimitry    ASSERT_TRUE(fn != nullptr) << dlerror();
133906016f226efe7aff2736643cb8e719c513948eccdimitry
134006016f226efe7aff2736643cb8e719c513948eccdimitry    fn(is_dtor_triggered);
134106016f226efe7aff2736643cb8e719c513948eccdimitry
134206016f226efe7aff2736643cb8e719c513948eccdimitry    ASSERT_TRUE(!*is_dtor_triggered);
134306016f226efe7aff2736643cb8e719c513948eccdimitry  };
134406016f226efe7aff2736643cb8e719c513948eccdimitry
134506016f226efe7aff2736643cb8e719c513948eccdimitry  void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
134606016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(handle == nullptr);
134706016f226efe7aff2736643cb8e719c513948eccdimitry
134806016f226efe7aff2736643cb8e719c513948eccdimitry  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
134906016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(handle != nullptr) << dlerror();
135006016f226efe7aff2736643cb8e719c513948eccdimitry
135106016f226efe7aff2736643cb8e719c513948eccdimitry  std::thread t(f, handle, &is_dtor_triggered);
135206016f226efe7aff2736643cb8e719c513948eccdimitry  t.join();
135306016f226efe7aff2736643cb8e719c513948eccdimitry
135406016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(is_dtor_triggered);
135506016f226efe7aff2736643cb8e719c513948eccdimitry  dlclose(handle);
135606016f226efe7aff2736643cb8e719c513948eccdimitry
135706016f226efe7aff2736643cb8e719c513948eccdimitry  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
135806016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(handle == nullptr);
135906016f226efe7aff2736643cb8e719c513948eccdimitry}
136006016f226efe7aff2736643cb8e719c513948eccdimitry
136106016f226efe7aff2736643cb8e719c513948eccdimitryTEST(dlfcn, dlclose_before_thread_local_dtor) {
136206016f226efe7aff2736643cb8e719c513948eccdimitry  bool is_dtor_triggered = false;
136306016f226efe7aff2736643cb8e719c513948eccdimitry
136406016f226efe7aff2736643cb8e719c513948eccdimitry  auto f = [](bool* is_dtor_triggered) {
136506016f226efe7aff2736643cb8e719c513948eccdimitry    void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
136606016f226efe7aff2736643cb8e719c513948eccdimitry    ASSERT_TRUE(handle == nullptr);
136706016f226efe7aff2736643cb8e719c513948eccdimitry
136806016f226efe7aff2736643cb8e719c513948eccdimitry    handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
136906016f226efe7aff2736643cb8e719c513948eccdimitry    ASSERT_TRUE(handle != nullptr) << dlerror();
137006016f226efe7aff2736643cb8e719c513948eccdimitry
137106016f226efe7aff2736643cb8e719c513948eccdimitry    typedef void (*fn_t)(bool*);
137206016f226efe7aff2736643cb8e719c513948eccdimitry    fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
137306016f226efe7aff2736643cb8e719c513948eccdimitry    ASSERT_TRUE(fn != nullptr) << dlerror();
137406016f226efe7aff2736643cb8e719c513948eccdimitry
137506016f226efe7aff2736643cb8e719c513948eccdimitry    fn(is_dtor_triggered);
137606016f226efe7aff2736643cb8e719c513948eccdimitry
137706016f226efe7aff2736643cb8e719c513948eccdimitry    dlclose(handle);
137806016f226efe7aff2736643cb8e719c513948eccdimitry
137906016f226efe7aff2736643cb8e719c513948eccdimitry    ASSERT_TRUE(!*is_dtor_triggered);
138006016f226efe7aff2736643cb8e719c513948eccdimitry
138106016f226efe7aff2736643cb8e719c513948eccdimitry    // Since we have thread_atexit dtors associated with handle - the library should
138206016f226efe7aff2736643cb8e719c513948eccdimitry    // still be availabe.
138306016f226efe7aff2736643cb8e719c513948eccdimitry    handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
138406016f226efe7aff2736643cb8e719c513948eccdimitry    ASSERT_TRUE(handle != nullptr) << dlerror();
138506016f226efe7aff2736643cb8e719c513948eccdimitry    dlclose(handle);
138606016f226efe7aff2736643cb8e719c513948eccdimitry  };
138706016f226efe7aff2736643cb8e719c513948eccdimitry
138806016f226efe7aff2736643cb8e719c513948eccdimitry  void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
138906016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(handle != nullptr) << dlerror();
139006016f226efe7aff2736643cb8e719c513948eccdimitry  dlclose(handle);
139106016f226efe7aff2736643cb8e719c513948eccdimitry
139206016f226efe7aff2736643cb8e719c513948eccdimitry  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
139306016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(handle == nullptr);
139406016f226efe7aff2736643cb8e719c513948eccdimitry
139506016f226efe7aff2736643cb8e719c513948eccdimitry  std::thread t(f, &is_dtor_triggered);
139606016f226efe7aff2736643cb8e719c513948eccdimitry  t.join();
139706016f226efe7aff2736643cb8e719c513948eccdimitry#if defined(__BIONIC__)
139806016f226efe7aff2736643cb8e719c513948eccdimitry  // ld-android.so unloads unreferenced libraries on pthread_exit()
139906016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(is_dtor_triggered);
140006016f226efe7aff2736643cb8e719c513948eccdimitry  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
140106016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(handle == nullptr);
140206016f226efe7aff2736643cb8e719c513948eccdimitry#else
140306016f226efe7aff2736643cb8e719c513948eccdimitry  // GLIBC does not unload libraries with ref_count = 0 on pthread_exit
140406016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(is_dtor_triggered);
140506016f226efe7aff2736643cb8e719c513948eccdimitry  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
140606016f226efe7aff2736643cb8e719c513948eccdimitry  ASSERT_TRUE(handle != nullptr) << dlerror();
140706016f226efe7aff2736643cb8e719c513948eccdimitry#endif
140806016f226efe7aff2736643cb8e719c513948eccdimitry}
140906016f226efe7aff2736643cb8e719c513948eccdimitry
14108ad40936597c94901b6acb0b21bfe0e2a0689224Elliott HughesTEST(dlfcn, RTLD_macros) {
14118ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#if !defined(RTLD_LOCAL)
14128ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#error no RTLD_LOCAL
14138ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#elif !defined(RTLD_LAZY)
14148ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#error no RTLD_LAZY
14158ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#elif !defined(RTLD_NOW)
14168ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#error no RTLD_NOW
14178ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#elif !defined(RTLD_NOLOAD)
14188ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#error no RTLD_NOLOAD
14198ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#elif !defined(RTLD_GLOBAL)
14208ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#error no RTLD_GLOBAL
14218ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#elif !defined(RTLD_NODELETE)
14228ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#error no RTLD_NODELETE
14238ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes#endif
14248ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes}
14258ad40936597c94901b6acb0b21bfe0e2a0689224Elliott Hughes
1426a36e59bb9973aaae2e3487e0bfadd1f79814097eDimitry Ivanov// Bionic specific tests
1427a36e59bb9973aaae2e3487e0bfadd1f79814097eDimitry Ivanov#if defined(__BIONIC__)
1428a36e59bb9973aaae2e3487e0bfadd1f79814097eDimitry Ivanov
1429b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz#if defined(__arm__)
1430b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitzconst llvm::ELF::Elf32_Dyn* to_dynamic_table(const char* p) {
1431b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  return reinterpret_cast<const llvm::ELF::Elf32_Dyn*>(p);
1432b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz}
1433b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1434b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz// Duplicate these definitions here because they are android specific
1435b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz// note that we cannot include <elf.h> because #defines conflict with
1436b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz// enum names provided by LLVM.
1437b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz#define DT_ANDROID_REL (llvm::ELF::DT_LOOS + 2)
1438b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz#define DT_ANDROID_RELA (llvm::ELF::DT_LOOS + 4)
1439b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1440b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitztemplate<typename ELFT>
14419dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichardvoid validate_compatibility_of_native_library(const std::string& soname,
14429dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichard                                              const std::string& path, ELFT* elf) {
1443b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  bool has_elf_hash = false;
1444b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  bool has_android_rel = false;
1445b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  bool has_rel = false;
1446b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  // Find dynamic section and check that DT_HASH and there is no DT_ANDROID_REL
1447b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
1448b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz    const llvm::object::ELFSectionRef& section_ref = *it;
1449b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz    if (section_ref.getType() == llvm::ELF::SHT_DYNAMIC) {
1450b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz      llvm::StringRef data;
1451b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz      ASSERT_TRUE(!it->getContents(data)) << "unable to get SHT_DYNAMIC section data";
1452b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz      for (auto d = to_dynamic_table(data.data()); d->d_tag != llvm::ELF::DT_NULL; ++d) {
1453b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz        if (d->d_tag == llvm::ELF::DT_HASH) {
1454b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz          has_elf_hash = true;
1455b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz        } else if (d->d_tag == DT_ANDROID_REL || d->d_tag == DT_ANDROID_RELA) {
1456b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz          has_android_rel = true;
1457b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz        } else if (d->d_tag == llvm::ELF::DT_REL || d->d_tag == llvm::ELF::DT_RELA) {
1458b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz          has_rel = true;
1459b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz        }
1460b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz      }
1461b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1462b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz      break;
1463b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz    }
1464b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  }
1465b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1466b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  ASSERT_TRUE(has_elf_hash) << path.c_str() << ": missing elf hash (DT_HASH)";
1467b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  ASSERT_TRUE(!has_android_rel) << path.c_str() << ": has packed relocations";
14689dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichard  // libdl.so is simple enough that it might not have any relocations, so
14699dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichard  // exempt it from the DT_REL/DT_RELA check.
14709dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichard  if (soname != "libdl.so") {
14719dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichard    ASSERT_TRUE(has_rel) << path.c_str() << ": missing DT_REL/DT_RELA";
14729dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichard  }
1473b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz}
1474b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
14759dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichardvoid validate_compatibility_of_native_library(const std::string& soname) {
1476b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  // On the systems with emulation system libraries would be of different
1477b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  // architecture.  Try to use alternate paths first.
1478b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  std::string path = std::string(ALTERNATE_PATH_TO_SYSTEM_LIB) + soname;
1479b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  auto binary_or_error = llvm::object::createBinary(path);
1480b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  if (!binary_or_error) {
1481b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz    path = std::string(PATH_TO_SYSTEM_LIB) + soname;
1482b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz    binary_or_error = llvm::object::createBinary(path);
1483b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  }
1484b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  ASSERT_FALSE(!binary_or_error);
1485b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1486b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  llvm::object::Binary* binary = binary_or_error.get().getBinary();
1487b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1488b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
1489b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  ASSERT_TRUE(obj != nullptr);
1490b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1491b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj);
1492b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1493b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  ASSERT_TRUE(elf != nullptr);
1494b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
14959dac3e9efdf6b00766b992940c831ca3881b48d5Ryan Prichard  validate_compatibility_of_native_library(soname, path, elf);
1496b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz}
1497b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1498b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz// This is a test for app compatibility workaround for arm apps
1499b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz// affected by http://b/24465209
1500b6310c2aa704bd30990f4e3152e494b5290972b2Ian PedowitzTEST(dlext, compat_elf_hash_and_relocation_tables) {
1501b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  validate_compatibility_of_native_library("libc.so");
1502b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  validate_compatibility_of_native_library("liblog.so");
1503b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  validate_compatibility_of_native_library("libstdc++.so");
1504b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  validate_compatibility_of_native_library("libdl.so");
1505b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  validate_compatibility_of_native_library("libm.so");
1506b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  validate_compatibility_of_native_library("libz.so");
1507b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz  validate_compatibility_of_native_library("libjnigraphics.so");
1508b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz}
1509b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
1510b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz#endif //  defined(__arm__)
1511b6310c2aa704bd30990f4e3152e494b5290972b2Ian Pedowitz
15129700babc051f5839b4fc861587d63bf06bab6324Dimitry IvanovTEST(dlfcn, dlopen_invalid_rw_load_segment) {
1513d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1514927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1515927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-rw_load_segment.so";
15169700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
15179700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
15189076b0c4e78e8680ce40ce48321e8ab81a87705bElliott Hughes  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W+E load segments are not allowed";
15199700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
15209700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov}
1521972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov
1522972e3d0787cf177450cdc1b52e177c747b94cabaDimitry IvanovTEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) {
1523d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1524927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1525927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-unaligned_shdr_offset.so";
1526927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
1527972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1528972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1529972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: ";
1530972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1531972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov}
1532972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov
1533cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry IvanovTEST(dlfcn, dlopen_invalid_zero_shentsize) {
1534d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1535927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1536927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-zero_shentsize.so";
1537927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
1538cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1539cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1540cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has unsupported e_shentsize: 0x0 (expected 0x";
1541cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1542cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov}
1543cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov
1544c9a95613a95b1a275ff897594abb89786ae387edDimitry IvanovTEST(dlfcn, dlopen_invalid_zero_shstrndx) {
1545d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1546927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1547927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-zero_shstrndx.so";
1548927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
1549c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1550c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1551c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid e_shstrndx";
1552c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
1553c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov}
1554c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov
15558bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry IvanovTEST(dlfcn, dlopen_invalid_empty_shdr_table) {
1556d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1557927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1558927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-empty_shdr_table.so";
1559927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
15608bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
15618bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
15628bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has no section headers";
15638bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
15648bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov}
15658bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov
156646230445172d3cd72c38102d57f5a1b725c80367Dimitry IvanovTEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) {
1567d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1568927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1569927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-zero_shdr_table_offset.so";
1570927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
157146230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
157246230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
157346230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: 0/";
157446230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
157546230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov}
157646230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov
1577559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry IvanovTEST(dlfcn, dlopen_invalid_zero_shdr_table_content) {
1578d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1579927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1580927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-zero_shdr_table_content.so";
1581927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
1582559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1583559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1584559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" .dynamic section header was not found";
1585559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1586559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov}
1587559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov
1588816676e70da0e00761b0d23f512ea3571211b3aeDimitry IvanovTEST(dlfcn, dlopen_invalid_textrels) {
1589d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1590816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov                              "/" + kPrebuiltElfDir +
1591816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov                              "/libtest_invalid-textrels.so";
1592816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov
1593816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1594816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1595816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has text relocations";
1596816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1597816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov}
1598816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov
1599816676e70da0e00761b0d23f512ea3571211b3aeDimitry IvanovTEST(dlfcn, dlopen_invalid_textrels2) {
1600d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1601816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov                              "/" + kPrebuiltElfDir +
1602816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov                              "/libtest_invalid-textrels2.so";
1603816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov
1604816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1605816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1606816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has text relocations";
1607816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1608816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov}
1609816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov
161001162f24696aedd0f80fde006596bec7786ac684Jiyong ParkTEST(dlfcn, dlopen_df_1_global) {
161101162f24696aedd0f80fde006596bec7786ac684Jiyong Park  void* handle = dlopen("libtest_dlopen_df_1_global.so", RTLD_NOW);
161201162f24696aedd0f80fde006596bec7786ac684Jiyong Park  ASSERT_TRUE(handle != nullptr) << dlerror();
161301162f24696aedd0f80fde006596bec7786ac684Jiyong Park}
161401162f24696aedd0f80fde006596bec7786ac684Jiyong Park
16159700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov#endif
1616