dlfcn_test.cpp revision 5419b9474753d25dff947c7740532f86d130c0be
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 30acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaostatic bool gCalled = false; 31acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() { 32acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao gCalled = true; 33acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao} 34acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 35acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoTEST(dlopen, dlsym_in_self) { 363b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes dlerror(); // Clear any pending errors. 37acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao void* self = dlopen(NULL, RTLD_NOW); 38acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao ASSERT_TRUE(self != NULL); 393b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(dlerror() == NULL); 40acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 41acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao void* sym = dlsym(self, "DlSymTestFunction"); 42acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao ASSERT_TRUE(sym != NULL); 43acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 44acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao void (*function)() = reinterpret_cast<void(*)()>(sym); 45acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao 46acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao gCalled = false; 47acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao function(); 48acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao ASSERT_TRUE(gCalled); 49acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao} 508e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott HughesTEST(dlopen, dlopen_failure) { 523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes void* self = dlopen("/does/not/exist", RTLD_NOW); 533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(self == NULL); 543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#if __BIONIC__ 553b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror()); 563b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else 573b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror()); 583b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif 593b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes} 603b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes 615419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic void* ConcurrentDlErrorFn(void* arg) { 625419b9474753d25dff947c7740532f86d130c0beElliott Hughes dlopen("/child/thread", RTLD_NOW); 635419b9474753d25dff947c7740532f86d130c0beElliott Hughes return reinterpret_cast<void*>(strdup(dlerror())); 645419b9474753d25dff947c7740532f86d130c0beElliott Hughes} 655419b9474753d25dff947c7740532f86d130c0beElliott Hughes 665419b9474753d25dff947c7740532f86d130c0beElliott HughesTEST(dlopen, dlerror_concurrent) { 675419b9474753d25dff947c7740532f86d130c0beElliott Hughes dlopen("/main/thread", RTLD_NOW); 685419b9474753d25dff947c7740532f86d130c0beElliott Hughes const char* main_thread_error = dlerror(); 695419b9474753d25dff947c7740532f86d130c0beElliott Hughes ASSERT_SUBSTR("/main/thread", main_thread_error); 705419b9474753d25dff947c7740532f86d130c0beElliott Hughes 715419b9474753d25dff947c7740532f86d130c0beElliott Hughes pthread_t t; 725419b9474753d25dff947c7740532f86d130c0beElliott Hughes ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL)); 735419b9474753d25dff947c7740532f86d130c0beElliott Hughes void* result; 745419b9474753d25dff947c7740532f86d130c0beElliott Hughes ASSERT_EQ(0, pthread_join(t, &result)); 755419b9474753d25dff947c7740532f86d130c0beElliott Hughes char* child_thread_error = static_cast<char*>(result); 765419b9474753d25dff947c7740532f86d130c0beElliott Hughes ASSERT_SUBSTR("/child/thread", child_thread_error); 775419b9474753d25dff947c7740532f86d130c0beElliott Hughes free(child_thread_error); 785419b9474753d25dff947c7740532f86d130c0beElliott Hughes 795419b9474753d25dff947c7740532f86d130c0beElliott Hughes ASSERT_SUBSTR("/main/thread", main_thread_error); 805419b9474753d25dff947c7740532f86d130c0beElliott Hughes} 815419b9474753d25dff947c7740532f86d130c0beElliott Hughes 823b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott HughesTEST(dlopen, dlsym_failures) { 833b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes dlerror(); // Clear any pending errors. 843b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes void* self = dlopen(NULL, RTLD_NOW); 853b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(self != NULL); 863b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(dlerror() == NULL); 873b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes 883b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes void* sym; 893b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes 903b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes // NULL handle. 913b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes sym = dlsym(NULL, "test"); 923b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(sym == NULL); 933b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#if __BIONIC__ 943b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_SUBSTR("dlsym library handle is null", dlerror()); 953b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else 963b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_SUBSTR("undefined symbol: test", dlerror()); // glibc isn't specific about the failure. 973b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif 983b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes 993b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes // NULL symbol name. 1003b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#if __BIONIC__ 1013b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes // glibc marks this parameter non-null and SEGVs if you cheat. 1023b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes sym = dlsym(self, NULL); 1033b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(sym == NULL); 1043b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_SUBSTR("", dlerror()); 1053b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif 1063b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes 1073b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes // Symbol that doesn't exist. 1083b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes sym = dlsym(self, "ThisSymbolDoesNotExist"); 1093b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(sym == NULL); 1103b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror()); 1113b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes} 1123b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes 1138e15b08ae22a5230c1fea4779410de0420fa939cElliott HughesTEST(dlopen, dladdr) { 1143b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes dlerror(); // Clear any pending errors. 1158e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes void* self = dlopen(NULL, RTLD_NOW); 1168e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_TRUE(self != NULL); 1173b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(dlerror() == NULL); 1188e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1198e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes void* sym = dlsym(self, "DlSymTestFunction"); 1208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_TRUE(sym != NULL); 1218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address. 1238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2); 1248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes Dl_info info; 1268e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes int rc = dladdr(addr, &info); 1278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_NE(rc, 0); // Zero on error, non-zero on success. 1288e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1298e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // Get the name of this executable. 1308e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes char executable_path[PATH_MAX]; 1318e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path)); 1328e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_NE(rc, -1); 1338e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes executable_path[rc] = '\0'; 1348e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes std::string executable_name(basename(executable_path)); 1358e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1368e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // The filename should be that of this executable. 1378e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // Note that we don't know whether or not we have the full path, so we want an "ends_with" test. 1388e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes std::string dli_fname(info.dli_fname); 1398e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes dli_fname = basename(&dli_fname[0]); 1408e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(dli_fname, executable_name); 1418e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1428e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // The symbol name should be the symbol we looked up. 1438e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_STREQ(info.dli_sname, "DlSymTestFunction"); 1448e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1458e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // The address should be the exact address of the symbol. 1468e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(info.dli_saddr, sym); 1478e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1488e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // Look in /proc/pid/maps to find out what address we were loaded at. 1498e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic. 1508e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes void* base_address = NULL; 1518e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes char path[PATH_MAX]; 1528e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes snprintf(path, sizeof(path), "/proc/%d/maps", getpid()); 1538e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes char line[BUFSIZ]; 1548e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes FILE* fp = fopen(path, "r"); 1558e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_TRUE(fp != NULL); 1568e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes while (fgets(line, sizeof(line), fp) != NULL) { 1578e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes uintptr_t start = strtoul(line, 0, 16); 1588e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes line[strlen(line) - 1] = '\0'; // Chomp the '\n'. 1598e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes char* path = strchr(line, '/'); 160156da966214957c5616a0b83cc84686eedfc4e31Elliott Hughes if (path != NULL && strcmp(executable_path, path) == 0) { 1618e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes base_address = reinterpret_cast<void*>(start); 1628e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes break; 1638e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes } 1648e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes } 1658e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes fclose(fp); 1668e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1678e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // The base address should be the address we were loaded at. 1688e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(info.dli_fbase, base_address); 1698e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes} 1708e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1718e15b08ae22a5230c1fea4779410de0420fa939cElliott HughesTEST(dlopen, dladdr_invalid) { 1728e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes Dl_info info; 1738e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1743b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes dlerror(); // Clear any pending errors. 1753b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes 1768e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // No symbol corresponding to NULL. 1778e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success. 1783b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3). 1798e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes 1808e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes // No symbol corresponding to a stack address. 1818e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success. 1823b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3). 1838e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes} 184