xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===- ObjectFileTransformer.cpp --------------------------------*- C++ -*-===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
95ffd83dbSDimitry Andric #include <unordered_set>
105ffd83dbSDimitry Andric 
115ffd83dbSDimitry Andric #include "llvm/Object/ELFObjectFile.h"
125ffd83dbSDimitry Andric #include "llvm/Object/MachOUniversal.h"
135ffd83dbSDimitry Andric #include "llvm/Object/ObjectFile.h"
145ffd83dbSDimitry Andric #include "llvm/Support/DataExtractor.h"
155ffd83dbSDimitry Andric #include "llvm/Support/raw_ostream.h"
165ffd83dbSDimitry Andric 
175ffd83dbSDimitry Andric #include "llvm/DebugInfo/GSYM/GsymCreator.h"
18*0fca6ea1SDimitry Andric #include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
19*0fca6ea1SDimitry Andric #include "llvm/DebugInfo/GSYM/OutputAggregator.h"
205ffd83dbSDimitry Andric 
215ffd83dbSDimitry Andric using namespace llvm;
225ffd83dbSDimitry Andric using namespace gsym;
235ffd83dbSDimitry Andric 
245ffd83dbSDimitry Andric constexpr uint32_t NT_GNU_BUILD_ID_TAG = 0x03;
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {
275ffd83dbSDimitry Andric   // Extract the UUID from the object file
285ffd83dbSDimitry Andric   std::vector<uint8_t> UUID;
295ffd83dbSDimitry Andric   if (auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj)) {
305ffd83dbSDimitry Andric     const ArrayRef<uint8_t> MachUUID = MachO->getUuid();
315ffd83dbSDimitry Andric     if (!MachUUID.empty())
325ffd83dbSDimitry Andric       UUID.assign(MachUUID.data(), MachUUID.data() + MachUUID.size());
335ffd83dbSDimitry Andric   } else if (isa<object::ELFObjectFileBase>(&Obj)) {
345ffd83dbSDimitry Andric     const StringRef GNUBuildID(".note.gnu.build-id");
355ffd83dbSDimitry Andric     for (const object::SectionRef &Sect : Obj.sections()) {
365ffd83dbSDimitry Andric       Expected<StringRef> SectNameOrErr = Sect.getName();
375ffd83dbSDimitry Andric       if (!SectNameOrErr) {
385ffd83dbSDimitry Andric         consumeError(SectNameOrErr.takeError());
395ffd83dbSDimitry Andric         continue;
405ffd83dbSDimitry Andric       }
415ffd83dbSDimitry Andric       StringRef SectName(*SectNameOrErr);
425ffd83dbSDimitry Andric       if (SectName != GNUBuildID)
435ffd83dbSDimitry Andric         continue;
445ffd83dbSDimitry Andric       StringRef BuildIDData;
455ffd83dbSDimitry Andric       Expected<StringRef> E = Sect.getContents();
465ffd83dbSDimitry Andric       if (E)
475ffd83dbSDimitry Andric         BuildIDData = *E;
485ffd83dbSDimitry Andric       else {
495ffd83dbSDimitry Andric         consumeError(E.takeError());
505ffd83dbSDimitry Andric         continue;
515ffd83dbSDimitry Andric       }
525ffd83dbSDimitry Andric       DataExtractor Decoder(BuildIDData, Obj.makeTriple().isLittleEndian(), 8);
535ffd83dbSDimitry Andric       uint64_t Offset = 0;
545ffd83dbSDimitry Andric       const uint32_t NameSize = Decoder.getU32(&Offset);
555ffd83dbSDimitry Andric       const uint32_t PayloadSize = Decoder.getU32(&Offset);
565ffd83dbSDimitry Andric       const uint32_t PayloadType = Decoder.getU32(&Offset);
575ffd83dbSDimitry Andric       StringRef Name(Decoder.getFixedLengthString(&Offset, NameSize));
585ffd83dbSDimitry Andric       if (Name == "GNU" && PayloadType == NT_GNU_BUILD_ID_TAG) {
595ffd83dbSDimitry Andric         Offset = alignTo(Offset, 4);
605ffd83dbSDimitry Andric         StringRef UUIDBytes(Decoder.getBytes(&Offset, PayloadSize));
615ffd83dbSDimitry Andric         if (!UUIDBytes.empty()) {
625ffd83dbSDimitry Andric           auto Ptr = reinterpret_cast<const uint8_t *>(UUIDBytes.data());
635ffd83dbSDimitry Andric           UUID.assign(Ptr, Ptr + UUIDBytes.size());
645ffd83dbSDimitry Andric         }
655ffd83dbSDimitry Andric       }
665ffd83dbSDimitry Andric     }
675ffd83dbSDimitry Andric   }
685ffd83dbSDimitry Andric   return UUID;
695ffd83dbSDimitry Andric }
705ffd83dbSDimitry Andric 
715ffd83dbSDimitry Andric llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
72*0fca6ea1SDimitry Andric                                            OutputAggregator &Out,
735ffd83dbSDimitry Andric                                            GsymCreator &Gsym) {
745ffd83dbSDimitry Andric   using namespace llvm::object;
755ffd83dbSDimitry Andric 
765ffd83dbSDimitry Andric   const bool IsMachO = isa<MachOObjectFile>(&Obj);
775ffd83dbSDimitry Andric   const bool IsELF = isa<ELFObjectFileBase>(&Obj);
785ffd83dbSDimitry Andric 
795ffd83dbSDimitry Andric   // Read build ID.
805ffd83dbSDimitry Andric   Gsym.setUUID(getUUID(Obj));
815ffd83dbSDimitry Andric 
825ffd83dbSDimitry Andric   // Parse the symbol table.
835ffd83dbSDimitry Andric   size_t NumBefore = Gsym.getNumFunctionInfos();
845ffd83dbSDimitry Andric   for (const object::SymbolRef &Sym : Obj.symbols()) {
855ffd83dbSDimitry Andric     Expected<SymbolRef::Type> SymType = Sym.getType();
865ffd83dbSDimitry Andric     if (!SymType) {
875ffd83dbSDimitry Andric       consumeError(SymType.takeError());
885ffd83dbSDimitry Andric       continue;
895ffd83dbSDimitry Andric     }
905ffd83dbSDimitry Andric     Expected<uint64_t> AddrOrErr = Sym.getValue();
915ffd83dbSDimitry Andric     if (!AddrOrErr)
925ffd83dbSDimitry Andric       // TODO: Test this error.
935ffd83dbSDimitry Andric       return AddrOrErr.takeError();
945ffd83dbSDimitry Andric 
955ffd83dbSDimitry Andric     if (SymType.get() != SymbolRef::Type::ST_Function ||
965f757f3fSDimitry Andric         !Gsym.IsValidTextAddress(*AddrOrErr))
975ffd83dbSDimitry Andric       continue;
985ffd83dbSDimitry Andric     // Function size for MachO files will be 0
995ffd83dbSDimitry Andric     constexpr bool NoCopy = false;
1005ffd83dbSDimitry Andric     const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;
1015ffd83dbSDimitry Andric     Expected<StringRef> Name = Sym.getName();
1025ffd83dbSDimitry Andric     if (!Name) {
103*0fca6ea1SDimitry Andric       if (Out.GetOS())
104*0fca6ea1SDimitry Andric         logAllUnhandledErrors(Name.takeError(), *Out.GetOS(),
1055f757f3fSDimitry Andric                               "ObjectFileTransformer: ");
1065f757f3fSDimitry Andric       else
1075f757f3fSDimitry Andric         consumeError(Name.takeError());
1085ffd83dbSDimitry Andric       continue;
1095ffd83dbSDimitry Andric     }
1105ffd83dbSDimitry Andric     // Remove the leading '_' character in any symbol names if there is one
1115ffd83dbSDimitry Andric     // for mach-o files.
1125ffd83dbSDimitry Andric     if (IsMachO)
1135ffd83dbSDimitry Andric       Name->consume_front("_");
1145ffd83dbSDimitry Andric     Gsym.addFunctionInfo(
1155ffd83dbSDimitry Andric         FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));
1165ffd83dbSDimitry Andric   }
1175ffd83dbSDimitry Andric   size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
118*0fca6ea1SDimitry Andric   if (Out.GetOS())
119*0fca6ea1SDimitry Andric     *Out.GetOS() << "Loaded " << FunctionsAddedCount
1205f757f3fSDimitry Andric                  << " functions from symbol table.\n";
1215ffd83dbSDimitry Andric   return Error::success();
1225ffd83dbSDimitry Andric }
123