Home | History | Annotate | Download | only in dsymutil
      1 //===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
      2 //
      3 //                             The LLVM Linker
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #include "DebugMap.h"
     10 #include "BinaryHolder.h"
     11 #include "llvm/ADT/STLExtras.h"
     12 #include "llvm/ADT/iterator_range.h"
     13 #include "llvm/Support/DataTypes.h"
     14 #include "llvm/Support/Format.h"
     15 #include "llvm/Support/raw_ostream.h"
     16 #include <algorithm>
     17 
     18 namespace llvm {
     19 namespace dsymutil {
     20 
     21 using namespace llvm::object;
     22 
     23 DebugMapObject::DebugMapObject(StringRef ObjectFilename,
     24                                sys::TimeValue Timestamp)
     25     : Filename(ObjectFilename), Timestamp(Timestamp) {}
     26 
     27 bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress,
     28                                uint64_t LinkedAddress, uint32_t Size) {
     29   auto InsertResult = Symbols.insert(
     30       std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
     31 
     32   if (ObjectAddress && InsertResult.second)
     33     AddressToMapping[*ObjectAddress] = &*InsertResult.first;
     34   return InsertResult.second;
     35 }
     36 
     37 void DebugMapObject::print(raw_ostream &OS) const {
     38   OS << getObjectFilename() << ":\n";
     39   // Sort the symbols in alphabetical order, like llvm-nm (and to get
     40   // deterministic output for testing).
     41   typedef std::pair<StringRef, SymbolMapping> Entry;
     42   std::vector<Entry> Entries;
     43   Entries.reserve(Symbols.getNumItems());
     44   for (const auto &Sym : make_range(Symbols.begin(), Symbols.end()))
     45     Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue()));
     46   std::sort(
     47       Entries.begin(), Entries.end(),
     48       [](const Entry &LHS, const Entry &RHS) { return LHS.first < RHS.first; });
     49   for (const auto &Sym : Entries) {
     50     if (Sym.second.ObjectAddress)
     51       OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress));
     52     else
     53       OS << "\t????????????????";
     54     OS << format(" => %016" PRIx64 "+0x%x\t%s\n",
     55                  uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size),
     56                  Sym.first.data());
     57   }
     58   OS << '\n';
     59 }
     60 
     61 #ifndef NDEBUG
     62 void DebugMapObject::dump() const { print(errs()); }
     63 #endif
     64 
     65 DebugMapObject &DebugMap::addDebugMapObject(StringRef ObjectFilePath,
     66                                             sys::TimeValue Timestamp) {
     67   Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp));
     68   return *Objects.back();
     69 }
     70 
     71 const DebugMapObject::DebugMapEntry *
     72 DebugMapObject::lookupSymbol(StringRef SymbolName) const {
     73   StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
     74   if (Sym == Symbols.end())
     75     return nullptr;
     76   return &*Sym;
     77 }
     78 
     79 const DebugMapObject::DebugMapEntry *
     80 DebugMapObject::lookupObjectAddress(uint64_t Address) const {
     81   auto Mapping = AddressToMapping.find(Address);
     82   if (Mapping == AddressToMapping.end())
     83     return nullptr;
     84   return Mapping->getSecond();
     85 }
     86 
     87 void DebugMap::print(raw_ostream &OS) const {
     88   yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
     89   yout << const_cast<DebugMap &>(*this);
     90 }
     91 
     92 #ifndef NDEBUG
     93 void DebugMap::dump() const { print(errs()); }
     94 #endif
     95 
     96 namespace {
     97 struct YAMLContext {
     98   StringRef PrependPath;
     99   Triple BinaryTriple;
    100 };
    101 }
    102 
    103 ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
    104 DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
    105                             bool Verbose) {
    106   auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
    107   if (auto Err = ErrOrFile.getError())
    108     return Err;
    109 
    110   YAMLContext Ctxt;
    111 
    112   Ctxt.PrependPath = PrependPath;
    113 
    114   std::unique_ptr<DebugMap> Res;
    115   yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
    116   yin >> Res;
    117 
    118   if (auto EC = yin.error())
    119     return EC;
    120   std::vector<std::unique_ptr<DebugMap>> Result;
    121   Result.push_back(std::move(Res));
    122   return std::move(Result);
    123 }
    124 }
    125 
    126 namespace yaml {
    127 
    128 // Normalize/Denormalize between YAML and a DebugMapObject.
    129 struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {
    130   YamlDMO(IO &io) { Timestamp = 0; }
    131   YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);
    132   dsymutil::DebugMapObject denormalize(IO &IO);
    133 
    134   std::string Filename;
    135   sys::TimeValue::SecondsType Timestamp;
    136   std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
    137 };
    138 
    139 void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>::
    140     mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) {
    141   io.mapRequired("sym", s.first);
    142   io.mapOptional("objAddr", s.second.ObjectAddress);
    143   io.mapRequired("binAddr", s.second.BinaryAddress);
    144   io.mapOptional("size", s.second.Size);
    145 }
    146 
    147 void MappingTraits<dsymutil::DebugMapObject>::mapping(
    148     IO &io, dsymutil::DebugMapObject &DMO) {
    149   MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);
    150   io.mapRequired("filename", Norm->Filename);
    151   io.mapOptional("timestamp", Norm->Timestamp);
    152   io.mapRequired("symbols", Norm->Entries);
    153 }
    154 
    155 void ScalarTraits<Triple>::output(const Triple &val, void *,
    156                                   llvm::raw_ostream &out) {
    157   out << val.str();
    158 }
    159 
    160 StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) {
    161   value = Triple(scalar);
    162   return StringRef();
    163 }
    164 
    165 size_t
    166 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size(
    167     IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) {
    168   return seq.size();
    169 }
    170 
    171 dsymutil::DebugMapObject &
    172 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
    173     IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
    174     size_t index) {
    175   if (index >= seq.size()) {
    176     seq.resize(index + 1);
    177     seq[index].reset(new dsymutil::DebugMapObject);
    178   }
    179   return *seq[index];
    180 }
    181 
    182 void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
    183                                                 dsymutil::DebugMap &DM) {
    184   io.mapRequired("triple", DM.BinaryTriple);
    185   io.mapOptional("binary-path", DM.BinaryPath);
    186   if (void *Ctxt = io.getContext())
    187     reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
    188   io.mapOptional("objects", DM.Objects);
    189 }
    190 
    191 void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
    192     IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) {
    193   if (!DM)
    194     DM.reset(new DebugMap());
    195   io.mapRequired("triple", DM->BinaryTriple);
    196   io.mapOptional("binary-path", DM->BinaryPath);
    197   if (void *Ctxt = io.getContext())
    198     reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
    199   io.mapOptional("objects", DM->Objects);
    200 }
    201 
    202 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
    203     IO &io, dsymutil::DebugMapObject &Obj) {
    204   Filename = Obj.Filename;
    205   Timestamp = Obj.getTimestamp().toEpochTime();
    206   Entries.reserve(Obj.Symbols.size());
    207   for (auto &Entry : Obj.Symbols)
    208     Entries.push_back(std::make_pair(Entry.getKey(), Entry.getValue()));
    209 }
    210 
    211 dsymutil::DebugMapObject
    212 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
    213   BinaryHolder BinHolder(/* Verbose =*/false);
    214   const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());
    215   SmallString<80> Path(Ctxt.PrependPath);
    216   StringMap<uint64_t> SymbolAddresses;
    217 
    218   sys::path::append(Path, Filename);
    219   auto ErrOrObjectFiles = BinHolder.GetObjectFiles(Path);
    220   if (auto EC = ErrOrObjectFiles.getError()) {
    221     llvm::errs() << "warning: Unable to open " << Path << " " << EC.message()
    222                  << '\n';
    223   } else if (auto ErrOrObjectFile = BinHolder.Get(Ctxt.BinaryTriple)) {
    224     // Rewrite the object file symbol addresses in the debug map. The
    225     // YAML input is mainly used to test llvm-dsymutil without
    226     // requiring binaries checked-in. If we generate the object files
    227     // during the test, we can't hardcode the symbols addresses, so
    228     // look them up here and rewrite them.
    229     for (const auto &Sym : ErrOrObjectFile->symbols()) {
    230       uint64_t Address = Sym.getValue();
    231       Expected<StringRef> Name = Sym.getName();
    232       if (!Name ||
    233           (Sym.getFlags() & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {
    234         // TODO: Actually report errors helpfully.
    235         if (!Name)
    236           consumeError(Name.takeError());
    237         continue;
    238       }
    239       SymbolAddresses[*Name] = Address;
    240     }
    241   }
    242 
    243   sys::TimeValue TV;
    244   TV.fromEpochTime(Timestamp);
    245   dsymutil::DebugMapObject Res(Path, TV);
    246   for (auto &Entry : Entries) {
    247     auto &Mapping = Entry.second;
    248     Optional<uint64_t> ObjAddress;
    249     if (Mapping.ObjectAddress)
    250       ObjAddress = *Mapping.ObjectAddress;
    251     auto AddressIt = SymbolAddresses.find(Entry.first);
    252     if (AddressIt != SymbolAddresses.end())
    253       ObjAddress = AddressIt->getValue();
    254     Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);
    255   }
    256   return Res;
    257 }
    258 }
    259 }
    260