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