ObjectFileTransformer.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. //===- ObjectFileTransformer.cpp --------------------------------*- C++ -*-===//
  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. #include <unordered_set>
  9. #include "llvm/Object/ELFObjectFile.h"
  10. #include "llvm/Object/MachOUniversal.h"
  11. #include "llvm/Object/ObjectFile.h"
  12. #include "llvm/Support/DataExtractor.h"
  13. #include "llvm/Support/raw_ostream.h"
  14. #include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
  15. #include "llvm/DebugInfo/GSYM/GsymCreator.h"
  16. using namespace llvm;
  17. using namespace gsym;
  18. constexpr uint32_t NT_GNU_BUILD_ID_TAG = 0x03;
  19. static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {
  20. // Extract the UUID from the object file
  21. std::vector<uint8_t> UUID;
  22. if (auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj)) {
  23. const ArrayRef<uint8_t> MachUUID = MachO->getUuid();
  24. if (!MachUUID.empty())
  25. UUID.assign(MachUUID.data(), MachUUID.data() + MachUUID.size());
  26. } else if (isa<object::ELFObjectFileBase>(&Obj)) {
  27. const StringRef GNUBuildID(".note.gnu.build-id");
  28. for (const object::SectionRef &Sect : Obj.sections()) {
  29. Expected<StringRef> SectNameOrErr = Sect.getName();
  30. if (!SectNameOrErr) {
  31. consumeError(SectNameOrErr.takeError());
  32. continue;
  33. }
  34. StringRef SectName(*SectNameOrErr);
  35. if (SectName != GNUBuildID)
  36. continue;
  37. StringRef BuildIDData;
  38. Expected<StringRef> E = Sect.getContents();
  39. if (E)
  40. BuildIDData = *E;
  41. else {
  42. consumeError(E.takeError());
  43. continue;
  44. }
  45. DataExtractor Decoder(BuildIDData, Obj.makeTriple().isLittleEndian(), 8);
  46. uint64_t Offset = 0;
  47. const uint32_t NameSize = Decoder.getU32(&Offset);
  48. const uint32_t PayloadSize = Decoder.getU32(&Offset);
  49. const uint32_t PayloadType = Decoder.getU32(&Offset);
  50. StringRef Name(Decoder.getFixedLengthString(&Offset, NameSize));
  51. if (Name == "GNU" && PayloadType == NT_GNU_BUILD_ID_TAG) {
  52. Offset = alignTo(Offset, 4);
  53. StringRef UUIDBytes(Decoder.getBytes(&Offset, PayloadSize));
  54. if (!UUIDBytes.empty()) {
  55. auto Ptr = reinterpret_cast<const uint8_t *>(UUIDBytes.data());
  56. UUID.assign(Ptr, Ptr + UUIDBytes.size());
  57. }
  58. }
  59. }
  60. }
  61. return UUID;
  62. }
  63. llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
  64. raw_ostream &Log,
  65. GsymCreator &Gsym) {
  66. using namespace llvm::object;
  67. const bool IsMachO = isa<MachOObjectFile>(&Obj);
  68. const bool IsELF = isa<ELFObjectFileBase>(&Obj);
  69. // Read build ID.
  70. Gsym.setUUID(getUUID(Obj));
  71. // Parse the symbol table.
  72. size_t NumBefore = Gsym.getNumFunctionInfos();
  73. for (const object::SymbolRef &Sym : Obj.symbols()) {
  74. Expected<SymbolRef::Type> SymType = Sym.getType();
  75. if (!SymType) {
  76. consumeError(SymType.takeError());
  77. continue;
  78. }
  79. Expected<uint64_t> AddrOrErr = Sym.getValue();
  80. if (!AddrOrErr)
  81. // TODO: Test this error.
  82. return AddrOrErr.takeError();
  83. if (SymType.get() != SymbolRef::Type::ST_Function ||
  84. !Gsym.IsValidTextAddress(*AddrOrErr) ||
  85. Gsym.hasFunctionInfoForAddress(*AddrOrErr))
  86. continue;
  87. // Function size for MachO files will be 0
  88. constexpr bool NoCopy = false;
  89. const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;
  90. Expected<StringRef> Name = Sym.getName();
  91. if (!Name) {
  92. logAllUnhandledErrors(Name.takeError(), Log, "ObjectFileTransformer: ");
  93. continue;
  94. }
  95. // Remove the leading '_' character in any symbol names if there is one
  96. // for mach-o files.
  97. if (IsMachO)
  98. Name->consume_front("_");
  99. Gsym.addFunctionInfo(
  100. FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));
  101. }
  102. size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
  103. Log << "Loaded " << FunctionsAddedCount << " functions from symbol table.\n";
  104. return Error::success();
  105. }