[llvm] Errorize DebuginfodFetcher for inspection at call-sites (#191191)

Failure to fetch debuginfod is rarely an error, but there are cases where
we want to distinguish error reasons down the line, for example in order
to test connection timeouts.
This commit is contained in:
Stefan Gränitz
2026-04-21 12:24:53 +02:00
committed by GitHub
parent 9584e9c9b2
commit 337ad44a3e
9 changed files with 57 additions and 37 deletions

View File

@@ -16,7 +16,6 @@
#define LLVM_DEBUGINFOD_DIFETCHER_H
#include "llvm/Object/BuildID.h"
#include <optional>
namespace llvm {
@@ -28,7 +27,7 @@ public:
/// Fetches the given Build ID using debuginfod and returns a local path to
/// the resulting file.
std::optional<std::string> fetch(object::BuildIDRef BuildID) const override;
Expected<std::string> fetch(object::BuildIDRef BuildID) const override;
};
} // namespace llvm

View File

@@ -18,6 +18,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
namespace llvm {
namespace object {
@@ -44,7 +45,7 @@ public:
virtual ~BuildIDFetcher() = default;
/// Returns the path to the debug file with the given build ID.
virtual std::optional<std::string> fetch(BuildIDRef BuildID) const;
virtual Expected<std::string> fetch(BuildIDRef BuildID) const;
private:
const std::vector<std::string> DebugFileDirectories;

View File

@@ -490,14 +490,17 @@ bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,
}
if (!BIDFetcher)
return false;
if (std::optional<std::string> Path = BIDFetcher->fetch(BuildID)) {
Expected<std::string> Path = BIDFetcher->fetch(BuildID);
if (Path) {
Result = *Path;
auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result});
assert(InsertResult.second);
(void)InsertResult;
return true;
}
// Failure to fetch debuginfod is rarely an error and most users will not care
// why this failed.
consumeError(Path.takeError());
return false;
}

View File

@@ -15,17 +15,19 @@
#include "llvm/Debuginfod/BuildIDFetcher.h"
#include "llvm/Debuginfod/Debuginfod.h"
#include "llvm/Support/Error.h"
using namespace llvm;
std::optional<std::string>
Expected<std::string>
DebuginfodFetcher::fetch(ArrayRef<uint8_t> BuildID) const {
if (std::optional<std::string> Path = BuildIDFetcher::fetch(BuildID))
return std::move(*Path);
Expected<std::string> PathOrErr = getCachedOrDownloadDebuginfo(BuildID);
if (PathOrErr)
return *PathOrErr;
consumeError(PathOrErr.takeError());
return std::nullopt;
Expected<std::string> Path = BuildIDFetcher::fetch(BuildID);
if (Path)
return Path;
// Most users will not care why this failed.
assert(errorToErrorCode(Path.takeError()) ==
std::errc::no_such_file_or_directory &&
"BuildIDFetcher::fetch() failed in an unexpected way");
consumeError(Path.takeError());
return getCachedOrDownloadDebuginfo(BuildID);
}

View File

