brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · 8798601 Raw
318 lines · cpp
1//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//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 "DebugMap.h"10#include "BinaryHolder.h"11#include "llvm/ADT/SmallString.h"12#include "llvm/ADT/StringMap.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/BinaryFormat/MachO.h"15#include "llvm/Object/ObjectFile.h"16#include "llvm/Support/Chrono.h"17#include "llvm/Support/Error.h"18#include "llvm/Support/Format.h"19#include "llvm/Support/MemoryBuffer.h"20#include "llvm/Support/Path.h"21#include "llvm/Support/WithColor.h"22#include "llvm/Support/YAMLTraits.h"23#include "llvm/Support/raw_ostream.h"24#include "llvm/TargetParser/Triple.h"25#include <algorithm>26#include <cinttypes>27#include <cstdint>28#include <memory>29#include <optional>30#include <string>31#include <utility>32#include <vector>33 34namespace llvm {35 36namespace dsymutil {37 38using namespace llvm::object;39 40DebugMapObject::DebugMapObject(StringRef ObjectFilename,41                               sys::TimePoint<std::chrono::seconds> Timestamp,42                               uint8_t Type)43    : Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {}44 45bool DebugMapObject::addSymbol(StringRef Name,46                               std::optional<uint64_t> ObjectAddress,47                               uint64_t LinkedAddress, uint32_t Size) {48  if (Symbols.count(Name)) {49    // Symbol was previously added.50    return true;51  }52 53  auto InsertResult = Symbols.insert(54      std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));55 56  if (ObjectAddress && InsertResult.second)57    AddressToMapping[*ObjectAddress] = &*InsertResult.first;58  return InsertResult.second;59}60 61void DebugMapObject::setRelocationMap(dsymutil::RelocationMap &RM) {62  RelocMap.emplace(RM);63}64 65void DebugMapObject::setInstallName(StringRef IN) { InstallName.emplace(IN); }66 67void DebugMapObject::print(raw_ostream &OS) const {68  OS << getObjectFilename() << ":\n";69  // Sort the symbols in alphabetical order, like llvm-nm (and to get70  // deterministic output for testing).71  using Entry = std::pair<StringRef, SymbolMapping>;72  std::vector<Entry> Entries;73  Entries.reserve(Symbols.getNumItems());74  for (const auto &Sym : Symbols)75    Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue()));76  llvm::sort(Entries, llvm::less_first());77  for (const auto &Sym : Entries) {78    if (Sym.second.ObjectAddress)79      OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress));80    else81      OS << "\t????????????????";82    OS << format(" => %016" PRIx64 "+0x%x\t%s\n",83                 uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size),84                 Sym.first.data());85  }86  OS << '\n';87}88 89#ifndef NDEBUG90void DebugMapObject::dump() const { print(errs()); }91#endif92 93DebugMapObject &94DebugMap::addDebugMapObject(StringRef ObjectFilePath,95                            sys::TimePoint<std::chrono::seconds> Timestamp,96                            uint8_t Type) {97  Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type));98  return *Objects.back();99}100 101const DebugMapObject::DebugMapEntry *102DebugMapObject::lookupSymbol(StringRef SymbolName) const {103  StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);104  if (Sym == Symbols.end())105    return nullptr;106  return &*Sym;107}108 109const DebugMapObject::DebugMapEntry *110DebugMapObject::lookupObjectAddress(uint64_t Address) const {111  auto Mapping = AddressToMapping.find(Address);112  if (Mapping == AddressToMapping.end())113    return nullptr;114  return Mapping->getSecond();115}116 117void DebugMap::print(raw_ostream &OS) const {118  yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);119  yout << const_cast<DebugMap &>(*this);120}121 122#ifndef NDEBUG123void DebugMap::dump() const { print(errs()); }124#endif125 126namespace {127 128struct YAMLContext {129  YAMLContext(BinaryHolder &BinHolder, StringRef PrependPath)130      : BinHolder(BinHolder), PrependPath(PrependPath) {}131  BinaryHolder &BinHolder;132  StringRef PrependPath;133  Triple BinaryTriple;134};135 136} // end anonymous namespace137 138DebugMap::DebugMap(const Triple &BinaryTriple, StringRef BinaryPath,139                   ArrayRef<uint8_t> BinaryUUID)140    : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)),141      BinaryUUID(BinaryUUID.begin(), BinaryUUID.end()) {}142 143ErrorOr<std::vector<std::unique_ptr<DebugMap>>>144DebugMap::parseYAMLDebugMap(BinaryHolder &BinHolder, StringRef InputFile,145                            StringRef PrependPath, bool Verbose) {146  auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);147  if (auto Err = ErrOrFile.getError())148    return Err;149 150  YAMLContext Ctxt(BinHolder, PrependPath);151 152  std::unique_ptr<DebugMap> Res;153  yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);154  yin >> Res;155 156  if (auto EC = yin.error())157    return EC;158  std::vector<std::unique_ptr<DebugMap>> Result;159  Result.push_back(std::move(Res));160  return std::move(Result);161}162 163} // end namespace dsymutil164 165namespace yaml {166 167// Normalize/Denormalize between YAML and a DebugMapObject.168struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {169  YamlDMO(IO &io) {}170  YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);171  dsymutil::DebugMapObject denormalize(IO &IO);172 173  std::string Filename;174  int64_t Timestamp = 0;175  uint8_t Type = MachO::N_OSO;176  std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;177};178 179void MappingTraits<std::pair<std::string, SymbolMapping>>::mapping(180    IO &io, std::pair<std::string, SymbolMapping> &s) {181  io.mapRequired("sym", s.first);182  io.mapOptional("objAddr", s.second.ObjectAddress);183  io.mapRequired("binAddr", s.second.BinaryAddress);184  io.mapOptional("size", s.second.Size);185}186 187void MappingTraits<dsymutil::DebugMapObject>::mapping(188    IO &io, dsymutil::DebugMapObject &DMO) {189  MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);190  io.mapRequired("filename", Norm->Filename);191  io.mapOptional("timestamp", Norm->Timestamp);192  io.mapOptional("type", Norm->Type);193  io.mapRequired("symbols", Norm->Entries);194}195 196void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) {197  out << val.str();198}199 200StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) {201  value = Triple(scalar);202  return StringRef();203}204 205size_t206SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size(207    IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) {208  return seq.size();209}210 211dsymutil::DebugMapObject &212SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(213    IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,214    size_t index) {215  if (index >= seq.size()) {216    seq.resize(index + 1);217    seq[index].reset(new dsymutil::DebugMapObject);218  }219  return *seq[index];220}221 222void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,223                                                dsymutil::DebugMap &DM) {224  io.mapRequired("triple", DM.BinaryTriple);225  io.mapOptional("binary-path", DM.BinaryPath);226  if (void *Ctxt = io.getContext())227    reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;228  io.mapOptional("objects", DM.Objects);229}230 231void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(232    IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) {233  if (!DM)234    DM.reset(new DebugMap());235  io.mapRequired("triple", DM->BinaryTriple);236  io.mapOptional("binary-path", DM->BinaryPath);237  if (void *Ctxt = io.getContext())238    reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;239  io.mapOptional("objects", DM->Objects);240}241 242MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(243    IO &io, dsymutil::DebugMapObject &Obj) {244  Filename = Obj.Filename;245  Timestamp = sys::toTimeT(Obj.getTimestamp());246  Type = Obj.getType();247  Entries.reserve(Obj.Symbols.size());248  for (auto &Entry : Obj.Symbols)249    Entries.push_back(250        std::make_pair(std::string(Entry.getKey()), Entry.getValue()));251  llvm::sort(Entries, llvm::less_first());252}253 254dsymutil::DebugMapObject255MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {256  const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());257  SmallString<80> Path(Ctxt.PrependPath);258  StringMap<uint64_t> SymbolAddresses;259 260  sys::path::append(Path, Filename);261 262  auto ObjectEntry = Ctxt.BinHolder.getObjectEntry(Path);263  if (!ObjectEntry) {264    auto Err = ObjectEntry.takeError();265    WithColor::warning() << "Unable to open " << Path << " "266                         << toString(std::move(Err)) << '\n';267  } else {268    auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple);269    if (!Object) {270      auto Err = Object.takeError();271      WithColor::warning() << "Unable to open " << Path << " "272                           << toString(std::move(Err)) << '\n';273    } else {274      for (const auto &Sym : Object->symbols()) {275        Expected<uint64_t> AddressOrErr = Sym.getValue();276        if (!AddressOrErr) {277          // TODO: Actually report errors helpfully.278          consumeError(AddressOrErr.takeError());279          continue;280        }281        Expected<StringRef> Name = Sym.getName();282        Expected<uint32_t> FlagsOrErr = Sym.getFlags();283        if (!Name || !FlagsOrErr ||284            (*FlagsOrErr & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {285          // TODO: Actually report errors helpfully.286          if (!FlagsOrErr)287            consumeError(FlagsOrErr.takeError());288          if (!Name)289            consumeError(Name.takeError());290          continue;291        }292        SymbolAddresses[*Name] = *AddressOrErr;293      }294    }295  }296 297  if (Path.ends_with(".dylib")) {298    // FIXME: find a more resilient way299    Type = MachO::N_LIB;300  }301  dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), Type);302 303  for (auto &Entry : Entries) {304    auto &Mapping = Entry.second;305    std::optional<uint64_t> ObjAddress;306    if (Mapping.ObjectAddress)307      ObjAddress = *Mapping.ObjectAddress;308    auto AddressIt = SymbolAddresses.find(Entry.first);309    if (AddressIt != SymbolAddresses.end())310      ObjAddress = AddressIt->getValue();311    Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);312  }313  return Res;314}315 316} // end namespace yaml317} // end namespace llvm318