BuildID.cpp 2.8 KB

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