1 //===- llvm/unittest/Support/DynamicLibrary/DynamicLibraryTest.cpp --------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/DynamicLibrary.h" 11 #include "llvm/Config/config.h" 12 #include "llvm/Support/FileSystem.h" 13 #include "llvm/Support/ManagedStatic.h" 14 #include "llvm/Support/Path.h" 15 #include "gtest/gtest.h" 16 17 #include "PipSqueak.h" 18 19 using namespace llvm; 20 using namespace llvm::sys; 21 22 std::string LibPath(const std::string Name = "PipSqueak") { 23 const std::vector<testing::internal::string> &Argvs = 24 testing::internal::GetArgvs(); 25 const char *Argv0 = 26 Argvs.size() > 0 ? Argvs[0].c_str() : "DynamicLibraryTests"; 27 void *Ptr = (void*)(intptr_t)TestA; 28 std::string Path = fs::getMainExecutable(Argv0, Ptr); 29 llvm::SmallString<256> Buf(path::parent_path(Path)); 30 path::append(Buf, (Name + LTDL_SHLIB_EXT).c_str()); 31 return Buf.str(); 32 } 33 34 #if defined(_WIN32) || (defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)) 35 36 typedef void (*SetStrings)(std::string &GStr, std::string &LStr); 37 typedef void (*TestOrder)(std::vector<std::string> &V); 38 typedef const char *(*GetString)(); 39 40 template <class T> static T FuncPtr(void *Ptr) { 41 union { 42 T F; 43 void *P; 44 } Tmp; 45 Tmp.P = Ptr; 46 return Tmp.F; 47 } 48 template <class T> static void* PtrFunc(T *Func) { 49 union { 50 T *F; 51 void *P; 52 } Tmp; 53 Tmp.F = Func; 54 return Tmp.P; 55 } 56 57 static const char *OverloadTestA() { return "OverloadCall"; } 58 59 std::string StdString(const char *Ptr) { return Ptr ? Ptr : ""; } 60 61 TEST(DynamicLibrary, Overload) { 62 { 63 std::string Err; 64 llvm_shutdown_obj Shutdown; 65 DynamicLibrary DL = 66 DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err); 67 EXPECT_TRUE(DL.isValid()); 68 EXPECT_TRUE(Err.empty()); 69 70 GetString GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); 71 EXPECT_TRUE(GS != nullptr && GS != &TestA); 72 EXPECT_EQ(StdString(GS()), "LibCall"); 73 74 GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); 75 EXPECT_TRUE(GS != nullptr && GS != &TestA); 76 EXPECT_EQ(StdString(GS()), "LibCall"); 77 78 DL = DynamicLibrary::getPermanentLibrary(nullptr, &Err); 79 EXPECT_TRUE(DL.isValid()); 80 EXPECT_TRUE(Err.empty()); 81 82 // Test overloading local symbols does not occur by default 83 GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); 84 EXPECT_TRUE(GS != nullptr && GS == &TestA); 85 EXPECT_EQ(StdString(GS()), "ProcessCall"); 86 87 GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); 88 EXPECT_TRUE(GS != nullptr && GS == &TestA); 89 EXPECT_EQ(StdString(GS()), "ProcessCall"); 90 91 // Test overloading by forcing library priority when searching for a symbol 92 DynamicLibrary::SearchOrder = DynamicLibrary::SO_LoadedFirst; 93 GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); 94 EXPECT_TRUE(GS != nullptr && GS != &TestA); 95 EXPECT_EQ(StdString(GS()), "LibCall"); 96 97 DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA)); 98 GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); 99 EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA); 100 101 GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); 102 EXPECT_TRUE(GS != nullptr && GS == &OverloadTestA); 103 EXPECT_EQ(StdString(GS()), "OverloadCall"); 104 } 105 EXPECT_TRUE(FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol( 106 "TestA")) == nullptr); 107 108 // Check serach ordering is reset to default after call to llvm_shutdown 109 EXPECT_TRUE(DynamicLibrary::SearchOrder == DynamicLibrary::SO_Linker); 110 } 111 112 TEST(DynamicLibrary, Shutdown) { 113 std::string A("PipSqueak"), B, C("SecondLib"); 114 std::vector<std::string> Order; 115 { 116 std::string Err; 117 llvm_shutdown_obj Shutdown; 118 DynamicLibrary DL = 119 DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err); 120 EXPECT_TRUE(DL.isValid()); 121 EXPECT_TRUE(Err.empty()); 122 123 SetStrings SS_0 = FuncPtr<SetStrings>( 124 DynamicLibrary::SearchForAddressOfSymbol("SetStrings")); 125 EXPECT_TRUE(SS_0 != nullptr); 126 127 SS_0(A, B); 128 EXPECT_EQ(B, "Local::Local(PipSqueak)"); 129 130 TestOrder TO_0 = FuncPtr<TestOrder>( 131 DynamicLibrary::SearchForAddressOfSymbol("TestOrder")); 132 EXPECT_TRUE(TO_0 != nullptr); 133 134 DynamicLibrary DL2 = 135 DynamicLibrary::getPermanentLibrary(LibPath(C).c_str(), &Err); 136 EXPECT_TRUE(DL2.isValid()); 137 EXPECT_TRUE(Err.empty()); 138 139 // Should find latest version of symbols in SecondLib 140 SetStrings SS_1 = FuncPtr<SetStrings>( 141 DynamicLibrary::SearchForAddressOfSymbol("SetStrings")); 142 EXPECT_TRUE(SS_1 != nullptr); 143 EXPECT_TRUE(SS_0 != SS_1); 144 145 TestOrder TO_1 = FuncPtr<TestOrder>( 146 DynamicLibrary::SearchForAddressOfSymbol("TestOrder")); 147 EXPECT_TRUE(TO_1 != nullptr); 148 EXPECT_TRUE(TO_0 != TO_1); 149 150 B.clear(); 151 SS_1(C, B); 152 EXPECT_EQ(B, "Local::Local(SecondLib)"); 153 154 TO_0(Order); 155 TO_1(Order); 156 } 157 EXPECT_EQ(A, "Global::~Global"); 158 EXPECT_EQ(B, "Local::~Local"); 159 EXPECT_TRUE(FuncPtr<SetStrings>(DynamicLibrary::SearchForAddressOfSymbol( 160 "SetStrings")) == nullptr); 161 162 // Test unload/destruction ordering 163 EXPECT_EQ(Order.size(), 2UL); 164 EXPECT_EQ(Order.front(), "SecondLib"); 165 EXPECT_EQ(Order.back(), "PipSqueak"); 166 } 167 168 #else 169 170 TEST(DynamicLibrary, Unsupported) { 171 std::string Err; 172 DynamicLibrary DL = 173 DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err); 174 EXPECT_FALSE(DL.isValid()); 175 EXPECT_EQ(Err, "dlopen() not supported on this platform"); 176 } 177 178 #endif 179