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