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