1e61d89efSDaniel Thornburgh //===- llvm/Object/BuildID.cpp - Build ID ---------------------------------===// 2e61d89efSDaniel Thornburgh // 3e61d89efSDaniel Thornburgh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e61d89efSDaniel Thornburgh // See https://llvm.org/LICENSE.txt for license information. 5e61d89efSDaniel Thornburgh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e61d89efSDaniel Thornburgh // 7e61d89efSDaniel Thornburgh //===----------------------------------------------------------------------===// 8e61d89efSDaniel Thornburgh /// 9e61d89efSDaniel Thornburgh /// \file 10e61d89efSDaniel Thornburgh /// This file defines a library for handling Build IDs and using them to find 11e61d89efSDaniel Thornburgh /// debug info. 12e61d89efSDaniel Thornburgh /// 13e61d89efSDaniel Thornburgh //===----------------------------------------------------------------------===// 14e61d89efSDaniel Thornburgh 15e61d89efSDaniel Thornburgh #include "llvm/Object/BuildID.h" 16e61d89efSDaniel Thornburgh 17e61d89efSDaniel Thornburgh #include "llvm/Object/ELFObjectFile.h" 18e61d89efSDaniel Thornburgh #include "llvm/Support/FileSystem.h" 19e61d89efSDaniel Thornburgh #include "llvm/Support/Path.h" 20e61d89efSDaniel Thornburgh 219812948dSDaniel Thornburgh using namespace llvm; 229812948dSDaniel Thornburgh using namespace llvm::object; 23e61d89efSDaniel Thornburgh 24e61d89efSDaniel Thornburgh namespace { 25e61d89efSDaniel Thornburgh 269812948dSDaniel Thornburgh template <typename ELFT> BuildIDRef getBuildID(const ELFFile<ELFT> &Obj) { 27e61d89efSDaniel Thornburgh auto PhdrsOrErr = Obj.program_headers(); 28e61d89efSDaniel Thornburgh if (!PhdrsOrErr) { 29e61d89efSDaniel Thornburgh consumeError(PhdrsOrErr.takeError()); 30e61d89efSDaniel Thornburgh return {}; 31e61d89efSDaniel Thornburgh } 32e61d89efSDaniel Thornburgh for (const auto &P : *PhdrsOrErr) { 33e61d89efSDaniel Thornburgh if (P.p_type != ELF::PT_NOTE) 34e61d89efSDaniel Thornburgh continue; 35e61d89efSDaniel Thornburgh Error Err = Error::success(); 36e61d89efSDaniel Thornburgh for (auto N : Obj.notes(P, Err)) 37e61d89efSDaniel Thornburgh if (N.getType() == ELF::NT_GNU_BUILD_ID && 38e61d89efSDaniel Thornburgh N.getName() == ELF::ELF_NOTE_GNU) 39689715f3SFangrui Song return N.getDesc(P.p_align); 40e61d89efSDaniel Thornburgh consumeError(std::move(Err)); 41e61d89efSDaniel Thornburgh } 42e61d89efSDaniel Thornburgh return {}; 43e61d89efSDaniel Thornburgh } 44e61d89efSDaniel Thornburgh 45e61d89efSDaniel Thornburgh } // namespace 46e61d89efSDaniel Thornburgh 479812948dSDaniel Thornburgh BuildID llvm::object::parseBuildID(StringRef Str) { 489812948dSDaniel Thornburgh std::string Bytes; 499812948dSDaniel Thornburgh if (!tryGetFromHex(Str, Bytes)) 509812948dSDaniel Thornburgh return {}; 519812948dSDaniel Thornburgh ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()), 529812948dSDaniel Thornburgh Bytes.size()); 537df9da7dSKazu Hirata return SmallVector<uint8_t>(BuildID); 549812948dSDaniel Thornburgh } 559812948dSDaniel Thornburgh 569812948dSDaniel Thornburgh BuildIDRef llvm::object::getBuildID(const ObjectFile *Obj) { 57e61d89efSDaniel Thornburgh if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj)) 589812948dSDaniel Thornburgh return ::getBuildID(O->getELFFile()); 59e61d89efSDaniel Thornburgh if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj)) 609812948dSDaniel Thornburgh return ::getBuildID(O->getELFFile()); 61e61d89efSDaniel Thornburgh if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj)) 629812948dSDaniel Thornburgh return ::getBuildID(O->getELFFile()); 63e61d89efSDaniel Thornburgh if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj)) 649812948dSDaniel Thornburgh return ::getBuildID(O->getELFFile()); 65*e03f4271SJay Foad return {}; 66e61d89efSDaniel Thornburgh } 67e61d89efSDaniel Thornburgh 68c302fb5cSFangrui Song std::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const { 69e61d89efSDaniel Thornburgh auto GetDebugPath = [&](StringRef Directory) { 70e61d89efSDaniel Thornburgh SmallString<128> Path{Directory}; 71e61d89efSDaniel Thornburgh sys::path::append(Path, ".build-id", 72e61d89efSDaniel Thornburgh llvm::toHex(BuildID[0], /*LowerCase=*/true), 73e61d89efSDaniel Thornburgh llvm::toHex(BuildID.slice(1), /*LowerCase=*/true)); 74e61d89efSDaniel Thornburgh Path += ".debug"; 75e61d89efSDaniel Thornburgh return Path; 76e61d89efSDaniel Thornburgh }; 77e61d89efSDaniel Thornburgh if (DebugFileDirectories.empty()) { 78e61d89efSDaniel Thornburgh SmallString<128> Path = GetDebugPath( 79e61d89efSDaniel Thornburgh #if defined(__NetBSD__) 80e61d89efSDaniel Thornburgh // Try /usr/libdata/debug/.build-id/../... 81e61d89efSDaniel Thornburgh "/usr/libdata/debug" 82e61d89efSDaniel Thornburgh #else 83e61d89efSDaniel Thornburgh // Try /usr/lib/debug/.build-id/../... 84e61d89efSDaniel Thornburgh "/usr/lib/debug" 85e61d89efSDaniel Thornburgh #endif 86e61d89efSDaniel Thornburgh ); 87e61d89efSDaniel Thornburgh if (llvm::sys::fs::exists(Path)) 88e61d89efSDaniel Thornburgh return std::string(Path); 89e61d89efSDaniel Thornburgh } else { 90e61d89efSDaniel Thornburgh for (const auto &Directory : DebugFileDirectories) { 91e61d89efSDaniel Thornburgh // Try <debug-file-directory>/.build-id/../... 92e61d89efSDaniel Thornburgh SmallString<128> Path = GetDebugPath(Directory); 93e61d89efSDaniel Thornburgh if (llvm::sys::fs::exists(Path)) 94e61d89efSDaniel Thornburgh return std::string(Path); 95e61d89efSDaniel Thornburgh } 96e61d89efSDaniel Thornburgh } 97aadaafacSKazu Hirata return std::nullopt; 98e61d89efSDaniel Thornburgh } 99