1//=- tools/dsymutil/DebugMap.h - Generic debug map representation -*- 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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10///
11/// This file contains the class declaration of the DebugMap
12/// entity. A DebugMap lists all the object files linked together to
13/// produce an executable along with the linked address of all the
14/// atoms used in these object files.
15/// The DebugMap is an input to the DwarfLinker class that will
16/// extract the Dwarf debug information from the referenced object
17/// files and link their usefull debug info together.
18//
19//===----------------------------------------------------------------------===//
20
21#ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
22#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
23
24#include "BinaryHolder.h"
25#include "RelocationMap.h"
26#include "llvm/ADT/DenseMap.h"
27#include "llvm/ADT/StringMap.h"
28#include "llvm/ADT/StringRef.h"
29#include "llvm/ADT/iterator_range.h"
30#include "llvm/Object/MachO.h"
31#include "llvm/Support/Chrono.h"
32#include "llvm/Support/ErrorOr.h"
33#include "llvm/Support/YAMLTraits.h"
34#include "llvm/TargetParser/Triple.h"
35#include <chrono>
36#include <cstddef>
37#include <cstdint>
38#include <memory>
39#include <optional>
40#include <string>
41#include <utility>
42#include <vector>
43
44namespace llvm {
45
46class raw_ostream;
47
48namespace dsymutil {
49
50class DebugMapObject;
51class DebugMapObjectFilter;
52
53class DebugMapFilter {
54 using ObjectContainer = std::vector<std::unique_ptr<DebugMapObjectFilter>>;
55
56public:
57 virtual ~DebugMapFilter() = default;
58 using const_iterator = ObjectContainer::const_iterator;
59
60 iterator_range<const_iterator> objects() const {
61 return make_range(x: begin(), y: end());
62 }
63
64 const_iterator begin() const { return Objects.begin(); }
65
66 const_iterator end() const { return Objects.end(); }
67
68protected:
69 std::vector<std::unique_ptr<DebugMapObjectFilter>> Objects;
70
71private:
72 friend class DebugMap;
73
74 /// For YAML IO support.
75 ///@{
76 friend yaml::MappingTraits<std::unique_ptr<DebugMapFilter>>;
77 friend yaml::MappingTraits<DebugMapFilter>;
78
79 DebugMapFilter() = default;
80
81public:
82 DebugMapFilter(DebugMapFilter &&) = default;
83 DebugMapFilter &operator=(DebugMapFilter &&) = default;
84 ///@}
85};
86
87/// The DebugMap object stores the list of object files to query for debug
88/// information along with the mapping between the symbols' addresses in the
89/// object file to their linked address in the linked binary.
90///
91/// A DebugMap producer could look like this:
92/// DebugMap *DM = new DebugMap();
93/// for (const auto &Obj: LinkedObjects) {
94/// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath());
95/// for (const auto &Sym: Obj.getLinkedSymbols())
96/// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(),
97/// Sym.getBinaryAddress());
98/// }
99///
100/// A DebugMap consumer can then use the map to link the debug
101/// information. For example something along the lines of:
102/// for (const auto &DMO: DM->objects()) {
103/// auto Obj = createBinary(DMO.getObjectFilename());
104/// for (auto &DIE: Obj.getDwarfDIEs()) {
105/// if (SymbolMapping *Sym = DMO.lookup(DIE.getName()))
106/// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress);
107/// else
108/// DIE.discardSubtree();
109/// }
110/// }
111class DebugMap : public DebugMapFilter {
112 Triple BinaryTriple;
113 std::string BinaryPath;
114 std::vector<uint8_t> BinaryUUID;
115 using ObjectContainer = std::vector<std::unique_ptr<DebugMapObject>>;
116
117 ObjectContainer &getObjects() {
118 return reinterpret_cast<ObjectContainer &>(Objects);
119 }
120 const ObjectContainer &getObjects() const {
121 return reinterpret_cast<const ObjectContainer &>(Objects);
122 }
123
124 /// For YAML IO support.
125 ///@{
126 friend yaml::MappingTraits<std::unique_ptr<DebugMap>>;
127 friend yaml::MappingTraits<DebugMap>;
128
129 DebugMap() = default;
130 ///@}
131
132public:
133 DebugMap(const Triple &BinaryTriple, StringRef BinaryPath,
134 ArrayRef<uint8_t> BinaryUUID = ArrayRef<uint8_t>());
135
136 using const_iterator = ObjectContainer::const_iterator;
137
138 iterator_range<const_iterator> objects() const {
139 return make_range(x: begin(), y: end());
140 }
141
142 const_iterator begin() const { return getObjects().begin(); }
143
144 const_iterator end() const { return getObjects().end(); }
145
146 unsigned getNumberOfObjects() const { return Objects.size(); }
147
148 /// This function adds an DebugMapObject to the list owned by this
149 /// debug map.
150 DebugMapObject &
151 addDebugMapObject(StringRef ObjectFilePath,
152 sys::TimePoint<std::chrono::seconds> Timestamp,
153 uint8_t Type = llvm::MachO::N_OSO);
154
155 const Triple &getTriple() const { return BinaryTriple; }
156
157 ArrayRef<uint8_t> getUUID() const { return ArrayRef<uint8_t>(BinaryUUID); }
158
159 StringRef getBinaryPath() const { return BinaryPath; }
160
161 void print(raw_ostream &OS) const;
162
163#ifndef NDEBUG
164 void dump() const;
165#endif
166
167 /// Read a debug map for \a InputFile.
168 static ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
169 parseYAMLDebugMap(BinaryHolder &BinHolder, StringRef InputFile,
170 StringRef PrependPath, bool Verbose);
171};
172
173class DebugMapObjectFilter {
174public:
175 virtual ~DebugMapObjectFilter() = default;
176 StringRef getObjectFilename() const { return Filename; }
177
178protected:
179 std::string Filename;
180
181private:
182 friend class DebugMapFilter;
183 friend class DebugMapObject;
184
185 DebugMapObjectFilter(StringRef ObjectFilename);
186
187 /// For YAMLIO support.
188 ///@{
189 friend yaml::MappingTraits<dsymutil::DebugMapObjectFilter>;
190 friend yaml::SequenceTraits<
191 std::vector<std::unique_ptr<DebugMapObjectFilter>>>;
192
193 DebugMapObjectFilter() = default;
194
195public:
196 DebugMapObjectFilter(DebugMapObjectFilter &&) = default;
197 DebugMapObjectFilter &operator=(DebugMapObjectFilter &&) = default;
198 ///@}
199};
200
201/// The DebugMapObject represents one object file described by the DebugMap. It
202/// contains a list of mappings between addresses in the object file and in the
203/// linked binary for all the linked atoms in this object file.
204class DebugMapObject : public DebugMapObjectFilter {
205public:
206 using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>;
207 using DebugMapEntry = StringMapEntry<SymbolMapping>;
208
209 /// Adds a symbol mapping to this DebugMapObject.
210 /// \returns false if the symbol was already registered. The request
211 /// is discarded in this case.
212 bool addSymbol(StringRef SymName, std::optional<uint64_t> ObjectAddress,
213 uint64_t LinkedAddress, uint32_t Size);
214
215 /// Lookup a symbol mapping.
216 /// \returns null if the symbol isn't found.
217 const DebugMapEntry *lookupSymbol(StringRef SymbolName) const;
218
219 /// Lookup an object file address.
220 /// \returns null if the address isn't found.
221 const DebugMapEntry *lookupObjectAddress(uint64_t Address) const;
222
223 sys::TimePoint<std::chrono::seconds> getTimestamp() const {
224 return Timestamp;
225 }
226
227 uint8_t getType() const { return Type; }
228
229 bool empty() const { return Symbols.empty(); }
230
231 void addWarning(StringRef Warning) {
232 Warnings.push_back(x: std::string(Warning));
233 }
234 const std::vector<std::string> &getWarnings() const { return Warnings; }
235
236 const std::optional<RelocationMap> &getRelocationMap() const {
237 return RelocMap;
238 }
239 void setRelocationMap(dsymutil::RelocationMap &RM);
240
241 const std::optional<std::string> &getInstallName() const {
242 return InstallName;
243 }
244 void setInstallName(StringRef IN);
245
246 void print(raw_ostream &OS) const;
247#ifndef NDEBUG
248 void dump() const;
249#endif
250
251private:
252 friend class DebugMap;
253
254 /// DebugMapObjects can only be constructed by the owning DebugMap.
255 DebugMapObject(StringRef ObjectFilename,
256 sys::TimePoint<std::chrono::seconds> Timestamp, uint8_t Type);
257
258 sys::TimePoint<std::chrono::seconds> Timestamp;
259 StringMap<struct SymbolMapping> Symbols;
260 DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
261 uint8_t Type;
262
263 std::optional<RelocationMap> RelocMap;
264 std::optional<std::string> InstallName;
265
266 std::vector<std::string> Warnings;
267
268 /// For YAMLIO support.
269 ///@{
270 friend yaml::MappingTraits<dsymutil::DebugMapObject>;
271 friend yaml::SequenceTraits<std::vector<std::unique_ptr<DebugMapObject>>>;
272
273 DebugMapObject() = default;
274
275public:
276 DebugMapObject(DebugMapObject &&) = default;
277 DebugMapObject &operator=(DebugMapObject &&) = default;
278 ///@}
279};
280
281} // end namespace dsymutil
282} // end namespace llvm
283
284LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::dsymutil::DebugMapObject::YAMLSymbolMapping)
285
286namespace llvm {
287namespace yaml {
288
289using namespace llvm::dsymutil;
290
291template <> struct MappingTraits<std::pair<std::string, SymbolMapping>> {
292 static void mapping(IO &io, std::pair<std::string, SymbolMapping> &s);
293 static const bool flow = true;
294};
295
296template <> struct MappingTraits<dsymutil::DebugMapObject> {
297 struct YamlDMO;
298 static void mapping(IO &io, dsymutil::DebugMapObject &DMO);
299};
300
301template <>
302struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> {
303 static size_t
304 size(IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq);
305 static dsymutil::DebugMapObject &
306 element(IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
307 size_t index);
308};
309
310template <> struct MappingTraits<dsymutil::DebugMapObjectFilter> {
311 static void mapping(IO &io, dsymutil::DebugMapObjectFilter &DMO);
312};
313
314template <>
315struct SequenceTraits<
316 std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>>> {
317 static size_t
318 size(IO &io,
319 std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>> &seq);
320 static dsymutil::DebugMapObjectFilter &
321 element(IO &,
322 std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>> &seq,
323 size_t index);
324};
325
326template <> struct MappingTraits<dsymutil::DebugMap> {
327 static void mapping(IO &io, dsymutil::DebugMap &DM);
328};
329
330template <> struct MappingTraits<std::unique_ptr<dsymutil::DebugMap>> {
331 static void mapping(IO &io, std::unique_ptr<dsymutil::DebugMap> &DM);
332};
333
334template <> struct MappingTraits<dsymutil::DebugMapFilter> {
335 static void mapping(IO &io, dsymutil::DebugMapFilter &DMF);
336};
337
338template <> struct MappingTraits<std::unique_ptr<dsymutil::DebugMapFilter>> {
339 static void mapping(IO &io, std::unique_ptr<dsymutil::DebugMapFilter> &DMF);
340};
341
342} // end namespace yaml
343} // end namespace llvm
344
345#endif // LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
346