brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.2 KiB · 122de4d Raw
121 lines · cpp
1//===- ObjectFileTransformer.cpp --------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Object/ELFObjectFile.h"10#include "llvm/Object/MachOUniversal.h"11#include "llvm/Object/ObjectFile.h"12#include "llvm/Support/DataExtractor.h"13#include "llvm/Support/raw_ostream.h"14 15#include "llvm/DebugInfo/GSYM/GsymCreator.h"16#include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"17#include "llvm/DebugInfo/GSYM/OutputAggregator.h"18 19using namespace llvm;20using namespace gsym;21 22constexpr uint32_t NT_GNU_BUILD_ID_TAG = 0x03;23 24static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {25  // Extract the UUID from the object file26  std::vector<uint8_t> UUID;27  if (auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj)) {28    const ArrayRef<uint8_t> MachUUID = MachO->getUuid();29    if (!MachUUID.empty())30      UUID.assign(MachUUID.data(), MachUUID.data() + MachUUID.size());31  } else if (isa<object::ELFObjectFileBase>(&Obj)) {32    const StringRef GNUBuildID(".note.gnu.build-id");33    for (const object::SectionRef &Sect : Obj.sections()) {34      Expected<StringRef> SectNameOrErr = Sect.getName();35      if (!SectNameOrErr) {36        consumeError(SectNameOrErr.takeError());37        continue;38      }39      StringRef SectName(*SectNameOrErr);40      if (SectName != GNUBuildID)41        continue;42      StringRef BuildIDData;43      Expected<StringRef> E = Sect.getContents();44      if (E)45        BuildIDData = *E;46      else {47        consumeError(E.takeError());48        continue;49      }50      DataExtractor Decoder(BuildIDData, Obj.makeTriple().isLittleEndian(), 8);51      uint64_t Offset = 0;52      const uint32_t NameSize = Decoder.getU32(&Offset);53      const uint32_t PayloadSize = Decoder.getU32(&Offset);54      const uint32_t PayloadType = Decoder.getU32(&Offset);55      StringRef Name(Decoder.getFixedLengthString(&Offset, NameSize));56      if (Name == "GNU" && PayloadType == NT_GNU_BUILD_ID_TAG) {57        Offset = alignTo(Offset, 4);58        StringRef UUIDBytes(Decoder.getBytes(&Offset, PayloadSize));59        if (!UUIDBytes.empty()) {60          auto Ptr = reinterpret_cast<const uint8_t *>(UUIDBytes.data());61          UUID.assign(Ptr, Ptr + UUIDBytes.size());62        }63      }64    }65  }66  return UUID;67}68 69llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,70                                           OutputAggregator &Out,71                                           GsymCreator &Gsym) {72  using namespace llvm::object;73 74  const bool IsMachO = isa<MachOObjectFile>(&Obj);75  const bool IsELF = isa<ELFObjectFileBase>(&Obj);76 77  // Read build ID.78  Gsym.setUUID(getUUID(Obj));79 80  // Parse the symbol table.81  size_t NumBefore = Gsym.getNumFunctionInfos();82  for (const object::SymbolRef &Sym : Obj.symbols()) {83    Expected<SymbolRef::Type> SymType = Sym.getType();84    if (!SymType) {85      consumeError(SymType.takeError());86      continue;87    }88    Expected<uint64_t> AddrOrErr = Sym.getValue();89    if (!AddrOrErr)90      // TODO: Test this error.91      return AddrOrErr.takeError();92 93    if (SymType.get() != SymbolRef::Type::ST_Function ||94        !Gsym.IsValidTextAddress(*AddrOrErr))95      continue;96    // Function size for MachO files will be 097    constexpr bool NoCopy = false;98    const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;99    Expected<StringRef> Name = Sym.getName();100    if (!Name) {101      if (Out.GetOS())102        logAllUnhandledErrors(Name.takeError(), *Out.GetOS(),103                              "ObjectFileTransformer: ");104      else105        consumeError(Name.takeError());106      continue;107    }108    // Remove the leading '_' character in any symbol names if there is one109    // for mach-o files.110    if (IsMachO)111      Name->consume_front("_");112    Gsym.addFunctionInfo(113        FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));114  }115  size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;116  if (Out.GetOS())117    *Out.GetOS() << "Loaded " << FunctionsAddedCount118                 << " functions from symbol table.\n";119  return Error::success();120}121