forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			287 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "DebugMap.h"
 | 
						|
#include "BinaryHolder.h"
 | 
						|
#include "llvm/ADT/Optional.h"
 | 
						|
#include "llvm/ADT/SmallString.h"
 | 
						|
#include "llvm/ADT/StringMap.h"
 | 
						|
#include "llvm/ADT/StringRef.h"
 | 
						|
#include "llvm/ADT/Triple.h"
 | 
						|
#include "llvm/ADT/iterator_range.h"
 | 
						|
#include "llvm/BinaryFormat/MachO.h"
 | 
						|
#include "llvm/Object/ObjectFile.h"
 | 
						|
#include "llvm/Support/Chrono.h"
 | 
						|
#include "llvm/Support/Error.h"
 | 
						|
#include "llvm/Support/Format.h"
 | 
						|
#include "llvm/Support/MemoryBuffer.h"
 | 
						|
#include "llvm/Support/Path.h"
 | 
						|
#include "llvm/Support/WithColor.h"
 | 
						|
#include "llvm/Support/YAMLTraits.h"
 | 
						|
#include "llvm/Support/raw_ostream.h"
 | 
						|
#include <algorithm>
 | 
						|
#include <cinttypes>
 | 
						|
#include <cstdint>
 | 
						|
#include <memory>
 | 
						|
#include <string>
 | 
						|
#include <utility>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
 | 
						|
namespace dsymutil {
 | 
						|
 | 
						|
using namespace llvm::object;
 | 
						|
 | 
						|
DebugMapObject::DebugMapObject(StringRef ObjectFilename,
 | 
						|
                               sys::TimePoint<std::chrono::seconds> Timestamp,
 | 
						|
                               uint8_t Type)
 | 
						|
    : Filename(ObjectFilename), Timestamp(Timestamp), Type(Type) {}
 | 
						|
 | 
						|
bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress,
 | 
						|
                               uint64_t LinkedAddress, uint32_t Size) {
 | 
						|
  auto InsertResult = Symbols.insert(
 | 
						|
      std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
 | 
						|
 | 
						|
  if (ObjectAddress && InsertResult.second)
 | 
						|
    AddressToMapping[*ObjectAddress] = &*InsertResult.first;
 | 
						|
  return InsertResult.second;
 | 
						|
}
 | 
						|
 | 
						|
void DebugMapObject::print(raw_ostream &OS) const {
 | 
						|
  OS << getObjectFilename() << ":\n";
 | 
						|
  // Sort the symbols in alphabetical order, like llvm-nm (and to get
 | 
						|
  // deterministic output for testing).
 | 
						|
  using Entry = std::pair<StringRef, SymbolMapping>;
 | 
						|
  std::vector<Entry> Entries;
 | 
						|
  Entries.reserve(Symbols.getNumItems());
 | 
						|
  for (const auto &Sym : make_range(Symbols.begin(), Symbols.end()))
 | 
						|
    Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue()));
 | 
						|
  llvm::sort(Entries, [](const Entry &LHS, const Entry &RHS) {
 | 
						|
    return LHS.first < RHS.first;
 | 
						|
  });
 | 
						|
  for (const auto &Sym : Entries) {
 | 
						|
    if (Sym.second.ObjectAddress)
 | 
						|
      OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress));
 | 
						|
    else
 | 
						|
      OS << "\t????????????????";
 | 
						|
    OS << format(" => %016" PRIx64 "+0x%x\t%s\n",
 | 
						|
                 uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size),
 | 
						|
                 Sym.first.data());
 | 
						|
  }
 | 
						|
  OS << '\n';
 | 
						|
}
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
void DebugMapObject::dump() const { print(errs()); }
 | 
						|
#endif
 | 
						|
 | 
						|
DebugMapObject &
 | 
						|
DebugMap::addDebugMapObject(StringRef ObjectFilePath,
 | 
						|
                            sys::TimePoint<std::chrono::seconds> Timestamp,
 | 
						|
                            uint8_t Type) {
 | 
						|
  Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type));
 | 
						|
  return *Objects.back();
 | 
						|
}
 | 
						|
 | 
						|
const DebugMapObject::DebugMapEntry *
 | 
						|
