1 //===-- CompileUnit.cpp -----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Symbol/CompileUnit.h" 11 #include "lldb/Core/Module.h" 12 #include "lldb/Symbol/LineTable.h" 13 #include "lldb/Symbol/SymbolVendor.h" 14 #include "lldb/Symbol/VariableList.h" 15 #include "lldb/Target/Language.h" 16 17 using namespace lldb; 18 using namespace lldb_private; 19 20 CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, 21 const char *pathname, const lldb::user_id_t cu_sym_id, 22 lldb::LanguageType language, 23 lldb_private::LazyBool is_optimized) 24 : ModuleChild(module_sp), FileSpec(pathname), UserID(cu_sym_id), 25 m_user_data(user_data), m_language(language), m_flags(0), 26 m_support_files(), m_line_table_ap(), m_variables(), 27 m_is_optimized(is_optimized) { 28 if (language != eLanguageTypeUnknown) 29 m_flags.Set(flagsParsedLanguage); 30 assert(module_sp); 31 } 32 33 CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, 34 const FileSpec &fspec, const lldb::user_id_t cu_sym_id, 35 lldb::LanguageType language, 36 lldb_private::LazyBool is_optimized) 37 : ModuleChild(module_sp), FileSpec(fspec), UserID(cu_sym_id), 38 m_user_data(user_data), m_language(language), m_flags(0), 39 m_support_files(), m_line_table_ap(), m_variables(), 40 m_is_optimized(is_optimized) { 41 if (language != eLanguageTypeUnknown) 42 m_flags.Set(flagsParsedLanguage); 43 assert(module_sp); 44 } 45 46 CompileUnit::~CompileUnit() {} 47 48 void CompileUnit::CalculateSymbolContext(SymbolContext *sc) { 49 sc->comp_unit = this; 50 GetModule()->CalculateSymbolContext(sc); 51 } 52 53 ModuleSP CompileUnit::CalculateSymbolContextModule() { return GetModule(); } 54 55 CompileUnit *CompileUnit::CalculateSymbolContextCompileUnit() { return this; } 56 57 void CompileUnit::DumpSymbolContext(Stream *s) { 58 GetModule()->DumpSymbolContext(s); 59 s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID()); 60 } 61 62 void CompileUnit::GetDescription(Stream *s, 63 lldb::DescriptionLevel level) const { 64 const char *language = Language::GetNameForLanguageType(m_language); 65 *s << "id = " << (const UserID &)*this << ", file = \"" 66 << (const FileSpec &)*this << "\", language = \"" << language << '"'; 67 } 68 69 void CompileUnit::ForeachFunction( 70 llvm::function_ref<bool(const FunctionSP &)> lambda) const { 71 std::vector<lldb::FunctionSP> sorted_functions; 72 sorted_functions.reserve(m_functions_by_uid.size()); 73 for (auto &p : m_functions_by_uid) 74 sorted_functions.push_back(p.second); 75 llvm::sort(sorted_functions.begin(), sorted_functions.end(), 76 [](const lldb::FunctionSP &a, const lldb::FunctionSP &b) { 77 return a->GetID() < b->GetID(); 78 }); 79 80 for (auto &f : sorted_functions) 81 if (lambda(f)) 82 return; 83 } 84 85 //---------------------------------------------------------------------- 86 // Dump the current contents of this object. No functions that cause on demand 87 // parsing of functions, globals, statics are called, so this is a good 88 // function to call to get an idea of the current contents of the CompileUnit 89 // object. 90 //---------------------------------------------------------------------- 91 void CompileUnit::Dump(Stream *s, bool show_context) const { 92 const char *language = Language::GetNameForLanguageType(m_language); 93 94 s->Printf("%p: ", static_cast<const void *>(this)); 95 s->Indent(); 96 *s << "CompileUnit" << static_cast<const UserID &>(*this) << ", language = \"" 97 << language << "\", file = '" << static_cast<const FileSpec &>(*this) 98 << "'\n"; 99 100 // m_types.Dump(s); 101 102 if (m_variables.get()) { 103 s->IndentMore(); 104 m_variables->Dump(s, show_context); 105 s->IndentLess(); 106 } 107 108 if (!m_functions_by_uid.empty()) { 109 s->IndentMore(); 110 ForeachFunction([&s, show_context](const FunctionSP &f) { 111 f->Dump(s, show_context); 112 return false; 113 }); 114 115 s->IndentLess(); 116 s->EOL(); 117 } 118 } 119 120 //---------------------------------------------------------------------- 121 // Add a function to this compile unit 122 //---------------------------------------------------------------------- 123 void CompileUnit::AddFunction(FunctionSP &funcSP) { 124 m_functions_by_uid[funcSP->GetID()] = funcSP; 125 } 126 127 //---------------------------------------------------------------------- 128 // Find functions using the Mangled::Tokens token list. This function currently 129 // implements an interactive approach designed to find all instances of certain 130 // functions. It isn't designed to the quickest way to lookup functions as it 131 // will need to iterate through all functions and see if they match, though it 132 // does provide a powerful and context sensitive way to search for all 133 // functions with a certain name, all functions in a namespace, or all 134 // functions of a template type. See Mangled::Tokens::Parse() comments for more 135 // information. 136 // 137 // The function prototype will need to change to return a list of results. It 138 // was originally used to help debug the Mangled class and the 139 // Mangled::Tokens::MatchesQuery() function and it currently will print out a 140 // list of matching results for the functions that are currently in this 141 // compile unit. 142 // 143 // A FindFunctions method should be called prior to this that takes 144 // a regular function name (const char * or ConstString as a parameter) before 145 // resorting to this slower but more complete function. The other FindFunctions 146 // method should be able to take advantage of any accelerator tables available 147 // in the debug information (which is parsed by the SymbolFile parser plug-ins 148 // and registered with each Module). 149 //---------------------------------------------------------------------- 150 // void 151 // CompileUnit::FindFunctions(const Mangled::Tokens& tokens) 152 //{ 153 // if (!m_functions.empty()) 154 // { 155 // Stream s(stdout); 156 // std::vector<FunctionSP>::const_iterator pos; 157 // std::vector<FunctionSP>::const_iterator end = m_functions.end(); 158 // for (pos = m_functions.begin(); pos != end; ++pos) 159 // { 160 // const ConstString& demangled = (*pos)->Mangled().Demangled(); 161 // if (demangled) 162 // { 163 // const Mangled::Tokens& func_tokens = 164 // (*pos)->Mangled().GetTokens(); 165 // if (func_tokens.MatchesQuery (tokens)) 166 // s << "demangled MATCH found: " << demangled << "\n"; 167 // } 168 // } 169 // } 170 //} 171 172 FunctionSP CompileUnit::FindFunctionByUID(lldb::user_id_t func_uid) { 173 auto it = m_functions_by_uid.find(func_uid); 174 if (it == m_functions_by_uid.end()) 175 return FunctionSP(); 176 return it->second; 177 } 178 179 lldb::LanguageType CompileUnit::GetLanguage() { 180 if (m_language == eLanguageTypeUnknown) { 181 if (m_flags.IsClear(flagsParsedLanguage)) { 182 m_flags.Set(flagsParsedLanguage); 183 SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); 184 if (symbol_vendor) { 185 m_language = symbol_vendor->ParseLanguage(*this); 186 } 187 } 188 } 189 return m_language; 190 } 191 192 LineTable *CompileUnit::GetLineTable() { 193 if (m_line_table_ap.get() == nullptr) { 194 if (m_flags.IsClear(flagsParsedLineTable)) { 195 m_flags.Set(flagsParsedLineTable); 196 SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); 197 if (symbol_vendor) 198 symbol_vendor->ParseLineTable(*this); 199 } 200 } 201 return m_line_table_ap.get(); 202 } 203 204 void CompileUnit::SetLineTable(LineTable *line_table) { 205 if (line_table == nullptr) 206 m_flags.Clear(flagsParsedLineTable); 207 else 208 m_flags.Set(flagsParsedLineTable); 209 m_line_table_ap.reset(line_table); 210 } 211 212 DebugMacros *CompileUnit::GetDebugMacros() { 213 if (m_debug_macros_sp.get() == nullptr) { 214 if (m_flags.IsClear(flagsParsedDebugMacros)) { 215 m_flags.Set(flagsParsedDebugMacros); 216 SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); 217 if (symbol_vendor) { 218 symbol_vendor->ParseDebugMacros(*this); 219 } 220 } 221 } 222 223 return m_debug_macros_sp.get(); 224 } 225 226 void CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) { 227 if (debug_macros_sp.get() == nullptr) 228 m_flags.Clear(flagsParsedDebugMacros); 229 else 230 m_flags.Set(flagsParsedDebugMacros); 231 m_debug_macros_sp = debug_macros_sp; 232 } 233 234 VariableListSP CompileUnit::GetVariableList(bool can_create) { 235 if (m_variables.get() == nullptr && can_create) { 236 SymbolContext sc; 237 CalculateSymbolContext(&sc); 238 assert(sc.module_sp); 239 sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc); 240 } 241 242 return m_variables; 243 } 244 245 uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line, 246 const FileSpec *file_spec_ptr, bool exact, 247 LineEntry *line_entry_ptr) { 248 uint32_t file_idx = 0; 249 250 if (file_spec_ptr) { 251 file_idx = GetSupportFiles().FindFileIndex(1, *file_spec_ptr, true); 252 if (file_idx == UINT32_MAX) 253 return UINT32_MAX; 254 } else { 255 // All the line table entries actually point to the version of the Compile 256 // Unit that is in the support files (the one at 0 was artificially added.) 257 // So prefer the one further on in the support files if it exists... 258 FileSpecList &support_files = GetSupportFiles(); 259 const bool full = true; 260 file_idx = support_files.FindFileIndex( 261 1, support_files.GetFileSpecAtIndex(0), full); 262 if (file_idx == UINT32_MAX) 263 file_idx = 0; 264 } 265 LineTable *line_table = GetLineTable(); 266 if (line_table) 267 return line_table->FindLineEntryIndexByFileIndex(start_idx, file_idx, line, 268 exact, line_entry_ptr); 269 return UINT32_MAX; 270 } 271 272 uint32_t CompileUnit::ResolveSymbolContext(const FileSpec &file_spec, 273 uint32_t line, bool check_inlines, 274 bool exact, 275 SymbolContextItem resolve_scope, 276 SymbolContextList &sc_list) { 277 // First find all of the file indexes that match our "file_spec". If 278 // "file_spec" has an empty directory, then only compare the basenames when 279 // finding file indexes 280 std::vector<uint32_t> file_indexes; 281 const bool full_match = (bool)file_spec.GetDirectory(); 282 bool file_spec_matches_cu_file_spec = 283 FileSpec::Equal(file_spec, *this, full_match); 284 285 // If we are not looking for inlined functions and our file spec doesn't 286 // match then we are done... 287 if (!file_spec_matches_cu_file_spec && !check_inlines) 288 return 0; 289 290 uint32_t file_idx = 291 GetSupportFiles().FindFileIndex(1, file_spec, true); 292 while (file_idx != UINT32_MAX) { 293 file_indexes.push_back(file_idx); 294 file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true); 295 } 296 297 const size_t num_file_indexes = file_indexes.size(); 298 if (num_file_indexes == 0) 299 return 0; 300 301 const uint32_t prev_size = sc_list.GetSize(); 302 303 SymbolContext sc(GetModule()); 304 sc.comp_unit = this; 305 306 if (line != 0) { 307 LineTable *line_table = sc.comp_unit->GetLineTable(); 308 309 if (line_table != nullptr) { 310 uint32_t found_line; 311 uint32_t line_idx; 312 313 if (num_file_indexes == 1) { 314 // We only have a single support file that matches, so use the line 315 // table function that searches for a line entries that match a single 316 // support file index 317 LineEntry line_entry; 318 line_idx = line_table->FindLineEntryIndexByFileIndex( 319 0, file_indexes.front(), line, exact, &line_entry); 320 321 // If "exact == true", then "found_line" will be the same as "line". If 322 // "exact == false", the "found_line" will be the closest line entry 323 // with a line number greater than "line" and we will use this for our 324 // subsequent line exact matches below. 325 found_line = line_entry.line; 326 327 while (line_idx != UINT32_MAX) { 328 // If they only asked for the line entry, then we're done, we can 329 // just copy that over. But if they wanted more than just the line 330 // number, fill it in. 331 if (resolve_scope == eSymbolContextLineEntry) { 332 sc.line_entry = line_entry; 333 } else { 334 line_entry.range.GetBaseAddress().CalculateSymbolContext( 335 &sc, resolve_scope); 336 } 337 338 sc_list.Append(sc); 339 line_idx = line_table->FindLineEntryIndexByFileIndex( 340 line_idx + 1, file_indexes.front(), found_line, true, 341 &line_entry); 342 } 343 } else { 344 // We found multiple support files that match "file_spec" so use the 345 // line table function that searches for a line entries that match a 346 // multiple support file indexes. 347 LineEntry line_entry; 348 line_idx = line_table->FindLineEntryIndexByFileIndex( 349 0, file_indexes, line, exact, &line_entry); 350 351 // If "exact == true", then "found_line" will be the same as "line". If 352 // "exact == false", the "found_line" will be the closest line entry 353 // with a line number greater than "line" and we will use this for our 354 // subsequent line exact matches below. 355 found_line = line_entry.line; 356 357 while (line_idx != UINT32_MAX) { 358 if (resolve_scope == eSymbolContextLineEntry) { 359 sc.line_entry = line_entry; 360 } else { 361 line_entry.range.GetBaseAddress().CalculateSymbolContext( 362 &sc, resolve_scope); 363 } 364 365 sc_list.Append(sc); 366 line_idx = line_table->FindLineEntryIndexByFileIndex( 367 line_idx + 1, file_indexes, found_line, true, &line_entry); 368 } 369 } 370 } 371 } else if (file_spec_matches_cu_file_spec && !check_inlines) { 372 // only append the context if we aren't looking for inline call sites by 373 // file and line and if the file spec matches that of the compile unit 374 sc_list.Append(sc); 375 } 376 return sc_list.GetSize() - prev_size; 377 } 378 379 bool CompileUnit::GetIsOptimized() { 380 if (m_is_optimized == eLazyBoolCalculate) { 381 m_is_optimized = eLazyBoolNo; 382 if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) { 383 if (symbol_vendor->ParseIsOptimized(*this)) 384 m_is_optimized = eLazyBoolYes; 385 } 386 } 387 return m_is_optimized; 388 } 389 390 void CompileUnit::SetVariableList(VariableListSP &variables) { 391 m_variables = variables; 392 } 393 394 const std::vector<ConstString> &CompileUnit::GetImportedModules() { 395 if (m_imported_modules.empty() && 396 m_flags.IsClear(flagsParsedImportedModules)) { 397 m_flags.Set(flagsParsedImportedModules); 398 if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) { 399 SymbolContext sc; 400 CalculateSymbolContext(&sc); 401 symbol_vendor->ParseImportedModules(sc, m_imported_modules); 402 } 403 } 404 return m_imported_modules; 405 } 406 407 FileSpecList &CompileUnit::GetSupportFiles() { 408 if (m_support_files.GetSize() == 0) { 409 if (m_flags.IsClear(flagsParsedSupportFiles)) { 410 m_flags.Set(flagsParsedSupportFiles); 411 SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor(); 412 if (symbol_vendor) { 413 symbol_vendor->ParseSupportFiles(*this, m_support_files); 414 } 415 } 416 } 417 return m_support_files; 418 } 419 420 void *CompileUnit::GetUserData() const { return m_user_data; } 421