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