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
258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <string>
26acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
273b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ASSERT_SUBSTR(needle, haystack) \
283b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
301728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic bool g_called = false;
31acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() {
321728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = true;
33acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
34acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
35f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovstatic int g_ctor_function_called = 0;
36f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
37f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() __attribute__ ((constructor));
38f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
39f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() {
40f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  g_ctor_function_called = 17;
41f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
42f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
43f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy IvanovTEST(dlfcn, ctor_function_call) {
44f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  ASSERT_EQ(17, g_ctor_function_called);
45f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
46f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
47e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_in_self) {
483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
49acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* self = dlopen(NULL, RTLD_NOW);
50acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(self != NULL);
513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
52acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
53acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* sym = dlsym(self, "DlSymTestFunction");
54acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(sym != NULL);
55acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
56acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void (*function)() = reinterpret_cast<void(*)()>(sym);
57acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
581728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = false;
59acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  function();
601728b2396591853345507a063ed6075dfd251706Elliott Hughes  ASSERT_TRUE(g_called);
611a6961650c82168864afe040dbdc05977db701dfElliott Hughes
621a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
63acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
648e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
65db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy IvanovTEST(dlfcn, dlsym_with_dependencies) {
66db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
67db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
68db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  dlerror();
69db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  // This symbol is in DT_NEEDED library.
70db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
71db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  ASSERT_TRUE(sym != NULL);
72db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  int (*fn)(void);
73db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
74db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  EXPECT_EQ(4, fn());
75db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov  dlclose(handle);
76db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov}
77db7a17d4ff56a05af01ee2fee1f3c55245bfc630Dmitriy Ivanov
78b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy IvanovTEST(dlfcn, dlopen_noload) {
79b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
80b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == NULL);
81b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW);
82b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
83b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle != NULL);
84b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
85b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == handle2);
86b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
87b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
88b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov}
89b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
90e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_failure) {
913b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen("/does/not/exist", RTLD_NOW);
923b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self == NULL);
93063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
943b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
953b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
963b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
973b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
983b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
993b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
100ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughesstatic void* ConcurrentDlErrorFn(void*) {
1015419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/child/thread", RTLD_NOW);
1025419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return reinterpret_cast<void*>(strdup(dlerror()));
1035419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
1045419b9474753d25dff947c7740532f86d130c0beElliott Hughes
105e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlerror_concurrent) {
1065419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/main/thread", RTLD_NOW);
1075419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* main_thread_error = dlerror();
1085419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
1095419b9474753d25dff947c7740532f86d130c0beElliott Hughes
1105419b9474753d25dff947c7740532f86d130c0beElliott Hughes  pthread_t t;
1115419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
1125419b9474753d25dff947c7740532f86d130c0beElliott Hughes  void* result;
1135419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_join(t, &result));
1145419b9474753d25dff947c7740532f86d130c0beElliott Hughes  char* child_thread_error = static_cast<char*>(result);
1155419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/child/thread", child_thread_error);
1165419b9474753d25dff947c7740532f86d130c0beElliott Hughes  free(child_thread_error);
1175419b9474753d25dff947c7740532f86d130c0beElliott Hughes
1185419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
1195419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
1205419b9474753d25dff947c7740532f86d130c0beElliott Hughes
121e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_failures) {
1223b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
1233b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
1243b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self != NULL);
1253b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
1263b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1273b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* sym;
1283b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
12944adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov#if defined(__BIONIC__) && !defined(__LP64__)
13044adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // RTLD_DEFAULT in lp32 bionic is not (void*)0
13144adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // so it can be distinguished from the NULL handle.
1323b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(NULL, "test");
1333b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
1343b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
1353b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
1363b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1373b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // NULL symbol name.
138063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
1393b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // glibc marks this parameter non-null and SEGVs if you cheat.
1403b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, NULL);
1413b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
1423b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("", dlerror());
1433b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
1443b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
1453b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Symbol that doesn't exist.
1463b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, "ThisSymbolDoesNotExist");
1473b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
1483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
1491a6961650c82168864afe040dbdc05977db701dfElliott Hughes
1501a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
1513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
1523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
153e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr) {
1543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
1558e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
1568e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(self != NULL);
1573b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
1588e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1598e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* sym = dlsym(self, "DlSymTestFunction");
1608e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(sym != NULL);
1618e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1628e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
1638e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
1648e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1658e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
1668e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  int rc = dladdr(addr, &info);
1678e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
1688e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1698e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Get the name of this executable.
1708e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char executable_path[PATH_MAX];
1718e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
1728e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, -1);
1738e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  executable_path[rc] = '\0';
1748e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string executable_name(basename(executable_path));
1758e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1768e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The filename should be that of this executable.
1778e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
1788e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string dli_fname(info.dli_fname);
1798e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  dli_fname = basename(&dli_fname[0]);
1808e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dli_fname, executable_name);
1818e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1828e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The symbol name should be the symbol we looked up.
1838e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
1848e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1858e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The address should be the exact address of the symbol.
1868e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_saddr, sym);
1878e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
1888e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Look in /proc/pid/maps to find out what address we were loaded at.
1898e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
1908e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* base_address = NULL;
1918e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char line[BUFSIZ];
192642182341018b282148280a7bdb771493e15bd7dElliott Hughes  FILE* fp = fopen("/proc/self/maps", "r");
1938e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(fp != NULL);
1948e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  while (fgets(line, sizeof(line), fp) != NULL) {
1958e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    uintptr_t start = strtoul(line, 0, 16);
1968e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
1978e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    char* path = strchr(line, '/');
198156da966214957c5616a0b83cc84686eedfc4e31Elliott Hughes    if (path != NULL && strcmp(executable_path, path) == 0) {
1998e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      base_address = reinterpret_cast<void*>(start);
2008e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      break;
2018e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    }
2028e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  }
2038e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  fclose(fp);
2048e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
2058e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The base address should be the address we were loaded at.
2068e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_fbase, base_address);
2071a6961650c82168864afe040dbdc05977db701dfElliott Hughes
2081a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
2098e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
2108e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
211e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr_invalid) {
2128e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
2138e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
2143b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
2153b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
2168e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to NULL.
2178e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
2183b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
2198e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
2208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to a stack address.
2218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
2223b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
2238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
224124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
225124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes// Our dynamic linker doesn't support GNU hash tables.
226a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#if defined(__BIONIC__)
227a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// GNU-style ELF hash tables are incompatible with the MIPS ABI.
228a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
229a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#if !defined(__mips__)
230e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_library_with_only_gnu_hash) {
231124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  dlerror(); // Clear any pending errors.
2326e33b0296d23c75bdefa53f0bf0b08c0d877a652Elliott Hughes  void* handle = dlopen("no-elf-hash-table-library.so", RTLD_NOW);
233124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  ASSERT_TRUE(handle == NULL);
2346e33b0296d23c75bdefa53f0bf0b08c0d877a652Elliott Hughes  ASSERT_STREQ("dlopen failed: empty/missing DT_HASH in \"no-elf-hash-table-library.so\" (built with --hash-style=gnu?)", dlerror());
235124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes}
236124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes#endif
237a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#endif
238e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
239e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_bad_flags) {
240e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  dlerror(); // Clear any pending errors.
241e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  void* handle;
242e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
243063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__GLIBC__)
244e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
245e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0);
246e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
247e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
248e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes#endif
249e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
250e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0xffffffff);
251e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
252e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
253e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
254e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
255e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
256e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle != NULL);
257e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR(NULL, dlerror());
258e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes}
259ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
260ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_unknown_symbol) {
2612ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
262ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr == NULL);
263ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
264ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
265ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_known_symbol) {
2662ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "fopen");
2672ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr != NULL);
2682ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
2692ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
2702ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_unknown_symbol) {
2712ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
2722ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr == NULL);
2732ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
2742ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
2752ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_known_symbol) {
2762ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "fopen");
277ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr != NULL);
278ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
2797db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov
280ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy IvanovTEST(dlfcn, dlsym_weak_func) {
281ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlerror();
282ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_weak_func.so",RTLD_NOW);
283ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
284ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
285ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  int (*weak_func)();
286ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
287ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
288ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  EXPECT_EQ(42, weak_func());
289ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlclose(handle);
290ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov}
291ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
2927db180919c335287b201e859faa8ee0dbe281cdeDmitriy IvanovTEST(dlfcn, dlopen_symlink) {
2937db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
2947db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
2957db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle1 != NULL);
2967db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
2977db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_EQ(handle1, handle2);
2987db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov}
299