113 lines · cpp
1//===- llvm/Object/BuildID.cpp - Build ID ---------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file defines a library for handling Build IDs and using them to find11/// debug info.12///13//===----------------------------------------------------------------------===//14 15#include "llvm/Object/BuildID.h"16 17#include "llvm/Object/ELFObjectFile.h"18#include "llvm/Support/FileSystem.h"19#include "llvm/Support/Path.h"20 21using namespace llvm;22using namespace llvm::object;23 24namespace {25 26template <typename ELFT> BuildIDRef getBuildID(const ELFFile<ELFT> &Obj) {27 auto findBuildID = [&Obj](const auto &ShdrOrPhdr,28 uint64_t Alignment) -> std::optional<BuildIDRef> {29 Error Err = Error::success();30 for (auto N : Obj.notes(ShdrOrPhdr, Err))31 if (N.getType() == ELF::NT_GNU_BUILD_ID &&32 N.getName() == ELF::ELF_NOTE_GNU)33 return N.getDesc(Alignment);34 consumeError(std::move(Err));35 return std::nullopt;36 };37 38 auto Sections = cantFail(Obj.sections());39 for (const auto &S : Sections) {40 if (S.sh_type != ELF::SHT_NOTE)41 continue;42 if (std::optional<BuildIDRef> ShdrRes = findBuildID(S, S.sh_addralign))43 return ShdrRes.value();44 }45 auto PhdrsOrErr = Obj.program_headers();46 if (!PhdrsOrErr) {47 consumeError(PhdrsOrErr.takeError());48 return {};49 }50 for (const auto &P : *PhdrsOrErr) {51 if (P.p_type != ELF::PT_NOTE)52 continue;53 if (std::optional<BuildIDRef> PhdrRes = findBuildID(P, P.p_align))54 return PhdrRes.value();55 }56 return {};57}58 59} // namespace60 61BuildID llvm::object::parseBuildID(StringRef Str) {62 std::string Bytes;63 if (!tryGetFromHex(Str, Bytes))64 return {};65 ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()),66 Bytes.size());67 return SmallVector<uint8_t>(BuildID);68}69 70BuildIDRef llvm::object::getBuildID(const ObjectFile *Obj) {71 if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))72 return ::getBuildID(O->getELFFile());73 if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))74 return ::getBuildID(O->getELFFile());75 if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))76 return ::getBuildID(O->getELFFile());77 if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))78 return ::getBuildID(O->getELFFile());79 return {};80}81 82std::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const {83 auto GetDebugPath = [&](StringRef Directory) {84 SmallString<128> Path{Directory};85 sys::path::append(Path, ".build-id",86 llvm::toHex(BuildID[0], /*LowerCase=*/true),87 llvm::toHex(BuildID.slice(1), /*LowerCase=*/true));88 Path += ".debug";89 return Path;90 };91 if (DebugFileDirectories.empty()) {92 SmallString<128> Path = GetDebugPath(93#if defined(__NetBSD__)94 // Try /usr/libdata/debug/.build-id/../...95 "/usr/libdata/debug"96#else97 // Try /usr/lib/debug/.build-id/../...98 "/usr/lib/debug"99#endif100 );101 if (llvm::sys::fs::exists(Path))102 return std::string(Path);103 } else {104 for (const auto &Directory : DebugFileDirectories) {105 // Try <debug-file-directory>/.build-id/../...106 SmallString<128> Path = GetDebugPath(Directory);107 if (llvm::sys::fs::exists(Path))108 return std::string(Path);109 }110 }111 return std::nullopt;112}113