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 <unordered_set>
102f6cc21fSGreg Clayton
112f6cc21fSGreg Clayton #include "llvm/Object/ELFObjectFile.h"
122f6cc21fSGreg Clayton #include "llvm/Object/MachOUniversal.h"
132f6cc21fSGreg Clayton #include "llvm/Object/ObjectFile.h"
142f6cc21fSGreg Clayton #include "llvm/Support/DataExtractor.h"
152f6cc21fSGreg Clayton #include "llvm/Support/raw_ostream.h"
162f6cc21fSGreg Clayton
172f6cc21fSGreg Clayton #include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
182f6cc21fSGreg Clayton #include "llvm/DebugInfo/GSYM/GsymCreator.h"
192f6cc21fSGreg Clayton
202f6cc21fSGreg Clayton using namespace llvm;
212f6cc21fSGreg Clayton using namespace gsym;
222f6cc21fSGreg Clayton
232f6cc21fSGreg Clayton constexpr uint32_t NT_GNU_BUILD_ID_TAG = 0x03;
242f6cc21fSGreg Clayton
getUUID(const object::ObjectFile & Obj)252f6cc21fSGreg Clayton static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {
262f6cc21fSGreg Clayton // Extract the UUID from the object file
272f6cc21fSGreg Clayton std::vector<uint8_t> UUID;
282f6cc21fSGreg Clayton if (auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj)) {
292f6cc21fSGreg Clayton const ArrayRef<uint8_t> MachUUID = MachO->getUuid();
302f6cc21fSGreg Clayton if (!MachUUID.empty())
312f6cc21fSGreg Clayton UUID.assign(MachUUID.data(), MachUUID.data() + MachUUID.size());
322f6cc21fSGreg Clayton } else if (isa<object::ELFObjectFileBase>(&Obj)) {
332f6cc21fSGreg Clayton const StringRef GNUBuildID(".note.gnu.build-id");
342f6cc21fSGreg Clayton for (const object::SectionRef &Sect : Obj.sections()) {
352f6cc21fSGreg Clayton Expected<StringRef> SectNameOrErr = Sect.getName();
362f6cc21fSGreg Clayton if (!SectNameOrErr) {
372f6cc21fSGreg Clayton consumeError(SectNameOrErr.takeError());
382f6cc21fSGreg Clayton continue;
392f6cc21fSGreg Clayton }
402f6cc21fSGreg Clayton StringRef SectName(*SectNameOrErr);
412f6cc21fSGreg Clayton if (SectName != GNUBuildID)
422f6cc21fSGreg Clayton continue;
432f6cc21fSGreg Clayton StringRef BuildIDData;
442f6cc21fSGreg Clayton Expected<StringRef> E = Sect.getContents();
452f6cc21fSGreg Clayton if (E)
462f6cc21fSGreg Clayton BuildIDData = *E;
472f6cc21fSGreg Clayton else {
482f6cc21fSGreg Clayton consumeError(E.takeError());
492f6cc21fSGreg Clayton continue;
502f6cc21fSGreg Clayton }
512f6cc21fSGreg Clayton DataExtractor Decoder(BuildIDData, Obj.makeTriple().isLittleEndian(), 8);
522f6cc21fSGreg Clayton uint64_t Offset = 0;
532f6cc21fSGreg Clayton const uint32_t NameSize = Decoder.getU32(&Offset);
542f6cc21fSGreg Clayton const uint32_t PayloadSize = Decoder.getU32(&Offset);
552f6cc21fSGreg Clayton const uint32_t PayloadType = Decoder.getU32(&Offset);
562f6cc21fSGreg Clayton StringRef Name(Decoder.getFixedLengthString(&Offset, NameSize));
572f6cc21fSGreg Clayton if (Name == "GNU" && PayloadType == NT_GNU_BUILD_ID_TAG) {
582f6cc21fSGreg Clayton Offset = alignTo(Offset, 4);
592f6cc21fSGreg Clayton StringRef UUIDBytes(Decoder.getBytes(&Offset, PayloadSize));
602f6cc21fSGreg Clayton if (!UUIDBytes.empty()) {
612f6cc21fSGreg Clayton auto Ptr = reinterpret_cast<const uint8_t *>(UUIDBytes.data());
622f6cc21fSGreg Clayton UUID.assign(Ptr, Ptr + UUIDBytes.size());
632f6cc21fSGreg Clayton }
642f6cc21fSGreg Clayton }
652f6cc21fSGreg Clayton }
662f6cc21fSGreg Clayton }
672f6cc21fSGreg Clayton return UUID;
682f6cc21fSGreg Clayton }
692f6cc21fSGreg Clayton
convert(const object::ObjectFile & Obj,raw_ostream & Log,GsymCreator & Gsym)702f6cc21fSGreg Clayton llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
712f6cc21fSGreg Clayton raw_ostream &Log,
722f6cc21fSGreg Clayton GsymCreator &Gsym) {
732f6cc21fSGreg Clayton using namespace llvm::object;
742f6cc21fSGreg Clayton
752f6cc21fSGreg Clayton const bool IsMachO = isa<MachOObjectFile>(&Obj);
762f6cc21fSGreg Clayton const bool IsELF = isa<ELFObjectFileBase>(&Obj);
772f6cc21fSGreg Clayton
782f6cc21fSGreg Clayton // Read build ID.
792f6cc21fSGreg Clayton Gsym.setUUID(getUUID(Obj));
802f6cc21fSGreg Clayton
812f6cc21fSGreg Clayton // Parse the symbol table.
822f6cc21fSGreg Clayton size_t NumBefore = Gsym.getNumFunctionInfos();
832f6cc21fSGreg Clayton for (const object::SymbolRef &Sym : Obj.symbols()) {
842f6cc21fSGreg Clayton Expected<SymbolRef::Type> SymType = Sym.getType();
858994b14eSXing GUO if (!SymType) {
868994b14eSXing GUO consumeError(SymType.takeError());
878994b14eSXing GUO continue;
888994b14eSXing GUO }
89*ff6a0b6aSXing GUO Expected<uint64_t> AddrOrErr = Sym.getValue();
90*ff6a0b6aSXing GUO if (!AddrOrErr)
91*ff6a0b6aSXing GUO // TODO: Test this error.
92*ff6a0b6aSXing GUO return AddrOrErr.takeError();
93*ff6a0b6aSXing GUO
948994b14eSXing GUO if (SymType.get() != SymbolRef::Type::ST_Function ||
95*ff6a0b6aSXing GUO !Gsym.IsValidTextAddress(*AddrOrErr) ||
96*ff6a0b6aSXing GUO Gsym.hasFunctionInfoForAddress(*AddrOrErr))
972f6cc21fSGreg Clayton continue;
982f6cc21fSGreg Clayton // Function size for MachO files will be 0
992f6cc21fSGreg Clayton constexpr bool NoCopy = false;
1002f6cc21fSGreg Clayton const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;
1012f6cc21fSGreg Clayton Expected<StringRef> Name = Sym.getName();
1022f6cc21fSGreg Clayton if (!Name) {
1032f6cc21fSGreg Clayton logAllUnhandledErrors(Name.takeError(), Log, "ObjectFileTransformer: ");
1042f6cc21fSGreg Clayton continue;
1052f6cc21fSGreg Clayton }
1062f6cc21fSGreg Clayton // Remove the leading '_' character in any symbol names if there is one
1072f6cc21fSGreg Clayton // for mach-o files.
1082f6cc21fSGreg Clayton if (IsMachO)
1092f6cc21fSGreg Clayton Name->consume_front("_");
110*ff6a0b6aSXing GUO Gsym.addFunctionInfo(
111*ff6a0b6aSXing GUO FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));
1122f6cc21fSGreg Clayton }
1132f6cc21fSGreg Clayton size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
1142f6cc21fSGreg Clayton Log << "Loaded " << FunctionsAddedCount << " functions from symbol table.\n";
1152f6cc21fSGreg Clayton return Error::success();
1162f6cc21fSGreg Clayton }
117