diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -402,14 +402,6 @@ set(LLVM_ENABLE_Z3_SOLVER_DEFAULT "${Z3_FOUND}") -if (LLVM_ENABLE_DEBUGINFOD_CLIENT) - set(LLVM_WITH_CURL 1) - set(CURL_LIBRARY "-lcurl") - find_package(CURL 7.74.0 REQUIRED) - add_compile_definitions( - LLVM_ENABLE_DEBUGINFOD_CLIENT - LLVM_WITH_CURL) -endif() if( LLVM_TARGETS_TO_BUILD STREQUAL "all" ) set( LLVM_TARGETS_TO_BUILD ${LLVM_ALL_TARGETS} ) diff --git a/llvm/include/llvm/Debuginfod/Debuginfod.h b/llvm/include/llvm/Debuginfod/Debuginfod.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Debuginfod/Debuginfod.h @@ -0,0 +1,53 @@ +//===-- llvm/Support/Debuginfod.h - Debuginfod client library ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declarations of the debuginfod::fetchInfo +/// function and the debuginfod::AssetType enum class +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_DEBUGINFOD_H +#define LLVM_SUPPORT_DEBUGINFOD_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +namespace llvm { + +/// DebuginfodAsset - This enum class specifies the types of +/// debugging information that can be requested from a debuginfod +/// server. +enum class DebuginfodAssetType { Executable, Debuginfo, Source }; + +/// DebuginfodAssetCache - This interface provides a file caching mechanism +/// powered by LLVM's cache pruning. This should probably be replaced with the +/// ThinLTO caching scheme after a refactor to move the ThinLTO caching to the +/// support libs +class DebuginfodAssetCache { + StringRef DirectoryPath; + +public: + DebuginfodAssetCache(StringRef CacheDirectoryPath); + Expected contains(StringRef RelPath); + Error add(StringRef Key, StringRef Contents); + Error prune(); + std::string absolutePath(StringRef Key); + Expected contentsOf(StringRef Key); +}; + +Expected fetchDebuginfo(ArrayRef DebuginfodUrls, + StringRef CacheDirectoryPath, + StringRef BuildID, + DebuginfodAssetType Type, + StringRef Description = ""); + +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/Support/HTTPClient.h b/llvm/include/llvm/Support/HTTPClient.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/HTTPClient.h @@ -0,0 +1,29 @@ +//===-- llvm/Support/HTTPClient.h - HTTP client library ---*- C++ -------*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declarations of the HTTPResponse struct +/// and httpGet function. +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_HTTP_CLIENT_H +#define LLVM_SUPPORT_HTTP_CLIENT_H + +#include "llvm/Support/Error.h" + +namespace llvm { +struct HTTPResponse { + long Code = 0; + std::string Body; +}; +Expected httpGet(const Twine &Url); +} // end namespace llvm + +#endif // LLVM_SUPPORT_HTTP_CLIENT_H diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt --- a/llvm/lib/CMakeLists.txt +++ b/llvm/lib/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(BinaryFormat) add_subdirectory(Bitcode) add_subdirectory(Bitstream) +add_subdirectory(Debuginfod) add_subdirectory(DWARFLinker) add_subdirectory(Extensions) add_subdirectory(Frontend) diff --git a/llvm/lib/Debuginfod/CMakeLists.txt b/llvm/lib/Debuginfod/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Debuginfod/CMakeLists.txt @@ -0,0 +1,11 @@ +if(LLVM_ENABLE_CURL) + add_llvm_component_library(LLVMDebuginfod + Debuginfod.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Debuginfod + + LINK_COMPONENTS + Support + ) +endif() diff --git a/llvm/lib/Debuginfod/Debuginfod.cpp b/llvm/lib/Debuginfod/Debuginfod.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Debuginfod/Debuginfod.cpp @@ -0,0 +1,200 @@ +//===-- llvm/Support/Debuginfod.cpp - Debuginfod client library -------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file defines the fetchInfo function, which retrieves +/// any of the three supported asset types: (executable, debuginfo, source file) +/// associated with a build-id from debuginfod servers. If a source file is to +/// be fetched, its absolute path must be specified in the Description argument +/// to fetchInfo. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Debuginfod/Debuginfod.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CachePruning.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/HTTPClient.h" + +using namespace llvm; +using namespace sys::fs; +using namespace sys::path; + +#define DEBUG_TYPE "DEBUGINFOD" + +llvm::DebuginfodAssetCache::DebuginfodAssetCache(StringRef CacheDirectoryPath) { + DirectoryPath = CacheDirectoryPath; +} + +Expected llvm::DebuginfodAssetCache::contains(StringRef Key) { + + // We prune the cache before answering each query. + if (Error Err = prune()) + return Err; + + auto AbsolutePath = absolutePath(Key); + file_status Status; + auto EC = status(AbsolutePath, Status); + if (EC && EC != errc::no_such_file_or_directory) + return createStringError(EC, "failed to check asset cache entry status"); + else if (EC == errc::no_such_file_or_directory) + return false; + else + return exists(Status); +} + +Error llvm::DebuginfodAssetCache::add(StringRef Key, StringRef Contents) { + auto AbsolutePath = absolutePath(Key); + StringRef Root = parent_path(AbsolutePath); + + // We do not assume the cache directory exists so we must create it. + std::error_code EC = create_directories(Root); + if (EC) + return createStringError(errc::io_error, + "failed to create cache directory path"); + + if (Error Err = prune()) + return Err; + + return writeFileAtomically("llvm-debuginfod-%%%%%%%%%%%%%%%%%%", AbsolutePath, + Contents); +} + +Error llvm::DebuginfodAssetCache::prune() { + // see CachePruning.h + // "A default constructed CachePruningPolicy + // provides a reasonable default policy." + pruneCache(DirectoryPath, CachePruningPolicy()); + return Error::success(); +} + +static Expected contentsOfFile(StringRef AbsolutePath) { + + uint64_t FileSize; + if (auto EC = file_size(AbsolutePath, FileSize)) + return createStringError(EC, "error getting file size"); + + LLVM_DEBUG(dbgs() << "got file size of " << FileSize << " bytes\n";); + + LLVM_DEBUG(dbgs() << "opening native file at " << AbsolutePath << "\n";); + auto FileOrErr = openNativeFileForRead(AbsolutePath); + if (Error Err = FileOrErr.takeError()) + return Err; + auto &File = *FileOrErr; + LLVM_DEBUG(dbgs() << "native file opened\n";); + + LLVM_DEBUG(dbgs() << "reading native file\n";); + std::vector Buf(FileSize); + auto SizeReadOrErr = + readNativeFile(File, MutableArrayRef(Buf.data(), Buf.size())); + if (Error Err = SizeReadOrErr.takeError()) + return Err; + LLVM_DEBUG(dbgs() << "read native file\n";); + + auto &SizeRead = *SizeReadOrErr; + LLVM_DEBUG(dbgs() << "SizeRead = " << SizeRead << " bytes\n";); + + if (SizeRead != FileSize) + return createStringError(errc::result_out_of_range, + "failed to read entire file"); + + if (auto EC = closeFile(File)) + return createStringError(EC, "error closing file"); + + return std::string(Buf.data(), Buf.size()); +} + +Expected llvm::DebuginfodAssetCache::contentsOf(StringRef Key) { + auto AbsolutePath = absolutePath(Key); + return contentsOfFile(AbsolutePath); +} + +static std::string hexEncode(std::string String) { + std::string Output = ""; + const std::vector hexDigits = {"0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "a", "b", + "c", "d", "e", "f"}; + for (auto c : String) { + unsigned int i1 = (int)c & 0b1111; + unsigned int i2 = (int)c >> 4; + Output += hexDigits.at(i1); + Output += hexDigits.at(i2); + } + return Output; +} + +std::string llvm::DebuginfodAssetCache::absolutePath(StringRef Key) { + LLVM_DEBUG(dbgs() << "getting absolute path of " << Key << "\n";); + std::string HexEncodedKey = hexEncode(Key.str()); + auto AbsPath = DirectoryPath + "/llvmcache-debuginfod-" + HexEncodedKey; + LLVM_DEBUG(dbgs() << "HexEncodedKey = " << HexEncodedKey << "\n";); + LLVM_DEBUG(dbgs() << "got absolute path " << AbsPath << "\n";); + return AbsPath.str(); +} + +Expected llvm::fetchDebuginfo(ArrayRef DebuginfodUrls, + StringRef CacheDirectoryPath, + StringRef BuildID, + DebuginfodAssetType Type, + StringRef Description) { + LLVM_DEBUG(dbgs() << "fetching info, debuginfod urls size = " + << DebuginfodUrls.size() << "\n";); + std::string Suffix; + if (Type == DebuginfodAssetType::Executable) { + Suffix = "executable"; + } else if (Type == DebuginfodAssetType::Debuginfo) { + Suffix = "debuginfo"; + } else if (Type == DebuginfodAssetType::Source) { + // Description is the absolute source path + Suffix = "source" + Description.str(); + } else { + llvm_unreachable("invalid debuginfo asset type"); + } + + DebuginfodAssetCache Cache(CacheDirectoryPath); + auto UniqueKey = (BuildID + Suffix).str(); + auto CacheHitOrErr = Cache.contains(UniqueKey); + + if (Error Err = CacheHitOrErr.takeError()) + return Err; + + bool &CacheHit = *CacheHitOrErr; + if (CacheHit) { + LLVM_DEBUG(dbgs() << "cache hit!\n";); + return Cache.absolutePath(UniqueKey); + } + + // The asset was not found in the local cache, so we must query + // the debuginfod servers. + for (auto &Url : DebuginfodUrls) { + + Expected ResponseOrErr = + httpGet(Url + "buildid/" + BuildID + "/" + Suffix); + + if (Error Err = ResponseOrErr.takeError()) + return Err; + + HTTPResponse &Resp = *ResponseOrErr; + if (Resp.Code == 200) { + // We have retrieved the asset from this server, + // so we add it to the file cache. + if (Error Err = Cache.add(UniqueKey, Resp.Body)) + return Err; + + // Return the path to the asset on disk. + return Cache.absolutePath(UniqueKey); + } + } + + return createStringError(errc::argument_out_of_domain, "build id not found"); +} + +#undef DEBUG_TYPE diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -74,6 +74,11 @@ set(system_libs ${system_libs} ${Z3_LIBRARIES}) endif() +# Link LibCURL if the user wants it +if (LLVM_ENABLE_CURL) + set(system_libs ${system_libs} ${CURL_LIBRARIES}) +endif() + # Override the C runtime allocator on Windows and embed it into LLVM tools & libraries if(LLVM_INTEGRATED_CRT_ALLOC) if (CMAKE_BUILD_TYPE AND NOT ${LLVM_USE_CRT_${uppercase_CMAKE_BUILD_TYPE}} MATCHES "^(MT|MTd)$") @@ -155,6 +160,7 @@ GlobPattern.cpp GraphWriter.cpp Hashing.cpp + HTTPClient.cpp InitLLVM.cpp InstructionCost.cpp IntEqClasses.cpp diff --git a/llvm/lib/Support/HTTPClient.cpp b/llvm/lib/Support/HTTPClient.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/HTTPClient.cpp @@ -0,0 +1,94 @@ +//===-- llvm/Support/HTTPClient.cpp - HTTP client library -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file defines the httpGet function, implemented using libcurl. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/HTTPClient.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" + +#include + +namespace llvm { + +#define DEBUG_TYPE "HTTPClient" + +struct MemoryStruct { + char *memory; + size_t size; +}; + +static size_t writeMemoryCallback(void *contents, size_t size, size_t nmemb, + void *userp) { + size_t realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *)userp; + + char *ptr = (char *)realloc(mem->memory, mem->size + realsize + 1); + if (!ptr) { + errs() << "not enough memory (realloc returned NULL)\n"; + return 0; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +Expected httpGet(const Twine &Url) { + + LLVM_DEBUG(dbgs() << "getting Url " << Url << "\n";); + + struct MemoryStruct chunk; + + chunk.memory = (char *)malloc(1); + chunk.size = 0; + + CURL *Curl = curl_easy_init(); + CURLcode CurlRes; + if (!Curl) { + return createStringError(errc::io_error, "http library error"); + } + + std::string UrlString = Url.str(); + curl_easy_setopt(Curl, CURLOPT_URL, UrlString.c_str()); + curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, writeMemoryCallback); + curl_easy_setopt(Curl, CURLOPT_WRITEDATA, (void *)&chunk); + + LLVM_DEBUG(dbgs() << "performing the curl\n";); + CurlRes = curl_easy_perform(Curl); + LLVM_DEBUG(dbgs() << "got the CurlRes\n";); + + curl_easy_cleanup(Curl); + + if (CurlRes != CURLE_OK) { + free(chunk.memory); + return createStringError(errc::io_error, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(CurlRes)); + } + + std::string Body(chunk.memory, chunk.size); + free(chunk.memory); + HTTPResponse Resp; + Resp.Body = Body; + curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Resp.Code); + return Resp; +} + +#undef DEBUG_TYPE + +} // end namespace llvm diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -396,3 +396,6 @@ if config.expensive_checks: config.available_features.add('expensive_checks') + +if getattr(config, 'enable_debuginfod_client', False): + config.available_features.add('debuginfod_client') diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in --- a/llvm/test/lit.site.cfg.py.in +++ b/llvm/test/lit.site.cfg.py.in @@ -1,5 +1,12 @@ @LIT_SITE_CFG_IN_HEADER@ + +# Set attribute value if it is unset. +def set_default(attr, value): + if not getattr(config, attr, None): + setattr(config, attr, value) + +import lit.util import sys config.host_triple = "@LLVM_HOST_TRIPLE@" @@ -37,6 +44,7 @@ config.llvm_use_intel_jitevents = @LLVM_USE_INTEL_JITEVENTS@ config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.have_zlib = @LLVM_ENABLE_ZLIB@ +set_default("enable_debuginfod_client", lit.util.pythonize_bool("@LLVM_ENABLE_DEBUGINFOD_CLIENT@")) config.have_libxar = @LLVM_HAVE_LIBXAR@ config.have_libxml2 = @LLVM_ENABLE_LIBXML2@ config.have_dia_sdk = @LLVM_ENABLE_DIA_SDK@ diff --git a/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/debuginfo b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/debuginfo new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/debuginfo @@ -0,0 +1 @@ +fake_debuginfo diff --git a/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/executable b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/executable new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/executable @@ -0,0 +1 @@ +fake_executable diff --git a/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/source/directory/file.c b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/source/directory/file.c new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/Inputs/buildid/fake_build_id/source/directory/file.c @@ -0,0 +1 @@ +int foo = 0; diff --git a/llvm/test/tools/llvm-debuginfod/find-test.sh b/llvm/test/tools/llvm-debuginfod/find-test.sh new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/find-test.sh @@ -0,0 +1,15 @@ +set -x + +# start the server +timeout 2s python -m http.server \ + --directory $1/Inputs/ $3 & + +sleep 0.5s + +# test the client +DEBUGINFOD_URLS=http://localhost:$3/ \ + llvm-debuginfod-find fake_build_id \ + $2 \ + -debug + +exit diff --git a/llvm/test/tools/llvm-debuginfod/llvm-debuginfod-find.test b/llvm/test/tools/llvm-debuginfod/llvm-debuginfod-find.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-debuginfod/llvm-debuginfod-find.test @@ -0,0 +1,4 @@ +# REQUIRES: debuginfod_client +# RUN: bash %S/find-test.sh %S --executable 13573 +# RUN: bash %S/find-test.sh %S --debuginfo 13574 +# RUN: bash %S/find-test.sh %S --source=/directory/file.c 13575 diff --git a/llvm/tools/llvm-debuginfod/CMakeLists.txt b/llvm/tools/llvm-debuginfod/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-debuginfod/CMakeLists.txt @@ -0,0 +1,13 @@ +if (LLVM_ENABLE_CURL) + set(LLVM_LINK_COMPONENTS + Debuginfod + Support + ) + add_llvm_tool(llvm-debuginfod-find + llvm-debuginfod-find.cpp + ) + set_property(TARGET llvm-debuginfod-find PROPERTY LLVM_SYSTEM_LIBS ${imported_libs}) + if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(debuginfod-find llvm-debuginfod-find) + endif() +endif() diff --git a/llvm/tools/llvm-debuginfod/llvm-debuginfod-find.cpp b/llvm/tools/llvm-debuginfod/llvm-debuginfod-find.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-debuginfod/llvm-debuginfod-find.cpp @@ -0,0 +1,99 @@ +//===-- llvm-debuginfod-find.cpp - Simple CLI for libdebuginfod-client ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the llvm-debuginfod-find tool. This tool +/// queries the debuginfod servers in the DEBUGINFOD_URLS environment +/// variable (delimited by space (" ")) for the executable, +/// debuginfo, or specified source file of the binary matching the +/// given build-id. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" +#include "llvm/Debuginfod/Debuginfod.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/COM.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + +#define DEBUG_TYPE "llvm-debuginfod-find" + +using namespace llvm; + +cl::opt InputBuildID(cl::Positional, cl::Required, + cl::desc(""), cl::init("-")); + +static cl::opt + FetchExecutable("executable", cl::init(false), + cl::desc("fetch the associated executable")); + +static cl::opt FetchDebuginfo("debuginfo", cl::init(false), + cl::desc("fetch associated debuginfo")); + +static cl::opt FetchSource("source", cl::init(""), + cl::desc("/filename")); + +ExitOnError ExitOnErr; + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv); + + const char *DebuginfodUrlsEnv = std::getenv("DEBUGINFOD_URLS"); + if (DebuginfodUrlsEnv == NULL) { + errs() << "DEBUGINFOD_URLS not set\n"; + return 1; + } + + SmallVector DebuginfodUrls; + StringRef(DebuginfodUrlsEnv).split(DebuginfodUrls, " "); + + const char *HomeEnv = std::getenv("HOME"); + if (HomeEnv == NULL) { + LLVM_DEBUG(dbgs() << "HOME not set\n";); + return 1; + } + LLVM_DEBUG(dbgs() << "HOME = " << HomeEnv << "\n";); + auto CacheDirectoryPath = + std::string(HomeEnv) + + std::string("/.llvmdebuginfodcache/debuginfod_client"); + LLVM_DEBUG(dbgs() << "CacheDirectoryPath = " << CacheDirectoryPath << "\n";); + + DebuginfodAssetType Type; + StringRef Description; + if (FetchExecutable) { + Type = DebuginfodAssetType::Executable; + } else if (FetchDebuginfo) { + Type = DebuginfodAssetType::Debuginfo; + } else if (FetchSource != "") { + Type = DebuginfodAssetType::Source; + Description = FetchSource; + } else { + llvm_unreachable("invalid asset request"); + } + std::string InfoFilePath = ExitOnErr(fetchDebuginfo( + DebuginfodUrls, CacheDirectoryPath, InputBuildID, Type, Description)); + outs() << InfoFilePath << "\n"; +} + +#undef DEBUG_TYPE diff --git a/llvm/unittests/Debuginfod/CMakeLists.txt b/llvm/unittests/Debuginfod/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/unittests/Debuginfod/CMakeLists.txt @@ -0,0 +1,9 @@ +if (LLVM_ENABLE_CURL) + set(LLVM_LINK_COMPONENTS + Debuginfod + ) + + add_llvm_unittest(DebuginfodTests + DebuginfodTests.cpp + ) +endif() diff --git a/llvm/unittests/Debuginfod/DebuginfodTests.cpp b/llvm/unittests/Debuginfod/DebuginfodTests.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Debuginfod/DebuginfodTests.cpp @@ -0,0 +1,19 @@ +//===-- llvm/unittest/Support/DebuginfodTests.cpp - unit tests --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Debuginfod/Debuginfod.h" + +#include "gtest/gtest.h" + +TEST(DebuginfodTests, noDebuginfodUrlsFetchInfoTest) { + auto InfoOrErr = fetchInfo({}, "./", "fakeBuildId", + llvm::DebuginfodAssetType::Executable, ""); + handleAllErrors(InfoOrErr.takeError(), [](const llvm::StringError &SE) { + llvm::dbgs() << "got a StringError as expected\n"; + }); +} diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -41,6 +41,7 @@ GlobPatternTest.cpp HashBuilderTest.cpp Host.cpp + HTTPClient.cpp IndexedAccessorTest.cpp InstructionCostTest.cpp ItaniumManglingCanonicalizerTest.cpp diff --git a/llvm/unittests/Support/HTTPClient.cpp b/llvm/unittests/Support/HTTPClient.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Support/HTTPClient.cpp @@ -0,0 +1,23 @@ +//===-- llvm/unittest/Support/HTTPClient.cpp - unit tests -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifdef LLVM_WITH_CURL + +#include "llvm/Support/HTTPClient.h" + +#include "gtest/gtest.h" + +TEST(HTTPClientTests, invalidUrlTest) { + std::string invalidUrl = "llvm is fun"; + handleAllErrors(llvm::httpGet(invalidUrl).takeError(), + [](const llvm::StringError &SE) { + llvm::dbgs() << "got a StringError as expected\n"; + }); +} + +#endif