Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp
35266 views
//===- ObjectFileTransformer.cpp --------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <unordered_set>910#include "llvm/Object/ELFObjectFile.h"11#include "llvm/Object/MachOUniversal.h"12#include "llvm/Object/ObjectFile.h"13#include "llvm/Support/DataExtractor.h"14#include "llvm/Support/raw_ostream.h"1516#include "llvm/DebugInfo/GSYM/GsymCreator.h"17#include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"18#include "llvm/DebugInfo/GSYM/OutputAggregator.h"1920using namespace llvm;21using namespace gsym;2223constexpr uint32_t NT_GNU_BUILD_ID_TAG = 0x03;2425static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {26// Extract the UUID from the object file27std::vector<uint8_t> UUID;28if (auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj)) {29const ArrayRef<uint8_t> MachUUID = MachO->getUuid();30if (!MachUUID.empty())31UUID.assign(MachUUID.data(), MachUUID.data() + MachUUID.size());32} else if (isa<object::ELFObjectFileBase>(&Obj)) {33const StringRef GNUBuildID(".note.gnu.build-id");34for (const object::SectionRef &Sect : Obj.sections()) {35Expected<StringRef> SectNameOrErr = Sect.getName();36if (!SectNameOrErr) {37consumeError(SectNameOrErr.takeError());38continue;39}40StringRef SectName(*SectNameOrErr);41if (SectName != GNUBuildID)42continue;43StringRef BuildIDData;44Expected<StringRef> E = Sect.getContents();45if (E)46BuildIDData = *E;47else {48consumeError(E.takeError());49continue;50}51DataExtractor Decoder(BuildIDData, Obj.makeTriple().isLittleEndian(), 8);52uint64_t Offset = 0;53const uint32_t NameSize = Decoder.getU32(&Offset);54const uint32_t PayloadSize = Decoder.getU32(&Offset);55const uint32_t PayloadType = Decoder.getU32(&Offset);56StringRef Name(Decoder.getFixedLengthString(&Offset, NameSize));57if (Name == "GNU" && PayloadType == NT_GNU_BUILD_ID_TAG) {58Offset = alignTo(Offset, 4);59StringRef UUIDBytes(Decoder.getBytes(&Offset, PayloadSize));60if (!UUIDBytes.empty()) {61auto Ptr = reinterpret_cast<const uint8_t *>(UUIDBytes.data());62UUID.assign(Ptr, Ptr + UUIDBytes.size());63}64}65}66}67return UUID;68}6970llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,71OutputAggregator &Out,72GsymCreator &Gsym) {73using namespace llvm::object;7475const bool IsMachO = isa<MachOObjectFile>(&Obj);76const bool IsELF = isa<ELFObjectFileBase>(&Obj);7778// Read build ID.79Gsym.setUUID(getUUID(Obj));8081// Parse the symbol table.82size_t NumBefore = Gsym.getNumFunctionInfos();83for (const object::SymbolRef &Sym : Obj.symbols()) {84Expected<SymbolRef::Type> SymType = Sym.getType();85if (!SymType) {86consumeError(SymType.takeError());87continue;88}89Expected<uint64_t> AddrOrErr = Sym.getValue();90if (!AddrOrErr)91// TODO: Test this error.92return AddrOrErr.takeError();9394if (SymType.get() != SymbolRef::Type::ST_Function ||95!Gsym.IsValidTextAddress(*AddrOrErr))96continue;97// Function size for MachO files will be 098constexpr bool NoCopy = false;99const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;100Expected<StringRef> Name = Sym.getName();101if (!Name) {102if (Out.GetOS())103logAllUnhandledErrors(Name.takeError(), *Out.GetOS(),104"ObjectFileTransformer: ");105else106consumeError(Name.takeError());107continue;108}109// Remove the leading '_' character in any symbol names if there is one110// for mach-o files.111if (IsMachO)112Name->consume_front("_");113Gsym.addFunctionInfo(114FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));115}116size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;117if (Out.GetOS())118*Out.GetOS() << "Loaded " << FunctionsAddedCount119<< " functions from symbol table.\n";120return Error::success();121}122123124