xref: /llvm-project/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp (revision 0060c54e0da6d1429875da2d30895faa7562b706)
12f6cc21fSGreg Clayton //===- ObjectFileTransformer.cpp --------------------------------*- C++ -*-===//
22f6cc21fSGreg Clayton //
32f6cc21fSGreg Clayton // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42f6cc21fSGreg Clayton // See https://llvm.org/LICENSE.txt for license information.
52f6cc21fSGreg Clayton // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62f6cc21fSGreg Clayton //
72f6cc21fSGreg Clayton //===----------------------------------------------------------------------===//
82f6cc21fSGreg Clayton 
92f6cc21fSGreg Clayton #include "llvm/Object/ELFObjectFile.h"
102f6cc21fSGreg Clayton #include "llvm/Object/MachOUniversal.h"
112f6cc21fSGreg Clayton #include "llvm/Object/ObjectFile.h"
122f6cc21fSGreg Clayton #include "llvm/Support/DataExtractor.h"
132f6cc21fSGreg Clayton #include "llvm/Support/raw_ostream.h"
142f6cc21fSGreg Clayton 
152f6cc21fSGreg Clayton #include "llvm/DebugInfo/GSYM/GsymCreator.h"
16*3bdc4c70SKevin Frei #include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
17*3bdc4c70SKevin Frei #include "llvm/DebugInfo/GSYM/OutputAggregator.h"
182f6cc21fSGreg Clayton 
192f6cc21fSGreg Clayton using namespace llvm;
202f6cc21fSGreg Clayton using namespace gsym;
212f6cc21fSGreg Clayton 
222f6cc21fSGreg Clayton constexpr uint32_t NT_GNU_BUILD_ID_TAG = 0x03;
232f6cc21fSGreg Clayton 
242f6cc21fSGreg Clayton static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {
252f6cc21fSGreg Clayton   // Extract the UUID from the object file
262f6cc21fSGreg Clayton   std::vector<uint8_t> UUID;
272f6cc21fSGreg Clayton   if (auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj)) {
282f6cc21fSGreg Clayton     const ArrayRef<uint8_t> MachUUID = MachO->getUuid();
292f6cc21fSGreg Clayton     if (!MachUUID.empty())
302f6cc21fSGreg Clayton       UUID.assign(MachUUID.data(), MachUUID.data() + MachUUID.size());
312f6cc21fSGreg Clayton   } else if (isa<object::ELFObjectFileBase>(&Obj)) {
322f6cc21fSGreg Clayton     const StringRef GNUBuildID(".note.gnu.build-id");
332f6cc21fSGreg Clayton     for (const object::SectionRef &Sect : Obj.sections()) {
342f6cc21fSGreg Clayton       Expected<StringRef> SectNameOrErr = Sect.getName();
352f6cc21fSGreg Clayton       if (!SectNameOrErr) {
362f6cc21fSGreg Clayton         consumeError(SectNameOrErr.takeError());
372f6cc21fSGreg Clayton         continue;
382f6cc21fSGreg Clayton       }
392f6cc21fSGreg Clayton       StringRef SectName(*SectNameOrErr);
402f6cc21fSGreg Clayton       if (SectName != GNUBuildID)
412f6cc21fSGreg Clayton         continue;
422f6cc21fSGreg Clayton       StringRef BuildIDData;
432f6cc21fSGreg Clayton       Expected<StringRef> E = Sect.getContents();
442f6cc21fSGreg Clayton       if (E)
452f6cc21fSGreg Clayton         BuildIDData = *E;
462f6cc21fSGreg Clayton       else {
472f6cc21fSGreg Clayton         consumeError(E.takeError());
482f6cc21fSGreg Clayton         continue;
492f6cc21fSGreg Clayton       }
502f6cc21fSGreg Clayton       DataExtractor Decoder(BuildIDData, Obj.makeTriple().isLittleEndian(), 8);
512f6cc21fSGreg Clayton       uint64_t Offset = 0;
522f6cc21fSGreg Clayton       const uint32_t NameSize = Decoder.getU32(&Offset);
532f6cc21fSGreg Clayton       const uint32_t PayloadSize = Decoder.getU32(&Offset);
542f6cc21fSGreg Clayton       const uint32_t PayloadType = Decoder.getU32(&Offset);
552f6cc21fSGreg Clayton       StringRef Name(Decoder.getFixedLengthString(&Offset, NameSize));
562f6cc21fSGreg Clayton       if (Name == "GNU" && PayloadType == NT_GNU_BUILD_ID_TAG) {
572f6cc21fSGreg Clayton         Offset = alignTo(Offset, 4);
582f6cc21fSGreg Clayton         StringRef UUIDBytes(Decoder.getBytes(&Offset, PayloadSize));
592f6cc21fSGreg Clayton         if (!UUIDBytes.empty()) {
602f6cc21fSGreg Clayton           auto Ptr = reinterpret_cast<const uint8_t *>(UUIDBytes.data());
612f6cc21fSGreg Clayton           UUID.assign(Ptr, Ptr + UUIDBytes.size());
622f6cc21fSGreg Clayton         }
632f6cc21fSGreg Clayton       }
642f6cc21fSGreg Clayton     }
652f6cc21fSGreg Clayton   }
662f6cc21fSGreg Clayton   return UUID;
672f6cc21fSGreg Clayton }
682f6cc21fSGreg Clayton 
692f6cc21fSGreg Clayton llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
70*3bdc4c70SKevin Frei                                            OutputAggregator &Out,
712f6cc21fSGreg Clayton                                            GsymCreator &Gsym) {
722f6cc21fSGreg Clayton   using namespace llvm::object;
732f6cc21fSGreg Clayton 
742f6cc21fSGreg Clayton   const bool IsMachO = isa<MachOObjectFile>(&Obj);
752f6cc21fSGreg Clayton   const bool IsELF = isa<ELFObjectFileBase>(&Obj);
762f6cc21fSGreg Clayton 
772f6cc21fSGreg Clayton   // Read build ID.
782f6cc21fSGreg Clayton   Gsym.setUUID(getUUID(Obj));
792f6cc21fSGreg Clayton 
802f6cc21fSGreg Clayton   // Parse the symbol table.
812f6cc21fSGreg Clayton   size_t NumBefore = Gsym.getNumFunctionInfos();
822f6cc21fSGreg Clayton   for (const object::SymbolRef &Sym : Obj.symbols()) {
832f6cc21fSGreg Clayton     Expected<SymbolRef::Type> SymType = Sym.getType();
848994b14eSXing GUO     if (!SymType) {
858994b14eSXing GUO       consumeError(SymType.takeError());
868994b14eSXing GUO       continue;
878994b14eSXing GUO     }
88ff6a0b6aSXing GUO     Expected<uint64_t> AddrOrErr = Sym.getValue();
89ff6a0b6aSXing GUO     if (!AddrOrErr)
90ff6a0b6aSXing GUO       // TODO: Test this error.
91ff6a0b6aSXing GUO       return AddrOrErr.takeError();
92ff6a0b6aSXing GUO 
938994b14eSXing GUO     if (SymType.get() != SymbolRef::Type::ST_Function ||
941d9c7c41SGreg Clayton         !Gsym.IsValidTextAddress(*AddrOrErr))
952f6cc21fSGreg Clayton       continue;
962f6cc21fSGreg Clayton     // Function size for MachO files will be 0
972f6cc21fSGreg Clayton     constexpr bool NoCopy = false;
982f6cc21fSGreg Clayton     const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;
992f6cc21fSGreg Clayton     Expected<StringRef> Name = Sym.getName();
1002f6cc21fSGreg Clayton     if (!Name) {
101*3bdc4c70SKevin Frei       if (Out.GetOS())
102*3bdc4c70SKevin Frei         logAllUnhandledErrors(Name.takeError(), *Out.GetOS(),
10327d6161bSGreg Clayton                               "ObjectFileTransformer: ");
10427d6161bSGreg Clayton       else
10527d6161bSGreg Clayton         consumeError(Name.takeError());
1062f6cc21fSGreg Clayton       continue;
1072f6cc21fSGreg Clayton     }
1082f6cc21fSGreg Clayton     // Remove the leading '_' character in any symbol names if there is one
1092f6cc21fSGreg Clayton     // for mach-o files.
1102f6cc21fSGreg Clayton     if (IsMachO)
1112f6cc21fSGreg Clayton       Name->consume_front("_");
112ff6a0b6aSXing GUO     Gsym.addFunctionInfo(
113ff6a0b6aSXing GUO         FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));
1142f6cc21fSGreg Clayton   }
1152f6cc21fSGreg Clayton   size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
116*3bdc4c70SKevin Frei   if (Out.GetOS())
117*3bdc4c70SKevin Frei     *Out.GetOS() << "Loaded " << FunctionsAddedCount
11827d6161bSGreg Clayton                  << " functions from symbol table.\n";
1192f6cc21fSGreg Clayton   return Error::success();
1202f6cc21fSGreg Clayton }
121