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