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 ®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 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