1*d415bd75Srobert //===- llvm/Object/BuildID.cpp - Build ID ---------------------------------===// 2*d415bd75Srobert // 3*d415bd75Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*d415bd75Srobert // See https://llvm.org/LICENSE.txt for license information. 5*d415bd75Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*d415bd75Srobert // 7*d415bd75Srobert //===----------------------------------------------------------------------===// 8*d415bd75Srobert /// 9*d415bd75Srobert /// \file 10*d415bd75Srobert /// This file defines a library for handling Build IDs and using them to find 11*d415bd75Srobert /// debug info. 12*d415bd75Srobert /// 13*d415bd75Srobert //===----------------------------------------------------------------------===// 14*d415bd75Srobert 15*d415bd75Srobert #include "llvm/Object/BuildID.h" 16*d415bd75Srobert 17*d415bd75Srobert #include "llvm/Object/ELFObjectFile.h" 18*d415bd75Srobert #include "llvm/Support/FileSystem.h" 19*d415bd75Srobert #include "llvm/Support/Path.h" 20*d415bd75Srobert 21*d415bd75Srobert namespace llvm { 22*d415bd75Srobert namespace object { 23*d415bd75Srobert 24*d415bd75Srobert namespace { 25*d415bd75Srobert 26*d415bd75Srobert template <typename ELFT> getBuildID(const ELFFile<ELFT> & Obj)27*d415bd75Srobertstd::optional<BuildIDRef> getBuildID(const ELFFile<ELFT> &Obj) { 28*d415bd75Srobert auto PhdrsOrErr = Obj.program_headers(); 29*d415bd75Srobert if (!PhdrsOrErr) { 30*d415bd75Srobert consumeError(PhdrsOrErr.takeError()); 31*d415bd75Srobert return {}; 32*d415bd75Srobert } 33*d415bd75Srobert for (const auto &P : *PhdrsOrErr) { 34*d415bd75Srobert if (P.p_type != ELF::PT_NOTE) 35*d415bd75Srobert continue; 36*d415bd75Srobert Error Err = Error::success(); 37*d415bd75Srobert for (auto N : Obj.notes(P, Err)) 38*d415bd75Srobert if (N.getType() == ELF::NT_GNU_BUILD_ID && 39*d415bd75Srobert N.getName() == ELF::ELF_NOTE_GNU) 40*d415bd75Srobert return N.getDesc(); 41*d415bd75Srobert consumeError(std::move(Err)); 42*d415bd75Srobert } 43*d415bd75Srobert return {}; 44*d415bd75Srobert } 45*d415bd75Srobert 46*d415bd75Srobert } // namespace 47*d415bd75Srobert getBuildID(const ObjectFile * Obj)48*d415bd75Srobertstd::optional<BuildIDRef> getBuildID(const ObjectFile *Obj) { 49*d415bd75Srobert if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj)) 50*d415bd75Srobert return getBuildID(O->getELFFile()); 51*d415bd75Srobert if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj)) 52*d415bd75Srobert return getBuildID(O->getELFFile()); 53*d415bd75Srobert if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj)) 54*d415bd75Srobert return getBuildID(O->getELFFile()); 55*d415bd75Srobert if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj)) 56*d415bd75Srobert return getBuildID(O->getELFFile()); 57*d415bd75Srobert return std::nullopt; 58*d415bd75Srobert } 59*d415bd75Srobert fetch(BuildIDRef BuildID) const60*d415bd75Srobertstd::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const { 61*d415bd75Srobert auto GetDebugPath = [&](StringRef Directory) { 62*d415bd75Srobert SmallString<128> Path{Directory}; 63*d415bd75Srobert sys::path::append(Path, ".build-id", 64*d415bd75Srobert llvm::toHex(BuildID[0], /*LowerCase=*/true), 65*d415bd75Srobert llvm::toHex(BuildID.slice(1), /*LowerCase=*/true)); 66*d415bd75Srobert Path += ".debug"; 67*d415bd75Srobert return Path; 68*d415bd75Srobert }; 69*d415bd75Srobert if (DebugFileDirectories.empty()) { 70*d415bd75Srobert SmallString<128> Path = GetDebugPath( 71*d415bd75Srobert #if defined(__NetBSD__) 72*d415bd75Srobert // Try /usr/libdata/debug/.build-id/../... 73*d415bd75Srobert "/usr/libdata/debug" 74*d415bd75Srobert #else 75*d415bd75Srobert // Try /usr/lib/debug/.build-id/../... 76*d415bd75Srobert "/usr/lib/debug" 77*d415bd75Srobert #endif 78*d415bd75Srobert ); 79*d415bd75Srobert if (llvm::sys::fs::exists(Path)) 80*d415bd75Srobert return std::string(Path); 81*d415bd75Srobert } else { 82*d415bd75Srobert for (const auto &Directory : DebugFileDirectories) { 83*d415bd75Srobert // Try <debug-file-directory>/.build-id/../... 84*d415bd75Srobert SmallString<128> Path = GetDebugPath(Directory); 85*d415bd75Srobert if (llvm::sys::fs::exists(Path)) 86*d415bd75Srobert return std::string(Path); 87*d415bd75Srobert } 88*d415bd75Srobert } 89*d415bd75Srobert return std::nullopt; 90*d415bd75Srobert } 91*d415bd75Srobert 92*d415bd75Srobert } // namespace object 93*d415bd75Srobert } // namespace llvm 94