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