dlfcn_test.cpp revision 14669a939d113214a4a20b9318fca0992d5453f0
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 <libgen.h>
218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <limits.h>
228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdio.h>
238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdint.h>
248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
25b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov#include "private/ScopeGuard.h"
26b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <string>
28acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ASSERT_SUBSTR(needle, haystack) \
303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
313b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
321728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic bool g_called = false;
33acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() {
341728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = true;
35acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
36acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
37f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovstatic int g_ctor_function_called = 0;
38f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
39f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() __attribute__ ((constructor));
40f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
41f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() {
42f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  g_ctor_function_called = 17;
43f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
44f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
45f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy IvanovTEST(dlfcn, ctor_function_call) {
46f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  ASSERT_EQ(17, g_ctor_function_called);
47f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
48f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
49e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_in_self) {
503b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
51acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* self = dlopen(NULL, RTLD_NOW);
52acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(self != NULL);
533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
54acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
55acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* sym = dlsym(self, "DlSymTestFunction");
56acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(sym != NULL);
57acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
58acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void (*function)() = reinterpret_cast<void(*)()>(sym);
59acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
601728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = false;
61acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  function();
621728b2396591853345507a063ed6075dfd251706Elliott Hughes  ASSERT_TRUE(g_called);
631a6961650c82168864afe040dbdc05977db701dfElliott Hughes
641a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
65acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
668e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
67aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy IvanovTEST(dlfcn, dlsym_with_dependencies) {
68aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
69aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
70aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlerror();
71aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  // This symbol is in DT_NEEDED library.
72aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
73aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  ASSERT_TRUE(sym != NULL);
74aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  int (*fn)(void);
75aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
76aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  EXPECT_EQ(4, fn());
77aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlclose(handle);
78aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}
79aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
80b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy IvanovTEST(dlfcn, dlopen_noload) {
81b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
82b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == NULL);
83b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW);
84b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
85b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle != NULL);
86b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
87b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == handle2);
88b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
89b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
90b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov}
91b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
92c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith// ifuncs are only supported on intel for now
93c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith#if defined(__i386__) || defined(__x86_64__)
94c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid SmithTEST(dlfcn, ifunc) {
959598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
96c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
97c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // ifunc's choice depends on whether IFUNC_CHOICE has a value
98c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // first check the set case
99c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  setenv("IFUNC_CHOICE", "set", 1);
100c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
101c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(handle != NULL);
1029598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
1039598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
104c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_ptr != NULL);
105c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_library_ptr != NULL);
1069598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
1079598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
108c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
109c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
110c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // then check the unset case
111c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  unsetenv("IFUNC_CHOICE");
112c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
113c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(handle != NULL);
1149598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
1159598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
116c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_ptr != NULL);
117c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_library_ptr != NULL);
1189598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
1199598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
1209598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  dlclose(handle);
1219598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov}
1229598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
1239598b8c415e2fa9f240508185fe8c964b83f538dDmitriy IvanovTEST(dlfcn, ifunc_ctor_call) {
1249598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
1259598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
1269598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
1279598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_TRUE(handle != NULL) << dlerror();
1289598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called"));
1299598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != NULL) << dlerror();
1309598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_STREQ("true", is_ctor_called());
131c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
132c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
133c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith#endif
134c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
135b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy IvanovTEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
136b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // This is the structure of the test library and
137b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // its dt_needed libraries
138b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // libtest_relo_check_dt_needed_order.so
139b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
140b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_1.so
141b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
142b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_2.so
143b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  //
144b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // The root library references relo_test_get_answer_lib - which is defined
145b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // in both dt_needed libraries, the correct relocation should
146b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // use the function defined in libtest_relo_check_dt_needed_order_1.so
147b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  void* handle = nullptr;
148b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  auto guard = create_scope_guard([&]() {
149b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov    dlclose(handle);
150b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  });
151b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
152b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
153b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
154b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
155b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  typedef int (*fn_t) (void);
156b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
157b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
158b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_EQ(1, fn());
159b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov}
160b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
16114669a939d113214a4a20b9318fca0992d5453f0Dmitriy IvanovTEST(dlfcn, dlopen_check_order) {
16214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Here is how the test library and its dt_needed
16314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // libraries are arranged
16414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
16514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  libtest_check_order.so
16614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
16714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  +-> libtest_check_order_1_left.so
16814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
16914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   +-> libtest_check_order_a.so
17014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
17114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   +-> libtest_check_order_b.so
17214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
17314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  +-> libtest_check_order_2_right.so
17414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
17514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   +-> libtest_check_order_d.so
17614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |       |
17714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |       +-> libtest_check_order_b.so
17814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
17914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  +-> libtest_check_order_3_c.so
18014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
18114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  load order should be (1, 2, 3, a, b, d)
18214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
18314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer() is defined in (2, 3, a, b, c)
18414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer2() is defined in (b, d)
18514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer");
18614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
18714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  void* handle = dlopen("libtest_check_order.so", RTLD_NOW);
18814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
18914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef int (*fn_t) (void);
19014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  fn_t fn, fn2;
19114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"));
19214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(fn != NULL);
19314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2"));
19414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(fn2 != NULL);
19514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
19614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(42, fn());
19714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(43, fn2());
19814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  dlclose(handle);
19914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
20014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
20114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
20214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
20314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_a.so
20414669a939d113214a4a20b9318fca0992d5453f0Dmitriy IvanovTEST(dlfcn, dlopen_check_loop) {
20514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
20614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(handle == NULL);
20714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror());
20814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
20914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
210e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_failure) {
2113b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen("/does/not/exist", RTLD_NOW);
2123b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self == NULL);
213063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
2143b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
2153b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
2163b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
2173b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
2183b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
2193b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
220ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughesstatic void* ConcurrentDlErrorFn(void*) {
2215419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/child/thread", RTLD_NOW);
2225419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return reinterpret_cast<void*>(strdup(dlerror()));
2235419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
2245419b9474753d25dff947c7740532f86d130c0beElliott Hughes
225e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlerror_concurrent) {
2265419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/main/thread", RTLD_NOW);
2275419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* main_thread_error = dlerror();
2285419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
2295419b9474753d25dff947c7740532f86d130c0beElliott Hughes
2305419b9474753d25dff947c7740532f86d130c0beElliott Hughes  pthread_t t;
2315419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
2325419b9474753d25dff947c7740532f86d130c0beElliott Hughes  void* result;
2335419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_join(t, &result));
2345419b9474753d25dff947c7740532f86d130c0beElliott Hughes  char* child_thread_error = static_cast<char*>(result);
2355419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/child/thread", child_thread_error);
2365419b9474753d25dff947c7740532f86d130c0beElliott Hughes  free(child_thread_error);
2375419b9474753d25dff947c7740532f86d130c0beElliott Hughes
2385419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
2395419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
2405419b9474753d25dff947c7740532f86d130c0beElliott Hughes
241e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_failures) {
2423b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
2433b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
2443b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self != NULL);
2453b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
2463b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
2473b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* sym;
2483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
24944adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov#if defined(__BIONIC__) && !defined(__LP64__)
25044adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // RTLD_DEFAULT in lp32 bionic is not (void*)0
25144adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // so it can be distinguished from the NULL handle.
2523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(NULL, "test");
2533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
2543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
2553b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
2563b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
2573b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // NULL symbol name.
258063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
2593b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // glibc marks this parameter non-null and SEGVs if you cheat.
2603b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, NULL);
2613b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
2623b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("", dlerror());
2633b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
2643b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
2653b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Symbol that doesn't exist.
2663b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, "ThisSymbolDoesNotExist");
2673b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
2683b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
2691a6961650c82168864afe040dbdc05977db701dfElliott Hughes
2701a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
2713b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
2723b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
273e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr) {
2743b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
2758e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
2768e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(self != NULL);
2773b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
2788e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
2798e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* sym = dlsym(self, "DlSymTestFunction");
2808e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(sym != NULL);
2818e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
2828e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
2838e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
2848e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
2858e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
2868e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  int rc = dladdr(addr, &info);
2878e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
2888e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
2898e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Get the name of this executable.
2908e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char executable_path[PATH_MAX];
2918e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
2928e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, -1);
2938e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  executable_path[rc] = '\0';
2948e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string executable_name(basename(executable_path));
2958e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
2968e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The filename should be that of this executable.
2978e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
2988e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string dli_fname(info.dli_fname);
2998e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  dli_fname = basename(&dli_fname[0]);
3008e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dli_fname, executable_name);
3018e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
3028e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The symbol name should be the symbol we looked up.
3038e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
3048e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
3058e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The address should be the exact address of the symbol.
3068e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_saddr, sym);
3078e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
3088e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Look in /proc/pid/maps to find out what address we were loaded at.
3098e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
3108e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* base_address = NULL;
3118e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char line[BUFSIZ];
31257b7a6110e7e8b446fc23cce4765ff625ee0a105Elliott Hughes  FILE* fp = fopen("/proc/self/maps", "r");
3138e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(fp != NULL);
3148e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  while (fgets(line, sizeof(line), fp) != NULL) {
3158e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    uintptr_t start = strtoul(line, 0, 16);
3168e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
3178e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    char* path = strchr(line, '/');
318156da966214957c5616a0b83cc84686eedfc4e31Elliott Hughes    if (path != NULL && strcmp(executable_path, path) == 0) {
3198e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      base_address = reinterpret_cast<void*>(start);
3208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      break;
3218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    }
3228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  }
3238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  fclose(fp);
3248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
3258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The base address should be the address we were loaded at.
3268e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_fbase, base_address);
3271a6961650c82168864afe040dbdc05977db701dfElliott Hughes
3281a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
3298e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
3308e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
331e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr_invalid) {
3328e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
3338e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
3343b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
3353b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
3368e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to NULL.
3378e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
3383b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
3398e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
3408e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to a stack address.
3418e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
3423b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
3438e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
344124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
345124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes// Our dynamic linker doesn't support GNU hash tables.
346a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#if defined(__BIONIC__)
347a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// GNU-style ELF hash tables are incompatible with the MIPS ABI.
348a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
349a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#if !defined(__mips__)
350e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_library_with_only_gnu_hash) {
351124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  dlerror(); // Clear any pending errors.
3526e33b0296d23c75bdefa53f0bf0b08c0d877a652Elliott Hughes  void* handle = dlopen("no-elf-hash-table-library.so", RTLD_NOW);
353124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  ASSERT_TRUE(handle == NULL);
3546e33b0296d23c75bdefa53f0bf0b08c0d877a652Elliott Hughes  ASSERT_STREQ("dlopen failed: empty/missing DT_HASH in \"no-elf-hash-table-library.so\" (built with --hash-style=gnu?)", dlerror());
355124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes}
356124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes#endif
357a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#endif
358e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
359e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_bad_flags) {
360e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  dlerror(); // Clear any pending errors.
361e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  void* handle;
362e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
363063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__GLIBC__)
364e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
365e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0);
366e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
367e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
368e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes#endif
369e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
370e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0xffffffff);
371e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
372e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
373e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
374e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
375e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
376e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle != NULL);
377e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR(NULL, dlerror());
378e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes}
379ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
380ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_unknown_symbol) {
3812ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
382ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr == NULL);
383ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
384ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
385ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_known_symbol) {
3862ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "fopen");
3872ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr != NULL);
3882ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
3892ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
3902ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_unknown_symbol) {
3912ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
3922ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr == NULL);
3932ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
3942ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
3952ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_known_symbol) {
3962ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "fopen");
397ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr != NULL);
398ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
3997db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov
400ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy IvanovTEST(dlfcn, dlsym_weak_func) {
401ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlerror();
402ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_weak_func.so",RTLD_NOW);
403ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
404ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
405ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  int (*weak_func)();
406ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
407ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
408ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  EXPECT_EQ(42, weak_func());
409ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlclose(handle);
410ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov}
411ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
4127db180919c335287b201e859faa8ee0dbe281cdeDmitriy IvanovTEST(dlfcn, dlopen_symlink) {
4137db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
4147db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
4157db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle1 != NULL);
4167db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
4177db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_EQ(handle1, handle2);
418319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle1);
419319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle2);
4207db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov}
421