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