14#include "llvm/ADT/StringSet.h"
15#include "llvm/BinaryFormat/Magic.h"
16#include "llvm/Support/Debug.h"
17#include "llvm/Support/DynamicLibrary.h"
18#include "llvm/Support/FileSystem.h"
19#include "llvm/Support/Path.h"
22#include "llvm/BinaryFormat/COFF.h"
23#include "llvm/Support/Endian.h"
28#include <system_error>
36 const SmallVector<const char*, 10> kSysLibraryEnv = {
40 "DYLD_FALLBACK_LIBRARY_PATH",
54 for (
const char* Var : kSysLibraryEnv) {
55 if (
const char* Env =
GetEnv(Var)) {
56 SmallVector<StringRef, 10> CurPaths;
57 SplitPaths(Env, CurPaths, SplitMode::kPruneNonExistent,
59 for (
const auto& Path : CurPaths)
67 SmallVector<std::string, 64> SysPaths;
70 for (
const std::string& P : SysPaths)
75static std::string
substFront(StringRef original, StringRef pattern,
76 StringRef replacement) {
77 if (!original.starts_with_insensitive(pattern))
78 return original.str();
79 SmallString<512> result(replacement);
80 result.append(original.drop_front(pattern.size()));
81 return result.str().str();
85static std::string
substAll(StringRef original, StringRef libLoader) {
102 SmallString<512> mainExecutablePath(
103 llvm::sys::fs::getMainExecutable(
nullptr,
nullptr));
104 llvm::sys::path::remove_filename(mainExecutablePath);
105 SmallString<512> loaderPath;
106 if (libLoader.empty()) {
107 loaderPath = mainExecutablePath;
109 loaderPath = libLoader.str();
110 llvm::sys::path::remove_filename(loaderPath);
113 result =
substFront(original,
"@executable_path", mainExecutablePath);
114 result =
substFront(result,
"@loader_path", loaderPath);
117 SmallString<512> loaderPath;
118 if (libLoader.empty()) {
119 loaderPath = llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
121 loaderPath = libLoader.str();
123 llvm::sys::path::remove_filename(loaderPath);
125 result =
substFront(original,
"$origin", loaderPath);
132std::string DynamicLibraryManager::lookupLibInPaths(
133 StringRef libStem, SmallVector<llvm::StringRef, 2> RPath ,
134 SmallVector<llvm::StringRef, 2> RunPath ,
135 StringRef libLoader )
const {
136#define DEBUG_TYPE "Dyld::lookupLibInPaths"
138 LLVM_DEBUG(dbgs() <<
"Dyld::lookupLibInPaths" << libStem.str()
139 <<
", ..., libLoader=" << libLoader <<
"\n");
145 LLVM_DEBUG(dbgs() <<
"Dyld::lookupLibInPaths: \n");
146 LLVM_DEBUG(dbgs() <<
":: RPATH\n");
148 for (
auto Info : RPath) {
149 LLVM_DEBUG(dbgs() <<
":::: " << Info.str() <<
"\n");
152 LLVM_DEBUG(dbgs() <<
":: SearchPaths (LD_LIBRARY_PATH, etc...)\n");
154 LLVM_DEBUG(dbgs() <<
":::: " << Info.Path
155 <<
", user=" << (Info.IsUser ?
"true" :
"false") <<
"\n");
157 LLVM_DEBUG(dbgs() <<
":: RUNPATH\n");
159 for (
auto Info : RunPath) {
160 LLVM_DEBUG(dbgs() <<
":::: " << Info.str() <<
"\n");
163 SmallString<512> ThisPath;
165 for (
auto Info : RPath) {
166 ThisPath =
substAll(Info, libLoader);
167 llvm::sys::path::append(ThisPath, libStem);
169 LLVM_DEBUG(dbgs() <<
"## Try: " << ThisPath);
171 LLVM_DEBUG(dbgs() <<
" ... Found (in RPATH)!\n");
172 return ThisPath.str().str();
176 for (
const SearchPathInfo& Info : m_SearchPaths) {
177 ThisPath = Info.Path;
178 llvm::sys::path::append(ThisPath, libStem);
180 LLVM_DEBUG(dbgs() <<
"## Try: " << ThisPath);
182 LLVM_DEBUG(dbgs() <<
" ... Found (in SearchPaths)!\n");
183 return ThisPath.str().str();
187 for (
auto Info : RunPath) {
188 ThisPath =
substAll(Info, libLoader);
189 llvm::sys::path::append(ThisPath, libStem);
191 LLVM_DEBUG(dbgs() <<
"## Try: " << ThisPath);
193 LLVM_DEBUG(dbgs() <<
" ... Found (in RUNPATH)!\n");
194 return ThisPath.str().str();
198 LLVM_DEBUG(dbgs() <<
"## NotFound!!!\n");
205std::string DynamicLibraryManager::lookupLibMaybeAddExt(
206 StringRef libStem, SmallVector<llvm::StringRef, 2> RPath ,
207 SmallVector<llvm::StringRef, 2> RunPath ,
208 StringRef libLoader )
const {
209#define DEBUG_TYPE "Dyld::lookupLibMaybeAddExt:"
211 using namespace llvm::sys;
213 LLVM_DEBUG(dbgs() <<
"Dyld::lookupLibMaybeAddExt: " << libStem.str()
214 <<
", ..., libLoader=" << libLoader <<
"\n");
216 std::string foundDyLib = lookupLibInPaths(libStem, RPath, RunPath, libLoader);
218 if (foundDyLib.empty()) {
220 SmallString<512> filenameWithExt(libStem);
221#if defined(LLVM_ON_UNIX)
223 SmallString<512>::iterator IStemEnd = filenameWithExt.end() - 1;
225 static const char* DyLibExt =
".so";
227 static const char* DyLibExt =
".dll";
229#error "Unsupported platform."
231 filenameWithExt += DyLibExt;
232 foundDyLib = lookupLibInPaths(filenameWithExt, RPath, RunPath, libLoader);
234 if (foundDyLib.empty()) {
235 filenameWithExt.erase(IStemEnd + 1, filenameWithExt.end());
236 filenameWithExt +=
".dylib";
237 foundDyLib = lookupLibInPaths(filenameWithExt, RPath, RunPath, libLoader);
242 if (foundDyLib.empty())
243 return std::string();
249 dbgs() <<
"cling::DynamicLibraryManager::lookupLibMaybeAddExt(): "
250 <<
"error getting real (canonical) path of library "
251 << foundDyLib <<
'\n');
260#define DEBUG_TYPE "Dyld::normalizePath:"
262 const std::string Path = path.str();
264 if (::stat(Path.c_str(), &buffer) != 0)
265 return std::string();
269 LLVM_DEBUG(dbgs() <<
"Could not normalize: '" << Path <<
"'");
277 result += item.str() +
",";
284 StringRef libStem, SmallVector<llvm::StringRef, 2> RPath ,
285 SmallVector<llvm::StringRef, 2> RunPath ,
286 StringRef libLoader ,
bool variateLibStem )
const {
287#define DEBUG_TYPE "Dyld::lookupLibrary:"
288 LLVM_DEBUG(dbgs() <<
"Dyld::lookupLibrary: " << libStem.str() <<
", "
290 <<
", " << libLoader.str() <<
"\n");
293 if (llvm::sys::path::is_absolute(libStem)) {
297 LLVM_DEBUG(dbgs() <<
"Dyld::lookupLibrary: '" << libStem.str() <<
"'"
298 <<
"is not a shared library\n");
299 return std::string();
305 if (libStem.starts_with_insensitive(
"@rpath")) {
306 for (
auto& P : RPath) {
307 std::string result =
substFront(libStem,
"@rpath", P);
313 std::string result =
substAll(libStem, libLoader);
321 std::string foundName;
322 if (variateLibStem) {
323 foundName = lookupLibMaybeAddExt(libStem, RPath, RunPath, libLoader);
324 if (foundName.empty()) {
325 StringRef libStemName = llvm::sys::path::filename(libStem);
326 if (!libStemName.starts_with(
"lib")) {
328 foundName = lookupLibMaybeAddExt(
329 libStem.str().insert(libStem.size() - libStemName.size(),
"lib"),
330 RPath, RunPath, libLoader);
334 foundName = lookupLibInPaths(libStem, RPath, RunPath, libLoader);
337 if (!foundName.empty())
340 return std::string();
347#define DEBUG_TYPE "Dyld::loadLibrary:"
348 LLVM_DEBUG(dbgs() <<
"Dyld::loadLibrary: " << libStem.str() <<
", "
349 << (permanent ?
"permanent" :
"not-permanent") <<
", "
350 << (resolved ?
"resolved" :
"not-resolved") <<
"\n");
352 std::string canonicalLoadedLib;
354 canonicalLoadedLib = libStem.str();
357 if (canonicalLoadedLib.empty())
361 if (m_LoadedLibraries.find(canonicalLoadedLib) != m_LoadedLibraries.end())
373 LLVM_DEBUG(dbgs() <<
"DynamicLibraryManager::loadLibrary(): " << errMsg);
378 std::pair<DyLibs::iterator, bool> insRes = m_DyLibs.insert(
379 std::pair<DyLibHandle, std::string>(dyLibHandle, canonicalLoadedLib));
382 m_LoadedLibraries.insert(canonicalLoadedLib);
388#define DEBUG_TYPE "Dyld::unloadLibrary:"
393 DyLibHandle dyLibHandle =
nullptr;
394 for (DyLibs::const_iterator I = m_DyLibs.begin(), E = m_DyLibs.end(); I != E;
396 if (I->second == canonicalLoadedLib) {
397 dyLibHandle = I->first;
406 if (!errMsg.empty()) {
407 LLVM_DEBUG(dbgs() <<
"cling::DynamicLibraryManager::unloadLibrary(): "
413 m_DyLibs.erase(dyLibHandle);
414 m_LoadedLibraries.erase(canonicalLoadedLib);
420 if (m_LoadedLibraries.find(canonPath) != m_LoadedLibraries.end())
426 llvm::raw_ostream& OS = S ? *S : llvm::outs();
432 OS << Info.Path.c_str() <<
"\n";
437static bool IsDLL(llvm::StringRef headers) {
438 using namespace llvm::support::endian;
440 uint32_t headeroffset = read32le(headers.data() + 0x3c);
441 auto peheader = headers.substr(headeroffset, 24);
442 if (peheader.size() != 24) {
446 uint32_t characteristics = read16le(peheader.data() + 22);
447 return (characteristics & llvm::COFF::IMAGE_FILE_DLL) != 0;
453 using namespace llvm;
455 auto filetype = sys::fs::get_file_type(libFullPath,
true);
456 if (filetype != sys::fs::file_type::regular_file) {
459 *exists = filetype != sys::fs::file_type::status_error;
471 std::string path = libFullPath.str();
472 std::ifstream in(path, std::ios::binary);
473 char header[1024] = {0};
474 in.read(header,
sizeof(header));
481 StringRef headerStr(header, in.gcount());
482 file_magic Magic = identify_magic(headerStr);
486 (Magic == file_magic::macho_fixed_virtual_memory_shared_lib ||
487 Magic == file_magic::macho_dynamically_linked_shared_lib ||
488 Magic == file_magic::macho_dynamically_linked_shared_lib_stub ||
489 Magic == file_magic::macho_universal_binary)
490#elif defined(LLVM_ON_UNIX)
492 (Magic == file_magic::pecoff_executable)
494 (Magic == file_magic::elf_shared_object)
499 (Magic == file_magic::pecoff_executable && IsDLL(headerStr))
501#error
"Unsupported platform."
static char * GetEnv(const char *Var_Name)
void unloadLibrary(llvm::StringRef libStem)
LoadLibResult loadLibrary(llvm::StringRef, bool permanent, bool resolved=false)
Loads a shared library.
static std::string normalizePath(llvm::StringRef path)
static bool isSharedLibrary(llvm::StringRef libFullPath, bool *exists=nullptr)
Returns true if file is a shared library.
LoadLibResult
Describes the result of loading a library.
@ kLoadLibNotFound
library was not found
@ kLoadLibAlreadyLoaded
library was already loaded
@ kLoadLibLoadError
loading the library failed
@ kLoadLibSuccess
library loaded successfully
void addSearchPath(llvm::StringRef dir, bool isUser=true, bool prepend=false)
void dump(llvm::raw_ostream *S=nullptr) const
const SearchPathInfos & getSearchPaths() const
Returns the system include paths.
bool isLibraryLoaded(llvm::StringRef fullPath) const
Returns true if the file was a dynamic library and it was already loaded.
std::string lookupLibrary(llvm::StringRef libStem, llvm::SmallVector< llvm::StringRef, 2 > RPath={}, llvm::SmallVector< llvm::StringRef, 2 > RunPath={}, llvm::StringRef libLoader="", bool variateLibStem=true) const
Looks up a library taking into account the current include paths and the system include paths.
bool SplitPaths(llvm::StringRef PathStr, llvm::SmallVectorImpl< llvm::StringRef > &Paths, SplitMode Mode, llvm::StringRef Delim, bool Verbose)
Collect the constituent paths from a PATH string.
std::string RPathToStr2(SmallVector< StringRef, 2 > V)
static std::string substFront(StringRef original, StringRef pattern, StringRef replacement)
static std::string substAll(StringRef original, StringRef libLoader)