DebugMapObject::lookupSymbol(StringRef SymbolName) const {
 | 
						|
  StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
 | 
						|
  if (Sym == Symbols.end())
 | 
						|
    return nullptr;
 | 
						|
  return &*Sym;
 | 
						|
}
 | 
						|
 | 
						|
const DebugMapObject::DebugMapEntry *
 | 
						|
DebugMapObject::lookupObjectAddress(uint64_t Address) const {
 | 
						|
  auto Mapping = AddressToMapping.find(Address);
 | 
						|
  if (Mapping == AddressToMapping.end())
 | 
						|
    return nullptr;
 | 
						|
  return Mapping->getSecond();
 | 
						|
}
 | 
						|
 | 
						|
void DebugMap::print(raw_ostream &OS) const {
 | 
						|
  yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
 | 
						|
  yout << const_cast<DebugMap &>(*this);
 | 
						|
}
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
void DebugMap::dump() const { print(errs()); }
 | 
						|
#endif
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
struct YAMLContext {
 | 
						|
  StringRef PrependPath;
 | 
						|
  Triple BinaryTriple;
 | 
						|
};
 | 
						|
 | 
						|
} // end anonymous namespace
 | 
						|
 | 
						|
ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
 | 
						|
DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
 | 
						|
                            bool Verbose) {
 | 
						|
  auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
 | 
						|
  if (auto Err = ErrOrFile.getError())
 | 
						|
    return Err;
 | 
						|
 | 
						|
  YAMLContext Ctxt;
 | 
						|
 | 
						|
  Ctxt.PrependPath = PrependPath;
 | 
						|
 | 
						|
  std::unique_ptr<DebugMap> Res;
 | 
						|
  yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
 | 
						|
  yin >> Res;
 | 
						|
 | 
						|
  if (auto EC = yin.error())
 | 
						|
    return EC;
 | 
						|
  std::vector<std::unique_ptr<DebugMap>> Result;
 | 
						|
  Result.push_back(std::move(Res));
 | 
						|
  return std::move(Result);
 | 
						|
}
 | 
						|
 | 
						|
} // end namespace dsymutil
 | 
						|
 | 
						|
namespace yaml {
 | 
						|
 | 
						|
// Normalize/Denormalize between YAML and a DebugMapObject.
 | 
						|
struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {
 | 
						|
  YamlDMO(IO &io) { Timestamp = 0; }
 | 
						|
  YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);
 | 
						|
  dsymutil::DebugMapObject denormalize(IO &IO);
 | 
						|
 | 
						|
  std::string Filename;
 | 
						|
  int64_t Timestamp;
 | 
						|
  std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
 | 
						|
};
 | 
						|
 | 
						|
void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>::
 | 
						|
    mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) {
 | 
						|
  io.mapRequired("sym", s.first);
 | 
						|
  io.mapOptional("objAddr", s.second.ObjectAddress);
 | 
						|
  io.mapRequired("binAddr", s.second.BinaryAddress);
 | 
						|
  io.mapOptional("size", s.second.Size);
 | 
						|
}
 | 
						|
 | 
						|
void MappingTraits<dsymutil::DebugMapObject>::mapping(
 | 
						|
    IO &io, dsymutil::DebugMapObject &DMO) {
 | 
						|
  MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);
 | 
						|
  io.mapRequired("filename", Norm->Filename);
 | 
						|
  io.mapOptional("timestamp", Norm->Timestamp);
 | 
						|
  io.mapRequired("symbols", Norm->Entries);
 | 
						|
}
 | 
						|
 | 
						|
void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) {
 | 
						|
  out << val.str();
 | 
						|
}
 | 
						|
 | 
						|
StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) {
 | 
						|
  value = Triple(scalar);
 | 
						|
  return StringRef();
 | 
						|
}
 | 
						|
 | 
						|
size_t
 | 
						|
SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size(
 | 
						|
    IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) {
 | 
						|
  return seq.size();
 | 
						|
}
 | 
						|
 | 
						|
dsymutil::DebugMapObject &
 | 
						|
SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
 | 
						|
    IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
 | 
						|
    size_t index) {
 | 
						|
  if (index >= seq.size()) {
 | 
						|
    seq.resize(index + 1);
 | 
						|
    seq[index].reset(new dsymutil::DebugMapObject);
 | 
						|
  }
 | 
						|
  return *seq[index];
 | 
						|
}
 | 
						|
 | 
						|
void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
 | 
						|
                                                dsymutil::DebugMap &DM) {
 | 
						|
  io.mapRequired("triple", DM.BinaryTriple);
 | 
						|
  io.mapOptional("binary-path", DM.BinaryPath);
 | 
						|
  if (void *Ctxt = io.getContext())
 | 
						|
    reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
 | 
						|
  io.mapOptional("objects", DM.Objects);
 | 
						|
}
 | 
						|
 | 
						|
void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
 | 
						|
    IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) {
 | 
						|
  if (!DM)
 | 
						|
    DM.reset(new DebugMap());
 | 
						|
  io.mapRequired("triple", DM->BinaryTriple);
 | 
						|
  io.mapOptional("binary-path", DM->BinaryPath);
 | 
						|
  if (void *Ctxt = io.getContext())
 | 
						|
    reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
 | 
						|
  io.mapOptional("objects", DM->Objects);
 | 
						|
}
 | 
						|
 | 
						|
MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
 | 
						|
    IO &io, dsymutil::DebugMapObject &Obj) {
 | 
						|
  Filename = Obj.Filename;
 | 
						|
  Timestamp = sys::toTimeT(Obj.getTimestamp());
 | 
						|
  Entries.reserve(Obj.Symbols.size());
 | 
						|
  for (auto &Entry : Obj.Symbols)
 | 
						|
    Entries.push_back(std::make_pair(Entry.getKey(), Entry.getValue()));
 | 
						|
}
 | 
						|
 | 
						|
dsymutil::DebugMapObject
 | 
						|
MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
 | 
						|
  BinaryHolder BinHolder(/* Verbose =*/false);
 | 
						|
  const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());
 | 
						|
  SmallString<80> Path(Ctxt.PrependPath);
 | 
						|
  StringMap<uint64_t> SymbolAddresses;
 | 
						|
 | 
						|
  sys::path::append(Path, Filename);
 | 
						|
 | 
						|
  auto ObjectEntry = BinHolder.getObjectEntry(Path);
 | 
						|
  if (!ObjectEntry) {
 | 
						|
    auto Err = ObjectEntry.takeError();
 | 
						|
    WithColor::warning() << "Unable to open " << Path << " "
 | 
						|
                         << toString(std::move(Err)) << '\n';
 | 
						|
  } else {
 | 
						|
    auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple);
 | 
						|
    if (!Object) {
 | 
						|
      auto Err = Object.takeError();
 | 
						|
      WithColor::warning() << "Unable to open " << Path << " "
 | 
						|
                           << toString(std::move(Err)) << '\n';
 | 
						|
    } else {
 | 
						|
      for (const auto &Sym : Object->symbols()) {
 | 
						|
        uint64_t Address = Sym.getValue();
 | 
						|
        Expected<StringRef> Name = Sym.getName();
 | 
						|
        if (!Name || (Sym.getFlags() &
 | 
						|
                      (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {
 | 
						|
          // TODO: Actually report errors helpfully.
 | 
						|
          if (!Name)
 | 
						|
            consumeError(Name.takeError());
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        SymbolAddresses[*Name] = Address;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO);
 | 
						|
  for (auto &Entry : Entries) {
 | 
						|
    auto &Mapping = Entry.second;
 | 
						|
    Optional<uint64_t> ObjAddress;
 | 
						|
    if (Mapping.ObjectAddress)
 | 
						|
      ObjAddress = *Mapping.ObjectAddress;
 | 
						|
    auto AddressIt = SymbolAddresses.find(Entry.first);
 | 
						|
    if (AddressIt != SymbolAddresses.end())
 | 
						|
      ObjAddress = AddressIt->getValue();
 | 
						|
    Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);
 | 
						|
  }
 | 
						|
  return Res;
 | 
						|
}
 | 
						|
 | 
						|
} // end namespace yaml
 | 
						|
} // end namespace llvm
 |