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