Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- DWARFContext.h -------------------------------------------*- 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 | #ifndef LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H |
||
10 | #define LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H |
||
11 | |||
12 | #include "llvm/ADT/SmallVector.h" |
||
13 | #include "llvm/ADT/StringMap.h" |
||
14 | #include "llvm/ADT/StringRef.h" |
||
15 | #include "llvm/DebugInfo/DIContext.h" |
||
16 | #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
||
17 | #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
||
18 | #include "llvm/DebugInfo/DWARF/DWARFObject.h" |
||
19 | #include "llvm/DebugInfo/DWARF/DWARFUnit.h" |
||
20 | #include "llvm/Object/Binary.h" |
||
21 | #include "llvm/Object/ObjectFile.h" |
||
22 | #include "llvm/Support/DataExtractor.h" |
||
23 | #include "llvm/Support/Error.h" |
||
24 | #include "llvm/Support/Host.h" |
||
25 | #include <cstdint> |
||
26 | #include <memory> |
||
27 | |||
28 | namespace llvm { |
||
29 | |||
30 | class MemoryBuffer; |
||
31 | class AppleAcceleratorTable; |
||
32 | class DWARFCompileUnit; |
||
33 | class DWARFDebugAbbrev; |
||
34 | class DWARFDebugAranges; |
||
35 | class DWARFDebugFrame; |
||
36 | class DWARFDebugLoc; |
||
37 | class DWARFDebugMacro; |
||
38 | class DWARFDebugNames; |
||
39 | class DWARFGdbIndex; |
||
40 | class DWARFTypeUnit; |
||
41 | class DWARFUnitIndex; |
||
42 | |||
43 | /// DWARFContext |
||
44 | /// This data structure is the top level entity that deals with dwarf debug |
||
45 | /// information parsing. The actual data is supplied through DWARFObj. |
||
46 | class DWARFContext : public DIContext { |
||
47 | DWARFUnitVector NormalUnits; |
||
48 | std::optional<DenseMap<uint64_t, DWARFTypeUnit *>> NormalTypeUnits; |
||
49 | std::unique_ptr<DWARFUnitIndex> CUIndex; |
||
50 | std::unique_ptr<DWARFGdbIndex> GdbIndex; |
||
51 | std::unique_ptr<DWARFUnitIndex> TUIndex; |
||
52 | std::unique_ptr<DWARFDebugAbbrev> Abbrev; |
||
53 | std::unique_ptr<DWARFDebugLoc> Loc; |
||
54 | std::unique_ptr<DWARFDebugAranges> Aranges; |
||
55 | std::unique_ptr<DWARFDebugLine> Line; |
||
56 | std::unique_ptr<DWARFDebugFrame> DebugFrame; |
||
57 | std::unique_ptr<DWARFDebugFrame> EHFrame; |
||
58 | std::unique_ptr<DWARFDebugMacro> Macro; |
||
59 | std::unique_ptr<DWARFDebugMacro> Macinfo; |
||
60 | std::unique_ptr<DWARFDebugNames> Names; |
||
61 | std::unique_ptr<AppleAcceleratorTable> AppleNames; |
||
62 | std::unique_ptr<AppleAcceleratorTable> AppleTypes; |
||
63 | std::unique_ptr<AppleAcceleratorTable> AppleNamespaces; |
||
64 | std::unique_ptr<AppleAcceleratorTable> AppleObjC; |
||
65 | |||
66 | DWARFUnitVector DWOUnits; |
||
67 | std::optional<DenseMap<uint64_t, DWARFTypeUnit *>> DWOTypeUnits; |
||
68 | std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO; |
||
69 | std::unique_ptr<DWARFDebugMacro> MacinfoDWO; |
||
70 | std::unique_ptr<DWARFDebugMacro> MacroDWO; |
||
71 | |||
72 | /// The maximum DWARF version of all units. |
||
73 | unsigned MaxVersion = 0; |
||
74 | |||
75 | struct DWOFile { |
||
76 | object::OwningBinary<object::ObjectFile> File; |
||
77 | std::unique_ptr<DWARFContext> Context; |
||
78 | }; |
||
79 | StringMap<std::weak_ptr<DWOFile>> DWOFiles; |
||
80 | std::weak_ptr<DWOFile> DWP; |
||
81 | bool CheckedForDWP = false; |
||
82 | std::string DWPName; |
||
83 | std::function<void(Error)> RecoverableErrorHandler = |
||
84 | WithColor::defaultErrorHandler; |
||
85 | std::function<void(Error)> WarningHandler = WithColor::defaultWarningHandler; |
||
86 | |||
87 | /// Read compile units from the debug_info section (if necessary) |
||
88 | /// and type units from the debug_types sections (if necessary) |
||
89 | /// and store them in NormalUnits. |
||
90 | void parseNormalUnits(); |
||
91 | |||
92 | /// Read compile units from the debug_info.dwo section (if necessary) |
||
93 | /// and type units from the debug_types.dwo section (if necessary) |
||
94 | /// and store them in DWOUnits. |
||
95 | /// If \p Lazy is true, set up to parse but don't actually parse them. |
||
96 | enum { EagerParse = false, LazyParse = true }; |
||
97 | void parseDWOUnits(bool Lazy = false); |
||
98 | |||
99 | std::unique_ptr<const DWARFObject> DObj; |
||
100 | |||
101 | /// Helper enum to distinguish between macro[.dwo] and macinfo[.dwo] |
||
102 | /// section. |
||
103 | enum MacroSecType { |
||
104 | MacinfoSection, |
||
105 | MacinfoDwoSection, |
||
106 | MacroSection, |
||
107 | MacroDwoSection |
||
108 | }; |
||
109 | |||
110 | // When set parses debug_info.dwo/debug_abbrev.dwo manually and populates CU |
||
111 | // Index, and TU Index for DWARF5. |
||
112 | bool ParseCUTUIndexManually = false; |
||
113 | |||
114 | public: |
||
115 | DWARFContext(std::unique_ptr<const DWARFObject> DObj, |
||
116 | std::string DWPName = "", |
||
117 | std::function<void(Error)> RecoverableErrorHandler = |
||
118 | WithColor::defaultErrorHandler, |
||
119 | std::function<void(Error)> WarningHandler = |
||
120 | WithColor::defaultWarningHandler); |
||
121 | ~DWARFContext() override; |
||
122 | |||
123 | DWARFContext(DWARFContext &) = delete; |
||
124 | DWARFContext &operator=(DWARFContext &) = delete; |
||
125 | |||
126 | const DWARFObject &getDWARFObj() const { return *DObj; } |
||
127 | |||
128 | static bool classof(const DIContext *DICtx) { |
||
129 | return DICtx->getKind() == CK_DWARF; |
||
130 | } |
||
131 | |||
132 | /// Dump a textual representation to \p OS. If any \p DumpOffsets are present, |
||
133 | /// dump only the record at the specified offset. |
||
134 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
||
135 | std::array<std::optional<uint64_t>, DIDT_ID_Count> DumpOffsets); |
||
136 | |||
137 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override { |
||
138 | std::array<std::optional<uint64_t>, DIDT_ID_Count> DumpOffsets; |
||
139 | dump(OS, DumpOpts, DumpOffsets); |
||
140 | } |
||
141 | |||
142 | bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override; |
||
143 | |||
144 | using unit_iterator_range = DWARFUnitVector::iterator_range; |
||
145 | using compile_unit_range = DWARFUnitVector::compile_unit_range; |
||
146 | |||
147 | /// Get units from .debug_info in this context. |
||
148 | unit_iterator_range info_section_units() { |
||
149 | parseNormalUnits(); |
||
150 | return unit_iterator_range(NormalUnits.begin(), |
||
151 | NormalUnits.begin() + |
||
152 | NormalUnits.getNumInfoUnits()); |
||
153 | } |
||
154 | |||
155 | const DWARFUnitVector &getNormalUnitsVector() { |
||
156 | parseNormalUnits(); |
||
157 | return NormalUnits; |
||
158 | } |
||
159 | |||
160 | /// Get units from .debug_types in this context. |
||
161 | unit_iterator_range types_section_units() { |
||
162 | parseNormalUnits(); |
||
163 | return unit_iterator_range( |
||
164 | NormalUnits.begin() + NormalUnits.getNumInfoUnits(), NormalUnits.end()); |
||
165 | } |
||
166 | |||
167 | /// Get compile units in this context. |
||
168 | compile_unit_range compile_units() { |
||
169 | return make_filter_range(info_section_units(), isCompileUnit); |
||
170 | } |
||
171 | |||
172 | // If you want type_units(), it'll need to be a concat iterator of a filter of |
||
173 | // TUs in info_section + all the (all type) units in types_section |
||
174 | |||
175 | /// Get all normal compile/type units in this context. |
||
176 | unit_iterator_range normal_units() { |
||
177 | parseNormalUnits(); |
||
178 | return unit_iterator_range(NormalUnits.begin(), NormalUnits.end()); |
||
179 | } |
||
180 | |||
181 | /// Get units from .debug_info..dwo in the DWO context. |
||
182 | unit_iterator_range dwo_info_section_units() { |
||
183 | parseDWOUnits(); |
||
184 | return unit_iterator_range(DWOUnits.begin(), |
||
185 | DWOUnits.begin() + DWOUnits.getNumInfoUnits()); |
||
186 | } |
||
187 | |||
188 | const DWARFUnitVector &getDWOUnitsVector() { |
||
189 | parseDWOUnits(); |
||
190 | return DWOUnits; |
||
191 | } |
||
192 | |||
193 | /// Get units from .debug_types.dwo in the DWO context. |
||
194 | unit_iterator_range dwo_types_section_units() { |
||
195 | parseDWOUnits(); |
||
196 | return unit_iterator_range(DWOUnits.begin() + DWOUnits.getNumInfoUnits(), |
||
197 | DWOUnits.end()); |
||
198 | } |
||
199 | |||
200 | /// Get compile units in the DWO context. |
||
201 | compile_unit_range dwo_compile_units() { |
||
202 | return make_filter_range(dwo_info_section_units(), isCompileUnit); |
||
203 | } |
||
204 | |||
205 | // If you want dwo_type_units(), it'll need to be a concat iterator of a |
||
206 | // filter of TUs in dwo_info_section + all the (all type) units in |
||
207 | // dwo_types_section. |
||
208 | |||
209 | /// Get all units in the DWO context. |
||
210 | unit_iterator_range dwo_units() { |
||
211 | parseDWOUnits(); |
||
212 | return unit_iterator_range(DWOUnits.begin(), DWOUnits.end()); |
||
213 | } |
||
214 | |||
215 | /// Get the number of compile units in this context. |
||
216 | unsigned getNumCompileUnits() { |
||
217 | parseNormalUnits(); |
||
218 | return NormalUnits.getNumInfoUnits(); |
||
219 | } |
||
220 | |||
221 | /// Get the number of type units in this context. |
||
222 | unsigned getNumTypeUnits() { |
||
223 | parseNormalUnits(); |
||
224 | return NormalUnits.getNumTypesUnits(); |
||
225 | } |
||
226 | |||
227 | /// Get the number of compile units in the DWO context. |
||
228 | unsigned getNumDWOCompileUnits() { |
||
229 | parseDWOUnits(); |
||
230 | return DWOUnits.getNumInfoUnits(); |
||
231 | } |
||
232 | |||
233 | /// Get the number of type units in the DWO context. |
||
234 | unsigned getNumDWOTypeUnits() { |
||
235 | parseDWOUnits(); |
||
236 | return DWOUnits.getNumTypesUnits(); |
||
237 | } |
||
238 | |||
239 | /// Get the unit at the specified index. |
||
240 | DWARFUnit *getUnitAtIndex(unsigned index) { |
||
241 | parseNormalUnits(); |
||
242 | return NormalUnits[index].get(); |
||
243 | } |
||
244 | |||
245 | /// Get the unit at the specified index for the DWO units. |
||
246 | DWARFUnit *getDWOUnitAtIndex(unsigned index) { |
||
247 | parseDWOUnits(); |
||
248 | return DWOUnits[index].get(); |
||
249 | } |
||
250 | |||
251 | DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash); |
||
252 | DWARFTypeUnit *getTypeUnitForHash(uint16_t Version, uint64_t Hash, bool IsDWO); |
||
253 | |||
254 | /// Return the compile unit that includes an offset (relative to .debug_info). |
||
255 | DWARFCompileUnit *getCompileUnitForOffset(uint64_t Offset); |
||
256 | |||
257 | /// Get a DIE given an exact offset. |
||
258 | DWARFDie getDIEForOffset(uint64_t Offset); |
||
259 | |||
260 | unsigned getMaxVersion() { |
||
261 | // Ensure info units have been parsed to discover MaxVersion |
||
262 | info_section_units(); |
||
263 | return MaxVersion; |
||
264 | } |
||
265 | |||
266 | unsigned getMaxDWOVersion() { |
||
267 | // Ensure DWO info units have been parsed to discover MaxVersion |
||
268 | dwo_info_section_units(); |
||
269 | return MaxVersion; |
||
270 | } |
||
271 | |||
272 | void setMaxVersionIfGreater(unsigned Version) { |
||
273 | if (Version > MaxVersion) |
||
274 | MaxVersion = Version; |
||
275 | } |
||
276 | |||
277 | const DWARFUnitIndex &getCUIndex(); |
||
278 | DWARFGdbIndex &getGdbIndex(); |
||
279 | const DWARFUnitIndex &getTUIndex(); |
||
280 | |||
281 | /// Get a pointer to the parsed DebugAbbrev object. |
||
282 | const DWARFDebugAbbrev *getDebugAbbrev(); |
||
283 | |||
284 | /// Get a pointer to the parsed DebugLoc object. |
||
285 | const DWARFDebugLoc *getDebugLoc(); |
||
286 | |||
287 | /// Get a pointer to the parsed dwo abbreviations object. |
||
288 | const DWARFDebugAbbrev *getDebugAbbrevDWO(); |
||
289 | |||
290 | /// Get a pointer to the parsed DebugAranges object. |
||
291 | const DWARFDebugAranges *getDebugAranges(); |
||
292 | |||
293 | /// Get a pointer to the parsed frame information object. |
||
294 | Expected<const DWARFDebugFrame *> getDebugFrame(); |
||
295 | |||
296 | /// Get a pointer to the parsed eh frame information object. |
||
297 | Expected<const DWARFDebugFrame *> getEHFrame(); |
||
298 | |||
299 | /// Get a pointer to the parsed DebugMacinfo information object. |
||
300 | const DWARFDebugMacro *getDebugMacinfo(); |
||
301 | |||
302 | /// Get a pointer to the parsed DebugMacinfoDWO information object. |
||
303 | const DWARFDebugMacro *getDebugMacinfoDWO(); |
||
304 | |||
305 | /// Get a pointer to the parsed DebugMacro information object. |
||
306 | const DWARFDebugMacro *getDebugMacro(); |
||
307 | |||
308 | /// Get a pointer to the parsed DebugMacroDWO information object. |
||
309 | const DWARFDebugMacro *getDebugMacroDWO(); |
||
310 | |||
311 | /// Get a reference to the parsed accelerator table object. |
||
312 | const DWARFDebugNames &getDebugNames(); |
||
313 | |||
314 | /// Get a reference to the parsed accelerator table object. |
||
315 | const AppleAcceleratorTable &getAppleNames(); |
||
316 | |||
317 | /// Get a reference to the parsed accelerator table object. |
||
318 | const AppleAcceleratorTable &getAppleTypes(); |
||
319 | |||
320 | /// Get a reference to the parsed accelerator table object. |
||
321 | const AppleAcceleratorTable &getAppleNamespaces(); |
||
322 | |||
323 | /// Get a reference to the parsed accelerator table object. |
||
324 | const AppleAcceleratorTable &getAppleObjC(); |
||
325 | |||
326 | /// Get a pointer to a parsed line table corresponding to a compile unit. |
||
327 | /// Report any parsing issues as warnings on stderr. |
||
328 | const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *U); |
||
329 | |||
330 | /// Get a pointer to a parsed line table corresponding to a compile unit. |
||
331 | /// Report any recoverable parsing problems using the handler. |
||
332 | Expected<const DWARFDebugLine::LineTable *> |
||
333 | getLineTableForUnit(DWARFUnit *U, |
||
334 | function_ref<void(Error)> RecoverableErrorHandler); |
||
335 | |||
336 | // Clear the line table object corresponding to a compile unit for memory |
||
337 | // management purpose. When it's referred to again, it'll be re-populated. |
||
338 | void clearLineTableForUnit(DWARFUnit *U); |
||
339 | |||
340 | DataExtractor getStringExtractor() const { |
||
341 | return DataExtractor(DObj->getStrSection(), false, 0); |
||
342 | } |
||
343 | DataExtractor getStringDWOExtractor() const { |
||
344 | return DataExtractor(DObj->getStrDWOSection(), false, 0); |
||
345 | } |
||
346 | DataExtractor getLineStringExtractor() const { |
||
347 | return DataExtractor(DObj->getLineStrSection(), false, 0); |
||
348 | } |
||
349 | |||
350 | /// Wraps the returned DIEs for a given address. |
||
351 | struct DIEsForAddress { |
||
352 | DWARFCompileUnit *CompileUnit = nullptr; |
||
353 | DWARFDie FunctionDIE; |
||
354 | DWARFDie BlockDIE; |
||
355 | explicit operator bool() const { return CompileUnit != nullptr; } |
||
356 | }; |
||
357 | |||
358 | /// Get the compilation unit, the function DIE and lexical block DIE for the |
||
359 | /// given address where applicable. |
||
360 | /// TODO: change input parameter from "uint64_t Address" |
||
361 | /// into "SectionedAddress Address" |
||
362 | DIEsForAddress getDIEsForAddress(uint64_t Address); |
||
363 | |||
364 | DILineInfo getLineInfoForAddress( |
||
365 | object::SectionedAddress Address, |
||
366 | DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; |
||
367 | DILineInfo |
||
368 | getLineInfoForDataAddress(object::SectionedAddress Address) override; |
||
369 | DILineInfoTable getLineInfoForAddressRange( |
||
370 | object::SectionedAddress Address, uint64_t Size, |
||
371 | DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; |
||
372 | DIInliningInfo getInliningInfoForAddress( |
||
373 | object::SectionedAddress Address, |
||
374 | DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; |
||
375 | |||
376 | std::vector<DILocal> |
||
377 | getLocalsForAddress(object::SectionedAddress Address) override; |
||
378 | |||
379 | bool isLittleEndian() const { return DObj->isLittleEndian(); } |
||
380 | static unsigned getMaxSupportedVersion() { return 5; } |
||
381 | static bool isSupportedVersion(unsigned version) { |
||
382 | return version >= 2 && version <= getMaxSupportedVersion(); |
||
383 | } |
||
384 | |||
385 | static SmallVector<uint8_t, 3> getSupportedAddressSizes() { |
||
386 | return {2, 4, 8}; |
||
387 | } |
||
388 | static bool isAddressSizeSupported(unsigned AddressSize) { |
||
389 | return llvm::is_contained(getSupportedAddressSizes(), AddressSize); |
||
390 | } |
||
391 | template <typename... Ts> |
||
392 | static Error checkAddressSizeSupported(unsigned AddressSize, |
||
393 | std::error_code EC, char const *Fmt, |
||
394 | const Ts &...Vals) { |
||
395 | if (isAddressSizeSupported(AddressSize)) |
||
396 | return Error::success(); |
||
397 | std::string Buffer; |
||
398 | raw_string_ostream Stream(Buffer); |
||
399 | Stream << format(Fmt, Vals...) |
||
400 | << " has unsupported address size: " << AddressSize |
||
401 | << " (supported are "; |
||
402 | ListSeparator LS; |
||
403 | for (unsigned Size : DWARFContext::getSupportedAddressSizes()) |
||
404 | Stream << LS << Size; |
||
405 | Stream << ')'; |
||
406 | return make_error<StringError>(Stream.str(), EC); |
||
407 | } |
||
408 | |||
409 | std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath); |
||
410 | |||
411 | function_ref<void(Error)> getRecoverableErrorHandler() { |
||
412 | return RecoverableErrorHandler; |
||
413 | } |
||
414 | |||
415 | function_ref<void(Error)> getWarningHandler() { return WarningHandler; } |
||
416 | |||
417 | enum class ProcessDebugRelocations { Process, Ignore }; |
||
418 | |||
419 | static std::unique_ptr<DWARFContext> |
||
420 | create(const object::ObjectFile &Obj, |
||
421 | ProcessDebugRelocations RelocAction = ProcessDebugRelocations::Process, |
||
422 | const LoadedObjectInfo *L = nullptr, std::string DWPName = "", |
||
423 | std::function<void(Error)> RecoverableErrorHandler = |
||
424 | WithColor::defaultErrorHandler, |
||
425 | std::function<void(Error)> WarningHandler = |
||
426 | WithColor::defaultWarningHandler); |
||
427 | |||
428 | static std::unique_ptr<DWARFContext> |
||
429 | create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, |
||
430 | uint8_t AddrSize, bool isLittleEndian = sys::IsLittleEndianHost, |
||
431 | std::function<void(Error)> RecoverableErrorHandler = |
||
432 | WithColor::defaultErrorHandler, |
||
433 | std::function<void(Error)> WarningHandler = |
||
434 | WithColor::defaultWarningHandler); |
||
435 | |||
436 | /// Get address size from CUs. |
||
437 | /// TODO: refactor compile_units() to make this const. |
||
438 | uint8_t getCUAddrSize(); |
||
439 | |||
440 | Triple::ArchType getArch() const { |
||
441 | return getDWARFObj().getFile()->getArch(); |
||
442 | } |
||
443 | |||
444 | /// Return the compile unit which contains instruction with provided |
||
445 | /// address. |
||
446 | /// TODO: change input parameter from "uint64_t Address" |
||
447 | /// into "SectionedAddress Address" |
||
448 | DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); |
||
449 | |||
450 | /// Returns whether CU/TU should be populated manually. TU Index populated |
||
451 | /// manually only for DWARF5. |
||
452 | bool getParseCUTUIndexManually() const { return ParseCUTUIndexManually; } |
||
453 | |||
454 | /// Sets whether CU/TU should be populated manually. TU Index populated |
||
455 | /// manually only for DWARF5. |
||
456 | void setParseCUTUIndexManually(bool PCUTU) { ParseCUTUIndexManually = PCUTU; } |
||
457 | |||
458 | private: |
||
459 | /// Parse a macro[.dwo] or macinfo[.dwo] section. |
||
460 | std::unique_ptr<DWARFDebugMacro> |
||
461 | parseMacroOrMacinfo(MacroSecType SectionType); |
||
462 | |||
463 | void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die, |
||
464 | std::vector<DILocal> &Result); |
||
465 | }; |
||
466 | |||
467 | } // end namespace llvm |
||
468 | |||
469 | #endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H |