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::TimePoint<std::chrono::seconds> 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 &
66 DebugMap::addDebugMapObject(StringRef ObjectFilePath,
67                             sys::TimePoint<std::chrono::seconds> Timestamp) {
68   Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp));
69   return *Objects.back();
70 }
71 
72 const DebugMapObject::DebugMapEntry *
73 DebugMapObject::lookupSymbol(StringRef SymbolName) const {
74   StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
75   if (Sym == Symbols.end())
76     return nullptr;
77   return &*Sym;
78 }
79 
80 const DebugMapObject::DebugMapEntry *
81 DebugMapObject::lookupObjectAddress(uint64_t Address) const {
82   auto Mapping = AddressToMapping.find(Address);
83   if (Mapping == AddressToMapping.end())
84     return nullptr;
85   return Mapping->getSecond();
86 }
87 
88 void DebugMap::print(raw_ostream &OS) const {
89   yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
90   yout << const_cast<DebugMap &>(*this);
91 }
92 
93 #ifndef NDEBUG
94 void DebugMap::dump() const { print(errs()); }
95 #endif
96 
97 namespace {
98 struct YAMLContext {
99   StringRef PrependPath;
100   Triple BinaryTriple;
101 };
102 }
103 
104 ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
105 DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
106                             bool Verbose) {
107   auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
108   if (auto Err = ErrOrFile.getError())
109     return Err;
110 
111   YAMLContext Ctxt;
112 
113   Ctxt.PrependPath = PrependPath;
114 
115   std::unique_ptr<DebugMap> Res;
116   yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
117   yin >> Res;
118 
119   if (auto EC = yin.error())
120     return EC;
121   std::vector<std::unique_ptr<DebugMap>> Result;
122   Result.push_back(std::move(Res));
123   return std::move(Result);
124 }
125 }
126 
127 namespace yaml {
128 
129 // Normalize/Denormalize between YAML and a DebugMapObject.
130 struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {
131   YamlDMO(IO &io) { Timestamp = 0; }
132   YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);
133   dsymutil::DebugMapObject denormalize(IO &IO);
134 
135   std::string Filename;
136   int64_t Timestamp;
137   std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
138 };
139 
140 void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>::
141     mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) {
142   io.mapRequired("sym", s.first);
143   io.mapOptional("objAddr", s.second.ObjectAddress);
144   io.mapRequired("binAddr", s.second.BinaryAddress);
145   io.mapOptional("size", s.second.Size);
146 }
147 
148 void MappingTraits<dsymutil::DebugMapObject>::mapping(
149     IO &io, dsymutil::DebugMapObject &DMO) {
150   MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);
151   io.mapRequired("filename", Norm->Filename);
152   io.mapOptional("timestamp", Norm->Timestamp);
153   io.mapRequired("symbols", Norm->Entries);
154 }
155 
156 void ScalarTraits<Triple>::output(const Triple &val, void *,
157                                   llvm::raw_ostream &out) {
158   out << val.str();
159 }
160 
161 StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) {
162   value = Triple(scalar);
163   return StringRef();
164 }
165 
166 size_t
167 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size(
168     IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) {
169   return seq.size();
170 }
171 
172 dsymutil::DebugMapObject &
173 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
174     IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
175     size_t index) {
176   if (index >= seq.size()) {
177     seq.resize(index + 1);
178     seq[index].reset(new dsymutil::DebugMapObject);
179   }
180   return *seq[index];
181 }
182 
183 void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
184                                                 dsymutil::DebugMap &DM) {
185   io.mapRequired("triple", DM.BinaryTriple);
186   io.mapOptional("binary-path", DM.BinaryPath);
187   if (void *Ctxt = io.getContext())
188     reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
189   io.mapOptional("objects", DM.Objects);
190 }
191 
192 void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
193     IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) {
194   if (!DM)
195     DM.reset(new DebugMap());
196   io.mapRequired("triple", DM->BinaryTriple);
197   io.mapOptional("binary-path", DM->BinaryPath);
198   if (void *Ctxt = io.getContext())
199     reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
200   io.mapOptional("objects", DM->Objects);
201 }
202 
203 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
204     IO &io, dsymutil::DebugMapObject &Obj) {
205   Filename = Obj.Filename;
206   Timestamp = sys::toTimeT(Obj.getTimestamp());
207   Entries.reserve(Obj.Symbols.size());
208   for (auto &Entry : Obj.Symbols)
209     Entries.push_back(std::make_pair(Entry.getKey(), Entry.getValue()));
210 }
211 
212 dsymutil::DebugMapObject
213 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
214   BinaryHolder BinHolder(/* Verbose =*/false);
215   const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());
216   SmallString<80> Path(Ctxt.PrependPath);
217   StringMap<uint64_t> SymbolAddresses;
218 
219   sys::path::append(Path, Filename);
220   auto ErrOrObjectFiles = BinHolder.GetObjectFiles(Path);
221   if (auto EC = ErrOrObjectFiles.getError()) {
222     llvm::errs() << "warning: Unable to open " << Path << " " << EC.message()
223                  << '\n';
224   } else if (auto ErrOrObjectFile = BinHolder.Get(Ctxt.BinaryTriple)) {
225     // Rewrite the object file symbol addresses in the debug map. The
226     // YAML input is mainly used to test llvm-dsymutil without
227     // requiring binaries checked-in. If we generate the object files
228     // during the test, we can't hardcode the symbols addresses, so
229     // look them up here and rewrite them.
230     for (const auto &Sym : ErrOrObjectFile->symbols()) {
231       uint64_t Address = Sym.getValue();
232       Expected<StringRef> Name = Sym.getName();
233       if (!Name ||
234           (Sym.getFlags() & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {
235         // TODO: Actually report errors helpfully.
236         if (!Name)
237           consumeError(Name.takeError());
238         continue;
239       }
240       SymbolAddresses[*Name] = Address;
241     }
242   }
243 
244   dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp));
245   for (auto &Entry : Entries) {
246     auto &Mapping = Entry.second;
247     Optional<uint64_t> ObjAddress;
248     if (Mapping.ObjectAddress)
249       ObjAddress = *Mapping.ObjectAddress;
250     auto AddressIt = SymbolAddresses.find(Entry.first);
251     if (AddressIt != SymbolAddresses.end())
252       ObjAddress = AddressIt->getValue();
253     Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);
254   }
255   return Res;
256 }
257 }
258 }
259