@@ -15,6 +15,7 @@
#include "llvm/Object/BuildID.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -79,7 +80,7 @@ BuildIDRef llvm::object::getBuildID(const ObjectFile *Obj) {
return {};
}
std::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const {
Expected<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const {
auto GetDebugPath = [&](StringRef Directory) {
SmallString<128> Path{Directory};
sys::path::append(Path, ".build-id",
@@ -108,5 +109,8 @@ std::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const {
return std::string(Path);
}
}
return std::nullopt;
return createStringError(
make_error_code(std::errc::no_such_file_or_directory),
"could not find debug file for build ID '" +
llvm::toHex(BuildID, /*LowerCase=*/true) + "'");
}

View File

@@ -1106,20 +1106,18 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
}
for (object::BuildIDRef BinaryID : BinaryIDsToFetch) {
std::optional<std::string> PathOpt = BIDFetcher->fetch(BinaryID);
if (PathOpt) {
std::string Path = std::move(*PathOpt);
Expected<std::string> Path = BIDFetcher->fetch(BinaryID);
if (Path) {
StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
if (Error E = loadFromFile(Path, Arch, CompilationDir, ProfileReaderRef,
*Coverage, DataFound))
if (Error E = loadFromFile(*Path, Arch, CompilationDir,
ProfileReaderRef, *Coverage, DataFound))
return std::move(E);
} else if (CheckBinaryIDs) {
return createFileError(
ProfileFilename.value(),
createStringError(errc::no_such_file_or_directory,
"Missing binary ID: " +
llvm::toHex(BinaryID, /*LowerCase=*/true)));
}
if (CheckBinaryIDs) {
return createFileError(ProfileFilename.value(), Path.takeError());
}
// Ignore error and continue.
consumeError(Path.takeError());
}
}

View File

@@ -114,7 +114,6 @@ llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind,
const object::BuildIDFetcher *BIDFetcher,
const ArrayRef<object::BuildID> BIs) {
std::optional<std::string> Path;
if (BIDFetcher) {
if (BIs.empty())
return make_error<InstrProfError>(
@@ -127,12 +126,18 @@ InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind,
"unsupported profile binary correlation when there are multiple "
"build IDs in a profile");
Path = BIDFetcher->fetch(BIs.front());
if (!Path)
Expected<std::string> Path = BIDFetcher->fetch(BIs.front());
if (!Path) {
// Propagate as InstrProf specific error type.
assert(errorToErrorCode(Path.takeError()) ==
std::errc::no_such_file_or_directory &&
"BuildIDFetcher::fetch() failed in an unexpected way");
consumeError(Path.takeError());
return make_error<InstrProfError>(
instrprof_error::unable_to_correlate_profile,
"Missing build ID: " + llvm::toHex(BIs.front(),
/*LowerCase=*/true));
}
Filename = *Path;
}

View File

@@ -152,10 +152,12 @@ int llvm_debuginfod_find_main(int argc, char **argv,
// Find a debug file in local build ID directories and via debuginfod.
std::string fetchDebugInfo(object::BuildIDRef BuildID) {
if (std::optional<std::string> Path =
DebuginfodFetcher(DebugFileDirectory).fetch(BuildID))
return *Path;
errs() << "Build ID " << llvm::toHex(BuildID, /*Lowercase=*/true)
Expected<std::string> PathOrErr =
DebuginfodFetcher(DebugFileDirectory).fetch(BuildID);
if (PathOrErr)
return *PathOrErr;
errs() << "Build ID " << llvm::toHex(BuildID, /*Lowercase=*/true) << ": "
<< " could not be found.\n";
consumeError(PathOrErr.takeError());
exit(1);
}

View File

@@ -1743,9 +1743,13 @@ fetchBinaryByBuildID(const ObjectFile &Obj) {
object::BuildIDRef BuildID = getBuildID(&Obj);
if (BuildID.empty())
return std::nullopt;
std::optional<std::string> Path = BIDFetcher->fetch(BuildID);
if (!Path)
Expected<std::string> Path = BIDFetcher->fetch(BuildID);
if (!Path) {
// Failure to fetch debuginfod is rarely an error and most users will not
// care why this failed.
consumeError(Path.takeError());
return std::nullopt;
}
Expected<OwningBinary<Binary>> DebugBinary = createBinary(*Path);
if (!DebugBinary) {
reportWarning(toString(DebugBinary.takeError()), *Path);
@@ -3841,8 +3845,10 @@ static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) {
// Look up any provided build IDs, then append them to the input filenames.
for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_build_id)) {
object::BuildID BuildID = parseBuildIDArg(A);
std::optional<std::string> Path = BIDFetcher->fetch(BuildID);
Expected<std::string> Path = BIDFetcher->fetch(BuildID);
if (!Path) {
// Most users will not care why this failed.
consumeError(Path.takeError());
reportCmdLineError(A->getSpelling() + ": could not find build ID '" +
A->getValue() + "'");
}