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