xref: /freebsd/contrib/llvm-project/llvm/lib/Object/BuildID.cpp (revision c989957f28ef5b03f594265612e3437c1e826ed4)
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