// // This file is distributed under the MIT License. See LICENSE.md for details. // extern "C" { #include "dlfcn.h" #include "link.h" } #include #include #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/GlobPattern.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "revng/Support/Assert.h" #include "revng/Support/Debug.h" #include "revng/Support/PathList.h" static Logger Log("find-resources"); struct Resources { bool FirstCall = true; std::string CurrentRoot; std::map LibrariesFullPath; }; llvm::ManagedStatic Resources; extern "C" { static int dlIteratePhdrCallback(struct dl_phdr_info *Info, size_t Size, void *Data) { using llvm::StringRef; if (Info->dlpi_name == nullptr) return 0; StringRef FullPath(Info->dlpi_name); if (FullPath.size() == 0) return 0; StringRef Name = llvm::sys::path::filename(FullPath); Resources->LibrariesFullPath[Name.rsplit(".so").first.str()] = FullPath.str(); return 0; } } static void initialize() { if (not Resources->FirstCall) return; Resources->FirstCall = false; dl_iterate_phdr(dlIteratePhdrCallback, nullptr); using namespace llvm::sys::path; constexpr const char *MainLibrary = "librevngSupport"; using llvm::StringRef; StringRef MainLibraryFullPath = Resources->LibrariesFullPath.at(MainLibrary); Resources->CurrentRoot = parent_path(parent_path(MainLibraryFullPath)); } llvm::StringRef getCurrentRoot() { initialize(); return Resources->CurrentRoot; } static std::string getXDGDirectory(llvm::StringRef EnvironmentVariable, llvm::StringRef DefaultInHome, llvm::StringRef Subdirectory) { std::string BaseDir; if (auto XDGDir = llvm::sys::Process::GetEnv(EnvironmentVariable)) { BaseDir = *XDGDir; } else { llvm::SmallString<64> PathHome; llvm::sys::path::home_directory(PathHome); BaseDir = joinPath(PathHome.str(), DefaultInHome); } return joinPath(BaseDir, Subdirectory); } std::string getCacheDirectory() { return getXDGDirectory("XDG_CACHE_HOME", ".cache", "revng"); } std::string getConfigDirectory() { return getXDGDirectory("XDG_CONFIG_HOME", ".config", "revng"); } const std::map &getLibrariesFullPath() { initialize(); return Resources->LibrariesFullPath; } static std::optional findFileInPaths(llvm::StringRef FileName, const std::vector &SearchPaths) { std::optional FoundFileName; for (const auto &Path : SearchPaths) { revng_log(Log, "Looking in path: " << Path); llvm::SmallString<64> FullFileName; llvm::sys::path::append(FullFileName, Path, FileName); LoggerIndent Indent(Log); if (not llvm::sys::fs::exists(FullFileName)) { revng_log(Log, "File not found: " << FullFileName.str().str()); continue; } std::error_code Err = llvm::sys::fs::access(FullFileName, llvm::sys::fs::AccessMode::Exist); if (Err) { revng_log(Log, "Cannot access file: " << FullFileName.str().str()); } else { revng_log(Log, "Found file: " << FullFileName.str().str()); FoundFileName = FullFileName.str().str(); break; } } if (not FoundFileName.has_value()) { revng_log(Log, "Failed to find `" << FileName.str() << "`."); } return FoundFileName; } std::optional PathList::findFile(llvm::StringRef FileName) const { return findFileInPaths(FileName, SearchPaths); } std::vector PathList::list(llvm::StringRef Path, llvm::StringRef Suffix) const { using namespace llvm; using namespace sys; using namespace fs; using std::string; std::set Visited; std::vector Result; for (const string &SearchPath : SearchPaths) { SmallString<16> FullPath(SearchPath); path::append(FullPath, Path); if (is_directory(FullPath)) { std::error_code EC; for (directory_iterator File(FullPath, EC), FileEnd; File != FileEnd && !EC; File.increment(EC)) { if (llvm::StringRef(File->path()).endswith(Suffix)) { bool New = Visited.insert(path::filename(File->path()).str()).second; if (New) Result.push_back(File->path()); } } revng_assert(!EC); } } return Result; }