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;
GetMutex()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 
GetObjectFile()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   /// \{
GetWasLoadedFromCache()228   bool GetWasLoadedFromCache() const {
229     return m_loaded_from_cache;
230   }
SetWasLoadedFromCache()231   void SetWasLoadedFromCache() {
232     m_loaded_from_cache = true;
233   }
GetWasSavedToCache()234   bool GetWasSavedToCache() const {
235     return m_saved_to_cache;
236   }
SetWasSavedToCache()237   void SetWasSavedToCache() {
238     m_saved_to_cache = true;
239   }
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:
FileRangeToIndexMapCompare(const Symtab & symtab)248     FileRangeToIndexMapCompare(const Symtab &symtab) : m_symtab(symtab) {}
operator()249     bool operator()(const uint32_t a_data, const uint32_t b_data) const {
250       return rank(a_data) > rank(b_data);
251     }
252 
253   private:
254     // How much preferred is this symbol?
rank(const uint32_t data)255     int rank(const uint32_t data) const {
256       const Symbol &symbol = *m_symtab.SymbolAtIndex(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 
285 private:
286   UniqueCStringMap<uint32_t> &
GetNameToSymbolIndexMap(lldb::FunctionNameType type)287   GetNameToSymbolIndexMap(lldb::FunctionNameType type) {
288     auto map = m_name_to_symbol_indices.find(type);
289     assert(map != m_name_to_symbol_indices.end());
290     return map->second;
291   }
CheckSymbolAtIndex(size_t idx,Debug symbol_debug_type,Visibility symbol_visibility)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