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(a_data) > rank(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(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(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