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   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
93   AppendSymbolIndexesMatchingRegExAndType(const RegularExpression &regex,
94                                           lldb::SymbolType symbol_type,
95                                           std::vector<uint32_t> &indexes);
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   void FindAllSymbolsWithNameAndType(ConstString name,
101                                      lldb::SymbolType symbol_type,
102                                      std::vector<uint32_t> &symbol_indexes);
103   void FindAllSymbolsWithNameAndType(ConstString name,
104                                      lldb::SymbolType symbol_type,
105                                      Debug symbol_debug_type,
106                                      Visibility symbol_visibility,
107                                      std::vector<uint32_t> &symbol_indexes);
108   void FindAllSymbolsMatchingRexExAndType(
109       const RegularExpression &regex, lldb::SymbolType symbol_type,
110       Debug symbol_debug_type, Visibility symbol_visibility,
111       std::vector<uint32_t> &symbol_indexes);
112   Symbol *FindFirstSymbolWithNameAndType(ConstString name,
113                                          lldb::SymbolType symbol_type,
114                                          Debug symbol_debug_type,
115                                          Visibility symbol_visibility);
116   Symbol *FindSymbolAtFileAddress(lldb::addr_t file_addr);
117   Symbol *FindSymbolContainingFileAddress(lldb::addr_t file_addr);
118   void ForEachSymbolContainingFileAddress(
119       lldb::addr_t file_addr, std::function<bool(Symbol *)> const &callback);
120   void FindFunctionSymbols(ConstString name, uint32_t name_type_mask,
121                            SymbolContextList &sc_list);
122 
123   void SortSymbolIndexesByValue(std::vector<uint32_t> &indexes,
124                                 bool remove_duplicates) const;
125 
126   static void DumpSymbolHeader(Stream *s);
127 
128   void Finalize();
129 
130   void AppendSymbolNamesToMap(const IndexCollection &indexes,
131                               bool add_demangled, bool add_mangled,
132                               NameToIndexMap &name_to_index_map) const;
133 
134   ObjectFile *GetObjectFile() const { return m_objfile; }
135 
136   /// Decode a serialized version of this object from data.
137   ///
138   /// \param data
139   ///   The decoder object that references the serialized data.
140   ///
141   /// \param offset_ptr
142   ///   A pointer that contains the offset from which the data will be decoded
143   ///   from that gets updated as data gets decoded.
144   ///
145   /// \param[out] uuid_mismatch
146   ///   Set to true if a cache file exists but the UUID didn't match, false
147   ///   otherwise.
148   ///
149   /// \return
150   ///   True if the symbol table is successfully decoded and can be used,
151   ///   false otherwise.
152   bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
153               bool &uuid_mismatch);
154 
155   /// Encode this object into a data encoder object.
156   ///
157   /// This allows this object to be serialized to disk. The object file must
158   /// have a valid Signature in order to be serialized as it is used to make
159   /// sure the cached information matches when cached data is loaded at a later
160   /// time. If the object file doesn't have a valid signature false will be
161   /// returned and it will indicate we should not cache this data.
162   ///
163   /// \param encoder
164   ///   A data encoder object that serialized bytes will be encoded into.
165   ///
166   /// \return
167   ///   True if the symbol table's object file can generate a valid signature
168   ///   and all data for the symbol table was encoded, false otherwise.
169   bool Encode(DataEncoder &encoder) const;
170 
171   /// Get the cache key string for this symbol table.
172   ///
173   /// The cache key must start with the module's cache key and is followed
174   /// by information that indicates this key is for caching the symbol table
175   /// contents and should also include the has of the object file. A module can
176   /// be represented by an ObjectFile object for the main executable, but can
177   /// also have a symbol file that is from the same or a different object file.
178   /// This means we might have two symbol tables cached in the index cache, one
179   /// for the main executable and one for the symbol file.
180   ///
181   /// \return
182   ///   The unique cache key used to save and retrieve data from the index cache.
183   std::string GetCacheKey();
184 
185   /// Save the symbol table data out into a cache.
186   ///
187   /// The symbol table will only be saved to a cache file if caching is enabled.
188   ///
189   /// We cache the contents of the symbol table since symbol tables in LLDB take
190   /// some time to initialize. This is due to the many sources for data that are
191   /// used to create a symbol table:
192   /// - standard symbol table
193   /// - dynamic symbol table (ELF)
194   /// - compressed debug info sections
195   /// - unwind information
196   /// - function pointers found in runtimes for global constructor/destructors
197   /// - other sources.
198   /// All of the above sources are combined and one symbol table results after
199   /// all sources have been considered.
200   void SaveToCache();
201 
202   /// Load the symbol table from the index cache.
203   ///
204   /// Quickly load the finalized symbol table from the index cache. This saves
205   /// time when the debugger starts up. The index cache file for the symbol
206   /// table has the modification time set to the same time as the main module.
207   /// If the cache file exists and the modification times match, we will load
208   /// the symbol table from the serlized cache file.
209   ///
210   /// \return
211   ///   True if the symbol table was successfully loaded from the index cache,
212   ///   false if the symbol table wasn't cached or was out of date.
213   bool LoadFromCache();
214 
215 
216   /// Accessors for the bool that indicates if the debug info index was loaded
217   /// from, or saved to the module index cache.
218   ///
219   /// In statistics it is handy to know if a module's debug info was loaded from
220   /// or saved to the cache. When the debug info index is loaded from the cache
221   /// startup times can be faster. When the cache is enabled and the debug info
222   /// index is saved to the cache, debug sessions can be slower. These accessors
223   /// can be accessed by the statistics and emitted to help track these costs.
224   /// \{
225   bool GetWasLoadedFromCache() const {
226     return m_loaded_from_cache;
227   }
228   void SetWasLoadedFromCache() {
229     m_loaded_from_cache = true;
230   }
231   bool GetWasSavedToCache() const {
232     return m_saved_to_cache;
233   }
234   void SetWasSavedToCache() {
235     m_saved_to_cache = true;
236   }
237   /// \}
238 
239 protected:
240   typedef std::vector<Symbol> collection;
241   typedef collection::iterator iterator;
242   typedef collection::const_iterator const_iterator;
243   class FileRangeToIndexMapCompare {
244   public:
245     FileRangeToIndexMapCompare(const Symtab &symtab) : m_symtab(symtab) {}
246     bool operator()(const uint32_t a_data, const uint32_t b_data) const {
247       return rank(a_data) > rank(b_data);
248     }
249 
250   private:
251     // How much preferred is this symbol?
252     int rank(const uint32_t data) const {
253       const Symbol &symbol = *m_symtab.SymbolAtIndex(data);
254       if (symbol.IsExternal())
255         return 3;
256       if (symbol.IsWeak())
257         return 2;
258       if (symbol.IsDebug())
259         return 0;
260       return 1;
261     }
262     const Symtab &m_symtab;
263   };
264   typedef RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t, 0,
265                           FileRangeToIndexMapCompare>
266       FileRangeToIndexMap;
267   void InitNameIndexes();
268   void InitAddressIndexes();
269 
270   ObjectFile *m_objfile;
271   collection m_symbols;
272   FileRangeToIndexMap m_file_addr_to_index;
273 
274   /// Maps function names to symbol indices (grouped by FunctionNameTypes)
275   std::map<lldb::FunctionNameType, UniqueCStringMap<uint32_t>>
276       m_name_to_symbol_indices;
277   mutable std::recursive_mutex
278       m_mutex; // Provide thread safety for this symbol table
279   bool m_file_addr_to_index_computed : 1, m_name_indexes_computed : 1,
280     m_loaded_from_cache : 1, m_saved_to_cache : 1;
281 
282 private:
283   UniqueCStringMap<uint32_t> &
284   GetNameToSymbolIndexMap(lldb::FunctionNameType type) {
285     auto map = m_name_to_symbol_indices.find(type);
286     assert(map != m_name_to_symbol_indices.end());
287     return map->second;
288   }
289   bool CheckSymbolAtIndex(size_t idx, Debug symbol_debug_type,
290                           Visibility symbol_visibility) const {
291     switch (symbol_debug_type) {
292     case eDebugNo:
293       if (m_symbols[idx].IsDebug())
294         return false;
295       break;
296 
297     case eDebugYes:
298       if (!m_symbols[idx].IsDebug())
299         return false;
300       break;
301 
302     case eDebugAny:
303       break;
304     }
305 
306     switch (symbol_visibility) {
307     case eVisibilityAny:
308       return true;
309 
310     case eVisibilityExtern:
311       return m_symbols[idx].IsExternal();
312 
313     case eVisibilityPrivate:
314       return !m_symbols[idx].IsExternal();
315     }
316     return false;
317   }
318 
319   /// A helper function that looks up full function names.
320   ///
321   /// We generate unique names for synthetic symbols so that users can look
322   /// them up by name when needed. But because doing so is uncommon in normal
323   /// debugger use, we trade off some performance at lookup time for faster
324   /// symbol table building by detecting these symbols and generating their
325   /// names lazily, rather than adding them to the normal symbol indexes. This
326   /// function does the job of first consulting the name indexes, and if that
327   /// fails it extracts the information it needs from the synthetic name and
328   /// locates the symbol.
329   ///
330   /// @param[in] symbol_name The symbol name to search for.
331   ///
332   /// @param[out] indexes The vector if symbol indexes to update with results.
333   ///
334   /// @returns The number of indexes added to the index vector. Zero if no
335   /// matches were found.
336   uint32_t GetNameIndexes(ConstString symbol_name,
337                           std::vector<uint32_t> &indexes);
338 
339   void SymbolIndicesToSymbolContextList(std::vector<uint32_t> &symbol_indexes,
340                                         SymbolContextList &sc_list);
341 
342   void RegisterMangledNameEntry(
343       uint32_t value, std::set<const char *> &class_contexts,
344       std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog,
345       RichManglingContext &rmc);
346 
347   void RegisterBacklogEntry(const NameToIndexMap::Entry &entry,
348                             const char *decl_context,
349                             const std::set<const char *> &class_contexts);
350 
351   Symtab(const Symtab &) = delete;
352   const Symtab &operator=(const Symtab &) = delete;
353 };
354 
355 } // namespace lldb_private
356 
357 #endif // LLDB_SYMBOL_SYMTAB_H
358