/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Symbol/Symtab.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- Symtab.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_SYMBOL_SYMTAB_H |
10 | | #define LLDB_SYMBOL_SYMTAB_H |
11 | | |
12 | | #include "lldb/Core/UniqueCStringMap.h" |
13 | | #include "lldb/Symbol/Symbol.h" |
14 | | #include "lldb/Utility/RangeMap.h" |
15 | | #include "lldb/lldb-private.h" |
16 | | #include <map> |
17 | | #include <mutex> |
18 | | #include <vector> |
19 | | |
20 | | namespace lldb_private { |
21 | | |
22 | | class Symtab { |
23 | | public: |
24 | | typedef std::vector<uint32_t> IndexCollection; |
25 | | typedef UniqueCStringMap<uint32_t> NameToIndexMap; |
26 | | |
27 | | enum Debug { |
28 | | eDebugNo, // Not a debug symbol |
29 | | eDebugYes, // A debug symbol |
30 | | eDebugAny |
31 | | }; |
32 | | |
33 | | enum Visibility { eVisibilityAny, eVisibilityExtern, eVisibilityPrivate }; |
34 | | |
35 | | Symtab(ObjectFile *objfile); |
36 | | ~Symtab(); |
37 | | |
38 | | void PreloadSymbols(); |
39 | | void Reserve(size_t count); |
40 | | Symbol *Resize(size_t count); |
41 | | uint32_t AddSymbol(const Symbol &symbol); |
42 | | size_t GetNumSymbols() const; |
43 | | void SectionFileAddressesChanged(); |
44 | | void |
45 | | Dump(Stream *s, Target *target, SortOrder sort_type, |
46 | | Mangled::NamePreference name_preference = Mangled::ePreferDemangled); |
47 | | void Dump(Stream *s, Target *target, std::vector<uint32_t> &indexes, |
48 | | Mangled::NamePreference name_preference = |
49 | | Mangled::ePreferDemangled) const; |
50 | | uint32_t GetIndexForSymbol(const Symbol *symbol) const; |
51 | 115k | std::recursive_mutex &GetMutex() { return m_mutex; } |
52 | | Symbol *FindSymbolByID(lldb::user_id_t uid) const; |
53 | | Symbol *SymbolAtIndex(size_t idx); |
54 | | const Symbol *SymbolAtIndex(size_t idx) const; |
55 | | Symbol *FindSymbolWithType(lldb::SymbolType symbol_type, |
56 | | Debug symbol_debug_type, |
57 | | Visibility symbol_visibility, uint32_t &start_idx); |
58 | | /// Get the parent symbol for the given symbol. |
59 | | /// |
60 | | /// Many symbols in symbol tables are scoped by other symbols that |
61 | | /// contain one or more symbol. This function will look for such a |
62 | | /// containing symbol and return it if there is one. |
63 | | const Symbol *GetParent(Symbol *symbol) const; |
64 | | uint32_t AppendSymbolIndexesWithType(lldb::SymbolType symbol_type, |
65 | | std::vector<uint32_t> &indexes, |
66 | | uint32_t start_idx = 0, |
67 | | uint32_t end_index = UINT32_MAX) const; |
68 | | uint32_t AppendSymbolIndexesWithTypeAndFlagsValue( |
69 | | lldb::SymbolType symbol_type, uint32_t flags_value, |
70 | | std::vector<uint32_t> &indexes, uint32_t start_idx = 0, |
71 | | uint32_t end_index = UINT32_MAX) const; |
72 | | uint32_t AppendSymbolIndexesWithType(lldb::SymbolType symbol_type, |
73 | | Debug symbol_debug_type, |
74 | | Visibility symbol_visibility, |
75 | | std::vector<uint32_t> &matches, |
76 | | uint32_t start_idx = 0, |
77 | | uint32_t end_index = UINT32_MAX) const; |
78 | | uint32_t AppendSymbolIndexesWithName(ConstString symbol_name, |
79 | | std::vector<uint32_t> &matches); |
80 | | uint32_t AppendSymbolIndexesWithName(ConstString symbol_name, |
81 | | Debug symbol_debug_type, |
82 | | Visibility symbol_visibility, |
83 | | std::vector<uint32_t> &matches); |
84 | | uint32_t AppendSymbolIndexesWithNameAndType(ConstString symbol_name, |
85 | | lldb::SymbolType symbol_type, |
86 | | std::vector<uint32_t> &matches); |
87 | | uint32_t AppendSymbolIndexesWithNameAndType(ConstString symbol_name, |
88 | | lldb::SymbolType symbol_type, |
89 | | Debug symbol_debug_type, |
90 | | Visibility symbol_visibility, |
91 | | std::vector<uint32_t> &matches); |
92 | | uint32_t AppendSymbolIndexesMatchingRegExAndType( |
93 | | const RegularExpression ®ex, lldb::SymbolType symbol_type, |
94 | | std::vector<uint32_t> &indexes, |
95 | | Mangled::NamePreference name_preference = Mangled::ePreferDemangled); |
96 | | uint32_t AppendSymbolIndexesMatchingRegExAndType( |
97 | | const RegularExpression ®ex, lldb::SymbolType symbol_type, |
98 | | Debug symbol_debug_type, Visibility symbol_visibility, |
99 | | std::vector<uint32_t> &indexes, |
100 | | Mangled::NamePreference name_preference = |
101 | | Mangled::NamePreference::ePreferDemangled); |
102 | | void FindAllSymbolsWithNameAndType(ConstString name, |
103 | | lldb::SymbolType symbol_type, |
104 | | std::vector<uint32_t> &symbol_indexes); |
105 | | void FindAllSymbolsWithNameAndType(ConstString name, |
106 | | lldb::SymbolType symbol_type, |
107 | | Debug symbol_debug_type, |
108 | | Visibility symbol_visibility, |
109 | | std::vector<uint32_t> &symbol_indexes); |
110 | | void FindAllSymbolsMatchingRexExAndType( |
111 | | const RegularExpression ®ex, lldb::SymbolType symbol_type, |
112 | | Debug symbol_debug_type, Visibility symbol_visibility, |
113 | | std::vector<uint32_t> &symbol_indexes, |
114 | | Mangled::NamePreference name_preference = Mangled::ePreferDemangled); |
115 | | Symbol *FindFirstSymbolWithNameAndType(ConstString name, |
116 | | lldb::SymbolType symbol_type, |
117 | | Debug symbol_debug_type, |
118 | | Visibility symbol_visibility); |
119 | | Symbol *FindSymbolAtFileAddress(lldb::addr_t file_addr); |
120 | | Symbol *FindSymbolContainingFileAddress(lldb::addr_t file_addr); |
121 | | void ForEachSymbolContainingFileAddress( |
122 | | lldb::addr_t file_addr, std::function<bool(Symbol *)> const &callback); |
123 | | void FindFunctionSymbols(ConstString name, uint32_t name_type_mask, |
124 | | SymbolContextList &sc_list); |
125 | | |
126 | | void SortSymbolIndexesByValue(std::vector<uint32_t> &indexes, |
127 | | bool remove_duplicates) const; |
128 | | |
129 | | static void DumpSymbolHeader(Stream *s); |
130 | | |
131 | | void Finalize(); |
132 | | |
133 | | void AppendSymbolNamesToMap(const IndexCollection &indexes, |
134 | | bool add_demangled, bool add_mangled, |
135 | | NameToIndexMap &name_to_index_map) const; |
136 | | |
137 | 135 | ObjectFile *GetObjectFile() const { return m_objfile; } |
138 | | |
139 | | /// Decode a serialized version of this object from data. |
140 | | /// |
141 | | /// \param data |
142 | | /// The decoder object that references the serialized data. |
143 | | /// |
144 | | /// \param offset_ptr |
145 | | /// A pointer that contains the offset from which the data will be decoded |
146 | | /// from that gets updated as data gets decoded. |
147 | | /// |
148 | | /// \param[out] uuid_mismatch |
149 | | /// Set to true if a cache file exists but the UUID didn't match, false |
150 | | /// otherwise. |
151 | | /// |
152 | | /// \return |
153 | | /// True if the symbol table is successfully decoded and can be used, |
154 | | /// false otherwise. |
155 | | bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr, |
156 | | bool &uuid_mismatch); |
157 | | |
158 | | /// Encode this object into a data encoder object. |
159 | | /// |
160 | | /// This allows this object to be serialized to disk. The object file must |
161 | | /// have a valid Signature in order to be serialized as it is used to make |
162 | | /// sure the cached information matches when cached data is loaded at a later |
163 | | /// time. If the object file doesn't have a valid signature false will be |
164 | | /// returned and it will indicate we should not cache this data. |
165 | | /// |
166 | | /// \param encoder |
167 | | /// A data encoder object that serialized bytes will be encoded into. |
168 | | /// |
169 | | /// \return |
170 | | /// True if the symbol table's object file can generate a valid signature |
171 | | /// and all data for the symbol table was encoded, false otherwise. |
172 | | bool Encode(DataEncoder &encoder) const; |
173 | | |
174 | | /// Get the cache key string for this symbol table. |
175 | | /// |
176 | | /// The cache key must start with the module's cache key and is followed |
177 | | /// by information that indicates this key is for caching the symbol table |
178 | | /// contents and should also include the has of the object file. A module can |
179 | | /// be represented by an ObjectFile object for the main executable, but can |
180 | | /// also have a symbol file that is from the same or a different object file. |
181 | | /// This means we might have two symbol tables cached in the index cache, one |
182 | | /// for the main executable and one for the symbol file. |
183 | | /// |
184 | | /// \return |
185 | | /// The unique cache key used to save and retrieve data from the index cache. |
186 | | std::string GetCacheKey(); |
187 | | |
188 | | /// Save the symbol table data out into a cache. |
189 | | /// |
190 | | /// The symbol table will only be saved to a cache file if caching is enabled. |
191 | | /// |
192 | | /// We cache the contents of the symbol table since symbol tables in LLDB take |
193 | | /// some time to initialize. This is due to the many sources for data that are |
194 | | /// used to create a symbol table: |
195 | | /// - standard symbol table |
196 | | /// - dynamic symbol table (ELF) |
197 | | /// - compressed debug info sections |
198 | | /// - unwind information |
199 | | /// - function pointers found in runtimes for global constructor/destructors |
200 | | /// - other sources. |
201 | | /// All of the above sources are combined and one symbol table results after |
202 | | /// all sources have been considered. |
203 | | void SaveToCache(); |
204 | | |
205 | | /// Load the symbol table from the index cache. |
206 | | /// |
207 | | /// Quickly load the finalized symbol table from the index cache. This saves |
208 | | /// time when the debugger starts up. The index cache file for the symbol |
209 | | /// table has the modification time set to the same time as the main module. |
210 | | /// If the cache file exists and the modification times match, we will load |
211 | | /// the symbol table from the serlized cache file. |
212 | | /// |
213 | | /// \return |
214 | | /// True if the symbol table was successfully loaded from the index cache, |
215 | | /// false if the symbol table wasn't cached or was out of date. |
216 | | bool LoadFromCache(); |
217 | | |
218 | | |
219 | | /// Accessors for the bool that indicates if the debug info index was loaded |
220 | | /// from, or saved to the module index cache. |
221 | | /// |
222 | | /// In statistics it is handy to know if a module's debug info was loaded from |
223 | | /// or saved to the cache. When the debug info index is loaded from the cache |
224 | | /// startup times can be faster. When the cache is enabled and the debug info |
225 | | /// index is saved to the cache, debug sessions can be slower. These accessors |
226 | | /// can be accessed by the statistics and emitted to help track these costs. |
227 | | /// \{ |
228 | 735 | bool GetWasLoadedFromCache() const { |
229 | 735 | return m_loaded_from_cache; |
230 | 735 | } |
231 | 0 | void SetWasLoadedFromCache() { |
232 | 0 | m_loaded_from_cache = true; |
233 | 0 | } |
234 | 735 | bool GetWasSavedToCache() const { |
235 | 735 | return m_saved_to_cache; |
236 | 735 | } |
237 | 6 | void SetWasSavedToCache() { |
238 | 6 | m_saved_to_cache = true; |
239 | 6 | } |
240 | | /// \} |
241 | | |
242 | | protected: |
243 | | typedef std::vector<Symbol> collection; |
244 | | typedef collection::iterator iterator; |
245 | | typedef collection::const_iterator const_iterator; |
246 | | class FileRangeToIndexMapCompare { |
247 | | public: |
248 | 115k | FileRangeToIndexMapCompare(const Symtab &symtab) : m_symtab(symtab) {} |
249 | 5.67M | bool operator()(const uint32_t a_data, const uint32_t b_data) const { |
250 | 5.67M | return rank(a_data) > rank(b_data); |
251 | 5.67M | } |
252 | | |
253 | | private: |
254 | | // How much preferred is this symbol? |
255 | 11.3M | int rank(const uint32_t data) const { |
256 | 11.3M | const Symbol &symbol = *m_symtab.SymbolAtIndex(data); |
257 | 11.3M | if (symbol.IsExternal()) |
258 | 10.1M | return 3; |
259 | 1.17M | if (symbol.IsWeak()) |
260 | 148 | return 2; |
261 | 1.17M | if (symbol.IsDebug()) |
262 | 3.16k | return 0; |
263 | 1.16M | return 1; |
264 | 1.17M | } |
265 | | const Symtab &m_symtab; |
266 | | }; |
267 | | typedef RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t, 0, |
268 | | FileRangeToIndexMapCompare> |
269 | | FileRangeToIndexMap; |
270 | | void InitNameIndexes(); |
271 | | void InitAddressIndexes(); |
272 | | |
273 | | ObjectFile *m_objfile; |
274 | | collection m_symbols; |
275 | | FileRangeToIndexMap m_file_addr_to_index; |
276 | | |
277 | | /// Maps function names to symbol indices (grouped by FunctionNameTypes) |
278 | | std::map<lldb::FunctionNameType, UniqueCStringMap<uint32_t>> |
279 | | m_name_to_symbol_indices; |
280 | | mutable std::recursive_mutex |
281 | | m_mutex; // Provide thread safety for this symbol table |
282 | | bool m_file_addr_to_index_computed : 1, m_name_indexes_computed : 1, |
283 | | m_loaded_from_cache : 1, m_saved_to_cache : 1; |
284 | | |
285 | | private: |
286 | | UniqueCStringMap<uint32_t> & |
287 | 43.1M | GetNameToSymbolIndexMap(lldb::FunctionNameType type) { |
288 | 43.1M | auto map = m_name_to_symbol_indices.find(type); |
289 | 43.1M | assert(map != m_name_to_symbol_indices.end()); |
290 | 43.1M | return map->second; |
291 | 43.1M | } |
292 | | bool CheckSymbolAtIndex(size_t idx, Debug symbol_debug_type, |
293 | 168M | Visibility symbol_visibility) const { |
294 | 168M | switch (symbol_debug_type) { |
295 | 82.4M | case eDebugNo: |
296 | 82.4M | if (m_symbols[idx].IsDebug()) |
297 | 0 | return false; |
298 | 82.4M | break; |
299 | | |
300 | 85.3M | case eDebugYes: |
301 | 85.3M | if (!m_symbols[idx].IsDebug()) |
302 | 85.2M | return false; |
303 | 38.9k | break; |
304 | | |
305 | 259k | case eDebugAny: |
306 | 259k | break; |
307 | 168M | } |
308 | | |
309 | 82.7M | switch (symbol_visibility) { |
310 | 82.7M | case eVisibilityAny: |
311 | 82.7M | return true; |
312 | | |
313 | 1 | case eVisibilityExtern: |
314 | 1 | return m_symbols[idx].IsExternal(); |
315 | | |
316 | 0 | case eVisibilityPrivate: |
317 | 0 | return !m_symbols[idx].IsExternal(); |
318 | 82.7M | } |
319 | 0 | return false; |
320 | 82.7M | } |
321 | | |
322 | | /// A helper function that looks up full function names. |
323 | | /// |
324 | | /// We generate unique names for synthetic symbols so that users can look |
325 | | /// them up by name when needed. But because doing so is uncommon in normal |
326 | | /// debugger use, we trade off some performance at lookup time for faster |
327 | | /// symbol table building by detecting these symbols and generating their |
328 | | /// names lazily, rather than adding them to the normal symbol indexes. This |
329 | | /// function does the job of first consulting the name indexes, and if that |
330 | | /// fails it extracts the information it needs from the synthetic name and |
331 | | /// locates the symbol. |
332 | | /// |
333 | | /// @param[in] symbol_name The symbol name to search for. |
334 | | /// |
335 | | /// @param[out] indexes The vector if symbol indexes to update with results. |
336 | | /// |
337 | | /// @returns The number of indexes added to the index vector. Zero if no |
338 | | /// matches were found. |
339 | | uint32_t GetNameIndexes(ConstString symbol_name, |
340 | | std::vector<uint32_t> &indexes); |
341 | | |
342 | | void SymbolIndicesToSymbolContextList(std::vector<uint32_t> &symbol_indexes, |
343 | | SymbolContextList &sc_list); |
344 | | |
345 | | void RegisterMangledNameEntry( |
346 | | uint32_t value, std::set<const char *> &class_contexts, |
347 | | std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog, |
348 | | RichManglingContext &rmc); |
349 | | |
350 | | void RegisterBacklogEntry(const NameToIndexMap::Entry &entry, |
351 | | const char *decl_context, |
352 | | const std::set<const char *> &class_contexts); |
353 | | |
354 | | Symtab(const Symtab &) = delete; |
355 | | const Symtab &operator=(const Symtab &) = delete; |
356 | | }; |
357 | | |
358 | | } // namespace lldb_private |
359 | | |
360 | | #endif // LLDB_SYMBOL_SYMTAB_H |