xref: /openbsd-src/gnu/llvm/llvm/lib/Object/BuildID.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
1*d415bd75Srobert //===- llvm/Object/BuildID.cpp - Build ID ---------------------------------===//
2*d415bd75Srobert //
3*d415bd75Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*d415bd75Srobert // See https://llvm.org/LICENSE.txt for license information.
5*d415bd75Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*d415bd75Srobert //
7*d415bd75Srobert //===----------------------------------------------------------------------===//
8*d415bd75Srobert ///
9*d415bd75Srobert /// \file
10*d415bd75Srobert /// This file defines a library for handling Build IDs and using them to find
11*d415bd75Srobert /// debug info.
12*d415bd75Srobert ///
13*d415bd75Srobert //===----------------------------------------------------------------------===//
14*d415bd75Srobert 
15*d415bd75Srobert #include "llvm/Object/BuildID.h"
16*d415bd75Srobert 
17*d415bd75Srobert #include "llvm/Object/ELFObjectFile.h"
18*d415bd75Srobert #include "llvm/Support/FileSystem.h"
19*d415bd75Srobert #include "llvm/Support/Path.h"
20*d415bd75Srobert 
21*d415bd75Srobert namespace llvm {
22*d415bd75Srobert namespace object {
23*d415bd75Srobert 
24*d415bd75Srobert namespace {
25*d415bd75Srobert 
26*d415bd75Srobert template <typename ELFT>
getBuildID(const ELFFile<ELFT> & Obj)27*d415bd75Srobert std::optional<BuildIDRef> getBuildID(const ELFFile<ELFT> &Obj) {
28*d415bd75Srobert   auto PhdrsOrErr = Obj.program_headers();
29*d415bd75Srobert   if (!PhdrsOrErr) {
30*d415bd75Srobert     consumeError(PhdrsOrErr.takeError());
31*d415bd75Srobert     return {};
32*d415bd75Srobert   }
33*d415bd75Srobert   for (const auto &P : *PhdrsOrErr) {
34*d415bd75Srobert     if (P.p_type != ELF::PT_NOTE)
35*d415bd75Srobert       continue;
36*d415bd75Srobert     Error Err = Error::success();
37*d415bd75Srobert     for (auto N : Obj.notes(P, Err))
38*d415bd75Srobert       if (N.getType() == ELF::NT_GNU_BUILD_ID &&
39*d415bd75Srobert           N.getName() == ELF::ELF_NOTE_GNU)
40*d415bd75Srobert         return N.getDesc();
41*d415bd75Srobert     consumeError(std::move(Err));
42*d415bd75Srobert   }
43*d415bd75Srobert   return {};
44*d415bd75Srobert }
45*d415bd75Srobert 
46*d415bd75Srobert } // namespace
47*d415bd75Srobert 
getBuildID(const ObjectFile * Obj)48*d415bd75Srobert std::optional<BuildIDRef> getBuildID(const ObjectFile *Obj) {
49*d415bd75Srobert   if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
50*d415bd75Srobert     return getBuildID(O->getELFFile());
51*d415bd75Srobert   if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
52*d415bd75Srobert     return getBuildID(O->getELFFile());
53*d415bd75Srobert   if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
54*d415bd75Srobert     return getBuildID(O->getELFFile());
55*d415bd75Srobert   if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
56*d415bd75Srobert     return getBuildID(O->getELFFile());
57*d415bd75Srobert   return std::nullopt;
58*d415bd75Srobert }
59*d415bd75Srobert 
fetch(BuildIDRef BuildID) const60*d415bd75Srobert std::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const {
61*d415bd75Srobert   auto GetDebugPath = [&](StringRef Directory) {
62*d415bd75Srobert     SmallString<128> Path{Directory};
63*d415bd75Srobert     sys::path::append(Path, ".build-id",
64*d415bd75Srobert                       llvm::toHex(BuildID[0], /*LowerCase=*/true),
65*d415bd75Srobert                       llvm::toHex(BuildID.slice(1), /*LowerCase=*/true));
66*d415bd75Srobert     Path += ".debug";
67*d415bd75Srobert     return Path;
68*d415bd75Srobert   };
69*d415bd75Srobert   if (DebugFileDirectories.empty()) {
70*d415bd75Srobert     SmallString<128> Path = GetDebugPath(
71*d415bd75Srobert #if defined(__NetBSD__)
72*d415bd75Srobert         // Try /usr/libdata/debug/.build-id/../...
73*d415bd75Srobert         "/usr/libdata/debug"
74*d415bd75Srobert #else
75*d415bd75Srobert         // Try /usr/lib/debug/.build-id/../...
76*d415bd75Srobert         "/usr/lib/debug"
77*d415bd75Srobert #endif
78*d415bd75Srobert     );
79*d415bd75Srobert     if (llvm::sys::fs::exists(Path))
80*d415bd75Srobert       return std::string(Path);
81*d415bd75Srobert   } else {
82*d415bd75Srobert     for (const auto &Directory : DebugFileDirectories) {
83*d415bd75Srobert       // Try <debug-file-directory>/.build-id/../...
84*d415bd75Srobert       SmallString<128> Path = GetDebugPath(Directory);
85*d415bd75Srobert       if (llvm::sys::fs::exists(Path))
86*d415bd75Srobert         return std::string(Path);
87*d415bd75Srobert     }
88*d415bd75Srobert   }
89*d415bd75Srobert   return std::nullopt;
90*d415bd75Srobert }
91*d415bd75Srobert 
92*d415bd75Srobert } // namespace object
93*d415bd75Srobert } // namespace llvm
94