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