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