Index: llvm/include/llvm/Debuginfod/Debuginfod.h =================================================================== --- /dev/null +++ llvm/include/llvm/Debuginfod/Debuginfod.h @@ -0,0 +1,44 @@ +//===-- llvm/Debuginfod/Debuginfod.h - Debuginfod client --------*- 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" +#include "llvm/Support/MemoryBuffer.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 }; + +/// Fetch a debuginfod asset to a file in a local cache and return the cached +/// file path. First queries the local cache in the given directory path, +/// followed by the debuginfod servers at the given urls for the specified +/// type of information about the given build ID. Source files are specified +/// by their absolute path provided in the Description. A callback function +/// may optionally be provided for further processing of the fetched asset. +Expected> fetchDebuginfo( + StringRef CacheDirectoryPath, ArrayRef DebuginfodUrls, + StringRef BuildID, DebuginfodAssetType Type, StringRef Description = "", + std::function)> AddBuffer = + [](size_t Task, std::unique_ptr MB) {}); + +} // end namespace llvm + +#endif Index: llvm/lib/CMakeLists.txt =================================================================== --- llvm/lib/CMakeLists.txt +++ llvm/lib/CMakeLists.txt @@ -26,6 +26,7 @@ add_subdirectory(Option) add_subdirectory(Remarks) add_subdirectory(DebugInfo) +add_subdirectory(Debuginfod) add_subdirectory(DWP) add_subdirectory(ExecutionEngine) add_subdirectory(Target) Index: llvm/lib/Debuginfod/CMakeLists.txt =================================================================== --- /dev/null +++ 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() Index: llvm/lib/Debuginfod/Debuginfod.cpp =================================================================== --- /dev/null +++ llvm/lib/Debuginfod/Debuginfod.cpp @@ -0,0 +1,103 @@ +//===-- 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 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/Caching.h" +#include "llvm/Support/CurlHTTPClient.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/HTTPClient.h" +#include "llvm/Support/xxhash.h" + +using namespace llvm; + +#define DEBUG_TYPE "DEBUGINFOD" + +Expected> llvm::fetchDebuginfo( + StringRef CacheDirectoryPath, ArrayRef DebuginfodUrls, + StringRef BuildID, DebuginfodAssetType Type, StringRef Description, + std::function)> AddBuffer) { + LLVM_DEBUG(dbgs() << "fetching info, debuginfod urls size = " + << DebuginfodUrls.size() << "\n";); + std::string Suffix; + switch (Type) { + case DebuginfodAssetType::Executable: + Suffix = "executable"; + break; + case DebuginfodAssetType::Debuginfo: + Suffix = "debuginfo"; + break; + case DebuginfodAssetType::Source: + // Description is the absolute source path + Suffix = "source" + Description.str(); + break; + } + + std::string UniqueKey = utostr(xxHash64((BuildID + Suffix).str())); + + Expected CacheOrErr = localCache( + "Debuginfod-client", ".debuginfod-client", CacheDirectoryPath, AddBuffer); + if (Error Err = CacheOrErr.takeError()) + return Err; + + NativeObjectCache &Cache = *CacheOrErr; + + // We choose an arbitrary Task parameter as we do not make use of it. + unsigned Task = 0; + AddStreamFn CacheAddStream = Cache(Task, UniqueKey); + + SmallString<64> AbsCachedAssetPath; + sys::path::append(AbsCachedAssetPath, CacheDirectoryPath, + "llvmcache-" + UniqueKey); + + if (!CacheAddStream) { + LLVM_DEBUG(dbgs() << "cache hit\n";); + return AbsCachedAssetPath; + } + + LLVM_DEBUG(dbgs() << "cache miss, UniqueKey = " << UniqueKey << "\n";); + + // The asset was not found in the local cache, so we must query + // the debuginfod servers. + for (const StringRef &ServerUrl : DebuginfodUrls) { + SmallString<64> AssetUrl; + sys::path::append(AssetUrl, sys::path::Style::posix, ServerUrl, "buildid", + BuildID, Suffix); + + Expected BufferOrErr = CurlHTTPClient().get(AssetUrl); + if (Error Err = BufferOrErr.takeError()) + return Err; + HTTPResponseBuffer &Buf = *BufferOrErr; + if (Buf.Code != 200) + continue; + + // We have retrieved the asset from this server and now add it to the file + // cache. + auto Stream = CacheAddStream(Task); + assert(Buf.Body && "Unallocated MemoryBuffer in HTTPResponseBuffer."); + *Stream->OS << StringRef(Buf.Body->getBufferStart(), + Buf.Body->getBufferSize()); + + // Return the path to the asset on disk. + return AbsCachedAssetPath; + } + + return createStringError(errc::argument_out_of_domain, "build id not found"); +} Index: llvm/unittests/CMakeLists.txt =================================================================== --- llvm/unittests/CMakeLists.txt +++ llvm/unittests/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(Bitstream) add_subdirectory(CodeGen) add_subdirectory(DebugInfo) +add_subdirectory(Debuginfod) add_subdirectory(Demangle) add_subdirectory(ExecutionEngine) add_subdirectory(FileCheck) Index: llvm/unittests/Debuginfod/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/unittests/Debuginfod/CMakeLists.txt @@ -0,0 +1,11 @@ +if (LLVM_ENABLE_CURL) + set(LLVM_LINK_COMPONENTS + Debuginfod + ) + + add_llvm_unittest(DebuginfodTests + DebuginfodTests.cpp + ) + + target_link_libraries(DebuginfodTests PRIVATE LLVMTestingSupport) +endif() Index: llvm/unittests/Debuginfod/DebuginfodTests.cpp =================================================================== --- /dev/null +++ llvm/unittests/Debuginfod/DebuginfodTests.cpp @@ -0,0 +1,18 @@ +//===-- 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 "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +TEST(DebuginfodTests, noDebuginfodUrlsFetchInfoTest) { + EXPECT_THAT_EXPECTED(fetchDebuginfo("./", {}, "fakeBuildId", + llvm::DebuginfodAssetType::Executable, + ""), + llvm::Failed()); +}