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