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