//===- 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" using namespace llvm; using namespace llvm::object; namespace { template BuildIDRef getBuildID(const ELFFile &Obj) { auto findBuildID = [&Obj](const auto &ShdrOrPhdr, uint64_t Alignment) -> std::optional { Error Err = Error::success(); for (auto N : Obj.notes(ShdrOrPhdr, Err)) if (N.getType() == ELF::NT_GNU_BUILD_ID && N.getName() == ELF::ELF_NOTE_GNU) return N.getDesc(Alignment); consumeError(std::move(Err)); return std::nullopt; }; auto Sections = cantFail(Obj.sections()); for (const auto &S : Sections) { if (S.sh_type != ELF::SHT_NOTE) continue; if (std::optional ShdrRes = findBuildID(S, S.sh_addralign)) return ShdrRes.value(); } auto PhdrsOrErr = Obj.program_headers(); if (!PhdrsOrErr) { consumeError(PhdrsOrErr.takeError()); return {}; } for (const auto &P : *PhdrsOrErr) { if (P.p_type != ELF::PT_NOTE) continue; if (std::optional PhdrRes = findBuildID(P, P.p_align)) return PhdrRes.value(); } return {}; } } // namespace BuildID llvm::object::parseBuildID(StringRef Str) { std::string Bytes; if (!tryGetFromHex(Str, Bytes)) return {}; ArrayRef BuildID(reinterpret_cast(Bytes.data()), Bytes.size()); return SmallVector(BuildID); } BuildIDRef llvm::object::getBuildID(const ObjectFile *Obj) { if (auto *O = dyn_cast>(Obj)) return ::getBuildID(O->getELFFile()); if (auto *O = dyn_cast>(Obj)) return ::getBuildID(O->getELFFile()); if (auto *O = dyn_cast>(Obj)) return ::getBuildID(O->getELFFile()); if (auto *O = dyn_cast>(Obj)) return ::getBuildID(O->getELFFile()); return {}; } std::optional 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 /.build-id/../... SmallString<128> Path = GetDebugPath(Directory); if (llvm::sys::fs::exists(Path)) return std::string(Path); } } return std::nullopt; }