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