123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- //===-- llvm/Debuginfod/Debuginfod.cpp - Debuginfod client library --------===//
- //
- // 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 artifact 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/Debuginfod/HTTPClient.h"
- #include "llvm/Support/CachePruning.h"
- #include "llvm/Support/Caching.h"
- #include "llvm/Support/Errc.h"
- #include "llvm/Support/Error.h"
- #include "llvm/Support/FileUtilities.h"
- #include "llvm/Support/Path.h"
- #include "llvm/Support/xxhash.h"
- namespace llvm {
- static std::string uniqueKey(llvm::StringRef S) { return utostr(xxHash64(S)); }
- // Returns a binary BuildID as a normalized hex string.
- // Uses lowercase for compatibility with common debuginfod servers.
- static std::string buildIDToString(BuildIDRef ID) {
- return llvm::toHex(ID, /*LowerCase=*/true);
- }
- Expected<SmallVector<StringRef>> getDefaultDebuginfodUrls() {
- const char *DebuginfodUrlsEnv = std::getenv("DEBUGINFOD_URLS");
- if (DebuginfodUrlsEnv == nullptr)
- return SmallVector<StringRef>();
- SmallVector<StringRef> DebuginfodUrls;
- StringRef(DebuginfodUrlsEnv).split(DebuginfodUrls, " ");
- return DebuginfodUrls;
- }
- Expected<std::string> getDefaultDebuginfodCacheDirectory() {
- if (const char *CacheDirectoryEnv = std::getenv("DEBUGINFOD_CACHE_PATH"))
- return CacheDirectoryEnv;
- SmallString<64> CacheDirectory;
- if (!sys::path::cache_directory(CacheDirectory))
- return createStringError(
- errc::io_error, "Unable to determine appropriate cache directory.");
- sys::path::append(CacheDirectory, "llvm-debuginfod", "client");
- return std::string(CacheDirectory);
- }
- std::chrono::milliseconds getDefaultDebuginfodTimeout() {
- long Timeout;
- const char *DebuginfodTimeoutEnv = std::getenv("DEBUGINFOD_TIMEOUT");
- if (DebuginfodTimeoutEnv &&
- to_integer(StringRef(DebuginfodTimeoutEnv).trim(), Timeout, 10))
- return std::chrono::milliseconds(Timeout * 1000);
- return std::chrono::milliseconds(90 * 1000);
- }
- /// The following functions fetch a debuginfod artifact to a file in a local
- /// cache and return the cached file path. They first search the local cache,
- /// followed by the debuginfod servers.
- Expected<std::string> getCachedOrDownloadSource(BuildIDRef ID,
- StringRef SourceFilePath) {
- SmallString<64> UrlPath;
- sys::path::append(UrlPath, sys::path::Style::posix, "buildid",
- buildIDToString(ID), "source",
- sys::path::convert_to_slash(SourceFilePath));
- return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath);
- }
- Expected<std::string> getCachedOrDownloadExecutable(BuildIDRef ID) {
- SmallString<64> UrlPath;
- sys::path::append(UrlPath, sys::path::Style::posix, "buildid",
- buildIDToString(ID), "executable");
- return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath);
- }
- Expected<std::string> getCachedOrDownloadDebuginfo(BuildIDRef ID) {
- SmallString<64> UrlPath;
- sys::path::append(UrlPath, sys::path::Style::posix, "buildid",
- buildIDToString(ID), "debuginfo");
- return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath);
- }
- // General fetching function.
- Expected<std::string> getCachedOrDownloadArtifact(StringRef UniqueKey,
- StringRef UrlPath) {
- SmallString<10> CacheDir;
- Expected<std::string> CacheDirOrErr = getDefaultDebuginfodCacheDirectory();
- if (!CacheDirOrErr)
- return CacheDirOrErr.takeError();
- CacheDir = *CacheDirOrErr;
- Expected<SmallVector<StringRef>> DebuginfodUrlsOrErr =
- getDefaultDebuginfodUrls();
- if (!DebuginfodUrlsOrErr)
- return DebuginfodUrlsOrErr.takeError();
- SmallVector<StringRef> &DebuginfodUrls = *DebuginfodUrlsOrErr;
- return getCachedOrDownloadArtifact(UniqueKey, UrlPath, CacheDir,
- DebuginfodUrls,
- getDefaultDebuginfodTimeout());
- }
- Expected<std::string> getCachedOrDownloadArtifact(
- StringRef UniqueKey, StringRef UrlPath, StringRef CacheDirectoryPath,
- ArrayRef<StringRef> DebuginfodUrls, std::chrono::milliseconds Timeout) {
- SmallString<64> AbsCachedArtifactPath;
- sys::path::append(AbsCachedArtifactPath, CacheDirectoryPath,
- "llvmcache-" + UniqueKey);
- Expected<FileCache> CacheOrErr =
- localCache("Debuginfod-client", ".debuginfod-client", CacheDirectoryPath);
- if (!CacheOrErr)
- return CacheOrErr.takeError();
- FileCache Cache = *CacheOrErr;
- // We choose an arbitrary Task parameter as we do not make use of it.
- unsigned Task = 0;
- Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, UniqueKey);
- if (!CacheAddStreamOrErr)
- return CacheAddStreamOrErr.takeError();
- AddStreamFn &CacheAddStream = *CacheAddStreamOrErr;
- if (!CacheAddStream)
- return std::string(AbsCachedArtifactPath);
- // The artifact was not found in the local cache, query the debuginfod
- // servers.
- if (!HTTPClient::isAvailable())
- return createStringError(errc::io_error,
- "No working HTTP client is available.");
- if (!HTTPClient::IsInitialized)
- return createStringError(
- errc::io_error,
- "A working HTTP client is available, but it is not initialized. To "
- "allow Debuginfod to make HTTP requests, call HTTPClient::initialize() "
- "at the beginning of main.");
- HTTPClient Client;
- Client.setTimeout(Timeout);
- for (StringRef ServerUrl : DebuginfodUrls) {
- SmallString<64> ArtifactUrl;
- sys::path::append(ArtifactUrl, sys::path::Style::posix, ServerUrl, UrlPath);
- Expected<HTTPResponseBuffer> ResponseOrErr = Client.get(ArtifactUrl);
- if (!ResponseOrErr)
- return ResponseOrErr.takeError();
- HTTPResponseBuffer &Response = *ResponseOrErr;
- if (Response.Code != 200)
- continue;
- // We have retrieved the artifact from this server, and now add it to the
- // file cache.
- Expected<std::unique_ptr<CachedFileStream>> FileStreamOrErr =
- CacheAddStream(Task);
- if (!FileStreamOrErr)
- return FileStreamOrErr.takeError();
- std::unique_ptr<CachedFileStream> &FileStream = *FileStreamOrErr;
- if (!Response.Body)
- return createStringError(
- errc::io_error, "Unallocated MemoryBuffer in HTTPResponseBuffer.");
- *FileStream->OS << StringRef(Response.Body->getBufferStart(),
- Response.Body->getBufferSize());
- // Return the path to the artifact on disk.
- return std::string(AbsCachedArtifactPath);
- }
- return createStringError(errc::argument_out_of_domain, "build id not found");
- }
- } // namespace llvm
|