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