1 | //===-- ManualDWARFIndex.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 LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H |
10 | #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H |
11 | |
12 | #include "Plugins/SymbolFile/DWARF/DWARFIndex.h" |
13 | #include "Plugins/SymbolFile/DWARF/NameToDIE.h" |
14 | #include "llvm/ADT/DenseSet.h" |
15 | |
16 | namespace lldb_private::plugin { |
17 | namespace dwarf { |
18 | class DWARFDebugInfo; |
19 | class SymbolFileDWARFDwo; |
20 | |
21 | class ManualDWARFIndex : public DWARFIndex { |
22 | public: |
23 | ManualDWARFIndex(Module &module, SymbolFileDWARF &dwarf, |
24 | llvm::DenseSet<dw_offset_t> units_to_avoid = {}) |
25 | : DWARFIndex(module), m_dwarf(&dwarf), |
26 | m_units_to_avoid(std::move(units_to_avoid)) {} |
27 | |
28 | void Preload() override { Index(); } |
29 | |
30 | void |
31 | GetGlobalVariables(ConstString basename, |
32 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
33 | void |
34 | GetGlobalVariables(const RegularExpression ®ex, |
35 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
36 | void |
37 | GetGlobalVariables(DWARFUnit &unit, |
38 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
39 | void GetObjCMethods(ConstString class_name, |
40 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
41 | void GetCompleteObjCClass( |
42 | ConstString class_name, bool must_be_implementation, |
43 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
44 | void GetTypes(ConstString name, |
45 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
46 | void GetTypes(const DWARFDeclContext &context, |
47 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
48 | void GetNamespaces(ConstString name, |
49 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
50 | void GetFunctions(const Module::LookupInfo &lookup_info, |
51 | SymbolFileDWARF &dwarf, |
52 | const CompilerDeclContext &parent_decl_ctx, |
53 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
54 | void GetFunctions(const RegularExpression ®ex, |
55 | llvm::function_ref<bool(DWARFDIE die)> callback) override; |
56 | |
57 | void Dump(Stream &s) override; |
58 | |
59 | // Make IndexSet public so we can unit test the encoding and decoding logic. |
60 | struct IndexSet { |
61 | NameToDIE function_basenames; |
62 | NameToDIE function_fullnames; |
63 | NameToDIE function_methods; |
64 | NameToDIE function_selectors; |
65 | NameToDIE objc_class_selectors; |
66 | NameToDIE globals; |
67 | NameToDIE types; |
68 | NameToDIE namespaces; |
69 | bool (const DataExtractor &data, lldb::offset_t *offset_ptr); |
70 | void Encode(DataEncoder &encoder) const; |
71 | bool operator==(const IndexSet &rhs) const { |
72 | return function_basenames == rhs.function_basenames && |
73 | function_fullnames == rhs.function_fullnames && |
74 | function_methods == rhs.function_methods && |
75 | function_selectors == rhs.function_selectors && |
76 | objc_class_selectors == rhs.objc_class_selectors && |
77 | globals == rhs.globals && types == rhs.types && |
78 | namespaces == rhs.namespaces; |
79 | } |
80 | }; |
81 | |
82 | private: |
83 | void Index(); |
84 | |
85 | /// Decode a serialized version of this object from data. |
86 | /// |
87 | /// \param data |
88 | /// The decoder object that references the serialized data. |
89 | /// |
90 | /// \param offset_ptr |
91 | /// A pointer that contains the offset from which the data will be decoded |
92 | /// from that gets updated as data gets decoded. |
93 | /// |
94 | /// \param strtab |
95 | /// All strings in cache files are put into string tables for efficiency |
96 | /// and cache file size reduction. Strings are stored as uint32_t string |
97 | /// table offsets in the cache data. |
98 | bool (const DataExtractor &data, lldb::offset_t *offset_ptr, |
99 | bool &signature_mismatch); |
100 | |
101 | /// Encode this object into a data encoder object. |
102 | /// |
103 | /// This allows this object to be serialized to disk. |
104 | /// |
105 | /// \param encoder |
106 | /// A data encoder object that serialized bytes will be encoded into. |
107 | /// |
108 | /// \param strtab |
109 | /// All strings in cache files are put into string tables for efficiency |
110 | /// and cache file size reduction. Strings are stored as uint32_t string |
111 | /// table offsets in the cache data. |
112 | /// |
113 | /// \return |
114 | /// True if the symbol table's object file can generate a valid signature |
115 | /// and all data for the symbol table was encoded, false otherwise. |
116 | bool Encode(DataEncoder &encoder) const; |
117 | |
118 | /// Get the cache key string for this symbol table. |
119 | /// |
120 | /// The cache key must start with the module's cache key and is followed |
121 | /// by information that indicates this key is for caching the symbol table |
122 | /// contents and should also include the has of the object file. A module can |
123 | /// be represented by an ObjectFile object for the main executable, but can |
124 | /// also have a symbol file that is from the same or a different object file. |
125 | /// This means we might have two symbol tables cached in the index cache, one |
126 | /// for the main executable and one for the symbol file. |
127 | /// |
128 | /// \return |
129 | /// The unique cache key used to save and retrieve data from the index |
130 | /// cache. |
131 | std::string GetCacheKey(); |
132 | |
133 | /// Save the symbol table data out into a cache. |
134 | /// |
135 | /// The symbol table will only be saved to a cache file if caching is enabled. |
136 | /// |
137 | /// We cache the contents of the symbol table since symbol tables in LLDB take |
138 | /// some time to initialize. This is due to the many sources for data that are |
139 | /// used to create a symbol table: |
140 | /// - standard symbol table |
141 | /// - dynamic symbol table (ELF) |
142 | /// - compressed debug info sections |
143 | /// - unwind information |
144 | /// - function pointers found in runtimes for global constructor/destructors |
145 | /// - other sources. |
146 | /// All of the above sources are combined and one symbol table results after |
147 | /// all sources have been considered. |
148 | void SaveToCache(); |
149 | |
150 | /// Load the symbol table from the index cache. |
151 | /// |
152 | /// Quickly load the finalized symbol table from the index cache. This saves |
153 | /// time when the debugger starts up. The index cache file for the symbol |
154 | /// table has the modification time set to the same time as the main module. |
155 | /// If the cache file exists and the modification times match, we will load |
156 | /// the symbol table from the serlized cache file. |
157 | /// |
158 | /// \return |
159 | /// True if the symbol table was successfully loaded from the index cache, |
160 | /// false if the symbol table wasn't cached or was out of date. |
161 | bool LoadFromCache(); |
162 | |
163 | void IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp, IndexSet &set); |
164 | |
165 | static void IndexUnitImpl(DWARFUnit &unit, |
166 | const lldb::LanguageType cu_language, |
167 | IndexSet &set); |
168 | |
169 | /// The DWARF file which we are indexing. |
170 | SymbolFileDWARF *m_dwarf; |
171 | /// Which dwarf units should we skip while building the index. |
172 | llvm::DenseSet<dw_offset_t> m_units_to_avoid; |
173 | |
174 | IndexSet m_set; |
175 | bool m_indexed = false; |
176 | }; |
177 | } // namespace dwarf |
178 | } // namespace lldb_private::plugin |
179 | |
180 | #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_MANUALDWARFINDEX_H |
181 | |