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