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