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 | |
44 | namespace llvm { |
45 | |
46 | class raw_ostream; |
47 | |
48 | namespace dsymutil { |
49 | |
50 | class DebugMapObject; |
51 | |
52 | /// The DebugMap object stores the list of object files to query for debug |
53 | /// information along with the mapping between the symbols' addresses in the |
54 | /// object file to their linked address in the linked binary. |
55 | /// |
56 | /// A DebugMap producer could look like this: |
57 | /// DebugMap *DM = new DebugMap(); |
58 | /// for (const auto &Obj: LinkedObjects) { |
59 | /// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath()); |
60 | /// for (const auto &Sym: Obj.getLinkedSymbols()) |
61 | /// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(), |
62 | /// Sym.getBinaryAddress()); |
63 | /// } |
64 | /// |
65 | /// A DebugMap consumer can then use the map to link the debug |
66 | /// information. For example something along the lines of: |
67 | /// for (const auto &DMO: DM->objects()) { |
68 | /// auto Obj = createBinary(DMO.getObjectFilename()); |
69 | /// for (auto &DIE: Obj.getDwarfDIEs()) { |
70 | /// if (SymbolMapping *Sym = DMO.lookup(DIE.getName())) |
71 | /// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress); |
72 | /// else |
73 | /// DIE.discardSubtree(); |
74 | /// } |
75 | /// } |
76 | class DebugMap { |
77 | Triple BinaryTriple; |
78 | std::string BinaryPath; |
79 | std::vector<uint8_t> BinaryUUID; |
80 | using ObjectContainer = std::vector<std::unique_ptr<DebugMapObject>>; |
81 | |
82 | ObjectContainer Objects; |
83 | |
84 | /// For YAML IO support. |
85 | ///@{ |
86 | friend yaml::MappingTraits<std::unique_ptr<DebugMap>>; |
87 | friend yaml::MappingTraits<DebugMap>; |
88 | |
89 | DebugMap() = default; |
90 | ///@} |
91 | |
92 | public: |
93 | DebugMap(const Triple &BinaryTriple, StringRef BinaryPath, |
94 | ArrayRef<uint8_t> BinaryUUID = ArrayRef<uint8_t>()) |
95 | : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)), |
96 | BinaryUUID(BinaryUUID.begin(), BinaryUUID.end()) {} |
97 | |
98 | using const_iterator = ObjectContainer::const_iterator; |
99 | |
100 | iterator_range<const_iterator> objects() const { |
101 | return make_range(x: begin(), y: end()); |
102 | } |
103 | |
104 | const_iterator begin() const { return Objects.begin(); } |
105 | |
106 | const_iterator end() const { return Objects.end(); } |
107 | |
108 | unsigned getNumberOfObjects() const { return Objects.size(); } |
109 | |
110 | /// This function adds an DebugMapObject to the list owned by this |
111 | /// debug map. |
112 | DebugMapObject & |
113 | addDebugMapObject(StringRef ObjectFilePath, |
114 | sys::TimePoint<std::chrono::seconds> Timestamp, |
115 | uint8_t Type = llvm::MachO::N_OSO); |
116 | |
117 | const Triple &getTriple() const { return BinaryTriple; } |
118 | |
119 | ArrayRef<uint8_t> getUUID() const { return ArrayRef<uint8_t>(BinaryUUID); } |
120 | |
121 | StringRef getBinaryPath() const { return BinaryPath; } |
122 | |
123 | void print(raw_ostream &OS) const; |
124 | |
125 | #ifndef NDEBUG |
126 | void dump() const; |
127 | #endif |
128 | |
129 | /// Read a debug map for \a InputFile. |
130 | static ErrorOr<std::vector<std::unique_ptr<DebugMap>>> |
131 | parseYAMLDebugMap(BinaryHolder &BinHolder, StringRef InputFile, |
132 | StringRef PrependPath, bool Verbose); |
133 | }; |
134 | |
135 | /// The DebugMapObject represents one object file described by the DebugMap. It |
136 | /// contains a list of mappings between addresses in the object file and in the |
137 | /// linked binary for all the linked atoms in this object file. |
138 | class DebugMapObject { |
139 | public: |
140 | using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>; |
141 | using DebugMapEntry = StringMapEntry<SymbolMapping>; |
142 | |
143 | /// Adds a symbol mapping to this DebugMapObject. |
144 | /// \returns false if the symbol was already registered. The request |
145 | /// is discarded in this case. |
146 | bool addSymbol(StringRef SymName, std::optional<uint64_t> ObjectAddress, |
147 | uint64_t LinkedAddress, uint32_t Size); |
148 | |
149 | /// Lookup a symbol mapping. |
150 | /// \returns null if the symbol isn't found. |
151 | const DebugMapEntry *lookupSymbol(StringRef SymbolName) const; |
152 | |
153 | /// Lookup an object file address. |
154 | /// \returns null if the address isn't found. |
155 | const DebugMapEntry *lookupObjectAddress(uint64_t Address) const; |
156 | |
157 | StringRef getObjectFilename() const { return Filename; } |
158 | |
159 | sys::TimePoint<std::chrono::seconds> getTimestamp() const { |
160 | return Timestamp; |
161 | } |
162 | |
163 | uint8_t getType() const { return Type; } |
164 | |
165 | bool empty() const { return Symbols.empty(); } |
166 | |
167 | void addWarning(StringRef Warning) { |
168 | Warnings.push_back(x: std::string(Warning)); |
169 | } |
170 | const std::vector<std::string> &getWarnings() const { return Warnings; } |
171 | |
172 | const std::optional<RelocationMap> &getRelocationMap() const { |
173 | return RelocMap; |
174 | } |
175 | void setRelocationMap(dsymutil::RelocationMap &RM); |
176 | |
177 | const std::optional<std::string> &getInstallName() const { |
178 | return InstallName; |
179 | } |
180 | void setInstallName(StringRef IN); |
181 | |
182 | void print(raw_ostream &OS) const; |
183 | #ifndef NDEBUG |
184 | void dump() const; |
185 | #endif |
186 | |
187 | private: |
188 | friend class DebugMap; |
189 | |
190 | /// DebugMapObjects can only be constructed by the owning DebugMap. |
191 | DebugMapObject(StringRef ObjectFilename, |
192 | sys::TimePoint<std::chrono::seconds> Timestamp, uint8_t Type); |
193 | |
194 | std::string Filename; |
195 | sys::TimePoint<std::chrono::seconds> Timestamp; |
196 | StringMap<struct SymbolMapping> Symbols; |
197 | DenseMap<uint64_t, DebugMapEntry *> AddressToMapping; |
198 | uint8_t Type; |
199 | |
200 | std::optional<RelocationMap> RelocMap; |
201 | std::optional<std::string> InstallName; |
202 | |
203 | std::vector<std::string> Warnings; |
204 | |
205 | /// For YAMLIO support. |
206 | ///@{ |
207 | friend yaml::MappingTraits<dsymutil::DebugMapObject>; |
208 | friend yaml::SequenceTraits<std::vector<std::unique_ptr<DebugMapObject>>>; |
209 | |
210 | DebugMapObject() = default; |
211 | |
212 | public: |
213 | DebugMapObject(DebugMapObject &&) = default; |
214 | DebugMapObject &operator=(DebugMapObject &&) = default; |
215 | ///@} |
216 | }; |
217 | |
218 | } // end namespace dsymutil |
219 | } // end namespace llvm |
220 | |
221 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::dsymutil::DebugMapObject::YAMLSymbolMapping) |
222 | |
223 | namespace llvm { |
224 | namespace yaml { |
225 | |
226 | using namespace llvm::dsymutil; |
227 | |
228 | template <> struct MappingTraits<std::pair<std::string, SymbolMapping>> { |
229 | static void mapping(IO &io, std::pair<std::string, SymbolMapping> &s); |
230 | static const bool flow = true; |
231 | }; |
232 | |
233 | template <> struct MappingTraits<dsymutil::DebugMapObject> { |
234 | struct YamlDMO; |
235 | static void mapping(IO &io, dsymutil::DebugMapObject &DMO); |
236 | }; |
237 | |
238 | template <> |
239 | struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> { |
240 | static size_t |
241 | size(IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq); |
242 | static dsymutil::DebugMapObject & |
243 | element(IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq, |
244 | size_t index); |
245 | }; |
246 | |
247 | template <> struct MappingTraits<dsymutil::DebugMap> { |
248 | static void mapping(IO &io, dsymutil::DebugMap &DM); |
249 | }; |
250 | |
251 | template <> struct MappingTraits<std::unique_ptr<dsymutil::DebugMap>> { |
252 | static void mapping(IO &io, std::unique_ptr<dsymutil::DebugMap> &DM); |
253 | }; |
254 | |
255 | } // end namespace yaml |
256 | } // end namespace llvm |
257 | |
258 | #endif // LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H |
259 | |