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