blob: 795c22e769aa559fa039d2b41d57cd6b54efd333 [file] [log] [blame]
//===- llvm/Object/BuildID.cpp - Build ID ---------------------------------===//
//
// 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 a library for handling Build IDs and using them to find
/// debug info.
///
//===----------------------------------------------------------------------===//
#include "llvm/Object/BuildID.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
namespace llvm {
namespace object {
namespace {
template <typename ELFT>
std::optional<BuildIDRef> getBuildID(const ELFFile<ELFT> &Obj) {
auto PhdrsOrErr = Obj.program_headers();
if (!PhdrsOrErr) {
consumeError(PhdrsOrErr.takeError());
return {};
}
for (const auto &P : *PhdrsOrErr) {
if (P.p_type != ELF::PT_NOTE)
continue;
Error Err = Error::success();
for (auto N : Obj.notes(P, Err))
if (N.getType() == ELF::NT_GNU_BUILD_ID &&
N.getName() == ELF::ELF_NOTE_GNU)
return N.getDesc();
consumeError(std::move(Err));
}
return {};
}
} // namespace
std::optional<BuildIDRef> getBuildID(const ObjectFile *Obj) {
if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
return getBuildID(O->getELFFile());
if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
return getBuildID(O->getELFFile());
if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
return getBuildID(O->getELFFile());
if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
return getBuildID(O->getELFFile());
return std::nullopt;
}
std::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const {
auto GetDebugPath = [&](StringRef Directory) {
SmallString<128> Path{Directory};
sys::path::append(Path, ".build-id",
llvm::toHex(BuildID[0], /*LowerCase=*/true),
llvm::toHex(BuildID.slice(1), /*LowerCase=*/true));
Path += ".debug";
return Path;
};
if (DebugFileDirectories.empty()) {
SmallString<128> Path = GetDebugPath(
#if defined(__NetBSD__)
// Try /usr/libdata/debug/.build-id/../...
"/usr/libdata/debug"
#else
// Try /usr/lib/debug/.build-id/../...
"/usr/lib/debug"
#endif
);
if (llvm::sys::fs::exists(Path))
return std::string(Path);
} else {
for (const auto &Directory : DebugFileDirectories) {
// Try <debug-file-directory>/.build-id/../...
SmallString<128> Path = GetDebugPath(Directory);
if (llvm::sys::fs::exists(Path))
return std::string(Path);
}
}
return std::nullopt;
}
} // namespace object
} // namespace llvm