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
20namespace lldb_private {
21
22class Symtab {
23public:
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 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 &regex, lldb::SymbolType symbol_type,
94 std::vector<uint32_t> &indexes,
95 Mangled::NamePreference name_preference = Mangled::ePreferDemangled);
96 uint32_t AppendSymbolIndexesMatchingRegExAndType(
97 const RegularExpression &regex, 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 &regex, 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 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 bool GetWasLoadedFromCache() const {
229 return m_loaded_from_cache;
230 }
231 void SetWasLoadedFromCache() {
232 m_loaded_from_cache = true;
233 }
234 bool GetWasSavedToCache() const {
235 return m_saved_to_cache;
236 }
237 void SetWasSavedToCache() {
238 m_saved_to_cache = true;
239 }
240 /// \}
241
242protected:
243 typedef std::vector<Symbol> collection;
244 typedef collection::iterator iterator;
245 typedef collection::const_iterator const_iterator;
246 class FileRangeToIndexMapCompare {
247 public:
248 FileRangeToIndexMapCompare(const Symtab &symtab) : m_symtab(symtab) {}
249 bool operator()(const uint32_t a_data, const uint32_t b_data) const {
250 return rank(data: a_data) > rank(data: b_data);
251 }
252
253 private:
254 // How much preferred is this symbol?
255 int rank(const uint32_t data) const {
256 const Symbol &symbol = *m_symtab.SymbolAtIndex(idx: data);
257 if (symbol.IsExternal())
258 return 3;
259 if (symbol.IsWeak())
260 return 2;
261 if (symbol.IsDebug())
262 return 0;
263 return 1;
264 }
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
285private:
286 UniqueCStringMap<uint32_t> &
287 GetNameToSymbolIndexMap(lldb::FunctionNameType type) {
288 auto map = m_name_to_symbol_indices.find(x: type);
289 assert(map != m_name_to_symbol_indices.end());
290 return map->second;
291 }
292 bool CheckSymbolAtIndex(size_t idx, Debug symbol_debug_type,
293 Visibility symbol_visibility) const {
294 switch (symbol_debug_type) {
295 case eDebugNo:
296 if (m_symbols[idx].IsDebug())
297 return false;
298 break;
299
300 case eDebugYes:
301 if (!m_symbols[idx].IsDebug())
302 return false;
303 break;
304
305 case eDebugAny:
306 break;
307 }
308
309 switch (symbol_visibility) {
310 case eVisibilityAny:
311 return true;
312
313 case eVisibilityExtern:
314 return m_symbols[idx].IsExternal();
315
316 case eVisibilityPrivate:
317 return !m_symbols[idx].IsExternal();
318 }
319 return false;
320 }
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
361

source code of lldb/include/lldb/Symbol/Symtab.h