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