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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file defines a library for handling Build IDs and using them to find 11 /// 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 21 using namespace llvm; 22 using namespace llvm::object; 23 24 namespace { 25 26 template <typename ELFT> BuildIDRef getBuildID(const ELFFile<ELFT> &Obj) { 27 auto PhdrsOrErr = Obj.program_headers(); 28 if (!PhdrsOrErr) { 29 consumeError(PhdrsOrErr.takeError()); 30 return {}; 31 } 32 for (const auto &P : *PhdrsOrErr) { 33 if (P.p_type != ELF::PT_NOTE) 34 continue; 35 Error Err = Error::success(); 36 for (auto N : Obj.notes(P, Err)) 37 if (N.getType() == ELF::NT_GNU_BUILD_ID && 38 N.getName() == ELF::ELF_NOTE_GNU) 39 return N.getDesc(P.p_align); 40 consumeError(std::move(Err)); 41 } 42 return {}; 43 } 44 45 } // namespace 46 47 BuildID llvm::object::parseBuildID(StringRef Str) { 48 std::string Bytes; 49 if (!tryGetFromHex(Str, Bytes)) 50 return {}; 51 ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()), 52 Bytes.size()); 53 return SmallVector<uint8_t>(BuildID.begin(), BuildID.end()); 54 } 55 56 BuildIDRef llvm::object::getBuildID(const ObjectFile *Obj) { 57 if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj)) 58 return ::getBuildID(O->getELFFile()); 59 if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj)) 60 return ::getBuildID(O->getELFFile()); 61 if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj)) 62 return ::getBuildID(O->getELFFile()); 63 if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj)) 64 return ::getBuildID(O->getELFFile()); 65 return std::nullopt; 66 } 67 68 std::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const { 69 auto GetDebugPath = [&](StringRef Directory) { 70 SmallString<128> Path{Directory}; 71 sys::path::append(Path, ".build-id", 72 llvm::toHex(BuildID[0], /*LowerCase=*/true), 73 llvm::toHex(BuildID.slice(1), /*LowerCase=*/true)); 74 Path += ".debug"; 75 return Path; 76 }; 77 if (DebugFileDirectories.empty()) { 78 SmallString<128> Path = GetDebugPath( 79 #if defined(__NetBSD__) 80 // Try /usr/libdata/debug/.build-id/../... 81 "/usr/libdata/debug" 82 #else 83 // Try /usr/lib/debug/.build-id/../... 84 "/usr/lib/debug" 85 #endif 86 ); 87 if (llvm::sys::fs::exists(Path)) 88 return std::string(Path); 89 } else { 90 for (const auto &Directory : DebugFileDirectories) { 91 // Try <debug-file-directory>/.build-id/../... 92 SmallString<128> Path = GetDebugPath(Directory); 93 if (llvm::sys::fs::exists(Path)) 94 return std::string(Path); 95 } 96 } 97 return std::nullopt; 98 } 99